diff options
Diffstat (limited to 'src')
420 files changed, 38465 insertions, 3154 deletions
diff --git a/src/main/java/NotSkyblockAddonsInstallerFrame.java b/src/main/java/NotSkyblockAddonsInstallerFrame.java new file mode 100644 index 00000000..7c5a1638 --- /dev/null +++ b/src/main/java/NotSkyblockAddonsInstallerFrame.java @@ -0,0 +1,667 @@ +import javax.imageio.ImageIO; +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.image.BufferedImage; +import java.io.*; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.util.Locale; +import java.util.jar.JarFile; +import java.util.regex.Pattern; +import java.util.zip.ZipEntry; + +public class NotSkyblockAddonsInstallerFrame extends JFrame implements ActionListener, MouseListener { + + private static final Pattern IN_MODS_SUBFOLDER = Pattern.compile("1\\.8\\.9[/\\\\]?$"); + + private JLabel logo = null; + private JLabel versionInfo = null; + private JLabel labelFolder = null; + + private JPanel panelCenter = null; + private JPanel panelBottom = null; + private JPanel totalContentPane = null; + + private JTextArea descriptionText = null; + private JTextArea forgeDescriptionText = null; + + private JTextField textFieldFolderLocation = null; + private JButton buttonChooseFolder = null; + + private JButton buttonInstall = null; + private JButton buttonOpenFolder = null; + private JButton buttonClose = null; + + private static final int TOTAL_HEIGHT = 435; + private static final int TOTAL_WIDTH = 404; + + private int x = 0; + private int y = 0; + + private int w = TOTAL_WIDTH; + private int h; + private int margin; + + public NotSkyblockAddonsInstallerFrame() { + try { + setName("NotEnoughUpdatesInstallerFrame"); + setTitle("NotEnoughUpdates Installer"); + setResizable(false); + setSize(TOTAL_WIDTH, TOTAL_HEIGHT); + setContentPane(getPanelContentPane()); + + getButtonFolder().addActionListener(this); + getButtonInstall().addActionListener(this); + getButtonOpenFolder().addActionListener(this); + getButtonClose().addActionListener(this); + getForgeTextArea().addMouseListener(this); + + pack(); + setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + + getFieldFolder().setText(getModsFolder().getPath()); + getButtonInstall().setEnabled(true); + getButtonInstall().requestFocus(); + } catch (Exception ex) { + showErrorPopup(ex); + } + } + + public static void main(String[] args) { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + NotSkyblockAddonsInstallerFrame frame = new NotSkyblockAddonsInstallerFrame(); + frame.centerFrame(frame); + frame.show(); + + } catch (Exception ex) { + showErrorPopup(ex); + } + } + + private JPanel getPanelContentPane() { + if (totalContentPane == null) { + try { + totalContentPane = new JPanel(); + totalContentPane.setName("PanelContentPane"); + totalContentPane.setLayout(new BorderLayout(5, 5)); + totalContentPane.setPreferredSize(new Dimension(TOTAL_WIDTH, TOTAL_HEIGHT)); + totalContentPane.add(getPanelCenter(), "Center"); + totalContentPane.add(getPanelBottom(), "South"); + } catch (Throwable ivjExc) { + showErrorPopup(ivjExc); + } + } + return totalContentPane; + } + + private JPanel getPanelCenter() { + if (panelCenter == null) { + try { + (panelCenter = new JPanel()).setName("PanelCenter"); + panelCenter.setLayout(null); + panelCenter.add(getPictureLabel(), getPictureLabel().getName()); + panelCenter.add(getVersionInfo(), getVersionInfo().getName()); + panelCenter.add(getTextArea(), getTextArea().getName()); + panelCenter.add(getForgeTextArea(), getForgeTextArea().getName()); + panelCenter.add(getLabelFolder(), getLabelFolder().getName()); + panelCenter.add(getFieldFolder(), getFieldFolder().getName()); + panelCenter.add(getButtonFolder(), getButtonFolder().getName()); + } catch (Throwable ivjExc) { + showErrorPopup(ivjExc); + } + } + return panelCenter; + } + + private JLabel getPictureLabel() { + if (logo == null) { + try { + h = w/2; + margin = 5; + + BufferedImage myPicture = ImageIO.read(getClass().getClassLoader().getResourceAsStream("assets/notenoughupdates/logo.png")); + Image scaled = myPicture.getScaledInstance(w-margin*2, h-margin, Image.SCALE_SMOOTH); + logo = new JLabel(new ImageIcon(scaled)); + logo.setName("Logo"); + logo.setBounds(x+margin, y+margin, w-margin*2, h-margin); + logo.setFont(new Font(Font.DIALOG, Font.BOLD, 18)); + logo.setHorizontalAlignment(SwingConstants.CENTER); + logo.setPreferredSize(new Dimension(h*742/537, h)); + + y += h; + } catch (Throwable ivjExc) { + showErrorPopup(ivjExc); + } + } + return logo; + } + + private JLabel getVersionInfo() { + if (versionInfo == null) { + try { + h = 25; + + versionInfo = new JLabel(); + versionInfo.setName("LabelMcVersion"); + versionInfo.setBounds(x, y, w, h); + versionInfo.setFont(new Font(Font.DIALOG, Font.BOLD, 14)); + versionInfo.setHorizontalAlignment(SwingConstants.CENTER); + versionInfo.setPreferredSize(new Dimension(w, h)); + versionInfo.setText("NEU by Moulberry, Installer by Biscuit - for Minecraft 1.8.9"); + + y += h; + } catch (Throwable ivjExc) { + showErrorPopup(ivjExc); + } + } + return versionInfo; + } + + private JTextArea getTextArea() { + if (descriptionText == null) { + try { + h = 60; + margin = 10; + + descriptionText = new JTextArea(); + descriptionText.setName("TextArea"); + descriptionText.setBounds(x+margin, y+margin, w-margin*2, h-margin); + descriptionText.setEditable(false); + descriptionText.setHighlighter(null); + descriptionText.setEnabled(true); + descriptionText.setFont(new Font(Font.DIALOG, Font.PLAIN, 12)); + descriptionText.setLineWrap(true); + descriptionText.setOpaque(false); + descriptionText.setPreferredSize(new Dimension(w-margin*2, h-margin)); + descriptionText.setText("This installer will copy NotEnoughUpdates into your forge mods folder for you, and replace any old versions that already exist. " + + "Close this if you prefer to do this yourself!"); + descriptionText.setWrapStyleWord(true); + + y += h; + } catch (Throwable ivjExc) { + showErrorPopup(ivjExc); + } + } + return descriptionText; + } + + private JTextArea getForgeTextArea() { + if (forgeDescriptionText == null) { + try { + h = 55; + margin = 10; + + forgeDescriptionText = new JTextArea(); + forgeDescriptionText.setName("TextAreaForge"); + forgeDescriptionText.setBounds(x+margin, y+margin, w-margin*2, h-margin); + forgeDescriptionText.setEditable(false); + forgeDescriptionText.setHighlighter(null); + forgeDescriptionText.setEnabled(true); + forgeDescriptionText.setFont(new Font(Font.DIALOG, Font.PLAIN, 12)); + forgeDescriptionText.setLineWrap(true); + forgeDescriptionText.setOpaque(false); + forgeDescriptionText.setPreferredSize(new Dimension(w-margin*2, h-margin)); + forgeDescriptionText.setText("However, you still need to install Forge client in order to be able to run this mod. Click here to visit the download page for Forge 1.8.9!"); + forgeDescriptionText.setForeground(Color.BLUE.darker()); + forgeDescriptionText.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + forgeDescriptionText.setWrapStyleWord(true); + + y += h; + } catch (Throwable ivjExc) { + showErrorPopup(ivjExc); + } + } + return forgeDescriptionText; + } + + private JLabel getLabelFolder() { + if (labelFolder == null) { + h = 16; + w = 65; + + x += 10; // Padding + + try { + labelFolder = new JLabel(); + labelFolder.setName("LabelFolder"); + labelFolder.setBounds(x, y+2, w, h); + labelFolder.setPreferredSize(new Dimension(w, h)); + labelFolder.setText("Mods Folder"); + } catch (Throwable ivjExc) { + showErrorPopup(ivjExc); + } + + x += w; + } + return labelFolder; + } + + private JTextField getFieldFolder() { + if (textFieldFolderLocation == null) { + h = 20; + w = 287; + + try { + textFieldFolderLocation = new JTextField(); + textFieldFolderLocation.setName("FieldFolder"); + textFieldFolderLocation.setBounds(x, y, w, h); + textFieldFolderLocation.setEditable(false); + textFieldFolderLocation.setPreferredSize(new Dimension(w, h)); + } catch (Throwable ivjExc) { + showErrorPopup(ivjExc); + } + + x += w; + } + return textFieldFolderLocation; + } + + private JButton getButtonFolder() { + if (buttonChooseFolder == null) { + h = 20; + w = 25; + + x += 10; // Padding + + try { + BufferedImage myPicture = ImageIO.read(getClass().getClassLoader().getResourceAsStream("assets/notenoughupdates/folder.png")); + Image scaled = myPicture.getScaledInstance(w-8, h-6, Image.SCALE_SMOOTH); + buttonChooseFolder = new JButton(new ImageIcon(scaled)); + buttonChooseFolder.setName("ButtonFolder"); + buttonChooseFolder.setBounds(x, y, w, h); + buttonChooseFolder.setPreferredSize(new Dimension(w, h)); + } catch (Throwable ivjExc) { + showErrorPopup(ivjExc); + } + } + return buttonChooseFolder; + } + + private JPanel getPanelBottom() { + if (panelBottom == null) { + try { + panelBottom = new JPanel(); + panelBottom.setName("PanelBottom"); + panelBottom.setLayout(new FlowLayout(FlowLayout.CENTER, 15, 10)); + panelBottom.setPreferredSize(new Dimension(390, 55)); + panelBottom.add(getButtonInstall(), getButtonInstall().getName()); + panelBottom.add(getButtonOpenFolder(), getButtonOpenFolder().getName()); + panelBottom.add(getButtonClose(), getButtonClose().getName()); + } catch (Throwable ivjExc) { + showErrorPopup(ivjExc); + } + } + return panelBottom; + } + + private JButton getButtonInstall() { + if (buttonInstall == null) { + w = 100; + h = 26; + + try { + buttonInstall = new JButton(); + buttonInstall.setName("ButtonInstall"); + buttonInstall.setPreferredSize(new Dimension(w, h)); + buttonInstall.setText("Install"); + } catch (Throwable ivjExc) { + showErrorPopup(ivjExc); + } + } + return buttonInstall; + } + + private JButton getButtonOpenFolder() { + if (buttonOpenFolder == null) { + w = 130; + h = 26; + + try { + buttonOpenFolder = new JButton(); + buttonOpenFolder.setName("ButtonOpenFolder"); + buttonOpenFolder.setPreferredSize(new Dimension(w, h)); + buttonOpenFolder.setText("Open Mods Folder"); + } catch (Throwable ivjExc) { + showErrorPopup(ivjExc); + } + } + return buttonOpenFolder; + } + + private JButton getButtonClose() { + if (buttonClose == null) { + w = 100; + h = 26; + + try { + (buttonClose = new JButton()).setName("ButtonClose"); + buttonClose.setPreferredSize(new Dimension(w, h)); + buttonClose.setText("Cancel"); + } catch (Throwable ivjExc) { + showErrorPopup(ivjExc); + } + } + return buttonClose; + } + + public void onFolderSelect() { + File currentDirectory = new File(getFieldFolder().getText()); + + JFileChooser jFileChooser = new JFileChooser(currentDirectory); + jFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + jFileChooser.setAcceptAllFileFilterUsed(false); + if (jFileChooser.showOpenDialog(this) == 0) { + File newDirectory = jFileChooser.getSelectedFile(); + getFieldFolder().setText(newDirectory.getPath()); + } + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getSource() == getButtonClose()) { + dispose(); + System.exit(0); + } + if (e.getSource() == getButtonFolder()) { + onFolderSelect(); + } + if (e.getSource() == getButtonInstall()) { + onInstall(); + } + if (e.getSource() == getButtonOpenFolder()) { + onOpenFolder(); + } + } + + @Override + public void mouseClicked(MouseEvent e) { + if (e.getSource() == getForgeTextArea()) { + try { + Desktop.getDesktop().browse(new URI("http://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.8.9.html")); + } catch (IOException | URISyntaxException ex) { + showErrorPopup(ex); + } + } + } + + public void onInstall() { + try { + File modsFolder = new File(getFieldFolder().getText()); + if (!modsFolder.exists()) { + showErrorMessage("Folder not found: " + modsFolder.getPath()); + return; + } + if (!modsFolder.isDirectory()) { + showErrorMessage("Not a folder: " + modsFolder.getPath()); + return; + } + tryInstall(modsFolder); + } catch (Exception e) { + showErrorPopup(e); + } + } + + private void tryInstall(File modsFolder) { + File thisFile = getThisFile(); + + if (thisFile != null) { + boolean inSubFolder = false; + if (IN_MODS_SUBFOLDER.matcher(modsFolder.getPath()).find()) { + inSubFolder = true; + } + + boolean deletingFailure = false; + if (modsFolder.isDirectory()) { // Delete in this current folder. + boolean failed = findSkyblockAddonsAndDelete(modsFolder.listFiles()); + if (failed) deletingFailure = true; + } + if (inSubFolder) { // We are in the 1.8.9 folder, delete in the parent folder as well. + if (modsFolder.getParentFile().isDirectory()) { + boolean failed = findSkyblockAddonsAndDelete(modsFolder.getParentFile().listFiles()); + if (failed) deletingFailure = true; + } + } else { // We are in the main mods folder, but the 1.8.9 subfolder exists... delete in there too. + File subFolder = new File(modsFolder, "1.8.9"); + if (subFolder.exists() && subFolder.isDirectory()) { + boolean failed = findSkyblockAddonsAndDelete(subFolder.listFiles()); + if (failed) deletingFailure = true; + } + } + + if (deletingFailure) return; + + if (thisFile.isDirectory()) { + showErrorMessage("This file is a directory... Are we in a development environment?"); + return; + } + + try { + Files.copy(thisFile.toPath(), new File(modsFolder, thisFile.getName()).toPath()); + } catch (Exception ex) { + showErrorPopup(ex); + return; + } + + showMessage("NotEnoughUpdates has been successfully installed into your mods folder."); + dispose(); + System.exit(0); + } + } + + private boolean findSkyblockAddonsAndDelete(File[] files) { + if (files == null) return false; + + for (File file : files) { + if (!file.isDirectory() && file.getPath().endsWith(".jar")) { + try { + JarFile jarFile = new JarFile(file); + ZipEntry mcModInfo = jarFile.getEntry("mcmod.info"); + if (mcModInfo != null) { + InputStream inputStream = jarFile.getInputStream(mcModInfo); + String modID = getModIDFromInputStream(inputStream); + if (modID.equals("notenoughupdates")) { + jarFile.close(); + try { + boolean deleted = file.delete(); + if (!deleted) { + throw new Exception(); + } + } catch (Exception ex) { + ex.printStackTrace(); + showErrorMessage("Was not able to delete the other NotEnoughUpdates files found in your mods folder!" + System.lineSeparator() + + "Please make sure that your minecraft is currently closed and try again, or feel" + System.lineSeparator() + + "free to open your mods folder and delete those files manually."); + return true; + } + continue; + } + } + jarFile.close(); + } catch (Exception ex) { + // Just don't check the file I guess, move on to the next... + } + } + } + return false; + } + + public void onOpenFolder() { + try { + Desktop.getDesktop().open(getModsFolder()); + } catch (Exception e) { + showErrorPopup(e); + } + } + + public File getModsFolder() { + String userHome = System.getProperty("user.home", "."); + + File modsFolder = getFile(userHome, "minecraft/mods/1.8.9"); + if (!modsFolder.exists()) { + modsFolder = getFile(userHome, "minecraft/mods"); + } + + if (!modsFolder.exists() && !modsFolder.mkdirs()) { + throw new RuntimeException("The working directory could not be created: " + modsFolder); + } + return modsFolder; + } + + public File getFile(String userHome, String minecraftPath) { + File workingDirectory; + switch (getOperatingSystem()) { + case LINUX: + case SOLARIS: { + workingDirectory = new File(userHome, '.' + minecraftPath + '/'); + break; + } + case WINDOWS: { + String applicationData = System.getenv("APPDATA"); + if (applicationData != null) { + workingDirectory = new File(applicationData, "." + minecraftPath + '/'); + break; + } + workingDirectory = new File(userHome, '.' + minecraftPath + '/'); + break; + } + case MACOS: { + workingDirectory = new File(userHome, "Library/Application Support/" + minecraftPath); + break; + } + default: { + workingDirectory = new File(userHome, minecraftPath + '/'); + break; + } + } + return workingDirectory; + } + + public OperatingSystem getOperatingSystem() { + String osName = System.getProperty("os.name").toLowerCase(Locale.US); + if (osName.contains("win")) { + return OperatingSystem.WINDOWS; + + } else if (osName.contains("mac")) { + return OperatingSystem.MACOS; + + } else if (osName.contains("solaris") || osName.contains("sunos")) { + + return OperatingSystem.SOLARIS; + } else if (osName.contains("linux") || osName.contains("unix")) { + + return OperatingSystem.LINUX; + } + return OperatingSystem.UNKNOWN; + } + + public void centerFrame(JFrame frame) { + Rectangle rectangle = frame.getBounds(); + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Rectangle screenRectangle = new Rectangle(0, 0, screenSize.width, screenSize.height); + + int newX = screenRectangle.x + (screenRectangle.width - rectangle.width) / 2; + int newY = screenRectangle.y + (screenRectangle.height - rectangle.height) / 2; + + if (newX < 0) newX = 0; + if (newY < 0) newY = 0; + + frame.setBounds(newX, newY, rectangle.width, rectangle.height); + } + + public void showMessage(String message) { + JOptionPane.showMessageDialog(null, message, "NotEnoughUpdates", JOptionPane.INFORMATION_MESSAGE); + } + + public void showErrorMessage(String message) { + JOptionPane.showMessageDialog(null, message, "NotEnoughUpdates - Error", JOptionPane.ERROR_MESSAGE); + } + + public enum OperatingSystem { + LINUX, + SOLARIS, + WINDOWS, + MACOS, + UNKNOWN + } + + private static String getStacktraceText(Throwable ex) { + StringWriter stringWriter = new StringWriter(); + ex.printStackTrace(new PrintWriter(stringWriter)); + return stringWriter.toString().replace("\t", " "); + } + + private static void showErrorPopup(Throwable ex) { + ex.printStackTrace(); + + JTextArea textArea = new JTextArea(getStacktraceText(ex)); + textArea.setEditable(false); + Font currentFont = textArea.getFont(); + Font newFont = new Font(Font.MONOSPACED, currentFont.getStyle(), currentFont.getSize()); + textArea.setFont(newFont); + + JScrollPane errorScrollPane = new JScrollPane(textArea); + errorScrollPane.setPreferredSize(new Dimension(600, 400)); + JOptionPane.showMessageDialog(null, errorScrollPane, "Error", JOptionPane.ERROR_MESSAGE); + } + + private String getVersionFromMcmodInfo() { + String version = ""; + try { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("mcmod.info"))); + while ((version = bufferedReader.readLine()) != null) { + if (version.contains("\"version\": \"")) { + version = version.split(Pattern.quote("\"version\": \""))[1]; + version = version.substring(0, version.length() - 2); + break; + } + } + } catch (Exception ex) { + // It's okay, I guess just don't use the version lol. + } + return version; + } + + private String getModIDFromInputStream(InputStream inputStream) { + String version = ""; + try { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + while ((version = bufferedReader.readLine()) != null) { + if (version.contains("\"modid\": \"")) { + version = version.split(Pattern.quote("\"modid\": \""))[1]; + version = version.substring(0, version.length() - 2); + break; + } + } + } catch (Exception ex) { + // RIP, couldn't find the modid... + } + return version; + } + + private File getThisFile() { + try { + return new File(NotSkyblockAddonsInstallerFrame.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + } catch (URISyntaxException ex) { + showErrorPopup(ex); + } + return null; + } + + @Override + public void mousePressed(MouseEvent e) {} + + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) {} + + @Override + public void mouseExited(MouseEvent e) {} +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/AccessoryBagOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/AccessoryBagOverlay.java new file mode 100644 index 00000000..5ca25082 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/AccessoryBagOverlay.java @@ -0,0 +1,824 @@ +package io.github.moulberry.notenoughupdates; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.profileviewer.PlayerStats; +import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.EnumChatFormatting; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; + +import java.awt.*; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.*; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static io.github.moulberry.notenoughupdates.GuiTextures.*; + +public class AccessoryBagOverlay { + + private static final int TAB_BASIC = 0; + private static final int TAB_TOTAL = 1; + private static final int TAB_BONUS = 2; + private static final int TAB_DUP = 3; + private static final int TAB_MISSING = 4; + private static final int TAB_OPTIMIZER = 5; + + private static final ItemStack[] TAB_STACKS = new ItemStack[] { + Utils.createItemStack(Items.dye, EnumChatFormatting.DARK_AQUA+"Basic Information", + 10, EnumChatFormatting.GREEN+"- Talis count by rarity"), + Utils.createItemStack(Items.diamond_sword, EnumChatFormatting.DARK_AQUA+"Total Stat Bonuses", + 0), + Utils.createItemStack(Item.getItemFromBlock(Blocks.anvil), EnumChatFormatting.DARK_AQUA+"Total Stat Bonuses (from reforges)", + 0), + Utils.createItemStack(Items.dye, EnumChatFormatting.DARK_AQUA+"Duplicates", + 8), + Utils.createItemStack(Item.getItemFromBlock(Blocks.barrier), EnumChatFormatting.DARK_AQUA+"Missing", + 0), + Utils.createItemStack(Item.getItemFromBlock(Blocks.redstone_block), EnumChatFormatting.DARK_AQUA+"Optimizer", + 0), + }; + + private static int currentTab = TAB_BASIC; + + public static boolean mouseClick() { + if(Minecraft.getMinecraft().currentScreen instanceof GuiChest) { + GuiChest eventGui = (GuiChest) Minecraft.getMinecraft().currentScreen; + ContainerChest cc = (ContainerChest) eventGui.inventorySlots; + String containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText(); + if(!containerName.trim().startsWith("Accessory Bag")) { + return false; + } + } else { + return false; + } + + if(!Mouse.getEventButtonState()) return false; + try { + 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(); + + int xSize = (int) Utils.getField(GuiContainer.class, Minecraft.getMinecraft().currentScreen, "xSize", "field_146999_f"); + int ySize = (int) Utils.getField(GuiContainer.class, Minecraft.getMinecraft().currentScreen, "ySize", "field_147000_g"); + int guiLeft = (int) Utils.getField(GuiContainer.class, Minecraft.getMinecraft().currentScreen, "guiLeft", "field_147003_i"); + int guiTop = (int) Utils.getField(GuiContainer.class, Minecraft.getMinecraft().currentScreen, "guiTop", "field_147009_r"); + + if(mouseX < guiLeft+xSize+3 || mouseX > guiLeft+xSize+80+28) return false; + if(mouseY < guiTop || mouseY > guiTop+166) return false; + + if(mouseX > guiLeft+xSize+83 && mouseY < guiTop+20*TAB_MISSING+22) { + currentTab = (mouseY - guiTop)/20; + if(currentTab < 0) currentTab = 0; + if(currentTab > TAB_MISSING) currentTab = TAB_MISSING; + } + + if(currentTab == TAB_OPTIMIZER) { + int x = guiLeft+xSize+3; + int y = guiTop; + + if(mouseY > y+92 && mouseY < y+103) { + if(mouseX > x+5 && mouseX < x+75) { + mainWeapon = (int)Math.floor((mouseX-x-5)/70f*9); + if(mainWeapon < 1) { + mainWeapon = 1; + } else if(mainWeapon > 9) { + mainWeapon = 9; + } + } + } + + if(mouseX > x+5 && mouseX < x+35 || mouseX > x+45 && mouseX < x+75) { + boolean set = mouseX > x+5 && mouseX < x+35; + + if(mouseY > y+32 && mouseY < y+43) { + forceCC = set; + } else if(mouseY > y+52 && mouseY < y+63) { + forceAS = set; + } else if(mouseY > y+72 && mouseY < y+83) { + useGodPot = set; + } else if(mouseY > y+92 && mouseY < y+103) { + allowShaded = set; + } + } + } + + return true; + } catch(Exception e) { + return false; + } + } + + public static void resetCache() { + accessoryStacks = new HashSet<>(); + pagesVisited = new HashSet<>(); + talismanCountRarity = null; + totalStats = null; + reforgeStats = null; + duplicates = null; + missing = null; + } + + private static Set<ItemStack> accessoryStacks = new HashSet<>(); + private static Set<Integer> pagesVisited = new HashSet<>(); + + public static void renderVisitOverlay(int x, int y) { + Utils.drawStringCenteredScaledMaxWidth("Please visit all", Minecraft.getMinecraft().fontRendererObj, x+40, y+78, true, 70, -1); + Utils.drawStringCenteredScaledMaxWidth("pages of the bag", Minecraft.getMinecraft().fontRendererObj, x+40, y+86, true, 70, -1); + } + + private static TreeMap<Integer, Integer> talismanCountRarity = null; + public static void renderBasicOverlay(int x, int y) { + if(talismanCountRarity == null) { + talismanCountRarity = new TreeMap<>(); + for(ItemStack stack : accessoryStacks) { + int rarity = getRarity(stack); + if(rarity >= 0) { + talismanCountRarity.put(rarity, talismanCountRarity.getOrDefault(rarity, 0)+1); + } + } + } + + Utils.drawStringCenteredScaledMaxWidth("# By Rarity", Minecraft.getMinecraft().fontRendererObj, x+40, y+12, false, 70, + new Color(80, 80, 80).getRGB()); + + int yIndex = 0; + for(Map.Entry<Integer, Integer> entry : talismanCountRarity.descendingMap().entrySet()) { + String rarityName = rarityArrC[entry.getKey()]; + renderAlignedString(rarityName, EnumChatFormatting.WHITE.toString()+entry.getValue(), x+5, y+20+11*yIndex, 70); + yIndex++; + } + } + + + private static PlayerStats.Stats totalStats = null; + public static void renderTotalStatsOverlay(int x, int y) { + if(totalStats == null) { + totalStats = new PlayerStats.Stats(); + for(ItemStack stack : accessoryStacks) { + if(stack != null) totalStats.add(getStatForItem(stack, STAT_PATTERN_MAP, true)); + } + } + + Utils.drawStringCenteredScaledMaxWidth("Total Stats", Minecraft.getMinecraft().fontRendererObj, x+40, y+12, false, 70, + new Color(80, 80, 80).getRGB()); + int yIndex = 0; + for(int i=0; i<PlayerStats.defaultStatNames.length; i++) { + String statName = PlayerStats.defaultStatNames[i]; + String statNamePretty = PlayerStats.defaultStatNamesPretty[i]; + + int val = Math.round(totalStats.get(statName)); + + if(Math.abs(val) < 1E-5) continue; + + GlStateManager.color(1, 1, 1, 1); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + renderAlignedString(statNamePretty, EnumChatFormatting.WHITE.toString()+val, x+5, y+20+11*yIndex, 70); + + yIndex++; + } + } + + private static PlayerStats.Stats reforgeStats = null; + public static void renderReforgeStatsOverlay(int x, int y) { + if(reforgeStats == null) { + reforgeStats = new PlayerStats.Stats(); + for(ItemStack stack : accessoryStacks) { + if(stack != null) reforgeStats.add(getStatForItem(stack, STAT_PATTERN_MAP_BONUS, false)); + } + } + + Utils.drawStringCenteredScaledMaxWidth("Reforge Stats", Minecraft.getMinecraft().fontRendererObj, x+40, y+12, false, 70, + new Color(80, 80, 80).getRGB()); + int yIndex = 0; + for(int i=0; i<PlayerStats.defaultStatNames.length; i++) { + String statName = PlayerStats.defaultStatNames[i]; + String statNamePretty = PlayerStats.defaultStatNamesPretty[i]; + + int val = Math.round(reforgeStats.get(statName)); + + if(Math.abs(val) < 1E-5) continue; + + GlStateManager.color(1, 1, 1, 1); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + renderAlignedString(statNamePretty, EnumChatFormatting.WHITE.toString()+val, x+5, y+20+11*yIndex, 70); + + yIndex++; + } + } + + private static Set<ItemStack> duplicates = null; + public static void renderDuplicatesOverlay(int x, int y) { + if(duplicates == null) { + JsonObject misc = Constants.MISC; + if(misc == null) { + Utils.drawStringCenteredScaledMaxWidth("Duplicates: ERROR", Minecraft.getMinecraft().fontRendererObj, x+40, y+12, false, 70, + new Color(80, 80, 80).getRGB()); + return; + } + JsonElement talisman_upgrades_element = misc.get("talisman_upgrades"); + if(talisman_upgrades_element == null) { + Utils.drawStringCenteredScaledMaxWidth("Duplicates: ERROR", Minecraft.getMinecraft().fontRendererObj, x+40, y+12, false, 70, + new Color(80, 80, 80).getRGB()); + return; + } + JsonObject talisman_upgrades = talisman_upgrades_element.getAsJsonObject(); + + duplicates = new HashSet<>(); + + Set<String> prevInternalnames = new HashSet<>(); + for(ItemStack stack : accessoryStacks) { + String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack); + + if(prevInternalnames.contains(internalname)) { + duplicates.add(stack); + continue; + } + prevInternalnames.add(internalname); + + if(talisman_upgrades.has(internalname)) { + JsonArray upgrades = talisman_upgrades.get(internalname).getAsJsonArray(); + for(ItemStack stack2 : accessoryStacks) { + if(stack != stack2) { + String internalname2 = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack2); + for(int j=0; j<upgrades.size(); j++) { + String upgrade = upgrades.get(j).getAsString(); + if(internalname2.equals(upgrade)) { + duplicates.add(stack); + break; + } + } + } + } + } + } + } + if(duplicates.isEmpty()) { + Utils.drawStringCenteredScaledMaxWidth("No Duplicates", Minecraft.getMinecraft().fontRendererObj, x+40, y+12, false, 70, + new Color(80, 80, 80).getRGB()); + } else { + Utils.drawStringCenteredScaledMaxWidth("Duplicates: " + duplicates.size(), Minecraft.getMinecraft().fontRendererObj, x+40, y+12, false, 70, + new Color(80, 80, 80).getRGB()); + + int yIndex = 0; + for(ItemStack duplicate : duplicates) { + renderAlignedString(duplicate.getDisplayName(), "", x+5, y+20+11*yIndex, 70); + if(duplicates.size() > 11) { + if(++yIndex >= 10) break; + } else { + if(++yIndex >= 11) break; + } + } + + if(duplicates.size() > 11) { + Utils.drawStringCenteredScaledMaxWidth("+" + (duplicates.size()-10) + " More", + Minecraft.getMinecraft().fontRendererObj, x+40, y+16+121, false, 70, + new Color(80, 80, 80).getRGB()); + } + } + } + + private static List<ItemStack> missing = null; + public static void renderMissingOverlay(int x, int y) { + if(missing == null) { + JsonObject misc = Constants.MISC; + if(misc == null) { + Utils.drawStringCenteredScaledMaxWidth("Duplicates: ERROR", Minecraft.getMinecraft().fontRendererObj, x+40, y+12, false, 70, + new Color(80, 80, 80).getRGB()); + return; + } + JsonElement talisman_upgrades_element = misc.get("talisman_upgrades"); + if(talisman_upgrades_element == null) { + Utils.drawStringCenteredScaledMaxWidth("Duplicates: ERROR", Minecraft.getMinecraft().fontRendererObj, x+40, y+12, false, 70, + new Color(80, 80, 80).getRGB()); + return; + } + JsonObject talisman_upgrades = talisman_upgrades_element.getAsJsonObject(); + + missing = new ArrayList<>(); + + List<String> missingInternal = new ArrayList<>(); + for(Map.Entry<String, JsonObject> entry : NotEnoughUpdates.INSTANCE.manager.getItemInformation().entrySet()) { + if(entry.getValue().has("lore")) { + if(checkItemType(entry.getValue().get("lore").getAsJsonArray(), "ACCESSORY", "HATCCESSORY") >= 0) { + missingInternal.add(entry.getKey()); + } + } + } + + for(ItemStack stack : accessoryStacks) { + String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack); + missingInternal.remove(internalname); + + for(Map.Entry<String, JsonElement> talisman_upgrade_element : talisman_upgrades.entrySet()) { + JsonArray upgrades = talisman_upgrade_element.getValue().getAsJsonArray(); + for(int j=0; j<upgrades.size(); j++) { + String upgrade = upgrades.get(j).getAsString(); + if(internalname.equals(upgrade)) { + missingInternal.remove(talisman_upgrade_element.getKey()); + break; + } + } + } + } + + missingInternal.sort(getItemComparator()); + + for(String internal : missingInternal) { + missing.add(NotEnoughUpdates.INSTANCE.manager.jsonToStack(NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(internal))); + } + } + if(missing.isEmpty()) { + Utils.drawStringCenteredScaledMaxWidth("No Missing", Minecraft.getMinecraft().fontRendererObj, x+40, y+12, false, 70, + new Color(80, 80, 80).getRGB()); + } else { + Utils.drawStringCenteredScaledMaxWidth("Missing: " + missing.size(), Minecraft.getMinecraft().fontRendererObj, x+40, y+12, false, 70, + new Color(80, 80, 80).getRGB()); + + int yIndex = 0; + for(ItemStack missingStack : missing) { + renderAlignedString(missingStack.getDisplayName(), "", x+5, y+20+11*yIndex, 70); + if(missing.size() > 11) { + if(++yIndex >= 10) break; + } else { + if(++yIndex >= 11) break; + } + } + + if(missing.size() > 11) { + Utils.drawStringCenteredScaledMaxWidth("+" + (missing.size()-10) + " More", + Minecraft.getMinecraft().fontRendererObj, x+40, y+16+121, false, 70, + new Color(80, 80, 80).getRGB()); + } + } + } + + private static boolean forceCC = false; + private static boolean forceAS = false; + private static boolean useGodPot = true; + private static boolean allowShaded = true; + private static int mainWeapon = 1; + + public static void renderOptimizerOverlay(int x, int y) { + Utils.drawStringCenteredScaledMaxWidth("Optimizer", Minecraft.getMinecraft().fontRendererObj, x+40, y+12, false, 70, + new Color(80, 80, 80).getRGB()); + + int light = new Color(220, 220, 220).getRGB(); + int dark = new Color(170, 170, 170).getRGB(); + + Gui.drawRect(x+5, y+32, x+35, y+43, forceCC?dark:light); + Gui.drawRect(x+45, y+32, x+75, y+43, forceCC?light:dark); + + Gui.drawRect(x+5, y+52, x+35, y+63, forceAS?dark:light); + Gui.drawRect(x+45, y+52, x+75, y+63, forceAS?light:dark); + + Gui.drawRect(x+5, y+72, x+35, y+83, useGodPot?dark:light); + Gui.drawRect(x+45, y+72, x+75, y+83, useGodPot?light:dark); + + Gui.drawRect(x+5, y+92, x+35, y+103, allowShaded?dark:light); + Gui.drawRect(x+45, y+92, x+75, y+103, allowShaded?light:dark); + + Gui.drawRect(x+5, y+102, x+75, y+113, light); + Gui.drawRect(x+5+(int)((mainWeapon-1)/9f*70), y+102, x+5+(int)(mainWeapon/9f*70), y+113, dark); + + Utils.drawStringCenteredScaledMaxWidth("Force 100% CC", Minecraft.getMinecraft().fontRendererObj, x+40, y+27, false, 70, + new Color(80, 80, 80).getRGB()); + Utils.drawStringCenteredScaledMaxWidth((forceCC?EnumChatFormatting.GREEN:EnumChatFormatting.GRAY)+"YES", + Minecraft.getMinecraft().fontRendererObj, x+20, y+37, + true, 30, new Color(80, 80, 80).getRGB()); + Utils.drawStringCenteredScaledMaxWidth((forceCC?EnumChatFormatting.GRAY:EnumChatFormatting.RED)+"NO", Minecraft.getMinecraft().fontRendererObj, x+60, y+37, + true, 30, new Color(80, 80, 80).getRGB()); + + Utils.drawStringCenteredScaledMaxWidth("Force 100% ATKSPEED", Minecraft.getMinecraft().fontRendererObj, x+40, y+47, false, 70, + new Color(80, 80, 80).getRGB()); + Utils.drawStringCenteredScaledMaxWidth((forceAS?EnumChatFormatting.GREEN:EnumChatFormatting.GRAY)+"YES", Minecraft.getMinecraft().fontRendererObj, x+20, y+57, + true, 30, new Color(80, 80, 80).getRGB()); + Utils.drawStringCenteredScaledMaxWidth((forceAS?EnumChatFormatting.GRAY:EnumChatFormatting.RED)+"NO", Minecraft.getMinecraft().fontRendererObj, x+60, y+57, + true, 30, new Color(80, 80, 80).getRGB()); + + Utils.drawStringCenteredScaledMaxWidth("Use God Potion", Minecraft.getMinecraft().fontRendererObj, x+40, y+67, false, 70, + new Color(80, 80, 80).getRGB()); + Utils.drawStringCenteredScaledMaxWidth((useGodPot?EnumChatFormatting.GREEN:EnumChatFormatting.GRAY)+"YES", Minecraft.getMinecraft().fontRendererObj, x+20, y+77, + true, 30, new Color(80, 80, 80).getRGB()); + Utils.drawStringCenteredScaledMaxWidth((useGodPot?EnumChatFormatting.GRAY:EnumChatFormatting.RED)+"NO", Minecraft.getMinecraft().fontRendererObj, x+60, y+77, + true, 30, new Color(80, 80, 80).getRGB()); + + Utils.drawStringCenteredScaledMaxWidth("Use God Potion", Minecraft.getMinecraft().fontRendererObj, x+40, y+87, false, 70, + new Color(80, 80, 80).getRGB()); + Utils.drawStringCenteredScaledMaxWidth((allowShaded?EnumChatFormatting.GREEN:EnumChatFormatting.GRAY)+"YES", + Minecraft.getMinecraft().fontRendererObj, x+20, y+97, + true, 30, new Color(80, 80, 80).getRGB()); + Utils.drawStringCenteredScaledMaxWidth((allowShaded?EnumChatFormatting.GRAY:EnumChatFormatting.RED)+"NO", + Minecraft.getMinecraft().fontRendererObj, x+60, y+97, + true, 30, new Color(80, 80, 80).getRGB()); + + Utils.drawStringCenteredScaledMaxWidth("Main Weapon", Minecraft.getMinecraft().fontRendererObj, x+40, y+107, false, 70, + new Color(80, 80, 80).getRGB()); + Utils.drawStringCenteredScaled("1 2 3 4 5 6 7 8 9", + Minecraft.getMinecraft().fontRendererObj, x+40, y+117, + true, 70, new Color(80, 80, 80).getRGB()); + } + + private static Comparator<String> getItemComparator() { + return (o1, o2) -> { + float cost1; + JsonObject o1Auc = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAuctionInfo(o1); + if(o1Auc != null && o1Auc.has("price")) { + cost1 = o1Auc.get("price").getAsFloat(); + } else { + cost1 = NotEnoughUpdates.INSTANCE.manager.auctionManager.getCraftCost(o1).craftCost; + } + float cost2; + JsonObject o2Auc = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAuctionInfo(o2); + if(o2Auc != null && o2Auc.has("price")) { + cost2 = o2Auc.get("price").getAsFloat(); + } else { + cost2 = NotEnoughUpdates.INSTANCE.manager.auctionManager.getCraftCost(o2).craftCost; + } + + + if(cost1 < cost2) return -1; + if(cost1 > cost2) return 1; + + return o1.compareTo(o2); + }; + } + + public static void renderOverlay() { + if(Minecraft.getMinecraft().currentScreen instanceof GuiChest) { + GuiChest eventGui = (GuiChest) Minecraft.getMinecraft().currentScreen; + ContainerChest cc = (ContainerChest) eventGui.inventorySlots; + String containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText(); + if(containerName.trim().startsWith("Accessory Bag")) { + try { + int xSize = (int) Utils.getField(GuiContainer.class, eventGui, "xSize", "field_146999_f"); + int ySize = (int) Utils.getField(GuiContainer.class, eventGui, "ySize", "field_147000_g"); + int guiLeft = (int) Utils.getField(GuiContainer.class, eventGui, "guiLeft", "field_147003_i"); + int guiTop = (int) Utils.getField(GuiContainer.class, eventGui, "guiTop", "field_147009_r"); + + if(accessoryStacks.isEmpty()) { + for(ItemStack stack : Minecraft.getMinecraft().thePlayer.inventory.mainInventory) { + if(stack != null && isAccessory(stack)) { + accessoryStacks.add(stack); + } + } + } + + if(containerName.trim().contains("(")) { + String first = containerName.trim().split("\\(")[1].split("/")[0]; + Integer currentPageNumber = Integer.parseInt(first); + //System.out.println("current:"+currentPageNumber); + if(!pagesVisited.contains(currentPageNumber)) { + boolean hasStack = false; + if(Minecraft.getMinecraft().thePlayer.openContainer instanceof ContainerChest) { + IInventory inv = ((ContainerChest)Minecraft.getMinecraft().thePlayer.openContainer).getLowerChestInventory(); + for(int i=0; i<inv.getSizeInventory(); i++) { + ItemStack stack = inv.getStackInSlot(i); + if(stack != null) { + hasStack = true; + if(isAccessory(stack)) { + accessoryStacks.add(stack); + } + } + } + } + + if(hasStack) pagesVisited.add(currentPageNumber); + } + + String second = containerName.trim().split("/")[1].split("\\)")[0]; + //System.out.println(second + ":" + pagesVisited.size()); + if(Integer.parseInt(second) > pagesVisited.size()) { + Minecraft.getMinecraft().getTextureManager().bindTexture(accessory_bag_overlay); + Utils.drawTexturedRect(guiLeft+xSize+3, guiTop, 80, 149, 0, 80/256f, 0, 149/256f, GL11.GL_NEAREST); + + renderVisitOverlay(guiLeft+xSize+3, guiTop); + return; + } + } else if(pagesVisited.isEmpty()) { + boolean hasStack = false; + if(Minecraft.getMinecraft().thePlayer.openContainer instanceof ContainerChest) { + IInventory inv = ((ContainerChest)Minecraft.getMinecraft().thePlayer.openContainer).getLowerChestInventory(); + for(int i=0; i<inv.getSizeInventory(); i++) { + ItemStack stack = inv.getStackInSlot(i); + if(stack != null) { + hasStack = true; + if(isAccessory(stack)) { + accessoryStacks.add(stack); + } + } + } + } + + if(hasStack) pagesVisited.add(1); + } + + for(int i=0; i<=TAB_MISSING; i++) { + if(i != currentTab) { + Minecraft.getMinecraft().getTextureManager().bindTexture(accessory_bag_overlay); + Utils.drawTexturedRect(guiLeft+xSize+80, guiTop+20*i, 25, 22, + 80/256f, 105/256f, 0, 22/256f, GL11.GL_NEAREST); + Utils.drawItemStack(TAB_STACKS[i], guiLeft+xSize+80+5, guiTop+20*i+3); + } + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(accessory_bag_overlay); + Utils.drawTexturedRect(guiLeft+xSize+3, guiTop, 80, 149, 0, 80/256f, 0, 149/256f, GL11.GL_NEAREST); + + if(pagesVisited.size() < 1) { + renderVisitOverlay(guiLeft+xSize+3, guiTop); + return; + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(accessory_bag_overlay); + Utils.drawTexturedRect(guiLeft+xSize+80, guiTop+20*currentTab, 28, 22, + 80/256f, 108/256f, 22/256f, 44/256f, GL11.GL_NEAREST); + Utils.drawItemStack(TAB_STACKS[currentTab], guiLeft+xSize+80+8, guiTop+20*currentTab+3); + + switch (currentTab) { + case TAB_BASIC: + renderBasicOverlay(guiLeft+xSize+3, guiTop); return; + case TAB_TOTAL: + renderTotalStatsOverlay(guiLeft+xSize+3, guiTop); return; + case TAB_BONUS: + renderReforgeStatsOverlay(guiLeft+xSize+3, guiTop); return; + case TAB_DUP: + renderDuplicatesOverlay(guiLeft+xSize+3, guiTop); return; + case TAB_MISSING: + renderMissingOverlay(guiLeft+xSize+3, guiTop); return; + case TAB_OPTIMIZER: + renderOptimizerOverlay(guiLeft+xSize+3, guiTop); return; + } + } catch(Exception e) { + e.printStackTrace(); + } + } + } + } + + private static void renderAlignedString(String first, String second, float x, float y, int length) { + FontRenderer fontRendererObj = Minecraft.getMinecraft().fontRendererObj; + + if(fontRendererObj.getStringWidth(first + " " + second) >= length) { + for(int xOff=-2; xOff<=2; xOff++) { + for(int yOff=-2; yOff<=2; yOff++) { + if(Math.abs(xOff) != Math.abs(yOff)) { + Utils.drawStringCenteredScaledMaxWidth(Utils.cleanColourNotModifiers(first + " " + second), Minecraft.getMinecraft().fontRendererObj, + x+length/2f+xOff/2f, y+4+yOff/2f, false, length, + new Color(0, 0, 0, 200/Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB()); + } + } + } + + GlStateManager.color(1, 1, 1, 1); + Utils.drawStringCenteredScaledMaxWidth(first + " " + second, Minecraft.getMinecraft().fontRendererObj, + x+length/2f, y+4, false, length, 4210752); + } else { + for(int xOff=-2; xOff<=2; xOff++) { + for(int yOff=-2; yOff<=2; yOff++) { + if(Math.abs(xOff) != Math.abs(yOff)) { + fontRendererObj.drawString(Utils.cleanColourNotModifiers(first), + x+xOff/2f, y+yOff/2f, + new Color(0, 0, 0, 200/Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB(), false); + } + } + } + + int secondLen = fontRendererObj.getStringWidth(second); + GlStateManager.color(1, 1, 1, 1); + fontRendererObj.drawString(first, x, y, 4210752, false); + for(int xOff=-2; xOff<=2; xOff++) { + for(int yOff=-2; yOff<=2; yOff++) { + if(Math.abs(xOff) != Math.abs(yOff)) { + fontRendererObj.drawString(Utils.cleanColourNotModifiers(second), + x+length-secondLen+xOff/2f, y+yOff/2f, + new Color(0, 0, 0, 200/Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB(), false); + } + } + } + + GlStateManager.color(1, 1, 1, 1); + fontRendererObj.drawString(second, x+length-secondLen, y, 4210752, false); + } + } + + private static final Pattern HEALTH_PATTERN_BONUS = Pattern.compile("^Health: (?:\\+|-)[0-9]+ HP \\([a-zA-Z]+ ((?:\\+|-)[0-9]+)"); + private static final Pattern DEFENCE_PATTERN_BONUS = Pattern.compile("^Defense: (?:\\+|-)[0-9]+ \\([a-zA-Z]+ ((?:\\+|-)[0-9]+)"); + private static final Pattern STRENGTH_PATTERN_BONUS = Pattern.compile("^Strength: (?:\\+|-)[0-9]+ \\([a-zA-Z]+ ((?:\\+|-)[0-9]+)"); + private static final Pattern SPEED_PATTERN_BONUS = Pattern.compile("^Speed: (?:\\+|-)[0-9]+ \\([a-zA-Z]+ ((?:\\+|-)[0-9]+)"); + private static final Pattern CC_PATTERN_BONUS = Pattern.compile("^Crit Chance: (?:\\+|-)[0-9]+% \\([a-zA-Z]+ ((?:\\+|-)[0-9]+)"); + private static final Pattern CD_PATTERN_BONUS = Pattern.compile("^Crit Damage: (?:\\+|-)[0-9]+% \\([a-zA-Z]+ ((?:\\+|-)[0-9]+)"); + private static final Pattern ATKSPEED_PATTERN_BONUS = Pattern.compile("^Bonus Attack Speed: (?:\\+|-)[0-9]+% \\([a-zA-Z]+ ((?:\\+|-)[0-9]+)"); + private static final Pattern INTELLIGENCE_PATTERN_BONUS = Pattern.compile("^Intelligence: (?:\\+|-)[0-9]+ \\([a-zA-Z]+ ((?:\\+|-)[0-9]+)"); + private static final Pattern SCC_PATTERN_BONUS = Pattern.compile("^Sea Creature Chance: (?:\\+|-)[0-9]+ \\([a-zA-Z]+ ((?:\\+|-)[0-9]+)"); + private static final HashMap<String, Pattern> STAT_PATTERN_MAP_BONUS = new HashMap<>(); + static { + STAT_PATTERN_MAP_BONUS.put("health", HEALTH_PATTERN_BONUS); + STAT_PATTERN_MAP_BONUS.put("defence", DEFENCE_PATTERN_BONUS); + STAT_PATTERN_MAP_BONUS.put("strength", STRENGTH_PATTERN_BONUS); + STAT_PATTERN_MAP_BONUS.put("speed", SPEED_PATTERN_BONUS); + STAT_PATTERN_MAP_BONUS.put("crit_chance", CC_PATTERN_BONUS); + STAT_PATTERN_MAP_BONUS.put("crit_damage", CD_PATTERN_BONUS); + STAT_PATTERN_MAP_BONUS.put("bonus_attack_speed", ATKSPEED_PATTERN_BONUS); + STAT_PATTERN_MAP_BONUS.put("intelligence", INTELLIGENCE_PATTERN_BONUS); + STAT_PATTERN_MAP_BONUS.put("sea_creature_chance", SCC_PATTERN_BONUS); + } + + private static final Pattern HEALTH_PATTERN = Pattern.compile("^Health: ((?:\\+|-)[0-9]+)"); + private static final Pattern DEFENCE_PATTERN = Pattern.compile("^Defense: ((?:\\+|-)[0-9]+)"); + private static final Pattern STRENGTH_PATTERN = Pattern.compile("^Strength: ((?:\\+|-)[0-9]+)"); + private static final Pattern SPEED_PATTERN = Pattern.compile("^Speed: ((?:\\+|-)[0-9]+)"); + private static final Pattern CC_PATTERN = Pattern.compile("^Crit Chance: ((?:\\+|-)[0-9]+)"); + private static final Pattern CD_PATTERN = Pattern.compile("^Crit Damage: ((?:\\+|-)[0-9]+)"); + private static final Pattern ATKSPEED_PATTERN = Pattern.compile("^Bonus Attack Speed: ((?:\\+|-)[0-9]+)"); + private static final Pattern INTELLIGENCE_PATTERN = Pattern.compile("^Intelligence: ((?:\\+|-)[0-9]+)"); + private static final Pattern SCC_PATTERN = Pattern.compile("^Sea Creature Chance: ((?:\\+|-)[0-9]+)"); + private static final HashMap<String, Pattern> STAT_PATTERN_MAP = new HashMap<>(); + static { + STAT_PATTERN_MAP.put("health", HEALTH_PATTERN); + STAT_PATTERN_MAP.put("defence", DEFENCE_PATTERN); + STAT_PATTERN_MAP.put("strength", STRENGTH_PATTERN); + STAT_PATTERN_MAP.put("speed", SPEED_PATTERN); + STAT_PATTERN_MAP.put("crit_chance", CC_PATTERN); + STAT_PATTERN_MAP.put("crit_damage", CD_PATTERN); + STAT_PATTERN_MAP.put("bonus_attack_speed", ATKSPEED_PATTERN); + STAT_PATTERN_MAP.put("intelligence", INTELLIGENCE_PATTERN); + STAT_PATTERN_MAP.put("sea_creature_chance", SCC_PATTERN); + } + private static PlayerStats.Stats getStatForItem(ItemStack stack, HashMap<String, Pattern> patternMap, boolean addExtras) { + String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack); + NBTTagCompound tag = stack.getTagCompound(); + PlayerStats.Stats stats = new PlayerStats.Stats(); + + if(internalname == null) { + return stats; + } + + if(tag != null) { + NBTTagCompound display = tag.getCompoundTag("display"); + if (display.hasKey("Lore", 9)) { + NBTTagList list = display.getTagList("Lore", 8); + for (int i = 0; i < list.tagCount(); i++) { + String line = list.getStringTagAt(i); + for(Map.Entry<String, Pattern> entry : patternMap.entrySet()) { + Matcher matcher = entry.getValue().matcher(Utils.cleanColour(line)); + if(matcher.find()) { + int bonus = Integer.parseInt(matcher.group(1)); + stats.addStat(entry.getKey(), bonus); + } + } + } + } + } + + if(!addExtras) return stats; + + if(internalname.equals("DAY_CRYSTAL") || internalname.equals("NIGHT_CRYSTAL")) { + stats.addStat(PlayerStats.STRENGTH, 2.5f); + stats.addStat(PlayerStats.DEFENCE, 2.5f); + } + + if(internalname.equals("NEW_YEAR_CAKE_BAG") && tag != null && tag.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + + byte[] bytes = null; + for (String key : ea.getKeySet()) { + if (key.endsWith("backpack_data") || key.equals("new_year_cake_bag_data")) { + bytes = ea.getByteArray(key); + try { + NBTTagCompound contents_nbt = CompressedStreamTools.readCompressed(new ByteArrayInputStream(bytes)); + NBTTagList items = contents_nbt.getTagList("i", 10); + HashSet<Integer> cakes = new HashSet<>(); + for(int j=0; j<items.tagCount(); j++) { + if(items.getCompoundTagAt(j).getKeySet().size() > 0) { + NBTTagCompound nbt = items.getCompoundTagAt(j).getCompoundTag("tag"); + if(nbt != null && nbt.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea2 = nbt.getCompoundTag("ExtraAttributes"); + if (ea2.hasKey("new_years_cake")) { + cakes.add(ea2.getInteger("new_years_cake")); + } + } + } + } + stats.addStat(PlayerStats.HEALTH, cakes.size()); + } catch(IOException e) { + e.printStackTrace(); + return stats; + } + break; + } + } + } + return stats; + } + + private static String[] rarityArr = new String[] { + "COMMON", "UNCOMMON", "RARE", "EPIC", "LEGENDARY", "MYTHIC", "SPECIAL", "VERY SPECIAL", + }; + private static String[] rarityArrC = new String[] { + EnumChatFormatting.WHITE+EnumChatFormatting.BOLD.toString()+"COMMON", + EnumChatFormatting.GREEN+EnumChatFormatting.BOLD.toString()+"UNCOMMON", + EnumChatFormatting.BLUE+EnumChatFormatting.BOLD.toString()+"RARE", + EnumChatFormatting.DARK_PURPLE+EnumChatFormatting.BOLD.toString()+"EPIC", + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD.toString()+"LEGENDARY", + EnumChatFormatting.LIGHT_PURPLE+EnumChatFormatting.BOLD.toString()+"MYTHIC", + EnumChatFormatting.RED+EnumChatFormatting.BOLD.toString()+"SPECIAL", + EnumChatFormatting.RED+EnumChatFormatting.BOLD.toString()+"VERY SPECIAL", + EnumChatFormatting.DARK_RED+EnumChatFormatting.BOLD.toString()+"SUPREME", + }; + public static int checkItemType(ItemStack stack, boolean contains, String... typeMatches) { + NBTTagCompound tag = stack.getTagCompound(); + if(tag != null) { + NBTTagCompound display = tag.getCompoundTag("display"); + if (display.hasKey("Lore", 9)) { + NBTTagList list = display.getTagList("Lore", 8); + for (int i = list.tagCount()-1; i >= 0; i--) { + String line = list.getStringTagAt(i); + for(String rarity : rarityArr) { + for(int j=0; j<typeMatches.length; j++) { + if(contains) { + if(line.trim().contains(rarity + " " + typeMatches[j])) { + return j; + } else if(line.trim().contains(rarity + " DUNGEON " + typeMatches[j])) { + return j; + } + } else { + if(line.trim().endsWith(rarity + " " + typeMatches[j])) { + return j; + } else if(line.trim().endsWith(rarity + " DUNGEON " + typeMatches[j])) { + return j; + } + } + } + } + } + } + } + return -1; + } + private static int checkItemType(JsonArray lore, String... typeMatches) { + for(int i=lore.size()-1; i>=0; i--) { + String line = lore.get(i).getAsString(); + + for(String rarity : rarityArr) { + for(int j=0; j<typeMatches.length; j++) { + if(line.trim().endsWith(rarity + " " + typeMatches[j])) { + return j; + } + } + } + } + return -1; + } + + public static boolean isAccessory(ItemStack stack) { + return checkItemType(stack, true, "ACCESSORY", "HATCCESSORY") >= 0; + } + + public static int getRarity(ItemStack stack) { + NBTTagCompound tag = stack.getTagCompound(); + if(tag != null) { + NBTTagCompound display = tag.getCompoundTag("display"); + if (display.hasKey("Lore", 9)) { + NBTTagList list = display.getTagList("Lore", 8); + for (int i = list.tagCount(); i >= 0; i--) { + String line = list.getStringTagAt(i); + for(int j=0; j<rarityArrC.length; j++) { + if(line.contains(rarityArrC[j])) { + return j; + } + } + } + } + } + return -1; + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/BetterContainers.java b/src/main/java/io/github/moulberry/notenoughupdates/BetterContainers.java new file mode 100644 index 00000000..fac3a8d1 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/BetterContainers.java @@ -0,0 +1,454 @@ +package io.github.moulberry.notenoughupdates; + +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.util.TexLoc; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Keyboard; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Random; + +public class BetterContainers { + + private static final ResourceLocation TOGGLE_OFF = new ResourceLocation("notenoughupdates:dynamic_54/toggle_off.png"); + private static final ResourceLocation TOGGLE_ON = new ResourceLocation("notenoughupdates:dynamic_54/toggle_on.png"); + + private static final ResourceLocation DYNAMIC_54_BASE = new ResourceLocation("notenoughupdates:dynamic_54/style1/dynamic_54.png"); + private static final ResourceLocation DYNAMIC_54_SLOT = new ResourceLocation("notenoughupdates:dynamic_54/style1/dynamic_54_slot_ctm.png"); + private static final ResourceLocation DYNAMIC_54_BUTTON = new ResourceLocation("notenoughupdates:dynamic_54/style1/dynamic_54_button_ctm.png"); + private static final ResourceLocation rl = new ResourceLocation("notenoughupdates:dynamic_chest_inventory.png"); + private static boolean loaded = false; + private static DynamicTexture texture = null; + private static int textColour = 4210752; + + private static int lastClickedSlot = 0; + private static int clickedSlot = 0; + private static long clickedSlotMillis = 0; + public static long lastRenderMillis = 0; + + public static HashMap<Integer, ItemStack> itemCache = new HashMap<>(); + public static boolean lastUsingCached = false; + public static boolean usingCached = false; + + public static void clickSlot(int slot) { + clickedSlotMillis = System.currentTimeMillis(); + clickedSlot = slot; + } + + public static int getClickedSlot() { + if(System.currentTimeMillis() - clickedSlotMillis < 500) { + return clickedSlot; + } + return -1; + } + + public static void bindHook(TextureManager textureManager, ResourceLocation location) { + if(isChestOpen()) { + Container container = ((GuiChest)Minecraft.getMinecraft().currentScreen).inventorySlots; + if(container instanceof ContainerChest) { + usingCached = true; + IInventory lower = ((ContainerChest)container).getLowerChestInventory(); + int size = lower.getSizeInventory(); + for(int index=0; index<size; index++) { + if(lower.getStackInSlot(index) != null) { + for(int index2=0; index2<size; index2++) { + itemCache.put(index2, lower.getStackInSlot(index2)); + } + usingCached = false; + break; + } + } + } + + if((texture != null && loaded && lastClickedSlot != getClickedSlot()) || + lastUsingCached != getUsingCache() || + (texture == null && !loaded)) { + lastUsingCached = getUsingCache(); + lastClickedSlot = getClickedSlot(); + generateTex(location); + } + if(texture != null && loaded) { + if(!usingCached) lastRenderMillis = System.currentTimeMillis(); + lastRenderMillis = System.currentTimeMillis(); + textureManager.loadTexture(rl, texture); + textureManager.bindTexture(rl); + return; + } + } + textureManager.bindTexture(location); + } + + public static boolean getUsingCache() { + return usingCached && System.currentTimeMillis() - lastRenderMillis < 300; + } + + public static boolean isAh() { + if(!isChestOpen()) return false; + + GuiChest eventGui = (GuiChest) Minecraft.getMinecraft().currentScreen; + ContainerChest cc = (ContainerChest) eventGui.inventorySlots; + String containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText(); + return containerName.trim().startsWith("Auctions Browser") || containerName.trim().startsWith("Wardrobe"); + } + + public static boolean isOverriding() { + return isChestOpen() && ((loaded && texture != null)); + } + + public static boolean isBlankStack(ItemStack stack) { + return stack != null && stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane) && + stack.getDisplayName() != null && stack.getDisplayName().trim().isEmpty(); + } + + public static boolean shouldRenderStack(ItemStack stack) { + return !isBlankStack(stack) && !isToggleOff(stack) && !isToggleOn(stack); + } + + public static boolean isButtonStack(ItemStack stack) { + return stack != null && stack.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane) + && NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack) == null && !isToggleOn(stack) && !isToggleOff(stack); + } + + public static int getTextColour() { + return textColour; + } + + public static boolean isToggleOn(ItemStack stack) { + if(stack != null && stack.getTagCompound() != null && stack.getTagCompound().hasKey("display", 10) && + stack.getTagCompound().getCompoundTag("display").hasKey("Lore", 9)) { + NBTTagList lore = stack.getTagCompound().getCompoundTag("display").getTagList("Lore", 8); + if(lore.tagCount() == 1 && lore.getStringTagAt(0).equalsIgnoreCase(EnumChatFormatting.GRAY+"click to disable!")) { + return true; + } + } + return false; + } + + public static boolean isToggleOff(ItemStack stack) { + if(stack != null && stack.getTagCompound() != null && stack.getTagCompound().hasKey("display", 10) && + stack.getTagCompound().getCompoundTag("display").hasKey("Lore", 9)) { + NBTTagList lore = stack.getTagCompound().getCompoundTag("display").getTagList("Lore", 8); + if(lore.tagCount() == 1 && lore.getStringTagAt(0).equalsIgnoreCase(EnumChatFormatting.GRAY+"click to enable!")) { + return true; + } + } + return false; + } + + private static void generateTex(ResourceLocation location) { + if(!hasItem()) return; + texture = null; + loaded = true; + Container container = ((GuiChest)Minecraft.getMinecraft().currentScreen).inventorySlots; + + if(hasNullPane() && container instanceof ContainerChest) { + int backgroundStyle = NotEnoughUpdates.INSTANCE.manager.config.dynamicMenuBackgroundStyle.value.intValue(); + backgroundStyle = Math.max(1, Math.min(10, backgroundStyle)); + try(BufferedReader reader = new BufferedReader(new InputStreamReader(Minecraft.getMinecraft().getResourceManager().getResource( + new ResourceLocation("notenoughupdates:dynamic_54/style"+ backgroundStyle+"/dynamic_config.json")).getInputStream(), StandardCharsets.UTF_8))) { + JsonObject json = NotEnoughUpdates.INSTANCE.manager.gson.fromJson(reader, JsonObject.class); + String textColourS = json.get("text-colour").getAsString(); + textColour = (int)Long.parseLong(textColourS, 16); + } catch(Exception e) { + textColour = 4210752; + e.printStackTrace(); + } + + try { + BufferedImage bufferedImageOn = ImageIO.read(Minecraft.getMinecraft().getResourceManager().getResource(TOGGLE_ON).getInputStream()); + BufferedImage bufferedImageOff = ImageIO.read(Minecraft.getMinecraft().getResourceManager().getResource(TOGGLE_OFF).getInputStream()); + + BufferedImage bufferedImageBase = ImageIO.read(Minecraft.getMinecraft().getResourceManager().getResource(DYNAMIC_54_BASE).getInputStream()); + try { + bufferedImageBase = ImageIO.read(Minecraft.getMinecraft().getResourceManager().getResource( + new ResourceLocation("notenoughupdates:dynamic_54/style"+ backgroundStyle+"/dynamic_54.png")).getInputStream()); + } catch(Exception e) {} + BufferedImage bufferedImageSlot = ImageIO.read(Minecraft.getMinecraft().getResourceManager().getResource(DYNAMIC_54_SLOT).getInputStream()); + try { + int buttonStyle = NotEnoughUpdates.INSTANCE.manager.config.dynamicMenuButtonStyle.value.intValue(); + buttonStyle = Math.max(1, Math.min(10, buttonStyle)); + bufferedImageSlot = ImageIO.read(Minecraft.getMinecraft().getResourceManager().getResource( + new ResourceLocation("notenoughupdates:dynamic_54/style"+buttonStyle+"/dynamic_54_slot_ctm.png")).getInputStream()); + } catch(Exception e) {} + BufferedImage bufferedImageButton = ImageIO.read(Minecraft.getMinecraft().getResourceManager().getResource(DYNAMIC_54_BUTTON).getInputStream()); + try { + int buttonStyle = NotEnoughUpdates.INSTANCE.manager.config.dynamicMenuButtonStyle.value.intValue(); + buttonStyle = Math.max(1, Math.min(10, buttonStyle)); + bufferedImageButton = ImageIO.read(Minecraft.getMinecraft().getResourceManager().getResource( + new ResourceLocation("notenoughupdates:dynamic_54/style"+buttonStyle+"/dynamic_54_button_ctm.png")).getInputStream()); + } catch(Exception e) {} + + int horzTexMult = bufferedImageBase.getWidth()/256; + int vertTexMult = bufferedImageBase.getWidth()/256; + BufferedImage bufferedImageNew = new BufferedImage( + bufferedImageBase.getColorModel(), + bufferedImageBase.copyData(null), + bufferedImageBase.isAlphaPremultiplied(), + null); + IInventory lower = ((ContainerChest) container).getLowerChestInventory(); + int size = lower.getSizeInventory(); + boolean[][] slots = new boolean[9][size/9]; + boolean[][] buttons = new boolean[9][size/9]; + for (int index = 0; index < size; index++) { + ItemStack stack = getStackCached(lower, index); + buttons[index%9][index/9] = isButtonStack(stack); + + if(buttons[index%9][index/9] && lastClickedSlot == index) { + buttons[index%9][index/9] = false; + slots[index%9][index/9] = true; + } else { + slots[index%9][index/9] = !isBlankStack(stack) && !buttons[index%9][index/9]; + } + } + for (int index = 0; index < size; index++) { + ItemStack stack = getStackCached(lower, index); + int xi = index%9; + int yi = index/9; + if(slots[xi][yi] || buttons[xi][yi]) { + int x = 7*horzTexMult + xi*18*horzTexMult; + int y = 17*vertTexMult + yi*18*vertTexMult; + + boolean on = isToggleOn(stack); + boolean off = isToggleOff(stack); + + if(on || off) { + for(int x2=0; x2<18; x2++) { + for(int y2=0; y2<18; y2++) { + BufferedImage toggle = on ? bufferedImageOn : bufferedImageOff; + Color c = new Color(toggle.getRGB(x2, y2), true); + if(c.getAlpha() < 10) { + continue; + } + bufferedImageNew.setRGB(x+x2, y+y2, c.getRGB()); + } + } + continue; + } + + if(buttons[xi][yi]) { + boolean up = yi > 0 && buttons[xi][yi-1]; + boolean right = xi < buttons.length-1 && buttons[xi+1][yi]; + boolean down = yi < buttons[xi].length-1 && buttons[xi][yi+1]; + boolean left = xi > 0 && buttons[xi-1][yi]; + + boolean upleft = yi > 0 && xi > 0 && buttons[xi-1][yi-1]; + boolean upright = yi > 0 && xi < buttons.length-1 && buttons[xi+1][yi-1]; + boolean downright = xi < buttons.length-1 && yi < buttons[xi+1].length-1 && buttons[xi+1][yi+1]; + boolean downleft = xi > 0 && yi < buttons[xi-1].length-1 && buttons[xi-1][yi+1]; + + int ctmIndex = getCTMIndex(up, right, down, left, upleft, upright, downright, downleft); + int[] rgbs = bufferedImageButton.getRGB((ctmIndex%12)*19*horzTexMult, (ctmIndex/12)*19*vertTexMult, + 18*horzTexMult, 18*vertTexMult, null, 0, 18*vertTexMult); + bufferedImageNew.setRGB(x, y, 18*horzTexMult, 18*vertTexMult, rgbs, 0, 18*vertTexMult); + + } else { + boolean up = yi > 0 && slots[xi][yi-1]; + boolean right = xi < slots.length-1 && slots[xi+1][yi]; + boolean down = yi < slots[xi].length-1 && slots[xi][yi+1]; + boolean left = xi > 0 && slots[xi-1][yi]; + + boolean upleft = yi > 0 && xi > 0 && slots[xi-1][yi-1]; + boolean upright = yi > 0 && xi < slots.length-1 && slots[xi+1][yi-1]; + boolean downright = xi < slots.length-1 && yi < slots[xi+1].length-1 && slots[xi+1][yi+1]; + boolean downleft = xi > 0 && yi < slots[xi-1].length-1 && slots[xi-1][yi+1]; + + int ctmIndex = getCTMIndex(up, right, down, left, upleft, upright, downright, downleft); + int[] rgbs = bufferedImageSlot.getRGB((ctmIndex%12)*19*horzTexMult, (ctmIndex/12)*19*vertTexMult, + 18*horzTexMult, 18*vertTexMult, null, 0, 18*vertTexMult); + bufferedImageNew.setRGB(x, y, 18*horzTexMult, 18*vertTexMult, rgbs, 0, 18*vertTexMult); + } + } + } + texture = new DynamicTexture(bufferedImageNew); + } catch(Exception e) { + e.printStackTrace(); + } + } + } + + public static void reset() { + texture = null; + loaded = false; + clickedSlot = -1; + clickedSlotMillis = 0; + textColour = 4210752; + } + + private static boolean isChestOpen() { + return Minecraft.getMinecraft().currentScreen instanceof GuiChest && + NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() && + (NotEnoughUpdates.INSTANCE.manager.config.dynamicMenuBackgroundStyle.value >= 1 && + NotEnoughUpdates.INSTANCE.manager.config.dynamicMenuButtonStyle.value >= 1); + } + + private static boolean hasItem() { + if(!isChestOpen()) return false; + Container container = ((GuiChest)Minecraft.getMinecraft().currentScreen).inventorySlots; + if(container instanceof ContainerChest) { + IInventory lower = ((ContainerChest)container).getLowerChestInventory(); + int size = lower.getSizeInventory(); + for(int index=0; index<size; index++) { + if(getStackCached(lower, index) != null) return true; + } + } + return false; + } + + private static ItemStack getStackCached(IInventory lower, int index) { + if(getUsingCache()) { + return itemCache.get(index); + } else { + return lower.getStackInSlot(index); + } + } + + private static boolean hasNullPane() { + if(!isChestOpen()) return false; + Container container = ((GuiChest)Minecraft.getMinecraft().currentScreen).inventorySlots; + if(container instanceof ContainerChest) { + IInventory lower = ((ContainerChest)container).getLowerChestInventory(); + int size = lower.getSizeInventory(); + for(int index=0; index<size; index++) { + if(isBlankStack(getStackCached(lower, index))) return true; + } + } + return false; + } + + private static int getCTMIndex(boolean up, boolean right, boolean down, boolean left, boolean upleft, boolean upright, boolean downright, boolean downleft) { + if(up && right && down && left) { + if(upleft && upright && downright && downleft) { + return 26; + } else if(upleft && upright && downright && !downleft) { + return 33; + } else if(upleft && upright && !downright && downleft) { + return 32; + } else if(upleft && upright && !downright && !downleft) { + return 11; + } else if(upleft && !upright && downright && downleft) { + return 44; + } else if(upleft && !upright && downright && !downleft) { + return 35; + } else if(upleft && !upright && !downright && downleft) { + return 10; + } else if(upleft && !upright && !downright && !downleft) { + return 20; + } else if(!upleft && upright && downright && downleft) { + return 45; + } else if(!upleft && upright && downright && !downleft) { + return 23; + } else if(!upleft && upright && !downright && downleft) { + return 34; + } else if(!upleft && upright && !downright && !downleft) { + return 8; + } else if(!upleft && !upright && downright && downleft) { + return 22; + } else if(!upleft && !upright && downright && !downleft) { + return 9; + } else if(!upleft && !upright && !downright && downleft) { + return 21; + } else { + return 46; + } + } else if(up && right && down && !left) { + if(!upright && !downright) { + return 6; + } else if(!upright) { + return 28; + } else if(!downright) { + return 30; + } else { + return 25; + } + } else if(up && right && !down && left) { + if(!upleft && !upright) { + return 18; + } else if(!upleft) { + return 40; + } else if(!upright) { + return 42; + } else { + return 38; + } + } else if(up && right && !down && !left) { + if(!upright) { + return 16; + } else { + return 37; + } + } else if(up && !right && down && left) { + if(!upleft && !downleft) { + return 19; + } else if(!upleft) { + return 43; + } else if(!downleft) { + return 41; + } else { + return 27; + } + } else if(up && !right && down && !left) { + return 24; + } else if(up && !right && !down && left) { + if(!upleft) { + return 17; + } else { + return 39; + } + } else if(up && !right && !down && !left) { + return 36; + } else if(!up && right && down && left) { + if(!downleft && !downright) { + return 7; + } else if(!downleft) { + return 31; + } else if(!downright) { + return 29; + } else { + return 14; + } + } else if(!up && right && down && !left) { + if(!downright) { + return 4; + } else { + return 13; + } + } else if(!up && right && !down && left) { + return 2; + } else if(!up && right && !down && !left) { + return 1; + } else if(!up && !right && down && left) { + if(!downleft) { + return 5; + } else { + return 15; + } + } else if(!up && !right && down && !left) { + return 12; + } else if(!up && !right && !down && left) { + return 3; + } else { + return 0; + } + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/BetterPortals.java b/src/main/java/io/github/moulberry/notenoughupdates/BetterPortals.java new file mode 100644 index 00000000..8c512164 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/BetterPortals.java @@ -0,0 +1,206 @@ +package io.github.moulberry.notenoughupdates; + +import io.github.moulberry.notenoughupdates.util.TexLoc; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityArmorStand; +import net.minecraft.init.Blocks; +import net.minecraft.util.BlockPos; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.client.event.RenderWorldEvent; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.event.world.WorldEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.glu.GLU; +import org.lwjgl.util.vector.Vector3f; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.*; + +public class BetterPortals extends Gui { + + private Set<Vector3f> loadedPortals = new HashSet<>(); + private HashMap<BlockPos, String> portalNameMap = new HashMap<>(); + + @SubscribeEvent + public void onWorldChange(WorldEvent.Load event) { + portalNameMap.clear(); + loadedPortals.clear(); + } + + /** The current GL viewport */ + private static final IntBuffer VIEWPORT = GLAllocation.createDirectIntBuffer(16); + /** The current GL modelview matrix */ + private static final FloatBuffer MODELVIEW = GLAllocation.createDirectFloatBuffer(16); + /** The current GL projection matrix */ + private static final FloatBuffer PROJECTION = GLAllocation.createDirectFloatBuffer(16); + private static final FloatBuffer WINCOORDS = GLAllocation.createDirectFloatBuffer(3); + + private float getFOVModifier(float partialTicks) { + Entity entity = Minecraft.getMinecraft().getRenderViewEntity(); + + float f = Minecraft.getMinecraft().gameSettings.fovSetting; + //f = f * (this.fovModifierHandPrev + (this.fovModifierHand - this.fovModifierHandPrev) * partialTicks); + + if (entity instanceof EntityLivingBase && ((EntityLivingBase)entity).getHealth() <= 0.0F) { + float f1 = (float)((EntityLivingBase)entity).deathTime + partialTicks; + f /= (1.0F - 500.0F / (f1 + 500.0F)) * 2.0F + 1.0F; + } + + Block block = ActiveRenderInfo.getBlockAtEntityViewpoint(Minecraft.getMinecraft().theWorld, entity, partialTicks); + + if (block.getMaterial() == Material.water) { + f = f * 60.0F / 70.0F; + } + + return net.minecraftforge.client.ForgeHooksClient.getFOVModifier(Minecraft.getMinecraft().entityRenderer, entity, block, partialTicks, f); + } + + TexLoc tl = new TexLoc(0, 1, Keyboard.KEY_M); + + @SubscribeEvent + public void renderWorld(RenderGameOverlayEvent event) { + + GlStateManager.getFloat(2982, MODELVIEW); + GlStateManager.getFloat(2983, PROJECTION); + GL11.glGetInteger(GL11.GL_VIEWPORT, VIEWPORT); + + EntityPlayerSP player = Minecraft.getMinecraft().thePlayer; + GlStateManager.disableCull(); + + tl.handleKeyboardInput(); + + WINCOORDS.flip().limit(3); + + /*float objx = -(float)(0-player.posX); + float objy = (float)(100-player.posY-player.eyeHeight); + float objz = (float)(0-player.posZ);*/ + + float dX = -(float)(0-player.posX); + float dY = (float)(100-player.posY-player.eyeHeight); + float dZ = (float)(0-player.posZ); + + //GLU.gluProject(objx, objy, objz, MODELVIEW, PROJECTION, VIEWPORT, WINCOORDS); + + double x = dX*Math.cos(Math.toRadians(player.rotationYawHead))-dZ*Math.sin(Math.toRadians(player.rotationYawHead)); + double z = dX*Math.sin(Math.toRadians(player.rotationYawHead))+dZ*Math.cos(Math.toRadians(player.rotationYawHead)); + + float fov = getFOVModifier(event.partialTicks); + x = x / z * Math.toRadians(fov); + dY = (float)(dY / z * Math.toRadians(fov)); + + //System.out.println(z); + + //GLU.gluProject((float)x, dY, (float)z, MODELVIEW, PROJECTION, VIEWPORT, WINCOORDS); + //x = x / z * 2; + //dY = (float)(dY / z * 2); + + GL11.glEnable(GL11.GL_SCISSOR_TEST); + + GL11.glScissor((int)(x*Minecraft.getMinecraft().displayWidth*tl.x/tl.y)+Minecraft.getMinecraft().displayWidth/2, + (int)(dY+Minecraft.getMinecraft().displayHeight/2), 2, 2); + + drawRect(0, 0, 2000, 2000, -1); + + GL11.glDisable(GL11.GL_SCISSOR_TEST); + + /*for(BlockPos pos : portalNameMap.keySet()) { + WINCOORDS.flip().limit(3); + + /*float objx = -(float)((pos.getX()-player.posX)*Math.cos(Math.toRadians(player.rotationYawHead))*Math.cos(Math.toRadians(player.rotationPitch))); + float objy = (float)((pos.getY()-player.posY)*Math.sin(Math.toRadians(player.rotationPitch))); + float objz = (float)((pos.getZ()-player.posZ)*Math.sin(Math.toRadians(player.rotationYawHead))); + + float objx = -(float)(pos.getX()-player.posX); + float objy = (float)(pos.getY()-player.posY-player.eyeHeight); + float objz = (float)(pos.getZ()-player.posZ); + + GLU.gluProject(objx, objy, objz, MODELVIEW, PROJECTION, VIEWPORT, WINCOORDS); + //GLU.glu + + GL11.glEnable(GL11.GL_SCISSOR_TEST); + + //System.out.println(WINCOORDS.get(1)); + + GL11.glScissor((int)WINCOORDS.get(0)*2, + Minecraft.getMinecraft().displayHeight-(int)WINCOORDS.get(1), (int)50, (int)50); + + //0-1 + //-1 - 1 + //0-1920 + + drawRect(0, 0, 2000, 2000, -1); + + GL11.glDisable(GL11.GL_SCISSOR_TEST); + }*/ + + GlStateManager.enableCull(); + } + + @SubscribeEvent + public void tick(TickEvent.ClientTickEvent event) { + if(Minecraft.getMinecraft().theWorld != null) { + List<Vector3f> travelToPositions = new ArrayList<>(); + for(Entity entity : Minecraft.getMinecraft().theWorld.loadedEntityList) { + if(entity instanceof EntityArmorStand) { + EntityArmorStand armorStand = (EntityArmorStand) entity; + if(armorStand.isInvisible() && armorStand.hasCustomName()) { + String customName = armorStand.getCustomNameTag(); + if(customName.equals(EnumChatFormatting.AQUA+"Travel to:")) { + travelToPositions.add(new Vector3f((float)armorStand.posX, (float)armorStand.posY, (float)armorStand.posZ)); + } + } + } + } + travelToPositions.removeAll(loadedPortals); + for(Entity entity : Minecraft.getMinecraft().theWorld.loadedEntityList) { + if(entity instanceof EntityArmorStand) { + EntityArmorStand armorStand = (EntityArmorStand) entity; + if(armorStand.isInvisible() && armorStand.hasCustomName()) { + String customName = armorStand.getCustomNameTag(); + for(Vector3f position : travelToPositions) { + if(position.x == (float)armorStand.posX && position.y-0.375 == (float)armorStand.posY && position.z == (float)armorStand.posZ) { + float smallestDist = 999; + BlockPos closestPortal = null; + for(int xOff=-3; xOff<=3; xOff++) { + for(int zOff=-3; zOff<=3; zOff++) { + if(xOff != 0 && zOff != 0) continue; + BlockPos pos = new BlockPos(armorStand.posX+xOff, armorStand.posY+2, armorStand.posZ+zOff); + if(Minecraft.getMinecraft().theWorld.getBlockState(pos).getBlock() == Blocks.portal) { + float dist = (float)(armorStand.posX-(pos.getX()+0.5) + armorStand.posZ-(pos.getZ()+0.5)); + if(closestPortal == null || dist < smallestDist) { + smallestDist = dist; + closestPortal = pos; + } + } + } + } + if(closestPortal != null) { + portalNameMap.put(closestPortal, customName); + } + } + } + } + } + } + loadedPortals.addAll(travelToPositions); + } + } + + public void tryRegisterPortal() { + + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/CustomItemEffects.java b/src/main/java/io/github/moulberry/notenoughupdates/CustomItemEffects.java new file mode 100644 index 00000000..0fa4aa96 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/CustomItemEffects.java @@ -0,0 +1,605 @@ +package io.github.moulberry.notenoughupdates; + +import io.github.moulberry.notenoughupdates.util.SpecialColour; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.BlockState; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.texture.TextureUtil; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.resources.model.IBakedModel; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagByteArray; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.*; +import net.minecraftforge.client.event.DrawBlockHighlightEvent; +import net.minecraftforge.client.event.EntityViewRenderEvent; +import net.minecraftforge.client.event.RenderBlockOverlayEvent; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.vector.Vector3f; +import scala.tools.cmd.Spec; + +import java.awt.*; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.*; +import java.util.List; + +public class CustomItemEffects { + + public static final CustomItemEffects INSTANCE = new CustomItemEffects(); + + private static final int MAX_BUILDERS_BLOCKS = 164; + + public long aoteUseMillis = 0; + public int aoteTeleportationMillis = 0; + public Vector3f aoteTeleportationCurr = null; + + public long lastMillis = 0; + + public Vector3f getCurrentPosition() { + if(aoteTeleportationMillis <= 0) return null; + return aoteTeleportationCurr; + } + + @SubscribeEvent + public void onTick(TickEvent.RenderTickEvent event) { + //if(aoteTeleportationTicks > 7) aoteTeleportationTicks = 7; + long currentTime = System.currentTimeMillis(); + int delta = (int)(currentTime - lastMillis); + lastMillis = currentTime; + + if(delta <= 0) return; + + if(aoteTeleportationMillis > NotEnoughUpdates.INSTANCE.manager.config.smoothAoteMillis.value.intValue()*2) { + aoteTeleportationMillis = NotEnoughUpdates.INSTANCE.manager.config.smoothAoteMillis.value.intValue()*2; + } + if(aoteTeleportationMillis < 0) aoteTeleportationMillis = 0; + + if(currentTime - aoteUseMillis > 1000 && aoteTeleportationMillis <= 0) { + aoteTeleportationCurr = null; + } + + if(aoteTeleportationCurr != null) { + if(aoteTeleportationMillis > 0) { + int deltaMin = Math.min(delta, aoteTeleportationMillis); + + float factor = deltaMin/(float)aoteTeleportationMillis; + + float dX = aoteTeleportationCurr.x - (float)Minecraft.getMinecraft().thePlayer.posX; + float dY = aoteTeleportationCurr.y - (float)Minecraft.getMinecraft().thePlayer.posY; + float dZ = aoteTeleportationCurr.z - (float)Minecraft.getMinecraft().thePlayer.posZ; + + aoteTeleportationCurr.x -= dX*factor; + aoteTeleportationCurr.y -= dY*factor; + aoteTeleportationCurr.z -= dZ*factor; + + if(Minecraft.getMinecraft().theWorld.getBlockState(new BlockPos(aoteTeleportationCurr.x, + aoteTeleportationCurr.y, aoteTeleportationCurr.z)).getBlock().getMaterial() != Material.air) { + aoteTeleportationCurr.y = (float)Math.ceil(aoteTeleportationCurr.y); + } + + aoteTeleportationMillis -= deltaMin; + } else { + aoteTeleportationCurr.x = (float) Minecraft.getMinecraft().thePlayer.posX; + aoteTeleportationCurr.y = (float) Minecraft.getMinecraft().thePlayer.posY; + aoteTeleportationCurr.z = (float) Minecraft.getMinecraft().thePlayer.posZ; + } + } else { + aoteUseMillis = 0; + aoteTeleportationMillis = 0; + } + } + + @SubscribeEvent + public void onPlayerInteract(PlayerInteractEvent event) { + if(NotEnoughUpdates.INSTANCE.manager.config.smoothAoteMillis.value <= 0 + || Minecraft.getMinecraft().gameSettings.thirdPersonView != 0) return; + + if(event.action == PlayerInteractEvent.Action.RIGHT_CLICK_AIR || event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) { + ItemStack held = Minecraft.getMinecraft().thePlayer.getHeldItem(); + if(held != null) { + String internal = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(held); + if(internal != null && internal.equals("ASPECT_OF_THE_END")) { + aoteUseMillis = System.currentTimeMillis(); + if(aoteTeleportationCurr == null) { + aoteTeleportationCurr = new Vector3f(); + aoteTeleportationCurr.x = (float) Minecraft.getMinecraft().thePlayer.posX; + aoteTeleportationCurr.y = (float) Minecraft.getMinecraft().thePlayer.posY; + aoteTeleportationCurr.z = (float) Minecraft.getMinecraft().thePlayer.posZ; + } + } + } + } + } + + @SubscribeEvent + public void onOverlayDrawn(RenderGameOverlayEvent event) { + if(!NotEnoughUpdates.INSTANCE.manager.config.disableWandOverlay.value && + Minecraft.getMinecraft().objectMouseOver != null && + Minecraft.getMinecraft().objectMouseOver.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK && + ((event.type == null && Loader.isModLoaded("labymod")) || + event.type == RenderGameOverlayEvent.ElementType.CROSSHAIRS)) { + + IBlockState hover = Minecraft.getMinecraft().theWorld.getBlockState( + Minecraft.getMinecraft().objectMouseOver.getBlockPos().offset( + Minecraft.getMinecraft().objectMouseOver.sideHit, 1)); + if(hover.getBlock() == Blocks.air) { + ItemStack held = Minecraft.getMinecraft().thePlayer.getHeldItem(); + String heldInternal = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(held); + + if(heldInternal != null && heldInternal.equals("BUILDERS_WAND")) { + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + + HashSet<BlockPos> candidatesOld = new HashSet<>(); + TreeMap<Float, Set<BlockPos>> candidatesOldSorted = new TreeMap<>(); + + IBlockState match = Minecraft.getMinecraft().theWorld.getBlockState(Minecraft.getMinecraft().objectMouseOver.getBlockPos()); + Item matchItem = Item.getItemFromBlock(match.getBlock()); + if(matchItem != null) { + ItemStack matchStack = new ItemStack(matchItem, 1, + match.getBlock().getDamageValue(Minecraft.getMinecraft().theWorld, Minecraft.getMinecraft().objectMouseOver.getBlockPos())); + int itemCount = countItemsInInventoryAndStorage(matchStack); + + getBuildersWandCandidates(Minecraft.getMinecraft().thePlayer, Minecraft.getMinecraft().objectMouseOver, event.partialTicks, + candidatesOld, candidatesOldSorted, 999-MAX_BUILDERS_BLOCKS); + + if(candidatesOld.size() > MAX_BUILDERS_BLOCKS) { + Utils.drawStringCentered(EnumChatFormatting.RED.toString()+candidatesOld.size()+"/"+MAX_BUILDERS_BLOCKS, + Minecraft.getMinecraft().fontRendererObj, + scaledResolution.getScaledWidth()/2f, scaledResolution.getScaledHeight()/2f+10, true, 0); + } else { + String pre = EnumChatFormatting.GREEN.toString(); + if(itemCount < candidatesOld.size()) { + pre = EnumChatFormatting.RED.toString(); + } + Utils.drawStringCentered(pre+Math.min(candidatesOld.size(), itemCount)+"/"+ + Math.min(candidatesOld.size(), MAX_BUILDERS_BLOCKS), + Minecraft.getMinecraft().fontRendererObj, + scaledResolution.getScaledWidth()/2f, scaledResolution.getScaledHeight()/2f+10, true, 0); + } + + String itemCountS = EnumChatFormatting.DARK_GRAY+"x"+EnumChatFormatting.RESET+countItemsInInventoryAndStorage(matchStack); + int itemCountLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth(itemCountS); + + if(NotEnoughUpdates.INSTANCE.manager.config.wandBlockCount.value) { + Utils.drawItemStack(matchStack, scaledResolution.getScaledWidth()/2 - (itemCountLen+16)/2, scaledResolution.getScaledHeight()/2+10+4); + Minecraft.getMinecraft().fontRendererObj.drawString(itemCountS, + scaledResolution.getScaledWidth()/2f - (itemCountLen+16)/2f+16, scaledResolution.getScaledHeight()/2f+10+8, + -1, + true); + } + + GlStateManager.color(1, 1, 1, 1); + } + + } + } + } + } + + public int countItemsInInventoryAndStorage(ItemStack match) { + int count = 0; + + for(ItemStack stack : Minecraft.getMinecraft().thePlayer.inventory.mainInventory) { + if(match.isItemEqual(stack)) { + count += stack.stackSize; + } + } + + ItemStack held = Minecraft.getMinecraft().thePlayer.getHeldItem(); + String heldInternal = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(held); + + if(heldInternal != null && heldInternal.equals("BUILDERS_WAND")) { + //System.out.println("1"); + if(held.hasTagCompound() && held.getTagCompound().hasKey("ExtraAttributes", 10) && + held.getTagCompound().getCompoundTag("ExtraAttributes").hasKey("builder's_wand_data", 7)) { + //System.out.println("2"); + byte[] bytes = held.getTagCompound().getCompoundTag("ExtraAttributes").getByteArray("builder's_wand_data"); + try { + NBTTagCompound contents_nbt = CompressedStreamTools.readCompressed(new ByteArrayInputStream(bytes)); + NBTTagList items = contents_nbt.getTagList("i", 10); + for(int j=0; j<items.tagCount(); j++) { + NBTTagCompound buildersItem = items.getCompoundTagAt(j); + if(buildersItem.getKeySet().size() > 0) { + if(buildersItem.getInteger("id") == Item.getIdFromItem(match.getItem())) { + count += items.getCompoundTagAt(j).getByte("Count"); + } + } + } + } catch(Exception e) { + return count; + } + } + } + + return count; + } + + @SubscribeEvent + public void renderBlockOverlay(DrawBlockHighlightEvent event) { + if(aoteTeleportationCurr != null && aoteTeleportationMillis > 0) { + event.setCanceled(true); + } + ItemStack held = Minecraft.getMinecraft().thePlayer.getHeldItem(); + String heldInternal = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(held); + if(heldInternal != null) { + if(!NotEnoughUpdates.INSTANCE.manager.config.disableTreecapOverlay.value && + (heldInternal.equals("JUNGLE_AXE") || heldInternal.equals("TREECAPITATOR_AXE"))) { + int maxWood = 10; + if(heldInternal.equals("TREECAPITATOR_AXE")) maxWood = 35; + + if (event.target.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) { + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.color(0.0F, 0.0F, 0.0F, 0.4F); + GlStateManager.disableTexture2D(); + GlStateManager.depthMask(false); + + if(Minecraft.getMinecraft().theWorld.getBlockState(event.target.getBlockPos()).getBlock() == Blocks.log || + Minecraft.getMinecraft().theWorld.getBlockState(event.target.getBlockPos()).getBlock() == Blocks.log2) { + EntityPlayer player = event.player; + + int woods = 0; + + HashSet<BlockPos> candidatesOld = new HashSet<>(); + LinkedList<BlockPos> candidates = new LinkedList<>(); + LinkedList<BlockPos> candidatesNew = new LinkedList<>(); + + candidatesNew.add(event.target.getBlockPos()); + + while(woods < maxWood) { + if(candidatesNew.isEmpty()) { + break; + } + + candidates.addAll(candidatesNew); + candidatesNew.clear(); + + woods += candidates.size(); + boolean random = woods > maxWood; + + while(!candidates.isEmpty()) { + BlockPos candidate = candidates.pop(); + Block block = Minecraft.getMinecraft().theWorld.getBlockState(candidate).getBlock(); + + candidatesOld.add(candidate); + + for(int x = -1; x <= 1; x++) { + for(int y = -1; y <= 1; y++) { + for(int z = -1; z <= 1; z++) { + if(x != 0 || y != 0 || z != 0) { + BlockPos posNew = candidate.add(x, y, z); + if(!candidatesOld.contains(posNew) && !candidates.contains(posNew) && !candidatesNew.contains(posNew)) { + Block blockNew = Minecraft.getMinecraft().theWorld.getBlockState(posNew).getBlock(); + if(blockNew == Blocks.log || blockNew == Blocks.log2) { + candidatesNew.add(posNew); + } + } + } + } + } + } + + block.setBlockBoundsBasedOnState(Minecraft.getMinecraft().theWorld, candidate); + double d0 = player.lastTickPosX + (player.posX - player.lastTickPosX) * (double)event.partialTicks; + double d1 = player.lastTickPosY + (player.posY - player.lastTickPosY) * (double)event.partialTicks; + double d2 = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * (double)event.partialTicks; + + drawFilledBoundingBox(block.getSelectedBoundingBox(Minecraft.getMinecraft().theWorld, candidate) + .expand(0.001D, 0.001D, 0.001D).offset(-d0, -d1, -d2), + random ? 0.5f : 1f, NotEnoughUpdates.INSTANCE.manager.config.treecapOverlayColour.value); + } + } + } + + GlStateManager.depthMask(true); + GlStateManager.enableTexture2D(); + GlStateManager.disableBlend(); + } + } else if(!NotEnoughUpdates.INSTANCE.manager.config.disableWandOverlay.value && heldInternal.equals("BUILDERS_WAND")) { + int maxBlocks = 164; + if (event.target.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) { + IBlockState hover = Minecraft.getMinecraft().theWorld.getBlockState(event.target.getBlockPos().offset(event.target.sideHit, 1)); + if(hover.getBlock() == Blocks.air) { + EntityPlayer player = event.player; + + IBlockState match = Minecraft.getMinecraft().theWorld.getBlockState(event.target.getBlockPos()); + Item matchItem = Item.getItemFromBlock(match.getBlock()); + if(matchItem != null) { + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.disableTexture2D(); + GlStateManager.depthMask(false); + + ItemStack matchStack = new ItemStack(matchItem, 1, match.getBlock().getMetaFromState(match)); + int itemCount = countItemsInInventoryAndStorage(matchStack); + + HashSet<BlockPos> candidatesOld = new HashSet<>(); + TreeMap<Float, Set<BlockPos>> candidatesOldSorted = new TreeMap<>(); + + getBuildersWandCandidates(player, event.target, event.partialTicks, candidatesOld, candidatesOldSorted, 10); + + String special = (candidatesOld.size() <= itemCount) ? NotEnoughUpdates.INSTANCE.manager.config.wandOverlayColour.value : + "0:255:255:0:0"; + + if(candidatesOld.size() <= maxBlocks) { + double d0 = player.lastTickPosX + (player.posX - player.lastTickPosX) * (double)event.partialTicks; + double d1 = player.lastTickPosY + (player.posY - player.lastTickPosY) * (double)event.partialTicks; + double d2 = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * (double)event.partialTicks; + + for(Set<BlockPos> candidatesSorted : candidatesOldSorted.values()) { + for(BlockPos candidate : candidatesSorted) { + match.getBlock().setBlockBoundsBasedOnState(Minecraft.getMinecraft().theWorld, candidate); + AxisAlignedBB bb = match.getBlock().getSelectedBoundingBox(Minecraft.getMinecraft().theWorld, candidate) + .offset(event.target.sideHit.getFrontOffsetX(), event.target.sideHit.getFrontOffsetY(), + event.target.sideHit.getFrontOffsetZ()); + + drawBlock((int)bb.minX, (int)bb.minY, (int)bb.minZ+1, match, event.partialTicks, 0.75f); + } + } + + for(BlockPos candidate : candidatesOld) { + match.getBlock().setBlockBoundsBasedOnState(Minecraft.getMinecraft().theWorld, candidate); + AxisAlignedBB bb = match.getBlock().getSelectedBoundingBox(Minecraft.getMinecraft().theWorld, candidate) + .expand(0.001D, 0.001D, 0.001D).offset(-d0, -d1, -d2) + .offset(event.target.sideHit.getFrontOffsetX(), event.target.sideHit.getFrontOffsetY(), + event.target.sideHit.getFrontOffsetZ()); + + drawOutlineBoundingBox(bb, 1f, special); + } + } + + GlStateManager.depthMask(true); + GlStateManager.enableTexture2D(); + GlStateManager.disableBlend(); + } + } + } + } + } + } + + public void getBuildersWandCandidates(EntityPlayer player, MovingObjectPosition target, float partialTicks, + HashSet<BlockPos> candidatesOld, TreeMap<Float, Set<BlockPos>> candidatesOldSorted, int extraMax) { + IBlockState match = Minecraft.getMinecraft().theWorld.getBlockState(target.getBlockPos()); + + candidatesOld.clear(); + candidatesOldSorted.clear(); + LinkedList<BlockPos> candidates = new LinkedList<>(); + LinkedList<BlockPos> candidatesNew = new LinkedList<>(); + + candidatesNew.add(target.getBlockPos()); + + double d0 = player.lastTickPosX + (player.posX - player.lastTickPosX) * (double)partialTicks; + double d1 = player.lastTickPosY + (player.posY - player.lastTickPosY) * (double)partialTicks; + double d2 = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * (double)partialTicks; + + while(candidatesOld.size() <= MAX_BUILDERS_BLOCKS+extraMax) { + if(candidatesNew.isEmpty()) { + break; + } + + candidates.addAll(candidatesNew); + candidatesNew.clear(); + + while(!candidates.isEmpty()) { + if(candidatesOld.size() > MAX_BUILDERS_BLOCKS+extraMax) break; + + BlockPos candidate = candidates.pop(); + + float distSq = (float)((candidate.getX()+0.5f-d0)*(candidate.getX()+0.5f-d0) + + (candidate.getY()+0.5f-d1-player.getEyeHeight())*(candidate.getY()+0.5f-d1-player.getEyeHeight()) + + (candidate.getZ()+0.5f-d2)*(candidate.getZ()+0.5f-d2)); + candidatesOldSorted.computeIfAbsent(distSq, k->new HashSet<>()).add(candidate); + + candidatesOld.add(candidate); + + for(int x = -1; x <= 1; x++) { + for(int y = -1; y <= 1; y++) { + for(int z = -1; z <= 1; z++) { + if(x*x+y*y+z*z == 1) { + if(((x == 0) && (target.sideHit.getAxis() == EnumFacing.Axis.X)) || + ((y == 0) && (target.sideHit.getAxis() == EnumFacing.Axis.Y)) || + ((z == 0) && (target.sideHit.getAxis() == EnumFacing.Axis.Z))) { + if(Minecraft.getMinecraft().theWorld.getBlockState(candidate.add( + x+target.sideHit.getFrontOffsetX(), + y+target.sideHit.getFrontOffsetY(), + z+target.sideHit.getFrontOffsetZ())).getBlock() == Blocks.air) { + BlockPos posNew = candidate.add(x, y, z); + if(!candidatesOld.contains(posNew) && !candidates.contains(posNew) && !candidatesNew.contains(posNew)) { + IBlockState blockNew = Minecraft.getMinecraft().theWorld.getBlockState(posNew); + if(blockNew == match) { + candidatesNew.add(posNew); + } + } + } + } + } + } + } + } + } + } + } + + public static void drawBlock(int x, int y, int z, IBlockState state, float partialTicks, float brightness) { + EntityPlayerSP player = Minecraft.getMinecraft().thePlayer; + double d0 = player.lastTickPosX + (player.posX - player.lastTickPosX) * (double)partialTicks; + double d1 = player.lastTickPosY + (player.posY - player.lastTickPosY) * (double)partialTicks; + double d2 = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * (double)partialTicks; + + BlockRendererDispatcher blockrendererdispatcher = Minecraft.getMinecraft().getBlockRendererDispatcher(); + + GlStateManager.enableTexture2D(); + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(770, 771); + + GlStateManager.enableDepth(); + GlStateManager.depthMask(true); + GlStateManager.enableCull(); + GlStateManager.cullFace(GL11.GL_BACK); + + GlStateManager.pushMatrix(); + GlStateManager.translate(x-d0, y-d1, z-d2); + + int i = state.getBlock().getRenderType(); + if(i == 3) { + IBakedModel ibakedmodel = blockrendererdispatcher.getModelFromBlockState(state, Minecraft.getMinecraft().theWorld, null); + + Block block = state.getBlock(); + block.setBlockBoundsForItemRender(); + GlStateManager.rotate(90.0F, 0.0F, 1.0F, 0.0F); + int colour = block.getRenderColor(block.getStateForEntityRender(state)); + + if (EntityRenderer.anaglyphEnable) { + colour = TextureUtil.anaglyphColor(i); + } + + colour = (colour & 0x00FFFFFF) | (100 << 24); //Set alpha to 100 + + for (EnumFacing enumfacing : EnumFacing.values()) { + renderModelBrightnessColorQuads(colour, ibakedmodel.getFaceQuads(enumfacing)); + } + + renderModelBrightnessColorQuads(colour, ibakedmodel.getGeneralQuads()); + } + + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + GlStateManager.translate(-x+d0, -y+d1, -z+d2); + GlStateManager.popMatrix(); + } + + private static void renderModelBrightnessColorQuads(int c, List<BakedQuad> listQuads) { + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + + for (BakedQuad bakedquad : listQuads) { + worldrenderer.begin(7, DefaultVertexFormats.ITEM); + worldrenderer.addVertexData(bakedquad.getVertexData()); + + worldrenderer.putColor4(c); + + Vec3i vec3i = bakedquad.getFace().getDirectionVec(); + worldrenderer.putNormal((float)vec3i.getX(), (float)vec3i.getY(), (float)vec3i.getZ()); + tessellator.draw(); + } + } + + public static void drawFilledBoundingBox(AxisAlignedBB p_181561_0_, float alpha, String special) { + Color c = new Color(SpecialColour.specialToChromaRGB(special), true); + GlStateManager.color(c.getRed()/255f, c.getGreen()/255f, c.getBlue()/255f, c.getAlpha()/255f*alpha); + + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.disableTexture2D(); + GlStateManager.depthMask(false); + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + //vertical + worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex(); + tessellator.draw(); + worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex(); + tessellator.draw(); + //x + + worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex(); + tessellator.draw(); + worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex(); + tessellator.draw(); + + //z + worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex(); + tessellator.draw(); + worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex(); + tessellator.draw(); + + } + + public static void drawOutlineBoundingBox(AxisAlignedBB p_181561_0_, float alpha, String special) { + Color c = new Color(SpecialColour.specialToChromaRGB(special), true); + GlStateManager.color(c.getRed()/255f, c.getGreen()/255f, c.getBlue()/255f, c.getAlpha()/255f*alpha); + + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.disableTexture2D(); + GlStateManager.depthMask(false); + + GL11.glLineWidth(3); + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(3, DefaultVertexFormats.POSITION); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.minZ).endVertex(); + tessellator.draw(); + worldrenderer.begin(3, DefaultVertexFormats.POSITION); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex(); + tessellator.draw(); + worldrenderer.begin(1, DefaultVertexFormats.POSITION); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex(); + worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex(); + tessellator.draw(); + + GL11.glLineWidth(1); + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java b/src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java index 4328eaf4..dcd8cfb2 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java @@ -35,6 +35,11 @@ public class CustomItems { "your buried duct tape problems are a thing of the past,", "all for the low price of $7.99 or a subscription", "to the Ducttapedigger youtube channel!"); + public static JsonObject SPINAXX = create( + "SPINAXX", + "emerald", + "Spinaxx", + "Famous streamer btw :)"); public static JsonObject RUNE = create("RUNE", "paper", "No.", "I hate runes."); public static JsonObject TWOBEETWOTEE = create("2B2T", "bedrock", "Minecraft's oldest anarchy Minecraft server in Minecraft.", "This Minecraft anarchy server is the oldest server,", @@ -48,6 +53,14 @@ public class CustomItems { "incursions on the server, some of which I, a player on this Minecraft", "anarchy server in Minecraft, have participated in. One of this server's", "most infamous Minecraft players on the oldest Minecraft"); + public static JsonObject LEOCTHL = create("LEOCTHL", "dragon_egg", "--- Stats below may not be entirely accurate ---", + "17 legendary dragon pets", + "24 epic dragon pets", + "18 epic golem pets", + "12 legendary golem pets", + "39 legendary phoenix pets", + "", + "get flexed"); /** * SHAAAAAAAAAAAAAAAAAAME diff --git a/src/main/java/io/github/moulberry/notenoughupdates/GuiEnchantColour.java b/src/main/java/io/github/moulberry/notenoughupdates/GuiEnchantColour.java new file mode 100644 index 00000000..c450c6f4 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/GuiEnchantColour.java @@ -0,0 +1,257 @@ +package io.github.moulberry.notenoughupdates; + +import com.google.common.base.Splitter; +import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField; +import io.github.moulberry.notenoughupdates.util.LerpingInteger; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class GuiEnchantColour extends GuiScreen { + + public static final ResourceLocation custom_ench_colour = new ResourceLocation("notenoughupdates:custom_ench_colour.png"); + + private int guiLeft; + private int guiTop; + private final int xSize = 176; + private int ySize = 0; + + private List<String> getEnchantColours() { + return NotEnoughUpdates.INSTANCE.manager.config.enchantColours.value; + } + + public static final Splitter splitter = Splitter.on(":").limit(4); + + private HashMap<Integer, String> comparators = new HashMap<>(); + private List<GuiElementTextField[]> guiElementTextFields = new ArrayList<>(); + + private LerpingInteger scroll = new LerpingInteger(0, 100); + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + drawDefaultBackground(); + + List<String> enchantColours = getEnchantColours(); + + ySize = 53+25*enchantColours.size(); + guiLeft = (width-xSize)/2; + + if(ySize > height) { + if(scroll.getTarget() > 0) { + scroll.setTarget(0); + } else if(scroll.getTarget() < height-ySize) { + scroll.setTarget(height-ySize); + } + scroll.tick(); + guiTop = scroll.getValue(); + } else { + guiTop = (height-ySize)/2; + scroll.setValue(0); + scroll.resetTimer(); + } + + + NotEnoughUpdates.INSTANCE.manager.loadConfig(); + + Minecraft.getMinecraft().getTextureManager().bindTexture(custom_ench_colour); + Utils.drawTexturedRect(guiLeft, guiTop, xSize, 21, 0, 1, 0, 21/78f, GL11.GL_NEAREST); + Utils.drawTexturedRect(guiLeft, guiTop+ySize-32, xSize, 32, 0, 1, 46/78f, 1, GL11.GL_NEAREST); + + fontRendererObj.drawString("Ench Name", guiLeft+10, guiTop+7, 4210752); + fontRendererObj.drawString("CMP", guiLeft+71, guiTop+7, 4210752); + fontRendererObj.drawString("LVL", guiLeft+96, guiTop+7, 4210752); + fontRendererObj.drawString("COL", guiLeft+121, guiTop+7, 4210752); + fontRendererObj.drawString("DEL", guiLeft+146, guiTop+7, 4210752); + + Utils.drawStringCentered("Add Ench Colour", fontRendererObj, guiLeft+xSize/2, guiTop+ySize-20, false, 4210752); + + int yIndex = 0; + for(String str : enchantColours) { + Minecraft.getMinecraft().getTextureManager().bindTexture(custom_ench_colour); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(guiLeft, guiTop+21+yIndex*25, xSize, 25, 0, 1, 21/78f, 46/78f, GL11.GL_NEAREST); + + List<String> colourOps = splitter.splitToList(str); + String enchantName = getColourOpIndex(colourOps, 0); + String comparator = getColourOpIndex(colourOps, 1); + String comparison = getColourOpIndex(colourOps, 2); + String colourCode = getColourOpIndex(colourOps, 3); + + if(colourCode.length() > 1) colourCode = String.valueOf(colourCode.toLowerCase().charAt(0)); + if(comparator.length() > 1) comparator = String.valueOf(comparator.toLowerCase().charAt(0)); + + Utils.drawStringCentered(comparator, fontRendererObj, guiLeft+81, guiTop+33+25*yIndex, false, 4210752); + + if(guiElementTextFields.size() <= yIndex) { + guiElementTextFields.add(new GuiElementTextField[3]); + } + if(guiElementTextFields.get(yIndex)[0] == null) { + guiElementTextFields.get(yIndex)[0] = new GuiElementTextField(enchantName, GuiElementTextField.SCALE_TEXT); + guiElementTextFields.get(yIndex)[0].setSize(56, 20); + } + if(guiElementTextFields.get(yIndex)[1] == null) { + guiElementTextFields.get(yIndex)[1] = new GuiElementTextField(comparison, + GuiElementTextField.SCALE_TEXT|GuiElementTextField.NUM_ONLY|GuiElementTextField.NO_SPACE); + guiElementTextFields.get(yIndex)[1].setSize(20, 20); + } + if(guiElementTextFields.get(yIndex)[2] == null) { + guiElementTextFields.get(yIndex)[2] = new GuiElementTextField(colourCode, GuiElementTextField.SCALE_TEXT); + guiElementTextFields.get(yIndex)[2].setSize(20, 20); + } + guiElementTextFields.get(yIndex)[0].setText(enchantName); + guiElementTextFields.get(yIndex)[1].setText(comparison); + comparators.put(yIndex, comparator); + guiElementTextFields.get(yIndex)[2].setText(colourCode); + + guiElementTextFields.get(yIndex)[0].render(guiLeft+10, guiTop+23+25*yIndex); + guiElementTextFields.get(yIndex)[1].render(guiLeft+96, guiTop+23+25*yIndex); + guiElementTextFields.get(yIndex)[2].render(guiLeft+121, guiTop+23+25*yIndex); + + yIndex++; + } + } + + @Override + protected void keyTyped(char typedChar, int keyCode) throws IOException { + super.keyTyped(typedChar, keyCode); + for(int yIndex=0; yIndex<guiElementTextFields.size(); yIndex++) { + for(int i=0; i<3; i++) { + guiElementTextFields.get(yIndex)[i].keyTyped(typedChar, keyCode); + if(guiElementTextFields.get(yIndex)[i].getFocus()) { + int addOffset = 0; + if(keyCode == Keyboard.KEY_UP) { + addOffset -= 1; + } else if(keyCode == Keyboard.KEY_DOWN) { + addOffset += 1; + } + + NotEnoughUpdates.INSTANCE.manager.config.enchantColours.value.remove(yIndex); + if(yIndex+addOffset < 0) { + addOffset = -yIndex; + } else if(yIndex+addOffset > NotEnoughUpdates.INSTANCE.manager.config.enchantColours.value.size()) { + addOffset = NotEnoughUpdates.INSTANCE.manager.config.enchantColours.value.size()-yIndex; + } + System.out.println(addOffset); + NotEnoughUpdates.INSTANCE.manager.config.enchantColours.value.add(yIndex+addOffset, + getEnchantOpString(guiElementTextFields.get(yIndex), comparators.get(yIndex))); + NotEnoughUpdates.INSTANCE.manager.saveConfig(); + if(addOffset != 0) { + GuiElementTextField[] guiElementTextFieldArray = guiElementTextFields.remove(yIndex); + guiElementTextFields.add(yIndex+addOffset, guiElementTextFieldArray); + } + return; + } + } + } + } + + public String getEnchantOpString(GuiElementTextField[] tfs, String comparator) { + StringBuilder enchantOp = new StringBuilder(); + enchantOp.append(tfs[0].getText()); + enchantOp.append(":"); + enchantOp.append(comparator); + enchantOp.append(":"); + enchantOp.append(tfs[1].getText()); + enchantOp.append(":"); + enchantOp.append(tfs[2].getText()); + return enchantOp.toString(); + } + + @Override + public void handleMouseInput() throws IOException { + super.handleMouseInput(); + + int dWheel = Mouse.getEventDWheel(); + + if(dWheel < 0) { + scroll.setTarget(scroll.getTarget()-50); + scroll.resetTimer(); + } else if(dWheel > 0) { + scroll.setTarget(scroll.getTarget()+50); + scroll.resetTimer(); + } + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { + super.mouseClicked(mouseX, mouseY, mouseButton); + for(int yIndex=0; yIndex<guiElementTextFields.size(); yIndex++) { + for(int i=0; i<3; i++) { + int x = guiLeft+10; + if(i == 1) x+=86; + else if(i == 2) x+=111; + + if(mouseX > x && mouseX < x+guiElementTextFields.get(yIndex)[i].getWidth()) { + if(mouseY > guiTop+23+25*yIndex && mouseY < guiTop+23+25*yIndex+20) { + guiElementTextFields.get(yIndex)[i].mouseClicked(mouseX, mouseY, mouseButton); + if(mouseButton == 1) { + NotEnoughUpdates.INSTANCE.manager.config.enchantColours.value.remove(yIndex); + NotEnoughUpdates.INSTANCE.manager.config.enchantColours.value.add(yIndex, + getEnchantOpString(guiElementTextFields.get(yIndex), comparators.get(yIndex))); + NotEnoughUpdates.INSTANCE.manager.saveConfig(); + } + continue; + } + } + guiElementTextFields.get(yIndex)[i].otherComponentClick(); + } + comparators.computeIfAbsent(yIndex, k->">"); + if(mouseY > guiTop+23+25*yIndex && mouseY < guiTop+23+25*yIndex+20) { + if(mouseX > guiLeft+71 && mouseX < guiLeft+71+20) { + switch (comparators.get(yIndex)) { + case ">": + comparators.put(yIndex, "="); break; + case "=": + comparators.put(yIndex, "<"); break; + default: + comparators.put(yIndex, ">"); break; + } + NotEnoughUpdates.INSTANCE.manager.config.enchantColours.value.remove(yIndex); + NotEnoughUpdates.INSTANCE.manager.config.enchantColours.value.add(yIndex, + getEnchantOpString(guiElementTextFields.get(yIndex), comparators.get(yIndex))); + NotEnoughUpdates.INSTANCE.manager.saveConfig(); + } else if(mouseX > guiLeft+146 && mouseX < guiLeft+146+20) { + NotEnoughUpdates.INSTANCE.manager.config.enchantColours.value.remove(yIndex); + guiElementTextFields.remove(yIndex); + comparators.remove(yIndex); + NotEnoughUpdates.INSTANCE.manager.saveConfig(); + } + } + } + if(mouseX >= guiLeft+42 && mouseX <= guiLeft+42+88) { + if(mouseY >= guiTop+ySize-30 && mouseY <= guiTop+ySize-10) { + NotEnoughUpdates.INSTANCE.manager.config.enchantColours.value.add("[a-zA-Z\\- ]+:>:5:9"); + NotEnoughUpdates.INSTANCE.manager.saveConfig(); + } + } + } + + public static String getColourOpIndex(List<String> colourOps, int index) { + if(colourOps.size() > index) { + return colourOps.get(index); + } else { + switch(index) { + case 0: + return "[a-zA-Z\\- ]+"; + case 1: + return ">"; + case 2: + return "5"; + case 3: + return "9"; + } + } + return null; + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/GuiItemRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/GuiItemRecipe.java index 200569df..c4040f60 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/GuiItemRecipe.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/GuiItemRecipe.java @@ -37,10 +37,10 @@ public class GuiItemRecipe extends GuiScreen { private String title; private NEUManager manager; - private int guiLeft = 0; - private int guiTop = 0; - private int xSize = 176; - private int ySize = 166; + public int guiLeft = 0; + public int guiTop = 0; + public int xSize = 176; + public int ySize = 166; public GuiItemRecipe(String title, List<ItemStack[]> craftMatrices, List<JsonObject> results, NEUManager manager) { this.craftMatrices = craftMatrices; @@ -170,7 +170,7 @@ public class GuiItemRecipe extends GuiScreen { @Override public void handleKeyboardInput() throws IOException { - super.handleKeyboardInput(); //TODO: r and u + super.handleKeyboardInput(); ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); int width = scaledResolution.getScaledWidth(); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/GuiTextures.java b/src/main/java/io/github/moulberry/notenoughupdates/GuiTextures.java index 1f87018b..05fb792a 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/GuiTextures.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/GuiTextures.java @@ -22,8 +22,27 @@ public class GuiTextures { public static final ResourceLocation slider_button = new ResourceLocation("notenoughupdates:slider_button.png"); public static final ResourceLocation item_mask = new ResourceLocation("notenoughupdates:item_mask.png"); + public static final ResourceLocation item_haschild = new ResourceLocation("notenoughupdates:item_haschild.png"); public static final ResourceLocation button_tex = new ResourceLocation("notenoughupdates:button.png"); + public static final ResourceLocation setting_border = new ResourceLocation("notenoughupdates:setting_border.png"); + + public static final ResourceLocation button_white = new ResourceLocation("notenoughupdates:button_white.png"); + public static final ResourceLocation colour_selector_dot = new ResourceLocation("notenoughupdates:colour_selector_dot.png"); + public static final ResourceLocation colour_selector_bar = new ResourceLocation("notenoughupdates:colour_selector_bar.png"); + public static final ResourceLocation colour_selector_bar_alpha = new ResourceLocation("notenoughupdates:colour_selector_bar_alpha.png"); + public static final ResourceLocation colour_selector_chroma = new ResourceLocation("notenoughupdates:colour_selector_chroma.png"); + + public static final ResourceLocation accessory_bag_overlay = new ResourceLocation("notenoughupdates:accessory_bag_overlay.png"); + + public static final ResourceLocation quickcommand_background = new ResourceLocation("notenoughupdates:quickcommand_background.png"); + + public static final ResourceLocation gamemodes = new ResourceLocation("notenoughupdates:gamemodes.png"); + public static final ResourceLocation radial_square_off = new ResourceLocation("notenoughupdates:radial_square_off.png"); + public static final ResourceLocation radial_square_on = new ResourceLocation("notenoughupdates:radial_square_on.png"); + public static final ResourceLocation radial_circle_off = new ResourceLocation("notenoughupdates:radial_circle_off.png"); + public static final ResourceLocation radial_circle_on = new ResourceLocation("notenoughupdates:radial_circle_on.png"); + public static final ResourceLocation dungeon_chest_worth = new ResourceLocation("notenoughupdates:dungeon_chest_worth.png"); public static final ResourceLocation auction_view = new ResourceLocation("notenoughupdates:auction_view.png"); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/HelpGUI.java b/src/main/java/io/github/moulberry/notenoughupdates/HelpGUI.java new file mode 100644 index 00000000..1049dc55 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/HelpGUI.java @@ -0,0 +1,189 @@ +package io.github.moulberry.notenoughupdates; + +import io.github.moulberry.notenoughupdates.util.TexLoc; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Keyboard; +import org.lwjgl.util.vector.Vector2f; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class HelpGUI extends GuiScreen { + + private int guiLeft = 0; + private int guiTop = 0; + private int sizeX = 0; + private int sizeY = 0; + + private int page = 0; + private ResourceLocation screenshotBorder = new ResourceLocation("notenoughupdates:ss_border.jpg"); + private ResourceLocation[] screenshots = null; + + int scaleFactor = 0; + + @Override + public void setWorldAndResolution(Minecraft mc, int width, int height) { + super.setWorldAndResolution(mc, width, height); + + screenshots = new ResourceLocation[18]; + for(int i=0; i<=17; i++) { + screenshots[i] = new ResourceLocation("notenoughupdates:ss_small/ss"+(i+1)+"-0.jpg"); + } + } + + @Override + protected void keyTyped(char typedChar, int keyCode) throws IOException { + Keyboard.enableRepeatEvents(true); + super.keyTyped(typedChar, keyCode); + if(keyCode == Keyboard.KEY_LEFT) { + page--; + } else if(keyCode == Keyboard.KEY_RIGHT) { + page++; + } + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + super.drawScreen(mouseX, mouseY, partialTicks); + + drawDefaultBackground(); + + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + scaleFactor = scaledResolution.getScaleFactor(); + + sizeX = width/2+40/scaleFactor; + sizeY = height/2+40/scaleFactor; + guiLeft = width/4-20/scaleFactor; + guiTop = height/4-20/scaleFactor; + + Minecraft.getMinecraft().getTextureManager().bindTexture(screenshotBorder); + Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY); + + page = Math.max(0, Math.min(17, page)); + + Minecraft.getMinecraft().getTextureManager().bindTexture(screenshots[page]); + Utils.drawTexturedRect(guiLeft+20f/scaleFactor, guiTop+20f/scaleFactor, sizeX-40f/scaleFactor, sizeY-40f/scaleFactor); + + Utils.drawStringCentered(EnumChatFormatting.GOLD+"NEU Tutorial - Page "+(page+1)+"/18 - Use arrow keys", Minecraft.getMinecraft().fontRendererObj, + width/2, guiTop+8, true, 0); + if(scaleFactor != 2) Utils.drawStringCentered(EnumChatFormatting.GOLD+"Use GUI Scale normal for better reading experience", Minecraft.getMinecraft().fontRendererObj, + width/2, guiTop+18, true, 0); + + for(Map.Entry<Vector2f, List<String>> entry : texts[page].entrySet()) { + Vector2f location = entry.getKey(); + List<String> text = entry.getValue(); + + float x = guiLeft+20f/scaleFactor+(sizeX-40f/scaleFactor)*location.x; + float y = guiTop+20f/scaleFactor+(sizeY-40f/scaleFactor)*location.y; + + Utils.drawHoveringText(text, (int)x, (int)y+12, 100000, 100000, 200, Minecraft.getMinecraft().fontRendererObj); + } + } + + + private static HashMap<Vector2f, List<String>>[] texts = new HashMap[18]; + static { + for(int i=0; i<18; i++) { + texts[i] = new HashMap<>(); + } + texts[0].put(new Vector2f(0.73f, 0.60f), Utils.createList( + EnumChatFormatting.GOLD+"Itemlist", + EnumChatFormatting.GRAY+"Here you will find a list of (most) skyblock items", + EnumChatFormatting.GRAY+"The itemlist can be accessed by opening your inventory or most menus while on skyblock")); + texts[1].put(new Vector2f(0.73f, 0.16f), Utils.createList( + EnumChatFormatting.GOLD+"Itemlist", + EnumChatFormatting.GRAY+"These are the page controls for the itemlist", + EnumChatFormatting.GRAY+"Clicking these controls will bring you to other pages of the itemlist")); + texts[2].put(new Vector2f(0.73f, 1.05f), Utils.createList( + EnumChatFormatting.GOLD+"Itemlist", + EnumChatFormatting.GRAY+"These are the sorting controls for the itemlist", + EnumChatFormatting.GRAY+"The buttons on the left control the ordering of the items", + EnumChatFormatting.GRAY+"The buttons on the right can be used to filter a certain type of item")); + texts[3].put(new Vector2f(0.39f, 1.04f), Utils.createList( + EnumChatFormatting.GOLD+"Itemlist", + EnumChatFormatting.GRAY+"This is the search bar for the itemlist", + EnumChatFormatting.GRAY+"Double-click the bar to enable inventory search mode", + EnumChatFormatting.GRAY+"The button on the left opens up the mod settings", + EnumChatFormatting.GRAY+"The button on the right displays this tutorial")); + texts[4].put(new Vector2f(0.39f, 0.99f), Utils.createList( + EnumChatFormatting.GOLD+"QuickCommands", + EnumChatFormatting.GRAY+"These are the QuickCommands", + EnumChatFormatting.GRAY+"They let you warp around or access certain menus more easily")); + texts[5].put(new Vector2f(0.7f, 0.71f), Utils.createList( + EnumChatFormatting.GOLD+"Itemlist", + EnumChatFormatting.GRAY+"Hover over an item in the list to display it's lore", + EnumChatFormatting.GRAY+"Left clicking some items will display the recipe for that item", + EnumChatFormatting.GRAY+"Right clicking some items will display a wiki page for that item", + EnumChatFormatting.GRAY+"'F' will favourite an item, putting it to the top of the itemlist")); + texts[6].put(new Vector2f(0.17f, 0.21f), Utils.createList( + EnumChatFormatting.GOLD+"Collection Log", + EnumChatFormatting.GRAY+"This is the collection log. It can be accessed using the /neucl command, or via the QuickCommand", + EnumChatFormatting.GRAY+"The collection log keeps track of all items that enter your inventory while you are playing skyblock", + EnumChatFormatting.GRAY+"If you are a completionist, this feature is for you")); + texts[7].put(new Vector2f(0.05f, 0.13f), Utils.createList( + EnumChatFormatting.GOLD+"Collection Log", + EnumChatFormatting.GRAY+"Clicking on 'Filter' will change the items that", + EnumChatFormatting.GRAY+"appear in the list")); + texts[8].put(new Vector2f(0.35f, 0.74f), Utils.createList( + EnumChatFormatting.GOLD+"NeuAH", + EnumChatFormatting.GRAY+"This is the NEU Auction House (NeuAH)", + EnumChatFormatting.GRAY+"This AH can be accessed from anywhere using the /neuah command, or via the QuickCommand", + EnumChatFormatting.GRAY+"The items here refresh automatically, so there is no need to close the GUI to see the latest auctions", + EnumChatFormatting.GRAY+"Sometimes, you might have to wait until the list is populated with items from the API")); + texts[9].put(new Vector2f(0.41f, 0.40f), Utils.createList( + EnumChatFormatting.GOLD+"NeuAH", + EnumChatFormatting.GRAY+"These tabs control the items that appear in NeuAH", + EnumChatFormatting.GRAY+"You can find the main categories on the top of the GUI and subcategories appear on the side of the GUI once a main category is selected")); + texts[10].put(new Vector2f(0.57f, 0.38f), Utils.createList( + EnumChatFormatting.GOLD+"NeuAH", + EnumChatFormatting.GRAY+"Search for items using the search bar at the top", + EnumChatFormatting.GRAY+"Boolean operators such as &, | or ! work here.")); + texts[10].put(new Vector2f(0.40f, 0.72f), Utils.createList( + EnumChatFormatting.GOLD+"NeuAH", + EnumChatFormatting.GRAY+"This toolbar contains many useful features", + EnumChatFormatting.GRAY+"which control the sorting and ordering of", + EnumChatFormatting.GRAY+"the auction house, similar to the normal AH")); + texts[11].put(new Vector2f(0.55f, 0.72f), Utils.createList( + EnumChatFormatting.GOLD+"NeuAH", + EnumChatFormatting.GRAY+"Clicking on an item will bring up the auction view", + EnumChatFormatting.GRAY+"Here you can viewer the buyer/seller and place bids or make purchases", + EnumChatFormatting.GRAY+"Trying to purchase an item will result in a confirmation GUI similar to the normal AH")); + texts[12].put(new Vector2f(0.28f, 0.82f), Utils.createList( + EnumChatFormatting.GOLD+"Profile Viewer", + EnumChatFormatting.GRAY+"Access the profile viewer using /neuprofile (ign) or /pv (ign)", + EnumChatFormatting.GRAY+"This is the main page of the profile viewer", + EnumChatFormatting.GRAY+"This page contains basic information like stats and skill levels")); + texts[12].put(new Vector2f(0.72f, 0.55f), Utils.createList( + EnumChatFormatting.GOLD+"Profile Viewer", + EnumChatFormatting.GRAY+"Click the button on the left to switch profiles and use the bar on the right to switch players")); + texts[13].put(new Vector2f(0.28f, 0.82f), Utils.createList( + EnumChatFormatting.GOLD+"Profile Viewer", + EnumChatFormatting.GRAY+"This is the extra info page of the profile viewer", + EnumChatFormatting.GRAY+"This page contains all the small bits of information about a player that don't fit anywhere else")); + texts[14].put(new Vector2f(0.28f, 0.82f), Utils.createList( + EnumChatFormatting.GOLD+"Profile Viewer", + EnumChatFormatting.GRAY+"This is the inventories page of the profile viewer", + EnumChatFormatting.GRAY+"Click on the inventory icons in the top-left or use your keyboard to switch the inventory type", + EnumChatFormatting.GRAY+"The bar on the bottom-left searches the current inventory for matching items")); + texts[15].put(new Vector2f(0.28f, 0.82f), Utils.createList( + EnumChatFormatting.GOLD+"Profile Viewer", + EnumChatFormatting.GRAY+"This is the collections page of the profile viewer", + EnumChatFormatting.GRAY+"Click on the icons on the left or use the keyboard shortcut to switch collection type")); + texts[16].put(new Vector2f(0.28f, 0.82f), Utils.createList( + EnumChatFormatting.GOLD+"Profile Viewer", + EnumChatFormatting.GRAY+"This is the pets page of the profile viewer", + EnumChatFormatting.GRAY+"Click to select the pet on the left", + EnumChatFormatting.GRAY+"The selected pet's stats will display on the right")); + texts[17].put(new Vector2f(0.27f, 0.40f), Utils.createList( + EnumChatFormatting.GOLD+"Overlay", + EnumChatFormatting.GRAY+"Rearrange certain GUI elements of the main overlay using /neuoverlay", + EnumChatFormatting.GRAY+"If you accidentally move them off screen, use the button in the top left to reset the GUI")); + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/ItemRarityHalo.java b/src/main/java/io/github/moulberry/notenoughupdates/ItemRarityHalo.java new file mode 100644 index 00000000..2c70ec1e --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/ItemRarityHalo.java @@ -0,0 +1,251 @@ +package io.github.moulberry.notenoughupdates; + +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.renderer.texture.TextureUtil; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.client.shader.Shader; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Matrix4f; +import org.lwjgl.BufferUtils; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; +import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.GL45; + +import java.awt.*; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.util.HashMap; + +public class ItemRarityHalo { + + public static Framebuffer itemFramebuffer1 = null; + public static Framebuffer itemFramebuffer2 = null; + public static HashMap<ItemStack, Integer> itemHaloTexMap = new HashMap<>(); + public static Matrix4f projectionMatrix = null; + + public static Shader colourShader = null; + public static Shader blurShaderHorz = null; + public static Shader blurShaderVert = null; + + private static int oldScaledResolution = 0; + + public static void onItemRender(ItemStack stack, int x, int y) { + if(x == 0 && y == 0) return; + + if(!OpenGlHelper.isFramebufferEnabled() || !OpenGlHelper.areShadersSupported()) return; + NotEnoughUpdates neu = NotEnoughUpdates.INSTANCE; + if(!neu.isOnSkyblock()) return; + if(neu.manager.config.itemHighlightOpacity.value <= 1) return; + if(neu.manager.getInternalNameForItem(stack) == null) return; + + ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + int size = 16*scaledresolution.getScaleFactor(); + + if(projectionMatrix == null) { + projectionMatrix = Utils.createProjectionMatrix(size, size); + } + + itemFramebuffer1 = checkFramebufferSizes(itemFramebuffer1, size, size); + itemFramebuffer2 = checkFramebufferSizes(itemFramebuffer2, size, size); + + try { + if(colourShader == null) { + colourShader = new Shader(new NEUResourceManager(Minecraft.getMinecraft().getResourceManager()), + "setrgbtoalpha", itemFramebuffer1, itemFramebuffer2); + upload(colourShader, size, size); + } + + if(blurShaderHorz == null) { + blurShaderHorz = new Shader(new NEUResourceManager(Minecraft.getMinecraft().getResourceManager()), + "blur", itemFramebuffer2, itemFramebuffer1); + blurShaderHorz.getShaderManager().getShaderUniform("BlurDir").set(1, 0); + blurShaderHorz.getShaderManager().getShaderUniform("Radius").set(5f); + blurShaderHorz.getShaderManager().getShaderUniform("AlphaMult").set(2f); + upload(blurShaderHorz, size, size); + } + + if(blurShaderVert == null) { + blurShaderVert = new Shader(new NEUResourceManager(Minecraft.getMinecraft().getResourceManager()), + "blur", itemFramebuffer1, itemFramebuffer2); + blurShaderVert.getShaderManager().getShaderUniform("BlurDir").set(0, 1); + blurShaderVert.getShaderManager().getShaderUniform("Radius").set(5f); + blurShaderVert.getShaderManager().getShaderUniform("AlphaMult").set(2f); + upload(blurShaderVert, size, size); + } + } catch(Exception e) { return; } + + if(oldScaledResolution != scaledresolution.getScaleFactor()) { + resetItemHaloCache(); + oldScaledResolution = scaledresolution.getScaleFactor(); + } + + int currentBuffer = GL11.glGetInteger(GL30.GL_FRAMEBUFFER_BINDING); + IntBuffer currentViewport = BufferUtils.createIntBuffer(16); + GL11.glGetInteger(GL11.GL_VIEWPORT, currentViewport); + try { + if(!itemHaloTexMap.containsKey(stack)) { + int texture1 = TextureUtil.glGenTextures(); + int texture2 = TextureUtil.glGenTextures(); + + GlStateManager.bindTexture(texture1); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, size, size, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, ((ByteBuffer)null)); + itemFramebuffer1.bindFramebuffer(false); + OpenGlHelper.glFramebufferTexture2D(OpenGlHelper.GL_FRAMEBUFFER, OpenGlHelper.GL_COLOR_ATTACHMENT0, 3553, texture1, 0); + + GlStateManager.bindTexture(texture2); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, size, size, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, ((ByteBuffer)null)); + itemFramebuffer2.bindFramebuffer(false); + OpenGlHelper.glFramebufferTexture2D(OpenGlHelper.GL_FRAMEBUFFER, OpenGlHelper.GL_COLOR_ATTACHMENT0, 3553, texture2, 0); + + itemFramebuffer1.framebufferClear(); + itemFramebuffer2.framebufferClear(); + + GlStateManager.pushMatrix(); { + GlStateManager.matrixMode(5889); + GlStateManager.loadIdentity(); + GlStateManager.ortho(0.0D, size, size, 0.0D, 1000.0D, 3000.0D); + GlStateManager.matrixMode(5888); + GlStateManager.loadIdentity(); + GlStateManager.translate(0.0F, 0.0F, -2000.0F); + + GL11.glScalef(scaledresolution.getScaleFactor(), scaledresolution.getScaleFactor(), 1); + + itemFramebuffer1.bindFramebuffer(true); + + RenderItem itemRender = Minecraft.getMinecraft().getRenderItem(); + RenderHelper.enableGUIStandardItemLighting(); + float zLevel = itemRender.zLevel; + itemRender.zLevel = -145; //Negates the z-offset of the below method. + itemRender.renderItemAndEffectIntoGUI(stack, 0, 0); + itemRender.zLevel = zLevel; + RenderHelper.disableStandardItemLighting(); + } GlStateManager.popMatrix(); + + GlStateManager.pushMatrix(); { + GL45.glTextureBarrier(); GL11.glFlush(); GL11.glFinish(); + executeShader(colourShader); + //GL45.glTextureBarrier(); GL11.glFlush(); GL11.glFinish(); + //executeShader(blurShaderHorz); + //GL45.glTextureBarrier(); GL11.glFlush(); GL11.glFinish(); + //executeShader(blurShaderVert); + //GL45.glTextureBarrier(); GL11.glFlush(); GL11.glFinish(); + } GlStateManager.popMatrix(); + + GlStateManager.matrixMode(5889); + GlStateManager.loadIdentity(); + GlStateManager.ortho(0.0D, scaledresolution.getScaledWidth_double(), scaledresolution.getScaledHeight_double(), 0.0D, 1000.0D, 3000.0D); + GlStateManager.matrixMode(5888); + + OpenGlHelper.glBindFramebuffer(OpenGlHelper.GL_FRAMEBUFFER, currentBuffer); + GlStateManager.viewport(currentViewport.get(), currentViewport.get(), currentViewport.get(), currentViewport.get()); + + //TextureUtil.deleteTexture(texture1); + itemHaloTexMap.put(stack, texture2); + } + + OpenGlHelper.glBindFramebuffer(OpenGlHelper.GL_FRAMEBUFFER, currentBuffer); + GlStateManager.viewport(currentViewport.get(), currentViewport.get(), currentViewport.get(), currentViewport.get()); + + GlStateManager.bindTexture(itemHaloTexMap.get(stack)); + Color color = Utils.getPrimaryColour(stack.getDisplayName()); + GlStateManager.color(color.getRed()/255f, color.getGreen()/255f, color.getBlue()/255f, + NotEnoughUpdates.INSTANCE.manager.config.itemHighlightOpacity.value.floatValue()/255f); + Utils.drawTexturedRect(x, y, 16, 16, + 0, 1, 1, 0, GL11.GL_NEAREST); + GlStateManager.bindTexture(0); + } catch(Exception e) { + e.printStackTrace(); + OpenGlHelper.glBindFramebuffer(OpenGlHelper.GL_FRAMEBUFFER, currentBuffer); + GlStateManager.viewport(currentViewport.get(), currentViewport.get(), currentViewport.get(), currentViewport.get()); + } + } + + private static Framebuffer checkFramebufferSizes(Framebuffer framebuffer, int width, int height) { + if(framebuffer == null || framebuffer.framebufferWidth != width || framebuffer.framebufferHeight != height) { + if(framebuffer == null) { + framebuffer = new Framebuffer(width, height, true); + } else { + framebuffer.createBindFramebuffer(width, height); + } + framebuffer.setFramebufferFilter(GL11.GL_NEAREST); + } + return framebuffer; + } + + public static void resetItemHaloCache() { + ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + int size = 16*scaledresolution.getScaleFactor(); + + for(int tex : itemHaloTexMap.values()) { + TextureUtil.deleteTexture(tex); + } + itemHaloTexMap.clear(); + + if(NotEnoughUpdates.INSTANCE.isOnSkyblock()) { + projectionMatrix = Utils.createProjectionMatrix(size, size); + upload(colourShader, size, size); + upload(blurShaderHorz, size, size); + upload(blurShaderVert, size, size); + } + } + + private static void upload(Shader shader, int width, int height) { + if(shader == null) return; + shader.getShaderManager().getShaderUniformOrDefault("ProjMat").set(projectionMatrix); + shader.getShaderManager().getShaderUniformOrDefault("InSize").set(width, height); + shader.getShaderManager().getShaderUniformOrDefault("OutSize").set(width, height); + shader.getShaderManager().getShaderUniformOrDefault("ScreenSize").set((float)width, (float)height); + } + + private static void executeShader(Shader shader) { + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + GlStateManager.disableBlend(); + GlStateManager.disableDepth(); + GlStateManager.disableAlpha(); + GlStateManager.disableFog(); + GlStateManager.disableLighting(); + GlStateManager.disableColorMaterial(); + GlStateManager.enableTexture2D(); + GlStateManager.bindTexture(0); + + float f = (float)shader.framebufferOut.framebufferTextureWidth; + float f1 = (float)shader.framebufferOut.framebufferTextureHeight; + GlStateManager.viewport(0, 0, (int)f, (int)f1); + + shader.getShaderManager().useShader(); + shader.getShaderManager().addSamplerTexture("DiffuseSampler", shader.framebufferIn); + + shader.framebufferOut.framebufferClear(); + shader.framebufferOut.bindFramebuffer(false); + + GlStateManager.depthMask(false); + + GlStateManager.enableAlpha(); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_COLOR); + worldrenderer.pos(0.0D, (double)f1, 500.0D).color(255, 255, 255, 255).endVertex(); + worldrenderer.pos((double)f, (double)f1, 500.0D).color(255, 255, 255, 255).endVertex(); + worldrenderer.pos((double)f, 0.0D, 500.0D).color(255, 255, 255, 255).endVertex(); + worldrenderer.pos(0.0D, 0.0D, 500.0D).color(255, 255, 255, 255).endVertex(); + tessellator.draw(); + + GlStateManager.depthMask(true); + + shader.getShaderManager().endShader(); + + shader.framebufferOut.unbindFramebuffer(); + shader.framebufferIn.unbindFramebufferTexture(); + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/MorusIntegration.java b/src/main/java/io/github/moulberry/notenoughupdates/MorusIntegration.java new file mode 100644 index 00000000..8ec4263a --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/MorusIntegration.java @@ -0,0 +1,60 @@ +package io.github.moulberry.notenoughupdates; + +import io.github.moulberry.morus.MorusSubstitutor; +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; + +import java.util.HashMap; +import java.util.Map; + +public class MorusIntegration { + + private static MorusIntegration INSTANCE = new MorusIntegration(); + + public static MorusIntegration getInstance() { + return INSTANCE; + } + + private HashMap<String, Integer> itemDrops = null; + private HashMap<String, Integer> inventoryItems = null; + + public void tick() { + if(itemDrops == null) { + itemDrops = new HashMap<>(); + for(String item : NotEnoughUpdates.INSTANCE.manager.getItemInformation().keySet()) { + itemDrops.put(item, 0); + } + } + + HashMap<String, Integer> newInventoryItems = getInventoryItems(); + if(inventoryItems != null) { + for(String internal : newInventoryItems.keySet()) { + int newAmount = newInventoryItems.get(internal); + int oldAmount = inventoryItems.getOrDefault(internal, 0); + if(newAmount > oldAmount) { + itemDrops.put(internal, itemDrops.getOrDefault(internal, 0)+newAmount-oldAmount); + } + } + } + inventoryItems = newInventoryItems; + + for(Map.Entry<String, Integer> entry : itemDrops.entrySet()) { + MorusSubstitutor.putSubstiution("notenoughupdates", "itemdrops."+entry.getKey().toLowerCase(), ""+entry.getValue()); + } + + } + + public HashMap<String, Integer> getInventoryItems() { + HashMap<String, Integer> inventoryItems = new HashMap<>(); + if(Minecraft.getMinecraft().thePlayer != null) { + for(ItemStack stack : Minecraft.getMinecraft().thePlayer.inventory.mainInventory) { + String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack); + if(internalname != null) { + inventoryItems.put(internalname, inventoryItems.getOrDefault(internalname, 0)+stack.stackSize); + } + } + } + return inventoryItems; + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUCape2.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUCape2.java deleted file mode 100644 index 996809da..00000000 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUCape2.java +++ /dev/null @@ -1,607 +0,0 @@ -package io.github.moulberry.notenoughupdates; - -import net.minecraft.block.Block; -import net.minecraft.client.Minecraft; -import net.minecraft.client.entity.EntityPlayerSP; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.client.renderer.texture.SimpleTexture; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.command.CommandBase; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.util.*; -import net.minecraftforge.client.event.ClientChatReceivedEvent; -import net.minecraftforge.client.event.RenderPlayerEvent; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.entity.EntityJoinWorldEvent; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL20; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -public class NEUCape2 { - - //private ResourceLocation capeImageLocation = new ResourceLocation(Morus.MODID, "cape.jpg"); - //private SimpleTexture capeTexture; - - private long millisLastRenderUpdate = 0; - - private int horzNodes = 20; - private double targetDist = 1/30.0; - - private EntityPlayer player = null; - - private double vertOffset = 1.4; - private double shoulderLength = 0.3; - private double shoulderWidth = 0.13; - private double crouchWidthOffset = -0.05; - private double maxCrouchOffset = 0.35; - - private double resistance = 0.08; - private double gravity = 0.04; - private int steps = 10; - - private List<List<Node>> nodes = new ArrayList<>(); - - /*private void reloadCapeImage() { - if(capeTexture != null) { - capeTexture.deleteGlTexture(); - } - capeTexture = new SimpleTexture(capeImageLocation); - try { - capeTexture.loadTexture(Minecraft.getMinecraft().getResourceManager()); - } catch(IOException e) { - e.printStackTrace(); - } - }*/ - - private void resetNodes(EntityPlayer player) { - nodes.clear(); - for(int i=0; i<50; i++) { - List<Node> list = new ArrayList<>(); - for(int j=0; j<horzNodes; j++) { - if(horzNodes == 1) { - list.add(new Node(player.posX-1, player.posY+2-i*targetDist, player.posZ, i, j)); - } else if(horzNodes > 1) { - list.add(new Node(player.posX-1, player.posY+2-i*targetDist, player.posZ+((double)j)/(horzNodes-1), i, j)); - } - } - - nodes.add(list); - } - } - - class Node { - public int iIndex; - public int jIndex; - - public boolean fixed = false; - - public double x; - public double y; - public double z; - public double xOld; - public double yOld; - public double zOld; - public double aX; - public double aY; - public double aZ; - - public double normalX; - public double normalY; - public double normalZ; - - public Node(double x, double y, double z, int iIndex, int jIndex) { - this.x = xOld = x; - this.y = xOld = y; - this.z = xOld = z; - this.iIndex = iIndex; - this.jIndex = jIndex; - } - - private void updateNormal(Node up, Node left, Node right, Node down, Node up2, Node left2, Node right2, Node down2) { - Vec3 normal1 = normal(up, left); - Vec3 normal2 = normal(right, up); - Vec3 normal3 = normal(down, right); - Vec3 normal4 = normal(left, down); - Vec3 normal5 = normal(up2, left2); - Vec3 normal6 = normal(right2, up2); - Vec3 normal7 = normal(down2, right2); - Vec3 normal8 = normal(left2, down2); - - Vec3 avgNormal = normal1.add(normal2).add(normal3).add(normal4) - .add(normal5).add(normal6).add(normal7).add(normal8).normalize(); - - normalX = avgNormal.xCoord; - normalY = avgNormal.yCoord; - normalZ = avgNormal.zCoord; - } - - private Vec3 normal(Node node1, Node node2) { - if(node1 == null || node2 == null) { - return new Vec3(0,0,0); - } - Vec3 thisNode = node2vec(this); - Vec3 node1Vec = node2vec(node1); - Vec3 node2Vec = node2vec(node2); - - Vec3 thisTo1 = node1Vec.subtract(thisNode); - Vec3 thisTo2 = node2Vec.subtract(thisNode); - - return thisTo1.crossProduct(thisTo2); - - } - - public void update(double pX, double pY, double pZ, EntityPlayer player) { - if(fixed) { - return; - } - - double xTemp = x; - double yTemp = y; - double zTemp = z; - - double res = resistance; - - BlockPos pos = new BlockPos( - MathHelper.floor_double(x), - MathHelper.floor_double(y), - MathHelper.floor_double(z)); - Block block = Minecraft.getMinecraft().theWorld.getBlockState(pos).getBlock(); - if(block.getMaterial().isLiquid()) { - aX /= 5; - aY /= 5; - aZ /= 5; - - res = Math.sqrt(res); - } - - double xDiff = x-xOld; - double yDiff = y-yOld; - double zDiff = z-zOld; - - xDiff = MathHelper.clamp_double(xDiff, -0.5, 0.5); - yDiff = MathHelper.clamp_double(yDiff, -0.5, 0.5); - zDiff = MathHelper.clamp_double(zDiff, -0.5, 0.5); - - x = x + xDiff*(1-res)+aX*0.2; - y = y + yDiff*(1-res)+aY*0.2; - z = z + zDiff*(1-res)+aZ*0.2; - - resolvePlayerCollision(pX, pY, pZ, player); - - if(!checkCollision(xTemp, yTemp, zTemp)) { - xOld = xTemp; - yOld = yTemp; - zOld = zTemp; - } - - if(checkCollision(x, y, z)) { - updateFromBoundingBox(); - } - - aX = 0; - aY = 0; - aZ = 0; - } - - public boolean resolvePlayerCollision(double pX, double pY, double pZ, EntityPlayer player) { - double angle = Math.toRadians(player.renderYawOffset); - - double offset = 0; - - if(player.getCurrentArmor(1) != null) { - if(player.isSneaking()) { - offset += 0.15; - } else { - offset += 0.06; - } - } - - if(player.isSneaking()) { - offset -= crouchWidthOffset; - - double dY = y - player.posY; - - if(dY < 0.65) { - offset += maxCrouchOffset; - } else if(dY < 1.2) { - offset += maxCrouchOffset*(1.2-dY)/0.55; - } - } - - double x1 = pX+Math.cos(angle)*2-Math.cos(angle+Math.PI/2)*(shoulderWidth+offset); - double z1 = pZ+Math.sin(angle)*2-Math.sin(angle+Math.PI/2)*(shoulderWidth+offset); - double x2 = pX-Math.cos(angle)*2-Math.cos(angle+Math.PI/2)*(shoulderWidth+offset); - double z2 = pZ-Math.sin(angle)*2-Math.sin(angle+Math.PI/2)*(shoulderWidth+offset); - - boolean crossed = ((x2 - x1)*(z - z1) < (z2 - z1)*(x - x1)); - - if(crossed) { - double dot1 = ((x-x2)*(x1-x2)+(z-z2)*(z1-z2)); - double dot2 = (x1-x2)*(x1-x2)+(z1-z2)*(z1-z2); - double k = dot1/dot2; - - x = xOld = (x1-x2)*k+x2; - z = zOld = (z1-z2)*k+z2; - - return true; - } - return false; - } - - public void updateFromBoundingBox() { - BlockPos pos = new BlockPos( - MathHelper.floor_double(x), - MathHelper.floor_double(y), - MathHelper.floor_double(z)); - Block block = Minecraft.getMinecraft().theWorld.getBlockState(pos).getBlock(); - block.setBlockBoundsBasedOnState(Minecraft.getMinecraft().theWorld, pos); - AxisAlignedBB bb = block.getSelectedBoundingBox(Minecraft.getMinecraft().theWorld, pos); - - Vec3 center = new Vec3((bb.minX + bb.maxX) / 2, (bb.minY + bb.maxY) / 2, (bb.minZ + bb.maxZ) / 2); - MovingObjectPosition mop = bb.calculateIntercept(center.add(new Vec3(x, y, z).subtract(center).normalize()), center); - - if(mop == null) { - return; - } - - Vec3 vec = mop.hitVec; - - if(vec == null) { - return; - } - - double dX = vec.xCoord - x; - double dY = vec.yCoord - y; - double dZ = vec.zCoord - z; - double adX = Math.abs(dX); - double adY = Math.abs(dY); - double adZ = Math.abs(dZ); - - double tot = adX + adY + adZ; - - //Simulate a little bit of friction - if(tot < 0.15 || checkCollision(vec.xCoord, vec.yCoord, vec.zCoord)) { - x = xOld; - y = yOld; - z = zOld; - return; - } - - //>0.3 check reduces the movement at corners a little bit - if(adX/tot > 0.3) x = xOld = vec.xCoord; - if(adY/tot > 0.3) y = yOld = vec.yCoord; - if(adZ/tot > 0.3) z = zOld = vec.zCoord; - } - - public boolean checkCollision(double x, double y, double z) { - BlockPos pos = new BlockPos( - MathHelper.floor_double(x), - MathHelper.floor_double(y), - MathHelper.floor_double(z)); - Block block = Minecraft.getMinecraft().theWorld.getBlockState(pos).getBlock(); - - if(block.getMaterial().isSolid()) { - block.setBlockBoundsBasedOnState(Minecraft.getMinecraft().theWorld, pos); - AxisAlignedBB bb = block.getSelectedBoundingBox(Minecraft.getMinecraft().theWorld, pos); - - return bb.isVecInside(new Vec3(x, y, z)); - } else { - return false; - } - } - } - - @SubscribeEvent - public void onRenderTick(TickEvent.RenderTickEvent e) { - if(Minecraft.getMinecraft().theWorld == null || player == null) { - return; - } - - long delta = System.currentTimeMillis() - millisLastRenderUpdate; - - double lagFactor = delta/(1000/60.0); - if(lagFactor > 3) { - lagFactor = 3; - } - - double playerX = player.lastTickPosX + (player.posX - player.lastTickPosX) * e.renderTickTime; - double playerY = player.lastTickPosY + (player.posY - player.lastTickPosY) * e.renderTickTime; - double playerZ = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * e.renderTickTime; - - updateFixedNodes(playerX, playerY, playerZ, player); - - for(List<Node> nodes2 : nodes) { - for(Node node : nodes2) { - node.aY -= gravity*lagFactor; - node.update(playerX, playerY, playerZ, player); - } - } - for(int step=0; step<steps*lagFactor; step++) { - for(int i=0; i<nodes.size(); i++) { - for (int j = 0; j < horzNodes; j++) { - Node node = nodes.get(i).get(j); - List<Node> struct = new ArrayList<>(); - List<Node> shear = new ArrayList<>(); - List<Node> bend = new ArrayList<>(); - - if(i+1 < nodes.size()) struct.add(nodes.get(i+1).get(j)); - if(j+1 < horzNodes) struct.add(nodes.get(i).get(j+1)); - if(i-1 >= 0) struct.add(nodes.get(i-1).get(j)); - if(j-1 >= 0) struct.add(nodes.get(i).get(j-1)); - - if(i+1 < nodes.size() && j+1 < horzNodes) shear.add(nodes.get(i+1).get(j+1)); - if(i+1 < nodes.size() && j-1 >= 0) shear.add(nodes.get(i+1).get(j-1)); - if(i-1 >= 0 && j+1 < horzNodes) shear.add(nodes.get(i-1).get(j+1)); - if(i-1 >= 0 && j-1 >= 0) shear.add(nodes.get(i-1).get(j-1)); - - if(i+2 < nodes.size()) bend.add(nodes.get(i+2).get(j)); - if(j+2 < horzNodes) bend.add(nodes.get(i).get(j+2)); - if(i-2 >= 0) bend.add(nodes.get(i-2).get(j)); - if(j-2 >= 0) bend.add(nodes.get(i).get(j-2)); - - try { - updateNode(node, struct, shear, bend); - } catch(Exception ex) { - - } - } - } - } - for(int i=0; i<nodes.size(); i++) { - for (int j = 0; j < horzNodes; j++) { - Node up = null, down = null, left = null, right = null; - Node up2 = null, down2 = null, left2 = null, right2 = null; - - if(i+1 < nodes.size()) down = nodes.get(i+1).get(j); - if(j+1 < horzNodes) right = nodes.get(i).get(j+1); - if(i-1 >= 0) up = nodes.get(i-1).get(j); - if(j-1 >= 0) left = nodes.get(i).get(j-1); - - if(i+2 < nodes.size()) down2 = nodes.get(i+2).get(j); - if(j+2 < horzNodes) right2 = nodes.get(i).get(j+2); - if(i-2 >= 0) up2 = nodes.get(i-2).get(j); - if(j-2 >= 0) left2 = nodes.get(i).get(j-2); - - nodes.get(i).get(j).updateNormal(up, left, right, down, up2, left2, right2, down2); - } - } - - millisLastRenderUpdate = System.currentTimeMillis(); - } - - @SubscribeEvent - public void onRenderPlayer(RenderPlayerEvent.Post e) { - EntityPlayer player = e.entityPlayer; - - if(!player.getName().equalsIgnoreCase("Moulberry")) { - return; - } - - if(nodes.size() == 0) { - resetNodes(player); - } - - this.player = player; - - Entity viewer = Minecraft.getMinecraft().getRenderViewEntity(); - - double viewerX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * e.partialRenderTick; - double viewerY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * e.partialRenderTick; - double viewerZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * e.partialRenderTick; - - GlStateManager.pushMatrix(); - GlStateManager.enableBlend(); - GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, - GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); - GL11.glDisable(GL11.GL_CULL_FACE); - GlStateManager.enableTexture2D(); - int currTex = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); - //GL11.glBindTexture(GL11.GL_TEXTURE_2D, capeTexture.getGlTextureId()); - - //ShaderManager shaderManager = ShaderManager.getInstance(); - - //shaderManager.loadShader("cape"); - - for(int i=0; i<nodes.size(); i++) { - for(int j=0; j<horzNodes; j++) { - Node node = nodes.get(i).get(j); - if(i+1 < nodes.size() && j+1 < horzNodes) { - GlStateManager.color(1F, 1F, 1F, 1F); - renderNodeConnection(viewerX, viewerY, viewerZ, node, - nodes.get(i+1).get(j), nodes.get(i).get(j+1), - nodes.get(i+1).get(j+1), true); - GlStateManager.color(0.1F, 0.1F, 0.1F, 1F); - renderNodeConnection(viewerX, viewerY, viewerZ, node, - nodes.get(i+1).get(j), nodes.get(i).get(j+1), - nodes.get(i+1).get(j+1), false); - } - } - } - - GlStateManager.color(0.1F, 0.1F, 0.1F, 1F); - for(int i=0; i<nodes.size(); i++) { - if(i+1 < nodes.size()) { - renderSideConnection(viewerX, viewerY, viewerZ, - nodes.get(i).get(0), nodes.get(i+1).get(0)); - renderSideConnection(viewerX, viewerY, viewerZ, - nodes.get(i).get(horzNodes-1), nodes.get(i+1).get(horzNodes-1)); - } - } - - for(int j=0; j<horzNodes; j++) { - if(j+1 < horzNodes) { - renderSideConnection(viewerX, viewerY, viewerZ, - nodes.get(0).get(j), nodes.get(0).get(j+1)); - renderSideConnection(viewerX, viewerY, viewerZ, - nodes.get(nodes.size()-1).get(j), nodes.get(nodes.size()-1).get(j+1)); - } - } - - GL20.glUseProgram(0); - - GL11.glBindTexture(GL11.GL_TEXTURE_2D, currTex); - GL11.glEnable(GL11.GL_CULL_FACE); - GlStateManager.enableTexture2D(); - GlStateManager.disableBlend(); - GlStateManager.popMatrix(); - GlStateManager.color(1F, 1F, 1F, 1F); - } - - private Vec3 node2vec(Node node) { - return new Vec3(node.x, node.y, node.z); - } - - private void renderSideConnection(double pX, double pY, double pZ, Node node1, Node node2) { - Tessellator tessellator = Tessellator.getInstance(); - WorldRenderer worldrenderer = tessellator.getWorldRenderer(); - - worldrenderer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_NORMAL); - - worldrenderer.pos(node1.x-pX, node1.y-pY, node1.z-pZ) - .normal((float)node1.normalX, (float)node1.normalY, (float)node1.normalZ).endVertex(); - worldrenderer.pos(node2.x-pX, node2.y-pY, node2.z-pZ) - .normal((float)node2.normalX, (float)node2.normalY, (float)node2.normalZ).endVertex(); - worldrenderer.pos(node1.x-pX+node1.normalX/15, node1.y-pY+node1.normalY/15, node1.z-pZ+node1.normalZ/15) - .normal((float)node1.normalX, (float)node1.normalY, (float)node1.normalZ).endVertex(); - worldrenderer.pos(node2.x-pX+node2.normalX/15, node2.y-pY+node2.normalY/15, node2.z-pZ+node2.normalZ/15) - .normal((float)node2.normalX, (float)node2.normalY, (float)node2.normalZ).endVertex(); - - tessellator.draw(); - } - - private void renderNodeConnection(double pX, double pY, double pZ, Node node1, Node node2, - Node node3, Node node4, boolean offset) { - Tessellator tessellator = Tessellator.getInstance(); - WorldRenderer worldrenderer = tessellator.getWorldRenderer(); - - //Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(node1.normalY + " " + node2.normalY + " " + node3.normalY + " " + node4.normalY)); - - if(offset) { - worldrenderer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_NORMAL); - - worldrenderer.pos(node1.x-pX+node1.normalX/15, node1.y-pY+node1.normalY/15, node1.z-pZ+node1.normalZ/15) - .tex(((double)node1.jIndex)/(horzNodes-1), ((double)node1.iIndex)/(nodes.size()-1)) - .normal((float)node1.normalX, (float)node1.normalY, (float)node1.normalZ).endVertex(); - worldrenderer.pos(node2.x-pX+node2.normalX/15, node2.y-pY+node2.normalY/15, node2.z-pZ+node2.normalZ/15) - .tex(((double)node2.jIndex)/(horzNodes-1), ((double)node2.iIndex)/(nodes.size()-1)) - .normal((float)node2.normalX, (float)node2.normalY, (float)node2.normalZ).endVertex(); - worldrenderer.pos(node3.x-pX+node3.normalX/15, node3.y-pY+node3.normalY/15, node3.z-pZ+node3.normalZ/15) - .tex(((double)node3.jIndex)/(horzNodes-1), ((double)node3.iIndex)/(nodes.size()-1)) - .normal((float)node3.normalX, (float)node3.normalY, (float)node3.normalZ).endVertex(); - worldrenderer.pos(node4.x-pX+node4.normalX/15, node4.y-pY+node4.normalY/15, node4.z-pZ+node4.normalZ/15) - .tex(((double)node4.jIndex)/(horzNodes-1), ((double)node4.iIndex)/(nodes.size()-1)) - .normal((float)node4.normalX, (float)node4.normalY, (float)node4.normalZ).endVertex(); - - } else { - worldrenderer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_NORMAL); - - worldrenderer.pos(node1.x-pX, node1.y-pY, node1.z-pZ) - .normal((float)node1.normalX, (float)node1.normalY, (float)node1.normalZ).endVertex(); - worldrenderer.pos(node2.x-pX, node2.y-pY, node2.z-pZ) - .normal((float)node2.normalX, (float)node2.normalY, (float)node2.normalZ).endVertex(); - worldrenderer.pos(node3.x-pX, node3.y-pY, node3.z-pZ) - .normal((float)node3.normalX, (float)node3.normalY, (float)node3.normalZ).endVertex(); - worldrenderer.pos(node4.x-pX, node4.y-pY, node4.z-pZ) - .normal((float)node4.normalX, (float)node4.normalY, (float)node4.normalZ).endVertex(); - } - - tessellator.draw(); - } - - private Vec3 scale(Vec3 vector, double amount) { - return new Vec3(vector.xCoord * amount, vector.yCoord * amount, vector.zCoord * amount); - } - - private void updateNode(Node node, List<Node> struct, List<Node> shear, List<Node> bend) { - double shearDist = 1.414*targetDist; - double bendDist = 2*targetDist; //Potentially differentiate between corners? - - for(Node bendNode : bend) { - resolve(node, bendNode, bendDist); - } - - for(Node shearNode : shear) { - resolve(node, shearNode, shearDist); - } - - for(Node structNode : struct) { - resolve(node, structNode, targetDist); - } - } - - public void resolve(Node node1, Node node2, double targetDist) { - double dX = node1.x - node2.x; - double dY = node1.y - node2.y; - double dZ = node1.z - node2.z; - - double distSq = dX*dX + dY*dY + dZ*dZ; - double dist = Math.sqrt(distSq); - - dX *= (1 - targetDist/dist)*0.5; - dY *= (1 - targetDist/dist)*0.5; - dZ *= (1 - targetDist/dist)*0.5; - - if(node1.fixed || node2.fixed) { - dX *= 2; - dY *= 2; - dZ *= 2; - } - - if(!node1.fixed) { - node1.x -= dX; - node1.y -= dY; - node1.z -= dZ; - } - - if(!node2.fixed) { - node2.x += dX; - node2.y += dY; - node2.z += dZ; - } - } - - private void updateFixedNodes(double pX, double pY, double pZ, EntityPlayer player) { - double angle = Math.toRadians(player.renderYawOffset); - - double shoulderWidth2 = shoulderWidth + (player.isSneaking()?crouchWidthOffset:0); - if(player.getCurrentArmor(1) != null || player.getCurrentArmor(2) != null) { - if(player.isSneaking()) { - shoulderWidth2 += 0.15; - } else { - shoulderWidth2 += 0.06; - } - } - - Node node = nodes.get(0).get(0); - node.x = pX+Math.cos(angle)*shoulderLength-Math.cos(angle+Math.PI/2)*shoulderWidth2; - node.y = pY+vertOffset-(player.isSneaking()?0.2:0); - node.z = pZ+Math.sin(angle)*shoulderLength-Math.sin(angle+Math.PI/2)*shoulderWidth2; - node.fixed = true; - - node = nodes.get(0).get(nodes.get(0).size()-1); - node.x = pX-Math.cos(angle)*shoulderLength-Math.cos(angle+Math.PI/2)*shoulderWidth2; - node.y = pY+vertOffset-(player.isSneaking()?0.2:0); - node.z = pZ-Math.sin(angle)*shoulderLength-Math.sin(angle+Math.PI/2)*shoulderWidth2; - node.fixed = true; - - - - /*for(int i=0; i<horzNodes; i++) { - Node node = nodes.get(0).get(i); - - node.x = pX-1; - node.y = pY+2; - node.z = pZ+((double)i)/(horzNodes-1); - }*/ - } - - -} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUEventListener.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUEventListener.java new file mode 100644 index 00000000..f67b09ed --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUEventListener.java @@ -0,0 +1,1564 @@ +package io.github.moulberry.notenoughupdates; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.auction.APIManager; +import io.github.moulberry.notenoughupdates.auction.CustomAHGui; +import io.github.moulberry.notenoughupdates.cosmetics.CapeManager; +import io.github.moulberry.notenoughupdates.dungeons.DungeonBlocks; +import io.github.moulberry.notenoughupdates.dungeons.DungeonWin; +import io.github.moulberry.notenoughupdates.gamemodes.SBGamemodes; +import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer; +import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer; +import io.github.moulberry.notenoughupdates.questing.SBInfo; +import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.gui.inventory.GuiCrafting; +import net.minecraft.client.gui.inventory.GuiEditSign; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.event.ClickEvent; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.client.event.*; +import net.minecraftforge.event.entity.player.ItemTooltipEvent; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import org.apache.commons.lang3.text.WordUtils; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import javax.swing.*; +import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.io.File; +import java.io.IOException; +import java.text.NumberFormat; +import java.util.*; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static io.github.moulberry.notenoughupdates.GuiTextures.dungeon_chest_worth; + +public class NEUEventListener { + + private NotEnoughUpdates neu; + + private boolean hoverInv = false; + private boolean focusInv = false; + + private boolean joinedSB = false; + + public NEUEventListener(NotEnoughUpdates neu) { + this.neu = neu; + } + + private void displayUpdateMessageIfOutOfDate() { + File repo = neu.manager.repoLocation; + if(repo.exists()) { + File updateJson = new File(repo, "update.json"); + try { + JsonObject o = neu.manager.getJsonFromFile(updateJson); + + String version = o.get("version").getAsString(); + + if(!neu.VERSION.equalsIgnoreCase(version)) { + String update_msg = o.get("update_msg").getAsString(); + String discord_link = o.get("discord_link").getAsString(); + String youtube_link = o.get("youtube_link").getAsString(); + String update_link = o.get("update_link").getAsString(); + String github_link = o.get("github_link").getAsString(); + String other_text = o.get("other_text").getAsString(); + String other_link = o.get("other_link").getAsString(); + + int first_len = -1; + for(String line : update_msg.split("\n")) { + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + int len = fr.getStringWidth(line); + if(first_len == -1) { + first_len = len; + } + int missing_len = first_len-len; + if(missing_len > 0) { + StringBuilder sb = new StringBuilder(line); + for(int i=0; i<missing_len/8; i++) { + sb.insert(0, " "); + } + line = sb.toString(); + } + line = line.replaceAll("\\{version}", version); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(line)); + } + + neu.displayLinks(o); + + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("")); + + } + } catch(Exception ignored) {} + } + } + + private long notificationDisplayMillis = 0; + private List<String> notificationLines = null; + + /** + * 1)Will send the cached message from #sendChatMessage when at least 200ms has passed since the last message. + * This is used in order to prevent the mod spamming messages. + * 2)Adds unique items to the collection log + */ + private HashMap<String, Long> newItemAddMap = new HashMap<>(); + private long lastLongUpdate = 0; + private long lastVeryLongUpdate = 0; + private long lastSkyblockScoreboard = 0; + @SubscribeEvent + public void onTick(TickEvent.ClientTickEvent event) { + if(event.phase != TickEvent.Phase.START) return; + + boolean longUpdate = false; + long currentTime = System.currentTimeMillis(); + if(currentTime - lastLongUpdate > 1000) { + longUpdate = true; + lastLongUpdate = currentTime; + } + if(!NotEnoughUpdates.INSTANCE.manager.config.slowDungeonBlocks.value) { + DungeonBlocks.tick(); + } + DungeonWin.tick(); + if(longUpdate) { + if(NotEnoughUpdates.INSTANCE.manager.config.slowDungeonBlocks.value) { + DungeonBlocks.tick(); + } + + neu.updateSkyblockScoreboard(); + CapeManager.getInstance().tick(); + + if(Minecraft.getMinecraft().currentScreen instanceof GuiChest) { + GuiChest eventGui = (GuiChest) Minecraft.getMinecraft().currentScreen; + ContainerChest cc = (ContainerChest) eventGui.inventorySlots; + String containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText(); + if(!containerName.trim().startsWith("Accessory Bag")) { + AccessoryBagOverlay.resetCache(); + } + } else { + AccessoryBagOverlay.resetCache(); + } + + if(neu.hasSkyblockScoreboard()) { + if(Loader.isModLoaded("morus")) { + MorusIntegration.getInstance().tick(); + } + lastSkyblockScoreboard = currentTime; + if(!joinedSB) { + joinedSB = true; + + SBGamemodes.loadFromFile(); + + if(neu.manager.config.showUpdateMsg.value) { + displayUpdateMessageIfOutOfDate(); + } + + long maxMemoryMB = Runtime.getRuntime().maxMemory()/1024L/1024L; + if(maxMemoryMB > 4100) { + notificationDisplayMillis = System.currentTimeMillis(); + notificationLines = new ArrayList<>(); + notificationLines.add(EnumChatFormatting.DARK_RED+"Too much memory allocated!"); + notificationLines.add(String.format(EnumChatFormatting.DARK_GRAY+"NEU has detected %03dMB of memory allocated to Minecraft!", maxMemoryMB)); + notificationLines.add(EnumChatFormatting.DARK_GRAY+"It is recommended to allocated between 2-4GB of memory"); + notificationLines.add(EnumChatFormatting.DARK_GRAY+"More than 4GB WILL cause FPS issues, EVEN if you have 16GB+ available"); + notificationLines.add(""); + notificationLines.add(EnumChatFormatting.DARK_GRAY+"For more information, visit #ram-info in discord.gg/spr6ESn"); + } + + if(!neu.manager.config.loadedModBefore.value) { + neu.manager.config.loadedModBefore.value = true; + try { neu.manager.saveConfig(); } catch(IOException e) {} + + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.BLUE+"It seems this is your first time using NotEnoughUpdates.")); + ChatComponentText clickText = new ChatComponentText( + EnumChatFormatting.YELLOW+"Click this message if you would like to view a short tutorial."); + clickText.setChatStyle(Utils.createClickStyle(ClickEvent.Action.RUN_COMMAND, "/neututorial")); + Minecraft.getMinecraft().thePlayer.addChatMessage(clickText); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("")); + } + } + SBInfo.getInstance().tick(); + //GuiQuestLine.questLine.tick(); + } + if(currentTime - lastSkyblockScoreboard < 5*60*1000) { //5 minutes + neu.manager.auctionManager.tick(); + } else { + neu.manager.auctionManager.markNeedsUpdate(); + } + //ItemRarityHalo.resetItemHaloCache(); + } + if(longUpdate && neu.hasSkyblockScoreboard()) { + if(neu.manager.getCurrentProfile() == null || neu.manager.getCurrentProfile().length() == 0) { + ProfileViewer.Profile profile = NotEnoughUpdates.profileViewer.getProfile(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""), + callback->{}); + if(profile != null) { + String latest = profile.getLatestProfile(); + if(latest != null) { + neu.manager.setCurrentProfileBackup(profile.getLatestProfile()); + } + } + } + if(neu.manager.getCurrentProfile() != null && neu.manager.getCurrentProfile().length() > 0) { + HashSet<String> newItem = new HashSet<>(); + if(Minecraft.getMinecraft().currentScreen instanceof GuiContainer && + !(Minecraft.getMinecraft().currentScreen instanceof GuiCrafting)) { + boolean usableContainer = true; + for(ItemStack stack : Minecraft.getMinecraft().thePlayer.openContainer.getInventory()) { + if(stack == null) { + continue; + } + if(stack.hasTagCompound()) { + NBTTagCompound tag = stack.getTagCompound(); + if(tag.hasKey("ExtraAttributes", 10)) { + continue; + } + } + usableContainer = false; + break; + } + if(!usableContainer) { + if(Minecraft.getMinecraft().currentScreen instanceof GuiChest) { + GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen; + ContainerChest container = (ContainerChest) chest.inventorySlots; + String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText(); + + if(containerName.equals("Accessory Bag") || containerName.startsWith("Wardrobe")) { + usableContainer = true; + } + } + } + if(usableContainer) { + for(ItemStack stack : Minecraft.getMinecraft().thePlayer.inventory.mainInventory) { + processUniqueStack(stack, newItem); + } + for(ItemStack stack : Minecraft.getMinecraft().thePlayer.openContainer.getInventory()) { + processUniqueStack(stack, newItem); + } + } + } else { + for(ItemStack stack : Minecraft.getMinecraft().thePlayer.inventory.mainInventory) { + processUniqueStack(stack, newItem); + } + } + newItemAddMap.keySet().retainAll(newItem); + } + } + } + + private void processUniqueStack(ItemStack stack, HashSet<String> newItem) { + if(stack != null && stack.hasTagCompound()) { + String internalname = neu.manager.getInternalNameForItem(stack); + if(internalname != null) { + ArrayList<String> log = neu.manager.config.collectionLog.value.computeIfAbsent( + neu.manager.getCurrentProfile(), k -> new ArrayList<>()); + if(!log.contains(internalname)) { + newItem.add(internalname); + if(newItemAddMap.containsKey(internalname)) { + if(System.currentTimeMillis() - newItemAddMap.get(internalname) > 1000) { + log.add(internalname); + try { neu.manager.saveConfig(); } catch(IOException ignored) {} + } + } else { + newItemAddMap.put(internalname, System.currentTimeMillis()); + } + } + } + } + } + + @SubscribeEvent(priority= EventPriority.HIGHEST) + public void onRenderEntitySpecials(RenderLivingEvent.Specials.Pre event) { + if(Minecraft.getMinecraft().currentScreen instanceof GuiProfileViewer) { + if(((GuiProfileViewer)Minecraft.getMinecraft().currentScreen).getEntityPlayer() == event.entity) { + event.setCanceled(true); + } + } + } + + @SubscribeEvent + public void onRenderGameOverlay(RenderGameOverlayEvent event) { + if(event.type != null && event.type.equals(RenderGameOverlayEvent.ElementType.BOSSHEALTH) && + Minecraft.getMinecraft().currentScreen instanceof GuiContainer && neu.overlay.isUsingMobsFilter()) { + event.setCanceled(true); + } + long timeRemaining = 15000 - (System.currentTimeMillis() - notificationDisplayMillis); + if(event.type == RenderGameOverlayEvent.ElementType.ALL) { + DungeonWin.render(event.partialTicks); + } + if(event.type == RenderGameOverlayEvent.ElementType.ALL && + timeRemaining > 0 && notificationLines != null && notificationLines.size() > 0) { + int width = 0; + int height = notificationLines.size()*10+10; + + for(String line : notificationLines) { + int len = Minecraft.getMinecraft().fontRendererObj.getStringWidth(line) + 8; + if(len > width) { + width = len; + } + } + + ScaledResolution sr = Utils.pushGuiScale(2); + + int midX = sr.getScaledWidth()/2; + int topY = sr.getScaledHeight()*3/4-height/2; + Gui.drawRect(midX-width/2, sr.getScaledHeight()*3/4-height/2, + midX+width/2, sr.getScaledHeight()*3/4+height/2, 0xFF3C3C3C); + Gui.drawRect(midX-width/2+2, sr.getScaledHeight()*3/4-height/2+2, + midX+width/2-2, sr.getScaledHeight()*3/4+height/2-2, 0xFFC8C8C8); + + Minecraft.getMinecraft().fontRendererObj.drawString((timeRemaining/1000)+"s", midX-width/2+3, + topY+3, 0xFF000000, false); + + Utils.drawStringCentered(notificationLines.get(0), Minecraft.getMinecraft().fontRendererObj, + midX, topY+4+5, false, -1); + for(int i=1; i<notificationLines.size(); i++) { + String line = notificationLines.get(i); + Utils.drawStringCentered(line, Minecraft.getMinecraft().fontRendererObj, + midX, topY+4+5+2+i*10, false, -1); + } + + Utils.pushGuiScale(-1); + } + } + + /** + * When opening a GuiContainer, will reset the overlay and load the config. + * When closing a GuiContainer, will save the config. + * Also includes a dev feature used for automatically acquiring crafting information from the "Crafting Table" GUI. + */ + AtomicBoolean missingRecipe = new AtomicBoolean(false); + @SubscribeEvent + public void onGuiOpen(GuiOpenEvent event) { + neu.manager.auctionManager.customAH.lastGuiScreenSwitch = System.currentTimeMillis(); + BetterContainers.reset(); + + if(event.gui == null && neu.manager.auctionManager.customAH.isRenderOverAuctionView() && + !(Minecraft.getMinecraft().currentScreen instanceof CustomAHGui)) { + event.gui = new CustomAHGui(); + } + + if(!(event.gui instanceof GuiChest || event.gui instanceof GuiEditSign)) { + neu.manager.auctionManager.customAH.setRenderOverAuctionView(false); + } else if(event.gui instanceof GuiChest && (neu.manager.auctionManager.customAH.isRenderOverAuctionView() || + Minecraft.getMinecraft().currentScreen instanceof CustomAHGui)){ + GuiChest chest = (GuiChest) event.gui; + ContainerChest container = (ContainerChest) chest.inventorySlots; + String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText(); + + neu.manager.auctionManager.customAH.setRenderOverAuctionView(containerName.trim().equals("Auction View") || + containerName.trim().equals("BIN Auction View") || containerName.trim().equals("Confirm Bid") || + containerName.trim().equals("Confirm Purchase")); + } + + //OPEN + if(Minecraft.getMinecraft().currentScreen == null + && event.gui instanceof GuiContainer) { + neu.overlay.reset(); + neu.manager.loadConfig(); + } + //CLOSE + if(Minecraft.getMinecraft().currentScreen instanceof GuiContainer + && event.gui == null) { + try { + neu.manager.saveConfig(); + } catch(IOException e) {} + } + if(event.gui != null && neu.manager.config.dev.value) { + if(event.gui instanceof GuiChest) { + GuiChest eventGui = (GuiChest) event.gui; + ContainerChest cc = (ContainerChest) eventGui.inventorySlots; + IInventory lower = cc.getLowerChestInventory(); + ses.schedule(() -> { + if(Minecraft.getMinecraft().currentScreen != event.gui) { + return; + } + if(lower.getStackInSlot(23).getDisplayName().endsWith("Crafting Table")) { + try { + ItemStack res = lower.getStackInSlot(25); + String resInternalname = neu.manager.getInternalNameForItem(res); + + if(lower.getStackInSlot(48) != null) { + String backName = null; + NBTTagCompound tag = lower.getStackInSlot(48).getTagCompound(); + if(tag.hasKey("display", 10)) { + NBTTagCompound nbttagcompound = tag.getCompoundTag("display"); + if(nbttagcompound.getTagId("Lore") == 9){ + NBTTagList nbttaglist1 = nbttagcompound.getTagList("Lore", 8); + backName = nbttaglist1.getStringTagAt(0); + } + } + + if(backName != null) { + String[] split = backName.split(" "); + if(split[split.length-1].contains("Rewards")) { + String col = backName.substring(split[0].length()+1, + backName.length()-split[split.length-1].length()-1); + + JsonObject json = neu.manager.getItemInformation().get(resInternalname); + json.addProperty("crafttext", "Requires: " + col); + + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Added: " + resInternalname)); + neu.manager.writeJsonDefaultDir(json, resInternalname+".json"); + neu.manager.loadItem(resInternalname); + } + } + } + + /*JsonArray arr = null; + File f = new File(neu.manager.configLocation, "missing.json"); + try(InputStream instream = new FileInputStream(f)) { + BufferedReader reader = new BufferedReader(new InputStreamReader(instream, StandardCharsets.UTF_8)); + JsonObject json = neu.manager.gson.fromJson(reader, JsonObject.class); + arr = json.getAsJsonArray("missing"); + } catch(IOException e) {} + try { + JsonObject json = new JsonObject(); + JsonArray newArr = new JsonArray(); + for(JsonElement e : arr) { + if(!e.getAsString().equals(resInternalname)) { + newArr.add(e); + } + } + json.add("missing", newArr); + neu.manager.writeJson(json, f); + } catch(IOException e) {}*/ + + + + /*JsonObject recipe = new JsonObject(); + + String[] x = {"1","2","3"}; + String[] y = {"A","B","C"}; + + for(int i=0; i<=18; i+=9) { + for(int j=0; j<3; j++) { + ItemStack stack = lower.getStackInSlot(10+i+j); + String internalname = ""; + if(stack != null) { + internalname = neu.manager.getInternalNameForItem(stack); + if(!neu.manager.getItemInformation().containsKey(internalname)) { + neu.manager.writeItemToFile(stack); + } + internalname += ":"+stack.stackSize; + } + recipe.addProperty(y[i/9]+x[j], internalname); + } + } + + JsonObject json = neu.manager.getJsonForItem(res); + json.add("recipe", recipe); + json.addProperty("internalname", resInternalname); + json.addProperty("clickcommand", "viewrecipe"); + json.addProperty("modver", NotEnoughUpdates.VERSION); + + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Added: " + resInternalname)); + neu.manager.writeJsonDefaultDir(json, resInternalname+".json"); + neu.manager.loadItem(resInternalname);*/ + } catch(Exception e) { + e.printStackTrace(); + } + } + }, 200, TimeUnit.MILLISECONDS); + return; + } + } + } + + /** + * 1) When receiving "You are playing on profile" messages, will set the current profile. + * 2) When a /viewrecipe command fails (i.e. player does not have recipe unlocked, will open the custom recipe GUI) + * 3) Replaces lobby join notifications when streamer mode is active + */ + @SubscribeEvent(priority = EventPriority.LOW) + public void onGuiChat(ClientChatReceivedEvent e) { + DungeonWin.onChatMessage(e); + + String r = null; + String unformatted = Utils.cleanColour(e.message.getUnformattedText()); + if(unformatted.startsWith("You are playing on profile: ")) { + neu.manager.setCurrentProfile(unformatted.substring("You are playing on profile: ".length()).split(" ")[0].trim()); + } else if(unformatted.startsWith("Your profile was changed to: ")) {//Your profile was changed to: + neu.manager.setCurrentProfile(unformatted.substring("Your profile was changed to: ".length()).split(" ")[0].trim()); + } else if(unformatted.startsWith("Your new API key is ")) { + neu.manager.config.apiKey.value = unformatted.substring("Your new API key is ".length()); + try { neu.manager.saveConfig(); } catch(IOException ioe) {} + } + if(e.message.getFormattedText().equals(EnumChatFormatting.RESET.toString()+ + EnumChatFormatting.RED+"You haven't unlocked this recipe!"+EnumChatFormatting.RESET)) { + r = EnumChatFormatting.RED+"You haven't unlocked this recipe!"; + } else if(e.message.getFormattedText().startsWith(EnumChatFormatting.RESET.toString()+ + EnumChatFormatting.RED+"Invalid recipe ")) { + r = ""; + } + if(e.message.getFormattedText().contains(EnumChatFormatting.YELLOW+"Visit the Auction House to collect your item!")) { + if(NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.latestBid != null && + System.currentTimeMillis() - NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.latestBidMillis < 5000) { + NotEnoughUpdates.INSTANCE.sendChatMessage("/viewauction " + + NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.niceAucId( + NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.latestBid)); + } + } + if(r != null) { + if(neu.manager.failViewItem(r)) { + e.setCanceled(true); + } + missingRecipe.set(true); + } + //System.out.println(e.message); + if(unformatted.startsWith("Sending to server") && + neu.isOnSkyblock() && neu.manager.config.streamerMode.value && e.message instanceof ChatComponentText) { + String m = e.message.getFormattedText(); + String m2 = StreamerMode.filterChat(e.message.getFormattedText()); + if(!m.equals(m2)) { + e.message = new ChatComponentText(m2); + } + } + } + + /** + * Sets hoverInv and focusInv variables, representing whether the NEUOverlay should render behind the inventory when + * (hoverInv == true) and whether mouse/kbd inputs shouldn't be sent to NEUOverlay (focusInv == true). + * + * If hoverInv is true, will render the overlay immediately (resulting in the inventory being drawn over the GUI) + * If hoverInv is false, the overlay will render in #onGuiScreenDraw (resulting in the GUI being drawn over the inv) + * + * All of this only matters if players are using gui scale auto which may result in the inventory being drawn + * over the various panes. + * @param event + */ + @SubscribeEvent + public void onGuiBackgroundDraw(GuiScreenEvent.BackgroundDrawnEvent event) { + if((shouldRenderOverlay(event.gui) || event.gui instanceof CustomAHGui) && neu.isOnSkyblock()) { + ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + int width = scaledresolution.getScaledWidth(); + + boolean hoverPane = event.getMouseX() < width*neu.overlay.getInfoPaneOffsetFactor() || + event.getMouseX() > width*neu.overlay.getItemPaneOffsetFactor(); + + if(event.gui instanceof GuiContainer) { + try { + int xSize = (int) Utils.getField(GuiContainer.class, event.gui, "xSize", "field_146999_f"); + int ySize = (int) Utils.getField(GuiContainer.class, event.gui, "ySize", "field_147000_g"); + int guiLeft = (int) Utils.getField(GuiContainer.class, event.gui, "guiLeft", "field_147003_i"); + int guiTop = (int) Utils.getField(GuiContainer.class, event.gui, "guiTop", "field_147009_r"); + + hoverInv = event.getMouseX() > guiLeft && event.getMouseX() < guiLeft + xSize && + event.getMouseY() > guiTop && event.getMouseY() < guiTop + ySize; + + if(hoverPane) { + if(!hoverInv) focusInv = false; + } else { + focusInv = true; + } + } catch(NullPointerException npe) { + npe.printStackTrace(); + focusInv = !hoverPane; + } + } + if(event.gui instanceof GuiItemRecipe) { + GuiItemRecipe guiItemRecipe = ((GuiItemRecipe)event.gui); + hoverInv = event.getMouseX() > guiItemRecipe.guiLeft && event.getMouseX() < guiItemRecipe.guiLeft + guiItemRecipe.xSize && + event.getMouseY() > guiItemRecipe.guiTop && event.getMouseY() < guiItemRecipe.guiTop + guiItemRecipe.ySize; + + if(hoverPane) { + if(!hoverInv) focusInv = false; + } else { + focusInv = true; + } + } + if(focusInv) { + try { + neu.overlay.render(hoverInv && focusInv); + } catch(ConcurrentModificationException e) {e.printStackTrace();} + GL11.glTranslatef(0, 0, 10); + } + } + + if(shouldRenderOverlay(event.gui) && neu.isOnSkyblock()) { + renderDungeonChestOverlay(event.gui); + if(neu.manager.config.accessoryBagOverlay.value) { + AccessoryBagOverlay.renderOverlay(); + } + } + } + + @SubscribeEvent + public void onGuiScreenDrawPre(GuiScreenEvent.DrawScreenEvent.Pre event) { + if(TradeWindow.tradeWindowActive() || + event.gui instanceof CustomAHGui || neu.manager.auctionManager.customAH.isRenderOverAuctionView()) { + event.setCanceled(true); + + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + int width = scaledResolution.getScaledWidth(); + int height = scaledResolution.getScaledHeight(); + + //Dark background + Utils.drawGradientRect(0, 0, width, height, -1072689136, -804253680); + + if(event.mouseX < width*neu.overlay.getWidthMult()/3 || event.mouseX > width-width*neu.overlay.getWidthMult()/3) { + if(event.gui instanceof CustomAHGui || neu.manager.auctionManager.customAH.isRenderOverAuctionView()) { + neu.manager.auctionManager.customAH.drawScreen(event.mouseX, event.mouseY); + } else { + TradeWindow.render(event.mouseX, event.mouseY); + } + neu.overlay.render(false); + } else { + neu.overlay.render(false); + if(event.gui instanceof CustomAHGui || neu.manager.auctionManager.customAH.isRenderOverAuctionView()) { + neu.manager.auctionManager.customAH.drawScreen(event.mouseX, event.mouseY); + } else { + TradeWindow.render(event.mouseX, event.mouseY); + } + } + } + } + + private static boolean shouldRenderOverlay(Gui gui) { + boolean validGui = gui instanceof GuiContainer || gui instanceof GuiItemRecipe; + if(gui instanceof GuiChest) { + GuiChest eventGui = (GuiChest) gui; + ContainerChest cc = (ContainerChest) eventGui.inventorySlots; + String containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText(); + if(containerName.trim().equals("Fast Travel")) { + validGui = false; + } + } + return validGui; + } + + /** + * Will draw the NEUOverlay over the inventory if focusInv == false. (z-translation of 300 is so that NEUOverlay + * will draw over Items in the inventory (which render at a z value of about 250)) + * @param event + */ + @SubscribeEvent + public void onGuiScreenDrawPost(GuiScreenEvent.DrawScreenEvent.Post event) { + if(!(TradeWindow.tradeWindowActive() || event.gui instanceof CustomAHGui || + neu.manager.auctionManager.customAH.isRenderOverAuctionView())) { + if(shouldRenderOverlay(event.gui) && neu.isOnSkyblock()) { + if(!focusInv) { + GL11.glTranslatef(0, 0, 300); + neu.overlay.render(hoverInv && focusInv); + GL11.glTranslatef(0, 0, -300); + } + neu.overlay.renderOverlay(); + } + } + } + + private void renderDungeonChestOverlay(GuiScreen gui) { + if(gui instanceof GuiChest && !neu.manager.config.dungeonProfitLore.value) { + try { + int xSize = (int) Utils.getField(GuiContainer.class, gui, "xSize", "field_146999_f"); + int ySize = (int) Utils.getField(GuiContainer.class, gui, "ySize", "field_147000_g"); + int guiLeft = (int) Utils.getField(GuiContainer.class, gui, "guiLeft", "field_147003_i"); + int guiTop = (int) Utils.getField(GuiContainer.class, gui, "guiTop", "field_147009_r"); + + GuiChest eventGui = (GuiChest) gui; + ContainerChest cc = (ContainerChest) eventGui.inventorySlots; + IInventory lower = cc.getLowerChestInventory(); + + ItemStack rewardChest = lower.getStackInSlot(31); + if (rewardChest != null && rewardChest.getDisplayName().endsWith(EnumChatFormatting.GREEN+"Open Reward Chest")) { + Minecraft.getMinecraft().getTextureManager().bindTexture(dungeon_chest_worth); + GL11.glColor4f(1, 1, 1, 1); + GlStateManager.disableLighting(); + Utils.drawTexturedRect(guiLeft+xSize+4, guiTop, 180, 71, 0, 180/256f, 0, 71/256f, GL11.GL_NEAREST); + + int chestCost = 0; + String line6 = Utils.cleanColour(neu.manager.getLoreFromNBT(rewardChest.getTagCompound())[6]); + StringBuilder cost = new StringBuilder(); + for(int i=0; i<line6.length(); i++) { + char c = line6.charAt(i); + if("0123456789".indexOf(c) >= 0) { + cost.append(c); + } + } + if(cost.length() > 0) { + chestCost = Integer.parseInt(cost.toString()); + } + + boolean missing = false; + int totalValueBIN = 0; + int totalValueAUC = 0; + for(int i=0; i<5; i++) { + ItemStack item = lower.getStackInSlot(11+i); + String internal = neu.manager.getInternalNameForItem(item); + if(internal != null) { + float bazaarPrice = -1; + JsonObject bazaarInfo = neu.manager.auctionManager.getBazaarInfo(internal); + if(bazaarInfo != null && bazaarInfo.has("avg_sell")) { + bazaarPrice = bazaarInfo.get("avg_sell").getAsFloat(); + } + + float worthBIN = -1; + float worthAUC = -1; + + if(bazaarPrice > 0) { + worthBIN = bazaarPrice; + worthAUC = bazaarPrice; + } else { + worthBIN = neu.manager.auctionManager.getLowestBin(internal); + JsonObject aucInfo = neu.manager.auctionManager.getItemAuctionInfo(internal); + if(aucInfo != null) { + worthAUC = aucInfo.get("price").getAsFloat(); + } + } + + if(worthAUC <= 0 && worthBIN <= 0) { + missing = true; + break; + } + + if(worthBIN > 0 && totalValueBIN >= 0) { + totalValueBIN += worthBIN; + } else { + totalValueBIN = -1; + } + + if(worthAUC > 0 && totalValueAUC >= 0) { + totalValueAUC += worthAUC; + } else { + totalValueAUC = -1; + } + } + } + if(totalValueAUC <= 0 && totalValueBIN <= 0) { + missing = true; + } + + if(missing) { + drawStringShadow(EnumChatFormatting.BLUE+"Couldn't find item on AH. Item is very rare!", + guiLeft+xSize+4+90, guiTop+14, 170); + } else { + NumberFormat format = NumberFormat.getInstance(Locale.US); + String valueStringBIN = EnumChatFormatting.YELLOW+"Value (BIN): " + EnumChatFormatting.GOLD + + EnumChatFormatting.BOLD + format.format(totalValueBIN) + " coins"; + String valueStringAUC = EnumChatFormatting.YELLOW+"Value (AUC): " + EnumChatFormatting.GOLD + + EnumChatFormatting.BOLD + format.format(totalValueAUC) + " coins"; + + + int profitLossBIN = totalValueBIN - chestCost; + String plStringBIN; + if(profitLossBIN >= 0) { + plStringBIN = EnumChatFormatting.YELLOW+"Profit/Loss: " + EnumChatFormatting.DARK_GREEN + + EnumChatFormatting.BOLD + "+" + format.format(profitLossBIN) + " coins"; + } else { + plStringBIN = EnumChatFormatting.YELLOW+"Profit/Loss: " + EnumChatFormatting.RED + + EnumChatFormatting.BOLD + "-" + format.format(-profitLossBIN) + " coins"; + } + + int profitLossAUC = totalValueAUC - chestCost; + String plStringAUC; + if(profitLossAUC >= 0) { + plStringAUC = EnumChatFormatting.YELLOW+"Profit/Loss: " + EnumChatFormatting.DARK_GREEN + + EnumChatFormatting.BOLD + "+" + format.format(profitLossAUC) + " coins"; + } else { + plStringAUC = EnumChatFormatting.YELLOW+"Profit/Loss: " + EnumChatFormatting.RED + + EnumChatFormatting.BOLD + "-" + format.format(-profitLossAUC) + " coins"; + } + + drawStringShadow(valueStringBIN, guiLeft+xSize+4+90, + guiTop+14, 170); + drawStringShadow(plStringBIN, guiLeft+xSize+4+90, + guiTop+26, 170); + + drawStringShadow(valueStringAUC, guiLeft+xSize+4+90, + guiTop+44, 170); + drawStringShadow(plStringAUC, guiLeft+xSize+4+90, + guiTop+56, 170); + } + } + } catch(Exception e) { + e.printStackTrace(); + } + } + } + + public void drawStringShadow(String str, float x, float y, int len) { + for(int xOff=-2; xOff<=2; xOff++) { + for(int yOff=-2; yOff<=2; yOff++) { + if(Math.abs(xOff) != Math.abs(yOff)) { + Utils.drawStringCenteredScaledMaxWidth(Utils.cleanColourNotModifiers(str), + Minecraft.getMinecraft().fontRendererObj, + x+xOff/2f, y+yOff/2f, false, len, + new Color(20, 20, 20, 100/Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB()); + } + } + } + + Utils.drawStringCenteredScaledMaxWidth(str, + Minecraft.getMinecraft().fontRendererObj, + x, y, false, len, + new Color(64, 64, 64, 255).getRGB()); + } + + /** + * Sends a mouse event to NEUOverlay if the inventory isn't hovered AND focused. + * Will also cancel the event if if NEUOverlay#mouseInput returns true. + * @param event + */ + @SubscribeEvent + public void onGuiScreenMouse(GuiScreenEvent.MouseInputEvent.Pre event) { + if(!event.isCanceled()) { + Utils.scrollTooltip(Mouse.getEventDWheel()); + } + if(TradeWindow.tradeWindowActive() || event.gui instanceof CustomAHGui || + neu.manager.auctionManager.customAH.isRenderOverAuctionView()) { + event.setCanceled(true); + if(event.gui instanceof CustomAHGui || + neu.manager.auctionManager.customAH.isRenderOverAuctionView()) { + neu.manager.auctionManager.customAH.handleMouseInput(); + } else { + TradeWindow.handleMouseInput(); + } + neu.overlay.mouseInput(); + return; + } + if(shouldRenderOverlay(event.gui) && neu.isOnSkyblock()) { + if(!neu.manager.config.accessoryBagOverlay.value || !AccessoryBagOverlay.mouseClick()) { + if(!(hoverInv && focusInv)) { + if(neu.overlay.mouseInput()) { + event.setCanceled(true); + } + } else { + neu.overlay.mouseInputInv(); + } + } + } + } + + ScheduledExecutorService ses = Executors.newScheduledThreadPool(1); + + /** + * Sends a kbd event to NEUOverlay, cancelling if NEUOverlay#keyboardInput returns true. + * Also includes a dev function used for creating custom named json files with recipes. + */ + @SubscribeEvent + public void onGuiScreenKeyboard(GuiScreenEvent.KeyboardInputEvent.Pre event) { + if(TradeWindow.tradeWindowActive() || event.gui instanceof CustomAHGui || + neu.manager.auctionManager.customAH.isRenderOverAuctionView()) { + if(event.gui instanceof CustomAHGui || + neu.manager.auctionManager.customAH.isRenderOverAuctionView()) { + if(neu.manager.auctionManager.customAH.keyboardInput()) { + event.setCanceled(true); + Minecraft.getMinecraft().dispatchKeypresses(); + } else if(neu.overlay.keyboardInput(focusInv)) { + event.setCanceled(true); + } + } else { + TradeWindow.keyboardInput(); + if(Keyboard.getEventKey() != Keyboard.KEY_ESCAPE) { + event.setCanceled(true); + Minecraft.getMinecraft().dispatchKeypresses(); + neu.overlay.keyboardInput(focusInv); + } + } + return; + } + + if(shouldRenderOverlay(event.gui) && neu.isOnSkyblock()) { + if(neu.overlay.keyboardInput(focusInv)) { + event.setCanceled(true); + } + } + if(neu.manager.config.dev.value && neu.manager.config.enableItemEditing.value && Minecraft.getMinecraft().theWorld != null && + Keyboard.getEventKey() == Keyboard.KEY_O && Keyboard.getEventKeyState()) { + GuiScreen gui = Minecraft.getMinecraft().currentScreen; + if(gui instanceof GuiChest) { + GuiChest eventGui = (GuiChest) event.gui; + ContainerChest cc = (ContainerChest) eventGui.inventorySlots; + IInventory lower = cc.getLowerChestInventory(); + + if(lower.getStackInSlot(23) != null && + lower.getStackInSlot(23).getDisplayName().endsWith("Crafting Table")) { + ItemStack res = lower.getStackInSlot(25); + String resInternalname = neu.manager.getInternalNameForItem(res); + JTextField tf = new JTextField(); + tf.setText(resInternalname); + tf.addAncestorListener(new RequestFocusListener()); + JOptionPane.showOptionDialog(null, + tf, + "Enter Name:", + JOptionPane.NO_OPTION, + JOptionPane.PLAIN_MESSAGE, + null, new String[]{"Enter"}, "Enter"); + resInternalname = tf.getText(); + if(resInternalname.trim().length() == 0) { + return; + } + + JsonObject recipe = new JsonObject(); + + String[] x = {"1","2","3"}; + String[] y = {"A","B","C"}; + + for(int i=0; i<=18; i+=9) { + for(int j=0; j<3; j++) { + ItemStack stack = lower.getStackInSlot(10+i+j); + String internalname = ""; + if(stack != null) { + internalname = neu.manager.getInternalNameForItem(stack); + if(!neu.manager.getItemInformation().containsKey(internalname)) { + neu.manager.writeItemToFile(stack); + } + internalname += ":"+stack.stackSize; + } + recipe.addProperty(y[i/9]+x[j], internalname); + } + } + + JsonObject json = neu.manager.getJsonForItem(res); + json.add("recipe", recipe); + json.addProperty("internalname", resInternalname); + json.addProperty("clickcommand", "viewrecipe"); + json.addProperty("modver", NotEnoughUpdates.VERSION); + try { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Added: " + resInternalname)); + neu.manager.writeJsonDefaultDir(json, resInternalname+".json"); + neu.manager.loadItem(resInternalname); + } catch(IOException e) {} + } + } + } + /*if(Minecraft.getMinecraft().theWorld != null && Keyboard.getEventKey() == Keyboard.KEY_RBRACKET && Keyboard.getEventKeyState()) { + Minecraft.getMinecraft().displayGuiScreen(null); + started = true; + final Object[] items = neu.manager.getItemInformation().values().toArray(); + AtomicInteger i = new AtomicInteger(0); + + Runnable checker = new Runnable() { + @Override + public void run() { + int in = i.getAndIncrement(); + /*if(missingRecipe.get()) { + String internalname = ((JsonObject)items[in]).get("internalname").getAsString(); + + JsonArray arr = null; + File f = new File(neu.manager.configLocation, "missing.json"); + try(InputStream instream = new FileInputStream(f)) { + BufferedReader reader = new BufferedReader(new InputStreamReader(instream, StandardCharsets.UTF_8)); + JsonObject json = neu.manager.gson.fromJson(reader, JsonObject.class); + arr = json.getAsJsonArray("missing"); + } catch(IOException e) {} + + try { + JsonObject json = new JsonObject(); + if(arr == null) arr = new JsonArray(); + arr.add(new JsonPrimitive(internalname)); + json.add("missing", arr); + neu.manager.writeJson(json, f); + } catch(IOException e) {} + } + missingRecipe.set(false); + + ses.schedule(() -> { + int index = i.get(); + JsonObject o = (JsonObject)items[index]; + if(Minecraft.getMinecraft().currentScreen != null) { + Minecraft.getMinecraft().displayGuiScreen(null); + } + Minecraft.getMinecraft().thePlayer.sendChatMessage("/viewrecipe " + o.get("internalname").getAsString()); + + ses.schedule(this, 1000, TimeUnit.MILLISECONDS); + }, 100, TimeUnit.MILLISECONDS); + } + }; + + int index = i.get(); + JsonObject o = (JsonObject)items[index]; + if(Minecraft.getMinecraft().currentScreen != null) { + Minecraft.getMinecraft().displayGuiScreen(null); + } + Minecraft.getMinecraft().thePlayer.sendChatMessage("/viewrecipe " + o.get("internalname").getAsString()); + + ses.schedule(checker, 1000, TimeUnit.MILLISECONDS); + }*/ + } + + private static String[] rarityArrC = new String[] { + EnumChatFormatting.WHITE+EnumChatFormatting.BOLD.toString()+"COMMON", + EnumChatFormatting.GREEN+EnumChatFormatting.BOLD.toString()+"UNCOMMON", + EnumChatFormatting.BLUE+EnumChatFormatting.BOLD.toString()+"RARE", + EnumChatFormatting.DARK_PURPLE+EnumChatFormatting.BOLD.toString()+"EPIC", + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD.toString()+"LEGENDARY", + EnumChatFormatting.LIGHT_PURPLE+EnumChatFormatting.BOLD.toString()+"MYTHIC", + EnumChatFormatting.RED+EnumChatFormatting.BOLD.toString()+"SPECIAL", + EnumChatFormatting.RED+EnumChatFormatting.BOLD.toString()+"VERY SPECIAL", + EnumChatFormatting.DARK_RED+EnumChatFormatting.BOLD.toString()+"SUPREME", + }; + @SubscribeEvent(priority = EventPriority.LOW) + public void onItemTooltipLow(ItemTooltipEvent event) { + if(!NotEnoughUpdates.INSTANCE.isOnSkyblock()) return; + + boolean hasEnchantments = event.itemStack.hasTagCompound() && event.itemStack.getTagCompound().hasKey("ExtraAttributes", 10) && + event.itemStack.getTagCompound().getCompoundTag("ExtraAttributes").hasKey("enchantments", 10); + Set<String> enchantIds = new HashSet<>(); + if(hasEnchantments) enchantIds = event.itemStack.getTagCompound().getCompoundTag("ExtraAttributes").getCompoundTag("enchantments").getKeySet(); + + JsonObject enchantsConst = Constants.ENCHANTS; + JsonArray allItemEnchs = null; + Set<String> ignoreFromPool = new HashSet<>(); + if(enchantsConst != null && hasEnchantments && NotEnoughUpdates.INSTANCE.manager.config.missingEnchantList.value) { + try { + JsonArray enchantPools = enchantsConst.get("enchant_pools").getAsJsonArray(); + for(JsonElement element : enchantPools) { + Set<String> currentPool = new HashSet<>(); + for(JsonElement poolElement : element.getAsJsonArray()) { + String poolS = poolElement.getAsString(); + currentPool.add(poolS); + } + for(JsonElement poolElement : element.getAsJsonArray()) { + String poolS = poolElement.getAsString(); + if(enchantIds.contains(poolS)) { + ignoreFromPool.addAll(currentPool); + break; + } + } + } + + JsonObject enchantsObj = enchantsConst.get("enchants").getAsJsonObject(); + NBTTagCompound tag = event.itemStack.getTagCompound(); + if(tag != null) { + NBTTagCompound display = tag.getCompoundTag("display"); + if (display.hasKey("Lore", 9)) { + NBTTagList list = display.getTagList("Lore", 8); + out: + for (int i = list.tagCount(); i >= 0; i--) { + String line = list.getStringTagAt(i); + for(int j=0; j<rarityArrC.length; j++) { + for(Map.Entry<String, JsonElement> entry : enchantsObj.entrySet()) { + if(line.contains(rarityArrC[j] + " " + entry.getKey()) || line.contains(rarityArrC[j] + " DUNGEON " + entry.getKey())) { + allItemEnchs = entry.getValue().getAsJsonArray(); + break out; + } + } + } + } + } + } + } catch(Exception e) {} + } + + boolean gotToEnchants = false; + boolean passedEnchants = false; + + boolean dungeonProfit = false; + int index = 0; + List<String> newTooltip = new ArrayList<>(); + for(String line : event.toolTip) { + if(line.contains("\u00A7cR\u00A76a\u00A7ei\u00A7an\u00A7bb\u00A79o\u00A7dw\u00A79 Rune")) { + line = line.replace("\u00A7cR\u00A76a\u00A7ei\u00A7an\u00A7bb\u00A79o\u00A7dw\u00A79 Rune", + Utils.chromaString("Rainbow Rune", index, false)+EnumChatFormatting.BLUE); + } else if(hasEnchantments) { + if(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) && NotEnoughUpdates.INSTANCE.manager.config.missingEnchantList.value) { + boolean lineHasEnch = false; + for(String s : enchantIds) { + String enchantName = WordUtils.capitalizeFully(s.replace("_", " ")); + if(line.contains(enchantName)) { + lineHasEnch = true; + break; + } + } + if(lineHasEnch) { + gotToEnchants = true; + } else { + if(gotToEnchants && !passedEnchants && Utils.cleanColour(line).trim().length() == 0) { + if(enchantsConst != null && allItemEnchs != null) { + List<String> missing = new ArrayList<>(); + for(JsonElement enchIdElement : allItemEnchs) { + String enchId = enchIdElement.getAsString(); + if(!enchId.startsWith("ultimate_") && !ignoreFromPool.contains(enchId) && !enchantIds.contains(enchId)) { + missing.add(enchId); + } + } + newTooltip.add(""); + StringBuilder currentLine = new StringBuilder(EnumChatFormatting.RED+"Missing: "+EnumChatFormatting.GRAY); + for(int i=0; i<missing.size(); i++) { + String enchName = WordUtils.capitalizeFully(missing.get(i).replace("_", " ")); + if(currentLine.length() != 0 && (Utils.cleanColour(currentLine.toString()).length() + enchName.length()) > 40) { + newTooltip.add(currentLine.toString()); + currentLine = new StringBuilder(); + } + if(currentLine.length() != 0 && i != 0) { + currentLine.append(", ").append(enchName); + } else { + currentLine.append(EnumChatFormatting.GRAY).append(enchName); + } + } + if(currentLine.length() != 0) { + newTooltip.add(currentLine.toString()); + } + } + passedEnchants = true; + } + } + } + for(String op : neu.manager.config.enchantColours.value) { + List<String> colourOps = GuiEnchantColour.splitter.splitToList(op); + String enchantName = GuiEnchantColour.getColourOpIndex(colourOps, 0); + String comparator = GuiEnchantColour.getColourOpIndex(colourOps, 1); + String comparison = GuiEnchantColour.getColourOpIndex(colourOps, 2); + String colourCode = GuiEnchantColour.getColourOpIndex(colourOps, 3); + + if(enchantName.length() == 0) continue; + if(comparator.length() == 0) continue; + if(comparison.length() == 0) continue; + if(colourCode.length() == 0) continue; + + int comparatorI = ">=<".indexOf(comparator.charAt(0)); + + int levelToFind = -1; + try { + levelToFind = Integer.parseInt(comparison); + } catch(Exception e) { continue; } + + if(comparatorI < 0) continue; + if("0123456789abcdefz".indexOf(colourCode.charAt(0)) < 0) continue; + + //item_lore = item_lore.replaceAll("\\u00A79("+lvl4Max+" IV)", EnumChatFormatting.DARK_PURPLE+"$1"); + //9([a-zA-Z ]+?) ([0-9]+|(I|II|III|IV|V|VI|VII|VIII|IX|X))(,|$) + Pattern pattern; + try { + pattern = Pattern.compile("(\\u00A79|\\u00A79\\u00A7d\\u00A7l)("+enchantName+") " + + "([0-9]+|(I|II|III|IV|V|VI|VII|VIII|IX|X|XI|XII|XIII|XIV|XV|XVI|XVII|XVIII|XIX|XX))(,|$)"); + } catch(Exception e) {continue;} //malformed regex + Matcher matcher = pattern.matcher(line); + int matchCount = 0; + while(matcher.find() && matchCount < 5) { + if(Utils.cleanColour(matcher.group(2)).startsWith(" ")) continue; + + matchCount++; + int level = -1; + String levelStr = matcher.group(matcher.groupCount()-2); + if(levelStr == null) continue; + try { + level = Integer.parseInt(levelStr); + } catch(Exception e) { + switch(levelStr) { + case "I": + level = 1; break; + case "II": + level = 2; break; + case "III": + level = 3; break; + case "IV": + level = 4; break; + case "V": + level = 5; break; + case "VI": + level = 6; break; + case "VII": + level = 7; break; + case "VIII": + level = 8; break; + case "IX": + level = 9; break; + case "X": + level = 10; break; + case "XI": + level = 11; break; + case "XII": + level = 12; break; + case "XIII": + level = 13; break; + case "XIV": + level = 14; break; + case "XV": + level = 15; break; + case "XVI": + level = 16; break; + case "XVII": + level = 17; break; + case "XVIII": + level = 18; break; + case "XIX": + level = 19; break; + case "XX": + level = 20; break; + } + } + boolean matches = false; + if(level > 0) { + switch(comparator) { + case ">": + matches = level > levelToFind; break; + case "=": + matches = level == levelToFind; break; + case "<": + matches = level < levelToFind; break; + } + } + if(matches) { + if(!colourCode.equals("z")) { + line = line.replace("\u00A79"+matcher.group(2), "\u00A7"+colourCode+matcher.group(2)); + line = line.replace("\u00A79\u00A7d\u00A7l"+matcher.group(2), "\u00A7"+colourCode+ + EnumChatFormatting.BOLD+matcher.group(2)); + } else { + int offset = Minecraft.getMinecraft().fontRendererObj.getStringWidth(line.replaceAll( + "\\u00A79"+matcher.group(2)+".*", "")); + line = line.replace("\u00A79"+matcher.group(2), Utils.chromaString(matcher.group(2), offset/12f+index, false)); + + offset = Minecraft.getMinecraft().fontRendererObj.getStringWidth(line.replaceAll( + "\\u00A79\\u00A7d\\u00A7l"+matcher.group(2)+".*", "")); + line = line.replace("\u00A79\u00A7d\u00A7l"+matcher.group(2), Utils.chromaString(matcher.group(2), + offset/12f+index, true)); + } + } + } + } + } + + newTooltip.add(line); + + if(neu.manager.config.auctionPriceInfo.value) { + if(line.contains(EnumChatFormatting.GRAY+"Buy it now: ") || + line.contains(EnumChatFormatting.GRAY+"Bidder: ") || + line.contains(EnumChatFormatting.GRAY+"Starting bid: ")) { + String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(event.itemStack); + if(internalname != null) { + newTooltip.add(""); + if(!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) && !Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) { + newTooltip.add(EnumChatFormatting.GRAY+"[SHIFT for Price Info]"); + } else { + JsonObject auctionInfo = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAuctionInfo(internalname); + + boolean hasAuctionPrice = auctionInfo != null; + + int lowestBin = NotEnoughUpdates.INSTANCE.manager.auctionManager.getLowestBin(internalname); + + NumberFormat format = NumberFormat.getInstance(Locale.US); + APIManager.CraftInfo craftCost = NotEnoughUpdates.INSTANCE.manager.auctionManager.getCraftCost(internalname); + + if(lowestBin > 0) { + newTooltip.add(EnumChatFormatting.GRAY+"Lowest BIN: "+ + EnumChatFormatting.GOLD+format.format(lowestBin)+" coins"); + } + if(hasAuctionPrice) { + int auctionPrice = (int)(auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat()); + newTooltip.add(EnumChatFormatting.GRAY+"AH Price: "+ + EnumChatFormatting.GOLD+format.format(auctionPrice)+" coins"); + newTooltip.add(EnumChatFormatting.GRAY+"AH Sales: "+ + EnumChatFormatting.GOLD+format.format(auctionInfo.get("sales").getAsFloat())+" sales/day"); + if(auctionInfo.has("clean_price")) { + newTooltip.add(EnumChatFormatting.GRAY+"AH Price (Clean): "+ + EnumChatFormatting.GOLD+format.format((int)auctionInfo.get("clean_price").getAsFloat())+" coins"); + newTooltip.add(EnumChatFormatting.GRAY+"AH Sales (Clean): "+ + EnumChatFormatting.GOLD+format.format(auctionInfo.get("clean_sales").getAsFloat())+" sales/day"); + } + + } + if(craftCost.fromRecipe) { + newTooltip.add(EnumChatFormatting.GRAY+"Raw Craft Cost: "+ + EnumChatFormatting.GOLD+format.format((int)craftCost.craftCost)+" coins"); + } + } + } + } + } + + if(neu.manager.config.dungeonProfitLore.value && Minecraft.getMinecraft().currentScreen instanceof GuiChest) { + if(line.contains(EnumChatFormatting.GREEN+"Open Reward Chest")) { + dungeonProfit = true; + } else if(index == 7 && dungeonProfit) { + GuiChest eventGui = (GuiChest) Minecraft.getMinecraft().currentScreen; + ContainerChest cc = (ContainerChest) eventGui.inventorySlots; + IInventory lower = cc.getLowerChestInventory(); + + int chestCost = 0; + String line6 = Utils.cleanColour(line); + StringBuilder cost = new StringBuilder(); + for(int i=0; i<line6.length(); i++) { + char c = line6.charAt(i); + if("0123456789".indexOf(c) >= 0) { + cost.append(c); + } + } + if(cost.length() > 0) { + chestCost = Integer.parseInt(cost.toString()); + } + + boolean missing = false; + int totalValueBIN = 0; + int totalValueAUC = 0; + for(int i=0; i<5; i++) { + ItemStack item = lower.getStackInSlot(11+i); + String internal = neu.manager.getInternalNameForItem(item); + if(internal != null) { + float worthBIN = neu.manager.auctionManager.getLowestBin(internal); + float worthAUC = neu.manager.auctionManager.getLowestBin(internal); + + if(worthAUC == -1) worthAUC = neu.manager.auctionManager.getCraftCost(internal).craftCost; + + if(worthAUC <= 0 && worthBIN <= 0) { + missing = true; + break; + } + + if(worthBIN > 0 && totalValueBIN >= 0) { + totalValueBIN += worthBIN; + } else { + totalValueBIN = -1; + } + + if(worthAUC > 0 && totalValueAUC >= 0) { + totalValueAUC += worthAUC; + } else { + totalValueAUC = -1; + } + } + } + if(totalValueAUC <= 0 && totalValueBIN <= 0) { + missing = true; + } + + String neu = EnumChatFormatting.YELLOW + "[NEU] "; + if(missing) { + newTooltip.add(neu + EnumChatFormatting.BLUE+"Couldn't find item on AH. Item is very rare!"); + } else { + NumberFormat format = NumberFormat.getInstance(Locale.US); + String valueStringBIN = EnumChatFormatting.YELLOW+"Value (BIN): " + EnumChatFormatting.GOLD + + EnumChatFormatting.BOLD + format.format(totalValueBIN) + " coins"; + String valueStringAUC = EnumChatFormatting.YELLOW+"Value (AUC): " + EnumChatFormatting.GOLD + + EnumChatFormatting.BOLD + format.format(totalValueAUC) + " coins"; + + + int profitLossBIN = totalValueBIN - chestCost; + String plStringBIN; + if(profitLossBIN >= 0) { + plStringBIN = EnumChatFormatting.YELLOW+"Profit/Loss: " + EnumChatFormatting.DARK_GREEN + + EnumChatFormatting.BOLD + "+" + format.format(profitLossBIN) + " coins"; + } else { + plStringBIN = EnumChatFormatting.YELLOW+"Profit/Loss: " + EnumChatFormatting.RED + + EnumChatFormatting.BOLD + "-" + format.format(-profitLossBIN) + " coins"; + } + + int profitLossAUC = totalValueAUC - chestCost; + String plStringAUC; + if(profitLossAUC >= 0) { + plStringAUC = EnumChatFormatting.YELLOW+"Profit/Loss: " + EnumChatFormatting.DARK_GREEN + + EnumChatFormatting.BOLD + "+" + format.format(profitLossAUC) + " coins"; + } else { + plStringAUC = EnumChatFormatting.YELLOW+"Profit/Loss: " + EnumChatFormatting.RED + + EnumChatFormatting.BOLD + "-" + format.format(-profitLossAUC) + " coins"; + } + + newTooltip.add(neu + valueStringBIN); + newTooltip.add(neu + plStringBIN); + newTooltip.add(neu + valueStringAUC); + newTooltip.add(neu + plStringAUC); + } + } + } + + index++; + } + + event.toolTip.clear(); + event.toolTip.addAll(newTooltip); + + if(neu.manager.config.invAuctionPrice.value || neu.manager.config.invBazaarPrice.value) { + String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(event.itemStack); + + if(internalname != null) { + JsonObject auctionInfo = neu.manager.auctionManager.getItemAuctionInfo(internalname); + JsonObject bazaarInfo = neu.manager.auctionManager.getBazaarInfo(internalname); + + int lowestBin = neu.manager.auctionManager.getLowestBin(internalname); + APIManager.CraftInfo craftCost = neu.manager.auctionManager.getCraftCost(internalname); + + boolean hasAuctionPrice = neu.manager.config.invAuctionPrice.value && auctionInfo != null; + boolean hasBazaarPrice = neu.manager.config.invBazaarPrice.value && bazaarInfo != null; + boolean hasLowestBinPrice = neu.manager.config.invAuctionPrice.value && lowestBin > 0; + + NumberFormat format = NumberFormat.getInstance(Locale.US); + + if(hasAuctionPrice || hasBazaarPrice || hasLowestBinPrice) event.toolTip.add(""); + if(hasLowestBinPrice) { + event.toolTip.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Lowest BIN: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(lowestBin)+" coins"); + } + if(hasAuctionPrice) { + int auctionPrice = (int)(auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat()); + event.toolTip.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"AH Price: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(auctionPrice)+" coins"); + if(neu.manager.config.advancedPriceInfo.value) { + event.toolTip.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"AH Sales: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(auctionInfo.get("sales").getAsFloat())+" sales/day"); + } + if(auctionInfo.has("clean_price")) { + event.toolTip.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"AH Price (Clean): "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format((int)auctionInfo.get("clean_price").getAsFloat())+" coins"); + if(neu.manager.config.advancedPriceInfo.value) { + event.toolTip.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"AH Sales (Clean): "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(auctionInfo.get("clean_sales").getAsFloat())+" sales/day"); + } + } + } else if(hasBazaarPrice) { + int stackMultiplier = 1; + int shiftStackMultiplier = event.itemStack.stackSize > 1 ? event.itemStack.stackSize : 64; + if(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) { + stackMultiplier = shiftStackMultiplier; + } else { + event.toolTip.add(EnumChatFormatting.DARK_GRAY.toString()+"[SHIFT show x"+shiftStackMultiplier+"]"); + } + if(bazaarInfo.has("avg_buy")) { + int bazaarBuyPrice = (int)bazaarInfo.get("avg_buy").getAsFloat()*stackMultiplier; + event.toolTip.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Buy: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarBuyPrice)+" coins"); + } + if(bazaarInfo.has("avg_sell")) { + int bazaarSellPrice = (int)bazaarInfo.get("avg_sell").getAsFloat()*stackMultiplier; + event.toolTip.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Sell: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarSellPrice)+" coins"); + } + if(neu.manager.config.advancedPriceInfo.value) { + if(bazaarInfo.has("curr_buy")) { + int bazaarInstantBuyPrice = (int)bazaarInfo.get("curr_buy").getAsFloat()*stackMultiplier; + event.toolTip.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Insta-Buy: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarInstantBuyPrice)+" coins"); + } + if(bazaarInfo.has("curr_sell")) { + int bazaarInstantSellPrice = (int)bazaarInfo.get("curr_sell").getAsFloat()*stackMultiplier; + event.toolTip.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Insta-Sell: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarInstantSellPrice)+" coins"); + } + } + } + if((hasAuctionPrice || hasBazaarPrice) && craftCost.fromRecipe) { + event.toolTip.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Raw Craft Cost: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format((int)craftCost.craftCost)+" coins"); + } + } + } + } + + /** + * This makes it so that holding LCONTROL while hovering over an item with NBT will show the NBT of the item. + * @param event + */ + @SubscribeEvent + public void onItemTooltip(ItemTooltipEvent event) { + if(!neu.isOnSkyblock()) return; + if(neu.manager.config.hideEmptyPanes.value && + event.itemStack.getItem().equals(Item.getItemFromBlock(Blocks.stained_glass_pane))) { + String first = Utils.cleanColour(event.toolTip.get(0)); + first = first.replaceAll("\\(.*\\)", "").trim(); + if(first.length() == 0) { + event.toolTip.clear(); + } + } + //AH prices + /*if(Minecraft.getMinecraft().currentScreen != null) { + if(Minecraft.getMinecraft().currentScreen instanceof GuiChest) { + GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen; + ContainerChest container = (ContainerChest) chest.inventorySlots; + String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText(); + if(containerName.trim().equals("Auctions Browser")) { + String internalname = neu.manager.getInternalNameForItem(event.itemStack); + if(internalname != null) { + for(int i=0; i<event.toolTip.size(); i++) { + String line = event.toolTip.get(i); + if(line.contains(EnumChatFormatting.GRAY + "Bidder: ") || + line.contains(EnumChatFormatting.GRAY + "Starting bid: ") || + line.contains(EnumChatFormatting.GRAY + "Buy it now: ")) { + neu.manager.updatePrices(); + JsonObject auctionInfo = neu.manager.getItemAuctionInfo(internalname); + + if(auctionInfo != null) { + NumberFormat format = NumberFormat.getInstance(Locale.US); + int auctionPrice = (int)(auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat()); + float costOfEnchants = neu.manager.getCostOfEnchants(internalname, + event.itemStack.getTagCompound()); + int priceWithEnchants = auctionPrice+(int)costOfEnchants; + + event.toolTip.add(++i, EnumChatFormatting.GRAY + "Average price: " + + EnumChatFormatting.GOLD + format.format(auctionPrice) + " coins"); + if(costOfEnchants > 0) { + event.toolTip.add(++i, EnumChatFormatting.GRAY + "Average price (w/ enchants): " + + EnumChatFormatting.GOLD + + format.format(priceWithEnchants) + " coins"); + } + + if(neu.manager.config.advancedPriceInfo.value) { + int salesVolume = (int) auctionInfo.get("sales").getAsFloat(); + int flipPrice = (int)(0.93*priceWithEnchants); + + event.toolTip.add(++i, EnumChatFormatting.GRAY + "Flip Price (93%): " + + EnumChatFormatting.GOLD + format.format(flipPrice) + " coins"); + event.toolTip.add(++i, EnumChatFormatting.GRAY + "Volume: " + + EnumChatFormatting.GOLD + format.format(salesVolume) + " sales/day"); + } + break; + } + } + } + } + } + } + }*/ + if(!Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || !neu.manager.config.dev.value) return; + if(event.toolTip.size()>0&&event.toolTip.get(event.toolTip.size()-1).startsWith(EnumChatFormatting.DARK_GRAY + "NBT: ")) { + event.toolTip.remove(event.toolTip.size()-1); + + StringBuilder sb = new StringBuilder(); + String nbt = event.itemStack.getTagCompound().toString(); + int indent = 0; + for(char c : nbt.toCharArray()) { + boolean newline = false; + if(c == '{' || c == '[') { + indent++; + newline = true; + } else if(c == '}' || c == ']') { + indent--; + sb.append("\n"); + for(int i=0; i<indent; i++) sb.append(" "); + } else if(c == ',') { + newline = true; + } else if(c == '\"') { + sb.append(EnumChatFormatting.RESET.toString() + EnumChatFormatting.GRAY); + } + + sb.append(c); + if(newline) { + sb.append("\n"); + for(int i=0; i<indent; i++) sb.append(" "); + } + } + event.toolTip.add(sb.toString()); + if(Keyboard.isKeyDown(Keyboard.KEY_H)) { + StringSelection selection = new StringSelection(sb.toString()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection); + } + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUIO.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUIO.java deleted file mode 100644 index b9f086a4..00000000 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUIO.java +++ /dev/null @@ -1,109 +0,0 @@ -package io.github.moulberry.notenoughupdates; - -import org.kohsuke.github.*; - -import java.io.IOException; -import java.util.*; - -public class NEUIO { - - private final String accessToken; - - /** - * THIS CLASS PROVIDES METHODS FOR INTERFACING WITH THE GIT REPOSITORY NotEnoughUpdates-REPO. THIS REPOSITORY - * CONTAINS ALL THE JSON ITEMS. THIS SHOULD NOT BE A PERMANENT SOLUTION AND I SHOULD LOOK AT USING SOME FORM OF - * HOSTING SERVICE OTHER THAN A GIT REPOSITORY IF THE USERBASE OF THE MOD GROWS SIGNIFICANTLY. UNFORTUNATELY I - * CANT AFFORD HOSTING RIGHT NOW SO THIS IS WHAT YOU GET AND GITHUB WILL PROBABLY THROW A FIT IF A LARGE NUMBER - * OF USERS START DOWNLOADING FROM THE REPO ALL AT ONCE. - */ - - public NEUIO(String accessToken) { - this.accessToken = accessToken; - } - - /** - * Creates a new branch, commits to it with a single file change and submits a pull request from the new branch - * back to the master branch. - */ - public boolean createNewRequest(String newBranchName, String prTitle, String prBody, String filename, String content) { - try { - GitHub github = new GitHubBuilder().withOAuthToken(accessToken).build(); - System.out.println("Getting repo"); - - //https://github.com/Moulberry/NotEnoughUpdates-REPO - GHRepository repo = github.getRepositoryById("247692460"); - - System.out.println("Getting last commit"); - String lastCommitSha = repo.getRef("heads/master").getObject().getSha(); - System.out.println("Last master commit sha: " + lastCommitSha); - - String lastTreeSha = repo.getCommit(lastCommitSha).getTree().getSha(); - - GHTreeBuilder tb = repo.createTree(); - tb.baseTree(lastTreeSha); - tb.add(filename, content, false); - GHTree tree = tb.create(); - System.out.println("Created new tree: " + tree.getSha()); - - GHCommitBuilder cb = repo.createCommit(); - cb.message(prTitle); - cb.tree(tree.getSha()); - cb.parent(lastCommitSha); - GHCommit commit = cb.create(); - System.out.println("Created commit: " + commit.getSHA1()); - - repo.createRef("refs/heads/"+newBranchName, commit.getSHA1()); - System.out.println("Set new branch head to commit."); - - repo.createPullRequest(prTitle, newBranchName, "master", prBody); - return true; - } catch(IOException e) { - e.printStackTrace(); - return false; - } - } - - /** - * @param oldShas Map from filename (eg. BOW.json) to the sha in the local repository - * @return Map from filename to the new shas - */ - public Map<String, String> getChangedItems(Map<String, String> oldShas) { - HashMap<String, String> changedFiles = new HashMap<>(); - try { - GitHub github = new GitHubBuilder().withOAuthToken(accessToken).build(); - GHRepository repo = github.getRepositoryById("247692460"); - - for(GHTreeEntry treeEntry : repo.getTreeRecursive("master", 1).getTree()) { - if(treeEntry.getPath().contains(".")) { - String oldSha = oldShas.get(treeEntry.getPath()); - if(!treeEntry.getSha().equals(oldSha)) { - changedFiles.put(treeEntry.getPath(), treeEntry.getSha()); - } - } - } - } catch(IOException e) { - return null; - } - return changedFiles; - } - - public Set<String> getRemovedItems(Set<String> currentlyInstalled) { - Set<String> removedItems = new HashSet<>(); - Set<String> repoItems = new HashSet<>(); - try { - GitHub github = new GitHubBuilder().withOAuthToken(accessToken).build(); - GHRepository repo = github.getRepositoryById("247692460"); - - for(GHTreeEntry treeEntry : repo.getTreeRecursive("master", 1).getTree()) { - String[] split = treeEntry.getPath().split("/"); - repoItems.add(split[split.length-1].split("\\.")[0]); - } - } catch(IOException e) { - e.printStackTrace(); - return removedItems; - } - removedItems.addAll(currentlyInstalled); - removedItems.removeAll(repoItems); - return removedItems; - } -} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java index 8d625c14..8073227c 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java @@ -5,11 +5,13 @@ import com.google.gson.*; import io.github.moulberry.notenoughupdates.auction.APIManager; import io.github.moulberry.notenoughupdates.cosmetics.CapeManager; import io.github.moulberry.notenoughupdates.options.Options; +import io.github.moulberry.notenoughupdates.util.Constants; import io.github.moulberry.notenoughupdates.util.HypixelApi; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.client.settings.KeyBinding; import net.minecraft.init.Blocks; +import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.*; @@ -21,8 +23,13 @@ import org.lwjgl.opengl.Display; import javax.swing.*; import java.io.*; import java.net.URL; +import java.net.URLConnection; import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -30,7 +37,6 @@ import java.util.zip.ZipInputStream; public class NEUManager { private final NotEnoughUpdates neu; - public final NEUIO neuio; public final Gson gson; public final APIManager auctionManager; @@ -45,7 +51,9 @@ public class NEUManager { public final KeyBinding keybindViewRecipe = new KeyBinding("Show recipe for item", Keyboard.KEY_R, "NotEnoughUpdates"); public final KeyBinding keybindToggleDisplay = new KeyBinding("Toggle NEU overlay", 0, "NotEnoughUpdates"); public final KeyBinding keybindClosePanes = new KeyBinding("Close NEU panes", 0, "NotEnoughUpdates"); - public final KeyBinding[] keybinds = new KeyBinding[]{keybindGive, keybindFavourite, keybindViewUsages, keybindViewRecipe, keybindToggleDisplay, keybindClosePanes}; + public final KeyBinding keybindItemSelect = new KeyBinding("Select Item", -98 /*middle*/, "NotEnoughUpdates"); + public final KeyBinding[] keybinds = new KeyBinding[]{ keybindGive, keybindFavourite, keybindViewUsages, keybindViewRecipe, + keybindToggleDisplay, keybindClosePanes, keybindItemSelect}; public String viewItemAttemptID = null; public long viewItemAttemptTime = 0; @@ -57,24 +65,23 @@ public class NEUManager { private ResourceLocation wkZip = new ResourceLocation("notenoughupdates:wkhtmltox.zip"); private Map<String, ItemStack> itemstackCache = new HashMap<>(); - private static final String AUCTIONS_PRICE_URL = "https://moulberry.github.io/files/auc_avg_jsons/average_3day.json.gz"; - private JsonObject auctionPricesJson = null; - private long auctionLastUpdate = 0; + //private static final String AUCTIONS_PRICE_URL = "https://moulberry.github.io/files/auc_avg_jsons/average_3day.json.gz"; + private static final String GIT_COMMITS_URL = "https://api.github.com/repos/Moulberry/NotEnoughUpdates-REPO/commits/master"; - private HashMap<String, CraftInfo> craftCost = new HashMap<>(); private HashMap<String, Set<String>> usagesMap = new HashMap<>(); + public String latestRepoCommit = null; + public File configLocation; public File repoLocation; - private File itemShaLocation; - private JsonObject itemShaConfig; public File configFile; + public File itemRenameFile; + public JsonObject itemRenameJson; public Options config; - public NEUManager(NotEnoughUpdates neu, NEUIO neuio, File configLocation) { + public NEUManager(NotEnoughUpdates neu, File configLocation) { this.neu = neu; this.configLocation = configLocation; - this.neuio = neuio; this.auctionManager = new APIManager(this); GsonBuilder gsonBuilder = new GsonBuilder().setPrettyPrinting(); @@ -87,12 +94,11 @@ public class NEUManager { this.repoLocation = new File(configLocation, "repo"); repoLocation.mkdir(); - this.itemShaLocation = new File(configLocation, "itemSha.json"); - try { - itemShaLocation.createNewFile(); - itemShaConfig = getJsonFromFile(itemShaLocation); - if(itemShaConfig == null) itemShaConfig = new JsonObject(); - } catch(IOException e) { } + this.itemRenameFile = new File(configLocation, "itemRename.json"); + itemRenameJson = getJsonFromFile(itemRenameFile); + if(itemRenameJson == null) { + itemRenameJson = new JsonObject(); + } File wkShell = new File(configLocation, "wkhtmltox/bin/wkhtmltoimage"); if(!wkShell.exists()) { @@ -104,12 +110,6 @@ public class NEUManager { } } - public class CraftInfo { - public boolean fromRecipe = false; - public boolean vanillaItem = false; - public float craftCost = -1; - } - public void setCurrentProfile(String currentProfile) { this.currentProfile = currentProfile; } @@ -126,85 +126,8 @@ public class NEUManager { } } - public boolean isVanillaItem(String internalname) { - //Removes trailing numbers and underscores, eg. LEAVES_2-3 -> LEAVES - String vanillaName = internalname.split("-")[0]; - int sub = 0; - for(int i=vanillaName.length()-1; i>1; i--) { - char c = vanillaName.charAt(i); - if((int)c >= 48 && (int)c <= 57) { //0-9 - sub++; - } else if(c == '_') { - sub++; - break; - } else { - break; - } - } - vanillaName = vanillaName.substring(0, vanillaName.length()-sub).toLowerCase(); - return Item.itemRegistry.getObject(new ResourceLocation(vanillaName)) != null; - } - - /** - * Recursively calculates the cost of crafting an item from raw materials. - */ - public CraftInfo getCraftCost(String internalname) { - if(craftCost.containsKey(internalname)) { - return craftCost.get(internalname); - } else { - CraftInfo ci = new CraftInfo(); - - ci.vanillaItem = isVanillaItem(internalname); - - JsonObject auctionInfo = getItemAuctionInfo(internalname); - JsonObject bazaarInfo = getBazaarInfo(internalname); - - if(bazaarInfo != null) { - float bazaarInstantBuyPrice = bazaarInfo.get("curr_buy").getAsFloat(); - ci.craftCost = bazaarInstantBuyPrice; - } - if(auctionInfo != null && !ci.vanillaItem) { //Don't use auction prices for vanilla items cuz people like to transfer money, messing up the cost of vanilla items. - float auctionPrice = auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat(); - if(ci.craftCost < 0 || auctionPrice < ci.craftCost) { - ci.craftCost = auctionPrice; - } - } - JsonObject item = getItemInformation().get(internalname); - if(item != null && item.has("recipe")) { - float craftPrice = 0; - JsonObject recipe = item.get("recipe").getAsJsonObject(); - - 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(); - if(itemS.length() == 0) continue; - - int count = 1; - if(itemS != null && itemS.split(":").length == 2) { - count = Integer.valueOf(itemS.split(":")[1]); - itemS = itemS.split(":")[0]; - } - float compCost = getCraftCost(itemS).craftCost * count; - if(compCost < 0) { - if(!getCraftCost(itemS).vanillaItem) { //If it's a vanilla item without a cost attached to it, let compCost = 0. - craftCost.put(internalname, ci); - return ci; - } - } else { - craftPrice += compCost; - } - } - - if(ci.craftCost < 0 || craftPrice < ci.craftCost) { - ci.craftCost = craftPrice; - ci.fromRecipe = true; - } - } - craftCost.put(internalname, ci); - return ci; - } + public void saveItemRenameConfig() { + try { writeJson(itemRenameJson, itemRenameFile); } catch(IOException ignored) {} } public void saveConfig() throws IOException { @@ -222,257 +145,233 @@ public class NEUManager { } /** - * Downloads and sets auctionPricesJson from the URL specified by AUCTIONS_PRICE_URL. + * Parses a file in to a JsonObject. */ - public void updatePrices() { - if(System.currentTimeMillis() - auctionLastUpdate > 1000*60*120) { //2 hours - craftCost.clear(); - System.out.println("UPDATING PRICE INFORMATION"); - auctionLastUpdate = System.currentTimeMillis(); - try(Reader inReader = new InputStreamReader(new GZIPInputStream(new URL(AUCTIONS_PRICE_URL).openStream()))) { - auctionPricesJson = gson.fromJson(inReader, JsonObject.class); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - public boolean hasAuctionInfo(String internalname) { - return auctionPricesJson.has("item_data") && auctionPricesJson.get("item_data").getAsJsonObject().has(internalname); - } - - public boolean hasBazaarInfo(String internalname) { - return auctionPricesJson.has("bazaar") && auctionPricesJson.get("bazaar").getAsJsonObject().has(internalname); - } - - public JsonObject getItemAuctionInfo(String internalname) { - if(!hasAuctionInfo(internalname)) return null; - JsonElement e = auctionPricesJson.get("item_data").getAsJsonObject().get(internalname); - if(e == null) { - return null; - } - return e.getAsJsonObject(); + public JsonObject getJsonFromFile(File file) { + try(BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) { + JsonObject json = gson.fromJson(reader, JsonObject.class); + return json; + } catch(Exception e) { return null; } } - public JsonObject getBazaarInfo(String internalname) { - if(!hasBazaarInfo(internalname)) return null; - JsonElement e = auctionPricesJson.get("bazaar").getAsJsonObject().get(internalname); - if(e == null) { - return null; - } - return e.getAsJsonObject(); + public void resetRepo() { + try { Utils.recursiveDelete(new File(configLocation, "repo")); } catch(Exception e) {} + try { new File(configLocation, "currentCommit.json").delete(); } catch(Exception e) {} } /** - * Calculates the cost of enchants + other price modifiers such as pet xp, midas price, etc. + * 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 float getCostOfEnchants(String internalname, NBTTagCompound tag) { - float costOfEnchants = 0; - if(true) return 0; - - JsonObject info = getItemAuctionInfo(internalname); - if(info == null || !info.has("price")) { - return 0; - } - if(!auctionPricesJson.has("ench_prices") || !auctionPricesJson.has("ench_maximums")) { - return 0; - } - JsonObject ench_prices = auctionPricesJson.getAsJsonObject("ench_prices"); - JsonObject ench_maximums = auctionPricesJson.getAsJsonObject("ench_maximums"); - if(!ench_prices.has(internalname) || !ench_maximums.has(internalname)) { - return 0; - } - JsonObject iid_variables = ench_prices.getAsJsonObject(internalname); - float ench_maximum = ench_maximums.get(internalname).getAsFloat(); + public void loadItemInformation() { + /*File repoFile = new File(configLocation, "repo2"); + repoFile.mkdirs(); + + try(Git git = Git.init().setDirectory(repoFile).call()) { + StoredConfig config = git.getRepository().getConfig(); + config.setString("branch", "master", "merge", "refs/heads/master"); + config.setString("branch", "master", "remote", "origin"); + config.setString("remote", "origin", "fetch", "+refs/heads/*:refs/remotes/origin/*"); + config.setString("remote", "origin", "url", "https://github.com/Moulberry/NotEnoughUpdates-REPO.git"); + config.save(); + + git.remoteAdd().setName("origin").setUri(new URIish("https://github.com/Moulberry/NotEnoughUpdates-REPO.git")).call(); + PullResult result = git.pull().setRemote("origin").setTimeout(30000).call(); + System.out.println("successful pull: " + result.isSuccessful()); + } catch(Exception e) { + e.printStackTrace(); + }*/ - int enchants = 0; - float price = getItemAuctionInfo(internalname).get("price").getAsFloat(); - if(tag.hasKey("ExtraAttributes")) { - NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); - if(ea.hasKey("enchantments")) { - - NBTTagCompound enchs = ea.getCompoundTag("enchantments"); - for(String ench : enchs.getKeySet()) { - enchants++; - int level = enchs.getInteger(ench); - - for(Map.Entry<String, JsonElement> entry : iid_variables.entrySet()) { - if(matchEnch(ench, level, entry.getKey())) { - costOfEnchants += entry.getValue().getAsJsonObject().get("A").getAsFloat()*price + - entry.getValue().getAsJsonObject().get("B").getAsFloat(); - break; - } - } - } + /*if(repoFile.mkdirs()) { + try { + Git.cloneRepository() + .setURI("https://github.com/Moulberry/NotEnoughUpdates-REPO.git") + .setDirectory(repoFile) + .call(); + } catch(Exception e) { + e.printStackTrace(); } - } - return costOfEnchants; - } - - /** - * Checks whether a certain enchant (ench name + lvl) matches an enchant id - * eg. PROTECTION_GE6 will match -> ench_name = PROTECTION, lvl >= 6 - */ - private boolean matchEnch(String ench, int level, String id) { - if(!id.contains(":")) { - return false; - } + } else { - String idEnch = id.split(":")[0]; - String idLevel = id.split(":")[1]; + }*/ - if(!ench.equalsIgnoreCase(idEnch)) { - return false; - } - if(String.valueOf(level).equalsIgnoreCase(idLevel)) { - return true; - } - if(idLevel.startsWith("LE")) { - int idLevelI = Integer.valueOf(idLevel.substring(2)); - return level <= idLevelI; - } else if(idLevel.startsWith("GE")) { - int idLevelI = Integer.valueOf(idLevel.substring(2)); - return level >= idLevelI; - } + Thread thread = new Thread(() -> { + JDialog dialog = null; + try { + if(config.autoupdate.value) { + JOptionPane pane = new JOptionPane("Getting items to download from remote repository."); + dialog = pane.createDialog("NotEnoughUpdates Remote Sync"); + dialog.setModal(false); + if(config.dev.value) dialog.setVisible(true); - return false; - } + if (Display.isActive()) dialog.toFront(); - /** - * Parses a file in to a JsonObject. - */ - public JsonObject getJsonFromFile(File file) throws IOException { - try { - InputStream in = new FileInputStream(file); - BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); - JsonObject json = gson.fromJson(reader, JsonObject.class); - return json; - } catch(Exception e) { return null; } - } + JsonObject currentCommitJSON = getJsonFromFile(new File(configLocation, "currentCommit.json")); - /** - * 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() { - try { - 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(); - - HashMap<String, String> oldShas = new HashMap<>(); - for (Map.Entry<String, JsonElement> entry : itemShaConfig.entrySet()) { - if (new File(repoLocation, entry.getKey() + ".json").exists()) { - oldShas.put(entry.getKey() + ".json", entry.getValue().getAsString()); + latestRepoCommit = null; + try(Reader inReader = new InputStreamReader(new URL(GIT_COMMITS_URL).openStream())) { + JsonObject commits = gson.fromJson(inReader, JsonObject.class); + latestRepoCommit = commits.get("sha").getAsString(); + } catch (Exception e) { + e.printStackTrace(); } - } - Map<String, String> changedFiles = neuio.getChangedItems(oldShas); + if(latestRepoCommit == null || latestRepoCommit.isEmpty()) return; - 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(new File(configLocation, "repo").exists() && new File(configLocation, "repo/items").exists()) { + + if(currentCommitJSON != null && currentCommitJSON.get("sha").getAsString().equals(latestRepoCommit)) { + dialog.setVisible(false); + return; + } + + /*HashMap<String, String> oldShas = new HashMap<>(); + for (Map.Entry<String, JsonElement> entry : itemShaConfig.entrySet()) { + if (new File(repoLocation, entry.getKey() + ".json").exists()) { + oldShas.put(entry.getKey() + ".json", entry.getValue().getAsString()); + } + } + changedFiles = neuio.getChangedItems(oldShas);*/ } - } - if (Display.isActive()) dialog.toFront(); + if (Display.isActive()) dialog.toFront(); - if (changedFiles != null && changedFiles.size() <= 20) { + if (false) {//changedFiles != null && changedFiles.size() <= 20) { + /*String startMessage = "NotEnoughUpdates: Syncing with remote repository ("; + int downloaded = 0; - String startMessage = "NotEnoughUpdates: Syncing with remote repository ("; - int downloaded = 0; + String dlUrl = "https://raw.githubusercontent.com/Moulberry/NotEnoughUpdates-REPO/master/"; - String dlUrl = "https://raw.githubusercontent.com/Moulberry/NotEnoughUpdates-REPO/master/"; + for (String name : changedFiles.keySet()) { + pane.setMessage(startMessage + (++downloaded) + "/" + changedFiles.size() + ")\nCurrent: " + name); + dialog.pack(); + if(config.dev.value) dialog.setVisible(true); + if (Display.isActive()) dialog.toFront(); - for (String name : changedFiles.keySet()) { - pane.setMessage(startMessage + (++downloaded) + "/" + changedFiles.size() + ")\nCurrent: " + name); + File item = new File(repoLocation, name); + try { + item.getParentFile().mkdirs(); + item.createNewFile(); + } catch (IOException e) { + continue; + } + URL url = new URL(dlUrl+name); + URLConnection urlConnection = url.openConnection(); + urlConnection.setConnectTimeout(5000); + urlConnection.setReadTimeout(5000); + try (BufferedInputStream inStream = new BufferedInputStream(urlConnection.getInputStream()); + 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); + } + itemShaConfig.addProperty(name.substring(0, name.length() - 5), + changedFiles.get(name)); + } catch (IOException e) { + } + } + try { + writeJson(itemShaConfig, itemShaLocation); + } catch (IOException e) { + e.printStackTrace(); + }*/ + } else { + Utils.recursiveDelete(repoLocation); + repoLocation.mkdirs(); + + //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(config.dev.value) dialog.setVisible(true); if (Display.isActive()) dialog.toFront(); - File item = new File(repoLocation, name); + File itemsZip = new File(repoLocation, "neu-items-master.zip"); try { - item.createNewFile(); + itemsZip.createNewFile(); } catch (IOException e) { + return; } - try (BufferedInputStream inStream = new BufferedInputStream(new URL(dlUrl+name).openStream()); - FileOutputStream fileOutputStream = new FileOutputStream(item)) { + URL url = new URL(dlUrl); + URLConnection urlConnection = url.openConnection(); + urlConnection.setConnectTimeout(15000); + urlConnection.setReadTimeout(20000); + try (BufferedInputStream inStream = new BufferedInputStream(urlConnection.getInputStream()); + 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) { + dialog.dispose(); + return; } - } - } else { - Utils.recursiveDelete(repoLocation); - repoLocation.mkdirs(); - //TODO: Store hard-coded value somewhere else - String dlUrl = "https://github.com/Moulberry/NotEnoughUpdates-REPO/archive/master.zip"; + pane.setMessage("Unzipping NEU Master Archive."); + dialog.pack(); + //dialog.setVisible(true); + if (Display.isActive()) dialog.toFront(); - pane.setMessage("Downloading NEU Master Archive. (DL# >20)"); - dialog.pack(); - dialog.setVisible(true); - if (Display.isActive()) dialog.toFront(); + unzipIgnoreFirstFolder(itemsZip.getAbsolutePath(), repoLocation.getAbsolutePath()); - File itemsZip = new File(repoLocation, "neu-items-master.zip"); - try { - itemsZip.createNewFile(); - } catch (IOException e) { + /*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) { + } + }*/ } - 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); + + if(currentCommitJSON == null || !currentCommitJSON.get("sha").getAsString().equals(latestRepoCommit)) { + JsonObject newCurrentCommitJSON = new JsonObject(); + newCurrentCommitJSON.addProperty("sha", latestRepoCommit); + try { + writeJson(newCurrentCommitJSON, new File(configLocation, "currentCommit.json")); + } catch (IOException e) { } - } catch (IOException e) { - e.printStackTrace(); } - - pane.setMessage("Unzipping NEU Master Archive."); - dialog.pack(); - dialog.setVisible(true); - if (Display.isActive()) dialog.toFront(); - - unzipIgnoreFirstFolder(itemsZip.getAbsolutePath(), repoLocation.getAbsolutePath()); } - - dialog.dispose(); + } catch(Exception e) { + e.printStackTrace(); + } finally { + if(dialog != null) dialog.dispose(); } - } catch(Exception e) {} - Set<String> currentlyInstalledItems = new HashSet<>(); - for(File f : new File(repoLocation, "items").listFiles()) { - currentlyInstalledItems.add(f.getName().substring(0, f.getName().length()-5)); - } - - Set<String> removedItems; - if(config.autoupdate.value) { - removedItems = neuio.getRemovedItems(currentlyInstalledItems); - } else { - removedItems = new HashSet<>(); - } - for(File f : new File(repoLocation, "items").listFiles()) { - String internalname = f.getName().substring(0, f.getName().length()-5); - if(!removedItems.contains(internalname)) { - loadItem(internalname); + File items = new File(repoLocation, "items"); + if(items.exists()) { + File[] itemFiles = new File(repoLocation, "items").listFiles(); + if(itemFiles != null) { + for(File f : itemFiles) { + String internalname = f.getName().substring(0, f.getName().length()-5); + if(!getItemInformation().keySet().contains(internalname)) { + loadItem(internalname); + } + } + } + } + }); + + File items = new File(repoLocation, "items"); + if(items.exists()) { + File[] itemFiles = new File(repoLocation, "items").listFiles(); + if(itemFiles != null) { + for(File f : itemFiles) { + String internalname = f.getName().substring(0, f.getName().length()-5); + loadItem(internalname); + } } } + + thread.start(); } /** @@ -549,7 +448,7 @@ public class NEUManager { } } } - } catch(IOException e) { + } catch(Exception e) { e.printStackTrace(); } } @@ -810,12 +709,25 @@ public class NEUManager { public JsonObject getJsonFromItemBytes(String item_bytes) { try { NBTTagCompound tag = CompressedStreamTools.readCompressed(new ByteArrayInputStream(Base64.getDecoder().decode(item_bytes))); + //System.out.println(tag.toString()); return getJsonFromNBT(tag); } catch(IOException e) { return null; } } + public String getUUIDFromNBT(NBTTagCompound tag) { + String uuid = null; + if (tag != null && tag.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + + if (ea.hasKey("uuid", 8)) { + uuid = ea.getString("uuid"); + } + } + return uuid; + } + public String getInternalnameFromNBT(NBTTagCompound tag) { String internalname = null; if(tag != null && tag.hasKey("ExtraAttributes", 10)) { @@ -873,7 +785,12 @@ public class NEUManager { } public JsonObject getJsonFromNBT(NBTTagCompound tag) { - tag = tag.getTagList("i", 10).getCompoundTagAt(0); + return getJsonFromNBTEntry(tag.getTagList("i", 10).getCompoundTagAt(0)); + } + + public JsonObject getJsonFromNBTEntry(NBTTagCompound tag) { + if(tag.getKeySet().size() == 0) return null; + int id = tag.getShort("id"); int damage = tag.getShort("Damage"); int count = tag.getShort("Count"); @@ -882,6 +799,7 @@ public class NEUManager { if(id == 141) id = 391; //for some reason hypixel thinks carrots have id 141 String internalname = getInternalnameFromNBT(tag); + if(internalname == null) return null; NBTTagCompound display = tag.getCompoundTag("display"); String[] lore = getLoreFromNBT(tag); @@ -895,16 +813,33 @@ public class NEUManager { String[] info = new String[0]; String clickcommand = ""; - - //public JsonObject createItemJson(String internalname, String itemid, String displayname, String[] lore, - // String crafttext, String infoType, String[] info, - // String clickcommand, int damage, NBTTagCompound nbttag) { - JsonObject item = new JsonObject(); item.addProperty("internalname", internalname); item.addProperty("itemid", itemid); item.addProperty("displayname", displayname); + if(tag != null && tag.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + + byte[] bytes = null; + for(String key : ea.getKeySet()) { + if(key.endsWith("backpack_data") || key.equals("new_year_cake_bag_data")) { + bytes = ea.getByteArray(key); + break; + } + } + if(bytes != null) { + JsonArray bytesArr = new JsonArray(); + for(byte b : bytes) { + bytesArr.add(new JsonPrimitive(b)); + } + item.add("item_contents", bytesArr); + } + if(ea.hasKey("dungeon_item_level")) { + item.addProperty("dungeon_item_level", ea.getInteger("dungeon_item_level")); + } + } + if(lore != null && lore.length > 0) { JsonArray jsonLore = new JsonArray(); for (String line : lore) { @@ -998,6 +933,12 @@ public class NEUManager { return getInternalnameFromNBT(tag); } + public String getUUIDForItem(ItemStack stack) { + if(stack == null) return null; + NBTTagCompound tag = stack.getTagCompound(); + return getUUIDFromNBT(tag); + } + public void writeItemToFile(ItemStack stack) { String internalname = getInternalNameForItem(stack); @@ -1060,8 +1001,6 @@ public class NEUManager { } if(craftMatrices.size() > 0) { - Minecraft.getMinecraft().thePlayer.sendQueue.addToSendQueue(new C0DPacketCloseWindow( - Minecraft.getMinecraft().thePlayer.openContainer.windowId)); Minecraft.getMinecraft().displayGuiScreen(new GuiItemRecipe("Item Usages", craftMatrices, results, this)); return true; } @@ -1304,9 +1243,9 @@ public class NEUManager { String prTitle = internalname + "-" + username; String prBody = "Internal name: " + internalname + "\nSubmitted by: " + username; String file = "items/"+internalname+".json"; - if(!neuio.createNewRequest(newBranchName, prTitle, prBody, file, gson.toJson(json))) { + /*if(!neuio.createNewRequest(newBranchName, prTitle, prBody, file, gson.toJson(json))) { return false; - } + }*/ try { writeJsonDefaultDir(json, internalname+".json"); @@ -1335,11 +1274,134 @@ public class NEUManager { return itemMap; } + public String removeUnusedDecimal(double num) { + if(num % 1 == 0) { + return String.valueOf((int)num); + } else { + return String.valueOf(num); + } + } + + public HashMap<String, String> getLoreReplacements(String petname, String tier, int level) { + JsonObject petnums = null; + if(petname != null && tier != null) { + petnums = Constants.PETNUMS; + } + + HashMap<String, String> replacements = new HashMap<>(); + if(level < 1) { + replacements.put("LVL", "1\u27A1100"); + } else { + replacements.put("LVL", ""+level); + } + if(petnums != null) { + if(petnums.has(petname)) { + JsonObject petInfo = petnums.get(petname).getAsJsonObject(); + if(petInfo.has(tier)) { + JsonObject petInfoTier = petInfo.get(tier).getAsJsonObject(); + if(petInfoTier == null || !petInfoTier.has("1") || !petInfoTier.has("100")) { + return replacements; + } + + JsonObject min = petInfoTier.get("1").getAsJsonObject(); + JsonObject max = petInfoTier.get("100").getAsJsonObject(); + + if(level < 1) { + JsonArray otherNumsMin = min.get("otherNums").getAsJsonArray(); + JsonArray otherNumsMax = max.get("otherNums").getAsJsonArray(); + for(int i=0; i<otherNumsMax.size(); i++) { + replacements.put(""+i, removeUnusedDecimal(Math.floor(otherNumsMin.get(i).getAsFloat()*10)/10f)+ + "\u27A1"+removeUnusedDecimal(Math.floor(otherNumsMax.get(i).getAsFloat()*10)/10f)); + } + + for(Map.Entry<String, JsonElement> entry : max.get("statNums").getAsJsonObject().entrySet()) { + int statMax = (int)Math.floor(entry.getValue().getAsFloat()); + int statMin = (int)Math.floor(min.get("statNums").getAsJsonObject().get(entry.getKey()).getAsFloat()); + String statStr = (statMin>0?"+":"")+statMin+"\u27A1"+statMax; + replacements.put(entry.getKey(), statStr); + } + } else { + float minMix = (100-level)/99f; + float maxMix = (level-1)/99f; + + JsonArray otherNumsMin = min.get("otherNums").getAsJsonArray(); + JsonArray otherNumsMax = max.get("otherNums").getAsJsonArray(); + for(int i=0; i<otherNumsMax.size(); i++) { + float val = otherNumsMin.get(i).getAsFloat()*minMix + otherNumsMax.get(i).getAsFloat()*maxMix; + replacements.put(""+i, removeUnusedDecimal(Math.floor(val*10)/10f)); + } + + for(Map.Entry<String, JsonElement> entry : max.get("statNums").getAsJsonObject().entrySet()) { + float statMax = entry.getValue().getAsFloat(); + float statMin = min.get("statNums").getAsJsonObject().get(entry.getKey()).getAsFloat(); + float val = statMin*minMix + statMax*maxMix; + String statStr = (statMin>0?"+":"")+(int)Math.floor(val); + replacements.put(entry.getKey(), statStr); + } + } + } + } + } + + return replacements; + } + + public HashMap<String, String> getLoreReplacements(NBTTagCompound tag, int level) { + String petname = null; + String tier = null; + if(tag != null && tag.hasKey("ExtraAttributes")) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + if(ea.hasKey("petInfo")) { + String petInfoStr = ea.getString("petInfo"); + JsonObject petInfo = gson.fromJson(petInfoStr, JsonObject.class); + petname = petInfo.get("type").getAsString(); + tier = petInfo.get("tier").getAsString(); + if(petInfo.has("heldItem")) { + String heldItem = petInfo.get("heldItem").getAsString(); + if(heldItem.equals("PET_ITEM_TIER_BOOST")) { + switch(tier) { + case "COMMON": + tier = "UNCOMMON"; break; + case "UNCOMMON": + tier = "RARE"; break; + case "RARE": + tier = "EPIC"; break; + case "EPIC": + tier = "LEGENDARY"; break; + } + } + } + } + } + return getLoreReplacements(petname, tier, level); + } + + public NBTTagList processLore(JsonArray lore, HashMap<String, String> replacements) { + NBTTagList nbtLore = new NBTTagList(); + for(JsonElement line : lore) { + String lineStr = line.getAsString(); + if(!lineStr.contains("Click to view recipes!") && + !lineStr.contains("Click to view recipe!")) { + for(Map.Entry<String, String> entry : replacements.entrySet()) { + lineStr = lineStr.replace("{"+entry.getKey()+"}", entry.getValue()); + } + nbtLore.appendTag(new NBTTagString(lineStr)); + } + } + return nbtLore; + } + public ItemStack jsonToStack(JsonObject json) { return jsonToStack(json, true); } public ItemStack jsonToStack(JsonObject json, boolean useCache) { + return jsonToStack(json, useCache, true); + } + + public ItemStack jsonToStack(JsonObject json, boolean useCache, boolean useReplacements) { + if(json == null) return new ItemStack(Items.painting, 1, 10); + if(useCache && itemstackCache.containsKey(json.get("internalname").getAsString())) { return itemstackCache.get(json.get("internalname").getAsString()).copy(); } @@ -1363,24 +1425,27 @@ public class NEUManager { NBTTagCompound tag = JsonToNBT.getTagFromJson(json.get("nbttag").getAsString()); stack.setTagCompound(tag); } catch(NBTException e) { - if(json.get("internalname").getAsString().equalsIgnoreCase("ROCK;0")) e.printStackTrace(); } } + HashMap<String, String> replacements = new HashMap<>(); + + if(useReplacements) { + replacements = getLoreReplacements(stack.getTagCompound(), -1); + + String displayname = json.get("displayname").getAsString(); + for(Map.Entry<String, String> entry : replacements.entrySet()) { + displayname = displayname.replace("{"+entry.getKey()+"}", entry.getValue()); + } + stack.setStackDisplayName(displayname); + } + if(json.has("lore")) { NBTTagCompound display = new NBTTagCompound(); if(stack.getTagCompound() != null && stack.getTagCompound().hasKey("display")) { 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); + display.setTag("Lore", processLore(json.get("lore").getAsJsonArray(), replacements)); NBTTagCompound tag = stack.getTagCompound() != null ? stack.getTagCompound() : new NBTTagCompound(); tag.setTag("display", display); stack.setTagCompound(tag); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java index 23def271..73381955 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java @@ -3,15 +3,14 @@ package io.github.moulberry.notenoughupdates; import com.google.common.collect.Lists; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.auction.APIManager; import io.github.moulberry.notenoughupdates.infopanes.*; import io.github.moulberry.notenoughupdates.itemeditor.NEUItemEditor; import io.github.moulberry.notenoughupdates.mbgui.MBAnchorPoint; import io.github.moulberry.notenoughupdates.mbgui.MBGuiElement; +import io.github.moulberry.notenoughupdates.mbgui.MBGuiGroupAligned; import io.github.moulberry.notenoughupdates.mbgui.MBGuiGroupFloating; -import io.github.moulberry.notenoughupdates.mbgui.MBGuiGroupHorz; -import io.github.moulberry.notenoughupdates.util.LerpingFloat; -import io.github.moulberry.notenoughupdates.util.LerpingInteger; -import io.github.moulberry.notenoughupdates.util.Utils; +import io.github.moulberry.notenoughupdates.util.*; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.*; import net.minecraft.client.gui.inventory.GuiContainer; @@ -57,6 +56,8 @@ import static io.github.moulberry.notenoughupdates.GuiTextures.*; public class NEUOverlay extends Gui { + private static final ResourceLocation SUPERGEHEIMNISVERMOGEN = new ResourceLocation("notenoughupdates:supersecretassets/bald.png"); + private NEUManager manager; private String mobRegex = ".*?((_MONSTER)|(_ANIMAL)|(_MINIBOSS)|(_BOSS)|(_SC))$"; @@ -95,8 +96,14 @@ public class NEUOverlay extends Gui { private TreeSet<JsonObject> searchedItems = null; private JsonObject[] searchedItemsArr = null; + private HashMap<String, Set<String>> searchedItemsSubgroup = new HashMap<>(); + + private long selectedItemMillis = 0; + private int selectedItemGroupX = -1; + private int selectedItemGroupY = -1; + private List<JsonObject> selectedItemGroup = null; + private boolean itemPaneOpen = false; - private boolean hoveringItemPaneToggle = false; private int page = 0; @@ -128,8 +135,6 @@ public class NEUOverlay extends Gui { private static final int SORT_MODE_ARMOR = 4; private static final int SORT_MODE_ACCESSORY = 5; - private ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); - private boolean disabled = false; private int lastScreenWidth; @@ -272,20 +277,17 @@ public class NEUOverlay extends Gui { @Override public void render(float x, float y) { int paddingUnscaled = getPaddingUnscaled(); + int searchYSize = getSearchBarYSize(); - Minecraft.getMinecraft().getTextureManager().bindTexture(settings); - drawRect((int)x, (int)y, - (int)x + getWidth(), (int)y + getHeight(), - Color.WHITE.getRGB()); - - - drawRect((int)x + paddingUnscaled, (int)y + paddingUnscaled, - (int)x + getWidth() - paddingUnscaled, (int)y + getHeight() - paddingUnscaled, - Color.GRAY.getRGB()); + Minecraft.getMinecraft().getTextureManager().bindTexture(quickcommand_background); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(x, y, + searchYSize + paddingUnscaled*2, searchYSize + paddingUnscaled*2, GL11.GL_NEAREST); + Minecraft.getMinecraft().getTextureManager().bindTexture(settings); GlStateManager.color(1f, 1f, 1f, 1f); Utils.drawTexturedRect((int)x + paddingUnscaled, (int)y + paddingUnscaled, - getSearchBarYSize(), getSearchBarYSize()); + searchYSize, searchYSize); GlStateManager.bindTexture(0); } }; @@ -310,8 +312,9 @@ public class NEUOverlay extends Gui { @Override public void mouseClick(float x, float y, int mouseX, int mouseY) { if(Mouse.getEventButtonState()) { - displayInformationPane(HTMLInfoPane.createFromWikiUrl(overlay, manager, "Help", - "https://moulberry.github.io/files/neu_help.html")); + //displayInformationPane(HTMLInfoPane.createFromWikiUrl(overlay, manager, "Help", + // "https://moulberry.github.io/files/neu_help.html")); + Minecraft.getMinecraft().displayGuiScreen(new HelpGUI()); Utils.playPressSound(); } } @@ -323,16 +326,14 @@ public class NEUOverlay extends Gui { @Override public void render(float x, float y) { int paddingUnscaled = getPaddingUnscaled(); + int searchYSize = getSearchBarYSize(); - Minecraft.getMinecraft().getTextureManager().bindTexture(help); - drawRect((int)x, (int)y, - (int)x + getWidth(), (int)y + getHeight(), - Color.WHITE.getRGB()); - - drawRect((int)x + paddingUnscaled, (int)y + paddingUnscaled, - (int)x + getWidth() - paddingUnscaled, (int)y + getHeight() - paddingUnscaled, - Color.GRAY.getRGB()); + Minecraft.getMinecraft().getTextureManager().bindTexture(quickcommand_background); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(x, y, + searchYSize + paddingUnscaled*2, searchYSize + paddingUnscaled*2, GL11.GL_NEAREST); + Minecraft.getMinecraft().getTextureManager().bindTexture(help); GlStateManager.color(1f, 1f, 1f, 1f); Utils.drawTexturedRect((int)x + paddingUnscaled, (int)y + paddingUnscaled, getSearchBarYSize(), getSearchBarYSize()); @@ -401,7 +402,6 @@ public class NEUOverlay extends Gui { NBTTagList textures = new NBTTagList(); NBTTagCompound textures_0 = new NBTTagCompound(); - String uuid = UUID.nameUUIDFromBytes(display.getBytes()).toString(); skullOwner.setString("Id", uuid); skullOwner.setString("Name", uuid); @@ -424,16 +424,13 @@ public class NEUOverlay extends Gui { } } if(render != null) { - Minecraft.getMinecraft().getTextureManager().bindTexture(item_mask); + Minecraft.getMinecraft().getTextureManager().bindTexture(quickcommand_background); GlStateManager.color(1, 1, 1, 1); Utils.drawTexturedRect(x, y, - bigItemSize + paddingUnscaled*2, bigItemSize + paddingUnscaled*2, GL11.GL_LINEAR); - GlStateManager.color(fg.getRed() / 255f,fg.getGreen() / 255f, - fg.getBlue() / 255f, fg.getAlpha() / 255f); - Utils.drawTexturedRect(x+paddingUnscaled, y+paddingUnscaled, bigItemSize, bigItemSize, GL11.GL_LINEAR); + bigItemSize + paddingUnscaled*2, bigItemSize + paddingUnscaled*2, GL11.GL_NEAREST); - int mouseX = Mouse.getX() * scaledresolution.getScaledWidth() / Minecraft.getMinecraft().displayWidth; - int mouseY = scaledresolution.getScaledHeight() - Mouse.getY() * scaledresolution.getScaledHeight() / Minecraft.getMinecraft().displayHeight - 1; + int mouseX = Mouse.getX() * Utils.peekGuiScale().getScaledWidth() / Minecraft.getMinecraft().displayWidth; + int mouseY = Utils.peekGuiScale().getScaledHeight() - Mouse.getY() * Utils.peekGuiScale().getScaledHeight() / Minecraft.getMinecraft().displayHeight - 1; if(mouseX > x && mouseX < x+bigItemSize) { if(mouseY > y && mouseY < y+bigItemSize) { @@ -454,21 +451,21 @@ public class NEUOverlay extends Gui { }; } - private MBGuiGroupHorz createQuickCommandGroup() { + private MBGuiGroupAligned createQuickCommandGroup() { List<MBGuiElement> children = new ArrayList<>(); for(String quickCommand : manager.config.quickCommands.value) { children.add(createQuickCommand(quickCommand)); } - return new MBGuiGroupHorz(children) { + return new MBGuiGroupAligned(children, false) { public int getPadding() { return getPaddingUnscaled()*4; } }; } - private MBGuiGroupHorz createSearchBarGroup() { + private MBGuiGroupAligned createSearchBarGroup() { List<MBGuiElement> children = Lists.newArrayList(createSettingsButton(this), createSearchBar(), createHelpButton(this)); - return new MBGuiGroupHorz(children) { + return new MBGuiGroupAligned(children, false) { public int getPadding() { return getPaddingUnscaled()*4; } @@ -490,7 +487,7 @@ public class NEUOverlay extends Gui { map.put(createSearchBarGroup(), searchBarAnchor); map.put(createQuickCommandGroup(), quickCommandAnchor); - return new MBGuiGroupFloating(scaledresolution.getScaledWidth(), scaledresolution.getScaledHeight(), map); + return new MBGuiGroupFloating(Utils.peekGuiScale().getScaledWidth(), Utils.peekGuiScale().getScaledHeight(), map); } public void resetAnchors(boolean onlyIfNull) { @@ -541,6 +538,7 @@ public class NEUOverlay extends Gui { itemPaneOffsetFactor.setValue(1); itemPaneTabOffset.setValue(20); } + if(activeInfoPane != null) activeInfoPane.reset(); } /** @@ -570,6 +568,22 @@ public class NEUOverlay extends Gui { } } + public void mouseInputInv() { + if(Minecraft.getMinecraft().currentScreen instanceof GuiContainer) { + if(Mouse.getEventButton() == manager.keybindItemSelect.getKeyCode()+100) { + Slot slot = Utils.getSlotUnderMouse((GuiContainer)Minecraft.getMinecraft().currentScreen); + if(slot != null) { + ItemStack hover = slot.getStack(); + if(hover != null) { + textField.setText("id:"+manager.getInternalNameForItem(hover)); + itemPaneOpen = true; + updateSearch(); + } + } + } + } + } + /** * Handles the mouse input, cancelling the forge event if a NEU gui element is clicked. */ @@ -578,11 +592,12 @@ public class NEUOverlay extends Gui { return false; } - int width = scaledresolution.getScaledWidth(); - int height = scaledresolution.getScaledHeight(); + Utils.pushGuiScale(manager.config.paneGuiScale.value.intValue()); - int mouseX = Mouse.getX() / scaledresolution.getScaleFactor(); - int mouseY = height - Mouse.getY() / scaledresolution.getScaleFactor(); + int width = Utils.peekGuiScale().getScaledWidth(); + int height = Utils.peekGuiScale().getScaledHeight(); + int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; //if(lastMouseX != mouseX || lastMouseY != mouseY) { // millisLastMouseMove = System.currentTimeMillis(); @@ -602,9 +617,36 @@ public class NEUOverlay extends Gui { guiGroup.mouseClick(0, 0, mouseX, mouseY); + if(selectedItemGroup != null) { + int selectedX = Math.min(selectedItemGroupX, width-getBoxPadding()-18*selectedItemGroup.size()); + if(mouseY > selectedItemGroupY+17 && mouseY < selectedItemGroupY+35) { + for(int i=0; i<selectedItemGroup.size(); i++) { + if(mouseX >= selectedX-1+18*i && mouseX <= selectedX+17+18*i) { + JsonObject item = selectedItemGroup.get(i); + if (item != null) { + if(Mouse.getEventButton() == 0) { + manager.showRecipe(item); + } else if(Mouse.getEventButton() == 1) { + showInfo(item); + } else if(Mouse.getEventButton() == manager.keybindItemSelect.getKeyCode()+100) { + textField.setText("id:"+item.get("internalname").getAsString()); + updateSearch(); + searchMode = true; + } + } + Utils.pushGuiScale(-1); + return true; + } + } + } + } + //Item selection (right) gui if(mouseX > width*getItemPaneOffsetFactor()) { - if(!Mouse.getEventButtonState()) return true; //End early if the mouse isn't pressed, but still cancel event. + if(!Mouse.getEventButtonState()) { + Utils.pushGuiScale(-1); + return true; //End early if the mouse isn't pressed, but still cancel event. + } AtomicBoolean clickedItem = new AtomicBoolean(false); iterateItemSlots(new ItemSlotConsumer() { @@ -619,7 +661,7 @@ public class NEUOverlay extends Gui { manager.showRecipe(item); } else if(Mouse.getEventButton() == 1) { showInfo(item); - } else if(Mouse.getEventButton() == 2) { + } else if(Mouse.getEventButton() == manager.keybindItemSelect.getKeyCode()+100) { textField.setText("id:"+item.get("internalname").getAsString()); updateSearch(); searchMode = true; @@ -637,7 +679,7 @@ public class NEUOverlay extends Gui { FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; int maxPages = getMaxPages(); - String name = scaledresolution.getScaleFactor()<4?"Page: ":""; + String name = Utils.peekGuiScale().getScaleFactor()<4?"Page: ":""; float maxStrLen = fr.getStringWidth(EnumChatFormatting.BOLD+name + maxPages + "/" + maxPages); float maxButtonXSize = (rightSide-leftSide+2 - maxStrLen*0.5f - 10)/2f; int buttonXSize = (int)Math.min(maxButtonXSize, getSearchBarYSize()*480/160f); @@ -692,47 +734,60 @@ public class NEUOverlay extends Gui { } } } + Utils.pushGuiScale(-1); return true; } - if(Minecraft.getMinecraft().currentScreen instanceof GuiContainer) { - if(Mouse.getEventButton() == 2) { - Slot slot = Utils.getSlotUnderMouse((GuiContainer)Minecraft.getMinecraft().currentScreen); - if(slot != null) { - ItemStack hover = slot.getStack(); - if(hover != null) { - textField.setText("id:"+manager.getInternalNameForItem(hover)); - updateSearch(); - searchMode = true; + //Clicking on "close info pane" button + if(activeInfoPane instanceof SettingsInfoPane) { + Utils.pushGuiScale(2); + + int widthN = Utils.peekGuiScale().getScaledWidth(); + int heightN = Utils.peekGuiScale().getScaledHeight(); + int mouseXN = Mouse.getX() * widthN / Minecraft.getMinecraft().displayWidth; + int mouseYN = heightN - Mouse.getY() * heightN / Minecraft.getMinecraft().displayHeight - 1; + + if(mouseXN > widthN*getInfoPaneOffsetFactor()-getBoxPadding()-8 && mouseXN < widthN*getInfoPaneOffsetFactor()-getBoxPadding()+8) { + if(mouseYN > getBoxPadding()-8 && mouseYN < getBoxPadding()+8) { + if(Mouse.getEventButtonState() && Mouse.getEventButton() < 2) { //Left or right click up + displayInformationPane(null); + + Utils.pushGuiScale(-1); + Utils.pushGuiScale(-1); return true; } } } - } - //Clicking on "close info pane" button - if(mouseX > width*getInfoPaneOffsetFactor()-getBoxPadding()-8 && mouseX < width*getInfoPaneOffsetFactor()-getBoxPadding()+8) { - if(mouseY > getBoxPadding()-8 && mouseY < getBoxPadding()+8) { - if(Mouse.getEventButtonState() && Mouse.getEventButton() < 2) { //Left or right click up - displayInformationPane(null); - return true; + Utils.pushGuiScale(-1); + } else { + if(mouseX > width*getInfoPaneOffsetFactor()-getBoxPadding()-8 && mouseX < width*getInfoPaneOffsetFactor()-getBoxPadding()+8) { + if(mouseY > getBoxPadding()-8 && mouseY < getBoxPadding()+8) { + if(Mouse.getEventButtonState() && Mouse.getEventButton() < 2) { //Left or right click up + displayInformationPane(null); + Utils.pushGuiScale(-1); + return true; + } } } } + if(activeInfoPane != null) { if(mouseX < width*getInfoPaneOffsetFactor()) { activeInfoPane.mouseInput(width, height, mouseX, mouseY, mouseDown); + Utils.pushGuiScale(-1); return true; } else if(Mouse.getEventButton() <= 1 && Mouse.getEventButtonState()) { //Left or right click activeInfoPane.mouseInputOutside(); } } + Utils.pushGuiScale(-1); return false; } public int getPaddingUnscaled() { - int paddingUnscaled = searchBarPadding/scaledresolution.getScaleFactor(); + int paddingUnscaled = searchBarPadding/Utils.peekGuiScale().getScaleFactor(); if(paddingUnscaled < 1) paddingUnscaled = 1; return paddingUnscaled; @@ -742,7 +797,7 @@ public class NEUOverlay extends Gui { * Returns searchBarXSize, scaled by 0.8 if gui scale == AUTO. */ public int getSearchBarXSize() { - if(scaledresolution.getScaleFactor()==4) return (int)(searchBarXSize*0.8); + if(Utils.peekGuiScale().getScaleFactor()==4) return (int)(searchBarXSize*0.8); return (int)(searchBarXSize); } @@ -767,8 +822,8 @@ public class NEUOverlay extends Gui { * Finds the index of the character inside the search bar that was clicked, used to set the caret. */ public int getClickedIndex(int mouseX, int mouseY) { - int width = scaledresolution.getScaledWidth(); - int height = scaledresolution.getScaledHeight(); + int width = Utils.peekGuiScale().getScaledWidth(); + int height = Utils.peekGuiScale().getScaledHeight(); int xComp = mouseX - (width/2 - getSearchBarXSize()/2 + 5); @@ -852,21 +907,38 @@ public class NEUOverlay extends Gui { itemstack.set(hover); } } else if(!hoverInv) { - int height = scaledresolution.getScaledHeight(); + Utils.pushGuiScale(manager.config.paneGuiScale.value.intValue()); - int mouseX = Mouse.getX() / scaledresolution.getScaleFactor(); - int mouseY = height - Mouse.getY() / scaledresolution.getScaleFactor(); + int width = Utils.peekGuiScale().getScaledWidth(); + int height = Utils.peekGuiScale().getScaledHeight(); + int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; - iterateItemSlots(new ItemSlotConsumer() { - public void consume(int x, int y, int id) { - if (mouseX >= x - 1 && mouseX <= x + ITEM_SIZE + 1) { - if (mouseY >= y - 1 && mouseY <= y + ITEM_SIZE + 1) { - JsonObject json = getSearchedItemPage(id); - if (json != null) internalname.set(json.get("internalname").getAsString()); + if (selectedItemGroup != null) { + int selectedX = Math.min(selectedItemGroupX, width - getBoxPadding() - 18 * selectedItemGroup.size()); + + if (mouseY > selectedItemGroupY + 17 && mouseY < selectedItemGroupY + 35) { + for (int i = 0; i < selectedItemGroup.size(); i++) { + if (mouseX >= selectedX - 1 + 18 * i && mouseX <= selectedX + 17 + 18 * i) { + internalname.set(selectedItemGroup.get(i).get("internalname").getAsString()); } } } - }); + } else { + iterateItemSlots(new ItemSlotConsumer() { + public void consume(int x, int y, int id) { + if (mouseX >= x - 1 && mouseX <= x + ITEM_SIZE + 1) { + if (mouseY >= y - 1 && mouseY <= y + ITEM_SIZE + 1) { + JsonObject json = getSearchedItemPage(id); + if (json != null) internalname.set(json.get("internalname").getAsString()); + } + } + } + }); + } + + + Utils.pushGuiScale(-1); } if(internalname.get() != null) { if(itemstack.get() != null) { @@ -988,8 +1060,8 @@ public class NEUOverlay extends Gui { float cost1 = manager.auctionManager.getLowestBin(o1.get("internalname").getAsString()); float cost2 = manager.auctionManager.getLowestBin(o2.get("internalname").getAsString()); - if(cost1 == -1) cost1 = manager.getCraftCost(o1.get("internalname").getAsString()).craftCost; - if(cost2 == -1) cost2 = manager.getCraftCost(o2.get("internalname").getAsString()).craftCost; + if(cost1 == -1) cost1 = manager.auctionManager.getCraftCost(o1.get("internalname").getAsString()).craftCost; + if(cost2 == -1) cost2 = manager.auctionManager.getCraftCost(o2.get("internalname").getAsString()).craftCost; if(cost1 < cost2) return mult; if(cost1 > cost2) return -mult; @@ -1049,12 +1121,16 @@ public class NEUOverlay extends Gui { * Checks whether an item matches the current sort mode. */ public boolean checkMatchesSort(String internalname, JsonObject item) { + if(!manager.config.showVanillaItems.value && item.has("vanilla") && item.get("vanilla").getAsBoolean()) { + return false; + } + if(getSortMode() == SORT_MODE_ALL) { return !internalname.matches(mobRegex); } else if(getSortMode() == SORT_MODE_MOB) { return internalname.matches(mobRegex); } else if(getSortMode() == SORT_MODE_PET) { - return internalname.matches(petRegex); + return internalname.matches(petRegex) && item.get("displayname").getAsString().contains("["); } else if(getSortMode() == SORT_MODE_TOOL) { return checkItemType(item.get("lore").getAsJsonArray(), "SWORD", "BOW", "AXE", "PICKAXE", "FISHING ROD", "WAND", "SHOVEL", "HOE") >= 0; @@ -1074,13 +1150,30 @@ public class NEUOverlay extends Gui { public void updateSearch() { if(searchedItems==null) searchedItems = new TreeSet<>(getItemComparator()); searchedItems.clear(); + searchedItemsSubgroup.clear(); searchedItemsArr = null; redrawItems = true; Set<String> itemsMatch = manager.search(textField.getText(), true); for(String itemname : itemsMatch) { JsonObject item = manager.getItemInformation().get(itemname); if(checkMatchesSort(itemname, item)) { - searchedItems.add(item); + if(item.has("parent") && item.get("parent").isJsonPrimitive()) { + searchedItemsSubgroup + .computeIfAbsent(item.get("parent").getAsString(), k->new HashSet<>()) + .add(item.get("internalname").getAsString()); + } else { + searchedItems.add(item); + } + } + } + out: + for(Map.Entry<String, Set<String>> entry : searchedItemsSubgroup.entrySet()) { + if(searchedItems.contains(manager.getItemInformation().get(entry.getKey()))) { + continue; + } + for(String itemname : entry.getValue()) { + JsonObject item = manager.getItemInformation().get(itemname); + if(item != null) searchedItems.add(item); } } switch(textField.getText().toLowerCase().trim()) { @@ -1097,6 +1190,15 @@ public class NEUOverlay extends Gui { case "ducttapedigger": searchedItems.add(CustomItems.DUCTTAPE); break; + case "thirtyvirus": + searchedItems.add(manager.getItemInformation().get("SPIKED_BAIT")); + break; + case "leocthl": + searchedItems.add(CustomItems.LEOCTHL); + break; + case "spinaxx": + searchedItems.add(CustomItems.SPINAXX); + break; } } @@ -1137,13 +1239,13 @@ public class NEUOverlay extends Gui { } public int getItemBoxXPadding() { - int width = scaledresolution.getScaledWidth(); + int width = Utils.peekGuiScale().getScaledWidth(); return (((int)(width/3*getWidthMult())-2*getBoxPadding())%(ITEM_SIZE+ITEM_PADDING)+ITEM_PADDING)/2; } public int getBoxPadding() { double panePadding = Math.max(0, Math.min(20, manager.config.panePadding.value)); - return (int)(panePadding*2/scaledresolution.getScaleFactor()+5); + return (int)(panePadding*2/Utils.peekGuiScale().getScaleFactor()+5); } private abstract class ItemSlotConsumer { @@ -1151,7 +1253,7 @@ public class NEUOverlay extends Gui { } public void iterateItemSlots(ItemSlotConsumer itemSlotConsumer) { - int width = scaledresolution.getScaledWidth(); + int width = Utils.peekGuiScale().getScaledWidth(); int itemBoxXPadding = getItemBoxXPadding(); iterateItemSlots(itemSlotConsumer, (int)(width*getItemPaneOffsetFactor())+getBoxPadding()+itemBoxXPadding); } @@ -1162,8 +1264,8 @@ public class NEUOverlay extends Gui { * code duplication issues. */ public void iterateItemSlots(ItemSlotConsumer itemSlotConsumer, int xStart) { - int width = scaledresolution.getScaledWidth(); - int height = scaledresolution.getScaledHeight(); + int width = Utils.peekGuiScale().getScaledWidth(); + int height = Utils.peekGuiScale().getScaledHeight(); int paneWidth = (int)(width/3*getWidthMult()); int itemBoxYPadding = ((height-getSearchBarYSize()-2*getBoxPadding()-ITEM_SIZE-2)%(ITEM_SIZE+ITEM_PADDING)+ITEM_PADDING)/2; @@ -1184,7 +1286,7 @@ public class NEUOverlay extends Gui { public float getWidthMult() { float scaleFMult = 1; - if(scaledresolution.getScaleFactor()==4) scaleFMult *= 0.9f; + if(Utils.peekGuiScale().getScaleFactor()==4) scaleFMult *= 0.9f; if(manager.auctionManager.customAH.isRenderOverAuctionView()) scaleFMult *= 0.8f; return (float)Math.max(0.5, Math.min(1.5, manager.config.paneWidthMult.value.floatValue()))*scaleFMult; } @@ -1193,7 +1295,7 @@ public class NEUOverlay extends Gui { * Calculates the number of horizontal item slots. */ public int getSlotsXSize() { - int width = scaledresolution.getScaledWidth(); + int width = Utils.peekGuiScale().getScaledWidth(); int paneWidth = (int)(width/3*getWidthMult()); int itemBoxXPadding = (((int)(width-width*getItemPaneOffsetFactor())-2*getBoxPadding())%(ITEM_SIZE+ITEM_PADDING)+ITEM_PADDING)/2; @@ -1207,7 +1309,7 @@ public class NEUOverlay extends Gui { * Calculates the number of vertical item slots. */ public int getSlotsYSize() { - int height = scaledresolution.getScaledHeight(); + int height = Utils.peekGuiScale().getScaledHeight(); int itemBoxYPadding = ((height-getSearchBarYSize()-2*getBoxPadding()-ITEM_SIZE-2)%(ITEM_SIZE+ITEM_PADDING)+ITEM_PADDING)/2; int yStart = getBoxPadding()+getSearchBarYSize()+itemBoxYPadding; @@ -1222,7 +1324,7 @@ public class NEUOverlay extends Gui { } public int getSearchBarYSize() { - return Math.max(searchBarYSize/scaledresolution.getScaleFactor(), ITEM_SIZE); + return Math.max(searchBarYSize/Utils.peekGuiScale().getScaleFactor(), ITEM_SIZE); } /** @@ -1245,10 +1347,11 @@ public class NEUOverlay extends Gui { int rightPressed = 0; if(Mouse.isButtonDown(0) || Mouse.isButtonDown(1)) { - int height = scaledresolution.getScaledHeight(); + int width = Utils.peekGuiScale().getScaledWidth(); + int height = Utils.peekGuiScale().getScaledHeight(); - int mouseX = Mouse.getX() / scaledresolution.getScaleFactor(); - int mouseY = height - Mouse.getY() / scaledresolution.getScaleFactor(); + int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; if(mouseY >= top && mouseY <= top+ySize) { int leftPrev = leftSide-1; @@ -1388,7 +1491,12 @@ public class NEUOverlay extends Gui { * Renders black squares over the inventory to indicate items that do not match a specific search. (When searchMode * is enabled) */ - public void renderOverlay(int mouseX, int mouseY) { + public void renderOverlay() { + int width = Utils.peekGuiScale().getScaledWidth(); + int height = Utils.peekGuiScale().getScaledHeight(); + int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; + if(searchMode && textField.getText().length() > 0) { if(Minecraft.getMinecraft().currentScreen instanceof GuiContainer) { GuiContainer inv = (GuiContainer) Minecraft.getMinecraft().currentScreen; @@ -1480,16 +1588,16 @@ public class NEUOverlay extends Gui { if(blurShaderHorz == null) { try { - blurShaderHorz = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", - Minecraft.getMinecraft().getFramebuffer(), blurOutputHorz); + blurShaderHorz = new Shader(Minecraft.getMinecraft().getResourceManager(), + "blur", Minecraft.getMinecraft().getFramebuffer(), blurOutputHorz); blurShaderHorz.getShaderManager().getShaderUniform("BlurDir").set(1, 0); blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); } catch(Exception e) { } } if(blurShaderVert == null) { try { - blurShaderVert = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", - blurOutputHorz, blurOutputVert); + blurShaderVert = new Shader(Minecraft.getMinecraft().getResourceManager(), + "blur", blurOutputHorz, blurOutputVert); blurShaderVert.getShaderManager().getShaderUniform("BlurDir").set(0, 1); blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height)); } catch(Exception e) { } @@ -1517,7 +1625,6 @@ public class NEUOverlay extends Gui { public void renderBlurredBackground(int width, int height, int x, int y, int blurWidth, int blurHeight) { if(manager.config.bgBlurFactor.value <= 0 || !OpenGlHelper.isFramebufferEnabled()) return; - int f = scaledresolution.getScaleFactor(); float uMin = x/(float)width; float uMax = (x+blurWidth)/(float)width; float vMin = y/(float)height; @@ -1532,11 +1639,11 @@ public class NEUOverlay extends Gui { } public void updateGuiGroupSize() { - ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); - int width = scaledresolution.getScaledWidth(); - int height = scaledresolution.getScaledHeight(); + Utils.pushGuiScale(manager.config.paneGuiScale.value.intValue()); + int width = Utils.peekGuiScale().getScaledWidth(); + int height = Utils.peekGuiScale().getScaledHeight(); - if(lastScreenWidth != width || lastScreenHeight != height || scaledresolution.getScaleFactor() != lastScale) { + if(lastScreenWidth != width || lastScreenHeight != height || Utils.peekGuiScale().getScaleFactor() != lastScale) { guiGroup.width = width; guiGroup.height = height; @@ -1545,28 +1652,48 @@ public class NEUOverlay extends Gui { lastScreenWidth = width; lastScreenHeight = height; - lastScale = scaledresolution.getScaleFactor(); + lastScale = Utils.peekGuiScale().getScaleFactor(); } + + Utils.pushGuiScale(-1); } int guiScaleLast = 0; + private boolean showVanillaLast = false; /** * Renders the search bar, quick commands, item selection (right) and item info (left) gui elements. */ - public void render(int mouseX, int mouseY, boolean hoverInv) { + public void render(boolean hoverInv) { if(disabled) { return; } FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; - scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); - int width = scaledresolution.getScaledWidth(); - int height = scaledresolution.getScaledHeight(); + + Utils.resetGuiScale(); + Utils.pushGuiScale(manager.config.paneGuiScale.value.intValue()); + + int width = Utils.peekGuiScale().getScaledWidth(); + int height = Utils.peekGuiScale().getScaledHeight(); + int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; + + if(showVanillaLast != manager.config.showVanillaItems.value) { + showVanillaLast = manager.config.showVanillaItems.value; + updateSearch(); + } + + if(textField.getText().toLowerCase().contains("bald")) { + Minecraft.getMinecraft().getTextureManager().bindTexture(SUPERGEHEIMNISVERMOGEN); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect((width-64)/2f, (height-64)/2f-114, 64, 64, GL11.GL_LINEAR); + GlStateManager.bindTexture(0); + } updateGuiGroupSize(); - if(guiScaleLast != scaledresolution.getScaleFactor()) { - guiScaleLast = scaledresolution.getScaleFactor(); + if(guiScaleLast != Utils.peekGuiScale().getScaleFactor()) { + guiScaleLast = Utils.peekGuiScale().getScaleFactor(); redrawItems = true; } @@ -1580,15 +1707,13 @@ public class NEUOverlay extends Gui { yaw++; yaw %= 360; - manager.updatePrices(); - - int opacity = Math.min(255, Math.max(0, manager.config.bgOpacity.value.intValue())); - bg = new Color((bg.getRGB() & 0x00ffffff) | opacity << 24, true); + bg = new Color(SpecialColour.specialToChromaRGB(manager.config.paneBackgroundColour.value), true); + fg = new Color(SpecialColour.specialToChromaRGB(manager.config.itemBackgroundColour.value)); + Color fgCustomOpacity = new Color(SpecialColour.specialToChromaRGB(manager.config.itemBackgroundColour.value), true); - opacity = Math.min(255, Math.max(0, manager.config.fgOpacity.value.intValue())); - Color fgCustomOpacity = new Color((fg.getRGB() & 0x00ffffff) | opacity << 24, true); - Color fgFavourite = new Color(limCol(fg.getRed()+20), limCol(fg.getGreen()+10), limCol(fg.getBlue()-10), opacity); - Color fgFavourite2 = new Color(limCol(fg.getRed()+100), limCol(fg.getGreen()+50), limCol(fg.getBlue()-50), opacity); + Color fgFavourite2 = new Color(SpecialColour.specialToChromaRGB(manager.config.itemFavouriteColour.value), true); + Color fgFavourite = new Color((int)(fgFavourite2.getRed()*0.8f), (int)(fgFavourite2.getGreen()*0.8f), + (int)(fgFavourite2.getBlue()*0.8f), fgFavourite2.getAlpha()); if(itemPaneOpen) { if(itemPaneTabOffset.getValue() == 0) { @@ -1633,21 +1758,16 @@ public class NEUOverlay extends Gui { int rightSide = leftSide+paneWidth-getBoxPadding()-getItemBoxXPadding(); //Tab - Minecraft.getMinecraft().getTextureManager().bindTexture(itemPaneTabArrow); - GlStateManager.color(1f, 1f, 1f, 0.3f); - Utils.drawTexturedRect(width-itemPaneTabOffset.getValue(), height/2 - 50, 20, 100); - GlStateManager.bindTexture(0); + if(!manager.config.disableItemTabOpen.value) { + Minecraft.getMinecraft().getTextureManager().bindTexture(itemPaneTabArrow); + GlStateManager.color(1f, 1f, 1f, 0.3f); + Utils.drawTexturedRect(width-itemPaneTabOffset.getValue()*64/20f, height/2f - 32, 64, 64); + GlStateManager.bindTexture(0); - if(mouseX > width-itemPaneTabOffset.getValue() && mouseY > height/2 - 50 - && mouseY < height/2 + 50) { - if(!hoveringItemPaneToggle) { - if(!manager.config.disableItemTabOpen.value) { - itemPaneOpen = !itemPaneOpen; - } - hoveringItemPaneToggle = true; + if(!itemPaneOpen && mouseX > width-itemPaneTabOffset.getValue() && mouseY > height/2 - 32 + && mouseY < height/2 + 32) { + itemPaneOpen = true; } - } else { - hoveringItemPaneToggle = false; } //Atomic reference used so that below lambda doesn't complain about non-effectively-final variable @@ -1661,7 +1781,7 @@ public class NEUOverlay extends Gui { leftSide+paneWidth-getBoxPadding()+5, height-getBoxPadding()+5, bg.getRGB()); renderNavElement(leftSide+getBoxPadding()+getItemBoxXPadding(), rightSide, getMaxPages(), page+1, - scaledresolution.getScaleFactor()<4?"Page: ":""); + Utils.peekGuiScale().getScaleFactor()<4?"Page: ":""); //Sort bar drawRect(leftSide+getBoxPadding()+getItemBoxXPadding()-1, @@ -1736,6 +1856,18 @@ public class NEUOverlay extends Gui { millisLastMouseMove = System.currentTimeMillis(); } + if(selectedItemGroup != null) { + if(mouseX < selectedItemGroupX-1 || mouseX > selectedItemGroupX+17 || + mouseY < selectedItemGroupY-1 || mouseY > selectedItemGroupY+17) { + int selectedX = Math.min(selectedItemGroupX, width-getBoxPadding()-18*selectedItemGroup.size()); + if(mouseX < selectedX-1 || mouseX > selectedX-1+18*selectedItemGroup.size() || + mouseY < selectedItemGroupY+17 || mouseY > selectedItemGroupY+35) { + selectedItemGroup = null; + selectedItemMillis = -1; + } + } + } + if(!hoverInv) { iterateItemSlots(new ItemSlotConsumer() { public void consume(int x, int y, int id) { @@ -1745,7 +1877,25 @@ public class NEUOverlay extends Gui { } if (mouseX > x - 1 && mouseX < x + ITEM_SIZE + 1) { if (mouseY > y - 1 && mouseY < y + ITEM_SIZE + 1) { - tooltipToDisplay.set(json); + String internalname = json.get("internalname").getAsString(); + if(searchedItemsSubgroup.containsKey(internalname)) { + if(selectedItemMillis == -1) selectedItemMillis = System.currentTimeMillis(); + if(System.currentTimeMillis() - selectedItemMillis > 200 && + (selectedItemGroup == null || selectedItemGroup.isEmpty())) { + + ArrayList<JsonObject> children = new ArrayList<>(); + children.add(json); + for(String itemname : searchedItemsSubgroup.get(internalname)) { + children.add(manager.getItemInformation().get(itemname)); + } + + selectedItemGroup = children; + selectedItemGroupX = x; + selectedItemGroupY = y; + } + } else { + tooltipToDisplay.set(json); + } } } } @@ -1770,6 +1920,38 @@ public class NEUOverlay extends Gui { renderItems(xStart, true, true, true); } + if(selectedItemGroup != null) { + GL11.glTranslatef(0, 0, 10); + + int selectedX = Math.min(selectedItemGroupX, width-getBoxPadding()-18*selectedItemGroup.size()); + + GlStateManager.depthFunc(GL11.GL_LESS); + drawRect(selectedX, selectedItemGroupY+18, + selectedX-2+18*selectedItemGroup.size(), selectedItemGroupY+34, fgCustomOpacity.getRGB()); + drawRect(selectedX, selectedItemGroupY+18, + selectedX-1+18*selectedItemGroup.size(), selectedItemGroupY+35, new Color(30, 30, 30).getRGB()); + drawRect(selectedX-1, selectedItemGroupY+17, + selectedX-2+18*selectedItemGroup.size(), selectedItemGroupY+34, new Color(180, 180, 180).getRGB()); + GlStateManager.depthFunc(GL11.GL_LEQUAL); + + GL11.glTranslatef(0, 0, 10); + + tooltipToDisplay.set(null); + if(mouseY > selectedItemGroupY+17 && mouseY < selectedItemGroupY+35) { + for(int i=0; i<selectedItemGroup.size(); i++) { + if(mouseX >= selectedX-1+18*i && mouseX <= selectedX+17+18*i) { + tooltipToDisplay.set(selectedItemGroup.get(i)); + } + } + } + for(int i=0; i<selectedItemGroup.size(); i++) { + JsonObject item = selectedItemGroup.get(i); + Utils.drawItemStack(manager.jsonToStack(item), selectedX+18*i, selectedItemGroupY+18); + } + + GL11.glTranslatef(0, 0, -20); + } + GlStateManager.enableBlend(); GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); GlStateManager.enableAlpha(); @@ -1792,64 +1974,96 @@ public class NEUOverlay extends Gui { if(activeInfoPane != null) { activeInfoPane.tick(); - activeInfoPane.render(width, height, bg, fg, scaledresolution, mouseX, mouseY); + activeInfoPane.render(width, height, bg, fg, Utils.peekGuiScale(), mouseX, mouseY); GlStateManager.color(1f, 1f, 1f, 1f); Minecraft.getMinecraft().getTextureManager().bindTexture(close); - Utils.drawTexturedRect(rightSide-getBoxPadding()-8, getBoxPadding()-8, 16, 16); + if(activeInfoPane instanceof SettingsInfoPane) { + Utils.pushGuiScale(2); + + int widthN = Utils.peekGuiScale().getScaledWidth(); + int rightSideN = (int)(widthN*getInfoPaneOffsetFactor()); + Utils.drawTexturedRect(rightSideN-getBoxPadding()-8, getBoxPadding()-8, 16, 16); + + Utils.pushGuiScale(-1); + } else { + Utils.drawTexturedRect(rightSide-getBoxPadding()-8, getBoxPadding()-8, 16, 16); + } GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); } //Render tooltip JsonObject json = tooltipToDisplay.get(); if(json != null) { - List<String> text = new ArrayList<>(); - text.add(json.get("displayname").getAsString()); - JsonArray lore = json.get("lore").getAsJsonArray(); - for(int i=0; i<lore.size(); i++) { - text.add(lore.get(i).getAsString()); - } + List<String> text = manager.jsonToStack(json).getTooltip(Minecraft.getMinecraft().thePlayer, false); String internalname = json.get("internalname").getAsString(); - JsonObject auctionInfo = manager.getItemAuctionInfo(internalname); - JsonObject bazaarInfo = manager.getBazaarInfo(internalname); - - boolean hasAuctionPrice = auctionInfo != null; - boolean hasBazaarPrice = bazaarInfo != null; + JsonObject auctionInfo = manager.auctionManager.getItemAuctionInfo(internalname); + JsonObject bazaarInfo = manager.auctionManager.getBazaarInfo(internalname); int lowestBin = manager.auctionManager.getLowestBin(internalname); + APIManager.CraftInfo craftCost = manager.auctionManager.getCraftCost(json.get("internalname").getAsString()); - NumberFormat format = NumberFormat.getInstance(Locale.US); + boolean hasAuctionPrice = !manager.config.invAuctionPrice.value && auctionInfo != null; + boolean hasBazaarPrice = !manager.config.invBazaarPrice.value && bazaarInfo != null; + boolean hasLowestBinPrice = !manager.config.invAuctionPrice.value && lowestBin > 0; - NEUManager.CraftInfo craftCost = manager.getCraftCost(json.get("internalname").getAsString()); + NumberFormat format = NumberFormat.getInstance(Locale.US); - if(hasAuctionPrice || hasBazaarPrice || craftCost.fromRecipe || lowestBin > 0) text.add(""); - if(lowestBin > 0) { + if(hasAuctionPrice || hasBazaarPrice || hasLowestBinPrice) text.add(""); + if(hasLowestBinPrice) { text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Lowest BIN: "+ EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(lowestBin)+" coins"); } - if(hasBazaarPrice) { - int bazaarBuyPrice = (int)bazaarInfo.get("avg_buy").getAsFloat(); - text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Buy: "+ - EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarBuyPrice)+" coins"); - int bazaarSellPrice = (int)bazaarInfo.get("avg_sell").getAsFloat(); - text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Sell: "+ - EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarSellPrice)+" coins"); - if(manager.config.advancedPriceInfo.value) { - int bazaarInstantBuyPrice = (int)bazaarInfo.get("curr_buy").getAsFloat(); - text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Insta-Buy: "+ - EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarInstantBuyPrice)+" coins"); - int bazaarInstantSellPrice = (int)bazaarInfo.get("curr_sell").getAsFloat(); - text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Insta-Sell: "+ - EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarInstantSellPrice)+" coins"); - } - } if(hasAuctionPrice) { int auctionPrice = (int)(auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat()); text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"AH Price: "+ EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(auctionPrice)+" coins"); + if(manager.config.advancedPriceInfo.value) { + text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"AH Sales: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(auctionInfo.get("sales").getAsFloat())+" sales/day"); + } + if(auctionInfo.has("clean_price")) { + text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"AH Price (Clean): "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format((int)auctionInfo.get("clean_price").getAsFloat())+" coins"); + if(manager.config.advancedPriceInfo.value) { + text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"AH Sales (Clean): "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(auctionInfo.get("clean_sales").getAsFloat())+" sales/day"); + } + } + + } else if(hasBazaarPrice) { + int stackMultiplier = 1; + int shiftStackMultiplier = 64; + if(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) { + stackMultiplier = shiftStackMultiplier; + } else { + text.add(EnumChatFormatting.DARK_GRAY.toString()+"[SHIFT show x"+shiftStackMultiplier+"]"); + } + if(bazaarInfo.has("avg_buy")) { + int bazaarBuyPrice = (int)bazaarInfo.get("avg_buy").getAsFloat()*stackMultiplier; + text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Buy: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarBuyPrice)+" coins"); + } + if(bazaarInfo.has("avg_sell")) { + int bazaarSellPrice = (int)bazaarInfo.get("avg_sell").getAsFloat()*stackMultiplier; + text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Sell: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarSellPrice)+" coins"); + } + if(manager.config.advancedPriceInfo.value) { + if(bazaarInfo.has("curr_buy")) { + int bazaarInstantBuyPrice = (int)bazaarInfo.get("curr_buy").getAsFloat()*stackMultiplier; + text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Insta-Buy: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarInstantBuyPrice)+" coins"); + } + if(bazaarInfo.has("curr_sell")) { + int bazaarInstantSellPrice = (int)bazaarInfo.get("curr_sell").getAsFloat()*stackMultiplier; + text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Insta-Sell: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarInstantSellPrice)+" coins"); + } + } } - if(craftCost.fromRecipe) { + if((hasAuctionPrice || hasBazaarPrice) && craftCost.fromRecipe) { text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Raw Craft Cost: "+ EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format((int)craftCost.craftCost)+" coins"); } @@ -1879,6 +2093,8 @@ public class NEUOverlay extends Gui { GlStateManager.enableAlpha(); GlStateManager.alphaFunc(516, 0.1F); GlStateManager.disableLighting(); + + Utils.pushGuiScale(-1); } /** @@ -1904,8 +2120,8 @@ public class NEUOverlay extends Gui { * itemPane should be redrawn. */ private void checkFramebufferSizes(int width, int height) { - int sw = width*scaledresolution.getScaleFactor(); - int sh = height*scaledresolution.getScaleFactor(); + int sw = width*Utils.peekGuiScale().getScaleFactor(); + int sh = height*Utils.peekGuiScale().getScaleFactor(); for(int i=0; i<itemFramebuffers.length; i++) { if(itemFramebuffers[i] == null || itemFramebuffers[i].framebufferWidth != sw || itemFramebuffers[i].framebufferHeight != sh) { if(itemFramebuffers[i] == null) { @@ -1936,8 +2152,8 @@ public class NEUOverlay extends Gui { */ private void renderItemsToImage(int width, int height, Color fgFavourite2, Color fgFavourite, Color fgCustomOpacity, boolean items, boolean entities) { - int sw = width*scaledresolution.getScaleFactor(); - int sh = height*scaledresolution.getScaleFactor(); + int sw = width*Utils.peekGuiScale().getScaleFactor(); + int sh = height*Utils.peekGuiScale().getScaleFactor(); GL11.glPushMatrix(); prepareFramebuffer(itemFramebuffers[0], sw, sh); @@ -2158,6 +2374,14 @@ public class NEUOverlay extends Gui { Utils.drawItemStackWithoutGlint(stack, x, y); } } + + GlStateManager.translate(0, 0, 50); + if(searchedItemsSubgroup.containsKey(json.get("internalname").getAsString())) { + Minecraft.getMinecraft().getTextureManager().bindTexture(item_haschild); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(x-1, y-1, ITEM_SIZE+2, ITEM_SIZE+2, GL11.GL_NEAREST); + } + GlStateManager.translate(0, 0, -50); } }, xStart); } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlayPlacements.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlayPlacements.java index 28ecbc8e..633c1c4b 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlayPlacements.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlayPlacements.java @@ -1,12 +1,12 @@ package io.github.moulberry.notenoughupdates; -import io.github.moulberry.notenoughupdates.mbgui.MBAnchorPoint; -import io.github.moulberry.notenoughupdates.mbgui.MBGuiElement; -import io.github.moulberry.notenoughupdates.mbgui.MBGuiGroup; -import io.github.moulberry.notenoughupdates.mbgui.MBGuiGroupFloating; +import io.github.moulberry.notenoughupdates.mbgui.*; +import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.EnumChatFormatting; import org.lwjgl.input.Keyboard; import org.lwjgl.util.vector.Vector2f; @@ -22,22 +22,40 @@ public class NEUOverlayPlacements extends GuiScreen { private MBGuiElement clickedElement; private GuiButton guiButton = new GuiButton(0, 5, 5, "Reset to Default"); + private boolean dropdownMenuShown = false; + @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { super.drawScreen(mouseX, mouseY, partialTicks); drawDefaultBackground(); + /*GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + Minecraft.getMinecraft().getTextureManager().bindTexture(icons); + GlStateManager.enableBlend(); + + GlStateManager.tryBlendFuncSeparate(775, 769, 1, 0); + GlStateManager.enableAlpha(); + this.drawTexturedModalRect(width / 2 - 7, height / 2 - 7, 0, 0, 16, 16);*/ + if(mouseX < 300 && mouseY < 300 && clickedElement != null) { guiButton.yPosition = height - 5 - guiButton.height; } else { guiButton.yPosition = 5; } + EnumChatFormatting GOLD = EnumChatFormatting.GOLD; + guiButton.drawButton(Minecraft.getMinecraft(), mouseX, mouseY); NotEnoughUpdates.INSTANCE.overlay.updateGuiGroupSize(); + drawRect((width-176)/2, (height-166)/2, + (width+176)/2, (height+166)/2, new Color(100, 100, 100, 200).getRGB()); + Utils.drawStringCentered(GOLD+"Inventory", Minecraft.getMinecraft().fontRendererObj, width/2f, height/2f, false, 0); + MBGuiGroupFloating mainGroup = NotEnoughUpdates.INSTANCE.overlay.guiGroup; + mainGroup.render(0, 0); + GlStateManager.translate(0, 0, 500); for(MBGuiElement element : mainGroup.getChildren()) { MBAnchorPoint anchorPoint = mainGroup.getChildrenMap().get(element); Vector2f position = mainGroup.getChildrenPosition().get(element); @@ -45,7 +63,6 @@ public class NEUOverlayPlacements extends GuiScreen { drawRect((int)position.x, (int)position.y, (int)position.x+element.getWidth(), (int)position.y+element.getHeight(), new Color(100, 100, 100, 200).getRGB()); - switch(anchorPoint.anchorPoint) { case TOPLEFT: case TOPRIGHT: @@ -84,13 +101,23 @@ public class NEUOverlayPlacements extends GuiScreen { break; } + + if(anchorPoint.inventoryRelative) { + Utils.drawStringCentered(GOLD+"Inv-Relative", Minecraft.getMinecraft().fontRendererObj, + position.x+element.getWidth()*0.5f, position.y+element.getHeight()*0.5f, false, 0); + } } + GlStateManager.translate(0, 0, -500); } @Override protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { super.mouseClicked(mouseX, mouseY, mouseButton); + + if(mouseButton != 0 && mouseButton != 1) return; + MBGuiGroupFloating mainGroup = NotEnoughUpdates.INSTANCE.overlay.guiGroup; + int index=0; for(MBGuiElement element : mainGroup.getChildren()) { MBAnchorPoint anchorPoint = mainGroup.getChildrenMap().get(element); Vector2f position = mainGroup.getChildrenPosition().get(element); @@ -104,22 +131,31 @@ public class NEUOverlayPlacements extends GuiScreen { clickedAnchorX = (int)anchorPoint.offset.x; clickedAnchorY = (int)anchorPoint.offset.y; } else { - float anchorX = (width-element.getWidth()) * anchorPoint.anchorPoint.x + anchorPoint.offset.x; - float anchorY = (height-element.getHeight()) * anchorPoint.anchorPoint.y + anchorPoint.offset.y; - - MBAnchorPoint.AnchorPoint[] vals = MBAnchorPoint.AnchorPoint.values(); - anchorPoint.anchorPoint = vals[(anchorPoint.anchorPoint.ordinal()+1)%vals.length]; - - float screenX = (width-element.getWidth()) * anchorPoint.anchorPoint.x; - float screenY = (height-element.getHeight()) * anchorPoint.anchorPoint.y; - anchorPoint.offset.x = anchorX - screenX; - anchorPoint.offset.y = anchorY - screenY; - - mainGroup.recalculate(); + if(Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)) { + anchorPoint.inventoryRelative = !anchorPoint.inventoryRelative; + } else { + MBAnchorPoint.AnchorPoint[] vals = MBAnchorPoint.AnchorPoint.values(); + anchorPoint.anchorPoint = vals[(anchorPoint.anchorPoint.ordinal()+1)%vals.length]; + + mainGroup.recalculate(); + + anchorPoint.offset.x += position.x - mainGroup.getChildrenPosition().get(element).x; + anchorPoint.offset.y += position.y - mainGroup.getChildrenPosition().get(element).y; + + mainGroup.recalculate(); + + if(index == 0) { + NotEnoughUpdates.INSTANCE.manager.config.overlaySearchBar.value = anchorPoint.toString(); + } else if(index == 1) { + NotEnoughUpdates.INSTANCE.manager.config.overlayQuickCommand.value = anchorPoint.toString(); + } + try { NotEnoughUpdates.INSTANCE.manager.saveConfig(); } catch(IOException ignored) {} + } } return; } } + index++; } if(guiButton.mousePressed(Minecraft.getMinecraft(), mouseX, mouseY)) { @@ -173,7 +209,7 @@ public class NEUOverlayPlacements extends GuiScreen { } index++; } - + try { MBDeserializer.serializeAndSave(mainGroup, "overlay"); } catch(Exception e) {} mainGroup.recalculate(); } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java index a589fe2b..3ca2ab04 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java @@ -1,6 +1,7 @@ package io.github.moulberry.notenoughupdates; import com.google.common.collect.Sets; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.mojang.authlib.Agent; import com.mojang.authlib.exceptions.AuthenticationException; @@ -9,119 +10,190 @@ import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication; import io.github.moulberry.notenoughupdates.auction.CustomAHGui; import io.github.moulberry.notenoughupdates.commands.SimpleCommand; import io.github.moulberry.notenoughupdates.cosmetics.CapeManager; +import io.github.moulberry.notenoughupdates.cosmetics.GuiCosmetics; +import io.github.moulberry.notenoughupdates.dungeons.DungeonMap; +import io.github.moulberry.notenoughupdates.dungeons.DungeonWin; +import io.github.moulberry.notenoughupdates.dungeons.GuiDungeonMapEditor; +import io.github.moulberry.notenoughupdates.gamemodes.GuiGamemodes; +import io.github.moulberry.notenoughupdates.gamemodes.SBGamemodes; import io.github.moulberry.notenoughupdates.infopanes.CollectionLogInfoPane; -import io.github.moulberry.notenoughupdates.infopanes.CosmeticsInfoPane; +import io.github.moulberry.notenoughupdates.infopanes.SettingsInfoPane; +import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer; +import io.github.moulberry.notenoughupdates.profileviewer.PlayerStats; +import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer; import io.github.moulberry.notenoughupdates.questing.GuiQuestLine; -import io.github.moulberry.notenoughupdates.questing.NEUQuesting; +import io.github.moulberry.notenoughupdates.questing.SBInfo; import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.block.material.MapColor; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.gui.ScaledResolution; -import net.minecraft.client.gui.inventory.*; -import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.gui.inventory.GuiInventory; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.settings.KeyBinding; import net.minecraft.command.ICommandSender; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.event.ClickEvent; -import net.minecraft.init.Blocks; -import net.minecraft.inventory.ContainerChest; -import net.minecraft.inventory.IInventory; -import net.minecraft.item.Item; +import net.minecraft.event.HoverEvent; +import net.minecraft.item.ItemMap; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; import net.minecraft.scoreboard.ScoreObjective; import net.minecraft.scoreboard.Scoreboard; -import net.minecraft.util.ChatComponentText; -import net.minecraft.util.ChatStyle; -import net.minecraft.util.EnumChatFormatting; -import net.minecraft.util.Session; +import net.minecraft.util.*; +import net.minecraft.world.storage.MapData; import net.minecraftforge.client.ClientCommandHandler; -import net.minecraftforge.client.event.ClientChatReceivedEvent; -import net.minecraftforge.client.event.GuiOpenEvent; -import net.minecraftforge.client.event.GuiScreenEvent; -import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.common.ForgeVersion; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.entity.player.ItemTooltipEvent; import net.minecraftforge.fml.client.registry.ClientRegistry; +import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventHandler; +import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; -import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; -import org.lwjgl.input.Keyboard; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.text.WordUtils; +import org.apache.commons.lang3.text.translate.UnicodeUnescaper; +import org.lwjgl.opengl.Display; import org.lwjgl.opengl.GL11; import javax.swing.*; import java.awt.*; import java.awt.datatransfer.StringSelection; import java.io.*; +import java.lang.management.ManagementFactory; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.net.Proxy; -import java.text.NumberFormat; +import java.net.*; +import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Matcher; +import java.util.regex.Pattern; -import static io.github.moulberry.notenoughupdates.GuiTextures.*; - -@Mod(modid = NotEnoughUpdates.MODID, version = NotEnoughUpdates.VERSION) +@Mod(modid = NotEnoughUpdates.MODID, version = NotEnoughUpdates.VERSION, clientSideOnly = true) public class NotEnoughUpdates { public static final String MODID = "notenoughupdates"; - public static final String VERSION = "REL-1.0.0"; + public static final String VERSION = "1.5-REL"; public static NotEnoughUpdates INSTANCE = null; public NEUManager manager; public NEUOverlay overlay; - private NEUIO neuio; private static final long CHAT_MSG_COOLDOWN = 200; private long lastChatMessage = 0; private long secondLastChatMessage = 0; private String currChatMessage = null; - private boolean hoverInv = false; - private boolean focusInv = false; - - private boolean joinedSB = false; - //Stolen from Biscut and used for detecting whether in skyblock - private static final Set<String> SKYBLOCK_IN_ALL_LANGUAGES = Sets.newHashSet("SKYBLOCK","\u7A7A\u5C9B\u751F\u5B58"); - - //Github Access Token, may change. Value hard-coded. - //Token is obfuscated so that github doesn't delete it whenever I upload the jar. - String[] token = new String[]{"b292496d2c","9146a","9f55d0868a545305a8","96344bf"}; - private String getAccessToken() { - String s = ""; - for(String str : token) { - s += str; - } - return s; - } + private static final Set<String> SKYBLOCK_IN_ALL_LANGUAGES = Sets.newHashSet("SKYBLOCK","\u7A7A\u5C9B\u751F\u5B58", "\u7A7A\u5CF6\u751F\u5B58"); private GuiScreen openGui = null; SimpleCommand collectionLogCommand = new SimpleCommand("neucl", new SimpleCommand.ProcessCommandRunnable() { public void processCommand(ICommandSender sender, String[] args) { if(!OpenGlHelper.isFramebufferEnabled()) { - Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "This feature requires FBOs to work. Try disabling Optifine's 'Fast Render'.")); } else { if(!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) { openGui = new GuiInventory(Minecraft.getMinecraft().thePlayer); } - manager.updatePrices(); overlay.displayInformationPane(new CollectionLogInfoPane(overlay, manager)); } } }); + SimpleCommand itemRenameCommand = new SimpleCommand("neurename", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + if(args.length == 0) { + args = new String[]{"help"}; + } + String heldUUID = manager.getUUIDForItem(Minecraft.getMinecraft().thePlayer.getHeldItem()); + switch(args[0].toLowerCase()) { + case "clearall": + manager.itemRenameJson = new JsonObject(); + manager.saveItemRenameConfig(); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN + "[NEU] Cleared custom name for all items")); + break; + case "clear": + if(heldUUID == null) { + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "[NEU] Can't clear rename - no UUID")); + return; + } + manager.itemRenameJson.remove(heldUUID); + manager.saveItemRenameConfig(); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN + "[NEU] Cleared custom name for held item")); + break; + case "copyuuid": + if(heldUUID == null) { + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "[NEU] Can't clear rename - no UUID")); + return; + } + StringSelection selection = new StringSelection(heldUUID); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN + "[NEU] UUID copied to clipboard")); + break; + case "uuid": + if(heldUUID == null) { + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "[NEU] Can't get UUID - no UUID")); + return; + } + ChatStyle style = new ChatStyle(); + style.setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new ChatComponentText(EnumChatFormatting.GRAY+"Click to copy to clipboard"))); + style.setChatClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "neurename copyuuid")); + + ChatComponentText text = new ChatComponentText(EnumChatFormatting.YELLOW+"[NEU] The UUID of your currently held item is: " + + EnumChatFormatting.GREEN + heldUUID); + text.setChatStyle(style); + sender.addChatMessage(text); + break; + case "set": + if(heldUUID == null) { + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "[NEU] Can't rename item - no UUID")); + return; + } + if(args.length == 1) { + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "[NEU] Usage: /neurename set [name...]")); + return; + } + StringBuilder sb = new StringBuilder(); + for(int i=1; i<args.length; i++) { + sb.append(args[i]); + if(i<args.length-1) sb.append(" "); + } + String name = sb.toString() + .replace("\\&", "{amp}") + .replace("&", "\u00a7") + .replace("{amp}", "&"); + name = new UnicodeUnescaper().translate(name); + manager.itemRenameJson.addProperty(heldUUID, name); + manager.saveItemRenameConfig(); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN + "[NEU] Set custom name for held item")); + break; + default: + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "[NEU] Unknown subcommand \""+args[0]+"\"")); + case "help": + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "[NEU] Available commands:")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "help: Print this message")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "clearall: Clears all custom names " + + EnumChatFormatting.BOLD + "(Cannot be undone)")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "clear: Clears held item name " + + EnumChatFormatting.BOLD + "(Cannot be undone)")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "uuid: Returns the UUID of the currently held item")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "set: Sets the custom name of the currently held item")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Usage: /neurename set [name...]")); + + } + } + }); + SimpleCommand questingCommand = new SimpleCommand("neuquest", new SimpleCommand.ProcessCommandRunnable() { public void processCommand(ICommandSender sender, String[] args) { @@ -129,18 +201,612 @@ public class NotEnoughUpdates { } }); + SimpleCommand gamemodesCommand = new SimpleCommand("neugamemodes", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + boolean upgradeOverride = args.length == 1 && args[0].equals("upgradeOverride"); + openGui = new GuiGamemodes(upgradeOverride); + } + }); + + SimpleCommand enchantColourCommand = new SimpleCommand("neuec", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + openGui = new GuiEnchantColour(); + } + }); + + SimpleCommand resetRepoCommand = new SimpleCommand("neuresetrepo", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + manager.resetRepo(); + } + }); + + SimpleCommand dungeonWinTest = new SimpleCommand("neudungeonwintest", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + if(args.length > 0) { + DungeonWin.TEAM_SCORE = new ResourceLocation("notenoughupdates:dungeon_win/"+args[0].toLowerCase()+".png"); + } + + DungeonWin.displayWin(); + } + }); + + SimpleCommand reloadRepoCommand = new SimpleCommand("neureloadrepo", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + File items = new File(manager.repoLocation, "items"); + if(items.exists()) { + File[] itemFiles = new File(manager.repoLocation, "items").listFiles(); + if(itemFiles != null) { + for(File f : itemFiles) { + String internalname = f.getName().substring(0, f.getName().length()-5); + manager.loadItem(internalname); + } + } + } + } + }); + + private static HashMap<String, String> petRarityToColourMap = new HashMap<>(); + static { + petRarityToColourMap.put("UNKNOWN", EnumChatFormatting.RED.toString()); + + petRarityToColourMap.put("COMMON", EnumChatFormatting.WHITE.toString()); + petRarityToColourMap.put("UNCOMMON", EnumChatFormatting.GREEN.toString()); + petRarityToColourMap.put("RARE", EnumChatFormatting.BLUE.toString()); + petRarityToColourMap.put("EPIC", EnumChatFormatting.DARK_PURPLE.toString()); + petRarityToColourMap.put("LEGENDARY", EnumChatFormatting.GOLD.toString()); + } + ScheduledExecutorService peekCommandExecutorService = null; + SimpleCommand peekCommand = new SimpleCommand("peek", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + String name; + if(args.length == 0) { + name = Minecraft.getMinecraft().thePlayer.getName(); + } else { + name = args[0]; + } + int id = new Random().nextInt(Integer.MAX_VALUE/2)+Integer.MAX_VALUE/2; + + Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion(new ChatComponentText( + EnumChatFormatting.YELLOW+"[PEEK] Getting player information..."), id); + profileViewer.getProfileByName(name, profile -> { + if (profile == null) { + Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion(new ChatComponentText( + EnumChatFormatting.RED+"[PEEK] Unknown player or api is down."), id); + } else { + profile.resetCache(); + + if(peekCommandExecutorService == null || peekCommandExecutorService.isShutdown()) { + peekCommandExecutorService = Executors.newSingleThreadScheduledExecutor(); + } else { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.RED+"[PEEK] New peek command run, cancelling old one.")); + peekCommandExecutorService.shutdownNow(); + peekCommandExecutorService = Executors.newSingleThreadScheduledExecutor(); + } + + Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion(new ChatComponentText( + EnumChatFormatting.YELLOW+"[PEEK] Getting player skyblock profiles..."), id); + + long startTime = System.currentTimeMillis(); + peekCommandExecutorService.schedule(new Runnable() { + public void run() { + if(System.currentTimeMillis() - startTime > 10*1000) { + + Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion(new ChatComponentText( + EnumChatFormatting.RED+"[PEEK] Getting profile info took too long, aborting."), id); + return; + } + + String g = EnumChatFormatting.GRAY.toString(); + + JsonObject profileInfo = profile.getProfileInformation(null); + if(profileInfo != null) { + float overallScore = 0; + + boolean isMe = name.equalsIgnoreCase("moulberry"); + + PlayerStats.Stats stats = profile.getStats(null); + JsonObject skill = profile.getSkillInfo(null); + + Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion(new ChatComponentText(EnumChatFormatting.GREEN+" "+ + EnumChatFormatting.STRIKETHROUGH+"-=-" +EnumChatFormatting.RESET+EnumChatFormatting.GREEN+" "+ + Utils.getElementAsString(profile.getHypixelProfile().get("displayname"), name) + "'s Info " + + EnumChatFormatting.STRIKETHROUGH+"-=-"), id); + + if(skill == null) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW+"Skills api disabled!")); + } else { + float totalSkillLVL = 0; + float totalSkillCount = 0; + + for(Map.Entry<String, JsonElement> entry : skill.entrySet()) { + if(entry.getKey().startsWith("level_skill")) { + if(entry.getKey().contains("runecrafting")) continue; + if(entry.getKey().contains("carpentry")) continue; + totalSkillLVL += entry.getValue().getAsFloat(); + totalSkillCount++; + } + } + + float combat = Utils.getElementAsFloat(skill.get("level_skill_combat"), 0); + float zombie = Utils.getElementAsFloat(skill.get("level_slayer_zombie"), 0); + float spider = Utils.getElementAsFloat(skill.get("level_slayer_spider"), 0); + float wolf = Utils.getElementAsFloat(skill.get("level_slayer_wolf"), 0); + + float avgSkillLVL = totalSkillLVL/totalSkillCount; + + if(isMe) { + avgSkillLVL = 6; + combat = 4; + zombie = 2; + spider = 1; + wolf = 2; + } + + EnumChatFormatting combatPrefix = combat>20?(combat>35?EnumChatFormatting.GREEN:EnumChatFormatting.YELLOW):EnumChatFormatting.RED; + EnumChatFormatting zombiePrefix = zombie>3?(zombie>6?EnumChatFormatting.GREEN:EnumChatFormatting.YELLOW):EnumChatFormatting.RED; + EnumChatFormatting spiderPrefix = spider>3?(spider>6?EnumChatFormatting.GREEN:EnumChatFormatting.YELLOW):EnumChatFormatting.RED; + EnumChatFormatting wolfPrefix = wolf>3?(wolf>6?EnumChatFormatting.GREEN:EnumChatFormatting.YELLOW):EnumChatFormatting.RED; + EnumChatFormatting avgPrefix = avgSkillLVL>20?(avgSkillLVL>35?EnumChatFormatting.GREEN:EnumChatFormatting.YELLOW):EnumChatFormatting.RED; + + overallScore += zombie*zombie/81f; + overallScore += spider*spider/81f; + overallScore += wolf*wolf/81f; + overallScore += avgSkillLVL/20f; + + int cata = (int)Utils.getElementAsFloat(skill.get("level_skill_catacombs"), 0); + EnumChatFormatting cataPrefix = cata>15?(cata>25?EnumChatFormatting.GREEN:EnumChatFormatting.YELLOW):EnumChatFormatting.RED; + + overallScore += cata*cata/2000f; + + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + g+"Combat: "+combatPrefix+(int)Math.floor(combat) + + (cata > 0 ? g+" - Cata: "+cataPrefix+cata : "")+ + g+" - AVG: " + avgPrefix+(int)Math.floor(avgSkillLVL))); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + g+"Slayer: "+zombiePrefix+(int)Math.floor(zombie)+g+"-"+ + spiderPrefix+(int)Math.floor(spider)+g+"-"+wolfPrefix+(int)Math.floor(wolf))); + } + if(stats == null) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.YELLOW+"Skills, collection and/or inventory apis disabled!")); + } else { + int health = (int)stats.get("health"); + int defence = (int)stats.get("defence"); + int strength = (int)stats.get("strength"); + int intelligence = (int)stats.get("intelligence"); + + EnumChatFormatting healthPrefix = health>800?(health>1600?EnumChatFormatting.GREEN:EnumChatFormatting.YELLOW):EnumChatFormatting.RED; + EnumChatFormatting defencePrefix = defence>200?(defence>600?EnumChatFormatting.GREEN:EnumChatFormatting.YELLOW):EnumChatFormatting.RED; + EnumChatFormatting strengthPrefix = strength>100?(strength>300?EnumChatFormatting.GREEN:EnumChatFormatting.YELLOW):EnumChatFormatting.RED; + EnumChatFormatting intelligencePrefix = intelligence>300?(intelligence>900?EnumChatFormatting.GREEN:EnumChatFormatting.YELLOW):EnumChatFormatting.RED; + + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + g+"Stats : "+healthPrefix+health+EnumChatFormatting.RED+"\u2764 "+ + defencePrefix+defence+EnumChatFormatting.GREEN+"\u2748 "+ + strengthPrefix+strength+EnumChatFormatting.RED+"\u2741 "+ + intelligencePrefix+intelligence+EnumChatFormatting.AQUA+"\u270e ")); + } + float bankBalance = Utils.getElementAsFloat(Utils.getElement(profileInfo, "banking.balance"), -1); + float purseBalance = Utils.getElementAsFloat(Utils.getElement(profileInfo, "coin_purse"), 0); + + long networth = profile.getNetWorth(null); + float money = Math.max(bankBalance+purseBalance, networth); + EnumChatFormatting moneyPrefix = money>50*1000*1000? + (money>200*1000*1000?EnumChatFormatting.GREEN:EnumChatFormatting.YELLOW):EnumChatFormatting.RED; + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + g+"Purse: "+moneyPrefix+Utils.shortNumberFormat(purseBalance, 0) + g+" - Bank: " + + (bankBalance == -1 ? EnumChatFormatting.YELLOW+"N/A" : moneyPrefix+ + (isMe?"4.8b":Utils.shortNumberFormat(bankBalance, 0))) + + (networth > 0 ? g+" - Net: "+moneyPrefix+Utils.shortNumberFormat(networth, 0) : ""))); + + overallScore += Math.min(2, money/(100f*1000*1000)); + + String activePet = Utils.getElementAsString(Utils.getElement(profile.getPetsInfo(null), "active_pet.type"), + "None Active"); + String activePetTier = Utils.getElementAsString(Utils.getElement(profile.getPetsInfo(null), "active_pet.tier"), "UNKNOWN"); + + String col = petRarityToColourMap.get(activePetTier); + if(col == null) col = EnumChatFormatting.LIGHT_PURPLE.toString(); + + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(g+"Pet : " + + col + WordUtils.capitalizeFully(activePet.replace("_", " ")))); + + String overall = "Skywars Main"; + if(isMe) { + overall = Utils.chromaString("Literally the best player to exist"); + } else if(overallScore < 5 && (bankBalance+purseBalance) > 500*1000*1000) { + overall = EnumChatFormatting.GOLD+"Bill Gates"; + } else if(overallScore > 9) { + overall = Utils.chromaString("Didn't even think this score was possible"); + } else if(overallScore > 8) { + overall = Utils.chromaString("Mentally unstable"); + } else if(overallScore > 7) { + overall = EnumChatFormatting.GOLD+"Why though 0.0"; + } else if(overallScore > 5.5) { + overall = EnumChatFormatting.GOLD+"Bro stop playing"; + } else if(overallScore > 4) { + overall = EnumChatFormatting.GREEN+"Kinda sweaty"; + } else if(overallScore > 3) { + overall = EnumChatFormatting.YELLOW+"Alright I guess"; + } else if(overallScore > 2) { + overall = EnumChatFormatting.YELLOW+"Ender Non"; + } else if(overallScore > 1) { + overall = EnumChatFormatting.RED+"Played Skyblock"; + } + + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(g+"Overall score: " + + overall + g + " (" + Math.round(overallScore*10)/10f + ")")); + + peekCommandExecutorService.shutdownNow(); + } else { + peekCommandExecutorService.schedule(this, 200, TimeUnit.MILLISECONDS); + } + } + }, 200, TimeUnit.MILLISECONDS); + } + }); + } + }, new SimpleCommand.TabCompleteRunnable() { + @Override + public List<String> tabComplete(ICommandSender sender, String[] args, BlockPos pos) { + if (args.length != 1) return null; + + String lastArg = args[args.length - 1]; + List<String> playerMatches = new ArrayList<>(); + for (EntityPlayer player : Minecraft.getMinecraft().theWorld.playerEntities) { + String playerName = player.getName(); + if (playerName.toLowerCase().startsWith(lastArg.toLowerCase())) { + playerMatches.add(playerName); + } + } + return playerMatches; + } + }); + + + SimpleCommand pcStatsCommand = new SimpleCommand("neustats", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + Minecraft mc = Minecraft.getMinecraft(); + StringBuilder builder = new StringBuilder(); + + if (args.length > 0 && args[0].toLowerCase().equals("modlist")){ + builder.append("```md\n"); + builder.append("# Mods Loaded").append("\n"); + for (ModContainer modContainer : Loader.instance().getActiveModList()) { + builder.append("[").append(modContainer.getName()).append("]") + .append("[").append(modContainer.getSource().getName()).append("]\n"); + } + builder.append("```"); + } else { + long memorySize = -1; + try { + memorySize = ((com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean()).getTotalPhysicalMemorySize(); + } catch(Exception e){} + long maxMemory = Runtime.getRuntime().maxMemory(); + long totalMemory = Runtime.getRuntime().totalMemory(); + long freeMemory = Runtime.getRuntime().freeMemory(); + long currentMemory = totalMemory - freeMemory; + int modCount = Loader.instance().getModList().size(); + int activeModCount = Loader.instance().getActiveModList().size(); + + builder.append("```md\n"); + builder.append("# System Stats").append("\n"); + builder.append("[OS]").append("[").append(System.getProperty("os.name")).append("]").append("\n"); + builder.append("[CPU]").append("[").append(OpenGlHelper.getCpu()).append("]").append("\n"); + builder.append("[Display]").append("[").append(String.format("%dx%d (%s)", Display.getWidth(), Display.getHeight(), GL11.glGetString(GL11.GL_VENDOR))).append("]").append("\n"); + builder.append("[GPU]").append("[").append(GL11.glGetString(GL11.GL_RENDERER)).append("]").append("\n"); + builder.append("[GPU Driver]").append("[").append(GL11.glGetString(GL11.GL_VERSION)).append("]").append("\n"); + if(memorySize > 0) { + builder.append("[Maximum Memory]").append("[").append(memorySize / 1024L / 1024L).append("MB]").append("\n"); + } + builder.append("[Shaders]").append("[").append((""+OpenGlHelper.areShadersSupported()).toUpperCase()).append("]").append("\n"); + builder.append("[Framebuffers]").append("[").append((""+OpenGlHelper.isFramebufferEnabled()).toUpperCase()).append("]").append("\n"); + builder.append("# Java Stats").append("\n"); + builder.append("[Java]").append("[").append(String.format("%s %dbit", System.getProperty("java.version"), mc.isJava64bit() ? 64 : 32)).append("]").append("\n"); + builder.append("[Memory]").append("[").append(String.format("% 2d%% %03d/%03dMB", currentMemory * 100L / maxMemory, currentMemory / 1024L / 1024L, maxMemory / 1024L / 1024L)).append("]").append("\n"); + builder.append("[Memory Allocated]").append("[").append(String.format("% 2d%% %03dMB", totalMemory * 100L / maxMemory, totalMemory / 1024L / 1024L)).append("]").append("\n"); + builder.append("# Game Stats").append("\n"); + builder.append("[Current FPS]").append("[").append(Minecraft.getDebugFPS()).append("]").append("\n"); + builder.append("[Loaded Mods]").append("[").append(activeModCount).append("/").append(modCount).append("]").append("\n"); + builder.append("[Forge]").append("[").append(ForgeVersion.getVersion()).append("]").append("\n"); + builder.append("# Neu Settings").append("\n"); + builder.append("[API Key]").append("[").append(!INSTANCE.manager.config.apiKey.value.isEmpty()).append("]").append("\n"); + builder.append("[On Skyblock]").append("[").append(hasSkyblockScoreboard).append("]").append("\n"); + builder.append("[Mod Version]").append("[").append(Loader.instance().getIndexedModList().get(MODID).getSource().getName()).append("]").append("\n"); + builder.append("# Repo Stats").append("\n"); + builder.append("[Last Commit]").append("[").append(manager.latestRepoCommit).append("]").append("\n"); + builder.append("[Loaded Items]").append("[").append(manager.getItemInformation().size()).append("]").append("\n"); + if (activeModCount <= 15) { + builder.append("# Mods Loaded").append("\n"); + for (ModContainer modContainer : Loader.instance().getActiveModList()) { + builder.append("[").append(modContainer.getName()).append("]") + .append("[").append(modContainer.getSource().getName()).append("]\n"); + } + builder.append("```"); + } else { + builder.append("```"); + } + } + try { + StringSelection clipboard = new StringSelection(builder.toString()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(clipboard, clipboard); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.GOLD + "[" + EnumChatFormatting.RED + "NotEnoughUpdates" + EnumChatFormatting.GOLD + "]: " + EnumChatFormatting.GREEN + "Dev info copied to clipboard.")); + } catch (Exception ignored) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.GOLD + "[" + EnumChatFormatting.RED + "NotEnoughUpdates" + EnumChatFormatting.GOLD + "]: " + EnumChatFormatting.DARK_RED + "Could not copy to clipboard.")); + } + } + }); + + public static ProfileViewer profileViewer; + + SimpleCommand.ProcessCommandRunnable viewProfileRunnable = new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + if(Loader.isModLoaded("optifine") && + new File(Minecraft.getMinecraft().mcDataDir, "optionsof.txt").exists()) { + try(InputStream in = new FileInputStream(new File(Minecraft.getMinecraft().mcDataDir, "optionsof.txt"))) { + BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); + + String line; + while((line = reader.readLine()) != null) { + if(line.contains("ofFastRender:true")) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + + "Some parts of the profile viewer do not work with OF Fast Render. Go to Video > Performance to disable it.")); + break; + } + } + } catch(Exception e) { + } + } + if (manager.config.apiKey.value == null || manager.config.apiKey.value.trim().isEmpty()) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + + "Can't view profile, apikey is not set. Run /api new and put the result in settings.")); + } else if (args.length == 0) { + profileViewer.getProfileByName(Minecraft.getMinecraft().thePlayer.getName(), profile -> { + if(profile == null) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + + "Invalid player name/api key. Maybe api is down? Try /api new.")); + } else { + profile.resetCache(); + openGui = new GuiProfileViewer(profile); + } + }); + } else if (args.length > 1) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + + "Too many arguments. Usage: /neuprofile [name]")); + } else { + profileViewer.getProfileByName(args[0], profile -> { + if(profile == null) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + + "Invalid player name/api key. Maybe api is down? Try /api new.")); + } else { + profile.resetCache(); + openGui = new GuiProfileViewer(profile); + } + }); + } + } + }; + + SimpleCommand viewProfileCommand = new SimpleCommand("neuprofile", viewProfileRunnable, new SimpleCommand.TabCompleteRunnable() { + @Override + public List<String> tabComplete(ICommandSender sender, String[] args, BlockPos pos) { + if(args.length != 1) return null; + + String lastArg = args[args.length-1]; + List<String> playerMatches = new ArrayList<>(); + for(EntityPlayer player : Minecraft.getMinecraft().theWorld.playerEntities) { + String playerName = player.getName(); + if(playerName.toLowerCase().startsWith(lastArg.toLowerCase())) { + playerMatches.add(playerName); + } + } + return playerMatches; + } + }); + + SimpleCommand viewProfileShortCommand = new SimpleCommand("pv", new SimpleCommand.ProcessCommandRunnable() { + @Override + public void processCommand(ICommandSender sender, String[] args) { + if(!isOnSkyblock()) { + Minecraft.getMinecraft().thePlayer.sendChatMessage("/pv " + StringUtils.join(args, " ")); + } else { + viewProfileRunnable.processCommand(sender, args); + } + } + }, new SimpleCommand.TabCompleteRunnable() { + @Override + public List<String> tabComplete(ICommandSender sender, String[] args, BlockPos pos) { + if (args.length != 1) return null; + + String lastArg = args[args.length - 1]; + List<String> playerMatches = new ArrayList<>(); + for (EntityPlayer player : Minecraft.getMinecraft().theWorld.playerEntities) { + String playerName = player.getName(); + if (playerName.toLowerCase().startsWith(lastArg.toLowerCase())) { + playerMatches.add(playerName); + } + } + return playerMatches; + } + }); + + SimpleCommand viewProfileShort2Command = new SimpleCommand("vp", new SimpleCommand.ProcessCommandRunnable() { + @Override + public void processCommand(ICommandSender sender, String[] args) { + if(!isOnSkyblock()) { + Minecraft.getMinecraft().thePlayer.sendChatMessage("/vp " + StringUtils.join(args, " ")); + } else { + viewProfileRunnable.processCommand(sender, args); + } + } + }, new SimpleCommand.TabCompleteRunnable() { + @Override + public List<String> tabComplete(ICommandSender sender, String[] args, BlockPos pos) { + if (args.length != 1) return null; + + String lastArg = args[args.length - 1]; + List<String> playerMatches = new ArrayList<>(); + for (EntityPlayer player : Minecraft.getMinecraft().theWorld.playerEntities) { + String playerName = player.getName(); + if (playerName.toLowerCase().startsWith(lastArg.toLowerCase())) { + playerMatches.add(playerName); + } + } + return playerMatches; + } + }); + + SimpleCommand linksCommand = new SimpleCommand("neulinks", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + File repo = manager.repoLocation; + if(repo.exists()) { + File updateJson = new File(repo, "update.json"); + try { + JsonObject update = manager.getJsonFromFile(updateJson); + + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("")); + displayLinks(update); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("")); + } catch (Exception ignored) { + } + } + } + }); + SimpleCommand overlayPlacementsCommand = new SimpleCommand("neuoverlay", new SimpleCommand.ProcessCommandRunnable() { public void processCommand(ICommandSender sender, String[] args) { openGui = new NEUOverlayPlacements(); } }); + SimpleCommand tutorialCommand = new SimpleCommand("neututorial", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + openGui = new HelpGUI(); + } + }); + + public Color[][] colourMap = null; + SimpleCommand neumapCommand = new SimpleCommand("neumap", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + if(colourMap == null) { + try(BufferedReader reader = new BufferedReader(new InputStreamReader(Minecraft.getMinecraft().getResourceManager().getResource( + new ResourceLocation("notenoughupdates:maps/F1Full.json")).getInputStream(), StandardCharsets.UTF_8))) { + JsonObject json = NotEnoughUpdates.INSTANCE.manager.gson.fromJson(reader, JsonObject.class); + + colourMap = new Color[128][128]; + for(int x=0; x<128; x++) { + for(int y=0; y<128; y++) { + colourMap[x][y] = new Color(0, 0, 0, 0); + } + } + for(Map.Entry<String, JsonElement> entry : json.entrySet()) { + int x = Integer.parseInt(entry.getKey().split(":")[0]); + int y = Integer.parseInt(entry.getKey().split(":")[1]); + + colourMap[x][y] = new Color(entry.getValue().getAsInt(), true); + } + } catch(Exception ignored) { } + } + + if(!manager.config.dev.value) { + openGui = new GuiDungeonMapEditor(); + return; + } + + if(args.length == 1 && args[0].equals("reset")) { + colourMap = null; + return; + } + + if(args.length != 2) { + openGui = new GuiDungeonMapEditor(); + return; + } + + if(args[0].equals("save")) { + ItemStack stack = Minecraft.getMinecraft().thePlayer.getHeldItem(); + if(stack != null && stack.getItem() instanceof ItemMap) { + ItemMap map = (ItemMap) stack.getItem(); + MapData mapData = map.getMapData(stack, Minecraft.getMinecraft().theWorld); + + if (mapData == null) return; + + JsonObject json = new JsonObject(); + for (int i = 0; i < 16384; ++i) { + int x = i % 128; + int y = i / 128; + + int j = mapData.colors[i] & 255; + + Color c; + if (j / 4 == 0) { + c = new Color((i + i / 128 & 1) * 8 + 16 << 24, true); + } else { + c = new Color(MapColor.mapColorArray[j / 4].func_151643_b(j & 3), true); + } + + json.addProperty(x+":"+y, c.getRGB()); + } + + try { + new File(manager.configLocation, "maps").mkdirs(); + manager.writeJson(json, new File(manager.configLocation, "maps/"+args[1]+".json")); + } catch(Exception e) { + e.printStackTrace(); + } + + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN+ + "Saved to file.")); + } + + return; + } + + if(args[0].equals("load")) { + JsonObject json = manager.getJsonFromFile(new File(manager.configLocation, "maps/"+args[1]+".json")); + + colourMap = new Color[128][128]; + for(int x=0; x<128; x++) { + for(int y=0; y<128; y++) { + colourMap[x][y] = new Color(0, 0, 0, 0); + } + } + for(Map.Entry<String, JsonElement> entry : json.entrySet()) { + int x = Integer.parseInt(entry.getKey().split(":")[0]); + int y = Integer.parseInt(entry.getKey().split(":")[1]); + + colourMap[x][y] = new Color(entry.getValue().getAsInt(), true); + } + + return; + } + + openGui = new GuiDungeonMapEditor(); + } + }); + SimpleCommand cosmeticsCommand = new SimpleCommand("neucosmetics", new SimpleCommand.ProcessCommandRunnable() { public void processCommand(ICommandSender sender, String[] args) { + openGui = new GuiCosmetics(); + } + }); + + SimpleCommand settingsCommand = new SimpleCommand("neusettings", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + overlay.displayInformationPane(new SettingsInfoPane(overlay, manager)); + if(!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) { + openGui = new GuiInventory(Minecraft.getMinecraft().thePlayer); + } + } + }); + + SimpleCommand settingsCommand2 = new SimpleCommand("neuconfig", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + overlay.displayInformationPane(new SettingsInfoPane(overlay, manager)); if(!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) { openGui = new GuiInventory(Minecraft.getMinecraft().thePlayer); } - overlay.displayInformationPane(new CosmeticsInfoPane(overlay, manager)); } }); @@ -151,12 +817,14 @@ public class NotEnoughUpdates { "You must be on Skyblock to use this feature.")); } else if(manager.config.apiKey.value == null || manager.config.apiKey.value.trim().isEmpty()) { Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED+ - "Can't open NeuAH, Api Key is not set. Run /api new and put the result in settings.")); + "Can't open NeuAH, apikey is not set. Run /api new and put the result in settings.")); } else { openGui = new CustomAHGui(); manager.auctionManager.customAH.lastOpen = System.currentTimeMillis(); manager.auctionManager.customAH.clearSearch(); manager.auctionManager.customAH.updateSearch(); + + if(args.length > 0) manager.auctionManager.customAH.setSearch(StringUtils.join(args, " ")); } } }); @@ -168,21 +836,43 @@ public class NotEnoughUpdates { @EventHandler public void preinit(FMLPreInitializationEvent event) { INSTANCE = this; + MinecraftForge.EVENT_BUS.register(this); + MinecraftForge.EVENT_BUS.register(new NEUEventListener(this)); MinecraftForge.EVENT_BUS.register(CapeManager.getInstance()); + MinecraftForge.EVENT_BUS.register(new SBGamemodes()); + MinecraftForge.EVENT_BUS.register(SBInfo.getInstance()); + MinecraftForge.EVENT_BUS.register(CustomItemEffects.INSTANCE); + MinecraftForge.EVENT_BUS.register(new DungeonMap()); + //MinecraftForge.EVENT_BUS.register(new BetterPortals()); File f = new File(event.getModConfigurationDirectory(), "notenoughupdates"); f.mkdirs(); ClientCommandHandler.instance.registerCommand(collectionLogCommand); ClientCommandHandler.instance.registerCommand(cosmeticsCommand); + ClientCommandHandler.instance.registerCommand(linksCommand); + ClientCommandHandler.instance.registerCommand(gamemodesCommand); + ClientCommandHandler.instance.registerCommand(resetRepoCommand); + ClientCommandHandler.instance.registerCommand(reloadRepoCommand); + ClientCommandHandler.instance.registerCommand(itemRenameCommand); + ClientCommandHandler.instance.registerCommand(viewProfileCommand); + ClientCommandHandler.instance.registerCommand(viewProfileShortCommand); + ClientCommandHandler.instance.registerCommand(viewProfileShort2Command); + ClientCommandHandler.instance.registerCommand(peekCommand); + ClientCommandHandler.instance.registerCommand(tutorialCommand); ClientCommandHandler.instance.registerCommand(overlayPlacementsCommand); - //ClientCommandHandler.instance.registerCommand(questingCommand); + ClientCommandHandler.instance.registerCommand(enchantColourCommand); ClientCommandHandler.instance.registerCommand(neuAhCommand); + ClientCommandHandler.instance.registerCommand(pcStatsCommand); + ClientCommandHandler.instance.registerCommand(neumapCommand); + ClientCommandHandler.instance.registerCommand(settingsCommand); + ClientCommandHandler.instance.registerCommand(settingsCommand2); + ClientCommandHandler.instance.registerCommand(dungeonWinTest); - neuio = new NEUIO(getAccessToken()); - manager = new NEUManager(this, neuio, f); + manager = new NEUManager(this, f); manager.loadItemInformation(); overlay = new NEUOverlay(manager); + profileViewer = new ProfileViewer(manager); for(KeyBinding kb : manager.keybinds) { ClientRegistry.registerKeyBinding(kb); @@ -203,7 +893,7 @@ public class NotEnoughUpdates { })); //TODO: login code. Ignore this, used for testing. - /*try { + try { Field field = Minecraft.class.getDeclaredField("session"); YggdrasilUserAuthentication auth = (YggdrasilUserAuthentication) new YggdrasilAuthenticationService(Proxy.NO_PROXY, UUID.randomUUID().toString()) @@ -232,7 +922,7 @@ public class NotEnoughUpdates { field.setAccessible(true); field.set(Minecraft.getMinecraft(), session); } catch (NoSuchFieldException | AuthenticationException | IllegalAccessException e) { - }*/ + } } /** @@ -250,814 +940,117 @@ public class NotEnoughUpdates { } } - /** - * 1)Will send the cached message from #sendChatMessage when at least 200ms has passed since the last message. - * This is used in order to prevent the mod spamming messages. - * 2)Adds unique items to the collection log - */ - private HashMap<String, Long> newItemAddMap = new HashMap<>(); - @SubscribeEvent - public void onTick(TickEvent.ClientTickEvent event) { - if(openGui != null) { - Minecraft.getMinecraft().displayGuiScreen(openGui); - openGui = null; - } - if(hasSkyblockScoreboard()) { - manager.auctionManager.tick(); - if(!joinedSB && manager.config.showUpdateMsg.value) { - File repo = manager.repoLocation; - if(repo.exists()) { - File updateJson = new File(repo, "update.json"); - try { - JsonObject o = manager.getJsonFromFile(updateJson); - - String version = o.get("version").getAsString(); - - if(!VERSION.equalsIgnoreCase(version)) { - String update_msg = o.get("update_msg").getAsString(); - String discord_link = o.get("discord_link").getAsString(); - String youtube_link = o.get("youtube_link").getAsString(); - String update_link = o.get("update_link").getAsString(); - String github_link = o.get("github_link").getAsString(); - String other_text = o.get("other_text").getAsString(); - String other_link = o.get("other_link").getAsString(); - - int first_len = -1; - for(String line : update_msg.split("\n")) { - FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; - int len = fr.getStringWidth(line); - if(first_len == -1) { - first_len = len; - } - int missing_len = first_len-len; - if(missing_len > 0) { - StringBuilder sb = new StringBuilder(line); - for(int i=0; i<missing_len/8; i++) { - sb.insert(0, " "); - } - line = sb.toString(); - } - line = line.replaceAll("\\{version}", version); - Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(line)); - } - ChatComponentText other = null; - if(other_text.length() > 0) { - other = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.BLUE+other_text+EnumChatFormatting.GRAY+"]"); - other.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, other_link)); - } - ChatComponentText links = new ChatComponentText(""); - ChatComponentText separator = new ChatComponentText( - EnumChatFormatting.GRAY+EnumChatFormatting.BOLD.toString()+EnumChatFormatting.STRIKETHROUGH+(other==null?"---":"--")); - ChatComponentText discord = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.BLUE+"Discord"+EnumChatFormatting.GRAY+"]"); - discord.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, discord_link)); - ChatComponentText youtube = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.RED+"YouTube"+EnumChatFormatting.GRAY+"]"); - youtube.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, youtube_link)); - ChatComponentText release = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.GREEN+"Release"+EnumChatFormatting.GRAY+"]"); - release.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, update_link)); - ChatComponentText github = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.DARK_PURPLE+"GitHub"+EnumChatFormatting.GRAY+"]"); - github.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, github_link)); - - - links.appendSibling(separator); - links.appendSibling(discord); - links.appendSibling(separator); - links.appendSibling(youtube); - links.appendSibling(separator); - links.appendSibling(release); - links.appendSibling(separator); - links.appendSibling(github); - links.appendSibling(separator); - if(other != null) { - links.appendSibling(other); - links.appendSibling(separator); - } - - Minecraft.getMinecraft().thePlayer.addChatMessage(links); - Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("")); - - } - - joinedSB = true; - } catch(Exception ignored) {} - } - } - //NEUQuesting.getInstance().tick(); - //GuiQuestLine.questLine.tick(); - } - if(currChatMessage != null && System.currentTimeMillis() - lastChatMessage > CHAT_MSG_COOLDOWN) { - lastChatMessage = System.currentTimeMillis(); - Minecraft.getMinecraft().thePlayer.sendChatMessage(currChatMessage); - currChatMessage = null; - } - if(hasSkyblockScoreboard() && manager.getCurrentProfile() != null && manager.getCurrentProfile().length() > 0) { - HashSet<String> newItem = new HashSet<>(); - if(Minecraft.getMinecraft().currentScreen instanceof GuiContainer && - !(Minecraft.getMinecraft().currentScreen instanceof GuiCrafting)) { - boolean usableContainer = true; - for(ItemStack stack : Minecraft.getMinecraft().thePlayer.openContainer.getInventory()) { - if(stack == null) { - continue; - } - if(stack.hasTagCompound()) { - NBTTagCompound tag = stack.getTagCompound(); - if(tag.hasKey("ExtraAttributes", 10)) { - continue; - } - } - usableContainer = false; - break; - } - if(!usableContainer) { - if(Minecraft.getMinecraft().currentScreen instanceof GuiChest) { - GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen; - ContainerChest container = (ContainerChest) chest.inventorySlots; - String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText(); - - if(containerName.equals("Accessory Bag")) { - usableContainer = true; - } - } - } - if(usableContainer) { - for(ItemStack stack : Minecraft.getMinecraft().thePlayer.openContainer.getInventory()) { - processUniqueStack(stack, newItem); - } - for(ItemStack stack : Minecraft.getMinecraft().thePlayer.inventory.mainInventory) { - processUniqueStack(stack, newItem); - } - } - } else { - - for(ItemStack stack : Minecraft.getMinecraft().thePlayer.inventory.mainInventory) { - processUniqueStack(stack, newItem); - } - } - newItemAddMap.keySet().retainAll(newItem); - } - } - - private void processUniqueStack(ItemStack stack, HashSet<String> newItem) { - if(stack != null && stack.hasTagCompound()) { - String internalname = manager.getInternalNameForItem(stack); - if(internalname != null) { - ArrayList<String> log = manager.config.collectionLog.value.computeIfAbsent( - manager.getCurrentProfile(), k -> new ArrayList<>()); - if(!log.contains(internalname)) { - newItem.add(internalname); - if(newItemAddMap.containsKey(internalname)) { - if(System.currentTimeMillis() - newItemAddMap.get(internalname) > 1000) { - log.add(internalname); - } - } else { - newItemAddMap.put(internalname, System.currentTimeMillis()); - } - } - } - } - } - - @SubscribeEvent - public void onRenderGameOverlay(RenderGameOverlayEvent event) { - if(event.type != null && event.type.equals(RenderGameOverlayEvent.ElementType.BOSSHEALTH) && - Minecraft.getMinecraft().currentScreen instanceof GuiContainer && overlay.isUsingMobsFilter()) { - event.setCanceled(true); - } - } - - /** - * When opening a GuiContainer, will reset the overlay and load the config. - * When closing a GuiContainer, will save the config. - * Also includes a dev feature used for automatically acquiring crafting information from the "Crafting Table" GUI. - */ - AtomicBoolean missingRecipe = new AtomicBoolean(false); - @SubscribeEvent - public void onGuiOpen(GuiOpenEvent event) { - manager.auctionManager.customAH.lastGuiScreenSwitch = System.currentTimeMillis(); - - if(event.gui == null && manager.auctionManager.customAH.isRenderOverAuctionView() && - !(Minecraft.getMinecraft().currentScreen instanceof CustomAHGui)) { - event.gui = new CustomAHGui(); + public void displayLinks(JsonObject update) { + String discord_link = update.get("discord_link").getAsString(); + String youtube_link = update.get("youtube_link").getAsString(); + String update_link = update.get("update_link").getAsString(); + String github_link = update.get("github_link").getAsString(); + String other_text = update.get("other_text").getAsString(); + String other_link = update.get("other_link").getAsString(); + + ChatComponentText other = null; + if(other_text.length() > 0) { + other = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.BLUE+other_text+EnumChatFormatting.GRAY+"]"); + other.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, other_link)); } - - if(!(event.gui instanceof GuiChest || event.gui instanceof GuiEditSign)) { - manager.auctionManager.customAH.setRenderOverAuctionView(false); - } else if(event.gui instanceof GuiChest && (manager.auctionManager.customAH.isRenderOverAuctionView() || - Minecraft.getMinecraft().currentScreen instanceof CustomAHGui)){ - GuiChest chest = (GuiChest) event.gui; - ContainerChest container = (ContainerChest) chest.inventorySlots; - String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText(); - - manager.auctionManager.customAH.setRenderOverAuctionView(containerName.trim().equals("Auction View") || - containerName.trim().equals("BIN Auction View") || containerName.trim().equals("Confirm Bid")); + ChatComponentText links = new ChatComponentText(""); + ChatComponentText separator = new ChatComponentText( + EnumChatFormatting.GRAY+EnumChatFormatting.BOLD.toString()+EnumChatFormatting.STRIKETHROUGH+(other==null?"---":"--")); + ChatComponentText discord = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.BLUE+"Discord"+EnumChatFormatting.GRAY+"]"); + discord.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, discord_link)); + ChatComponentText youtube = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.RED+"YouTube"+EnumChatFormatting.GRAY+"]"); + youtube.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, youtube_link)); + ChatComponentText release = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.GREEN+"Release"+EnumChatFormatting.GRAY+"]"); + release.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, update_link)); + ChatComponentText github = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.DARK_PURPLE+"GitHub"+EnumChatFormatting.GRAY+"]"); + github.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, github_link)); + + links.appendSibling(separator); + links.appendSibling(discord); + links.appendSibling(separator); + links.appendSibling(youtube); + links.appendSibling(separator); + links.appendSibling(release); + links.appendSibling(separator); + links.appendSibling(github); + links.appendSibling(separator); + if(other != null) { + links.appendSibling(other); + links.appendSibling(separator); } - //OPEN - if(Minecraft.getMinecraft().currentScreen == null - && event.gui instanceof GuiContainer) { - overlay.reset(); - manager.loadConfig(); - } - //CLOSE - if(Minecraft.getMinecraft().currentScreen instanceof GuiContainer - && event.gui == null) { - try { - manager.saveConfig(); - } catch(IOException e) {} - } - if(event.gui != null && manager.config.dev.value) { - if(event.gui instanceof GuiChest) { - GuiChest eventGui = (GuiChest) event.gui; - ContainerChest cc = (ContainerChest) eventGui.inventorySlots; - IInventory lower = cc.getLowerChestInventory(); - ses.schedule(() -> { - if(Minecraft.getMinecraft().currentScreen != event.gui) { - return; - } - if(lower.getStackInSlot(23).getDisplayName().endsWith("Crafting Table")) { - try { - ItemStack res = lower.getStackInSlot(25); - String resInternalname = manager.getInternalNameForItem(res); - - if(lower.getStackInSlot(48) != null) { - String backName = null; - NBTTagCompound tag = lower.getStackInSlot(48).getTagCompound(); - if(tag.hasKey("display", 10)) { - NBTTagCompound nbttagcompound = tag.getCompoundTag("display"); - if(nbttagcompound.getTagId("Lore") == 9){ - NBTTagList nbttaglist1 = nbttagcompound.getTagList("Lore", 8); - backName = nbttaglist1.getStringTagAt(0); - } - } - - if(backName != null) { - String[] split = backName.split(" "); - if(split[split.length-1].contains("Rewards")) { - String col = backName.substring(split[0].length()+1, - backName.length()-split[split.length-1].length()-1); - - JsonObject json = manager.getItemInformation().get(resInternalname); - json.addProperty("crafttext", "Requires: " + col); - - Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Added: " + resInternalname)); - manager.writeJsonDefaultDir(json, resInternalname+".json"); - manager.loadItem(resInternalname); - } - } - } - - /*JsonArray arr = null; - File f = new File(manager.configLocation, "missing.json"); - try(InputStream instream = new FileInputStream(f)) { - BufferedReader reader = new BufferedReader(new InputStreamReader(instream, StandardCharsets.UTF_8)); - JsonObject json = manager.gson.fromJson(reader, JsonObject.class); - arr = json.getAsJsonArray("missing"); - } catch(IOException e) {} - try { - JsonObject json = new JsonObject(); - JsonArray newArr = new JsonArray(); - for(JsonElement e : arr) { - if(!e.getAsString().equals(resInternalname)) { - newArr.add(e); - } - } - json.add("missing", newArr); - manager.writeJson(json, f); - } catch(IOException e) {}*/ - - - - /*JsonObject recipe = new JsonObject(); - - String[] x = {"1","2","3"}; - String[] y = {"A","B","C"}; - - for(int i=0; i<=18; i+=9) { - for(int j=0; j<3; j++) { - ItemStack stack = lower.getStackInSlot(10+i+j); - String internalname = ""; - if(stack != null) { - internalname = manager.getInternalNameForItem(stack); - if(!manager.getItemInformation().containsKey(internalname)) { - manager.writeItemToFile(stack); - } - internalname += ":"+stack.stackSize; - } - recipe.addProperty(y[i/9]+x[j], internalname); - } - } - - JsonObject json = manager.getJsonForItem(res); - json.add("recipe", recipe); - json.addProperty("internalname", resInternalname); - json.addProperty("clickcommand", "viewrecipe"); - json.addProperty("modver", NotEnoughUpdates.VERSION); - - Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Added: " + resInternalname)); - manager.writeJsonDefaultDir(json, resInternalname+".json"); - manager.loadItem(resInternalname);*/ - } catch(Exception e) { - e.printStackTrace(); - } - } - }, 200, TimeUnit.MILLISECONDS); - return; - } - } + Minecraft.getMinecraft().thePlayer.addChatMessage(links); } - /** - * 1) When receiving "You are playing on profile" messages, will set the current profile. - * 2) When a /viewrecipe command fails (i.e. player does not have recipe unlocked, will open the custom recipe GUI) - * 3) Replaces lobby join notifications when streamer mode is active - */ - @SubscribeEvent(priority = EventPriority.LOW) - public void onGuiChat(ClientChatReceivedEvent e) { - String r = null; - String unformatted = Utils.cleanColour(e.message.getUnformattedText()); - if(unformatted.startsWith("You are playing on profile: ")) { - manager.setCurrentProfile(unformatted.substring("You are playing on profile: ".length()).split(" ")[0].trim()); - } else if(unformatted.startsWith("Your profile was changed to: ")) {//Your profile was changed to: - manager.setCurrentProfile(unformatted.substring("Your profile was changed to: ".length()).split(" ")[0].trim()); - } else if(unformatted.startsWith("Your new API key is ")) { - manager.config.apiKey.value = unformatted.substring("Your new API key is ".length()); - try { manager.saveConfig(); } catch(IOException ioe) {} - } - if(e.message.getFormattedText().equals(EnumChatFormatting.RESET.toString()+ - EnumChatFormatting.RED+"You haven't unlocked this recipe!"+EnumChatFormatting.RESET)) { - r = EnumChatFormatting.RED+"You haven't unlocked this recipe!"; - } else if(e.message.getFormattedText().startsWith(EnumChatFormatting.RESET.toString()+ - EnumChatFormatting.RED+"Invalid recipe ")) { - r = ""; - } - if(r != null) { - if(manager.failViewItem(r)) { - e.setCanceled(true); - } - missingRecipe.set(true); - } - //System.out.println(e.message); - if(isOnSkyblock() && manager.config.streamerMode.value && e.message instanceof ChatComponentText) { - String m = e.message.getFormattedText(); - String m2 = StreamerMode.filterChat(e.message.getFormattedText()); - if(!m.equals(m2)) { - e.message = new ChatComponentText(m2); - } - } - } - - /** - * Sets hoverInv and focusInv variables, representing whether the NEUOverlay should render behind the inventory when - * (hoverInv == true) and whether mouse/kbd inputs shouldn't be sent to NEUOverlay (focusInv == true). - * - * If hoverInv is true, will render the overlay immediately (resulting in the inventory being drawn over the GUI) - * If hoverInv is false, the overlay will render in #onGuiScreenDraw (resulting in the GUI being drawn over the inv) - * - * All of this only matters if players are using gui scale auto which may result in the inventory being drawn - * over the various panes. - * @param event - */ @SubscribeEvent - public void onGuiBackgroundDraw(GuiScreenEvent.BackgroundDrawnEvent event) { - if((event.gui instanceof GuiContainer || event.gui instanceof CustomAHGui) && isOnSkyblock()) { - ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); - int width = scaledresolution.getScaledWidth(); - - boolean hoverPane = event.getMouseX() < width*overlay.getInfoPaneOffsetFactor() || - event.getMouseX() > width*overlay.getItemPaneOffsetFactor(); - - if(event.gui instanceof GuiContainer) { - try { - int xSize = (int) Utils.getField(GuiContainer.class, event.gui, "xSize", "field_146999_f"); - int ySize = (int) Utils.getField(GuiContainer.class, event.gui, "ySize", "field_147000_g"); - int guiLeft = (int) Utils.getField(GuiContainer.class, event.gui, "guiLeft", "field_147003_i"); - int guiTop = (int) Utils.getField(GuiContainer.class, event.gui, "guiTop", "field_147009_r"); - - hoverInv = event.getMouseX() > guiLeft && event.getMouseX() < guiLeft + xSize && - event.getMouseY() > guiTop && event.getMouseY() < guiTop + ySize; + public void onTick(TickEvent.ClientTickEvent event) { + if (event.phase != TickEvent.Phase.START) return; + long currentTime = System.currentTimeMillis(); - if(hoverPane) { - if(!hoverInv) focusInv = false; - } else { - focusInv = true; - } - } catch(NullPointerException npe) { - npe.printStackTrace(); - focusInv = !hoverPane; - } - if(focusInv) { - try { - overlay.render(event.getMouseX(), event.getMouseY(), hoverInv && focusInv); - } catch(ConcurrentModificationException e) {e.printStackTrace();} - GL11.glTranslatef(0, 0, 10); - } + if (openGui != null) { + if(Minecraft.getMinecraft().thePlayer.openContainer != null) { + Minecraft.getMinecraft().thePlayer.closeScreen(); } + Minecraft.getMinecraft().displayGuiScreen(openGui); + openGui = null; } - } - - @SubscribeEvent - public void onGuiScreenDrawPre(GuiScreenEvent.DrawScreenEvent.Pre event) { - if(event.gui instanceof CustomAHGui || manager.auctionManager.customAH.isRenderOverAuctionView()) { - event.setCanceled(true); - - ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); - int width = scaledResolution.getScaledWidth(); - int height = scaledResolution.getScaledHeight(); - - //Dark background - Utils.drawGradientRect(0, 0, width, height, -1072689136, -804253680); - - if(event.mouseX < width*overlay.getWidthMult()/3 || event.mouseX > width-width*overlay.getWidthMult()/3) { - manager.auctionManager.customAH.drawScreen(event.mouseX, event.mouseY); - overlay.render(event.mouseX, event.mouseY, false); - } else { - overlay.render(event.mouseX, event.mouseY, false); - manager.auctionManager.customAH.drawScreen(event.mouseX, event.mouseY); - } - + if(currChatMessage != null && currentTime - lastChatMessage > CHAT_MSG_COOLDOWN) { + lastChatMessage = currentTime; + Minecraft.getMinecraft().thePlayer.sendChatMessage(currChatMessage); + currChatMessage = null; } } - /** - * Will draw the NEUOverlay over the inventory if focusInv == false. (z-translation of 300 is so that NEUOverlay - * will draw over Items in the inventory (which render at a z value of about 250)) - * @param event - */ - @SubscribeEvent - public void onGuiScreenDrawPost(GuiScreenEvent.DrawScreenEvent.Post event) { - if(!(event.gui instanceof CustomAHGui || manager.auctionManager.customAH.isRenderOverAuctionView())) { - if(event.gui instanceof GuiContainer && isOnSkyblock()) { - - renderDungeonChestOverlay(event.gui); - - if(!focusInv) { - GL11.glTranslatef(0, 0, 300); - overlay.render(event.mouseX, event.mouseY, hoverInv && focusInv); - GL11.glTranslatef(0, 0, -300); - } - overlay.renderOverlay(event.mouseX, event.mouseY); - } - } + public boolean isOnSkyblock() { + if(!manager.config.onlyShowOnSkyblock.value) return true; + return hasSkyblockScoreboard(); } - private void renderDungeonChestOverlay(GuiScreen gui) { - if(gui instanceof GuiChest && manager.auctionManager.activeAuctions > 0) { - try { - int xSize = (int) Utils.getField(GuiContainer.class, gui, "xSize", "field_146999_f"); - int ySize = (int) Utils.getField(GuiContainer.class, gui, "ySize", "field_147000_g"); - int guiLeft = (int) Utils.getField(GuiContainer.class, gui, "guiLeft", "field_147003_i"); - int guiTop = (int) Utils.getField(GuiContainer.class, gui, "guiTop", "field_147009_r"); - - GuiChest eventGui = (GuiChest) gui; - ContainerChest cc = (ContainerChest) eventGui.inventorySlots; - IInventory lower = cc.getLowerChestInventory(); - - ItemStack rewardChest = lower.getStackInSlot(31); - if (rewardChest != null && rewardChest.getDisplayName().endsWith(EnumChatFormatting.GREEN+"Open Reward Chest")) { - int chestCost = 0; - String line6 = Utils.cleanColour(manager.getLoreFromNBT(rewardChest.getTagCompound())[6]); - StringBuilder cost = new StringBuilder(); - for(int i=0; i<line6.length(); i++) { - char c = line6.charAt(i); - if("0123456789".indexOf(c) >= 0) { - cost.append(c); - } - } - if(cost.length() > 0) { - chestCost = Integer.parseInt(cost.toString()); - } - - boolean missing = false; - int totalValue = 0; - for(int i=0; i<5; i++) { - ItemStack item = lower.getStackInSlot(11+i); - String internal = manager.getInternalNameForItem(item); - if(internal != null) { - int worth = manager.auctionManager.getLowestBin(internal); - if(worth > 0) { - totalValue += worth; - } else { - missing = true; - break; - } - } - } - int profitLoss = totalValue - chestCost; - - NumberFormat format = NumberFormat.getInstance(Locale.US); - String valueString; - if(!missing) { - valueString = EnumChatFormatting.BLUE+"Chest value: " + EnumChatFormatting.GOLD - + EnumChatFormatting.BOLD + format.format(totalValue) + " coins"; - } else { - valueString = EnumChatFormatting.BLUE+"Couldn't find item on AH. Item is very rare!"; - } - String plString; - if(missing) { - plString = ""; - } else if(profitLoss >= 0) { - plString = EnumChatFormatting.BLUE+"Profit/loss: " + EnumChatFormatting.DARK_GREEN - + EnumChatFormatting.BOLD + "+" + format.format(profitLoss) + " coins"; - } else { - plString = EnumChatFormatting.BLUE+"Profit/loss: " + EnumChatFormatting.RED - + EnumChatFormatting.BOLD + "-" + format.format(-profitLoss) + " coins"; - } - - Minecraft.getMinecraft().getTextureManager().bindTexture(dungeon_chest_worth); - GL11.glColor4f(1, 1, 1, 1); - GlStateManager.disableLighting(); - Utils.drawTexturedRect(guiLeft+xSize+4, guiTop, 180, 45, 0, 180/256f, 0, 45/256f, GL11.GL_NEAREST); + private boolean hasSkyblockScoreboard; - Utils.drawStringCenteredScaledMaxWidth(valueString, Minecraft.getMinecraft().fontRendererObj, guiLeft+xSize+4+90, - guiTop+14, true, 170, Color.BLACK.getRGB()); - Utils.drawStringCenteredScaledMaxWidth(plString, Minecraft.getMinecraft().fontRendererObj, guiLeft+xSize+4+90, - guiTop+28, true, 170, Color.BLACK.getRGB()); - - } - } catch(Exception e) { - e.printStackTrace(); - } - } + public boolean hasSkyblockScoreboard() { + return hasSkyblockScoreboard; } - /** - * Sends a mouse event to NEUOverlay if the inventory isn't hovered AND focused. - * Will also cancel the event if if NEUOverlay#mouseInput returns true. - * @param event - */ - @SubscribeEvent - public void onGuiScreenMouse(GuiScreenEvent.MouseInputEvent.Pre event) { - if(event.gui instanceof CustomAHGui || manager.auctionManager.customAH.isRenderOverAuctionView()) { - event.setCanceled(true); - manager.auctionManager.customAH.handleMouseInput(); - overlay.mouseInput(); - return; - } - if(event.gui instanceof GuiContainer && !(hoverInv && focusInv) && isOnSkyblock()) { - if(overlay.mouseInput()) { - event.setCanceled(true); - } - } - } + //Stolen from Biscut's SkyblockAddons + public void updateSkyblockScoreboard() { + final Pattern SERVER_BRAND_PATTERN = Pattern.compile("(.+) <- (?:.+)"); + final String HYPIXEL_SERVER_BRAND = "BungeeCord (Hypixel)"; - ScheduledExecutorService ses = Executors.newScheduledThreadPool(1); + Minecraft mc = Minecraft.getMinecraft(); - /** - * Sends a kbd event to NEUOverlay, cancelling if NEUOverlay#keyboardInput returns true. - * Also includes a dev function used for creating custom named json files with recipes. - */ - @SubscribeEvent - public void onGuiScreenKeyboard(GuiScreenEvent.KeyboardInputEvent.Pre event) { - if(event.gui instanceof CustomAHGui || manager.auctionManager.customAH.isRenderOverAuctionView()) { - if(manager.auctionManager.customAH.keyboardInput()) { - event.setCanceled(true); - Minecraft.getMinecraft().dispatchKeypresses(); - } else if(overlay.keyboardInput(focusInv)) { - event.setCanceled(true); - } - return; - } + if (mc != null && mc.theWorld != null && mc.thePlayer != null) { + if (!mc.isSingleplayer() && mc.thePlayer.getClientBrand() != null) { + Matcher matcher = SERVER_BRAND_PATTERN.matcher(mc.thePlayer.getClientBrand()); - if(event.gui instanceof GuiContainer && isOnSkyblock()) { - if(overlay.keyboardInput(focusInv)) { - event.setCanceled(true); - } - } - if(manager.config.dev.value && manager.config.enableItemEditing.value && Minecraft.getMinecraft().theWorld != null && - Keyboard.getEventKey() == Keyboard.KEY_O && Keyboard.getEventKeyState()) { - GuiScreen gui = Minecraft.getMinecraft().currentScreen; - if(gui instanceof GuiChest) { - GuiChest eventGui = (GuiChest) event.gui; - ContainerChest cc = (ContainerChest) eventGui.inventorySlots; - IInventory lower = cc.getLowerChestInventory(); - - if(lower.getStackInSlot(23) != null && - lower.getStackInSlot(23).getDisplayName().endsWith("Crafting Table")) { - ItemStack res = lower.getStackInSlot(25); - String resInternalname = manager.getInternalNameForItem(res); - JTextField tf = new JTextField(); - tf.setText(resInternalname); - tf.addAncestorListener(new RequestFocusListener()); - JOptionPane.showOptionDialog(null, - tf, - "Enter Name:", - JOptionPane.NO_OPTION, - JOptionPane.PLAIN_MESSAGE, - null, new String[]{"Enter"}, "Enter"); - resInternalname = tf.getText(); - if(resInternalname.trim().length() == 0) { + if (matcher.find()) { + // Group 1 is the server brand. + if(!matcher.group(1).equals(HYPIXEL_SERVER_BRAND)) { + hasSkyblockScoreboard = false; return; } - - JsonObject recipe = new JsonObject(); - - String[] x = {"1","2","3"}; - String[] y = {"A","B","C"}; - - for(int i=0; i<=18; i+=9) { - for(int j=0; j<3; j++) { - ItemStack stack = lower.getStackInSlot(10+i+j); - String internalname = ""; - if(stack != null) { - internalname = manager.getInternalNameForItem(stack); - if(!manager.getItemInformation().containsKey(internalname)) { - manager.writeItemToFile(stack); - } - internalname += ":"+stack.stackSize; - } - recipe.addProperty(y[i/9]+x[j], internalname); - } - } - - JsonObject json = manager.getJsonForItem(res); - json.add("recipe", recipe); - json.addProperty("internalname", resInternalname); - json.addProperty("clickcommand", "viewrecipe"); - json.addProperty("modver", NotEnoughUpdates.VERSION); - try { - Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Added: " + resInternalname)); - manager.writeJsonDefaultDir(json, resInternalname+".json"); - manager.loadItem(resInternalname); - } catch(IOException e) {} - } - } - } - /*if(Minecraft.getMinecraft().theWorld != null && Keyboard.getEventKey() == Keyboard.KEY_RBRACKET && Keyboard.getEventKeyState()) { - Minecraft.getMinecraft().displayGuiScreen(null); - started = true; - final Object[] items = manager.getItemInformation().values().toArray(); - AtomicInteger i = new AtomicInteger(0); - - Runnable checker = new Runnable() { - @Override - public void run() { - int in = i.getAndIncrement(); - /*if(missingRecipe.get()) { - String internalname = ((JsonObject)items[in]).get("internalname").getAsString(); - - JsonArray arr = null; - File f = new File(manager.configLocation, "missing.json"); - try(InputStream instream = new FileInputStream(f)) { - BufferedReader reader = new BufferedReader(new InputStreamReader(instream, StandardCharsets.UTF_8)); - JsonObject json = manager.gson.fromJson(reader, JsonObject.class); - arr = json.getAsJsonArray("missing"); - } catch(IOException e) {} - - try { - JsonObject json = new JsonObject(); - if(arr == null) arr = new JsonArray(); - arr.add(new JsonPrimitive(internalname)); - json.add("missing", arr); - manager.writeJson(json, f); - } catch(IOException e) {} - } - missingRecipe.set(false); - - ses.schedule(() -> { - int index = i.get(); - JsonObject o = (JsonObject)items[index]; - if(Minecraft.getMinecraft().currentScreen != null) { - Minecraft.getMinecraft().displayGuiScreen(null); - } - Minecraft.getMinecraft().thePlayer.sendChatMessage("/viewrecipe " + o.get("internalname").getAsString()); - - ses.schedule(this, 1000, TimeUnit.MILLISECONDS); - }, 100, TimeUnit.MILLISECONDS); - } - }; - - int index = i.get(); - JsonObject o = (JsonObject)items[index]; - if(Minecraft.getMinecraft().currentScreen != null) { - Minecraft.getMinecraft().displayGuiScreen(null); - } - Minecraft.getMinecraft().thePlayer.sendChatMessage("/viewrecipe " + o.get("internalname").getAsString()); - - ses.schedule(checker, 1000, TimeUnit.MILLISECONDS); - }*/ - } - - /** - * This makes it so that holding LCONTROL while hovering over an item with NBT will show the NBT of the item. - * @param event - */ - @SubscribeEvent - public void onItemTooltip(ItemTooltipEvent event) { - if(!isOnSkyblock()) return; - if(manager.config.hideEmptyPanes.value && - event.itemStack.getItem().equals(Item.getItemFromBlock(Blocks.stained_glass_pane))) { - String first = Utils.cleanColour(event.toolTip.get(0)); - first = first.replaceAll("\\(.*\\)", "").trim(); - if(first.length() == 0) { - event.toolTip.clear(); - } - } - //AH prices - /*if(Minecraft.getMinecraft().currentScreen != null) { - if(Minecraft.getMinecraft().currentScreen instanceof GuiChest) { - GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen; - ContainerChest container = (ContainerChest) chest.inventorySlots; - String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText(); - if(containerName.trim().equals("Auctions Browser")) { - String internalname = manager.getInternalNameForItem(event.itemStack); - if(internalname != null) { - for(int i=0; i<event.toolTip.size(); i++) { - String line = event.toolTip.get(i); - if(line.contains(EnumChatFormatting.GRAY + "Bidder: ") || - line.contains(EnumChatFormatting.GRAY + "Starting bid: ") || - line.contains(EnumChatFormatting.GRAY + "Buy it now: ")) { - manager.updatePrices(); - JsonObject auctionInfo = manager.getItemAuctionInfo(internalname); - - if(auctionInfo != null) { - NumberFormat format = NumberFormat.getInstance(Locale.US); - int auctionPrice = (int)(auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat()); - float costOfEnchants = manager.getCostOfEnchants(internalname, - event.itemStack.getTagCompound()); - int priceWithEnchants = auctionPrice+(int)costOfEnchants; - - event.toolTip.add(++i, EnumChatFormatting.GRAY + "Average price: " + - EnumChatFormatting.GOLD + format.format(auctionPrice) + " coins"); - if(costOfEnchants > 0) { - event.toolTip.add(++i, EnumChatFormatting.GRAY + "Average price (w/ enchants): " + - EnumChatFormatting.GOLD + - format.format(priceWithEnchants) + " coins"); - } - - if(manager.config.advancedPriceInfo.value) { - int salesVolume = (int) auctionInfo.get("sales").getAsFloat(); - int flipPrice = (int)(0.93*priceWithEnchants); - - event.toolTip.add(++i, EnumChatFormatting.GRAY + "Flip Price (93%): " + - EnumChatFormatting.GOLD + format.format(flipPrice) + " coins"); - event.toolTip.add(++i, EnumChatFormatting.GRAY + "Volume: " + - EnumChatFormatting.GOLD + format.format(salesVolume) + " sales/day"); - } - break; - } - } - } - } - } - } - }*/ - if(!Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || !manager.config.dev.value) return; - if(event.toolTip.size()>0&&event.toolTip.get(event.toolTip.size()-1).startsWith(EnumChatFormatting.DARK_GRAY + "NBT: ")) { - event.toolTip.remove(event.toolTip.size()-1); - - StringBuilder sb = new StringBuilder(); - String nbt = event.itemStack.getTagCompound().toString(); - int indent = 0; - for(char c : nbt.toCharArray()) { - boolean newline = false; - if(c == '{' || c == '[') { - indent++; - newline = true; - } else if(c == '}' || c == ']') { - indent--; - sb.append("\n"); - for(int i=0; i<indent; i++) sb.append(" "); - } else if(c == ',') { - newline = true; - } else if(c == '\"') { - sb.append(EnumChatFormatting.RESET.toString() + EnumChatFormatting.GRAY); + } else { + hasSkyblockScoreboard = false; + return; } - - sb.append(c); - if(newline) { - sb.append("\n"); - for(int i=0; i<indent; i++) sb.append(" "); - } - } - event.toolTip.add(sb.toString()); - if(Keyboard.isKeyDown(Keyboard.KEY_H)) { - StringSelection selection = new StringSelection(sb.toString()); - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection); + } else { + hasSkyblockScoreboard = false; + return; } - } - } - - //Stolen from Biscut's SkyblockAddons - public boolean isOnSkyblock() { - if(!manager.config.onlyShowOnSkyblock.value) return true; - return hasSkyblockScoreboard(); - } - public boolean hasSkyblockScoreboard() { - Minecraft mc = Minecraft.getMinecraft(); - - if (mc != null && mc.theWorld != null) { Scoreboard scoreboard = mc.theWorld.getScoreboard(); ScoreObjective sidebarObjective = scoreboard.getObjectiveInDisplaySlot(1); if (sidebarObjective != null) { String objectiveName = sidebarObjective.getDisplayName().replaceAll("(?i)\\u00A7.", ""); for (String skyblock : SKYBLOCK_IN_ALL_LANGUAGES) { if (objectiveName.startsWith(skyblock)) { - return true; + hasSkyblockScoreboard = true; + return; } } } } - return false; + hasSkyblockScoreboard = false; } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/SBAIntegration.java b/src/main/java/io/github/moulberry/notenoughupdates/SBAIntegration.java new file mode 100644 index 00000000..d9e9217a --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/SBAIntegration.java @@ -0,0 +1,211 @@ +package io.github.moulberry.notenoughupdates; + +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.settings.KeyBinding; +import net.minecraft.item.ItemStack; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; + +public class SBAIntegration { + + private static boolean hasSBA = true; + private static Class<?> skyblockAddonsClass = null; + private static Method skyblockAddons_getInstance = null; + private static Method skyblockAddons_getUtils = null; + private static Class<?> backpackManagerClass = null; + private static Method backpackManager_getFromItem = null; + private static Class<?> backpackClass = null; + private static Method backpackClass_setX= null; + private static Method backpackClass_setY = null; + private static Class<?> utilsClass = null; + private static Method utils_setBackpackToPreview = null; + public static boolean setActiveBackpack(ItemStack stack, int mouseX, int mouseY) { + if(!hasSBA) return false; + try { + if(skyblockAddonsClass == null) { + skyblockAddonsClass = Class.forName("codes.biscuit.skyblockaddons.SkyblockAddons"); + } + if(skyblockAddons_getInstance == null) { + skyblockAddons_getInstance = skyblockAddonsClass.getDeclaredMethod("getInstance"); + } + if(skyblockAddons_getUtils == null) { + skyblockAddons_getUtils = skyblockAddonsClass.getDeclaredMethod("getUtils"); + } + if(backpackManagerClass == null) { + backpackManagerClass = Class.forName("codes.biscuit.skyblockaddons.features.backpacks.BackpackManager"); + } + if(backpackManager_getFromItem == null) { + backpackManager_getFromItem = backpackManagerClass.getDeclaredMethod("getFromItem", ItemStack.class); + } + if(backpackClass == null) { + backpackClass = Class.forName("codes.biscuit.skyblockaddons.features.backpacks.Backpack"); + } + if(backpackClass_setX == null) { + backpackClass_setX = backpackClass.getDeclaredMethod("setX", int.class); + } + if(backpackClass_setY == null) { + backpackClass_setY = backpackClass.getDeclaredMethod("setY", int.class); + } + if(utilsClass == null) { + utilsClass = Class.forName("codes.biscuit.skyblockaddons.utils.Utils"); + } + if(utils_setBackpackToPreview == null) { + utils_setBackpackToPreview = utilsClass.getDeclaredMethod("setBackpackToPreview", backpackClass); + } + } catch(Exception e) { + e.printStackTrace(); + hasSBA = false; + return false; + } + try { + Object skyblockAddons = skyblockAddons_getInstance.invoke(null); + Object utils = skyblockAddons_getUtils.invoke(skyblockAddons); + if(stack == null) { + utils_setBackpackToPreview.invoke(utils, (Object) null); + } else { + Object backpack = backpackManager_getFromItem.invoke(null, stack); + backpackClass_setX.invoke(backpack, mouseX); + backpackClass_setY.invoke(backpack, mouseY); + utils_setBackpackToPreview.invoke(utils, backpack); + } + } catch(Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + private static Field guiContainerHook_freezeBackpack = null; + public static boolean isFreezeBackpack() { + if(!hasSBA) return false; + try { + if(guiContainerHookClass == null) { + guiContainerHookClass = Class.forName("codes.biscuit.skyblockaddons.asm.hooks.GuiContainerHook"); + } + if(guiContainerHook_freezeBackpack == null) { + guiContainerHook_freezeBackpack = guiContainerHookClass.getDeclaredField("freezeBackpack"); + guiContainerHook_freezeBackpack.setAccessible(true); + } + } catch(Exception e) { + e.printStackTrace(); + hasSBA = false; + return false; + } + try { + return (boolean) guiContainerHook_freezeBackpack.get(null); + } catch(Exception e) { + e.printStackTrace(); + return false; + } + } + + public static boolean setFreezeBackpack(boolean freezeBackpack) { + if(!hasSBA) return false; + try { + if(guiContainerHookClass == null) { + guiContainerHookClass = Class.forName("codes.biscuit.skyblockaddons.asm.hooks.GuiContainerHook"); + } + if(guiContainerHook_freezeBackpack == null) { + guiContainerHook_freezeBackpack = guiContainerHookClass.getDeclaredField("freezeBackpack"); + guiContainerHook_freezeBackpack.setAccessible(true); + } + } catch(Exception e) { + e.printStackTrace(); + hasSBA = false; + return false; + } + try { + guiContainerHook_freezeBackpack.set(null, freezeBackpack); + return true; + } catch(Exception e) { + e.printStackTrace(); + return false; + } + } + + private static Method guiContainerHook_keyTyped = null; + private static Method skyblockAddons_getFreezeBackpackKey = null; + public static boolean keyTyped(int keyCode) { + if(!hasSBA) return false; + try { + if(skyblockAddonsClass == null) { + skyblockAddonsClass = Class.forName("codes.biscuit.skyblockaddons.SkyblockAddons"); + } + if(skyblockAddons_getInstance == null) { + skyblockAddons_getInstance = skyblockAddonsClass.getDeclaredMethod("getInstance"); + } + if(skyblockAddons_getFreezeBackpackKey == null) { + skyblockAddons_getFreezeBackpackKey = skyblockAddonsClass.getDeclaredMethod("getFreezeBackpackKey"); + } + if(guiContainerHookClass == null) { + guiContainerHookClass = Class.forName("codes.biscuit.skyblockaddons.asm.hooks.GuiContainerHook"); + } + if(guiContainerHook_keyTyped == null) { + guiContainerHook_keyTyped = guiContainerHookClass.getDeclaredMethod("keyTyped", int.class); + } + } catch(Exception e) { + e.printStackTrace(); + hasSBA = false; + return false; + } + try { + Object skyblockAddons = skyblockAddons_getInstance.invoke(null); + if(!isFreezeBackpack() && ((KeyBinding)skyblockAddons_getFreezeBackpackKey.invoke(skyblockAddons)).getKeyCode() == keyCode) { + setFreezeBackpack(true); + } else { + guiContainerHook_keyTyped.invoke(null, keyCode); + } + } catch(Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + private static Class<?> guiContainerHookClass = null; + private static Method guiContainerHook_drawBackpacks = null; + public static boolean renderActiveBackpack(int mouseX, int mouseY, FontRenderer fontRendererObj) { + if(!hasSBA) return false; + try { + if(guiContainerHookClass == null) { + guiContainerHookClass = Class.forName("codes.biscuit.skyblockaddons.asm.hooks.GuiContainerHook"); + } + if(guiContainerHook_drawBackpacks == null) { + guiContainerHook_drawBackpacks = guiContainerHookClass.getDeclaredMethod("drawBackpacks", + GuiContainer.class, int.class, int.class, FontRenderer.class); + } + } catch(Exception e) { + e.printStackTrace(); + hasSBA = false; + return false; + } + try { + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + int width = scaledResolution.getScaledWidth(); + int height = scaledResolution.getScaledHeight(); + + if(Minecraft.getMinecraft().currentScreen instanceof GuiContainer) { + guiContainerHook_drawBackpacks.invoke(null, Minecraft.getMinecraft().currentScreen, mouseX, mouseY, fontRendererObj); + } else { + GuiContainer container = new GuiContainer(null) { + protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { + } + }; + container.setWorldAndResolution(Minecraft.getMinecraft(), width, height); + + guiContainerHook_drawBackpacks.invoke(null, container, mouseX, mouseY, fontRendererObj); + } + } catch(Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/TradeWindow.java b/src/main/java/io/github/moulberry/notenoughupdates/TradeWindow.java new file mode 100644 index 00000000..6bdf2c5d --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/TradeWindow.java @@ -0,0 +1,1042 @@ +package io.github.moulberry.notenoughupdates; + +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.util.TexLoc; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.gui.inventory.GuiEditSign; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.inventory.Slot; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.tileentity.TileEntitySign; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.awt.*; +import java.io.ByteArrayInputStream; +import java.text.NumberFormat; +import java.util.*; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TradeWindow { + + private static ResourceLocation location = new ResourceLocation("notenoughupdates", "custom_trade.png"); + + private static final int xSize = 176; + private static final int ySize = 204; + private static int guiLeft; + private static int guiTop; + + private static long lastTradeMillis = -1; + + private static final long CHANGE_EXCLAM_MILLIS = 5000; + + private static Integer[] ourTradeIndexes = new Integer[16]; + private static Integer[] theirTradeIndexes = new Integer[16]; + private static String[] theirTradeOld = new String[16]; + private static Long[] theirTradeChangesMillis = new Long[16]; + + private static ItemStack lastBackpack; + private static int lastBackpackX; + private static int lastBackpackY; + + public static boolean tradeWindowActive() { + if(!NotEnoughUpdates.INSTANCE.isOnSkyblock()) return false; + if(!NotEnoughUpdates.INSTANCE.manager.config.useCustomTrade.value) return false; + + GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen; + if(guiScreen instanceof GuiChest) { + GuiChest eventGui = (GuiChest) guiScreen; + ContainerChest cc = (ContainerChest) eventGui.inventorySlots; + String containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText(); + if(containerName.trim().startsWith("You ")) { + return true; + } + } + + lastTradeMillis = -1; + ourTradeIndexes = new Integer[16]; + theirTradeIndexes = new Integer[16]; + theirTradeOld = new String[16]; + theirTradeChangesMillis = new Long[16]; + + return false; + } + + private static TexLoc tl = new TexLoc(0, 0, Keyboard.KEY_M); + + private static void drawStringShadow(String str, float x, float y, int len) { + for(int xOff=-2; xOff<=2; xOff++) { + for(int yOff=-2; yOff<=2; yOff++) { + if(Math.abs(xOff) != Math.abs(yOff)) { + Utils.drawStringCenteredScaledMaxWidth(Utils.cleanColourNotModifiers(str), + Minecraft.getMinecraft().fontRendererObj, + x+xOff/2f, y+yOff/2f, false, len, + new Color(20, 20, 20, 100/Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB()); + } + } + } + + Utils.drawStringCenteredScaledMaxWidth(str, + Minecraft.getMinecraft().fontRendererObj, + x, y, false, len, + new Color(64, 64, 64, 255).getRGB()); + } + + private static int processTopItems(ItemStack stack, Map<Integer, Set<String>> topItems, + Map<String, ItemStack> topItemsStack, Map<String, Integer> topItemsCount) { + String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack); + if(internalname == null) { + if(stack.getDisplayName().endsWith(" coins")) { + String clean = Utils.cleanColour(stack.getDisplayName()); + + int mult = 1; + StringBuilder sb = new StringBuilder(); + for(int index = 0; index < clean.length(); index++) { + char c = clean.charAt(index); + if("0123456789.".indexOf(c) >= 0) { + sb.append(c); + } else { + switch(c) { + case 'K': + case 'k': + mult = 1000; break; + case 'M': + case 'm': + mult = 1000000; break; + case 'B': + case 'b': + mult = 1000000000; break; + default: + break; + } + break; + } + } + try { + int coins = (int)(Float.parseFloat(sb.toString())*mult); + + topItemsStack.putIfAbsent("TRADE_COINS", stack); + + int existingPrice = coins; + Set<Integer> toRemove = new HashSet<>(); + for(Map.Entry<Integer, Set<String>> entry : topItems.entrySet()) { + if(entry.getValue().contains("TRADE_COINS")) { + entry.getValue().remove("TRADE_COINS"); + existingPrice += entry.getKey(); + } + if(entry.getValue().isEmpty()) toRemove.add(entry.getKey()); + } + topItems.keySet().removeAll(toRemove); + + Set<String> items = topItems.computeIfAbsent(existingPrice, k->new HashSet<>()); + items.add("TRADE_COINS"); + + return coins; + + } catch(Exception ignored) {} + } + } else { + JsonObject info = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAuctionInfo(internalname); + int pricePer = -1; + if(info != null && !NotEnoughUpdates.INSTANCE.manager.auctionManager.isVanillaItem(internalname) && + info.has("price") && info.has("count")) { + int auctionPricePer = (int)(info.get("price").getAsFloat() / info.get("count").getAsFloat()); + + pricePer = auctionPricePer; + } else { + JsonObject bazaarInfo = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo(internalname); + if(bazaarInfo != null && bazaarInfo.has("avg_buy")) { + pricePer = (int)bazaarInfo.get("avg_buy").getAsFloat(); + } + } + if(pricePer > 0) { + topItemsStack.putIfAbsent(internalname, stack); + + int price = pricePer * stack.stackSize; + int priceInclBackpack = price; + + NBTTagCompound tag = stack.getTagCompound(); + if(tag != null && tag.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + + byte[] bytes = null; + for (String key : ea.getKeySet()) { + if (key.endsWith("backpack_data") || key.equals("new_year_cake_bag_data")) { + bytes = ea.getByteArray(key); + break; + } + } + if(bytes != null) { + try { + NBTTagCompound contents_nbt = CompressedStreamTools.readCompressed(new ByteArrayInputStream(bytes)); + NBTTagList items = contents_nbt.getTagList("i", 10); + for(int k=0; k<items.tagCount(); k++) { + if(items.getCompoundTagAt(k).getKeySet().size() > 0) { + NBTTagCompound nbt = items.getCompoundTagAt(k).getCompoundTag("tag"); + + int id2 = items.getCompoundTagAt(k).getShort("id"); + int count2 = items.getCompoundTagAt(k).getByte("Count"); + int damage2 = items.getCompoundTagAt(k).getShort("Damage"); + + if(id2 == 141) id2 = 391; //for some reason hypixel thinks carrots have id 141 + + Item mcItem = Item.getItemById(id2); + if(mcItem == null) continue; + + ItemStack stack2 = new ItemStack(mcItem, count2, damage2); + stack2.setTagCompound(nbt); + + priceInclBackpack += processTopItems(stack2, topItems, topItemsStack, topItemsCount); + } + } + } catch(Exception e) { } + } + } + + int existingPrice = price; + Set<Integer> toRemove = new HashSet<>(); + for(Map.Entry<Integer, Set<String>> entry : topItems.entrySet()) { + if(entry.getValue().contains(internalname)) { + entry.getValue().remove(internalname); + existingPrice += entry.getKey(); + } + if(entry.getValue().isEmpty()) toRemove.add(entry.getKey()); + } + topItems.keySet().removeAll(toRemove); + + Set<String> items = topItems.computeIfAbsent(existingPrice, k->new HashSet<>()); + items.add(internalname); + + int count = topItemsCount.computeIfAbsent(internalname, l->0); + topItemsCount.put(internalname, count+stack.stackSize); + + return priceInclBackpack; + } + } + return 0; + } + + private static int getBackpackValue(ItemStack stack) { + int price = 0; + + NBTTagCompound tag = stack.getTagCompound(); + if(tag != null && tag.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + + byte[] bytes = null; + for (String key : ea.getKeySet()) { + if (key.endsWith("backpack_data") || key.equals("new_year_cake_bag_data")) { + bytes = ea.getByteArray(key); + break; + } + } + if(bytes != null) { + try { + NBTTagCompound contents_nbt = CompressedStreamTools.readCompressed(new ByteArrayInputStream(bytes)); + NBTTagList items = contents_nbt.getTagList("i", 10); + for(int k=0; k<items.tagCount(); k++) { + if(items.getCompoundTagAt(k).getKeySet().size() > 0) { + NBTTagCompound nbt = items.getCompoundTagAt(k).getCompoundTag("tag"); + String internalname2 = NotEnoughUpdates.INSTANCE.manager.getInternalnameFromNBT(nbt); + if(internalname2 != null) { + JsonObject info2 = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAuctionInfo(internalname2); + + int pricePer2 = -1; + if(info2 != null && info2.has("price") && info2.has("count")) { + int auctionPricePer2 = (int)(info2.get("price").getAsFloat() / info2.get("count").getAsFloat()); + + pricePer2 = auctionPricePer2; + } else { + JsonObject bazaarInfo2 = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo(internalname2); + if(bazaarInfo2 != null && bazaarInfo2.has("avg_buy")) { + pricePer2 = (int)bazaarInfo2.get("avg_buy").getAsFloat(); + } + } + if(pricePer2 > 0) { + int count2 = items.getCompoundTagAt(k).getByte("Count"); + price += pricePer2 * count2; + } + } + } + } + } catch(Exception e) { } + } + } + return price; + } + + public static void render(int mouseX, int mouseY) { + if(!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return; + + GuiContainer chest = ((GuiContainer)Minecraft.getMinecraft().currentScreen); + ContainerChest cc = (ContainerChest) chest.inventorySlots; + String containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText(); + + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + + guiLeft = (scaledResolution.getScaledWidth()-xSize)/2; + guiTop = (scaledResolution.getScaledHeight()-ySize)/2; + + List<String> tooltipToDisplay = null; + ItemStack stackToRender = null; + int tooltipLen = -1; + tl.handleKeyboardInput(); + + //Set index mappings + //Our slots + TreeMap<Integer, List<Integer>> ourTradeMap = new TreeMap<>(); + for(int i=0; i<16; i++) { + ourTradeIndexes[i] = -1; + + int x = i % 4; + int y = i / 4; + int containerIndex = y*9+x; + + ItemStack stack = chest.inventorySlots.getInventory().get(containerIndex); + if(stack == null) continue; + + String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack); + if(internalname == null) { + if(stack.getDisplayName().endsWith(" coins")) { + String clean = Utils.cleanColour(stack.getDisplayName()); + + int mult = 1; + StringBuilder sb = new StringBuilder(); + for(int index = 0; index < clean.length(); index++) { + char c = clean.charAt(index); + if("0123456789.".indexOf(c) >= 0) { + sb.append(c); + } else { + switch(c) { + case 'K': + case 'k': + mult = 1000; break; + case 'M': + case 'm': + mult = 1000000; break; + case 'B': + case 'b': + mult = 1000000000; break; + default: + break; + } + break; + } + } + try { + int coins = (int)(Float.parseFloat(sb.toString())*mult); + + List<Integer> list = ourTradeMap.computeIfAbsent(coins, k -> new ArrayList<>()); + list.add(containerIndex); + + } catch(Exception ignored) { + List<Integer> list = ourTradeMap.computeIfAbsent(-1, k -> new ArrayList<>()); + list.add(containerIndex); + } + } else { + List<Integer> list = ourTradeMap.computeIfAbsent(-1, k -> new ArrayList<>()); + list.add(containerIndex); + } + } else { + JsonObject info = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAuctionInfo(internalname); + int price = -1; + if(info != null && info.has("price") && info.has("count")) { + int auctionPricePer = (int)(info.get("price").getAsFloat() / info.get("count").getAsFloat()); + + price = auctionPricePer * stack.stackSize; + } else { + JsonObject bazaarInfo = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo(internalname); + if(bazaarInfo != null && bazaarInfo.has("avg_buy")) { + price = (int)bazaarInfo.get("avg_buy").getAsFloat() * stack.stackSize; + } + } + + price += getBackpackValue(stack); + + List<Integer> list = ourTradeMap.computeIfAbsent(price, k -> new ArrayList<>()); + list.add(containerIndex); + } + } + long currentTime = System.currentTimeMillis(); + List<String> theirTradeCurrent = new ArrayList<>(); + TreeMap<Integer, List<Integer>> theirTradeMap = new TreeMap<>(); + HashMap<String, Integer> displayCountMap = new HashMap<>(); + for(int i=0; i<16; i++) { + theirTradeIndexes[i] = -1; + if(theirTradeChangesMillis[i] == null || currentTime - theirTradeChangesMillis[i] > CHANGE_EXCLAM_MILLIS) { + theirTradeChangesMillis[i] = -1L; + } + + int x = i % 4; + int y = i / 4; + int containerIndex = y*9+x+5; + + ItemStack stack = chest.inventorySlots.getInventory().get(containerIndex); + if(stack == null) continue; + + NBTTagCompound tag = stack.getTagCompound(); + String uuid = null; + if(tag != null && tag.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + + if (ea.hasKey("uuid", 8)) { + uuid = ea.getString("uuid"); + } else { + int displayCount = displayCountMap.computeIfAbsent(stack.getDisplayName(), k->0); + uuid = stack.getDisplayName() + ":" + displayCount; + displayCountMap.put(stack.getDisplayName(), displayCount+1); + } + } else { + int displayCount = displayCountMap.computeIfAbsent(stack.getDisplayName(), k->0); + uuid = stack.getDisplayName() + ":" + displayCount; + displayCountMap.put(stack.getDisplayName(), displayCount+1); + } + if(uuid != null) theirTradeCurrent.add(uuid); + + String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack); + if(internalname == null) { + if(stack.getDisplayName().endsWith(" coins")) { + String clean = Utils.cleanColour(stack.getDisplayName()); + + int mult = 1; + StringBuilder sb = new StringBuilder(); + for(int index = 0; index < clean.length(); index++) { + char c = clean.charAt(index); + if("0123456789.".indexOf(c) >= 0) { + sb.append(c); + } else { + switch(c) { + case 'K': + case 'k': + mult = 1000; break; + case 'M': + case 'm': + mult = 1000000; break; + case 'B': + case 'b': + mult = 1000000000; break; + default: + break; + } + break; + } + } + try { + int coins = (int)(Float.parseFloat(sb.toString())*mult); + + List<Integer> list = theirTradeMap.computeIfAbsent(coins, k -> new ArrayList<>()); + list.add(containerIndex); + + } catch(Exception ignored) { + List<Integer> list = theirTradeMap.computeIfAbsent(-1, k -> new ArrayList<>()); + list.add(containerIndex); + } + } else { + List<Integer> list = theirTradeMap.computeIfAbsent(-1, k -> new ArrayList<>()); + list.add(containerIndex); + } + } else { + JsonObject info = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAuctionInfo(internalname); + int price = -1; + if(info != null && info.has("price") && info.has("count")) { + int auctionPricePer = (int)(info.get("price").getAsFloat() / info.get("count").getAsFloat()); + + price = auctionPricePer * stack.stackSize; + } else { + JsonObject bazaarInfo = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo(internalname); + if(bazaarInfo != null && bazaarInfo.has("avg_buy")) { + price = (int)bazaarInfo.get("avg_buy").getAsFloat() * stack.stackSize; + } + } + + price += getBackpackValue(stack); + + List<Integer> list = theirTradeMap.computeIfAbsent(price, k -> new ArrayList<>()); + list.add(containerIndex); + } + } + int ourTradeIndex = 0; + for(Map.Entry<Integer, List<Integer>> entry : ourTradeMap.descendingMap().entrySet()) { + for(Integer index : entry.getValue()) { + ourTradeIndexes[ourTradeIndex++] = index; + } + } + + //Their slots + int maxMissing = 16-theirTradeCurrent.size(); + int j=0; + for(int i=0; i<16; i++) { + while(j <= 15 && (j-i<maxMissing) && theirTradeChangesMillis[j] >= 0) j++; + j = Math.min(15, j); + + String oldUUID = theirTradeOld[i]; + if(oldUUID != null && !theirTradeCurrent.contains(oldUUID)) { + theirTradeChangesMillis[j] = System.currentTimeMillis(); + } + j++; + } + + for(int i=0; i<16; i++) { + theirTradeOld[i] = null; + } + int theirTradeIndex = 0; + displayCountMap.clear(); + j=0; + for(Map.Entry<Integer, List<Integer>> entry : theirTradeMap.descendingMap().entrySet()) { + for(Integer index : entry.getValue()) { + while(j <= 15 && (j-theirTradeIndex<maxMissing) && theirTradeChangesMillis[j] >= 0) j++; + j = Math.min(15, j); + + theirTradeIndexes[j] = index; + + ItemStack stack = chest.inventorySlots.getInventory().get(index); + if(stack == null) continue; + + NBTTagCompound tag = stack.getTagCompound(); + String uuid = null; + if(tag != null && tag.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + + if (ea.hasKey("uuid", 8)) { + uuid = ea.getString("uuid"); + } else { + int displayCount = displayCountMap.computeIfAbsent(stack.getDisplayName(), k->0); + uuid = stack.getDisplayName() + ":" + displayCount; + displayCountMap.put(stack.getDisplayName(), displayCount+1); + } + } else { + int displayCount = displayCountMap.computeIfAbsent(stack.getDisplayName(), k->0); + uuid = stack.getDisplayName() + ":" + displayCount; + displayCountMap.put(stack.getDisplayName(), displayCount+1); + } + //System.out.println(uuid); + theirTradeOld[theirTradeIndex] = uuid; + + j++; + theirTradeIndex++; + } + } + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(location); + Utils.drawTexturedRect(guiLeft, guiTop, xSize, ySize, 0, 176/256f, 0, 204/256f, GL11.GL_NEAREST); + + Utils.drawStringF(new ChatComponentTranslation("container.inventory").getUnformattedText(), + Minecraft.getMinecraft().fontRendererObj, guiLeft+8, guiTop+111, false, 4210752); + Utils.drawStringF("You", Minecraft.getMinecraft().fontRendererObj, guiLeft+8, + guiTop+5, false, 4210752); + String[] split = containerName.split(" "); + if(split.length >= 1) { + Utils.drawStringF(split[split.length-1], Minecraft.getMinecraft().fontRendererObj, + guiLeft+167-Minecraft.getMinecraft().fontRendererObj.getStringWidth(split[split.length-1]), + guiTop+5, false, 4210752); + } + + int index=0; + for(ItemStack stack : Minecraft.getMinecraft().thePlayer.inventory.mainInventory) { + int x = 8+18*(index % 9); + int y = 104+18*(index / 9); + if(index < 9) y = 180; + + Utils.drawItemStack(stack, guiLeft+x, guiTop+y); + + if(mouseX > guiLeft+x-1 && mouseX < guiLeft+x+18) { + if(mouseY > guiTop+y-1 && mouseY < guiTop+y+18) { + if(stack != null) stackToRender = stack; + + GlStateManager.disableLighting(); + GlStateManager.disableDepth(); + GlStateManager.colorMask(true, true, true, false); + Utils.drawGradientRect(guiLeft+x, guiTop+y, + guiLeft+x + 16, guiTop+y + 16, -2130706433, -2130706433); + GlStateManager.colorMask(true, true, true, true); + GlStateManager.enableLighting(); + GlStateManager.enableDepth(); + } + } + + index++; + } + + for(int i=0; i<16; i++) { + int x = i % 4; + int y = i / 4; + + int containerIndex = ourTradeIndexes[i]; + + ItemStack stack = null; + if(containerIndex >= 0) { + stack = chest.inventorySlots.getInventory().get(containerIndex); + Utils.drawItemStack(stack, guiLeft+10+x*18, guiTop+15+y*18); + } + + if(mouseX > guiLeft+10+x*18-1 && mouseX < guiLeft+10+x*18+18) { + if(mouseY > guiTop+15+y*18-1 && mouseY < guiTop+15+y*18+18) { + if(stack != null) stackToRender = stack; + + GlStateManager.disableLighting(); + GlStateManager.disableDepth(); + GlStateManager.colorMask(true, true, true, false); + Utils.drawGradientRect(guiLeft+10+x*18, guiTop+15+y*18, + guiLeft+10+x*18 + 16, guiTop+15+y*18 + 16, -2130706433, -2130706433); + GlStateManager.colorMask(true, true, true, true); + GlStateManager.enableLighting(); + GlStateManager.enableDepth(); + } + } + } + + ItemStack bidStack = chest.inventorySlots.getInventory().get(36); + if(bidStack != null) { + Utils.drawItemStack(bidStack, guiLeft+10, guiTop+90); + if(mouseX > guiLeft+10-1 && mouseX < guiLeft+10+18) { + if(mouseY > guiTop+90-1 && mouseY < guiTop+90+18) { + tooltipToDisplay = bidStack.getTooltip(Minecraft.getMinecraft().thePlayer, + Minecraft.getMinecraft().gameSettings.advancedItemTooltips); + } + } + } + + ItemStack confirmStack = chest.inventorySlots.getInventory().get(39); + if(confirmStack != null) { + String confirmDisplay = confirmStack.getDisplayName(); + if(!confirmDisplay.equals(EnumChatFormatting.GREEN+"Trading!")) { + if(mouseX > guiLeft+81-51 && mouseX < guiLeft+81) { + if (mouseY > guiTop+91 && mouseY < guiTop+91+14) { + tooltipToDisplay = confirmStack.getTooltip(Minecraft.getMinecraft().thePlayer, + Minecraft.getMinecraft().gameSettings.advancedItemTooltips); + } + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(location); + Utils.drawTexturedRect(guiLeft+81-51, guiTop+91, 51, 14, + 0, 51/256f, ySize/256f, (ySize+14)/256f, GL11.GL_NEAREST); + + Pattern pattern = Pattern.compile(EnumChatFormatting.GRAY+"\\("+EnumChatFormatting.YELLOW+"([0-9]+)"+EnumChatFormatting.GRAY+"\\)"); + Matcher matcher = pattern.matcher(confirmDisplay); + + if(!confirmDisplay.equals(EnumChatFormatting.YELLOW+"Warning!") && + !confirmDisplay.equals(EnumChatFormatting.YELLOW+"Deal!")) { + lastTradeMillis = -1; + } + + if(matcher.find()) { + String numS = matcher.group(1); + int num = Integer.parseInt(numS); + + Utils.drawStringCentered(EnumChatFormatting.DARK_RED + "Check " + EnumChatFormatting.BOLD + (char) (9311 + num), Minecraft.getMinecraft().fontRendererObj, guiLeft + 56, guiTop + 99, + false, 4210752); + } else if(confirmDisplay.equals(EnumChatFormatting.AQUA+"Gift!")) { + Utils.drawStringCentered(EnumChatFormatting.GREEN+"Accept", Minecraft.getMinecraft().fontRendererObj, guiLeft+56, guiTop+99, + true, 4210752); + } else if(confirmDisplay.equals(EnumChatFormatting.GREEN+"Deal accepted!")) { + Utils.drawStringCentered(EnumChatFormatting.GREEN+"Accepted", Minecraft.getMinecraft().fontRendererObj, + guiLeft+56, guiTop+99, true, 4210752); + } else if(lastTradeMillis > 0) { + long delta = System.currentTimeMillis() - lastTradeMillis; + if(delta > 2000) { + Utils.drawStringCentered(EnumChatFormatting.GREEN+"Accept", Minecraft.getMinecraft().fontRendererObj, guiLeft+56, guiTop+99, + true, 4210752); + } else { + Utils.drawStringCentered(EnumChatFormatting.YELLOW+"Trade "+EnumChatFormatting.BOLD+(char)(9312+(2000-delta)/1000), + Minecraft.getMinecraft().fontRendererObj, guiLeft+56, guiTop+99, + true, 4210752); + } + } else { + Utils.drawStringCentered(EnumChatFormatting.YELLOW+"Trade "+EnumChatFormatting.BOLD+(char)(9314), Minecraft.getMinecraft().fontRendererObj, guiLeft+56, guiTop+99, + true, 4210752); + } + } + } + + ItemStack theirConfirmStack = chest.inventorySlots.getInventory().get(41); + if(theirConfirmStack != null) { + String confirmDisplay = theirConfirmStack.getDisplayName(); + if(mouseX > guiLeft+95 && mouseX < guiLeft+95+51) { + if (mouseY > guiTop+91 && mouseY < guiTop+91+14) { + tooltipToDisplay = theirConfirmStack.getTooltip(Minecraft.getMinecraft().thePlayer, + Minecraft.getMinecraft().gameSettings.advancedItemTooltips); + } + } + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(location); + Utils.drawTexturedRect(guiLeft+95, guiTop+91, 51, 14, + 0, 51/256f, ySize/256f, (ySize+14)/256f, GL11.GL_NEAREST); + + if(confirmDisplay.equals(EnumChatFormatting.YELLOW+"Pending their confirm")) { + Utils.drawStringCentered(EnumChatFormatting.YELLOW+"Pending", Minecraft.getMinecraft().fontRendererObj, guiLeft+120, guiTop+99, + true, 4210752); + } else if(confirmDisplay.equals(EnumChatFormatting.YELLOW+"Deal timer...")) { + Utils.drawStringCentered(EnumChatFormatting.YELLOW+"Pending", Minecraft.getMinecraft().fontRendererObj, guiLeft+120, guiTop+99, + true, 4210752); + } else if(confirmDisplay.equals(EnumChatFormatting.GREEN+"Other player confirmed!")) { + Utils.drawStringCentered(EnumChatFormatting.GREEN+"Accepted", Minecraft.getMinecraft().fontRendererObj, guiLeft+120, guiTop+99, + true, 4210752); + } + } + + for(int i=0; i<16; i++) { + int x = i % 4; + int y = i / 4; + + int containerIndex = theirTradeIndexes[i]; + + ItemStack stack = null; + if(containerIndex >= 0) { + stack = chest.inventorySlots.getInventory().get(containerIndex); + Utils.drawItemStack(stack, guiLeft+96+x*18, guiTop+15+y*18); + } + + if(currentTime % 400 > 200 && theirTradeChangesMillis[i] != null && theirTradeChangesMillis[i] > 0) { + GlStateManager.translate(0, 0, 200); + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(location); + Utils.drawTexturedRect(guiLeft+96+x*18, guiTop+15+y*18, 16, 16, + 51/256f, 67/256f, 204/256f, 220/256f, GL11.GL_NEAREST); + GlStateManager.translate(0, 0, -200); + } + + if(mouseX > guiLeft+96+x*18-1 && mouseX < guiLeft+96+x*18+18) { + if(mouseY > guiTop+15+y*18-1 && mouseY < guiTop+15+y*18+18) { + if(stack != null) stackToRender = stack; + + GlStateManager.disableLighting(); + GlStateManager.disableDepth(); + GlStateManager.colorMask(true, true, true, false); + Utils.drawGradientRect(guiLeft+96+x*18, guiTop+15+y*18, + guiLeft+96+x*18 + 16, guiTop+15+y*18 + 16, -2130706433, -2130706433); + GlStateManager.colorMask(true, true, true, true); + GlStateManager.enableLighting(); + GlStateManager.enableDepth(); + } + } + } + + if(NotEnoughUpdates.INSTANCE.manager.config.customTradePrices.value) { + TreeMap<Integer, Set<String>> ourTopItems = new TreeMap<>(); + TreeMap<String, ItemStack> ourTopItemsStack = new TreeMap<>(); + TreeMap<String, Integer> ourTopItemsCount = new TreeMap<>(); + int ourPrice = 0; + for(int i=0; i<16; i++) { + int x = i % 4; + int y = i / 4; + int containerIndex = y*9+x; + + ItemStack stack = chest.inventorySlots.getInventory().get(containerIndex); + if(stack == null) continue; + + ourPrice += processTopItems(stack, ourTopItems, ourTopItemsStack, ourTopItemsCount); + } + TreeMap<Integer, Set<String>> theirTopItems = new TreeMap<>(); + TreeMap<String, ItemStack> theirTopItemsStack = new TreeMap<>(); + TreeMap<String, Integer> theirTopItemsCount = new TreeMap<>(); + int theirPrice = 0; + for(int i=0; i<16; i++) { + int x = i % 4; + int y = i / 4; + int containerIndex = y*9+x+5; + + ItemStack stack = chest.inventorySlots.getInventory().get(containerIndex); + if(stack == null) continue; + + theirPrice += processTopItems(stack, theirTopItems, theirTopItemsStack, theirTopItemsCount); + } + + NumberFormat format = NumberFormat.getInstance(Locale.US); + + GlStateManager.disableLighting(); + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(location); + Utils.drawTexturedRect(guiLeft-80-3, guiTop, 80, 106, + 176/256f, 1, 0, 106/256f, GL11.GL_NEAREST); + drawStringShadow(EnumChatFormatting.GOLD.toString()+EnumChatFormatting.BOLD+"Total Value", + guiLeft-40-3, guiTop+11, 72); + drawStringShadow(EnumChatFormatting.GOLD.toString()+EnumChatFormatting.BOLD+format.format(ourPrice), + guiLeft-40-3, guiTop+21, 72); + + int ourTopIndex = Math.max(0, 3-ourTopItemsStack.size()); + out: + for(Map.Entry<Integer, Set<String>> entry : ourTopItems.descendingMap().entrySet()) { + for(String ourTopItemInternal : entry.getValue()) { + ItemStack stack = ourTopItemsStack.get(ourTopItemInternal); + if(stack == null) continue; + + if(NotEnoughUpdates.INSTANCE.manager.config.customTradePriceStyle.value) { + String countS = ""; + if(ourTopItemsCount.containsKey(ourTopItemInternal)) { + int count = ourTopItemsCount.get(ourTopItemInternal); + if(count > 999999) { + countS = Math.floor(count/10000f)/100f+"m"; + } else if(count > 999) { + countS = Math.floor(count/10f)/100f+"k"; + } else { + countS = ""+count; + } + } + + Utils.drawItemStackWithText(stack, guiLeft-75-3, guiTop+49+18*ourTopIndex, countS); + + GlStateManager.disableLighting(); + GlStateManager.disableBlend(); + GlStateManager.color(1, 1, 1, 1); + drawStringShadow(EnumChatFormatting.GOLD.toString()+EnumChatFormatting.BOLD+format.format(entry.getKey()), + guiLeft-29-3, guiTop+57+18*ourTopIndex, 52); + GlStateManager.enableBlend(); + } else { + drawStringShadow(stack.getDisplayName() + EnumChatFormatting.GRAY+"x"+ourTopItemsCount.get(ourTopItemInternal), + guiLeft-40-3, guiTop+46+20*ourTopIndex, 72); + drawStringShadow(EnumChatFormatting.GOLD.toString()+EnumChatFormatting.BOLD+format.format(entry.getKey()), + guiLeft-40-3, guiTop+56+20*ourTopIndex, 72); + } + + if(++ourTopIndex >= 3) break out; + } + } + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(location); + Utils.drawTexturedRect(guiLeft+xSize+3, guiTop, 80, 106, + 176/256f, 1, 0, 106/256f, GL11.GL_NEAREST); + drawStringShadow(EnumChatFormatting.GOLD.toString()+EnumChatFormatting.BOLD+"Total Value", + guiLeft+xSize+3+40, guiTop+11, 72); + drawStringShadow(EnumChatFormatting.GOLD.toString()+EnumChatFormatting.BOLD+format.format(theirPrice), + guiLeft+xSize+3+40, guiTop+21, 72); + + int theirTopIndex = Math.max(0, 3-theirTopItemsStack.size()); + out: + for(Map.Entry<Integer, Set<String>> entry : theirTopItems.descendingMap().entrySet()) { + for(String theirTopItemInternal : entry.getValue()) { + ItemStack stack = theirTopItemsStack.get(theirTopItemInternal); + if(stack == null) continue; + + if(NotEnoughUpdates.INSTANCE.manager.config.customTradePriceStyle.value) { + String countS = ""; + if(theirTopItemsCount.containsKey(theirTopItemInternal)) { + int count = theirTopItemsCount.get(theirTopItemInternal); + if(count > 999999) { + countS = Math.floor(count/10000f)/100f+"m"; + } else if(count > 999) { + countS = Math.floor(count/10f)/100f+"k"; + } else { + countS = ""+count; + } + } + + Utils.drawItemStackWithText(stack, guiLeft+xSize+25+3-16, guiTop+49+18*theirTopIndex, countS); + + GlStateManager.disableLighting(); + GlStateManager.disableBlend(); + GlStateManager.color(1, 1, 1, 1); + drawStringShadow(EnumChatFormatting.GOLD.toString()+EnumChatFormatting.BOLD+format.format(entry.getKey()), + guiLeft+xSize+3+51, guiTop+57+18*theirTopIndex, 52); + GlStateManager.enableBlend(); + } else { + drawStringShadow(stack.getDisplayName(), + guiLeft+xSize+3+40, guiTop+46+20*theirTopIndex, 72); + drawStringShadow(EnumChatFormatting.GOLD.toString()+EnumChatFormatting.BOLD+format.format(entry.getKey()), + guiLeft+xSize+3+40, guiTop+56+20*theirTopIndex, 72); + } + + if(++theirTopIndex >= 3) break out; + } + } + } + + + boolean button1 = NotEnoughUpdates.INSTANCE.manager.config.customTradePriceStyle.value; + boolean button2 = NotEnoughUpdates.INSTANCE.manager.config.customTradePrices.value; + boolean button3 = NotEnoughUpdates.INSTANCE.manager.config.useCustomTrade.value; + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(location); + Utils.drawTexturedRect(guiLeft+xSize+3, guiTop+ySize-19, 17, 17, + (button3?17:0)/256f, (button3?34:17)/256f, 218/256f, 235/256f, GL11.GL_NEAREST); + Utils.drawTexturedRect(guiLeft+xSize+3, guiTop+ySize-38, 17, 17, + (button2?17:0)/256f, (button2?34:17)/256f, 218/256f, 235/256f, GL11.GL_NEAREST); + Utils.drawTexturedRect(guiLeft+xSize+3, guiTop+ySize-57, 17, 17, + (button1?17:0)/256f, (button1?34:17)/256f, 218/256f, 235/256f, GL11.GL_NEAREST); + + if(mouseX >= guiLeft+xSize+3 && mouseX <= guiLeft+xSize+3+17) { + if(mouseY >= guiTop+ySize-19 && mouseY <= guiTop+ySize-19+17) { + tooltipToDisplay = new ArrayList<>(); + tooltipToDisplay.add(EnumChatFormatting.GOLD+NotEnoughUpdates.INSTANCE.manager.config.useCustomTrade.displayName); + tooltipToDisplay.add(EnumChatFormatting.GRAY+NotEnoughUpdates.INSTANCE.manager.config.useCustomTrade.desc); + tooltipLen = 200; + } else if(mouseY >= guiTop+ySize-38 && mouseY <= guiTop+ySize-38+17) { + tooltipToDisplay = new ArrayList<>(); + tooltipToDisplay.add(EnumChatFormatting.GOLD+NotEnoughUpdates.INSTANCE.manager.config.customTradePrices.displayName); + tooltipToDisplay.add(EnumChatFormatting.GRAY+NotEnoughUpdates.INSTANCE.manager.config.customTradePrices.desc); + tooltipLen = 200; + } else if(mouseY >= guiTop+ySize-57 && mouseY <= guiTop+ySize-57+17) { + tooltipToDisplay = new ArrayList<>(); + tooltipToDisplay.add(EnumChatFormatting.GOLD+NotEnoughUpdates.INSTANCE.manager.config.customTradePriceStyle.displayName); + tooltipToDisplay.add(EnumChatFormatting.GRAY+NotEnoughUpdates.INSTANCE.manager.config.customTradePriceStyle.desc); + tooltipLen = 200; + } + } + + if(stackToRender == null && !SBAIntegration.isFreezeBackpack()) lastBackpack = null; + if(SBAIntegration.isFreezeBackpack()) { + if(lastBackpack != null) { + SBAIntegration.setActiveBackpack(lastBackpack, lastBackpackX, lastBackpackY); + GlStateManager.translate(0, 0, 100); + SBAIntegration.renderActiveBackpack(mouseX, mouseY, Minecraft.getMinecraft().fontRendererObj); + GlStateManager.translate(0, 0, -100); + } + } else { + if(stackToRender != null) { + String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stackToRender); + boolean renderedBackpack; + if(internalname != null && (internalname.endsWith("BACKPACK") || internalname.equals("NEW_YEAR_CAKE_BAG"))) { + lastBackpack = stackToRender; + lastBackpackX = mouseX; + lastBackpackY = mouseY; + renderedBackpack = SBAIntegration.setActiveBackpack(lastBackpack, lastBackpackX, lastBackpackY); + if(renderedBackpack) { + GlStateManager.translate(0, 0, 100); + renderedBackpack = SBAIntegration.renderActiveBackpack(mouseX, mouseY, Minecraft.getMinecraft().fontRendererObj); + GlStateManager.translate(0, 0, -100); + } + } else { + renderedBackpack = false; + } + if(!renderedBackpack) { + lastBackpack = null; + tooltipToDisplay = stackToRender.getTooltip(Minecraft.getMinecraft().thePlayer, + Minecraft.getMinecraft().gameSettings.advancedItemTooltips); + } + } + } + + if(tooltipToDisplay != null) { + Utils.drawHoveringText(tooltipToDisplay, mouseX, mouseY, scaledResolution.getScaledWidth(), scaledResolution.getScaledHeight(), + tooltipLen, Minecraft.getMinecraft().fontRendererObj); + } + } + + public static void handleMouseInput() { + if(!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return; + + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + int width = scaledResolution.getScaledWidth(); + int height = scaledResolution.getScaledHeight(); + + int mouseX = Mouse.getEventX() * width / Minecraft.getMinecraft().displayWidth; + int mouseY = height - Mouse.getEventY() * height / Minecraft.getMinecraft().displayHeight - 1; + + GuiContainer chest = ((GuiContainer)Minecraft.getMinecraft().currentScreen); + + if(Mouse.getEventButtonState() && Mouse.isButtonDown(0)) { + int index=0; + for(ItemStack stack : Minecraft.getMinecraft().thePlayer.inventory.mainInventory) { + if(stack == null) { + index++; + continue; + } + + int x = 8+18*(index % 9); + int y = 104+18*(index / 9); + if(index < 9) y = 180; + + if(mouseX > guiLeft+x && mouseX < guiLeft+x+16) { + if(mouseY > guiTop+y && mouseY < guiTop+y+16) { + Slot slot = chest.inventorySlots.getSlotFromInventory(Minecraft.getMinecraft().thePlayer.inventory, index); + Minecraft.getMinecraft().playerController.windowClick( + chest.inventorySlots.windowId, + slot.slotNumber, 2, 3, Minecraft.getMinecraft().thePlayer); + return; + } + } + + index++; + } + + for(int i=0; i<16; i++) { + int x = i % 4; + int y = i / 4; + + int containerIndex = ourTradeIndexes[i]; + if(containerIndex < 0) continue; + + if(mouseX > guiLeft+10+x*18-1 && mouseX < guiLeft+10+x*18+18) { + if(mouseY > guiTop+15+y*18-1 && mouseY < guiTop+15+y*18+18) { + Minecraft.getMinecraft().playerController.windowClick( + chest.inventorySlots.windowId, + containerIndex, 2, 3, Minecraft.getMinecraft().thePlayer); + return; + } + } + } + + if(mouseX > guiLeft+10-1 && mouseX < guiLeft+10+18) { + if(mouseY > guiTop+90-1 && mouseY < guiTop+90+18) { + Minecraft.getMinecraft().playerController.windowClick( + chest.inventorySlots.windowId, + 36, 2, 3, Minecraft.getMinecraft().thePlayer); + return; + } + } + + ItemStack confirmStack = chest.inventorySlots.getInventory().get(39); + if(confirmStack != null) { + String confirmDisplay = confirmStack.getDisplayName(); + if(!confirmDisplay.equals(EnumChatFormatting.GREEN+"Trading!")) { + if(mouseX > guiLeft+42 && mouseX < guiLeft+42+40) { + if (mouseY > guiTop+92 && mouseY < guiTop+92+14) { + if((confirmDisplay.equals(EnumChatFormatting.YELLOW+"Warning!") || + confirmDisplay.equals(EnumChatFormatting.YELLOW+"Deal!")) && lastTradeMillis < 0) { + lastTradeMillis = System.currentTimeMillis(); + } else if(lastTradeMillis < 0 || System.currentTimeMillis() - lastTradeMillis > 2000) { + Minecraft.getMinecraft().playerController.windowClick( + chest.inventorySlots.windowId, + 39, 2, 3, Minecraft.getMinecraft().thePlayer); + return; + } + } + } + + } + } + + if(mouseX >= guiLeft+xSize+3 && mouseX <= guiLeft+xSize+3+17) { + if(mouseY >= guiTop+ySize-19 && mouseY <= guiTop+ySize-19+17) { + NotEnoughUpdates.INSTANCE.manager.config.useCustomTrade.value = + !NotEnoughUpdates.INSTANCE.manager.config.useCustomTrade.value; + return; + } else if(mouseY >= guiTop+ySize-38 && mouseY <= guiTop+ySize-38+17) { + NotEnoughUpdates.INSTANCE.manager.config.customTradePrices.value = + !NotEnoughUpdates.INSTANCE.manager.config.customTradePrices.value; + return; + } else if(mouseY >= guiTop+ySize-57 && mouseY <= guiTop+ySize-57+17) { + NotEnoughUpdates.INSTANCE.manager.config.customTradePriceStyle.value = + !NotEnoughUpdates.INSTANCE.manager.config.customTradePriceStyle.value; + return; + } + } + } + } + + public static boolean keyboardInput() { + return Keyboard.getEventKey() != Keyboard.KEY_ESCAPE; + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java b/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java index 20ac86ba..d6f390c6 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java @@ -1,12 +1,15 @@ package io.github.moulberry.notenoughupdates.auction; import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import io.github.moulberry.notenoughupdates.NEUManager; +import io.github.moulberry.notenoughupdates.util.Constants; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.event.ClickEvent; import net.minecraft.event.HoverEvent; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; @@ -15,36 +18,47 @@ import net.minecraft.nbt.NBTTagString; import net.minecraft.util.ChatComponentText; import net.minecraft.util.ChatStyle; import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; public class APIManager { private NEUManager manager; public final CustomAH customAH; - private int totalPages = 0; - private int lastApiUpdate; - private LinkedList<Integer> needUpdate = new LinkedList<>(); - private TreeMap<String, Auction> auctionMap = new TreeMap<>(); public HashMap<String, HashSet<String>> internalnameToAucIdMap = new HashMap<>(); private HashSet<String> playerBids = new HashSet<>(); private HashSet<String> playerBidsNotified = new HashSet<>(); private HashSet<String> playerBidsFinishedNotified = new HashSet<>(); - private HashMap<String, TreeMap<Integer, String>> internalnameToLowestBIN = new HashMap<>(); + private JsonObject lowestBins = null; + + private LinkedList<Integer> pagesToDownload = null; - private JsonArray playerInformation = null; + private JsonObject bazaarJson = null; + private JsonObject auctionPricesJson = null; + private HashMap<String, CraftInfo> craftCost = new HashMap<>(); public TreeMap<String, HashMap<Integer, HashSet<String>>> extrasToAucIdMap = new TreeMap<>(); - private long lastPageUpdate = 0; - private long lastProfileUpdate = 0; + private long lastAuctionUpdate = 0; + private long lastShortAuctionUpdate = 0; private long lastCustomAHSearch = 0; private long lastCleanup = 0; + private long lastAuctionAvgUpdate = 0; + private long lastBazaarUpdate = 0; + private long lastLowestBinUpdate = 0; + + private long lastApiUpdate = 0; + private long firstHypixelApiUpdate = 0; public int activeAuctions = 0; public int uniqueItems = 0; @@ -53,28 +67,11 @@ public class APIManager { public int taggedAuctions = 0; public int processMillis = 0; - private boolean doFullUpdate = false; - public APIManager(NEUManager manager) { this.manager = manager; customAH = new CustomAH(manager); } - public JsonObject getPlayerInformation() { - if(playerInformation == null) return null; - for(int i=0; i<playerInformation.size(); i++) { - JsonObject profile = playerInformation.get(i).getAsJsonObject(); - if(profile.get("cute_name").getAsString().equalsIgnoreCase(manager.getCurrentProfile())) { - if(!profile.has("members")) return null; - JsonObject members = profile.get("members").getAsJsonObject(); - String uuid = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""); - if(!members.has(uuid)) return null; - return members.get(uuid).getAsJsonObject(); - } - } - return null; - } - public TreeMap<String, Auction> getAuctionItems() { return auctionMap; } @@ -96,15 +93,15 @@ public class APIManager { public boolean bin; public String category; public String rarity; - public NBTTagCompound item_tag; + public int dungeonTier; + public String item_tag_str; + public NBTTagCompound item_tag = null; private ItemStack stack; - public long lastUpdate = 0; - public int enchLevel = 0; //0 = clean, 1 = ench, 2 = ench/hpb public Auction(String auctioneerUuid, long end, int starting_bid, int highest_bid_amount, int bid_count, - boolean bin, String category, String rarity, NBTTagCompound item_tag) { + boolean bin, String category, String rarity, int dungeonTier, String item_tag_str) { this.auctioneerUuid = auctioneerUuid; this.end = end; this.starting_bid = starting_bid; @@ -112,79 +109,106 @@ public class APIManager { this.bid_count = bid_count; this.bin = bin; this.category = category; + this.dungeonTier = dungeonTier; this.rarity = rarity; - this.item_tag = item_tag; + this.item_tag_str = item_tag_str; } public ItemStack getStack() { + if(item_tag == null && item_tag_str != null) { + try { + item_tag = CompressedStreamTools.readCompressed( + new ByteArrayInputStream(Base64.getDecoder().decode(item_tag_str))); + item_tag_str = null; + } catch(IOException e) { + return null; + } + } if(stack != null) { return stack; } else { JsonObject item = manager.getJsonFromNBT(item_tag); ItemStack stack = manager.jsonToStack(item, false); + + JsonObject itemDefault = manager.getItemInformation().get(item.get("internalname").getAsString()); + + if(stack != null && itemDefault != null) { + ItemStack stackDefault = manager.jsonToStack(itemDefault, true); + if(stack.isItemEqual(stackDefault)) { + //Item types are the same, compare lore + + String[] stackLore = manager.getLoreFromNBT(stack.getTagCompound()); + String[] defaultLore = manager.getLoreFromNBT(stackDefault.getTagCompound()); + + boolean loreMatches = stackLore != null && defaultLore != null && stackLore.length == defaultLore.length; + if(loreMatches) { + for(int i=0; i<stackLore.length; i++) { + if(!stackLore[i].equals(defaultLore[i])) { + loreMatches = false; + break; + } + } + } + if(loreMatches) { + stack = stackDefault; + } + } + } this.stack = stack; return stack; } } } + public void markNeedsUpdate() { + firstHypixelApiUpdate = 0; + pagesToDownload = null; + + auctionMap.clear(); + internalnameToAucIdMap.clear(); + extrasToAucIdMap.clear(); + } + public void tick() { + if(manager.config.apiKey.value == null || manager.config.apiKey.value.isEmpty()) return; + customAH.tick(); - if(System.currentTimeMillis() - lastPageUpdate > 5*1000) { - lastPageUpdate = System.currentTimeMillis(); - updatePageTick(); - ahNotification(); - } - if(System.currentTimeMillis() - lastProfileUpdate > 10*1000) { - lastProfileUpdate = System.currentTimeMillis(); - updateProfiles(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", "")); - } - if(System.currentTimeMillis() - lastCleanup > 120*1000) { - lastCleanup = System.currentTimeMillis(); - cleanup(); - } - if(System.currentTimeMillis() - lastCustomAHSearch > 60*1000) { - lastCustomAHSearch = System.currentTimeMillis(); - if(Minecraft.getMinecraft().currentScreen instanceof CustomAHGui || customAH.isRenderOverAuctionView()) { - customAH.updateSearch(); - calculateStats(); + long currentTime = System.currentTimeMillis(); + if(manager.config.neuAuctionHouse.value) { + if(currentTime - lastAuctionUpdate > 60*1000) { + lastAuctionUpdate = currentTime; + updatePageTick(); } - } - } - - public void updateProfiles(String uuid) { - HashMap<String, String> args = new HashMap<>(); - args.put("uuid", ""+uuid); - manager.hypixelApi.getHypixelApiAsync(manager.config.apiKey.value, "skyblock/profiles", - args, jsonObject -> { - if(jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) { - playerInformation = jsonObject.get("profiles").getAsJsonArray(); - if(playerInformation == null) return; - String backup = null; - long backupLastSave = 0; - for(int i=0; i<playerInformation.size(); i++) { - JsonObject profile = playerInformation.get(i).getAsJsonObject(); - String cute_name = profile.get("cute_name").getAsString(); - - if(backup == null) backup = cute_name; - - if(!profile.has("members")) continue; - JsonObject members = profile.get("members").getAsJsonObject(); - - if(members.has(uuid)) { - JsonObject member = members.get(uuid).getAsJsonObject(); - long last_save = member.get("last_save").getAsLong(); - if(last_save > backupLastSave) { - backupLastSave = last_save; - backup = cute_name; - } - } - } - manager.setCurrentProfileBackup(backup); + if(currentTime - lastShortAuctionUpdate > 10*1000) { + lastShortAuctionUpdate = currentTime; + updatePageTickShort(); + ahNotification(); + } + if(currentTime - lastCleanup > 60*1000) { + lastCleanup = currentTime; + cleanup(); + } + if(currentTime - lastCustomAHSearch > 60*1000) { + lastCustomAHSearch = currentTime; + if(Minecraft.getMinecraft().currentScreen instanceof CustomAHGui || customAH.isRenderOverAuctionView()) { + customAH.updateSearch(); + calculateStats(); } } - ); + } + if(currentTime - lastAuctionAvgUpdate > 30*60*1000) { //30 minutes + lastAuctionAvgUpdate = currentTime - 28*60*1000; //Try again in 2 minutes if updateAvgPrices doesn't succeed + updateAvgPrices(); + } + if(currentTime - lastBazaarUpdate > 10*60*1000) { + lastBazaarUpdate = currentTime; + updateBazaar(); + } + if(currentTime - lastLowestBinUpdate > 2*60*1000) { + lastLowestBinUpdate = currentTime; + updateLowestBin(); + } } private String niceAucId(String aucId) { @@ -204,9 +228,24 @@ public class APIManager { } public int getLowestBin(String internalname) { - TreeMap<Integer, String> lowestBIN = internalnameToLowestBIN.get(internalname); - if(lowestBIN == null || lowestBIN.isEmpty()) return -1; - return lowestBIN.firstKey(); + if(lowestBins != null && lowestBins.has(internalname)) { + JsonElement e = lowestBins.get(internalname); + if(e.isJsonPrimitive() && e.getAsJsonPrimitive().isNumber()) { + return e.getAsInt(); + } + } + return -1; + } + + public void updateLowestBin() { + manager.hypixelApi.getMyApiGZIPAsync("lowestbin.json.gz", (jsonObject) -> { + if(lowestBins == null) { + lowestBins = new JsonObject(); + } + for(Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) { + lowestBins.add(entry.getKey(), entry.getValue()); + } + }, () -> {}); } private void ahNotification() { @@ -246,58 +285,119 @@ public class APIManager { } } + private ExecutorService es = Executors.newSingleThreadExecutor(); private void cleanup() { - try { - long currTime = System.currentTimeMillis(); - Set<String> toRemove = new HashSet<>(); - for(Map.Entry<String, Auction> entry : auctionMap.entrySet()) { - long timeToEnd = entry.getValue().end - currTime; - if(timeToEnd < -60) { - toRemove.add(entry.getKey()); - } else if(currTime - entry.getValue().lastUpdate > 5*60*1000) { - toRemove.add(entry.getKey()); - } - } - toRemove.removeAll(playerBids); - for(String aucid : toRemove) { - auctionMap.remove(aucid); - } - for(HashMap<Integer, HashSet<String>> extrasMap : extrasToAucIdMap.values()) { - for(HashSet<String> aucids : extrasMap.values()) { - for(String aucid : toRemove) { - aucids.remove(aucid); + es.submit(() -> { + try { + long currTime = System.currentTimeMillis(); + Set<String> toRemove = new HashSet<>(); + for(Map.Entry<String, Auction> entry : auctionMap.entrySet()) { + long timeToEnd = entry.getValue().end - currTime; + if(timeToEnd < -120*1000) { //2 minutes + toRemove.add(entry.getKey()); } } + toRemove.removeAll(playerBids); + remove(toRemove); + } catch(ConcurrentModificationException e) { + lastCleanup = System.currentTimeMillis() - 110*1000; } - for(HashSet<String> aucids : internalnameToAucIdMap.values()) { - aucids.removeAll(toRemove); - } - for(TreeMap<Integer, String> lowestBINs : internalnameToLowestBIN.values()) { - lowestBINs.values().removeAll(toRemove); + }); + } + + private void remove(Set<String> toRemove) { + for(String aucid : toRemove) { + auctionMap.remove(aucid); + } + for(HashMap<Integer, HashSet<String>> extrasMap : extrasToAucIdMap.values()) { + for(HashSet<String> aucids : extrasMap.values()) { + for(String aucid : toRemove) { + aucids.remove(aucid); + } } - } catch(ConcurrentModificationException e) { - cleanup(); + } + for(HashSet<String> aucids : internalnameToAucIdMap.values()) { + aucids.removeAll(toRemove); + } + } + + private void updatePageTickShort() { + if(pagesToDownload == null || pagesToDownload.isEmpty()) return; + + if(firstHypixelApiUpdate == 0 || (System.currentTimeMillis() - firstHypixelApiUpdate)%(60*1000) > 15*1000) return; + + JsonObject disable = Constants.DISABLE; + if(disable != null && disable.has("auctions_new") && disable.get("auctions_new").getAsBoolean()) return; + + while(!pagesToDownload.isEmpty()) { + try { + int page = pagesToDownload.pop(); + getPageFromAPI(page); + } catch(NoSuchElementException ignored) {} //Weird race condition? } } private void updatePageTick() { - if(totalPages == 0) { + JsonObject disable = Constants.DISABLE; + if(disable != null && disable.has("auctions_new") && disable.get("auctions_new").getAsBoolean()) return; + + if(pagesToDownload == null) { getPageFromAPI(0); - } else if(doFullUpdate) { - doFullUpdate = false; - for(int i=0; i<totalPages; i++) { - getPageFromAPI(i); - } - } else { - if(needUpdate.isEmpty()) resetNeedUpdate(); + } - int pageToUpdate = needUpdate.pop(); - while (pageToUpdate >= totalPages && !needUpdate.isEmpty()) { - pageToUpdate = needUpdate.pop(); + Consumer<JsonObject> process = jsonObject -> { + if(jsonObject.get("success").getAsBoolean()) { + JsonArray new_auctions = jsonObject.get("new_auctions").getAsJsonArray(); + for(JsonElement auctionElement : new_auctions) { + JsonObject auction = auctionElement.getAsJsonObject(); + //System.out.println("New auction " + auction); + processAuction(auction); + } + JsonArray new_bids = jsonObject.get("new_bids").getAsJsonArray(); + for(JsonElement newBidElement : new_bids) { + JsonObject newBid = newBidElement.getAsJsonObject(); + String newBidUUID = newBid.get("uuid").getAsString(); + //System.out.println("new bid" + newBidUUID); + int newBidAmount = newBid.get("highest_bid_amount").getAsInt(); + int end = newBid.get("end").getAsInt(); + int bid_count = newBid.get("bid_count").getAsInt(); + + Auction auc = auctionMap.get(newBidUUID); + if(auc != null) { + //System.out.println("Setting auction " + newBidUUID + " price to " + newBidAmount); + auc.highest_bid_amount = newBidAmount; + auc.end = end; + auc.bid_count = bid_count; + } + } + Set<String> toRemove = new HashSet<>(); + JsonArray removed_auctions = jsonObject.get("removed_auctions").getAsJsonArray(); + for(JsonElement removedAuctionsElement : removed_auctions) { + String removed = removedAuctionsElement.getAsString(); + toRemove.add(removed); + } + remove(toRemove); } + }; + + manager.hypixelApi.getMyApiGZIPAsync("auctionLast.json.gz", process, () -> { + System.out.println("Error downloading auction from Moulberry's jank API. :("); + }); + + manager.hypixelApi.getMyApiGZIPAsync("auction.json.gz", jsonObject -> { + if(jsonObject.get("success").getAsBoolean()) { + long apiUpdate = (long) jsonObject.get("time").getAsFloat(); + if (lastApiUpdate == apiUpdate) { + lastAuctionUpdate -= 30 * 1000; + } + lastApiUpdate = apiUpdate; + + process.accept(jsonObject); + } + }, () -> { + System.out.println("Error downloading auction from Moulberry's jank API. :("); + }); - getPageFromAPI(pageToUpdate); - } } public void calculateStats() { @@ -332,6 +432,8 @@ public class APIManager { if(contains) { if(line.trim().contains(rarity + " " + typeMatches[j])) { return j; + } else if(line.trim().contains(rarity + " DUNGEON " + typeMatches[j])) { + return j; } } else { if(line.trim().endsWith(rarity + " " + typeMatches[j])) { @@ -346,169 +448,426 @@ public class APIManager { return -1; } + private String[] romans = new String[]{"I","II","III","IV","V","VI","VII","VIII","IX","X","XI", + "XII","XIII","XIV","XV","XVI","XVII","XIX","XX"}; + + + String[] categoryItemType = new String[]{"sword","fishingrod","pickaxe","axe", + "shovel","petitem","travelscroll","reforgestone","bow"}; + String playerUUID = null; + private void processAuction(JsonObject auction) { + if(playerUUID == null) playerUUID = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replaceAll("-",""); + + String auctionUuid = auction.get("uuid").getAsString(); + String auctioneerUuid = auction.get("auctioneer").getAsString(); + long end = auction.get("end").getAsLong(); + int starting_bid = auction.get("starting_bid").getAsInt(); + int highest_bid_amount = auction.get("highest_bid_amount").getAsInt(); + int bid_count = auction.get("bids").getAsJsonArray().size(); + boolean bin = false; + if(auction.has("bin")) { + bin = auction.get("bin").getAsBoolean(); + } + String sbCategory = auction.get("category").getAsString(); + String extras = auction.get("extra").getAsString().toLowerCase(); + String item_name = auction.get("item_name").getAsString(); + String item_lore = Utils.fixBrokenAPIColour(auction.get("item_lore").getAsString()); + String item_bytes = auction.get("item_bytes").getAsString(); + String rarity = auction.get("tier").getAsString(); + JsonArray bids = auction.get("bids").getAsJsonArray(); + + try { + NBTTagCompound item_tag; + try { + item_tag = CompressedStreamTools.readCompressed( + new ByteArrayInputStream(Base64.getDecoder().decode(item_bytes))); + } catch(IOException e) { return; } + + NBTTagCompound tag = item_tag.getTagList("i", 10).getCompoundTagAt(0).getCompoundTag("tag"); + String internalname = manager.getInternalnameFromNBT(tag); + + NBTTagCompound display = tag.getCompoundTag("display"); + if(display.hasKey("Lore", 9)) { + NBTTagList loreList = new NBTTagList(); + for(String line : item_lore.split("\n")) { + loreList.appendTag(new NBTTagString(line)); + } + display.setTag("Lore", loreList); + } + tag.setTag("display", display); + item_tag.getTagList("i", 10).getCompoundTagAt(0).setTag("tag", tag); + + if(tag.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + + if(ea.hasKey("enchantments", 10)) { + NBTTagCompound enchantments = ea.getCompoundTag("enchantments"); + for(String key : enchantments.getKeySet()) { + String enchantname = key.toLowerCase().replace("ultimate_", "").replace("_", " "); + int enchantlevel = enchantments.getInteger(key); + String enchantLevelStr; + if(enchantlevel >= 1 && enchantlevel <= 20) { + enchantLevelStr = romans[enchantlevel-1]; + } else { + enchantLevelStr = String.valueOf(enchantlevel); + } + extras = extras.replace(enchantname, enchantname + " " + enchantLevelStr); + } + } + } + + int index=0; + for(String str : extras.split(" ")) { + str = Utils.cleanColour(str).toLowerCase(); + if(str.length() > 0) { + HashMap<Integer, HashSet<String>> extrasMap = extrasToAucIdMap.computeIfAbsent(str, k -> new HashMap<>()); + HashSet<String> aucids = extrasMap.computeIfAbsent(index, k -> new HashSet<>()); + aucids.add(auctionUuid); + } + index++; + } + + for(int j=0; j<bids.size(); j++) { + JsonObject bid = bids.get(j).getAsJsonObject(); + if(bid.get("bidder").getAsString().equalsIgnoreCase(playerUUID)) { + playerBids.add(auctionUuid); + } + } + + int dungeonTier = -1; + if(checkItemType(item_lore, true, "DUNGEON") >= 0) { + dungeonTier = 0; + for(int i=0; i<item_name.length(); i++) { + char c = item_name.charAt(i); + if(c == 0x272A) { + dungeonTier++; + } + } + } + + //Categories + String category = sbCategory; + int itemType = checkItemType(item_lore, true,"SWORD", "FISHING ROD", "PICKAXE", + "AXE", "SHOVEL", "PET ITEM", "TRAVEL SCROLL", "REFORGE STONE", "BOW"); + if(itemType >= 0 && itemType < categoryItemType.length) { + category = categoryItemType[itemType]; + } + if(category.equals("consumables") && extras.contains("enchanted book")) category = "ebook"; + if(category.equals("consumables") && extras.endsWith("potion")) category = "potion"; + if(category.equals("misc") && extras.contains("rune")) category = "rune"; + if(category.equals("misc") && item_lore.split("\n")[0].endsWith("Furniture")) category = "furniture"; + if(item_lore.split("\n")[0].endsWith("Pet") || + item_lore.split("\n")[0].endsWith("Mount")) category = "pet"; + + Auction auction1 = new Auction(auctioneerUuid, end, starting_bid, highest_bid_amount, + bid_count, bin, category, rarity, dungeonTier, item_bytes); + + if(tag.hasKey("ench")) { + auction1.enchLevel = 1; + if(tag.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + + int hotpotatocount = ea.getInteger("hot_potato_count"); + if(hotpotatocount == 10) { + auction1.enchLevel = 2; + } + } + } + + auctionMap.put(auctionUuid, auction1); + internalnameToAucIdMap.computeIfAbsent(internalname, k -> new HashSet<>()).add(auctionUuid); + } catch(Exception e) {e.printStackTrace();} + } + private void getPageFromAPI(int page) { + //System.out.println("downloading page:"+page); //System.out.println("Trying to update page: " + page); HashMap<String, String> args = new HashMap<>(); args.put("page", ""+page); manager.hypixelApi.getHypixelApiAsync(manager.config.apiKey.value, "skyblock/auctions", args, jsonObject -> { - if (jsonObject.get("success").getAsBoolean()) { - totalPages = jsonObject.get("totalPages").getAsInt(); - activeAuctions = jsonObject.get("totalAuctions").getAsInt(); + if(jsonObject == null) return; + + if (jsonObject.get("success").getAsBoolean()) { + if(pagesToDownload == null) { + int totalPages = jsonObject.get("totalPages").getAsInt(); + pagesToDownload = new LinkedList<>(); + for(int i=0; i<totalPages+2; i++) { + pagesToDownload.add(i); + } + } + if(firstHypixelApiUpdate == 0) { + firstHypixelApiUpdate = jsonObject.get("lastUpdated").getAsLong(); + } + activeAuctions = jsonObject.get("totalAuctions").getAsInt(); - int lastUpdated = jsonObject.get("lastUpdated").getAsInt(); + long startProcess = System.currentTimeMillis(); + JsonArray auctions = jsonObject.get("auctions").getAsJsonArray(); + for (int i = 0; i < auctions.size(); i++) { + JsonObject auction = auctions.get(i).getAsJsonObject(); - if(lastApiUpdate != lastUpdated) { - if(manager.config.quickAHUpdate.value && - (Minecraft.getMinecraft().currentScreen instanceof CustomAHGui || customAH.isRenderOverAuctionView())) { - doFullUpdate = true; + processAuction(auction); } - resetNeedUpdate(); + processMillis = (int)(System.currentTimeMillis() - startProcess); + } else { + pagesToDownload.addLast(page); } + }, () -> { + pagesToDownload.addLast(page); + } + ); + } - lastApiUpdate = lastUpdated; + public void updateBazaar() { + manager.hypixelApi.getHypixelApiAsync(manager.config.apiKey.value, "skyblock/bazaar", new HashMap<>(), (jsonObject) -> { + if(!jsonObject.get("success").getAsBoolean()) return; + + craftCost.clear(); + bazaarJson = new JsonObject(); + JsonObject products = jsonObject.get("products").getAsJsonObject(); + for(Map.Entry<String, JsonElement> entry : products.entrySet()) { + if(entry.getValue().isJsonObject()) { + JsonObject productInfo = new JsonObject(); + + JsonObject product = entry.getValue().getAsJsonObject(); + JsonObject quickStatus = product.get("quick_status").getAsJsonObject(); + productInfo.addProperty("avg_buy", quickStatus.get("buyPrice").getAsFloat()); + productInfo.addProperty("avg_sell", quickStatus.get("sellPrice").getAsFloat()); + + for(JsonElement element : product.get("sell_summary").getAsJsonArray()) { + if(element.isJsonObject()) { + JsonObject sellSummaryFirst = element.getAsJsonObject(); + productInfo.addProperty("curr_sell", sellSummaryFirst.get("pricePerUnit").getAsFloat()); + break; + } + } - String[] lvl4Maxes = {"Experience", "Life Steal", "Scavenger", "Looting"}; + for(JsonElement element : product.get("buy_summary").getAsJsonArray()) { + if(element.isJsonObject()) { + JsonObject sellSummaryFirst = element.getAsJsonObject(); + productInfo.addProperty("curr_buy", sellSummaryFirst.get("pricePerUnit").getAsFloat()); + break; + } + } - String[] categoryItemType = new String[]{"sword","fishingrod","pickaxe","axe", - "shovel","petitem","travelscroll","reforgestone","bow"}; - String playerUUID = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replaceAll("-",""); + bazaarJson.add(entry.getKey().replace(":", "-"), productInfo); + } + } + }); + } - long startProcess = System.currentTimeMillis(); - JsonArray auctions = jsonObject.get("auctions").getAsJsonArray(); - for (int i = 0; i < auctions.size(); i++) { - JsonObject auction = auctions.get(i).getAsJsonObject(); + public void updateAvgPrices() { + manager.hypixelApi.getMyApiGZIPAsync("auction_averages/3day.json.gz", (jsonObject) -> { + craftCost.clear(); + auctionPricesJson = jsonObject; + lastAuctionAvgUpdate = System.currentTimeMillis(); + }, () -> {}); + } - String auctionUuid = auction.get("uuid").getAsString(); - String auctioneerUuid = auction.get("auctioneer").getAsString(); - long end = auction.get("end").getAsLong(); - int starting_bid = auction.get("starting_bid").getAsInt(); - int highest_bid_amount = auction.get("highest_bid_amount").getAsInt(); - int bid_count = auction.get("bids").getAsJsonArray().size(); - boolean bin = false; - if(auction.has("bin")) { - bin = auction.get("bin").getAsBoolean(); - } - String sbCategory = auction.get("category").getAsString(); - String extras = auction.get("extra").getAsString(); - String item_name = auction.get("item_name").getAsString(); - String item_lore = Utils.fixBrokenAPIColour(auction.get("item_lore").getAsString()); - String item_bytes = auction.get("item_bytes").getAsString(); - String rarity = auction.get("tier").getAsString(); - JsonArray bids = auction.get("bids").getAsJsonArray(); - - for(String lvl4Max : lvl4Maxes) { - item_lore = item_lore.replaceAll("\\u00A79("+lvl4Max+" IV)", EnumChatFormatting.DARK_PURPLE+"$1"); - } - item_lore = item_lore.replaceAll("\\u00A79([A-Za-z ]+ VI)", EnumChatFormatting.DARK_PURPLE+"$1"); - item_lore = item_lore.replaceAll("\\u00A79([A-Za-z ]+ VII)", EnumChatFormatting.RED+"$1"); - - try { - NBTTagCompound item_tag; - try { - item_tag = CompressedStreamTools.readCompressed( - new ByteArrayInputStream(Base64.getDecoder().decode(item_bytes))); - } catch(IOException e) { continue; } - - NBTTagCompound tag = item_tag.getTagList("i", 10).getCompoundTagAt(0).getCompoundTag("tag"); - String internalname = manager.getInternalnameFromNBT(tag); - String displayNormal = ""; - if(manager.getItemInformation().containsKey(internalname)) { - displayNormal = Utils.cleanColour(manager.getItemInformation().get(internalname).get("displayname").getAsString()); - } + public Set<String> getItemAuctionInfoKeySet() { + if(auctionPricesJson == null) return new HashSet<>(); + HashSet<String> keys = new HashSet<>(); + for(Map.Entry<String, JsonElement> entry : auctionPricesJson.entrySet()) { + keys.add(entry.getKey()); + } + return keys; + } - String[] lore = new String[0]; - NBTTagCompound display = tag.getCompoundTag("display"); - if(display.hasKey("Lore", 9)) { - NBTTagList loreList = new NBTTagList(); - for(String line : item_lore.split("\n")) { - loreList.appendTag(new NBTTagString(line)); - } - display.setTag("Lore", loreList); - } - tag.setTag("display", display); - item_tag.getTagList("i", 10).getCompoundTagAt(0).setTag("tag", tag); - - int index=0; - for(String str : extras.split(" ")) { - str = Utils.cleanColour(str).toLowerCase(); - if(str.length() > 0) { - HashMap<Integer, HashSet<String>> extrasMap = extrasToAucIdMap.computeIfAbsent(str, k -> new HashMap<>()); - HashSet<String> aucids = extrasMap.computeIfAbsent(index, k -> new HashSet<>()); - aucids.add(auctionUuid); - } - index++; - } + public JsonObject getItemAuctionInfo(String internalname) { + if(auctionPricesJson == null) return null; + JsonElement e = auctionPricesJson.get(internalname); + if(e == null) { + return null; + } + return e.getAsJsonObject(); + } - if(bin) { - TreeMap<Integer, String> lowestBINs = internalnameToLowestBIN.computeIfAbsent(internalname, k -> new TreeMap<>()); - int count = item_tag.getInteger("Count"); - lowestBINs.put(starting_bid/(count>0?count:1), auctionUuid); - if(lowestBINs.size() > 5) { - lowestBINs.keySet().remove(lowestBINs.lastKey()); - } - } + public JsonObject getBazaarInfo(String internalname) { + if(bazaarJson == null) return null; + JsonElement e = bazaarJson.get(internalname); + if(e == null) { + return null; + } + return e.getAsJsonObject(); + } - for(int j=0; j<bids.size(); j++) { - JsonObject bid = bids.get(j).getAsJsonObject(); - if(bid.get("bidder").getAsString().equalsIgnoreCase(playerUUID)) { - playerBids.add(auctionUuid); - } - } + private static final List<String> hardcodedVanillaItems = Utils.createList( + "WOOD_AXE", "WOOD_HOE", "WOOD_PICKAXE","WOOD_SPADE", "WOOD_SWORD", + "GOLD_AXE", "GOLD_HOE", "GOLD_PICKAXE", "GOLD_SPADE", "GOLD_SWORD", + "ROOKIE_HOE" + ); + public boolean isVanillaItem(String internalname) { + if(hardcodedVanillaItems.contains(internalname)) return true; + + //Removes trailing numbers and underscores, eg. LEAVES_2-3 -> LEAVES + String vanillaName = internalname.split("-")[0]; + if(manager.getItemInformation().containsKey(vanillaName)) { + JsonObject json = manager.getItemInformation().get(vanillaName); + if(json != null && json.has("vanilla") && json.get("vanilla").getAsBoolean()) return true; + } + return Item.itemRegistry.getObject(new ResourceLocation(vanillaName)) != null; + } - if(checkItemType(item_lore, true, "DUNGEON") >= 0) { - HashMap<Integer, HashSet<String>> extrasMap = extrasToAucIdMap.computeIfAbsent("dungeon", k -> new HashMap<>()); - HashSet<String> aucids = extrasMap.computeIfAbsent(0, k -> new HashSet<>()); - aucids.add(auctionUuid); - } + public class CraftInfo { + public boolean fromRecipe = false; + public boolean vanillaItem = false; + public float craftCost = -1; + } - //Categories - String category = sbCategory; - int itemType = checkItemType(item_lore, false,"SWORD", "FISHING ROD", "PICKAXE", - "AXE", "SHOVEL", "PET ITEM", "TRAVEL SCROLL", "REFORGE STONE", "BOW"); - if(itemType >= 0 && itemType < categoryItemType.length) { - category = categoryItemType[itemType]; - } - if(extras.startsWith("Enchanted Book")) category = "ebook"; - if(extras.endsWith("Potion")) category = "potion"; - if(extras.contains("Rune")) category = "rune"; - if(item_lore.split("\n")[0].endsWith("Furniture")) category = "furniture"; - if(item_lore.split("\n")[0].endsWith("Pet") || - item_lore.split("\n")[0].endsWith("Mount")) category = "pet"; - - Auction auction1 = new Auction(auctioneerUuid, end, starting_bid, highest_bid_amount, - bid_count, bin, category, rarity, item_tag); - - if(tag.hasKey("ench")) { - auction1.enchLevel = 1; - if(tag.hasKey("ExtraAttributes", 10)) { - NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); - - int hotpotatocount = ea.getInteger("hot_potato_count"); - if(hotpotatocount == 10) { - auction1.enchLevel = 2; - } - } - } + public CraftInfo getCraftCost(String internalname) { + return getCraftCost(internalname, 0); + } - auction1.lastUpdate = System.currentTimeMillis(); + /** + * Recursively calculates the cost of crafting an item from raw materials. + */ + public CraftInfo getCraftCost(String internalname, int depth) { + if(craftCost.containsKey(internalname)) { + return craftCost.get(internalname); + } else { + CraftInfo ci = new CraftInfo(); + + ci.vanillaItem = isVanillaItem(internalname); + + JsonObject auctionInfo = getItemAuctionInfo(internalname); + JsonObject bazaarInfo = getBazaarInfo(internalname); + + if(bazaarInfo != null && bazaarInfo.get("curr_buy") != null) { + float bazaarInstantBuyPrice = bazaarInfo.get("curr_buy").getAsFloat(); + ci.craftCost = bazaarInstantBuyPrice; + } + //Don't use auction prices for vanilla items cuz people like to transfer money, messing up the cost of vanilla items. + if(auctionInfo != null && !ci.vanillaItem) { + float auctionPrice = auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat(); + if(ci.craftCost < 0 || auctionPrice < ci.craftCost) { + ci.craftCost = auctionPrice; + } + } + + if(depth > 16) { + craftCost.put(internalname, ci); + return ci; + } + + JsonObject item = manager.getItemInformation().get(internalname); + if(item != null && item.has("recipe")) { + float craftPrice = 0; + JsonObject recipe = item.get("recipe").getAsJsonObject(); + + 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(); + if(itemS == null || itemS.length() == 0) continue; + + int count = 1; + if(itemS.split(":").length == 2) { + count = Integer.parseInt(itemS.split(":")[1]); + itemS = itemS.split(":")[0]; + } + if(itemS.equals(internalname)) { //if item is used a crafting component in its own recipe, return + craftCost.put(internalname, ci); + return ci; + } - auctionMap.put(auctionUuid, auction1); - internalnameToAucIdMap.computeIfAbsent(internalname, k -> new HashSet<>()).add(auctionUuid); - } catch(Exception e) {e.printStackTrace();} + float compCost = getCraftCost(itemS, depth+1).craftCost * count; + if(compCost < 0) { + //If it's a custom item without a cost, return + if(!getCraftCost(itemS).vanillaItem) { + craftCost.put(internalname, ci); + return ci; + } + } else { + craftPrice += compCost; } - processMillis = (int)(System.currentTimeMillis() - startProcess); + } + + if(ci.craftCost < 0 || craftPrice < ci.craftCost) { + ci.craftCost = craftPrice; + ci.fromRecipe = true; } } - ); + craftCost.put(internalname, ci); + return ci; + } } - private void resetNeedUpdate() { - for(Integer page=0; page<totalPages; page++) { - if(!needUpdate.contains(page)) { - needUpdate.addLast(page); + /** + * Calculates the cost of enchants + other price modifiers such as pet xp, midas price, etc. + */ + public float getCostOfEnchants(String internalname, NBTTagCompound tag) { + float costOfEnchants = 0; + if(true) return 0; + + JsonObject info = getItemAuctionInfo(internalname); + if(info == null || !info.has("price")) { + return 0; + } + if(auctionPricesJson == null || !auctionPricesJson.has("ench_prices") || !auctionPricesJson.has("ench_maximums")) { + return 0; + } + JsonObject ench_prices = auctionPricesJson.getAsJsonObject("ench_prices"); + JsonObject ench_maximums = auctionPricesJson.getAsJsonObject("ench_maximums"); + if(!ench_prices.has(internalname) || !ench_maximums.has(internalname)) { + return 0; + } + JsonObject iid_variables = ench_prices.getAsJsonObject(internalname); + float ench_maximum = ench_maximums.get(internalname).getAsFloat(); + + int enchants = 0; + float price = getItemAuctionInfo(internalname).get("price").getAsFloat(); + if(tag.hasKey("ExtraAttributes")) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + if(ea.hasKey("enchantments")) { + + NBTTagCompound enchs = ea.getCompoundTag("enchantments"); + for(String ench : enchs.getKeySet()) { + enchants++; + int level = enchs.getInteger(ench); + + for(Map.Entry<String, JsonElement> entry : iid_variables.entrySet()) { + if(matchEnch(ench, level, entry.getKey())) { + costOfEnchants += entry.getValue().getAsJsonObject().get("A").getAsFloat()*price + + entry.getValue().getAsJsonObject().get("B").getAsFloat(); + break; + } + } + } } } + return costOfEnchants; + } + + /** + * Checks whether a certain enchant (ench name + lvl) matches an enchant id + * eg. PROTECTION_GE6 will match -> ench_name = PROTECTION, lvl >= 6 + */ + private boolean matchEnch(String ench, int level, String id) { + if(!id.contains(":")) { + return false; + } + + String idEnch = id.split(":")[0]; + String idLevel = id.split(":")[1]; + + if(!ench.equalsIgnoreCase(idEnch)) { + return false; + } + + if(String.valueOf(level).equalsIgnoreCase(idLevel)) { + return true; + } + + if(idLevel.startsWith("LE")) { + int idLevelI = Integer.valueOf(idLevel.substring(2)); + return level <= idLevelI; + } else if(idLevel.startsWith("GE")) { + int idLevelI = Integer.valueOf(idLevel.substring(2)); + return level >= idLevelI; + } + + return false; } /*ScheduledExecutorService auctionUpdateSES = Executors.newSingleThreadScheduledExecutor(); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java b/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java index 17ce216e..42346651 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java @@ -1,6 +1,8 @@ package io.github.moulberry.notenoughupdates.auction; +import com.google.gson.JsonObject; import io.github.moulberry.notenoughupdates.NEUManager; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; @@ -34,6 +36,8 @@ import java.awt.datatransfer.StringSelection; import java.text.NumberFormat; import java.util.*; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -76,15 +80,18 @@ public class CustomAH extends Gui { public long lastOpen; public long lastGuiScreenSwitch; - private int splits = 2; + private final int splits = 2; - private int ySplit = 35; - private int ySplitSize = 18; + public String latestBid; + public long latestBidMillis; + + private final int ySplit = 35; + private final int ySplitSize = 18; private float scrollAmount; - private int guiLeft = 0; - private int guiTop = 0; + public int guiLeft = -1; + public int guiTop = -1; private Category CATEGORY_SWORD = new Category("sword", "Swords", "diamond_sword"); private Category CATEGORY_ARMOR = new Category("armor", "Armor", "diamond_chestplate"); @@ -103,7 +110,7 @@ public class CustomAH extends Gui { private Category CATEGORY_TRAVEL_SCROLLS = new Category("travelscroll", "Travel Scrolls", "map"); private Category CATEGORY_REFORGE_STONES = new Category("reforgestone", "Reforge Stones", "anvil"); - private Category CATEGORY_RUNES = new Category("rune", "Runes", "end_portal_frame"); + private Category CATEGORY_RUNES = new Category("rune", "Runes", "magma_cream"); private Category CATEGORY_FURNITURE = new Category("furniture", "Furniture", "armor_stand"); private Category CATEGORY_COMBAT = new Category("weapon", "Combat", "golden_sword", CATEGORY_SWORD, @@ -125,11 +132,11 @@ public class CustomAH extends Gui { private static final int SORT_MODE_SOON = 2; private static final String[] rarities = { "COMMON", "UNCOMMON", "RARE", "EPIC", - "LEGENDARY", "MYTHIC", "SPECIAL", "VERY SPECIAL" }; + "LEGENDARY", "MYTHIC", "SPECIAL", "VERY SPECIAL", "SUPREME" }; private static final String[] rarityColours = { ""+EnumChatFormatting.WHITE, ""+EnumChatFormatting.GREEN, ""+EnumChatFormatting.BLUE, ""+EnumChatFormatting.DARK_PURPLE, ""+EnumChatFormatting.GOLD, ""+EnumChatFormatting.LIGHT_PURPLE, ""+EnumChatFormatting.RED, - ""+EnumChatFormatting.RED }; + ""+EnumChatFormatting.RED, ""+EnumChatFormatting.DARK_RED }; private static final int BIN_FILTER_ALL = 0; private static final int BIN_FILTER_BIN = 1; @@ -140,12 +147,23 @@ public class CustomAH extends Gui { private static final int ENCH_FILTER_ENCH = 2; private static final int ENCH_FILTER_ENCHHPB = 3; + private static final int DUNGEON_FILTER_ALL = 0; + private static final int DUNGEON_FILTER_DUNGEON = 1; + private static final int DUNGEON_FILTER_1 = 2; + private static final int DUNGEON_FILTER_2 = 3; + private static final int DUNGEON_FILTER_3 = 4; + private static final int DUNGEON_FILTER_4 = 5; + private static final int DUNGEON_FILTER_5 = 6; + + private int dungeonFilter = DUNGEON_FILTER_ALL; private int sortMode = SORT_MODE_HIGH; private int rarityFilter = -1; private boolean filterMyAuctions = false; private int binFilter = BIN_FILTER_ALL; private int enchFilter = ENCH_FILTER_ALL; + private static ItemStack DUNGEON_SORT = Utils.createItemStack(Item.getItemFromBlock(Blocks.deadbush), + EnumChatFormatting.GREEN+"Dungeon Sorting"); private static ItemStack CONTROL_SORT = Utils.createItemStack(Item.getItemFromBlock(Blocks.hopper), EnumChatFormatting.GREEN+"Sort"); private static ItemStack CONTROL_TIER = Utils.createItemStack(Items.ender_eye, @@ -158,7 +176,7 @@ public class CustomAH extends Gui { EnumChatFormatting.GREEN+"Enchant Filter"); private static ItemStack CONTROL_STATS = Utils.createItemStack(Item.getItemFromBlock(Blocks.command_block), EnumChatFormatting.GREEN+"Stats for nerds"); - private ItemStack[] controls = {null,CONTROL_SORT,CONTROL_TIER,null,CONTROL_MYAUC,null,CONTROL_BIN,CONTROL_ENCH,CONTROL_STATS}; + private ItemStack[] controls = {DUNGEON_SORT,CONTROL_SORT,CONTROL_TIER,null,CONTROL_MYAUC,null,CONTROL_BIN,CONTROL_ENCH,CONTROL_STATS}; private NEUManager manager; @@ -175,17 +193,25 @@ public class CustomAH extends Gui { filterMyAuctions = false; //binFilter = BIN_FILTER_ALL; enchFilter = ENCH_FILTER_ALL; + dungeonFilter = DUNGEON_FILTER_ALL; searchField.setText(""); searchField.setFocused(true); priceField.setText(""); } + public void setSearch(String search) { + searchField.setText(search); + updateSearch(); + } + public void tick() { - if(shouldUpdateSearch) updateSearch(); - if(shouldSortItems) { - sortItems(); - shouldSortItems = false; + if(Minecraft.getMinecraft().currentScreen instanceof CustomAHGui || renderOverAuctionView) { + if(shouldUpdateSearch) updateSearch(); + if(shouldSortItems) { + sortItems(); + shouldSortItems = false; + } } } @@ -246,11 +272,11 @@ public class CustomAH extends Gui { this.renderOverAuctionView = renderOverAuctionView; } - private int getXSize() { + public int getXSize() { return 195; } - private int getYSize() { + public int getYSize() { return 136 + ySplitSize*splits; } @@ -313,6 +339,47 @@ public class CustomAH extends Gui { } } + if(manager.config.auctionPriceInfo.value) { + String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(auc.getStack()); + if(internalname != null) { + tooltip.add(""); + if(!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) && !Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) { + tooltip.add(EnumChatFormatting.GRAY+"[SHIFT for Price Info]"); + } else { + JsonObject auctionInfo = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAuctionInfo(internalname); + + boolean hasAuctionPrice = auctionInfo != null; + + int lowestBin = NotEnoughUpdates.INSTANCE.manager.auctionManager.getLowestBin(internalname); + + APIManager.CraftInfo craftCost = NotEnoughUpdates.INSTANCE.manager.auctionManager.getCraftCost(internalname); + + if(lowestBin > 0) { + tooltip.add(EnumChatFormatting.GRAY+"Lowest BIN: "+ + EnumChatFormatting.GOLD+format.format(lowestBin)+" coins"); + } + if(hasAuctionPrice) { + int auctionPrice = (int)(auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat()); + tooltip.add(EnumChatFormatting.GRAY+"AH Price: "+ + EnumChatFormatting.GOLD+format.format(auctionPrice)+" coins"); + tooltip.add(EnumChatFormatting.GRAY+"AH Sales: "+ + EnumChatFormatting.GOLD+format.format(auctionInfo.get("sales").getAsFloat())+" sales/day"); + if(auctionInfo.has("clean_price")) { + tooltip.add(EnumChatFormatting.GRAY+"AH Price (Clean): "+ + EnumChatFormatting.GOLD+format.format((int)auctionInfo.get("clean_price").getAsFloat())+" coins"); + tooltip.add(EnumChatFormatting.GRAY+"AH Sales (Clean): "+ + EnumChatFormatting.GOLD+format.format(auctionInfo.get("clean_sales").getAsFloat())+" sales/day"); + } + + } + if(craftCost.fromRecipe) { + tooltip.add(EnumChatFormatting.GRAY+"Raw Craft Cost: "+ + EnumChatFormatting.GOLD+format.format((int)craftCost.craftCost)+" coins"); + } + } + } + } + tooltip.add(""); tooltip.add(EnumChatFormatting.GRAY+"Ends in: "+endsIn); tooltip.add(""); @@ -401,13 +468,12 @@ public class CustomAH extends Gui { return -1; } - public String findEndsInStr(ItemStack stack) { + public String findStrStart(ItemStack stack, String toFind) { if(stack.hasTagCompound()) { //§7Ends in: - String endsIn = EnumChatFormatting.GRAY+"Ends in: "; for(String line : manager.getLoreFromNBT(stack.getTagCompound())) { - if(line.trim().startsWith(endsIn)) { - return line.substring(endsIn.length()); + if(line.trim().startsWith(toFind)) { + return line.substring(toFind.length()); } } } @@ -415,6 +481,10 @@ public class CustomAH extends Gui { return null; } + public String findEndsInStr(ItemStack stack) { + return findStrStart(stack, EnumChatFormatting.GRAY+"Ends in: "); + } + public void drawScreen(int mouseX, int mouseY) { if(System.currentTimeMillis() - lastOpen < 1000) Mouse.setGrabbed(false); @@ -518,11 +588,71 @@ public class CustomAH extends Gui { if(mouseX > auctionViewLeft+31 && mouseX <auctionViewLeft+31+16) { if(mouseY > guiTop+35 && mouseY < guiTop+35+16) { - if(topStack != null) tooltipToRender = topStack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + if(topStack != null) { + tooltipToRender = topStack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + tooltipToRender.add(""); + tooltipToRender.add(EnumChatFormatting.YELLOW+"Click to copy seller name!"); + } } else if(mouseY > guiTop+100 && mouseY < guiTop+100+16) { if(leftStack != null) tooltipToRender = leftStack.getTooltip(Minecraft.getMinecraft().thePlayer, false); } else if(mouseY > guiTop+61 && mouseY < guiTop+61+16) { - if(rightStack != null) tooltipToRender = rightStack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + tooltipToRender = new ArrayList<>(); + APIManager.Auction auc = manager.auctionManager.getAuctionItems().get(currentAucId); + if(auc != null) { + tooltipToRender.add(EnumChatFormatting.WHITE+"Price Info"); + + String internalname = manager.getInternalNameForItem(auc.getStack()); + JsonObject auctionInfo = manager.auctionManager.getItemAuctionInfo(internalname); + JsonObject bazaarInfo = manager.auctionManager.getBazaarInfo(internalname); + + boolean hasAuctionPrice = auctionInfo != null; + boolean hasBazaarPrice = bazaarInfo != null; + + int lowestBin = manager.auctionManager.getLowestBin(internalname); + + NumberFormat format = NumberFormat.getInstance(Locale.US); + + APIManager.CraftInfo craftCost = manager.auctionManager.getCraftCost(internalname); + + if(lowestBin > 0) { + tooltipToRender.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Lowest BIN: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(lowestBin)+" coins"); + } + if(hasBazaarPrice) { + int bazaarBuyPrice = (int)bazaarInfo.get("avg_buy").getAsFloat(); + tooltipToRender.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Buy: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarBuyPrice)+" coins"); + int bazaarSellPrice = (int)bazaarInfo.get("avg_sell").getAsFloat(); + tooltipToRender.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Sell: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarSellPrice)+" coins"); + int bazaarInstantBuyPrice = (int)bazaarInfo.get("curr_buy").getAsFloat(); + tooltipToRender.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Insta-Buy: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarInstantBuyPrice)+" coins"); + int bazaarInstantSellPrice = (int)bazaarInfo.get("curr_sell").getAsFloat(); + tooltipToRender.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Bazaar Insta-Sell: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(bazaarInstantSellPrice)+" coins"); + } + if(hasAuctionPrice) { + int auctionPrice = (int)(auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat()); + tooltipToRender.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"AH Price: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(auctionPrice)+" coins"); + tooltipToRender.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"AH Sales: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(auctionInfo.get("sales").getAsFloat())+" sales/day"); + if(auctionInfo.has("clean_price")) { + tooltipToRender.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"AH Price (Clean): "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format((int)auctionInfo.get("clean_price").getAsFloat())+" coins"); + tooltipToRender.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"AH Sales (Clean): "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format(auctionInfo.get("clean_sales").getAsFloat())+" sales/day"); + } + + } + if(craftCost.fromRecipe) { + tooltipToRender.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"Raw Craft Cost: "+ + EnumChatFormatting.GOLD+EnumChatFormatting.BOLD+format.format((int)craftCost.craftCost)+" coins"); + } + tooltipToRender.add(""); + } + if(rightStack != null) tooltipToRender.addAll(rightStack.getTooltip(Minecraft.getMinecraft().thePlayer, false)); } else if(mouseY > guiTop+126 && mouseY < guiTop+126+16) { if(middleStack != null) tooltipToRender = middleStack.getTooltip(Minecraft.getMinecraft().thePlayer, false); } @@ -530,8 +660,7 @@ public class CustomAH extends Gui { } catch(NullPointerException e) { //i cant be bothered } } - } else if(containerName.trim().equals("Confirm Bid")) { - + } else if(containerName.trim().equals("Confirm Bid") || containerName.trim().equals("Confirm Purchase")) { Minecraft.getMinecraft().getTextureManager().bindTexture(auction_accept); this.drawTexturedModalRect(auctionViewLeft, guiTop, 0, 0, 78, 172); @@ -728,29 +857,30 @@ public class CustomAH extends Gui { int maxItemScroll = Math.max(0, totalItems - (5+splits)*9); itemsScroll = Math.min(itemsScroll, maxItemScroll); - out: - for(int i=0; i<5+splits; i++) { - int itemY = guiTop + i*18 + 18; - for(int j=0; j<9; j++) { - int itemX = guiLeft + j*18 + 9; - int id = itemsScroll + i*9 + j; - if(auctionIds.size() <= id) break out; + if(manager.config.neuAuctionHouse.value) { + out: + for(int i=0; i<5+splits; i++) { + int itemY = guiTop + i*18 + 18; + for(int j=0; j<9; j++) { + int itemX = guiLeft + j*18 + 9; + int id = itemsScroll + i*9 + j; + if(auctionIds.size() <= id) break out; - try { - String aucid = sortedAuctionIds.get(id); + try { + String aucid = sortedAuctionIds.get(id); - GL11.glTranslatef(0,0,100); - ItemStack stack = manager.auctionManager.getAuctionItems().get(aucid).getStack(); - Utils.drawItemStack(stack, itemX, itemY); - GL11.glTranslatef(0,0,-100); + GL11.glTranslatef(0,0,100); + ItemStack stack = manager.auctionManager.getAuctionItems().get(aucid).getStack(); + Utils.drawItemStack(stack, itemX, itemY); + GL11.glTranslatef(0,0,-100); - if(mouseX > itemX && mouseX < itemX+16) { - if(mouseY > itemY && mouseY < itemY+16) { - tooltipToRender = getTooltipForAucId(aucid); + if(mouseX > itemX && mouseX < itemX+16) { + if(mouseY > itemY && mouseY < itemY+16) { + tooltipToRender = getTooltipForAucId(aucid); + } } + } catch(Exception e) { } - } catch(Exception e) { - break out; } } } @@ -773,6 +903,11 @@ public class CustomAH extends Gui { this.drawTexturedModalRect(guiLeft+175, guiTop+18+(int)((95+ySplitSize*2)*scrollAmount), 256-(scrollClicked?12:24), 0, 12, 15); + if(!manager.config.neuAuctionHouse.value) { + Utils.drawStringCentered(EnumChatFormatting.RED+"NEUAH is DISABLED! Enable in /neusettings.", + Minecraft.getMinecraft().fontRendererObj, guiLeft+getXSize()/2, guiTop+getYSize()/2-5, true, 0); + } + if(tooltipToRender != null) { List<String> tooltipGray = new ArrayList<>(); for(String line : tooltipToRender) { @@ -794,7 +929,30 @@ public class CustomAH extends Gui { String selPrefix = EnumChatFormatting.DARK_AQUA + selPrefixNC; String unselPrefix = EnumChatFormatting.GRAY.toString(); switch(index) { - case 0: break; + case 0: + lore.add(""); + String gold = EnumChatFormatting.GOLD.toString(); + String gray = EnumChatFormatting.GRAY.toString(); + char s = 0x272A; + String[] linesDung = {"Show All","Any Dungeon", + gold+s+gray+s+s+s+s, + gold+s+s+gray+s+s+s, + gold+s+s+s+gray+s+s, + gold+s+s+s+s+gray+s, + gold+s+s+s+s+s}; + for(int i=0; i<linesDung.length; i++) { + String line = linesDung[i]; + if(i == dungeonFilter) { + line = selPrefix + line.replace(gray, EnumChatFormatting.DARK_AQUA.toString()); + } else { + line = unselPrefix + line; + } + lore.add(line); + } + lore.add(""); + lore.add(EnumChatFormatting.AQUA + "Right-Click to go backwards!"); + lore.add(EnumChatFormatting.YELLOW + "Click to switch sort!"); + return lore; case 1: lore.add(""); String[] linesSort = {"Highest Bid","Lowest Bid","Ending soon"}; @@ -867,6 +1025,12 @@ public class CustomAH extends Gui { case 8: lore.add(""); lore.add("Current aucid: " + currentAucId); + if(currentAucId != null) { + APIManager.Auction auc = manager.auctionManager.getAuctionItems().get(currentAucId); + if(auc != null) { + lore.add("Current auc category: " + auc.category); + } + } lore.add(" --- Processing"); lore.add("Page Process Millis: " + manager.auctionManager.processMillis); lore.add(" --- Auction Stats"); @@ -887,6 +1051,10 @@ public class CustomAH extends Gui { } public void handleMouseInput() { + if(!manager.config.neuAuctionHouse.value) { + return; + } + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); int width = scaledResolution.getScaledWidth(); int height = scaledResolution.getScaledHeight(); @@ -907,14 +1075,16 @@ public class CustomAH extends Gui { mouseClickMove(mouseX, mouseY, this.eventButton, l); } - int dWheel = Mouse.getEventDWheel(); - dWheel = Math.max(-1, Math.min(1, dWheel)); + if(!manager.config.disableAhScroll.value) { + int dWheel = Mouse.getEventDWheel(); + dWheel = Math.max(-1, Math.min(1, dWheel)); - scrollAmount = scrollAmount - dWheel/(float)(auctionIds.size()/9-(5+splits)); - scrollAmount = Math.max(0, Math.min(1, scrollAmount)); + scrollAmount = scrollAmount - dWheel/(float)(auctionIds.size()/9-(5+splits)); + scrollAmount = Math.max(0, Math.min(1, scrollAmount)); + } } - private String niceAucId(String aucId) { + public String niceAucId(String aucId) { if(aucId.length()!=32) return aucId; StringBuilder niceAucId = new StringBuilder(); @@ -976,6 +1146,14 @@ public class CustomAH extends Gui { } } + if(dungeonFilter > DUNGEON_FILTER_ALL) { + if(dungeonFilter == DUNGEON_FILTER_DUNGEON && auc.dungeonTier < 0) { + match = false; + } else { + match &= dungeonFilter == auc.dungeonTier+1; + } + } + return match; } @@ -1032,116 +1210,125 @@ public class CustomAH extends Gui { return matches; } + private ExecutorService es = Executors.newSingleThreadExecutor(); public void updateSearch() { - if(searchField == null || priceField == null) init(); - - /*if(searchField.getText().length() > 0 && searchField.getText().length() <= 2 && - System.currentTimeMillis() - lastSearchFieldUpdate < 200) { - shouldUpdateSearch = true; - return; - }*/ - - if(System.currentTimeMillis() - lastUpdateSearch < 500) { - shouldUpdateSearch = true; + if(!manager.config.neuAuctionHouse.value) { return; } - lastUpdateSearch = System.currentTimeMillis(); - shouldUpdateSearch = false; + if(searchField == null || priceField == null) init(); + long currentTime = System.currentTimeMillis(); - scrollAmount = 0; - try { - auctionIds.clear(); - if(filterMyAuctions) { - for(String aucid : manager.auctionManager.getPlayerBids()) { - APIManager.Auction auc = manager.auctionManager.getAuctionItems().get(aucid); - if(doesAucMatch(auc)) { - auctionIds.add(aucid); - } - } - } else if(searchField.getText().length() == 0) { - for(Map.Entry<String, APIManager.Auction> entry : manager.auctionManager.getAuctionItems().entrySet()) { - if(doesAucMatch(entry.getValue())) { - auctionIds.add(entry.getKey()); - } - } - } else { - String query = searchField.getText(); - Set<String> dontMatch = new HashSet<>(); + es.submit(() -> { + if(currentTime - lastUpdateSearch < 100) { + shouldUpdateSearch = true; + return; + } + + lastUpdateSearch = currentTime; + shouldUpdateSearch = false; - HashSet<String> allMatch = new HashSet<>(); - if(query.contains("!")) { //only used for inverted queries, so dont need to populate unless ! in query + scrollAmount = 0; + try { + HashSet<String> auctionIdsNew = new HashSet<>(); + auctionIdsNew.clear(); + if(filterMyAuctions) { + for(String aucid : manager.auctionManager.getPlayerBids()) { + APIManager.Auction auc = manager.auctionManager.getAuctionItems().get(aucid); + if(doesAucMatch(auc)) { + auctionIdsNew.add(aucid); + } + } + } else if(searchField.getText().length() == 0) { for(Map.Entry<String, APIManager.Auction> entry : manager.auctionManager.getAuctionItems().entrySet()) { if(doesAucMatch(entry.getValue())) { - allMatch.add(entry.getKey()); - } else { - dontMatch.add(entry.getKey()); + auctionIdsNew.add(entry.getKey()); } } - } - - boolean invert = false; - - StringBuilder query2 = new StringBuilder(); - char lastOp = '|'; - for(char c : query.toCharArray()) { - if(query2.toString().trim().isEmpty() && c == '!') { - invert = true; - } else if(c == '|' || c == '&') { - if(lastOp == '|') { - HashSet<String> result = search(query2.toString(), dontMatch); - if(!invert) { - auctionIds.addAll(result); - } else { - HashSet<String> allClone = (HashSet<String>) allMatch.clone(); - allClone.removeAll(result); - auctionIds.addAll(allClone); - } - } else if(lastOp == '&') { - HashSet<String> result = search(query2.toString(), dontMatch); - if(!invert) { - auctionIds.retainAll(result); + } else { + String query = searchField.getText(); + Set<String> dontMatch = new HashSet<>(); + + HashSet<String> allMatch = new HashSet<>(); + if(query.contains("!")) { //only used for inverted queries, so dont need to populate unless ! in query + for(Map.Entry<String, APIManager.Auction> entry : manager.auctionManager.getAuctionItems().entrySet()) { + if(doesAucMatch(entry.getValue())) { + allMatch.add(entry.getKey()); } else { - auctionIds.removeAll(result); + dontMatch.add(entry.getKey()); } } - - query2 = new StringBuilder(); - invert = false; - lastOp = c; - } else { - query2.append(c); } - } - if(lastOp == '|') { - HashSet<String> result = search(query2.toString(), dontMatch); - if(!invert) { - auctionIds.addAll(result); - } else { - HashSet<String> allClone = (HashSet<String>) allMatch.clone(); - allClone.removeAll(result); - auctionIds.addAll(allClone); + + boolean invert = false; + + StringBuilder query2 = new StringBuilder(); + char lastOp = '|'; + for(char c : query.toCharArray()) { + if(query2.toString().trim().isEmpty() && c == '!') { + invert = true; + } else if(c == '|' || c == '&') { + if(lastOp == '|') { + HashSet<String> result = search(query2.toString(), dontMatch); + if(!invert) { + auctionIdsNew.addAll(result); + } else { + HashSet<String> allClone = (HashSet<String>) allMatch.clone(); + allClone.removeAll(result); + auctionIdsNew.addAll(allClone); + } + } else if(lastOp == '&') { + HashSet<String> result = search(query2.toString(), dontMatch); + if(!invert) { + auctionIdsNew.retainAll(result); + } else { + auctionIdsNew.removeAll(result); + } + } + + query2 = new StringBuilder(); + invert = false; + lastOp = c; + } else { + query2.append(c); + } } - } else if(lastOp == '&') { - HashSet<String> result = search(query2.toString(), dontMatch); - if(!invert) { - auctionIds.retainAll(result); - } else { - auctionIds.removeAll(result); + if(lastOp == '|') { + HashSet<String> result = search(query2.toString(), dontMatch); + if(!invert) { + auctionIdsNew.addAll(result); + } else { + HashSet<String> allClone = (HashSet<String>) allMatch.clone(); + allClone.removeAll(result); + auctionIdsNew.addAll(allClone); + } + } else if(lastOp == '&') { + HashSet<String> result = search(query2.toString(), dontMatch); + if(!invert) { + auctionIdsNew.retainAll(result); + } else { + auctionIdsNew.removeAll(result); + } } } + auctionIds = auctionIdsNew; + sortItems(); + } catch(Exception e) { + shouldUpdateSearch = true; } - sortItems(); - } catch(Exception e) { - shouldUpdateSearch = true; - } + }); } public void sortItems() throws ConcurrentModificationException { + if(!manager.config.neuAuctionHouse.value) { + return; + } + try { - sortedAuctionIds.clear(); - sortedAuctionIds.addAll(auctionIds); - sortedAuctionIds.sort((o1, o2) -> { + List<String> sortedAuctionIdsNew = new ArrayList<>(); + + sortedAuctionIdsNew.addAll(auctionIds); + sortedAuctionIdsNew.sort((o1, o2) -> { APIManager.Auction auc1 = manager.auctionManager.getAuctionItems().get(o1); APIManager.Auction auc2 = manager.auctionManager.getAuctionItems().get(o2); @@ -1176,12 +1363,18 @@ public class CustomAH extends Gui { } return o1.compareTo(o2); }); + + sortedAuctionIds = sortedAuctionIdsNew; } catch(Exception e) { shouldSortItems = true; } } public boolean keyboardInput() { + if(!manager.config.neuAuctionHouse.value) { + return false; + } + Keyboard.enableRepeatEvents(true); if(isEditingPrice() && Keyboard.getEventKey() == Keyboard.KEY_RETURN) { Minecraft.getMinecraft().displayGuiScreen(null); @@ -1236,7 +1429,11 @@ public class CustomAH extends Gui { } protected void mouseClicked(int mouseX, int mouseY, int mouseButton) { + boolean wasFocused = searchField.isFocused(); searchField.mouseClicked(mouseX, mouseY, mouseButton); + if(mouseButton == 1 && !wasFocused && searchField.isFocused()) { + searchField.setText(""); + } priceField.mouseClicked(mouseX, mouseY, mouseButton); int totalItems = auctionIds.size(); @@ -1285,7 +1482,15 @@ public class CustomAH extends Gui { int index = offset/18; boolean rightClicked = Mouse.getEventButton() == 1; switch(index) { - case 0: break; + case 0: + if(rightClicked) { + dungeonFilter--; + if(dungeonFilter < DUNGEON_FILTER_ALL) dungeonFilter = DUNGEON_FILTER_5; + } else { + dungeonFilter++; + if(dungeonFilter > DUNGEON_FILTER_5) dungeonFilter = DUNGEON_FILTER_ALL; + } + break; case 1: if(rightClicked) { sortMode--; @@ -1350,7 +1555,16 @@ public class CustomAH extends Gui { if(containerName.trim().equals("Auction View") || containerName.trim().equals("BIN Auction View")) { if(mouseX > guiLeft+getXSize()+4+31 && mouseX < guiLeft+getXSize()+4+31+16) { boolean leftFiller = isGuiFiller(auctionView.inventorySlots.getSlot(29).getStack());//isBin - if(mouseY > guiTop+100 && mouseY < guiTop+100+16) { + if(mouseY > guiTop+35 && mouseY < guiTop+35+16) { + ItemStack topStack = auctionView.inventorySlots.getSlot(13).getStack(); + if(topStack != null) { + String line = findStrStart(topStack, EnumChatFormatting.GRAY+"Seller: "); + String[] split = line.split(" "); + String seller = split[split.length-1]; + StringSelection selection = new StringSelection(seller); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection); + } + } else if(mouseY > guiTop+100 && mouseY < guiTop+100+16) { int slotClick = leftFiller ? 31 : 29; Minecraft.getMinecraft().playerController.windowClick(auctionView.inventorySlots.windowId, slotClick, 2, 3, Minecraft.getMinecraft().thePlayer); @@ -1371,11 +1585,13 @@ public class CustomAH extends Gui { Utils.playPressSound(); } } - } else if(containerName.trim().equals("Confirm Bid")) { + } else if(containerName.trim().equals("Confirm Bid") || containerName.trim().equals("Confirm Purchase")) { if(mouseX > guiLeft+getXSize()+4+31 && mouseX < guiLeft+getXSize()+4+31+16) { if(mouseY > guiTop+31 && mouseY < guiTop+31+16) { if(currentAucId != null) { manager.auctionManager.getPlayerBids().add(currentAucId); + latestBid = currentAucId; + latestBidMillis = System.currentTimeMillis(); //reset timer to 2m if below if(manager.auctionManager.getAuctionItems().get(currentAucId).end - System.currentTimeMillis() < 2*60*1000) { @@ -1444,6 +1660,7 @@ public class CustomAH extends Gui { aucid = sortedAuctionIds.get(id); } catch (IndexOutOfBoundsException e) { break out; } + if(aucid == null) continue; APIManager.Auction auc = manager.auctionManager.getAuctionItems().get(aucid); if(auc != null) { if(mouseX > itemX && mouseX < itemX+16) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/SimpleCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/SimpleCommand.java index ae27be46..029e24db 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/commands/SimpleCommand.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/SimpleCommand.java @@ -3,21 +3,36 @@ package io.github.moulberry.notenoughupdates.commands; import net.minecraft.command.CommandBase; import net.minecraft.command.CommandException; import net.minecraft.command.ICommandSender; +import net.minecraft.util.BlockPos; + +import java.util.ArrayList; +import java.util.List; public class SimpleCommand extends CommandBase { private String commandName; private ProcessCommandRunnable runnable; + private TabCompleteRunnable tabRunnable; public SimpleCommand(String commandName, ProcessCommandRunnable runnable) { this.commandName = commandName; this.runnable = runnable; } + public SimpleCommand(String commandName, ProcessCommandRunnable runnable, TabCompleteRunnable tabRunnable) { + this.commandName = commandName; + this.runnable = runnable; + this.tabRunnable = tabRunnable; + } + public abstract static class ProcessCommandRunnable { public abstract void processCommand(ICommandSender sender, String[] args); } + public abstract static class TabCompleteRunnable { + public abstract List<String> tabComplete(ICommandSender sender, String[] args, BlockPos pos); + } + public boolean canCommandSenderUseCommand(ICommandSender sender) { return true; } @@ -33,4 +48,9 @@ public class SimpleCommand extends CommandBase { public void processCommand(ICommandSender sender, String[] args) throws CommandException { runnable.processCommand(sender, args); } + + public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) { + if(tabRunnable != null) return tabRunnable.tabComplete(sender, args, pos); + return null; + } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java index 331ba8b1..fa1db64e 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java @@ -1,7 +1,10 @@ package io.github.moulberry.notenoughupdates.cosmetics; +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.util.HypixelApi; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.client.event.RenderPlayerEvent; @@ -11,6 +14,7 @@ import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.tuple.MutablePair; import org.apache.commons.lang3.tuple.Pair; +import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Set; @@ -18,28 +22,108 @@ import java.util.Set; public class CapeManager { public static final CapeManager INSTANCE = new CapeManager(); + public long lastCapeUpdate = 0; + public long lastCapeSynced = 0; + public Pair<NEUCape, String> localCape = null; private HashMap<String, Pair<NEUCape, String>> capeMap = new HashMap<>(); - private String[] capes = new String[]{"testcape", "nullzee", "gravy", "fade", "contrib"}; + + private int permSyncTries = 5; + private boolean allAvailable = false; + private HashSet<String> availableCapes = new HashSet<>(); + + private String[] capes = new String[]{"patreon1", "patreon2", "fade", "contrib", "nullzee", "gravy", "space", "mcworld", "lava", "packshq", "mbstaff" }; + public Boolean[] specialCapes = new Boolean[]{ true, true, false, true, true, true, false, false, true, true, true }; public static CapeManager getInstance() { return INSTANCE; } - public void setCape(String player, String capename) { - if(capename == null) { - NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value = ""; - capeMap.remove(player); - return; + public void tick() { + long currentTime = System.currentTimeMillis(); + if(currentTime - lastCapeUpdate > 60*1000) { + lastCapeUpdate = currentTime; + updateCapes(); } - if(player.equalsIgnoreCase(Minecraft.getMinecraft().thePlayer.getName())) { - NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value = capename; + } + + private void updateCapes() { + NotEnoughUpdates.INSTANCE.manager.hypixelApi.getMyApiAsync("activecapes.json", (jsonObject) -> { + if(jsonObject.get("success").getAsBoolean()) { + lastCapeSynced = System.currentTimeMillis(); + capeMap.clear(); + for(JsonElement active : jsonObject.get("active").getAsJsonArray()) { + if(active.isJsonObject()) { + JsonObject activeObj = (JsonObject) active; + setCape(activeObj.get("_id").getAsString(), activeObj.get("capeType").getAsString(), false); + } + } + } + }, () -> { + System.out.println("[MBAPI] Update capes errored"); + }); + + if(Minecraft.getMinecraft().thePlayer != null && permSyncTries > 0) { + String uuid = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""); + permSyncTries--; + NotEnoughUpdates.INSTANCE.manager.hypixelApi.getMyApiAsync("permscapes.json", (jsonObject) -> { + if(jsonObject.get("success").getAsBoolean()) { + permSyncTries = 0; + + availableCapes.clear(); + for(JsonElement permPlayer : jsonObject.get("perms").getAsJsonArray()) { + if(permPlayer.isJsonObject()) { + String playerUuid = permPlayer.getAsJsonObject().get("_id").getAsString(); + if(playerUuid != null && playerUuid.equals(uuid)) { + for(JsonElement perm : permPlayer.getAsJsonObject().get("perms").getAsJsonArray()) { + if(perm.isJsonPrimitive()) { + String cape = perm.getAsString(); + if(cape.equals("*")) { + allAvailable = true; + } else { + availableCapes.add(cape); + } + } + } + return; + } + } + } + } + }, () -> { + System.out.println("[MBAPI] Update capes errored - perms"); + }); } - if(capeMap.containsKey(player)) { - Pair<NEUCape, String> capePair = capeMap.get(player); - capePair.setValue(capename); - } else { - capeMap.put(player, new MutablePair<>(new NEUCape(capename), capename)); + } + + public HashSet<String> getAvailableCapes() { + return allAvailable ? null : availableCapes; + } + + public void setCape(String playerUUID, String capename, boolean updateConfig) { + boolean none = capename == null || capename.equals("null"); + + updateConfig = updateConfig && playerUUID.equals(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", "")); + if(updateConfig) { + NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value = String.valueOf(capename); + try { NotEnoughUpdates.INSTANCE.manager.saveConfig(); } catch(IOException ignored) {} + } + + if(updateConfig) { + if(none) { + localCape = null; + } else { + localCape = new MutablePair<>(new NEUCape(capename), capename); + } + } else if(capeMap.containsKey(playerUUID)) { + if(none) { + capeMap.remove(playerUUID); + } else { + Pair<NEUCape, String> capePair = capeMap.get(playerUUID); + capePair.setValue(capename); + } + } else if(!none) { + capeMap.put(playerUUID, new MutablePair<>(new NEUCape(capename), capename)); } } @@ -50,10 +134,10 @@ public class CapeManager { return null; } - public EntityPlayer getPlayerForName(String name) { + public EntityPlayer getPlayerForUUID(String uuid) { if(Minecraft.getMinecraft().theWorld != null) { for(EntityPlayer player : Minecraft.getMinecraft().theWorld.playerEntities) { - if(player.getName().equals(name)) { + if(player.getUniqueID().toString().replace("-", "").equals(uuid)) { return player; } } @@ -64,34 +148,56 @@ public class CapeManager { @SubscribeEvent public void onRenderPlayer(RenderPlayerEvent.Post e) { if(e.partialRenderTick == 1.0F) return; //rendering in inventory - if(e.entityPlayer == Minecraft.getMinecraft().thePlayer) { - if(NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value != null && - !NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value.isEmpty()) { - setCape(Minecraft.getMinecraft().thePlayer.getName(), - NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value); + + String uuid = e.entityPlayer.getUniqueID().toString().replace("-", ""); + String clientUuid = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""); + + if(Minecraft.getMinecraft().thePlayer != null && uuid.equals(clientUuid)) { + String selCape = NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value; + if(selCape != null && !selCape.isEmpty()) { + if(localCape == null) { + localCape = new MutablePair<>(new NEUCape(selCape), selCape); + } else { + localCape.setValue(selCape); + } } } - if(capeMap.containsKey(e.entityPlayer.getName())) { - capeMap.get(e.entityPlayer.getName()).getLeft().onRenderPlayer(e); + if(uuid.equals(clientUuid) && localCape != null && localCape.getRight() != null && !localCape.getRight().equals("null")) { + localCape.getLeft().onRenderPlayer(e); + } else if(capeMap.containsKey(uuid)) { + capeMap.get(uuid).getLeft().onRenderPlayer(e); } } @SubscribeEvent public void onTick(TickEvent.ClientTickEvent event) { + String clientUuid = null; + if(Minecraft.getMinecraft().thePlayer != null) { + clientUuid = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""); + } + Set<String> toRemove = new HashSet<>(); - for(String playerName : capeMap.keySet()) { - EntityPlayer player = getPlayerForName(playerName); - if(player == null) { - toRemove.add(playerName); - } else { - String capeName = capeMap.get(playerName).getRight(); - if(capeName != null) { - capeMap.get(playerName).getLeft().setCapeTexture(capeName); - capeMap.get(playerName).getLeft().onTick(event, player); - } else { - toRemove.add(playerName); + try { + for(String playerUUID : capeMap.keySet()) { + EntityPlayer player = getPlayerForUUID(playerUUID); + if(player != null) { + String capeName = capeMap.get(playerUUID).getRight(); + if(capeName != null && !capeName.equals("null")) { + if(playerUUID.equals(clientUuid) && localCape != null && localCape.getRight() != null && !localCape.getRight().equals("null")) { + continue; + } + capeMap.get(playerUUID).getLeft().setCapeTexture(capeName); + capeMap.get(playerUUID).getLeft().onTick(event, player); + } else { + toRemove.add(playerUUID); + } } } + } catch(Exception e) {} + + if(localCape != null) { + localCape.getLeft().setCapeTexture(localCape.getValue()); + localCape.getLeft().onTick(event, Minecraft.getMinecraft().thePlayer); } for(String playerName : toRemove) { capeMap.remove(playerName); @@ -102,22 +208,6 @@ public class CapeManager { return capes; } - private String[] contributors = new String[]{"thatgravyboat", "twasnt", "traxyrr", "some1sm", "meguminqt", "marethyu_77"}; - - public boolean getPermissionForCape(String player, String capename) { - if(capename == null) { - return false; - } else if(player.equalsIgnoreCase("Moulberry")) { - return true; //Oh yeah gimme gimme - } else { - switch(capename) { - case "nullzee": return player.equalsIgnoreCase("Nullzee"); - case "gravy": return player.equalsIgnoreCase("ThatGravyBoat"); - case "contrib": return ArrayUtils.contains(contributors, player.toLowerCase()); - case "fade": return true; - } - } - return false; - } + //private String[] contributors = new String[]{"thatgravyboat", "twasnt", "traxyrr", "some1sm", "meguminqt", "marethyu_77"}; } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeNode.java b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeNode.java index 1ec2dee3..bfd33e48 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeNode.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeNode.java @@ -45,8 +45,8 @@ public class CapeNode { public float vertSideTexU = 0; public float vertSideTexVTop = 0; - public static final float gravity = 0.1f; - public static final float resistance = 0.5f; + public final float gravity = 0.1f; + public final float resistance = 0.5f; public static final int FLOAT_NUM = 20; @@ -110,14 +110,14 @@ public class CapeNode { velocity.y -= gravity * (resistance)/(1-resistance); float actualResistance = resistance; - BlockPos pos = new BlockPos( + /*BlockPos pos = new BlockPos( MathHelper.floor_double(position.x), MathHelper.floor_double(position.y), MathHelper.floor_double(position.z)); Block block = Minecraft.getMinecraft().theWorld.getBlockState(pos).getBlock(); if(block.getMaterial().isLiquid()) { actualResistance = 0.8f; - } + }*/ velocity.scale(1-actualResistance); @@ -160,8 +160,6 @@ public class CapeNode { } public void resolve(CapeNode other, float targetDist, float strength, boolean opt) { - if(other == null || Keyboard.isKeyDown(Keyboard.KEY_H)) return; - double dX = position.x - other.position.x; double dY = position.y - other.position.y; double dZ = position.z - other.position.z; @@ -209,7 +207,7 @@ public class CapeNode { NEUCape.Offset o = new NEUCape.Offset(d, 1); CapeNode neighbor = getNeighbor(o); if(neighbor != null) { - if(!Keyboard.isKeyDown(Keyboard.KEY_H))resolve(neighbor, 1f*NEUCape.targetDist*(d.yOff==0?horzDistMult:1f), 0.5f*7.5f, opt); + resolve(neighbor, 1f*NEUCape.targetDist*(d.yOff==0?horzDistMult:1f), 0.5f*7.5f, opt); } } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/GuiCosmetics.java b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/GuiCosmetics.java new file mode 100644 index 00000000..4723d00f --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/GuiCosmetics.java @@ -0,0 +1,501 @@ +package io.github.moulberry.notenoughupdates.cosmetics; + +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.client.shader.Shader; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.Matrix4f; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; + +import java.awt.*; +import java.util.List; +import java.util.*; + +public class GuiCosmetics extends GuiScreen { + + public static final ResourceLocation pv_bg = new ResourceLocation("notenoughupdates:pv_bg.png"); + public static final ResourceLocation pv_dropdown = new ResourceLocation("notenoughupdates:pv_dropdown.png"); + public static final ResourceLocation cosmetics_fg = new ResourceLocation("notenoughupdates:cosmetics_fg.png"); + public static final ResourceLocation pv_elements = new ResourceLocation("notenoughupdates:pv_elements.png"); + + private CosmeticsPage currentPage = CosmeticsPage.CAPES; + private int sizeX; + private int sizeY; + private int guiLeft; + private int guiTop; + + private String wantToEquipCape = null; + private long lastCapeEquip = 0; + + private List<String> tooltipToDisplay = null; + + public enum CosmeticsPage { + CAPES(new ItemStack(Items.chainmail_chestplate)); + + public final ItemStack stack; + + CosmeticsPage(ItemStack stack) { + this.stack = stack; + } + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + this.sizeX = 431; + this.sizeY = 202; + this.guiLeft = (this.width-this.sizeX)/2; + this.guiTop = (this.height-this.sizeY)/2; + + super.drawScreen(mouseX, mouseY, partialTicks); + drawDefaultBackground(); + + blurBackground(); + renderBlurredBackground(width, height, guiLeft+2, guiTop+2, sizeX-4, sizeY-4); + + GlStateManager.enableDepth(); + GlStateManager.translate(0, 0, 5); + renderTabs(true); + GlStateManager.translate(0, 0, -3); + + GlStateManager.disableDepth(); + GlStateManager.translate(0, 0, -2); + renderTabs(false); + GlStateManager.translate(0, 0, 2); + + GlStateManager.disableLighting(); + GlStateManager.enableDepth(); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.enableAlpha(); + GlStateManager.alphaFunc(516, 0.1F); + + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_bg); + Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST); + + GlStateManager.color(1, 1, 1, 1); + switch (currentPage) { + case CAPES: + drawCapesPage(mouseX, mouseY, partialTicks); + break; + } + + if(tooltipToDisplay != null) { + List<String> grayTooltip = new ArrayList<>(tooltipToDisplay.size()); + for(String line : tooltipToDisplay) { + grayTooltip.add(EnumChatFormatting.GRAY + line); + } + Utils.drawHoveringText(grayTooltip, mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj); + tooltipToDisplay = null; + } + + StringBuilder statusMsg = new StringBuilder("Last Sync: "); + if(CapeManager.INSTANCE.lastCapeSynced == 0) { + statusMsg.append("Not Synced"); + } else { + statusMsg.append((System.currentTimeMillis() - CapeManager.INSTANCE.lastCapeSynced)/1000).append("s ago"); + } + statusMsg.append(" - Next Sync: "); + if(CapeManager.INSTANCE.lastCapeUpdate == 0) { + statusMsg.append("ASAP"); + } else { + statusMsg.append(60 - (System.currentTimeMillis() - CapeManager.INSTANCE.lastCapeUpdate)/1000).append("s"); + } + + Minecraft.getMinecraft().fontRendererObj.drawString(EnumChatFormatting.AQUA+statusMsg.toString(), + guiLeft+sizeX-Minecraft.getMinecraft().fontRendererObj.getStringWidth(statusMsg.toString()), guiTop-12, 0, true); + + if(currentPage == CosmeticsPage.CAPES) { + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_dropdown); + Utils.drawTexturedRect(guiLeft+sizeX/2f-50, guiTop+sizeY+5, 100, 20, 0, 100/200f, 0, 20/185f, GL11.GL_NEAREST); + + String equipMsg; + if(wantToEquipCape != null) { + equipMsg = EnumChatFormatting.GREEN + "Equip Cape"; + if(System.currentTimeMillis() - lastCapeEquip < 20*1000) { + equipMsg += " - " + (20 - (System.currentTimeMillis() - lastCapeEquip)/1000) + "s"; + } + } else { + equipMsg = EnumChatFormatting.GREEN + "Unequip"; + if(System.currentTimeMillis() - lastCapeEquip < 20*1000) { + equipMsg += " - " + (20 - (System.currentTimeMillis() - lastCapeEquip)/1000) + "s"; + } + } + + Utils.drawStringCenteredScaledMaxWidth(equipMsg, Minecraft.getMinecraft().fontRendererObj, + guiLeft+sizeX/2f, guiTop+sizeY+5+10, false, 90, 0); + } + } + + private void renderTabs(boolean renderPressed) { + int ignoredTabs = 0; + for(int i = 0; i< CosmeticsPage.values().length; i++) { + CosmeticsPage page = CosmeticsPage.values()[i]; + if(page.stack == null) { + ignoredTabs++; + continue; + } + boolean pressed = page == currentPage; + if(pressed == renderPressed) { + renderTab(page.stack, i-ignoredTabs, pressed); + } + } + } + + private void renderTab(ItemStack stack, int xIndex, boolean pressed) { + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.enableAlpha(); + GlStateManager.alphaFunc(516, 0.1F); + + int x = guiLeft+xIndex*28; + int y = guiTop-28; + + float uMin = 0; + float uMax = 28/256f; + float vMin = 20/256f; + float vMax = 51/256f; + if(pressed) { + vMin = 52/256f; + vMax = 84/256f; + + if(xIndex != 0) { + uMin = 28/256f; + uMax = 56/256f; + } + + renderBlurredBackground(width, height, x+2, y+2, 28-4, 28-4); + } else { + renderBlurredBackground(width, height, x+2, y+4, 28-4, 28-4); + } + + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.enableAlpha(); + GlStateManager.alphaFunc(516, 0.1F); + + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); + Utils.drawTexturedRect(x, y, 28, pressed?32:31, uMin, uMax, vMin, vMax, GL11.GL_NEAREST); + + GlStateManager.enableDepth(); + Utils.drawItemStack(stack, x+6, y+9); + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) { + for (int i = 0; i < CosmeticsPage.values().length; i++) { + CosmeticsPage page = CosmeticsPage.values()[i]; + int x = guiLeft + i * 28; + int y = guiTop - 28; + + if (mouseX > x && mouseX < x + 28) { + if (mouseY > y && mouseY < y + 32) { + if (currentPage != page) Utils.playPressSound(); + currentPage = page; + return; + } + } + } + if(mouseY > guiTop+177 && mouseY < guiTop+177+12) { + if(mouseX > guiLeft+15+371*scroll && mouseX < guiLeft+15+371*scroll+32) { + scrollClickedX = mouseX - (int)(guiLeft+15+371*scroll); + return; + } + } + + int index = 0; + int displayingCapes = 0; + for(String cape : CapeManager.INSTANCE.getCapes()) { + boolean equipable = CapeManager.INSTANCE.getAvailableCapes() == null || CapeManager.INSTANCE.getAvailableCapes().contains(cape); + if (!CapeManager.INSTANCE.specialCapes[index++] || equipable) { + displayingCapes++; + } + } + + float totalNeeded = 91*displayingCapes; + float totalAvail = sizeX-20; + float xOffset = scroll*(totalNeeded-totalAvail); + + index = 0; + int displayIndex = 0; + for(String cape : CapeManager.INSTANCE.getCapes()) { + boolean equipable = CapeManager.INSTANCE.getAvailableCapes() == null || CapeManager.INSTANCE.getAvailableCapes().contains(cape); + if(CapeManager.INSTANCE.specialCapes[index++] && !equipable) continue; + + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(guiLeft + 20 + 91 * displayIndex - xOffset, guiTop + 123, 81, 20, + 0, 81 / 256f, 216 / 256f, 236 / 256f, GL11.GL_NEAREST); + + if(mouseX > guiLeft + 20 + 91 * displayIndex - xOffset && mouseX < guiLeft + 20 + 91 * displayIndex - xOffset+81) { + if(mouseY > guiTop + 123 && mouseY < guiTop + 123 + 20) { + if(CapeManager.INSTANCE.localCape != null && CapeManager.INSTANCE.localCape.getRight().equals(cape)) { + CapeManager.INSTANCE.setCape(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""), + "null", true); + } else { + CapeManager.INSTANCE.setCape(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""), + cape, true); + } + + return; + } else if(equipable && mouseY > guiTop + 149 && mouseY < guiTop + 149 + 20) { + if(cape.equals(wantToEquipCape)) { + wantToEquipCape = null; + } else { + wantToEquipCape = cape; + } + return; + } + } + + displayIndex++; + } + + if(currentPage == CosmeticsPage.CAPES) { + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_dropdown); + Utils.drawTexturedRect(guiLeft+sizeX/2f-50, guiTop+sizeY+5, 100, 20, 0, 100/200f, 0, 20/185f, GL11.GL_NEAREST); + + if(mouseX > guiLeft+sizeX/2f-50 && mouseX < guiLeft+sizeX/2f+50) { + if(mouseY > guiTop+sizeY+5 && mouseY < guiTop+sizeY+25) { + if(System.currentTimeMillis() - lastCapeEquip > 20*1000) { + CapeManager.INSTANCE.setCape(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""), + null, true); + + lastCapeEquip = System.currentTimeMillis(); + if(wantToEquipCape == null) { + NotEnoughUpdates.INSTANCE.manager.hypixelApi.getMyApiAsync("cgi-bin/changecape.py?capeType=null&accessToken="+ + Minecraft.getMinecraft().getSession().getToken(), (jsonObject) -> { System.out.println(jsonObject); }, () -> { + System.out.println("change cape error"); + }); + } else { + NotEnoughUpdates.INSTANCE.manager.hypixelApi.getMyApiAsync("cgi-bin/changecape.py?capeType="+wantToEquipCape+"&accessToken="+ + Minecraft.getMinecraft().getSession().getToken(), (jsonObject) -> { System.out.println(jsonObject); }, () -> { + System.out.println("change cape error"); + }); + } + } + } + } + } + } + + @Override + protected void mouseReleased(int mouseX, int mouseY, int state) { + super.mouseReleased(mouseX, mouseY, state); + + scrollClickedX = -1; + } + + @Override + protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) { + super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick); + + if(scrollClickedX >= 0) { + float scrollStartX = mouseX - scrollClickedX; + scroll = (scrollStartX-(guiLeft+15))/371f; + scroll = Math.max(0, Math.min(1, scroll)); + } + } + + private HashMap<String, ResourceLocation> capesLocation = new HashMap<>(); + private float scroll = 0f; + private int scrollClickedX = -1; + private void drawCapesPage(int mouseX, int mouseY, float partialTicks) { + Minecraft.getMinecraft().getTextureManager().bindTexture(cosmetics_fg); + Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); + Utils.drawTexturedRect(guiLeft+15+371*scroll, guiTop+177, 32, 12, + 0, 32/256f, 192/256f, 204/256f, GL11.GL_NEAREST); + + GL11.glEnable(GL11.GL_SCISSOR_TEST); + GL11.glScissor(Minecraft.getMinecraft().displayWidth*(guiLeft+3)/width, 0, + Minecraft.getMinecraft().displayWidth*(sizeX-6)/width, Minecraft.getMinecraft().displayHeight); + + int index = 0; + int displayingCapes = 0; + for(String cape : CapeManager.INSTANCE.getCapes()) { + boolean equipable = CapeManager.INSTANCE.getAvailableCapes() == null || CapeManager.INSTANCE.getAvailableCapes().contains(cape); + if (!CapeManager.INSTANCE.specialCapes[index++] || equipable) { + displayingCapes++; + } + } + + float totalNeeded = 91*displayingCapes; + float totalAvail = sizeX-20; + float xOffset = scroll*(totalNeeded-totalAvail); + + index = 0; + int displayIndex = 0; + for(String cape : CapeManager.INSTANCE.getCapes()) { + boolean equipable = CapeManager.INSTANCE.getAvailableCapes() == null || CapeManager.INSTANCE.getAvailableCapes().contains(cape); + if(CapeManager.INSTANCE.specialCapes[index++] && !equipable) continue; + + if(cape.equals(CapeManager.INSTANCE.getCape(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", "")))) { + GlStateManager.color(250 / 255f, 200 / 255f, 0 / 255f, 1); + Utils.drawGradientRect(guiLeft + 20 + 91 * displayIndex - (int) xOffset, guiTop + 10, + guiLeft + 20 + 91 * displayIndex - (int) xOffset + 81, guiTop + 10 + 108, + new Color(150, 100, 0, 40).getRGB(), new Color(250, 200, 0, 40).getRGB()); + } else if(cape.equals(wantToEquipCape)) { + GlStateManager.color(0, 200 / 255f, 250 / 255f, 1); + Utils.drawGradientRect(guiLeft + 20 + 91 * displayIndex - (int) xOffset, guiTop + 10, + guiLeft + 20 + 91 * displayIndex - (int) xOffset + 81, guiTop + 10 + 108, + new Color(0, 100, 150, 40).getRGB(), new Color(0, 200, 250, 40).getRGB()); + } else if(CapeManager.INSTANCE.localCape != null && CapeManager.INSTANCE.localCape.getRight().equals(cape)) { + GlStateManager.color(100/255f, 250/255f, 150/255f, 1); + Utils.drawGradientRect(guiLeft+20+91*displayIndex-(int)xOffset, guiTop+10, + guiLeft+20+91*displayIndex-(int)xOffset+81, guiTop+10+108, + new Color(50, 100, 75, 40).getRGB(), new Color(100, 250, 150, 40).getRGB()); + } + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); + Utils.drawTexturedRect(guiLeft+20+91*displayIndex-xOffset, guiTop+10, 81, 108, + 0, 81/256f, 84/256f, 192/256f, GL11.GL_NEAREST); + GlStateManager.color(1, 1, 1, 1); + + Utils.drawTexturedRect(guiLeft+20+91*displayIndex-xOffset, guiTop+123, 81, 20, + 0, 81/256f, 216/256f, 236/256f, GL11.GL_NEAREST); + + boolean equipPressed = cape.equals(wantToEquipCape); + if(!equipable) GlStateManager.color(1, 1, 1, 0.5f); + Utils.drawTexturedRect(guiLeft+20+91*displayIndex-xOffset, guiTop+149, 81, 20, + equipPressed?81/256f:0, equipPressed?0:81/256f, equipPressed?236/256f:216/256f, equipPressed?216/256f:236/256f, GL11.GL_NEAREST); + + Utils.drawStringCenteredScaledMaxWidth("Try it out", Minecraft.getMinecraft().fontRendererObj, + guiLeft+20+91*displayIndex+81/2f-xOffset, guiTop+123+10, false, 75, new Color(100, 250, 150).getRGB()); + if(equipable) { + Utils.drawStringCenteredScaledMaxWidth("Equip", Minecraft.getMinecraft().fontRendererObj, + guiLeft+20+91*displayIndex+81/2f-xOffset, guiTop+149+10, false, 75, new Color(100, 250, 150).getRGB()); + } else { + Utils.drawStringCenteredScaledMaxWidth("Not Unlocked", Minecraft.getMinecraft().fontRendererObj, + guiLeft+20+91*displayIndex+81/2f-xOffset, guiTop+149+10, false, 75, new Color(200, 50, 50, 100).getRGB()); + } + GlStateManager.color(1, 1, 1, 1); + + ResourceLocation capeTexture = capesLocation.computeIfAbsent(cape, k -> new ResourceLocation("notenoughupdates", "capes/"+cape+".png")); + Minecraft.getMinecraft().getTextureManager().bindTexture(capeTexture); + Utils.drawTexturedRect(guiLeft+31+91*displayIndex-xOffset, guiTop+24, 59, 84, + 0, 293/1024f, 0, 420/1024f, GL11.GL_NEAREST); + + displayIndex++; + } + + GL11.glScissor(0, 0, Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight); + GL11.glDisable(GL11.GL_SCISSOR_TEST); + + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); + } + + Shader blurShaderHorz = null; + Framebuffer blurOutputHorz = null; + Shader blurShaderVert = null; + Framebuffer blurOutputVert = null; + + /** + * Creates a projection matrix that projects from our coordinate space [0->width; 0->height] to OpenGL coordinate + * space [-1 -> 1; 1 -> -1] (Note: flipped y-axis). + * + * This is so that we can render to and from the framebuffer in a way that is familiar to us, instead of needing to + * apply scales and translations manually. + */ + private Matrix4f createProjectionMatrix(int width, int height) { + Matrix4f projMatrix = new Matrix4f(); + projMatrix.setIdentity(); + projMatrix.m00 = 2.0F / (float)width; + projMatrix.m11 = 2.0F / (float)(-height); + projMatrix.m22 = -0.0020001999F; + projMatrix.m33 = 1.0F; + projMatrix.m03 = -1.0F; + projMatrix.m13 = 1.0F; + projMatrix.m23 = -1.0001999F; + return projMatrix; + } + + /** + * Renders whatever is currently in the Minecraft framebuffer to our two framebuffers, applying a horizontal + * and vertical blur separately in order to significantly save computation time. + * This is only possible if framebuffers are supported by the system, so this method will exit prematurely + * if framebuffers are not available. (Apple machines, for example, have poor framebuffer support). + */ + private double lastBgBlurFactor = -1; + private void blurBackground() { + int width = Minecraft.getMinecraft().displayWidth; + int height = Minecraft.getMinecraft().displayHeight; + + if(blurOutputHorz == null) { + blurOutputHorz = new Framebuffer(width, height, false); + blurOutputHorz.setFramebufferFilter(GL11.GL_NEAREST); + } + if(blurOutputVert == null) { + blurOutputVert = new Framebuffer(width, height, false); + blurOutputVert.setFramebufferFilter(GL11.GL_NEAREST); + } + if(blurOutputHorz.framebufferWidth != width || blurOutputHorz.framebufferHeight != height) { + blurOutputHorz.createBindFramebuffer(width, height); + blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + if(blurOutputVert.framebufferWidth != width || blurOutputVert.framebufferHeight != height) { + blurOutputVert.createBindFramebuffer(width, height); + blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height)); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + + if(blurShaderHorz == null) { + try { + blurShaderHorz = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", + Minecraft.getMinecraft().getFramebuffer(), blurOutputHorz); + blurShaderHorz.getShaderManager().getShaderUniform("BlurDir").set(1, 0); + blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); + } catch(Exception e) { } + } + if(blurShaderVert == null) { + try { + blurShaderVert = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", + blurOutputHorz, blurOutputVert); + blurShaderVert.getShaderManager().getShaderUniform("BlurDir").set(0, 1); + blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height)); + } catch(Exception e) { } + } + if(blurShaderHorz != null && blurShaderVert != null) { + if(15 != lastBgBlurFactor) { + blurShaderHorz.getShaderManager().getShaderUniform("Radius").set((float)15); + blurShaderVert.getShaderManager().getShaderUniform("Radius").set((float)15); + lastBgBlurFactor = 15; + } + GL11.glPushMatrix(); + blurShaderHorz.loadShader(0); + blurShaderVert.loadShader(0); + GlStateManager.enableDepth(); + GL11.glPopMatrix(); + + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + } + + /** + * Renders a subsection of the blurred framebuffer on to the corresponding section of the screen. + * Essentially, this method will "blur" the background inside the bounds specified by [x->x+blurWidth, y->y+blurHeight] + */ + public void renderBlurredBackground(int width, int height, int x, int y, int blurWidth, int blurHeight) { + float uMin = x/(float)width; + float uMax = (x+blurWidth)/(float)width; + float vMin = (height-y)/(float)height; + float vMax = (height-y-blurHeight)/(float)height; + + blurOutputVert.bindFramebufferTexture(); + GlStateManager.color(1f, 1f, 1f, 1f); + //Utils.setScreen(width*f, height*f, f); + Utils.drawTexturedRect(x, y, blurWidth, blurHeight, uMin, uMax, vMin, vMax); + //Utils.setScreen(width, height, f); + blurOutputVert.unbindFramebufferTexture(); + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java index 08d91057..d56a3f8c 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java @@ -10,6 +10,7 @@ import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.potion.Potion; import net.minecraft.util.BlockPos; import net.minecraft.util.MathHelper; import net.minecraft.util.ResourceLocation; @@ -26,16 +27,29 @@ import org.lwjgl.util.vector.Vector3f; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.security.Key; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; +import java.util.*; public class NEUCape { - public ResourceLocation capeTex = null; + private int currentFrame = 0; + private int displayFrame = 0; + private String capeName; + public ResourceLocation[] capeTextures = null; + + private long lastFrameUpdate = 0; + + private static int ANIM_MODE_LOOP = 0; + private static int ANIM_MODE_PINGPONG = 1; + private int animMode = ANIM_MODE_LOOP; private List<List<CapeNode>> nodes = null; + private Random random = new Random(); + + private long eventMillis; + private float eventLength; + private float eventRandom; + private static double vertOffset = 1.4; private static double shoulderLength = 0.24; private static double shoulderWidth = 0.13; @@ -45,6 +59,8 @@ public class NEUCape { public static float targetDist = 1/20f; + private EntityPlayer currentPlayer; + private String shaderName = "cape"; public NEUCape(String capeName) { @@ -52,14 +68,82 @@ public class NEUCape { } public void setCapeTexture(String capeName) { - if(capeTex == null || !capeTex.getResourcePath().equals(capeName+".png")) { - if(capeName.equalsIgnoreCase("fade")) { - shaderName = "fade_cape"; - } else { - shaderName = "cape"; + if(this.capeName != null && this.capeName.equalsIgnoreCase(capeName)) return; + this.capeName = capeName; + + startTime = System.currentTimeMillis(); + + if(capeName.equalsIgnoreCase("fade")) { + shaderName = "fade_cape"; + } else if(capeName.equalsIgnoreCase("space")) { + shaderName = "space_cape"; + } else if(capeName.equalsIgnoreCase("mcworld")) { + shaderName = "mcworld_cape"; + } else if(capeName.equalsIgnoreCase("lava")) { + shaderName = "lava_cape"; + } else if(capeName.equalsIgnoreCase("lightning")) { + shaderName = "lightning_cape"; + } else { + shaderName = "cape"; + } + + ResourceLocation staticCapeTex = new ResourceLocation("notenoughupdates:capes/"+capeName+".png"); + capeTextures = new ResourceLocation[1]; + capeTextures[0] = staticCapeTex; + + /*if(rlExists(staticCapeTex)) { + capeTextures = new ResourceLocation[1]; + capeTextures[0] = staticCapeTex; + } else { + List<ResourceLocation> texs = new ArrayList<>(); + for(int i=0; i<99; i++) { + ResourceLocation frame = new ResourceLocation( + "notenoughupdates:capes/"+capeName+"/"+capeName+"_"+String.format("%02d", i)+".png"); + if(rlExists(frame)) { + texs.add(frame); + } else { + break; + } + } + capeTextures = new ResourceLocation[texs.size()]; + for(int i=0; i<texs.size(); i++) { + capeTextures[i] = texs.get(i); } - capeTex = new ResourceLocation("notenoughupdates:"+capeName+".png"); - startTime = System.currentTimeMillis(); + }*/ + } + + private void bindTexture() { + if(capeTextures != null && capeTextures.length>0) { + long currentTime = System.currentTimeMillis(); + if(currentTime - lastFrameUpdate > 100) { + lastFrameUpdate = currentTime/100*100; + currentFrame++; + + if(animMode == ANIM_MODE_PINGPONG) { + if(capeTextures.length == 1) { + currentFrame = displayFrame = 0; + } else { + int frameCount = 2*capeTextures.length-2; + currentFrame %= frameCount; + displayFrame = currentFrame; + if(currentFrame >= capeTextures.length) { + displayFrame = frameCount - displayFrame; + } + } + } else if(animMode == ANIM_MODE_LOOP) { + currentFrame %= capeTextures.length; + displayFrame = currentFrame; + } + } + Minecraft.getMinecraft().getTextureManager().bindTexture(capeTextures[displayFrame]); + } + } + + public boolean rlExists(ResourceLocation loc) { + try { + return !Minecraft.getMinecraft().getResourceManager().getAllResources(loc).isEmpty(); + } catch(Exception e) { + return false; } } @@ -88,7 +172,7 @@ public class NEUCape { float centerMult = 1-Math.abs(j-(HORZ_NODES-1)/2f)/((HORZ_NODES-1)/2f);//0-(horzCapeNodes) -> 0-1-0 float vMax = vMaxSide + (vMaxCenter - vMaxSide) * centerMult; - CapeNode node = new CapeNode(0, 0, 0);//pX-1, pY+2-i*targetDist, pZ+(j-(horzCapeNodes-1)/2f)*targetDist*2 + CapeNode node = new CapeNode(pX, pY, pZ);//pX-1, pY+2-i*targetDist, pZ+(j-(horzCapeNodes-1)/2f)*targetDist*2 node.texU = uMin + (uMax - uMin) * j/(float)(HORZ_NODES-1); node.texV = vMin + (vMax - vMin) * i/(float)(VERT_NODES-1); @@ -216,6 +300,16 @@ public class NEUCape { private void loadShaderUniforms(ShaderManager shaderManager) { if(shaderName.equalsIgnoreCase("fade_cape")) { shaderManager.loadData(shaderName, "millis", (int)(System.currentTimeMillis()-startTime)); + } else if(shaderName.equalsIgnoreCase("space_cape")) { + shaderManager.loadData(shaderName, "millis", (int)(System.currentTimeMillis()-startTime)); + shaderManager.loadData(shaderName, "eventMillis", (int)(System.currentTimeMillis()-eventMillis)); + shaderManager.loadData(shaderName, "eventRand", eventRandom); + } else if(shaderName.equalsIgnoreCase("mcworld_cape")) { + shaderManager.loadData(shaderName, "millis", (int) (System.currentTimeMillis() - startTime)); + } else if(shaderName.equalsIgnoreCase("lava_cape")) { + shaderManager.loadData(shaderName, "millis", (int) (System.currentTimeMillis() - startTime)); + } else if(shaderName.equalsIgnoreCase("lightning_cape")) { + shaderManager.loadData(shaderName, "millis", (int) (System.currentTimeMillis() - startTime)); } } @@ -223,6 +317,11 @@ public class NEUCape { public void onRenderPlayer(RenderPlayerEvent.Post e) { EntityPlayer player = e.entityPlayer; + if(currentPlayer != null && currentPlayer != player) return; + + if(player.getActivePotionEffect(Potion.invisibility) != null) return; + if(player.isSpectator() || player.isInvisible()) return; + ensureCapeNodesCreated(player); Entity viewer = Minecraft.getMinecraft().getRenderViewEntity(); @@ -234,10 +333,19 @@ public class NEUCape { GlStateManager.enableBlend(); GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); - Minecraft.getMinecraft().getTextureManager().bindTexture(capeTex); + bindTexture(); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, 0x8191, GL11.GL_TRUE); GlStateManager.enableTexture2D(); GlStateManager.disableCull(); + if(shaderName.equals("mcworld_cape")) { + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + } else { + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + } + GL11.glTranslatef(-(float)viewerX, -(float)viewerY, -(float)viewerZ); ShaderManager shaderManager = ShaderManager.getInstance(); @@ -258,9 +366,18 @@ public class NEUCape { lastRender = System.currentTimeMillis(); } + private boolean notRendering = false; public void onTick(TickEvent.ClientTickEvent event, EntityPlayer player) { - if(player != null && System.currentTimeMillis() - lastRender < 100) { - ensureCapeNodesCreated(Minecraft.getMinecraft().thePlayer); + if(player == null) return; + + if(System.currentTimeMillis() - lastRender < 500) { + if(currentPlayer == null) { + currentPlayer = player; + } else if(currentPlayer != player) { + return; + } + + ensureCapeNodesCreated(player); for(int y=0; y<nodes.size(); y++) { for(int x=0; x<nodes.get(y).size(); x++) { @@ -271,6 +388,12 @@ public class NEUCape { } } updateCape(player); + + notRendering = false; + } else { + currentPlayer = null; + + notRendering = true; } } @@ -346,128 +469,138 @@ public class NEUCape { private double oldPlayerAngle; private int crouchTicks = 0; long startTime = 0; - long updateMillis = 0; - long renderMillis = 0; private void updateCape(EntityPlayer player) { Vector3f capeTranslation = updateFixedCapeNodes(player); - if(System.currentTimeMillis() - lastRender > 100) { + if(shaderName.equals("space_cape")) { + long currentTime = System.currentTimeMillis(); + if(currentTime-startTime > eventMillis-startTime+eventLength) { + eventMillis = currentTime; + eventLength = random.nextFloat()*2000+4000; + eventRandom = random.nextFloat(); + } + } + + if(notRendering) { for (int y = 0; y < nodes.size(); y++) { for (int x = 0; x < nodes.get(y).size(); x++) { - Vector3f.add(nodes.get(y).get(x).position, capeTranslation, nodes.get(y).get(x).position); - nodes.get(y).get(x).lastPosition.set(nodes.get(y).get(x).position); - nodes.get(y).get(x).renderPosition.set(nodes.get(y).get(x).position); + CapeNode node = nodes.get(y).get(x); + if(!node.fixed) { + Vector3f.add(node.position, capeTranslation, node.position); + node.lastPosition.set(node.position); + node.renderPosition.set(node.position); + } } } - } else { - double playerAngle = Math.toRadians(player.renderYawOffset); - double deltaAngle = playerAngle - oldPlayerAngle; - if(deltaAngle > Math.PI) { - deltaAngle = 2*Math.PI - deltaAngle; - } - if(deltaAngle < -Math.PI) { - deltaAngle = 2*Math.PI + deltaAngle; - } - deltaAngleAccum *= 0.5f; - deltaAngleAccum += deltaAngle; + } - float dX = (float)Math.cos(playerAngle+Math.PI/2f); - float dZ = (float)Math.sin(playerAngle+Math.PI/2f); + double playerAngle = Math.toRadians(player.renderYawOffset); + double deltaAngle = playerAngle - oldPlayerAngle; + if(deltaAngle > Math.PI) { + deltaAngle = 2*Math.PI - deltaAngle; + } + if(deltaAngle < -Math.PI) { + deltaAngle = 2*Math.PI + deltaAngle; + } + deltaAngleAccum *= 0.5f; + deltaAngleAccum += deltaAngle; - float factor = (float)(deltaAngleAccum*deltaAngleAccum); + float dX = (float)Math.cos(playerAngle+Math.PI/2f); + float dZ = (float)Math.sin(playerAngle+Math.PI/2f); - tl.handleKeyboardInput(); + float factor = (float)(deltaAngleAccum*deltaAngleAccum); - float capeTransLength = capeTranslation.length(); + tl.handleKeyboardInput(); - float capeTranslationFactor = 0f; - if(capeTransLength > 0.5f) { - capeTranslationFactor = (capeTransLength-0.5f)/capeTransLength; - } - Vector3f lookDir = new Vector3f(dX, 0, dZ); - Vector3f lookDirNorm = lookDir.normalise(null); - float dot = Vector3f.dot(capeTranslation, lookDirNorm); - if(dot < 0) { //Moving backwards - for(int y=0; y<nodes.size(); y++) { - for(int x=0; x<nodes.get(y).size(); x++) { - CapeNode node = nodes.get(y).get(x); - if(!node.fixed) { - node.position.x += lookDirNorm.x*dot; - node.position.y += lookDirNorm.y*dot; - node.position.z += lookDirNorm.z*dot; - } - } - } - //Apply small backwards force - factor = 0.05f; - } + float capeTransLength = capeTranslation.length(); - if(factor > 0) { - for(int y=0; y<nodes.size(); y++) { - for(int x=0; x<nodes.get(y).size(); x++) { - nodes.get(y).get(x).applyForce(-dX*factor, 0, -dZ*factor); + float capeTranslationFactor = 0f; + if(capeTransLength > 0.5f) { + capeTranslationFactor = (capeTransLength-0.5f)/capeTransLength; + } + Vector3f lookDir = new Vector3f(dX, 0, dZ); + Vector3f lookDirNorm = lookDir.normalise(null); + float dot = Vector3f.dot(capeTranslation, lookDirNorm); + if(dot < 0) { //Moving backwards + for(int y=0; y<nodes.size(); y++) { + for(int x=0; x<nodes.get(y).size(); x++) { + CapeNode node = nodes.get(y).get(x); + if(!node.fixed) { + node.position.x += lookDirNorm.x*dot; + node.position.y += lookDirNorm.y*dot; + node.position.z += lookDirNorm.z*dot; } } } + //Apply small backwards force + factor = 0.05f; + } - if(capeTranslationFactor > 0f) { - float capeDX = capeTranslation.x*capeTranslationFactor; - float capeDY = capeTranslation.y*capeTranslationFactor; - float capeDZ = capeTranslation.z*capeTranslationFactor; - - for(int y=0; y<nodes.size(); y++) { - for(int x=0; x<nodes.get(y).size(); x++) { - CapeNode node = nodes.get(y).get(x); - if(!node.fixed) { - node.position.x += capeDX; - node.position.y += capeDY; - node.position.z += capeDZ; - } - } + if(factor > 0) { + for(int y=0; y<nodes.size(); y++) { + for(int x=0; x<nodes.get(y).size(); x++) { + nodes.get(y).get(x).applyForce(-dX*factor, 0, -dZ*factor); } } + } - //Wind - float currTime = (System.currentTimeMillis()-startTime)/1000f; - float windRandom = Math.abs((float)(0.5f*Math.sin(0.22f*currTime)+Math.sin(0.44f*currTime)*Math.sin(0.47f*currTime))); - double windDir = playerAngle+Math.PI/4f*Math.sin(0.2f*currTime); + if(capeTranslationFactor > 0f) { + float capeDX = capeTranslation.x*capeTranslationFactor; + float capeDY = capeTranslation.y*capeTranslationFactor; + float capeDZ = capeTranslation.z*capeTranslationFactor; - float windDX = (float)Math.cos(windDir+Math.PI/2f); - float windDZ = (float)Math.sin(windDir+Math.PI/2f); for(int y=0; y<nodes.size(); y++) { for(int x=0; x<nodes.get(y).size(); x++) { - nodes.get(y).get(x).applyForce(-windDX*windRandom*0.01f, 0, -windDZ*windRandom*0.01f); + CapeNode node = nodes.get(y).get(x); + if(!node.fixed) { + node.position.x += capeDX; + node.position.y += capeDY; + node.position.z += capeDZ; + } } } + } - if(player.isSneaking()) { - crouchTicks++; - float mult = 0.5f; - if(crouchTicks < 5) { - mult = 2f; - } - for(int y=0; y<8; y++) { - for(int x=0; x<nodes.get(y).size(); x++) { - nodes.get(y).get(x).applyForce(-dX*mult, 0, -dZ*mult); - } + //Wind + float currTime = (System.currentTimeMillis()-startTime)/1000f; + float windRandom = Math.abs((float)(0.5f*Math.sin(0.22f*currTime)+Math.sin(0.44f*currTime)*Math.sin(0.47f*currTime))); + double windDir = playerAngle+Math.PI/4f*Math.sin(0.2f*currTime); + + float windDX = (float)Math.cos(windDir+Math.PI/2f); + float windDZ = (float)Math.sin(windDir+Math.PI/2f); + for(int y=0; y<nodes.size(); y++) { + for(int x=0; x<nodes.get(y).size(); x++) { + nodes.get(y).get(x).applyForce(-windDX*windRandom*0.01f, 0, -windDZ*windRandom*0.01f); + } + } + + if(player.isSneaking()) { + crouchTicks++; + float mult = 0.5f; + if(crouchTicks < 5) { + mult = 2f; + } + for(int y=0; y<8; y++) { + for(int x=0; x<nodes.get(y).size(); x++) { + nodes.get(y).get(x).applyForce(-dX*mult, 0, -dZ*mult); } - } else { - crouchTicks = 0; } + } else { + crouchTicks = 0; + } - oldPlayerAngle = playerAngle; + oldPlayerAngle = playerAngle; + for(int y=0; y<nodes.size(); y++) { + for(int x=0; x<nodes.get(y).size(); x++) { + nodes.get(y).get(x).update(); + } + } + int updates = player == Minecraft.getMinecraft().thePlayer ? 50 : 50; + for(int i=0; i<updates; i++) { for(int y=0; y<nodes.size(); y++) { for(int x=0; x<nodes.get(y).size(); x++) { - nodes.get(y).get(x).update(); - } - } - int updates = player == Minecraft.getMinecraft().thePlayer ? 50 : 25; - for(int i=0; i<updates; i++) { - for(int y=0; y<nodes.size(); y++) { - for(int x=0; x<nodes.get(y).size(); x++) { - nodes.get(y).get(x).resolveAll(2+1f*y/nodes.size(), false); - } + nodes.get(y).get(x).resolveAll(2+1f*y/nodes.size(), false); } } } @@ -549,7 +682,7 @@ public class NEUCape { private void renderCape(EntityPlayer player, float partialRenderTick) { ensureCapeNodesCreated(player); - if(System.currentTimeMillis() - lastRender > 100) { + if(System.currentTimeMillis() - lastRender > 500) { updateCape(player); } updateFixedCapeNodesPartial(player, partialRenderTick); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonBlocks.java b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonBlocks.java new file mode 100644 index 00000000..fb9de198 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonBlocks.java @@ -0,0 +1,261 @@ +package io.github.moulberry.notenoughupdates.dungeons; + +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.questing.SBInfo; +import io.github.moulberry.notenoughupdates.util.SpecialColour; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.texture.*; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.client.resources.IResourceManagerReloadListener; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.BufferUtils; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.*; + +import java.awt.*; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +public class DungeonBlocks { + + private static Framebuffer framebufferBlocksTo = null; + private static Framebuffer framebufferBlocksFrom = null; + + private static HashMap<String, Framebuffer> framebuffersDynamicTo = new HashMap<>(); + public static HashMap<String, Framebuffer> framebuffersDynamicFrom = new HashMap<>(); + private static HashSet<String> dynamicUpdated = new HashSet<>(); + + private static FloatBuffer projectionMatrixOld = BufferUtils.createFloatBuffer(16); + private static FloatBuffer modelviewMatrixOld = BufferUtils.createFloatBuffer(16); + + public static boolean textureExists() { + return framebufferBlocksFrom != null && isOverriding(); + } + + public static void bindTextureIfExists() { + if(textureExists()) { + framebufferBlocksFrom.bindFramebufferTexture(); + } + } + + public static boolean isOverriding() { + return OpenGlHelper.isFramebufferEnabled() && !NotEnoughUpdates.INSTANCE.manager.config.disableDungeonBlocks.value && + (NotEnoughUpdates.INSTANCE.manager.config.dungeonBlocksEverywhere.value || + (SBInfo.getInstance().getLocation() != null && SBInfo.getInstance().getLocation().equals("dungeon"))); + } + + public static boolean bindModifiedTexture(ResourceLocation location, int colour) { + if(!isOverriding()) { + return false; + } + + if(Utils.disableCustomDungColours) { + return false; + } + + if(((colour >> 24) & 0xFF) < 10) { + return false; + } + + String id = location.getResourceDomain()+":"+location.getResourcePath(); + if(dynamicUpdated.contains(id) && framebuffersDynamicFrom.containsKey(id)) { + framebuffersDynamicFrom.get(id).bindFramebufferTexture(); + return true; + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(location); + int w = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_WIDTH); + int h = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_HEIGHT); + + Framebuffer to = checkFramebufferSizes(framebuffersDynamicTo.get(id), w, h); + dynamicUpdated.add(id); + + try { + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projectionMatrixOld); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelviewMatrixOld); + + GL11.glPushMatrix(); + + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GlStateManager.loadIdentity(); + GlStateManager.ortho(0.0D, w, h, 0.0D, 1000.0D, 3000.0D); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + GlStateManager.loadIdentity(); + GlStateManager.translate(0.0F, 0.0F, -2000.0F); + + to.bindFramebuffer(true); + GlStateManager.clearColor(0, 1, 0, 1); + GlStateManager.clear(GL11.GL_COLOR_BUFFER_BIT); + + GlStateManager.disableBlend(); + GlStateManager.disableLighting(); + GlStateManager.disableFog(); + + Minecraft.getMinecraft().getTextureManager().bindTexture(location); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRectNoBlend(0, 0, w, h, 0, 1, 1, 0, GL11.GL_LINEAR); + + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + Utils.drawRectNoBlend(0, 0, w, h, colour); + + GL11.glPopMatrix(); + + to.bindFramebufferTexture(); + if (Minecraft.getMinecraft().gameSettings.mipmapLevels >= 0) { + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, Minecraft.getMinecraft().gameSettings.mipmapLevels); + GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MIN_LOD, 0.0F); + GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LOD, (float)Minecraft.getMinecraft().gameSettings.mipmapLevels); + GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_LOD_BIAS, 0.0F); + GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); + } + + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GL11.glLoadMatrix(projectionMatrixOld); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + GL11.glLoadMatrix(modelviewMatrixOld); + + Framebuffer from = checkFramebufferSizes(framebuffersDynamicFrom.get(id), w, h); + framebuffersDynamicFrom.put(id, to); + framebuffersDynamicTo.put(id, from); + + to.bindFramebufferTexture(); + + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true); + GlStateManager.disableBlend(); + GlStateManager.enableLighting(); + return true; + } catch(Exception e) { + e.printStackTrace(); + } + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true); + GlStateManager.disableBlend(); + GlStateManager.enableLighting(); + return false; + } + + private static HashMap<ResourceLocation, String> dynamicPreloadMap = new HashMap<>(); + + static { + dynamicPreloadMap.put(new ResourceLocation("textures/entity/bat.png"), + NotEnoughUpdates.INSTANCE.manager.config.dungBatColour.value); + dynamicPreloadMap.put(new ResourceLocation("textures/entity/chest/normal.png"), + NotEnoughUpdates.INSTANCE.manager.config.dungChestColour.value); + dynamicPreloadMap.put(new ResourceLocation("textures/entity/chest/normal_double.png"), + NotEnoughUpdates.INSTANCE.manager.config.dungChestColour.value); + dynamicPreloadMap.put(new ResourceLocation("textures/entity/chest/trapped.png"), + NotEnoughUpdates.INSTANCE.manager.config.dungTrappedChestColour.value); + dynamicPreloadMap.put(new ResourceLocation("textures/entity/chest/trapped_double.png"), + NotEnoughUpdates.INSTANCE.manager.config.dungTrappedChestColour.value); + } + + public static void tick() { + if(!isOverriding() || Minecraft.getMinecraft().theWorld == null) { + return; + } + + dynamicUpdated.clear(); + + for(Map.Entry<ResourceLocation, String> entry : dynamicPreloadMap.entrySet()) { + bindModifiedTexture(entry.getKey(), SpecialColour.specialToChromaRGB(entry.getValue())); + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(TextureMap.locationBlocksTexture); + int w = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_WIDTH); + int h = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_HEIGHT); + + Framebuffer to = checkFramebufferSizes(framebufferBlocksTo, w, h); + + try { + GL11.glPushMatrix(); + + GlStateManager.matrixMode(5889); + GlStateManager.loadIdentity(); + GlStateManager.ortho(0.0D, w, h, 0.0D, 1000.0D, 3000.0D); + GlStateManager.matrixMode(5888); + GlStateManager.loadIdentity(); + GlStateManager.translate(0.0F, 0.0F, -2000.0F); + + to.bindFramebuffer(true); + GlStateManager.clear(GL11.GL_COLOR_BUFFER_BIT); + + GlStateManager.disableBlend(); + GlStateManager.disableLighting(); + GlStateManager.disableFog(); + + Minecraft.getMinecraft().getTextureManager().bindTexture(TextureMap.locationBlocksTexture); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRectNoBlend(0, 0, w, h, 0, 1, 1, 0, GL11.GL_LINEAR); + + HashMap<TextureAtlasSprite, Integer> spriteMap = new HashMap<>(); + spriteMap.put(Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite("minecraft:blocks/stonebrick_cracked"), + SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.manager.config.dungCrackedColour.value)); + spriteMap.put(Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite("minecraft:blocks/dispenser_front_horizontal"), + SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.manager.config.dungDispenserColour.value)); + spriteMap.put(Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite("minecraft:blocks/lever"), + SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.manager.config.dungLeverColour.value)); + spriteMap.put(Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite("minecraft:blocks/trip_wire"), + SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.manager.config.dungTripWireColour.value)); + + for(Map.Entry<TextureAtlasSprite, Integer> entry : spriteMap.entrySet()) { + if(((entry.getValue() >> 24) & 0xFF) < 10) continue; + + TextureAtlasSprite tas = entry.getKey(); + Gui.drawRect((int)(w*tas.getMinU()), h-(int)(h*tas.getMaxV())-1, + (int)(w*tas.getMaxU())+1, h-(int)(h*tas.getMinV()), entry.getValue()); + } + + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + GlStateManager.matrixMode(5889); + GlStateManager.loadIdentity(); + GlStateManager.ortho(0.0D, scaledResolution.getScaledWidth_double(), scaledResolution.getScaledHeight_double(), + 0.0D, 1000.0D, 3000.0D); + GlStateManager.matrixMode(5888); + GlStateManager.loadIdentity(); + GlStateManager.translate(0.0F, 0.0F, -2000.0F); + + GL11.glPopMatrix(); + + to.bindFramebufferTexture(); + if (Minecraft.getMinecraft().gameSettings.mipmapLevels >= 0) { + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, Minecraft.getMinecraft().gameSettings.mipmapLevels); + GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MIN_LOD, 0.0F); + GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LOD, (float)Minecraft.getMinecraft().gameSettings.mipmapLevels); + GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_LOD_BIAS, 0.0F); + GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); + } + + Framebuffer from = checkFramebufferSizes(framebufferBlocksFrom, w, h); + framebufferBlocksFrom = to; + framebufferBlocksTo = from; + } catch(Exception e) { + e.printStackTrace(); + } + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true); + GlStateManager.enableBlend(); + } + + private static Framebuffer checkFramebufferSizes(Framebuffer framebuffer, int width, int height) { + if(framebuffer == null || framebuffer.framebufferWidth != width || framebuffer.framebufferHeight != height) { + if(framebuffer == null) { + framebuffer = new Framebuffer(width, height, false); + framebuffer.framebufferColor[0] = 1f; + framebuffer.framebufferColor[1] = 0f; + framebuffer.framebufferColor[2] = 0f; + framebuffer.framebufferColor[3] = 0; + } else { + framebuffer.createBindFramebuffer(width, height); + } + framebuffer.setFramebufferFilter(GL11.GL_NEAREST); + } + return framebuffer; + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonMap.java b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonMap.java new file mode 100644 index 00000000..fa49c0c2 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonMap.java @@ -0,0 +1,1559 @@ +package io.github.moulberry.notenoughupdates.dungeons; + +import com.google.common.math.BigIntegerMath; +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.NEUResourceManager; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.questing.SBInfo; +import io.github.moulberry.notenoughupdates.util.SpecialColour; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.block.material.MapColor; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.AbstractClientPlayer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.MapItemRenderer; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.client.renderer.texture.TextureUtil; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.resources.DefaultPlayerSkin; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.client.shader.Shader; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemMap; +import net.minecraft.item.ItemStack; +import net.minecraft.scoreboard.ScorePlayerTeam; +import net.minecraft.util.*; +import net.minecraft.world.storage.MapData; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.lwjgl.BufferUtils; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; +import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.GL45; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.List; + +public class DungeonMap { + + private static final ResourceLocation GREEN_CHECK = new ResourceLocation("notenoughupdates:dungeon_map/green_check.png"); + private static final ResourceLocation WHITE_CHECK = new ResourceLocation("notenoughupdates:dungeon_map/white_check.png"); + private static final ResourceLocation QUESTION = new ResourceLocation("notenoughupdates:dungeon_map/question.png"); + private static final ResourceLocation CROSS = new ResourceLocation("notenoughupdates:dungeon_map/cross.png"); + + private static final ResourceLocation ROOM_RED = new ResourceLocation("notenoughupdates:dungeon_map/rooms_default/red_room.png"); + private static final ResourceLocation ROOM_BROWN = new ResourceLocation("notenoughupdates:dungeon_map/rooms_default/brown_room.png"); + private static final ResourceLocation ROOM_GRAY = new ResourceLocation("notenoughupdates:dungeon_map/rooms_default/gray_room.png"); + private static final ResourceLocation ROOM_GREEN = new ResourceLocation("notenoughupdates:dungeon_map/rooms_default/green_room.png"); + private static final ResourceLocation ROOM_PINK = new ResourceLocation("notenoughupdates:dungeon_map/rooms_default/pink_room.png"); + private static final ResourceLocation ROOM_PURPLE = new ResourceLocation("notenoughupdates:dungeon_map/rooms_default/purple_room.png"); + private static final ResourceLocation ROOM_YELLOW = new ResourceLocation("notenoughupdates:dungeon_map/rooms_default/yellow_room.png"); + private static final ResourceLocation ROOM_ORANGE = new ResourceLocation("notenoughupdates:dungeon_map/rooms_default/orange_room.png"); + + private static final ResourceLocation CORRIDOR_RED = new ResourceLocation("notenoughupdates:dungeon_map/corridors_default/red_corridor.png"); + private static final ResourceLocation CORRIDOR_BROWN = new ResourceLocation("notenoughupdates:dungeon_map/corridors_default/brown_corridor.png"); + private static final ResourceLocation CORRIDOR_GRAY = new ResourceLocation("notenoughupdates:dungeon_map/corridors_default/gray_corridor.png"); + private static final ResourceLocation CORRIDOR_GREEN = new ResourceLocation("notenoughupdates:dungeon_map/corridors_default/green_corridor.png"); + private static final ResourceLocation CORRIDOR_PINK = new ResourceLocation("notenoughupdates:dungeon_map/corridors_default/pink_corridor.png"); + private static final ResourceLocation CORRIDOR_PURPLE = new ResourceLocation("notenoughupdates:dungeon_map/corridors_default/purple_corridor.png"); + private static final ResourceLocation CORRIDOR_YELLOW = new ResourceLocation("notenoughupdates:dungeon_map/corridors_default/yellow_corridor.png"); + private static final ResourceLocation CORRIDOR_ORANGE = new ResourceLocation("notenoughupdates:dungeon_map/corridors_default/orange_corridor.png"); + + private static final ResourceLocation DIVIDER_BROWN = new ResourceLocation("notenoughupdates:dungeon_map/dividers_default/brown_divider.png"); + + private static final ResourceLocation CORNER_BROWN = new ResourceLocation("notenoughupdates:dungeon_map/corners_default/brown_corner.png"); + + private final HashMap<RoomOffset, Room> roomMap = new HashMap<>(); + private Color[][] colourMap = new Color[128][128]; + private int startRoomX = -1; + private int startRoomY = -1; + private int connectorSize = 5; + private int roomSize = 0; + + //private final List<MapDecoration> decorations = new ArrayList<>(); + //private final List<MapDecoration> lastDecorations = new ArrayList<>(); + private long lastDecorationsMillis = -1; + private long lastLastDecorationsMillis = -1; + + private Map<String, MapPosition> playerEntityMapPositions = new HashMap<>(); + private Map<String, MapPosition> playerMarkerMapPositions = new HashMap<>(); + private Map<String, MapPosition> playerMarkerMapPositionsLast = new HashMap<>(); + + private Map<String, ResourceLocation> playerSkinMap = new HashMap<>(); + + private class RoomOffset { + int x; + int y; + + public RoomOffset(int x, int y) { + this.x = x; + this.y = y; + } + + public RoomOffset left() { + return new RoomOffset(x-1, y); + } + + public RoomOffset right() { + return new RoomOffset(x+1, y); + } + + public RoomOffset up() { + return new RoomOffset(x, y-1); + } + + public RoomOffset down() { + return new RoomOffset(x, y+1); + } + + public RoomOffset[] getNeighbors() { + return new RoomOffset[]{left(), right(), up(), down()}; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RoomOffset that = (RoomOffset) o; + return x == that.x && y == that.y; + } + + @Override + public int hashCode() { + return Objects.hash(x, y); + } + } + + private enum RoomConnectionType { + NONE, WALL, CORRIDOR, ROOM_DIVIDER + } + + private class RoomConnection { + RoomConnectionType type; + Color colour; + + public RoomConnection(RoomConnectionType type, Color colour) { + this.type = type; + this.colour = colour; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RoomConnection that = (RoomConnection) o; + return type == that.type && + Objects.equals(colour, that.colour); + } + + @Override + public int hashCode() { + return Objects.hash(type, colour); + } + } + + private class Room { + Color colour = new Color(0, 0, 0, 0); + int tickColour = 0; + boolean fillCorner = false; + + RoomConnection left = new RoomConnection(RoomConnectionType.NONE, new Color(0, true)); + RoomConnection up = new RoomConnection(RoomConnectionType.NONE, new Color(0, true)); + RoomConnection right = new RoomConnection(RoomConnectionType.NONE, new Color(0, true)); + RoomConnection down = new RoomConnection(RoomConnectionType.NONE, new Color(0, true)); + + public void renderNoRotate(int roomSize, int connectorSize, int rotation) { + if(tickColour != 0) { + Color tick = new Color(tickColour, true); + ResourceLocation indicatorTex = null; + if(tick.getRed() == 255 && tick.getGreen() == 255 && tick.getBlue() == 255) { + indicatorTex = WHITE_CHECK; + } else if(tick.getRed() == 0 && tick.getGreen() == 124 && tick.getBlue() == 0) { + indicatorTex = GREEN_CHECK; + } else if(tick.getRed() == 13 && tick.getGreen() == 13 && tick.getBlue() == 13) { + indicatorTex = QUESTION; + } else if(tick.getRed() == 255 && tick.getGreen() == 0 && tick.getBlue() == 0) { + indicatorTex = CROSS; + } + if(indicatorTex != null) { + Minecraft.getMinecraft().getTextureManager().bindTexture(indicatorTex); + float x = 0; + float y = 0; + + if(NotEnoughUpdates.INSTANCE.manager.config.dmCenterCheck.value) { + if(fillCorner) { + x += -(roomSize+connectorSize)/2f*Math.cos(Math.toRadians(rotation-45))*1.414f; + y += (roomSize+connectorSize)/2f*Math.sin(Math.toRadians(rotation-45))*1.414; + } + if(down.type == RoomConnectionType.ROOM_DIVIDER && right.type != RoomConnectionType.ROOM_DIVIDER) { + x += -(roomSize+connectorSize)/2f*Math.sin(Math.toRadians(rotation)); + y += -(roomSize+connectorSize)/2f*Math.cos(Math.toRadians(rotation)); + } else if(down.type != RoomConnectionType.ROOM_DIVIDER && right.type == RoomConnectionType.ROOM_DIVIDER) { + x += -(roomSize+connectorSize)/2f*Math.cos(Math.toRadians(rotation)); + y += (roomSize+connectorSize)/2f*Math.sin(Math.toRadians(rotation)); + } + } + GlStateManager.translate(x, y, 0); + if(!NotEnoughUpdates.INSTANCE.manager.config.dmOrientCheck.value) { + GlStateManager.rotate(-rotation+180, 0, 0, 1); + } + + Utils.drawTexturedRect(-5, -5, 10, 10, GL11.GL_NEAREST); + + if(!NotEnoughUpdates.INSTANCE.manager.config.dmOrientCheck.value) { + GlStateManager.rotate(rotation-180, 0, 0, 1); + } + GlStateManager.translate(-x, -y, 0); + } + } + } + + public void render(int roomSize, int connectorSize) { + ResourceLocation roomTex = null; + if(colour.getRed() == 114 && colour.getGreen() == 67 && colour.getBlue() == 27) { + roomTex = ROOM_BROWN; + } else if(colour.getRed() == 65 && colour.getGreen() == 65 && colour.getBlue() == 65) { + roomTex = ROOM_GRAY; + } else if(colour.getRed() == 0 && colour.getGreen() == 124 && colour.getBlue() == 0) { + roomTex = ROOM_GREEN; + } else if(colour.getRed() == 242 && colour.getGreen() == 127 && colour.getBlue() == 165) { + roomTex = ROOM_PINK; + } else if(colour.getRed() == 178 && colour.getGreen() == 76 && colour.getBlue() == 216) { + roomTex = ROOM_PURPLE; + } else if(colour.getRed() == 255 && colour.getGreen() == 0 && colour.getBlue() == 0) { + roomTex = ROOM_RED; + } else if(colour.getRed() == 229 && colour.getGreen() == 229 && colour.getBlue() == 51) { + roomTex = ROOM_YELLOW; + } else if(colour.getRed() == 216 && colour.getGreen() == 127 && colour.getBlue() == 51) { + roomTex = ROOM_ORANGE; + } + + if(roomTex != null) { + Minecraft.getMinecraft().getTextureManager().bindTexture(roomTex); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(0, 0, roomSize, roomSize, GL11.GL_LINEAR); + } else { + Gui.drawRect(0, 0, roomSize, roomSize, colour.getRGB()); + } + + if(fillCorner) { + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(CORNER_BROWN); + Utils.drawTexturedRect(roomSize, roomSize, connectorSize, connectorSize, GL11.GL_NEAREST); + } + + for(int k=0; k<2; k++) { + RoomConnection connection = down; + if(k == 1) connection = right; + + if(connection.type == RoomConnectionType.NONE || connection.type == RoomConnectionType.WALL) continue; + + ResourceLocation corridorTex = null; + if(connection.colour.getRed() == 114 && connection.colour.getGreen() == 67 && connection.colour.getBlue() == 27) { + corridorTex = connection.type == RoomConnectionType.CORRIDOR ? CORRIDOR_BROWN : DIVIDER_BROWN; + } else if(connection.colour.getRed() == 65 && connection.colour.getGreen() == 65 && connection.colour.getBlue() == 65) { + corridorTex = CORRIDOR_GRAY; + } else if(connection.colour.getRed() == 0 && connection.colour.getGreen() == 124 && connection.colour.getBlue() == 0) { + corridorTex = CORRIDOR_GREEN; + } else if(connection.colour.getRed() == 242 && connection.colour.getGreen() == 127 && connection.colour.getBlue() == 165) { + corridorTex = CORRIDOR_PINK; + } else if(connection.colour.getRed() == 178 && connection.colour.getGreen() == 76 && connection.colour.getBlue() == 216) { + corridorTex = CORRIDOR_PURPLE; + } else if(connection.colour.getRed() == 255 && connection.colour.getGreen() == 0 && connection.colour.getBlue() == 0) { + corridorTex = CORRIDOR_RED; + } else if(connection.colour.getRed() == 229 && connection.colour.getGreen() == 229 && connection.colour.getBlue() == 51) { + corridorTex = CORRIDOR_YELLOW; + } else if(connection.colour.getRed() == 216 && connection.colour.getGreen() == 127 && connection.colour.getBlue() == 51) { + corridorTex = CORRIDOR_ORANGE; + } + + if(corridorTex == null) { + int xOffset = 0; + int yOffset = 0; + int width = 0; + int height = 0; + + if(connection == right) { + xOffset = roomSize; + width = connectorSize; + height = roomSize; + + if(connection.type == RoomConnectionType.CORRIDOR) { + height = 8; + yOffset += 4; + } + } else if(connection == down) { + yOffset = roomSize; + width = roomSize; + height = connectorSize; + + if(connection.type == RoomConnectionType.CORRIDOR) { + width = 8; + xOffset += 4; + } + } + + Gui.drawRect(xOffset, yOffset, xOffset+width, yOffset+height, connection.colour.getRGB()); + } else { + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(corridorTex); + GlStateManager.pushMatrix(); + if(connection==right) { + GlStateManager.translate(roomSize/2f, roomSize/2f, 0); + GlStateManager.rotate(-90, 0, 0, 1); + GlStateManager.translate(-roomSize/2f, -roomSize/2f, 0); + } + Utils.drawTexturedRect(0, roomSize, roomSize, connectorSize, GL11.GL_NEAREST); + GlStateManager.popMatrix(); + } + } + } + } + + private static final ResourceLocation mapIcons = new ResourceLocation("textures/map/map_icons.png"); + + public static Framebuffer mapFramebuffer1 = null; + public static Framebuffer mapFramebuffer2 = null; + public static Matrix4f projectionMatrix = null; + public static Shader mapShader = null; + + private static Framebuffer checkFramebufferSizes(Framebuffer framebuffer, int width, int height) { + if(framebuffer == null || framebuffer.framebufferWidth != width || framebuffer.framebufferHeight != height) { + if(framebuffer == null) { + framebuffer = new Framebuffer(width, height, true); + } else { + framebuffer.createBindFramebuffer(width, height); + } + framebuffer.setFramebufferFilter(GL11.GL_NEAREST); + } + return framebuffer; + } + + private static void upload(Shader shader, int width, int height, int scale, float radiusSq) { + if(shader == null) return; + shader.getShaderManager().getShaderUniformOrDefault("ProjMat").set(projectionMatrix); + shader.getShaderManager().getShaderUniformOrDefault("InSize").set(width*scale, height*scale); + shader.getShaderManager().getShaderUniformOrDefault("OutSize").set(width, height); + shader.getShaderManager().getShaderUniformOrDefault("ScreenSize").set((float)width, (float)height); + shader.getShaderManager().getShaderUniformOrDefault("radiusSq").set(radiusSq); + } + + public int getRenderRoomSize() { + int roomSizeOption = NotEnoughUpdates.INSTANCE.manager.config.dmRoomSize.value.intValue(); + if(roomSizeOption <= 0) return 12; + return 12 + roomSizeOption*4; + } + + public int getRenderConnSize() { + int roomSizeOption = NotEnoughUpdates.INSTANCE.manager.config.dmRoomSize.value.intValue(); + if(roomSizeOption <= 0) return 3; + return 3 + roomSizeOption; + } + + private HashMap<Integer, Float> borderRadiusCache = new HashMap<>(); + public float getBorderRadius() { + int borderSizeOption = NotEnoughUpdates.INSTANCE.manager.config.dmBorderSize.value.intValue(); + String sizeId = borderSizeOption == 0 ? "small" : borderSizeOption == 2 ? "large" : "medium"; + + int style = NotEnoughUpdates.INSTANCE.manager.config.dmBorderStyle.value.intValue(); + if(borderRadiusCache.containsKey(style)) { + return borderRadiusCache.get(style); + } + + try(BufferedReader reader = new BufferedReader(new InputStreamReader(Minecraft.getMinecraft().getResourceManager().getResource( + new ResourceLocation("notenoughupdates:dungeon_map/borders/"+sizeId+"/"+style+".json")).getInputStream(), StandardCharsets.UTF_8))) { + JsonObject json = NotEnoughUpdates.INSTANCE.manager.gson.fromJson(reader, JsonObject.class); + float radiusSq = json.get("radiusSq").getAsFloat(); + + borderRadiusCache.put(style, radiusSq); + return radiusSq; + } catch(Exception ignored) { } + + borderRadiusCache.put(style, 1f); + return 1f; + } + + public void render(int centerX, int centerY) { + boolean useFb = NotEnoughUpdates.INSTANCE.manager.config.dmCompat.value <= 1; + boolean useShd = NotEnoughUpdates.INSTANCE.manager.config.dmCompat.value <= 0; + + if((useFb && !OpenGlHelper.isFramebufferEnabled()) || (useShd && !OpenGlHelper.areShadersSupported())) { + Utils.drawStringCentered(EnumChatFormatting.RED+"NEU Dungeon Map requires framebuffers & shaders", + Minecraft.getMinecraft().fontRendererObj, centerX, centerY-10, true, 0); + Utils.drawStringCentered(EnumChatFormatting.RED+"Turn off Optifine Fast Render", + Minecraft.getMinecraft().fontRendererObj, centerX, centerY, true, 0); + Utils.drawStringCentered(EnumChatFormatting.RED+"If that doesn't work, join NEU discord for support", + Minecraft.getMinecraft().fontRendererObj, centerX, centerY+10, true, 0); + return; + } + + ScaledResolution scaledResolution = Utils.pushGuiScale(2); + + int minRoomX = 999; + int minRoomY = 999; + int maxRoomX = -999; + int maxRoomY = -999; + for(RoomOffset offset : roomMap.keySet()) { + minRoomX = Math.min(offset.x, minRoomX); + minRoomY = Math.min(offset.y, minRoomY); + maxRoomX = Math.max(offset.x, maxRoomX); + maxRoomY = Math.max(offset.y, maxRoomY); + } + + int borderSizeOption = NotEnoughUpdates.INSTANCE.manager.config.dmBorderSize.value.intValue(); + + int renderRoomSize = getRenderRoomSize(); + int renderConnSize = getRenderConnSize(); + + MapPosition playerPos = null; + if(playerEntityMapPositions.containsKey(Minecraft.getMinecraft().thePlayer.getName())) { + playerPos = playerEntityMapPositions.get(Minecraft.getMinecraft().thePlayer.getName()); + } else if(playerMarkerMapPositions.containsKey(Minecraft.getMinecraft().thePlayer.getName())) { + playerPos = playerMarkerMapPositions.get(Minecraft.getMinecraft().thePlayer.getName()); + } + + int rotation = 180; + if(playerPos != null && NotEnoughUpdates.INSTANCE.manager.config.dmRotatePlayer.value) { + rotation = (int)playerPos.rotation; + } + + int mapSizeX = borderSizeOption == 0 ? 90 : borderSizeOption == 2 ? 160 : borderSizeOption == 3 ? 240 : 120; + int mapSizeY = borderSizeOption == 0 ? 90 : borderSizeOption == 2 ? 160 : borderSizeOption == 3 ? 240 : 120; + int roomsSizeX = (maxRoomX-minRoomX)*(renderRoomSize+renderConnSize)+renderRoomSize; + int roomsSizeY = (maxRoomY-minRoomY)*(renderRoomSize+renderConnSize)+renderRoomSize; + int mapCenterX = mapSizeX/2; + int mapCenterY = mapSizeY/2; + int scaleFactor = 8; + + projectionMatrix = Utils.createProjectionMatrix(mapSizeX*scaleFactor, mapSizeY*scaleFactor); + mapFramebuffer1 = checkFramebufferSizes(mapFramebuffer1, mapSizeX*scaleFactor, mapSizeY*scaleFactor); + mapFramebuffer2 = checkFramebufferSizes(mapFramebuffer2, mapSizeX*scaleFactor, mapSizeY*scaleFactor); + mapFramebuffer1.framebufferColor[1] = 0; + mapFramebuffer1.framebufferColor[2] = 0; + + try { + if(mapShader == null) { + mapShader = new Shader(new NEUResourceManager(Minecraft.getMinecraft().getResourceManager()), + "dungeonmap", mapFramebuffer1, mapFramebuffer2); + } + } catch(Exception e) { + e.printStackTrace(); + return; + } + + int backgroundColour = SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.manager.config.dmBackgroundColour.value); + + mapFramebuffer1.framebufferColor[0] = ((backgroundColour >> 16) & 0xFF)/255f; + mapFramebuffer1.framebufferColor[1] = ((backgroundColour >> 8) & 0xFF)/255f; + mapFramebuffer1.framebufferColor[2] = (backgroundColour & 0xFF)/255f; + mapFramebuffer2.framebufferColor[0] = ((backgroundColour >> 16) & 0xFF)/255f; + mapFramebuffer2.framebufferColor[1] = ((backgroundColour >> 8) & 0xFF)/255f; + mapFramebuffer2.framebufferColor[2] = (backgroundColour & 0xFF)/255f; + + try { + if(useFb) { + mapFramebuffer1.framebufferClear(); + mapFramebuffer2.framebufferClear(); + } + + GlStateManager.pushMatrix(); { + if(useFb) { + GlStateManager.matrixMode(5889); + GlStateManager.loadIdentity(); + GlStateManager.ortho(0.0D, mapSizeX*scaleFactor, mapSizeY*scaleFactor, 0.0D, 1000.0D, 3000.0D); + GlStateManager.matrixMode(5888); + GlStateManager.loadIdentity(); + GlStateManager.translate(0.0F, 0.0F, -2000.0F); + + GlStateManager.scale(scaleFactor, scaleFactor, 1); + mapFramebuffer1.bindFramebuffer(true); + + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + GlStateManager.disableBlend(); + } else { + GL11.glEnable(GL11.GL_SCISSOR_TEST); + GL11.glScissor((centerX-mapSizeX/2)*2, Minecraft.getMinecraft().displayHeight-(centerY+mapSizeY/2)*2, mapSizeX*2, mapSizeY*2); + + GlStateManager.translate(centerX-mapSizeX/2, centerY-mapSizeY/2, 100); + } + + if(NotEnoughUpdates.INSTANCE.manager.config.dmBackgroundBlur.value > 0.1) { + GlStateManager.translate(-centerX+mapSizeX/2, -centerY+mapSizeY/2, 0); + renderBlurredBackground(scaledResolution.getScaledWidth(), scaledResolution.getScaledHeight(), + centerX-mapSizeX/2, centerY-mapSizeY/2, mapSizeX, mapSizeY); + GlStateManager.translate(centerX-mapSizeX/2, centerY-mapSizeY/2, 0); + } + + GlStateManager.translate(mapCenterX, mapCenterY, 10); + + if(!useFb || NotEnoughUpdates.INSTANCE.manager.config.dmBackgroundBlur.value > 0.1) { + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + } + Utils.drawRectNoBlend(-mapCenterX, -mapCenterY, mapCenterX, mapCenterY, backgroundColour); + + GlStateManager.rotate(-rotation+180, 0, 0, 1); + + if(NotEnoughUpdates.INSTANCE.manager.config.dmCenterPlayer.value && playerPos != null) { + float x = playerPos.getRenderX(); + float y = playerPos.getRenderY(); + x -= minRoomX*(renderRoomSize+renderConnSize); + y -= minRoomY*(renderRoomSize+renderConnSize); + + GlStateManager.translate(-x, -y, 0); + } else { + GlStateManager.translate(-roomsSizeX/2, -roomsSizeY/2, 0); + } + + for(Map.Entry<RoomOffset, Room> entry : roomMap.entrySet()) { + RoomOffset roomOffset = entry.getKey(); + Room room = entry.getValue(); + + int x = (roomOffset.x-minRoomX)*(renderRoomSize+renderConnSize); + int y = (roomOffset.y-minRoomY)*(renderRoomSize+renderConnSize); + + GlStateManager.pushMatrix(); + GlStateManager.translate(x, y, 0); + + room.render(renderRoomSize, renderConnSize); + + GlStateManager.translate(-x, -y, 0); + GlStateManager.popMatrix(); + } + + GlStateManager.translate(-mapCenterX+roomsSizeX/2f, -mapCenterY+roomsSizeY/2f, 0); + + GlStateManager.translate(mapCenterX, mapCenterY, 0); + GlStateManager.rotate(rotation-180, 0, 0, 1); + GlStateManager.translate(-mapCenterX, -mapCenterY, 0); + + GlStateManager.translate(mapCenterX, mapCenterY, 0); + + for(Map.Entry<RoomOffset, Room> entry : roomMap.entrySet()) { + RoomOffset roomOffset = entry.getKey(); + Room room = entry.getValue(); + + float x = (roomOffset.x-minRoomX)*(renderRoomSize+renderConnSize)-roomsSizeX/2f+renderRoomSize/2f; + float y = (roomOffset.y-minRoomY)*(renderRoomSize+renderConnSize)-roomsSizeY/2f+renderRoomSize/2f; + float x2 = (float)(-x*Math.cos(Math.toRadians(-rotation)) + y*Math.sin(Math.toRadians(-rotation))); + float y2 = (float)(-x*Math.sin(Math.toRadians(-rotation)) - y*Math.cos(Math.toRadians(-rotation))); + + GlStateManager.pushMatrix(); + GlStateManager.translate(x2, y2, 0); + + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + room.renderNoRotate(renderRoomSize, renderConnSize, rotation); + + GlStateManager.translate(-x2, -y2, 0); + GlStateManager.popMatrix(); + } + + + GlStateManager.translate(-mapCenterX, -mapCenterY, 0); + + GlStateManager.translate(mapCenterX, mapCenterY, 0); + GlStateManager.rotate(-rotation+180, 0, 0, 1); + GlStateManager.translate(-mapCenterX, -mapCenterY, 0); + + GlStateManager.translate(mapCenterX-roomsSizeX/2f, mapCenterY-roomsSizeY/2f, 0); + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + int k = 0; + + for(Map.Entry<String, MapPosition> entry : playerMarkerMapPositions.entrySet()) { + String name = entry.getKey(); + MapPosition pos = entry.getValue(); + float x = pos.getRenderX(); + float y = pos.getRenderY(); + float angle = pos.rotation; + + boolean doInterp = NotEnoughUpdates.INSTANCE.manager.config.dmPlayerInterp.value; + if(playerEntityMapPositions.containsKey(name)) { + MapPosition entityPos = playerEntityMapPositions.get(name); + angle = entityPos.rotation; + + float deltaX = entityPos.getRenderX() - pos.getRenderX(); + float deltaY = entityPos.getRenderY() - pos.getRenderY(); + + if(deltaX > (renderRoomSize + renderConnSize)/2) { + deltaX -= (renderRoomSize + renderConnSize); + } else if(deltaX < -(renderRoomSize + renderConnSize)/2) { + deltaX += (renderRoomSize + renderConnSize); + } + if(deltaY > (renderRoomSize + renderConnSize)/2) { + deltaY -= (renderRoomSize + renderConnSize); + } else if(deltaY < -(renderRoomSize + renderConnSize)/2) { + deltaY += (renderRoomSize + renderConnSize); + } + + x += deltaX; + y += deltaY; + + doInterp = false; + } + + float minU = 3/4f; + float minV = 0; + + if(name.equals(Minecraft.getMinecraft().thePlayer.getName())) { + minU = 1/4f; + } + + float maxU = minU + 1/4f; + float maxV = minV + 1/4f; + + if(doInterp && playerMarkerMapPositionsLast.containsKey(name)) { + MapPosition last = playerMarkerMapPositionsLast.get(name); + float xLast = last.getRenderX(); + float yLast = last.getRenderY(); + + float distSq = (x-xLast) * (x-xLast) + (y-yLast) * (y-yLast); + if (distSq < renderRoomSize*renderRoomSize/4f) { + float angleLast = last.rotation; + if (angle > 180 && angleLast < 180) angleLast += 360; + if (angleLast > 180 && angle < 180) angle += 360; + + float interpFactor = Math.round((System.currentTimeMillis() - lastDecorationsMillis) * 100f) / 100f / (lastDecorationsMillis - lastLastDecorationsMillis); + interpFactor = Math.max(0, Math.min(1, interpFactor)); + + x = xLast + (x - xLast) * interpFactor; + y = yLast + (y - yLast) * interpFactor; + angle = angleLast + (angle - angleLast) * interpFactor; + angle %= 360; + } + } + + boolean headLayer = false; + int pixelWidth = 8; + int pixelHeight = 8; + if(renderRoomSize >= 24) { + pixelWidth = pixelHeight = 12; + } + GlStateManager.color(1, 1, 1, 1); + if(NotEnoughUpdates.INSTANCE.manager.config.dmPlayerHeads.value >= 1 && + playerSkinMap.containsKey(entry.getKey())) { + Minecraft.getMinecraft().getTextureManager().bindTexture(playerSkinMap.get(entry.getKey())); + + headLayer = true; + if(NotEnoughUpdates.INSTANCE.manager.config.dmPlayerHeads.value >= 3) { + minU = 9/64f; + minV = 9/64f; + maxU = 15/64f; + maxV = 15/64f; + } else { + minU = 8/64f; + minV = 8/64f; + maxU = 16/64f; + maxV = 16/64f; + } + + if(NotEnoughUpdates.INSTANCE.manager.config.dmPlayerHeads.value >= 2) { + pixelWidth = pixelWidth*6/8; + pixelHeight = pixelHeight*6/8; + } + } else { + Minecraft.getMinecraft().getTextureManager().bindTexture(mapIcons); + } + + x -= minRoomX*(renderRoomSize+renderConnSize); + y -= minRoomY*(renderRoomSize+renderConnSize); + + GlStateManager.pushMatrix(); + + GlStateManager.disableDepth(); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + + GlStateManager.translate(x, y, -0.02F); + GlStateManager.rotate(angle, 0.0F, 0.0F, 1.0F); + GlStateManager.translate(-0.5F, 0.5F, 0.0F); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer.pos(-pixelWidth/2f, pixelHeight/2f, 30+((float)k * -0.005F)).tex(minU, minV).endVertex(); + worldrenderer.pos(pixelWidth/2f, pixelHeight/2f, 30+((float)k * -0.005F)).tex(maxU, minV).endVertex(); + worldrenderer.pos(pixelWidth/2f, -pixelHeight/2f, 30+((float)k * -0.005F)).tex(maxU, maxV).endVertex(); + worldrenderer.pos(-pixelWidth/2f, -pixelHeight/2f, 30+((float)k * -0.005F)).tex(minU, maxV).endVertex(); + tessellator.draw(); + + if(headLayer) { + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer.pos(-pixelWidth/2f, pixelHeight/2f, 30+((float)k * -0.005F)+0.001f).tex(minU+0.5f, minV).endVertex(); + worldrenderer.pos(pixelWidth/2f, pixelHeight/2f, 30+((float)k * -0.005F)+0.001f).tex(maxU+0.5f, minV).endVertex(); + worldrenderer.pos(pixelWidth/2f, -pixelHeight/2f, 30+((float)k * -0.005F)+0.001f).tex(maxU+0.5f, maxV).endVertex(); + worldrenderer.pos(-pixelWidth/2f, -pixelHeight/2f, 30+((float)k * -0.005F)+0.001f).tex(minU+0.5f, maxV).endVertex(); + tessellator.draw(); + } + GlStateManager.popMatrix(); + k--; + } + + if(useFb) { + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + } else { + GL11.glDisable(GL11.GL_SCISSOR_TEST); + } + } GlStateManager.popMatrix(); + + if(useFb) { + Framebuffer renderFromBuffer = mapFramebuffer1; + if(useShd) { + GlStateManager.pushMatrix(); { + try { + upload(mapShader, mapSizeX, mapSizeY, scaleFactor, getBorderRadius()); + mapShader.setProjectionMatrix(projectionMatrix); + mapShader.loadShader(0); + renderFromBuffer = mapFramebuffer2; + } catch(Exception e) { + } + } GlStateManager.popMatrix(); + } + + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true); + + Utils.pushGuiScale(2); + + GlStateManager.translate(centerX, centerY, 100); + + renderFromBuffer.bindFramebufferTexture(); + Utils.drawTexturedRect(-mapSizeX/2, -mapSizeY/2, mapSizeX, mapSizeY, + 0, 1, 1, 0, GL11.GL_NEAREST); + GlStateManager.bindTexture(0); + + GlStateManager.translate(-centerX, -centerY, -100); + + Utils.pushGuiScale(-1); + } + + GlStateManager.translate(centerX, centerY, 100); + + if(NotEnoughUpdates.INSTANCE.manager.config.dmChromaBorder.value) { + int colour = SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.manager.config.dmBorderColour.value); + + Gui.drawRect(-mapCenterX-2, -mapCenterY-2, -mapCenterX, -mapCenterY, + colour); //topleft + Gui.drawRect(-mapCenterX-2, mapCenterY+2, -mapCenterX, mapCenterY, + SpecialColour.rotateHue(colour, -180)); //bottomleft + Gui.drawRect(mapCenterX, -mapCenterY-2, mapCenterX+2, mapCenterY, + SpecialColour.rotateHue(colour, -180)); //topright + Gui.drawRect(mapCenterX, mapCenterY, mapCenterX+2, mapCenterY+2, + colour); //bottomright + + for(int i=0; i<20; i++) { + int start1 = SpecialColour.rotateHue(colour, -9*i); + int start2 = SpecialColour.rotateHue(colour, -9*i-9); + int end1 = SpecialColour.rotateHue(colour, -180-9*i); + int end2 = SpecialColour.rotateHue(colour, -180-9*i-9); + + Utils.drawGradientRect(-mapCenterX-2, -mapCenterY+(int)(mapSizeY*(i/20f)), -mapCenterX, + -mapCenterY+(int)(mapSizeY*((i+1)/20f)), start1, start2); //left + Utils.drawGradientRect(mapCenterX, -mapCenterY+(int)(mapSizeX*(i/20f)), mapCenterX+2, + -mapCenterY+(int)(mapSizeX*((i+1)/20f)), + end1, end2); //right + Utils.drawGradientRectHorz(-mapCenterX+(int)(mapSizeX*(i/20f)), -mapCenterY-2, + -mapCenterX+(int)(mapSizeX*((i+1)/20f)), -mapCenterY, start1, start2); //top + Utils.drawGradientRectHorz(-mapCenterX+(int)(mapSizeX*(i/20f)), + mapCenterY, -mapCenterX+(int)(mapSizeX*((i+1)/20f)), mapCenterY+2, + end1, end2); //bottom + } + + } else { + Gui.drawRect(-mapCenterX-2, -mapCenterY, -mapCenterX, mapCenterY, + SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.manager.config.dmBorderColour.value)); //left + Gui.drawRect(mapCenterX, -mapCenterY, mapCenterX+2, mapCenterY, + SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.manager.config.dmBorderColour.value)); //right + Gui.drawRect(-mapCenterX-2, -mapCenterY-2, mapCenterX+2, -mapCenterY, + SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.manager.config.dmBorderColour.value)); //top + Gui.drawRect(-mapCenterX-2, mapCenterY, mapCenterX+2, mapCenterY+2, + SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.manager.config.dmBorderColour.value)); //bottom + } + + String sizeId = borderSizeOption == 0 ? "small" : borderSizeOption == 2 ? "large" : "medium"; + + ResourceLocation rl = new ResourceLocation("notenoughupdates:dungeon_map/borders/"+sizeId+"/"+ + NotEnoughUpdates.INSTANCE.manager.config.dmBorderStyle.value.intValue()+".png"); + if(Minecraft.getMinecraft().getTextureManager().getTexture(rl) != TextureUtil.missingTexture) { + Minecraft.getMinecraft().getTextureManager().bindTexture(rl); + GlStateManager.color(1, 1, 1, 1); + + int size = borderSizeOption == 0 ? 165 : borderSizeOption == 2 ? 300 : borderSizeOption == 3 ? 440 : 220; + Utils.drawTexturedRect(-size/2, -size/2, size, size, GL11.GL_NEAREST); + } + + GlStateManager.translate(-centerX, -centerY, -100); + } catch(Exception e) { + e.printStackTrace(); + Minecraft.getMinecraft().entityRenderer.setupOverlayRendering(); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true); + } + + Utils.pushGuiScale(-1); + + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.enableDepth(); + } + + + public void updateRoomConnections(RoomOffset roomOffset) { + if(roomMap.containsKey(roomOffset)) { + Room room = roomMap.get(roomOffset); + + int otherPixelFilled = 0; + int otherPixelColour = 0; + for(int xOff=0; xOff<roomSize; xOff++) { + for(int yOff=0; yOff<roomSize; yOff++) { + int x = startRoomX + roomOffset.x*(roomSize+connectorSize) + xOff; + int y = startRoomY + roomOffset.y*(roomSize+connectorSize) + yOff; + + if(x > 0 && y > 0 && x < colourMap.length && y < colourMap[x].length) { + Color c = colourMap[x][y]; + if(!c.equals(room.colour)) { + if(otherPixelColour == c.getRGB()) { + otherPixelFilled++; + } else { + otherPixelFilled--; + if(otherPixelFilled <= 0) { + otherPixelFilled = 1; + otherPixelColour = c.getRGB(); + } + } + } + } + } + } + + room.tickColour = 0; + if((float)otherPixelFilled/roomSize/connectorSize > 0.05) { + room.tickColour = otherPixelColour; + } + + for(int k=0; k<4; k++) { + Color colour = null; + int totalFilled = 0; + + for(int i=0; i<roomSize; i++) { + for(int j=1; j<=connectorSize; j++) { + int x = startRoomX + roomOffset.x*(roomSize+connectorSize); + int y = startRoomY + roomOffset.y*(roomSize+connectorSize); + + if(k == 0) { + x += i; + y -= j; + } else if(k == 1) { + x += roomSize+j-1; + y += i; + } else if(k == 2) { + x += i; + y += roomSize+j-1; + } else { + x -= j; + y += i; + } + + if(x > 0 && y > 0 && x < colourMap.length && y < colourMap[x].length) { + Color pixel = colourMap[x][y]; + if(pixel.getAlpha() > 40) { + if(colour == null) { + colour = pixel; + totalFilled = 1; + } else { + if(colour.equals(pixel)) { + totalFilled++; + } else { + totalFilled--; + if(totalFilled <= 0) { + colour = pixel; + totalFilled = 1; + } + } + } + } + } + } + } + float proportionFilled = (float)totalFilled/roomSize/connectorSize; + + RoomConnectionType type = RoomConnectionType.WALL; + if(proportionFilled > 0.8) { + type = RoomConnectionType.ROOM_DIVIDER; + } else if(proportionFilled > 0.1) { + type = RoomConnectionType.CORRIDOR; + } + if(k == 0) { + room.up = new RoomConnection(type, colour); + } else if(k == 1) { + room.right = new RoomConnection(type, colour); + } else if(k == 2) { + room.down = new RoomConnection(type, colour); + } else { + room.left = new RoomConnection(type, colour); + } + } + + int x = startRoomX + roomOffset.x*(roomSize+connectorSize) + roomSize + connectorSize/2; + int y = startRoomY + roomOffset.y*(roomSize+connectorSize) + roomSize + connectorSize/2; + + room.fillCorner = false; + if(x > 0 && y > 0 && x < colourMap.length && y < colourMap[x].length) { + Color pixel = colourMap[x][y]; + if(pixel.equals(room.colour)) { + room.fillCorner = true; + } + } + } + } + + public void loadNeighbors(RoomOffset room) { + if(!roomMap.containsKey(room)) { + roomMap.put(room, new Room()); + } + for(RoomOffset neighbor : room.getNeighbors()) { + if(!roomMap.containsKey(neighbor)) { + int x = startRoomX + neighbor.x*(roomSize+connectorSize); + int y = startRoomY + neighbor.y*(roomSize+connectorSize); + + if(x >= 0 && y >= 0 && x+roomSize < colourMap.length && y+roomSize < colourMap[x].length) { + if(colourMap[x][y].getAlpha() > 100) { + roomMap.put(neighbor, new Room()); + loadNeighbors(neighbor); + } + } + } + } + } + + public void updateRoomColours() { + for(Map.Entry<RoomOffset, Room> entry : roomMap.entrySet()) { + int x = startRoomX + entry.getKey().x*(roomSize+connectorSize); + int y = startRoomY + entry.getKey().y*(roomSize+connectorSize); + + try { + entry.getValue().colour = colourMap[x][y]; + } catch(Exception e) {} + } + } + + private class MapPosition { + public float roomOffsetX; + public float connOffsetX; + + public float roomOffsetY; + public float connOffsetY; + + public float rotation; + + public MapPosition(float roomOffsetX, float connOffsetX, float roomOffsetY, float connOffsetY) { + this.roomOffsetX = roomOffsetX; + this.connOffsetX = connOffsetX; + this.roomOffsetY = roomOffsetY; + this.connOffsetY = connOffsetY; + } + + public float getRenderX() { + return roomOffsetX*getRenderRoomSize() + connOffsetX*getRenderConnSize(); + } + + public float getRenderY() { + return roomOffsetY*getRenderRoomSize() + connOffsetY*getRenderConnSize(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MapPosition that = (MapPosition) o; + return Float.compare(that.roomOffsetX, roomOffsetX) == 0 && + Float.compare(that.connOffsetX, connOffsetX) == 0 && + Float.compare(that.roomOffsetY, roomOffsetY) == 0 && + Float.compare(that.connOffsetY, connOffsetY) == 0 && + Float.compare(that.rotation, rotation) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(roomOffsetX, connOffsetX, roomOffsetY, connOffsetY, rotation); + } + } + + private long lastClearCache = 0; + public void renderMap(int centerX, int centerY, Color[][] colourMap, Map<String, Vec4b> mapDecorations, + int roomSizeBlocks, Set<String> actualPlayers, boolean usePlayerPositions) { + if(!NotEnoughUpdates.INSTANCE.manager.config.dmEnable.value) return; + if(colourMap == null) return; + if(colourMap.length != 128) return; + if(colourMap[0].length != 128) return; + this.colourMap = colourMap; + + if(System.currentTimeMillis() - lastClearCache > 1000) { + roomMap.clear(); + startRoomX = -1; + startRoomY = -1; + connectorSize = -1; + roomSize = -1; + borderRadiusCache.clear(); + + lastClearCache = System.currentTimeMillis(); + } + + if(startRoomX < 0 || startRoomY < 0 || roomSize <= 0) { + for(int x=0; x<colourMap.length; x++) { + for(int y=0; y<colourMap[x].length; y++) { + Color c = colourMap[x][y]; + if(c.getAlpha() > 80) { + if(startRoomX < 0 && startRoomY < 0 && c.getRed() == 0 && c.getGreen() == 124 && c.getBlue() == 0) { + roomSize = 0; + out: + for(int xd=0; xd<=20; xd++) { + for(int yd=0; yd<=20; yd++) { + if(x+xd >= colourMap.length || y+yd >= colourMap[x+xd].length) continue; + Color c2 = colourMap[x+xd][y+yd]; + + if(c2.getGreen() != 124 || c2.getAlpha() <= 80) { + if(xd < 10 && yd < 10) { + break out; + } + } else { + roomSize = Math.max(roomSize, Math.min(xd+1, yd+1)); + } + if(xd == 20 && yd == 20) { + if(roomSize == 0) roomSize = 20; + startRoomX = x; + startRoomY = y; + } + } + } + } + } + } + } + } + + if(connectorSize <= 0) { + for(int i=0; i<roomSize; i++) { + for(int k=0; k<4; k++) { + for(int j=1; j<8; j++) { + int x; + int y; + + if(k == 0) { + x = startRoomX+i; + y = startRoomY-j; + } else if(k == 1) { + x = startRoomX+roomSize+j-1; + y = startRoomY+i; + } else if(k == 2) { + x = startRoomX+i; + y = startRoomY+roomSize+j-1; + } else { + x = startRoomX-j; + y = startRoomY+i; + } + + if(x > 0 && y > 0 && x < colourMap.length && y < colourMap[x].length) { + if(colourMap[x][y].getAlpha() > 80) { + if(j == 1) { + break; + } + connectorSize = Math.min(connectorSize, j-1); + } + } + } + } + } + + if(connectorSize <= 0) { + connectorSize = 4; + } + } + + for(EntityPlayer player : Minecraft.getMinecraft().theWorld.playerEntities) { + if(player instanceof AbstractClientPlayer && actualPlayers.contains(player.getName())) { + AbstractClientPlayer aplayer = (AbstractClientPlayer) player; + ResourceLocation skin = aplayer.getLocationSkin(); + if(skin != DefaultPlayerSkin.getDefaultSkin(aplayer.getUniqueID())) { + playerSkinMap.put(player.getName(), skin); + } + } + } + + playerEntityMapPositions.clear(); + if(usePlayerPositions) { + for(EntityPlayer player : Minecraft.getMinecraft().theWorld.playerEntities) { + if(actualPlayers.contains(player.getName())) { + float roomX = (float)player.posX / (roomSizeBlocks+1); + float roomY = (float)player.posZ / (roomSizeBlocks+1); + + float playerRoomOffsetX = (float) Math.floor(roomX); + float playerConnOffsetX = (float) Math.floor(roomX); + float playerRoomOffsetY = (float) Math.floor(roomY); + float playerConnOffsetY = (float) Math.floor(roomY); + + float roomXInBlocks = (float)player.posX % (roomSizeBlocks+1); + if(roomXInBlocks < 2) { //0,1 + playerConnOffsetX -= 2/5f-roomXInBlocks/5f; + } else if(roomXInBlocks > roomSizeBlocks-2) { //31,30,29 + playerRoomOffsetX++; + playerConnOffsetX += (roomXInBlocks - (roomSizeBlocks-2))/5f; + } else { + playerRoomOffsetX += (roomXInBlocks-2) / (roomSizeBlocks-4); + } + + float roomYInBlocks = (float)player.posZ % (roomSizeBlocks+1); + if(roomYInBlocks < 2) { //0,1 + playerConnOffsetY -= 2/5f-roomYInBlocks/5f; + } else if(roomYInBlocks > roomSizeBlocks-2) { //31,30,29 + playerRoomOffsetY++; + playerConnOffsetY += (roomYInBlocks - (roomSizeBlocks-2))/5f; + } else { + playerRoomOffsetY += (roomYInBlocks-2) / (roomSizeBlocks-4); + } + + playerRoomOffsetX -= startRoomX/(roomSize+connectorSize); + playerRoomOffsetY -= startRoomY/(roomSize+connectorSize); + playerConnOffsetX -= startRoomX/(roomSize+connectorSize); + playerConnOffsetY -= startRoomY/(roomSize+connectorSize); + + MapPosition pos = new MapPosition(playerRoomOffsetX, playerConnOffsetX, playerRoomOffsetY, playerConnOffsetY); + pos.rotation = player.rotationYawHead % 360; + if(pos.rotation < 0) pos.rotation += 360; + playerEntityMapPositions.put(player.getName(), pos); + } + } + } + + loadNeighbors(new RoomOffset(0, 0)); + updateRoomColours(); + for(RoomOffset offset : roomMap.keySet()) { + updateRoomConnections(offset); + } + + if(mapDecorations != null && mapDecorations.size() > 0) { + List<MapPosition> positions = new ArrayList<>(); + for (Vec4b vec4b : mapDecorations.values()) { + float x = (float) vec4b.func_176112_b() / 2.0F + 64.0F; + float y = (float) vec4b.func_176113_c() / 2.0F + 64.0F; + + x = Math.max(0, Math.min(160, x)); + y = Math.max(0, Math.min(160, y)); + + float deltaX = x - startRoomX; + float deltaY = y - startRoomY; + + float roomsOffsetX = (int) Math.floor(deltaX / (roomSize + connectorSize)); + float connOffsetX = (int) Math.floor(deltaX / (roomSize + connectorSize)); + float xRemainder = deltaX % (roomSize + connectorSize); + if (Math.abs(xRemainder) > roomSize) { + roomsOffsetX += Math.copySign(1, xRemainder); + connOffsetX += Math.copySign(1, xRemainder) * (Math.abs(xRemainder) - roomSize) / connectorSize; + } else { + roomsOffsetX += xRemainder / roomSize; + } + if (deltaX < 0 && xRemainder != 0) { + roomsOffsetX++; + connOffsetX++; + } + float roomsOffsetY = (int) Math.floor(deltaY / (roomSize + connectorSize)); + float connOffsetY = (int) Math.floor(deltaY / (roomSize + connectorSize)); + float yRemainder = deltaY % (roomSize + connectorSize); + if (Math.abs(yRemainder) > roomSize) { + roomsOffsetY += Math.copySign(1, yRemainder); + connOffsetY += Math.copySign(1, yRemainder) * (Math.abs(yRemainder) - roomSize) / connectorSize; + } else { + roomsOffsetY += yRemainder / roomSize; + } + if (deltaY < 0 && yRemainder != 0) { + roomsOffsetY++; + connOffsetY++; + } + + float angle = (float) (vec4b.func_176111_d() * 360) / 16.0F; + + MapPosition pos = new MapPosition(roomsOffsetX, connOffsetX, roomsOffsetY, connOffsetY); + pos.rotation = angle % 360; + if(pos.rotation < 0) pos.rotation += 360; + positions.add(pos); + } + + //System.out.println(playerMarkerMapPositions.size() + ":" + positions.size()); + boolean different = playerMarkerMapPositions.size() != positions.size(); + + if (!different) { + for (MapPosition pos : playerMarkerMapPositions.values()) { + if (!positions.contains(pos)) { + different = true; + break; + } + } + } + + if(different && positions.size() > 0) { + lastLastDecorationsMillis = lastDecorationsMillis; + lastDecorationsMillis = System.currentTimeMillis(); + + playerMarkerMapPositionsLast.clear(); + for (Map.Entry<String, MapPosition> entry : playerMarkerMapPositions.entrySet()) { + playerMarkerMapPositionsLast.put(entry.getKey(), entry.getValue()); + } + playerMarkerMapPositions.clear(); + + Set<String> foundPlayers = new HashSet<>(); + for (Map.Entry<String, MapPosition> entry : playerEntityMapPositions.entrySet()) { + playerMarkerMapPositions.put(entry.getKey(), entry.getValue()); + playerMarkerMapPositionsLast.put(entry.getKey(), entry.getValue()); + foundPlayers.add(entry.getKey()); + } + + HashMap<String, HashMap<Integer, Float>> distanceMap = new HashMap<>(); + for (Map.Entry<String, MapPosition> entry : playerMarkerMapPositionsLast.entrySet()) { + HashMap<Integer, Float> deltaDists = new HashMap<>(); + for (int i = 0; i < positions.size(); i++) { + float dx = entry.getValue().getRenderX() - positions.get(i).getRenderX(); + float dy = entry.getValue().getRenderY() - positions.get(i).getRenderY(); + deltaDists.put(i, dx * dx + dy * dy); + } + distanceMap.put(entry.getKey(), deltaDists); + } + + List<String> playerList = new ArrayList<>(playerMarkerMapPositionsLast.keySet()); + List<List<String>> playerPermutations = permutations(playerList); + + //if(playerPermutations.size() > 0 || playerMarkerMapPositionsLast.size() > 0) + // System.out.println("Perm Size: " + playerPermutations.size() + " from " + playerMarkerMapPositionsLast.size()); + + List<Integer> finalUsedIndexes = new ArrayList<>(); + if (playerPermutations.size() > 0) { + HashMap<String, Integer> smallestPermutation = null; + float smallestTotalDistance = 0; + + for (List<String> permutation : playerPermutations) { + HashMap<String, Integer> usedIndexes = new HashMap<>(); + + float totalDistance = 0; + for (String player : permutation) { + int smallestIndex = -1; + float smallestDist = 0; + for (Map.Entry<Integer, Float> entry : distanceMap.get(player).entrySet()) { + if (!usedIndexes.containsValue(entry.getKey())) { + if (smallestIndex == -1 || entry.getValue() < smallestDist) { + smallestIndex = entry.getKey(); + smallestDist = entry.getValue(); + } + } + } + if (smallestIndex != -1) { + usedIndexes.put(player, smallestIndex); + totalDistance += smallestDist; + } + } + + if (smallestPermutation == null || totalDistance < smallestTotalDistance) { + smallestPermutation = usedIndexes; + smallestTotalDistance = totalDistance; + } + } + + //System.out.println("--- PERM START ---"); + for (Map.Entry<String, Integer> entry : smallestPermutation.entrySet()) { + //System.out.println(entry.getKey() + ":" + entry.getValue() + " : Total dist: " + smallestTotalDistance); + finalUsedIndexes.add(entry.getValue()); + playerMarkerMapPositions.put(entry.getKey(), positions.get(entry.getValue())); + } + } + + List<Integer> nonUsedIndexes = new ArrayList<>(); + for(int i=0; i<positions.size(); i++) { + if(!finalUsedIndexes.contains(i)) { + nonUsedIndexes.add(i); + } + } + + for(String missingPlayer : actualPlayers) { + if(!playerList.contains(missingPlayer)) { + if(nonUsedIndexes.isEmpty()) break; + playerMarkerMapPositions.put(missingPlayer, positions.get(nonUsedIndexes.get(0))); + nonUsedIndexes.remove(0); + } + } + } + } else if(mapDecorations == null) { + playerMarkerMapPositions.clear(); + playerMarkerMapPositionsLast.clear(); + + for (Map.Entry<String, MapPosition> entry : playerEntityMapPositions.entrySet()) { + playerMarkerMapPositions.put(entry.getKey(), entry.getValue()); + } + } + + if(!roomMap.isEmpty() && startRoomX >= 0 && startRoomY >= 0) { + render(centerX, centerY); + } + + this.colourMap = colourMap; + } + + @SubscribeEvent(priority=EventPriority.HIGH) + public void onRenderOverlayPre(RenderGameOverlayEvent.Pre event) { + if(event.type == RenderGameOverlayEvent.ElementType.ALL && + NotEnoughUpdates.INSTANCE.manager.config.dmEnable.value && + NotEnoughUpdates.INSTANCE.manager.config.dmBackgroundBlur.value > 0.1) { + blurBackground(); + GlStateManager.enableBlend(); + GlStateManager.enableTexture2D(); + } + } + + @SubscribeEvent + public void onRenderOverlay(RenderGameOverlayEvent event) { + if(event.type == RenderGameOverlayEvent.ElementType.ALL) { + if(!NotEnoughUpdates.INSTANCE.manager.config.dmEnable.value) return; + + if(SBInfo.getInstance().getLocation() == null || !SBInfo.getInstance().getLocation().equals("dungeon")) { + return; + } + if(Minecraft.getMinecraft().gameSettings.showDebugInfo || + (Minecraft.getMinecraft().gameSettings.keyBindPlayerList.isKeyDown() && + (!Minecraft.getMinecraft().isIntegratedServerRunning() || + Minecraft.getMinecraft().thePlayer.sendQueue.getPlayerInfoMap().size() > 1))) { + return; + } + + ItemStack stack = Minecraft.getMinecraft().thePlayer.inventory.mainInventory[8]; + boolean holdingBow = stack != null && stack.getItem() == Items.arrow; + if(holdingBow || (stack != null && stack.getItem() instanceof ItemMap)) { + Map<String, Vec4b> decorations = null; + + Color[][] colourMap = new Color[128][128]; + if(holdingBow) { + for(int x=0; x<128; x++) { + for(int y=0; y<128; y++) { + if(this.colourMap != null && this.colourMap[x][y] != null) { + colourMap[x][y] = this.colourMap[x][y]; + } else { + colourMap[x][y] = new Color(0, true); + } + } + } + } else { + ItemMap map = (ItemMap) stack.getItem(); + MapData mapData = map.getMapData(stack, Minecraft.getMinecraft().theWorld); + + if(mapData == null) return; + + decorations = mapData.mapDecorations; + + for (int i = 0; i < 16384; ++i) { + int x = i % 128; + int y = i / 128; + + int j = mapData.colors[i] & 255; + + Color c; + if (j / 4 == 0) { + c = new Color((i + i / 128 & 1) * 8 + 16 << 24, true); + } else { + c = new Color(MapColor.mapColorArray[j / 4].func_151643_b(j & 3), true); + } + + colourMap[x][y] = c; + } + } + + int roomSizeBlocks = 31; + /*List<Integer> dists = new ArrayList<>(); + int currentBlockCount = 0; + for(int i=0; i<300; i++) { + IBlockState state = Minecraft.getMinecraft().theWorld.getBlockState(new BlockPos(0, 99, i)); + if(state == null || state.getBlock() == Blocks.air) { + if(currentBlockCount > 0) dists.add(currentBlockCount); + currentBlockCount = 0; + } else { + currentBlockCount++; + } + } + currentBlockCount = 0; + for(int i=0; i<300; i++) { + IBlockState state = Minecraft.getMinecraft().theWorld.getBlockState(new BlockPos(i, 99, 0)); + if(state == null || state.getBlock() == Blocks.air) { + if(currentBlockCount > 0) dists.add(currentBlockCount); + currentBlockCount = 0; + } else { + currentBlockCount++; + } + } + int count = 0; + int mostCommonDist = -1; + for(int dist : dists) { + if(dist == mostCommonDist) { + count++; + } else { + if(--count < 0) { + count = 1; + mostCommonDist = dist; + } + } + } + if(mostCommonDist > 31) roomSizeBlocks = mostCommonDist;*/ + + Set<String> actualPlayers = new HashSet<>(); + for(ScorePlayerTeam team : Minecraft.getMinecraft().thePlayer.getWorldScoreboard().getTeams()) { + if(team.getTeamName().startsWith("a")) { + actualPlayers.addAll(team.getMembershipCollection()); + } + } + + renderMap((int)(NotEnoughUpdates.INSTANCE.manager.config.dmCenterX.value/100*Minecraft.getMinecraft().displayWidth/2), + (int)(NotEnoughUpdates.INSTANCE.manager.config.dmCenterY.value/100*Minecraft.getMinecraft().displayHeight/2), + colourMap, decorations, roomSizeBlocks, actualPlayers, true); + } + } + } + + public List<List<String>> permutations(List<String> values) { + List<List<String>> permutations = new ArrayList<>(); + + if(values.size() == 1) { + permutations.add(values); + return permutations; + } + + for(String first : values) { + List<String> newList = new ArrayList<>(); + for(String val : values) { + if(!val.equals(first)) { + newList.add(val); + } + } + + for(List<String> list2 : permutations(newList)) { + List<String> perm = new ArrayList<>(); + perm.add(first); + perm.addAll(list2); + permutations.add(perm); + } + } + + return permutations; + } + + Shader blurShaderHorz = null; + Framebuffer blurOutputHorz = null; + Shader blurShaderVert = null; + Framebuffer blurOutputVert = null; + + /** + * Creates a projection matrix that projects from our coordinate space [0->width; 0->height] to OpenGL coordinate + * space [-1 -> 1; 1 -> -1] (Note: flipped y-axis). + * + * This is so that we can render to and from the framebuffer in a way that is familiar to us, instead of needing to + * apply scales and translations manually. + */ + private Matrix4f createProjectionMatrix(int width, int height) { + Matrix4f projMatrix = new Matrix4f(); + projMatrix.setIdentity(); + projMatrix.m00 = 2.0F / (float)width; + projMatrix.m11 = 2.0F / (float)(-height); + projMatrix.m22 = -0.0020001999F; + projMatrix.m33 = 1.0F; + projMatrix.m03 = -1.0F; + projMatrix.m13 = 1.0F; + projMatrix.m23 = -1.0001999F; + return projMatrix; + } + + private double lastBgBlurFactor = -1; + private void blurBackground() { + if(!OpenGlHelper.isFramebufferEnabled()) return; + + int width = Minecraft.getMinecraft().displayWidth; + int height = Minecraft.getMinecraft().displayHeight; + + if(blurOutputHorz == null) { + blurOutputHorz = new Framebuffer(width, height, false); + blurOutputHorz.setFramebufferFilter(GL11.GL_NEAREST); + } + if(blurOutputVert == null) { + blurOutputVert = new Framebuffer(width, height, false); + blurOutputVert.setFramebufferFilter(GL11.GL_NEAREST); + } + if(blurOutputHorz.framebufferWidth != width || blurOutputHorz.framebufferHeight != height) { + blurOutputHorz.createBindFramebuffer(width, height); + blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + if(blurOutputVert.framebufferWidth != width || blurOutputVert.framebufferHeight != height) { + blurOutputVert.createBindFramebuffer(width, height); + blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height)); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + + if(blurShaderHorz == null) { + try { + blurShaderHorz = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", + Minecraft.getMinecraft().getFramebuffer(), blurOutputHorz); + blurShaderHorz.getShaderManager().getShaderUniform("BlurDir").set(1, 0); + blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); + } catch(Exception e) { } + } + if(blurShaderVert == null) { + try { + blurShaderVert = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", + blurOutputHorz, blurOutputVert); + blurShaderVert.getShaderManager().getShaderUniform("BlurDir").set(0, 1); + blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height)); + } catch(Exception e) { } + } + if(blurShaderHorz != null && blurShaderVert != null) { + float blur = NotEnoughUpdates.INSTANCE.manager.config.dmBackgroundBlur.value.floatValue(); + blur = Math.max(0, Math.min(50, blur)); + if(blur != lastBgBlurFactor) { + blurShaderHorz.getShaderManager().getShaderUniform("Radius").set(blur); + blurShaderVert.getShaderManager().getShaderUniform("Radius").set(blur); + lastBgBlurFactor = blur; + } + GL11.glPushMatrix(); + blurShaderHorz.loadShader(0); + blurShaderVert.loadShader(0); + GlStateManager.enableDepth(); + GL11.glPopMatrix(); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + } + + /** + * Renders a subsection of the blurred framebuffer on to the corresponding section of the screen. + * Essentially, this method will "blur" the background inside the bounds specified by [x->x+blurWidth, y->y+blurHeight] + */ + public void renderBlurredBackground(int width, int height, int x, int y, int blurWidth, int blurHeight) { + if(!OpenGlHelper.isFramebufferEnabled()) return; + + if(blurOutputVert == null) return; + + float uMin = x/(float)width; + float uMax = (x+blurWidth)/(float)width; + float vMin = (height-y)/(float)height; + float vMax = (height-y-blurHeight)/(float)height; + + blurOutputVert.bindFramebufferTexture(); + GlStateManager.color(1f, 1f, 1f, 1f); + Utils.drawTexturedRectNoBlend(x, y, blurWidth, blurHeight, uMin, uMax, vMin, vMax, GL11.GL_LINEAR); + blurOutputVert.unbindFramebufferTexture(); + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonWin.java b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonWin.java new file mode 100644 index 00000000..f6538346 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonWin.java @@ -0,0 +1,406 @@ +package io.github.moulberry.notenoughupdates.dungeons; + +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; + +import java.awt.*; +import java.util.*; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DungeonWin { + + private static class Confetti { + private float x; + private float y; + private float xLast; + private float yLast; + private int life = 0; + private float xVel; + private float yVel; + private int id; + + public Confetti(float x, float y, float xVel, float yVel) { + this.x = x; + this.xLast = x; + this.y = y; + this.yLast = y; + this.xVel = xVel; + this.yVel = yVel; + this.id = rand.nextInt(16); + this.life = 20+rand.nextInt(10); + } + } + public static ResourceLocation CONFETTI = new ResourceLocation("notenoughupdates:dungeon_win/confetti.png"); + public static ResourceLocation SPLUS = new ResourceLocation("notenoughupdates:dungeon_win/splus.png"); + public static ResourceLocation S = new ResourceLocation("notenoughupdates:dungeon_win/s.png"); + public static ResourceLocation A = new ResourceLocation("notenoughupdates:dungeon_win/a.png"); + public static ResourceLocation B = new ResourceLocation("notenoughupdates:dungeon_win/b.png"); + public static ResourceLocation C = new ResourceLocation("notenoughupdates:dungeon_win/c.png"); + public static ResourceLocation D = new ResourceLocation("notenoughupdates:dungeon_win/d.png"); + public static ResourceLocation TEAM_SCORE = SPLUS; + + private static final int SCALE_FACTOR = 3; + private static final int WIDTH = 32*SCALE_FACTOR; + private static final int HEIGHT = 16*SCALE_FACTOR; + + private static boolean hideChat = false; + private static long lastDungeonFinish = 0; + private static final Pattern TEAM_SCORE_REGEX = Pattern.compile("Team Score: [0-9]+ \\((S\\+|S|A|B|C|D)\\)"); + + private static final ScheduledExecutorService SES = Executors.newScheduledThreadPool(1); + + public static Random rand = new Random(); + public static List<Confetti> confetti = new ArrayList<>(); + public static List<String> text = new ArrayList<>(); + public static long startTime = 0; + + static { + for(int i=0; i<10; i++) { + text.add("{PLACEHOLDER DUNGEON STAT #"+i+"}"); + } + } + + public static void displayWin() { + if(NotEnoughUpdates.INSTANCE.manager.config.dungeonWinMillis.value < 100) return; + startTime = System.currentTimeMillis(); + confetti.clear(); + } + + public static void tick() { + if(NotEnoughUpdates.INSTANCE.manager.config.dungeonWinMillis.value < 100) return; + if(System.currentTimeMillis() - startTime > 5000) return; + int deltaTime = (int)(System.currentTimeMillis() - startTime); + + if(deltaTime < 1000) { + ScaledResolution sr = Utils.pushGuiScale(2); + int cap = 0; + switch(TEAM_SCORE.getResourcePath()) { + case "dungeon_win/splus.png": + cap = 200; break; + case "dungeon_win/s.png": + cap = 100; break; + case "dungeon_win/a.png": + cap = 50; break; + } + int maxConfetti = Math.min(cap, deltaTime/5); + while(confetti.size() < maxConfetti) { + int y; + if(deltaTime < 500) { + y = sr.getScaledHeight()/2-(int)(Math.sin(deltaTime/1000f*Math.PI)*sr.getScaledHeight()/9); + } else { + y = sr.getScaledHeight()/6+(int)(Math.sin(deltaTime/1000f*Math.PI)*sr.getScaledHeight()*4/18); + } + int xOffset = -WIDTH/2+rand.nextInt(WIDTH); + int x = sr.getScaledWidth()/2+xOffset; + + int xVel = xOffset/2; + int yVel = -25-rand.nextInt(10)+Math.abs(xVel)/2; + + confetti.add(new Confetti(x, y, xVel, yVel)); + } + } else { + Set<Confetti> toRemove = new HashSet<>(); + for(Confetti c : confetti) { + if(c.life <= 0) { + toRemove.add(c); + } + } + try { + confetti.removeAll(toRemove); + } catch(ConcurrentModificationException ignored) {} + } + + Utils.pushGuiScale(-1); + for(Confetti c : confetti) { + c.yVel += 1; + c.xVel /= 1.1f; + c.yVel /= 1.1f; + c.xLast = c.x; + c.yLast = c.y; + c.x += c.xVel; + c.y += c.yVel; + c.life--; + } + } + + public static void onChatMessage(ClientChatReceivedEvent e) { + if(NotEnoughUpdates.INSTANCE.manager.config.dungeonWinMillis.value < 100) return; + long currentTime = System.currentTimeMillis(); + String unformatted = Utils.cleanColour(e.message.getUnformattedText()); + if(e.message.getFormattedText().startsWith(EnumChatFormatting.RESET+" ")) { + if(currentTime - lastDungeonFinish > 10000) { + Matcher matcher = TEAM_SCORE_REGEX.matcher(unformatted); + if(matcher.find()) { + lastDungeonFinish = currentTime; + + String score = matcher.group(1); + System.out.println(score); + switch (score.toUpperCase()) { + case "S+": + TEAM_SCORE = SPLUS; break; + case "S": + TEAM_SCORE = S; break; + case "A": + TEAM_SCORE = A; break; + case "B": + TEAM_SCORE = B; break; + case "C": + TEAM_SCORE = C; break; + default: + TEAM_SCORE = D; break; + } + + SES.schedule(()->{ + NotEnoughUpdates.INSTANCE.sendChatMessage("/showextrastats"); + }, 100L, TimeUnit.MILLISECONDS); + } + } + } + if(currentTime - lastDungeonFinish > 100 && currentTime - lastDungeonFinish < 10000) { + if(hideChat) { + e.setCanceled(true); + if(unformatted.contains("\u25AC")) { + hideChat = false; + lastDungeonFinish = 0; + displayWin(); + } else { + if(unformatted.trim().length() > 0) { + text.add(e.message.getFormattedText().substring(2).trim()); + } + } + } else { + if(unformatted.contains("\u25AC")) { + hideChat = true; + text.clear(); + e.setCanceled(true); + } + } + + } + } + + public static void render(float partialTicks) { + if(NotEnoughUpdates.INSTANCE.manager.config.dungeonWinMillis.value < 100) return; + int maxTime = Math.min(30000, NotEnoughUpdates.INSTANCE.manager.config.dungeonWinMillis.value.intValue()); + if(System.currentTimeMillis() - startTime > maxTime) return; + int deltaTime = (int)(System.currentTimeMillis() - startTime); + + float alpha = Math.max(0, Math.min(1, 1-(deltaTime-maxTime+150)/150f)); + + ScaledResolution sr = Utils.pushGuiScale(2); + + if(deltaTime > 600) { + float bottom; + if(deltaTime < 1000) { + bottom = sr.getScaledHeight()/6f+(float)Math.sin(deltaTime/1000f*Math.PI)*sr.getScaledHeight()*4/18+HEIGHT/2; + } else { + bottom = sr.getScaledHeight()/6f+HEIGHT/2; + } + for(int i=0; i<text.size(); i++) { + String line = text.get(i); + float textCenterY = sr.getScaledHeight()/6f+HEIGHT/2+7+i*10; + if(textCenterY > bottom) { + int textAlpha = (int)(alpha * (deltaTime > 1000 ? 255 : Math.min(255, (textCenterY-bottom)/30f*255))); + GlStateManager.enableBlend(); + + if(textAlpha > 150) { + for(int xOff=-2; xOff<=2; xOff++) { + for(int yOff=-2; yOff<=2; yOff++) { + if(Math.abs(xOff) != Math.abs(yOff)) { + Utils.drawStringCentered(Utils.cleanColourNotModifiers(line), Minecraft.getMinecraft().fontRendererObj, + sr.getScaledWidth()/2+xOff/2f, textCenterY+yOff/2f, false, + ((textAlpha/Math.max(Math.abs(xOff), Math.abs(yOff))) << 24)); + } + } + } + } + + Utils.drawStringCentered(line, Minecraft.getMinecraft().fontRendererObj, + sr.getScaledWidth()/2, textCenterY, false, (textAlpha << 24) | 0x00FFFFFF); + } + } + } + + for(Confetti c : confetti) { + Minecraft.getMinecraft().getTextureManager().bindTexture(CONFETTI); + GlStateManager.color(1, 1, 1, 1); + if(c.life >= 15) { + GlStateManager.color(1, 1, 1, Math.min(1, c.life/4f)); + Utils.drawTexturedRect(c.xLast+(c.x-c.xLast)*partialTicks-4, c.yLast+(c.y-c.yLast)*partialTicks-4, + 8, 8, (c.id%4)/4f, (c.id%4+1)/4f, (c.id/4)/4f, (c.id/4+1)/4f, GL11.GL_NEAREST); + } + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(TEAM_SCORE); + GlStateManager.color(1, 1, 1, alpha); + + GlStateManager.pushMatrix(); + if(deltaTime < 1600) { + GlStateManager.translate(sr.getScaledWidth()/2, 0, 0); + if(deltaTime < 500) { + GlStateManager.translate(0, sr.getScaledHeight()/2f-Math.sin(deltaTime/1000f*Math.PI)*sr.getScaledHeight()/9, 0); + } else if(deltaTime < 1000) { + GlStateManager.translate(0, sr.getScaledHeight()/6f+Math.sin(deltaTime/1000f*Math.PI)*sr.getScaledHeight()*4/18, 0); + } else { + GlStateManager.translate(0, sr.getScaledHeight()/6f, 0); + } + if(deltaTime < 200) { + float scale = deltaTime/200f; + GlStateManager.scale(scale, scale, 1); + } else if(deltaTime < 1000) { + float scale = 1+(float)Math.sin((deltaTime-200)/800f*Math.PI)*0.8f; + GlStateManager.scale(scale, scale, 1); + } else if(deltaTime < 1100) { + float scale = 1+(float)Math.sin((deltaTime-1000)/100f*Math.PI)*0.15f; + GlStateManager.scale(scale, scale, 1); + } + + if(deltaTime < 600) { + GlStateManager.rotate(180+deltaTime/600f*180, 0, 1, 0); + GlStateManager.rotate(180-deltaTime/600f*180, 1, 0, 0); + GlStateManager.rotate(-180-deltaTime/600f*165, 0, 0, 1); + } else if(deltaTime < 1000) { + GlStateManager.rotate(15-(deltaTime-600)/400f*11, 0, 0, 1); + } else { + float logFac = 1-(float)Math.log((deltaTime-1000)/600f*1.7f+1); + logFac = logFac*logFac; + + GlStateManager.rotate(4f*logFac, 0, 0, 1); + float x = (deltaTime-1000)/300f; + GlStateManager.rotate((float)(40*(1-Math.log(x*0.85f+1))*Math.sin(10*x*x)), 0, 1, 0); + } + } else { + GlStateManager.translate(sr.getScaledWidth()/2, sr.getScaledHeight()/6f, 0); + } + + GlStateManager.disableCull(); + + Utils.drawTexturedRect(-WIDTH/2, -HEIGHT/2, WIDTH, HEIGHT, GL11.GL_NEAREST); + GlStateManager.translate(0, 0, -SCALE_FACTOR*2); + Utils.drawTexturedRect(-WIDTH/2, -HEIGHT/2, WIDTH, HEIGHT, GL11.GL_NEAREST); + GlStateManager.translate(0, 0, SCALE_FACTOR*2); + + if(deltaTime < 1600) { + float epsilon = 0.01f; + for(int xIndex=0; xIndex<32; xIndex++) { + for(int yIndex=0; yIndex<16; yIndex++) { + float uMin = xIndex/32f; + float uMax = (xIndex+1)/32f; + float vMin = yIndex/16f; + float vMax = (yIndex+1)/16f; + + int x = -WIDTH/2+xIndex*SCALE_FACTOR; + int y = -HEIGHT/2+yIndex*SCALE_FACTOR; + + GlStateManager.enableTexture2D(); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + //Left + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer + .pos(x+epsilon, y+SCALE_FACTOR, 0.0D+epsilon) + .tex(uMin, vMax).endVertex(); + worldrenderer + .pos(x+epsilon, y, 0.0D+epsilon) + .tex(uMax, vMax).endVertex(); + worldrenderer + .pos(x+epsilon, y, -SCALE_FACTOR*2-epsilon) + .tex(uMax, vMin).endVertex(); + worldrenderer + .pos(x+epsilon, y+SCALE_FACTOR, -SCALE_FACTOR*2-epsilon) + .tex(uMin, vMin).endVertex(); + tessellator.draw(); + //Right + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer + .pos(x+SCALE_FACTOR-epsilon, y+SCALE_FACTOR, 0.0D+epsilon) + .tex(uMin, vMax).endVertex(); + worldrenderer + .pos(x+SCALE_FACTOR-epsilon, y, 0.0D+epsilon) + .tex(uMax, vMax).endVertex(); + worldrenderer + .pos(x+SCALE_FACTOR-epsilon, y, -SCALE_FACTOR*2-epsilon) + .tex(uMax, vMin).endVertex(); + worldrenderer + .pos(x+SCALE_FACTOR-epsilon, y+SCALE_FACTOR, -SCALE_FACTOR*2-epsilon) + .tex(uMin, vMin).endVertex(); + tessellator.draw(); + //Top + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer + .pos(x+SCALE_FACTOR, y+epsilon, 0.0D+epsilon) + .tex(uMin, vMax).endVertex(); + worldrenderer + .pos(x, y+epsilon, 0.0D+epsilon) + .tex(uMax, vMax).endVertex(); + worldrenderer + .pos(x, y+epsilon, -SCALE_FACTOR*2-epsilon) + .tex(uMax, vMin).endVertex(); + worldrenderer + .pos(x+SCALE_FACTOR, y+epsilon, -SCALE_FACTOR*2-epsilon) + .tex(uMin, vMin).endVertex(); + tessellator.draw(); + //Top + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer + .pos(x+SCALE_FACTOR, y+SCALE_FACTOR-epsilon, 0.0D+epsilon) + .tex(uMin, vMax).endVertex(); + worldrenderer + .pos(x, y+SCALE_FACTOR-epsilon, 0.0D+epsilon) + .tex(uMax, vMax).endVertex(); + worldrenderer + .pos(x, y+SCALE_FACTOR-epsilon, -SCALE_FACTOR*2-epsilon) + .tex(uMax, vMin).endVertex(); + worldrenderer + .pos(x+SCALE_FACTOR, y+SCALE_FACTOR-epsilon, -SCALE_FACTOR*2-epsilon) + .tex(uMin, vMin).endVertex(); + tessellator.draw(); + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + + GlStateManager.disableBlend(); + } + } + } + + GlStateManager.popMatrix(); + + for(Confetti c : confetti) { + Minecraft.getMinecraft().getTextureManager().bindTexture(CONFETTI); + GlStateManager.color(1, 1, 1, 1); + if(c.life > 0 && c.life < 15) { + GlStateManager.color(1, 1, 1, Math.min(1, c.life/4f)); + Utils.drawTexturedRect(c.xLast+(c.x-c.xLast)*partialTicks-4, c.yLast+(c.y-c.yLast)*partialTicks-4, + 8, 8, (c.id%4)/4f, (c.id%4+1)/4f, (c.id/4)/4f, (c.id/4+1)/4f, GL11.GL_NEAREST); + } + } + + Utils.pushGuiScale(-1); + + GlStateManager.enableBlend(); + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/dungeons/GuiDungeonMapEditor.java b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/GuiDungeonMapEditor.java new file mode 100644 index 00000000..5890b5c0 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/GuiDungeonMapEditor.java @@ -0,0 +1,845 @@ +package io.github.moulberry.notenoughupdates.dungeons; + +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField; +import io.github.moulberry.notenoughupdates.options.Options; +import io.github.moulberry.notenoughupdates.util.SpecialColour; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.client.shader.Shader; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.Matrix4f; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Vec4b; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.*; +import java.util.List; + +import static io.github.moulberry.notenoughupdates.GuiTextures.*; +import static io.github.moulberry.notenoughupdates.GuiTextures.colour_selector_dot; + +public class GuiDungeonMapEditor extends GuiScreen { + + public static final ResourceLocation BACKGROUND = new ResourceLocation("notenoughupdates:dungeon_map/editor/background.png"); + public static final ResourceLocation BUTTON = new ResourceLocation("notenoughupdates:button.png"); + private static final DungeonMap demoMap = new DungeonMap(); + + private int sizeX; + private int sizeY; + private int guiLeft; + private int guiTop; + + private List<Button> buttons = new ArrayList<>(); + + private static final int colourEditorBG = new Color(80, 80, 80, 220).getRGB(); + private static ResourceLocation colourPickerLocation = new ResourceLocation("notenoughupdates:dynamic/colourpicker"); + private static ResourceLocation colourPickerBarValueLocation = new ResourceLocation("notenoughupdates:dynamic/colourpickervalue"); + private static ResourceLocation colourPickerBarOpacityLocation = new ResourceLocation("notenoughupdates:dynamic/colourpickeropacity"); + + private GuiElementTextField hexField = new GuiElementTextField("", + GuiElementTextField.SCALE_TEXT | GuiElementTextField.FORCE_CAPS | GuiElementTextField.NO_SPACE); + + private GuiElementTextField xField = new GuiElementTextField("", GuiElementTextField.NUM_ONLY | GuiElementTextField.NO_SPACE); + private GuiElementTextField yField = new GuiElementTextField("", GuiElementTextField.NUM_ONLY | GuiElementTextField.NO_SPACE); + private GuiElementTextField blurField = new GuiElementTextField("", GuiElementTextField.NUM_ONLY | GuiElementTextField.NO_SPACE); + private ColourEditor activeColourEditor = null; + + private class ColourEditor { + public int x; + public int y; + public Options.Option<String> option; + public String special; + + public ColourEditor(int x, int y, Options.Option<String> option, String special) { + this.x = x; + this.y = y; + this.option = option; + this.special = special; + } + } + + class Button { + private int id; + private int x; + private int y; + private String text; + private Color colour = new Color(-1, true); + private Options.Option<?> option; + + public Button(int id, int x, int y, String text) { + this(id, x, y, text, null); + } + + public Button(int id, int x, int y, String text, Options.Option<?> option) { + this.id = id; + this.x = x; + this.y = y; + this.text = text; + this.option = option; + } + + public List<String> getTooltip() { + if(option == null) { + return null; + } + + List<String> tooltip = new ArrayList<>(); + tooltip.add(EnumChatFormatting.YELLOW+option.displayName); + for(String line : option.desc.split("\n")) { + tooltip.add(EnumChatFormatting.AQUA+line); + } + return tooltip; + } + + public void render() { + if(text == null) return; + + Minecraft.getMinecraft().getTextureManager().bindTexture(BUTTON); + if(isButtonPressed(id)) { + GlStateManager.color(colour.getRed()*0.85f/255f, colour.getGreen()*0.85f/255f, + colour.getBlue()*0.85f/255f, 1); + Utils.drawTexturedRect(guiLeft+x, guiTop+y, 48, 16, 1, 0, 1, 0, GL11.GL_NEAREST); + } else { + GlStateManager.color(colour.getRed()/255f, colour.getGreen()/255f, colour.getBlue()/255f, 1); + Utils.drawTexturedRect(guiLeft+x, guiTop+y, 48, 16, GL11.GL_NEAREST); + } + + if(text.length() > 0) { + Utils.drawStringCenteredScaledMaxWidth(text, Minecraft.getMinecraft().fontRendererObj , guiLeft+x+24, guiTop+y+8, false, 39, 0xFF000000); + } + } + + } + + public GuiDungeonMapEditor() { + Options options = NotEnoughUpdates.INSTANCE.manager.config; + //Map Border Size + buttons.add(new Button(0, 6, 37, "Small", options.dmBorderSize)); + buttons.add(new Button(1, 52, 37, "Medium", options.dmBorderSize)); + buttons.add(new Button(2, 98, 37, "Large", options.dmBorderSize)); + + //Map Rooms Size + buttons.add(new Button(3, 6, 67+19, "Small", options.dmRoomSize)); + buttons.add(new Button(4, 52, 67+19, "Medium", options.dmRoomSize)); + buttons.add(new Button(5, 98, 67+19, "Large", options.dmRoomSize)); + + //Map Border Styles + buttons.add(new Button(6, 6, 97+38, "None")); + buttons.add(new Button(7, 52, 97+38, "Custom")); + buttons.add(new Button(8, 98, 97+38, "Stone")); + buttons.add(new Button(9, 6, 116+38, "Wood")); + buttons.add(new Button(10, 52, 116+38, "Rustic(S)")); + buttons.add(new Button(11, 98, 116+38, "Rustic(C)")); + buttons.add(new Button(12, 6, 135+38, "Fade")); + buttons.add(new Button(13, 52, 135+38, "Ribbons")); + buttons.add(new Button(14, 98, 135+38, "Paper")); + buttons.add(new Button(15, 6, 154+38, "Crimson")); + buttons.add(new Button(16, 52, 154+38, "Ornate")); + buttons.add(new Button(17, 98, 154+38, "Dragon")); + + //Dungeon Map + buttons.add(new Button(18, 20+139, 36, "Yes/No", options.dmEnable)); + //Center + buttons.add(new Button(19, 84+139, 36, "Player/Map", options.dmCenterPlayer)); + //Rotate + buttons.add(new Button(20, 20+139, 65, "Player/No Rotate", options.dmRotatePlayer)); + //Icon Style + buttons.add(new Button(21, 84+139, 65, "Default/Heads", options.dmPlayerHeads)); + //Check Orient + buttons.add(new Button(22, 20+139, 94, "Normal/Reorient", options.dmOrientCheck)); + //Check Center + buttons.add(new Button(23, 84+139, 94, "Yes/No", options.dmCenterCheck)); + //Interpolation + buttons.add(new Button(24, 20+139, 123, "Yes/No", options.dmPlayerInterp)); + //Compatibility + buttons.add(new Button(25, 84+139, 123, "Normal/No SHD/No FB/SHD", options.dmCompat)); + + //Background + buttons.add(new Button(26, 20+139, 152, "", options.dmBackgroundColour)); + //Border + buttons.add(new Button(27, 84+139, 152, "", options.dmBorderColour)); + + //Chroma Mode + buttons.add(new Button(28, 84+139, 181, "Normal/Scroll", options.dmChromaBorder)); + + buttons.add(new Button(29, 52, 86+19, "XLarge", options.dmRoomSize)); + buttons.add(new Button(30, 52, 56, "XLarge", options.dmBorderSize)); + + xField.setText(String.valueOf(NotEnoughUpdates.INSTANCE.manager.config.dmCenterX.value)); + yField.setText(String.valueOf(NotEnoughUpdates.INSTANCE.manager.config.dmCenterY.value)); + blurField.setText(String.valueOf(NotEnoughUpdates.INSTANCE.manager.config.dmBackgroundBlur.value)); + } + + private void showColourEditor(int mouseX, int mouseY, Options.Option<String> option, String special) { + activeColourEditor = new ColourEditor(mouseX, mouseY, option, special); + hexField.otherComponentClick(); + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + ScaledResolution scaledResolution = Utils.pushGuiScale(2); + this.width = scaledResolution.getScaledWidth(); + this.height = scaledResolution.getScaledHeight(); + + mouseX = Mouse.getEventX() * this.width / this.mc.displayWidth; + mouseY = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1; + + List<String> tooltipToDisplay = null; + for(Button button : buttons) { + if(mouseX >= guiLeft+button.x && mouseX <= guiLeft+button.x+48 && + mouseY >= guiTop+button.y-13 && mouseY <= guiTop+button.y+16) { + if(button.id >= 6 && button.id <= 17) { + String mapDesc = null; + String mapCredit = null; + int id = button.id; + switch(id) { + case 6: + mapDesc = "No Border"; break; + case 7: + mapDesc = "Used by custom Resource Packs"; break; + case 8: + mapDesc = "Simple gray border"; mapCredit = "TomEngMaster"; break; + case 9: + mapDesc = "Viney wood border"; mapCredit = "iDevil4Hell"; break; + case 10: + mapDesc = "Steampunk-inspired square border"; mapCredit = "ThatGravyBoat"; break; + case 11: + mapDesc = "Steampunk-inspired circular border"; mapCredit = "ThatGravyBoat"; break; + case 12: + mapDesc = "Light fade border"; mapCredit = "Qwiken"; break; + case 13: + mapDesc = "Simple gray border with red ribbons"; mapCredit = "Sai"; break; + case 14: + mapDesc = "Paper border"; mapCredit = "KingJames02st"; break; + case 15: + mapDesc = "Nether-inspired border"; mapCredit = "DTRW191"; break; + case 16: + mapDesc = "Golden ornate border"; mapCredit = "iDevil4Hell"; break; + case 17: + mapDesc = "Stone dragon border"; mapCredit = "ImperiaL"; break; + } + + ArrayList<String> tooltip = new ArrayList<>(); + tooltip.add(EnumChatFormatting.YELLOW+"Border Style"); + tooltip.add(EnumChatFormatting.AQUA+"Customize the look of the dungeon border"); + tooltip.add(""); + if(mapDesc != null) tooltip.add(EnumChatFormatting.YELLOW+"Set to: "+EnumChatFormatting.AQUA+mapDesc); + if(mapCredit != null) tooltip.add(EnumChatFormatting.YELLOW+"Artist: "+EnumChatFormatting.GOLD+mapCredit); + tooltipToDisplay = tooltip; + } else { + tooltipToDisplay = button.getTooltip(); + } + break; + } + } + + this.sizeX = 431; + this.sizeY = 237; + this.guiLeft = (this.width - this.sizeX) / 2; + this.guiTop = (this.height-this.sizeY)/2; + + super.drawScreen(mouseX, mouseY, partialTicks); + drawDefaultBackground(); + + blurBackground(); + renderBlurredBackground(width, height, guiLeft+2, guiTop+2, sizeX-4, sizeY-4); + + Minecraft.getMinecraft().getTextureManager().bindTexture(BACKGROUND); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST); + + Minecraft.getMinecraft().fontRendererObj.drawString("NEU Dungeon Map Editor", guiLeft+8, guiTop+6, 0xFFB4B4B4); + + Utils.drawStringCenteredScaledMaxWidth("Map Border Size", Minecraft.getMinecraft().fontRendererObj, + guiLeft+76, guiTop+30, false, 137, 0xFFB4B4B4); + Utils.drawStringCenteredScaledMaxWidth("Map Rooms Size", Minecraft.getMinecraft().fontRendererObj, + guiLeft+76, guiTop+60+19, false, 137, 0xFFB4B4B4); + Utils.drawStringCenteredScaledMaxWidth("Map Border Style", Minecraft.getMinecraft().fontRendererObj, + guiLeft+76, guiTop+90+38, false, 137, 0xFFB4B4B4); + + Utils.drawStringCenteredScaledMaxWidth("Dungeon Map", Minecraft.getMinecraft().fontRendererObj, + guiLeft+44+139, guiTop+30, false, 60, 0xFFB4B4B4); + Utils.drawStringCenteredScaledMaxWidth("Center", Minecraft.getMinecraft().fontRendererObj, + guiLeft+108+139, guiTop+30, false, 60, 0xFFB4B4B4); + + Utils.drawStringCenteredScaledMaxWidth("Rotate", Minecraft.getMinecraft().fontRendererObj, + guiLeft+44+139, guiTop+59, false, 60, 0xFFB4B4B4); + Utils.drawStringCenteredScaledMaxWidth("Icon Style", Minecraft.getMinecraft().fontRendererObj, + guiLeft+108+139, guiTop+59, false, 60, 0xFFB4B4B4); + + Utils.drawStringCenteredScaledMaxWidth("Check Orient", Minecraft.getMinecraft().fontRendererObj, + guiLeft+44+139, guiTop+88, false, 60, 0xFFB4B4B4); + Utils.drawStringCenteredScaledMaxWidth("Check Center", Minecraft.getMinecraft().fontRendererObj, + guiLeft+108+139, guiTop+88, false, 60, 0xFFB4B4B4); + + Utils.drawStringCenteredScaledMaxWidth("Interpolation", Minecraft.getMinecraft().fontRendererObj, + guiLeft+44+139, guiTop+117, false, 60, 0xFFB4B4B4); + Utils.drawStringCenteredScaledMaxWidth("Compatibility", Minecraft.getMinecraft().fontRendererObj, + guiLeft+108+139, guiTop+117, false, 60, 0xFFB4B4B4); + + Utils.drawStringCenteredScaledMaxWidth("Background", Minecraft.getMinecraft().fontRendererObj, + guiLeft+44+139, guiTop+146, false, 60, 0xFFB4B4B4); + Utils.drawStringCenteredScaledMaxWidth("Border", Minecraft.getMinecraft().fontRendererObj, + guiLeft+108+139, guiTop+146, false, 60, 0xFFB4B4B4); + + Utils.drawStringCenteredScaledMaxWidth("BG Blur", Minecraft.getMinecraft().fontRendererObj, + guiLeft+44+139, guiTop+175, false, 60, 0xFFB4B4B4); + Utils.drawStringCenteredScaledMaxWidth("Chroma Type", Minecraft.getMinecraft().fontRendererObj, + guiLeft+108+139, guiTop+175, false, 60, 0xFFB4B4B4); + + Utils.drawStringCenteredScaledMaxWidth("X (%)", Minecraft.getMinecraft().fontRendererObj, + guiLeft+44+139, guiTop+204, false, 60, 0xFFB4B4B4); + Utils.drawStringCenteredScaledMaxWidth("Y (%)", Minecraft.getMinecraft().fontRendererObj, + guiLeft+108+139, guiTop+204, false, 60, 0xFFB4B4B4); + + Options options = NotEnoughUpdates.INSTANCE.manager.config; + buttons.get(18).text = options.dmEnable.value ? "Enabled" : "Disabled"; + buttons.get(19).text = options.dmCenterPlayer.value ? "Player" : "Map"; + buttons.get(20).text = options.dmRotatePlayer.value ? "Player" : "Vertical"; + buttons.get(21).text = options.dmPlayerHeads.value <= 0 ? "Default" : options.dmPlayerHeads.value >= 3 ? "SmallHeads" : + options.dmPlayerHeads.value == 1 ? "Heads" : "ScaledHeads"; + buttons.get(22).text = options.dmOrientCheck.value ? "Orient" : "Off"; + buttons.get(23).text = options.dmCenterCheck.value ? "Center" : "Off"; + buttons.get(24).text = options.dmPlayerInterp.value ? "Interp" : "No Interp"; + buttons.get(25).text = options.dmCompat.value <= 0 ? "Normal" : options.dmCompat.value >= 2 ? "No FB/SHD" : "No SHD"; + + buttons.get(26).colour = new Color(SpecialColour.specialToChromaRGB(options.dmBackgroundColour.value)); + buttons.get(27).colour = new Color(SpecialColour.specialToChromaRGB(options.dmBorderColour.value)); + + buttons.get(28).text = options.dmChromaBorder.value ? "Scroll" : "Normal"; + + blurField.setSize(48, 16); + xField.setSize(48, 16); + yField.setSize(48, 16); + blurField.render(guiLeft+20+139, guiTop+181); + xField.render(guiLeft+20+139, guiTop+210); + yField.render(guiLeft+84+139, guiTop+210); + + Map<String, Vec4b> decorations = new HashMap<>(); + Vec4b vec4b = new Vec4b((byte)3, (byte)(((50)-64)*2), (byte)(((40)-64)*2), (byte)((60)*16/360)); + decorations.put(Minecraft.getMinecraft().thePlayer.getName(), vec4b); + + HashSet<String> players = new HashSet<>(); + players.add(Minecraft.getMinecraft().thePlayer.getName()); + GlStateManager.color(1, 1, 1, 1); + + demoMap.renderMap(guiLeft+357, guiTop+125, NotEnoughUpdates.INSTANCE.colourMap, decorations, 0, + players, false); + + for(Button button : buttons) { + button.render(); + } + + //List<String> textLines, final int mouseX, final int mouseY, final int screenWidth, final int screenHeight, final int maxTextWidth, FontRenderer font + if(tooltipToDisplay != null) { + Utils.drawHoveringText(tooltipToDisplay, mouseX, mouseY, width, height, 200, Minecraft.getMinecraft().fontRendererObj); + } + + if(activeColourEditor != null) { + Gui.drawRect(activeColourEditor.x, activeColourEditor.y, activeColourEditor.x+119, activeColourEditor.y+89, colourEditorBG); + + int currentColour = SpecialColour.specialToSimpleRGB(activeColourEditor.special); + Color c = new Color(currentColour, true); + float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null); + + BufferedImage bufferedImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB); + for(int x=0; x<256; x++) { + for(int y=0; y<256; y++) { + float radius = (float) Math.sqrt(((x-128)*(x-128)+(y-128)*(y-128))/16384f); + float angle = (float) Math.toDegrees(Math.atan((128-x)/(y-128+1E-5))+Math.PI/2); + if(y < 128) angle += 180; + if(radius <= 1) { + int rgb = Color.getHSBColor(angle/360f, (float)Math.pow(radius, 1.5f), hsv[2]).getRGB(); + bufferedImage.setRGB(x, y, rgb); + } + } + } + + BufferedImage bufferedImageValue = new BufferedImage(10, 64, BufferedImage.TYPE_INT_ARGB); + for(int x=0; x<10; x++) { + for(int y=0; y<64; y++) { + if((x == 0 || x == 9) && (y == 0 || y == 63)) continue; + + int rgb = Color.getHSBColor(hsv[0], hsv[1], (64-y)/64f).getRGB(); + bufferedImageValue.setRGB(x, y, rgb); + } + } + + BufferedImage bufferedImageOpacity = new BufferedImage(10, 64, BufferedImage.TYPE_INT_ARGB); + for(int x=0; x<10; x++) { + for(int y=0; y<64; y++) { + if((x == 0 || x == 9) && (y == 0 || y == 63)) continue; + + int rgb = (currentColour & 0x00FFFFFF) | (Math.min(255, (64-y)*4) << 24); + bufferedImageOpacity.setRGB(x, y, rgb); + } + } + + float selradius = (float) Math.pow(hsv[1], 1/1.5f)*32; + int selx = (int)(Math.cos(Math.toRadians(hsv[0]*360))*selradius); + int sely = (int)(Math.sin(Math.toRadians(hsv[0]*360))*selradius); + + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_bar_alpha); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(activeColourEditor.x+5+64+5+10+5, activeColourEditor.y+5, 10, 64, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().loadTexture(colourPickerBarValueLocation, new DynamicTexture(bufferedImageValue)); + Minecraft.getMinecraft().getTextureManager().bindTexture(colourPickerBarValueLocation); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(activeColourEditor.x+5+64+5, activeColourEditor.y+5, 10, 64, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().loadTexture(colourPickerBarOpacityLocation, new DynamicTexture(bufferedImageOpacity)); + Minecraft.getMinecraft().getTextureManager().bindTexture(colourPickerBarOpacityLocation); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(activeColourEditor.x+5+64+5+10+5, activeColourEditor.y+5, 10, 64, GL11.GL_NEAREST); + + int chromaSpeed = SpecialColour.getSpeed(activeColourEditor.special); + int currentColourChroma = SpecialColour.specialToChromaRGB(activeColourEditor.special); + Color cChroma = new Color(currentColourChroma, true); + float hsvChroma[] = Color.RGBtoHSB(cChroma.getRed(), cChroma.getGreen(), cChroma.getBlue(), null); + + if(chromaSpeed > 0) { + Gui.drawRect(activeColourEditor.x+5+64+5+10+5+10+5+1, activeColourEditor.y+5+1, + activeColourEditor.x+5+64+5+10+5+10+5+10-1, activeColourEditor.y+5+64-1, + Color.HSBtoRGB(hsvChroma[0], 0.8f, 0.8f)); + } else { + Gui.drawRect(activeColourEditor.x+5+64+5+10+5+10+5+1, activeColourEditor.y+5+27+1, + activeColourEditor.x+5+64+5+10+5+10+5+10-1, activeColourEditor.y+5+37-1, + Color.HSBtoRGB((hsvChroma[0]+(System.currentTimeMillis()-SpecialColour.startTime)/1000f)%1, 0.8f, 0.8f)); + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_bar); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(activeColourEditor.x+5+64+5, activeColourEditor.y+5, 10, 64, GL11.GL_NEAREST); + Utils.drawTexturedRect(activeColourEditor.x+5+64+5+10+5, activeColourEditor.y+5, 10, 64, GL11.GL_NEAREST); + + if(chromaSpeed > 0) { + Utils.drawTexturedRect(activeColourEditor.x+5+64+5+10+5+10+5, activeColourEditor.y+5, 10, 64, GL11.GL_NEAREST); + } else { + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_chroma); + Utils.drawTexturedRect(activeColourEditor.x+5+64+5+10+5+10+5, activeColourEditor.y+5+27, 10, 10, GL11.GL_NEAREST); + } + + Gui.drawRect(activeColourEditor.x+5+64+5, activeColourEditor.y+5+64-(int)(64*hsv[2]), + activeColourEditor.x+5+64+5+10, activeColourEditor.y+5+64-(int)(64*hsv[2])+1, 0xFF000000); + Gui.drawRect(activeColourEditor.x+5+64+5+10+5, activeColourEditor.y+5+64-c.getAlpha()/4, + activeColourEditor.x+5+64+5+10+5+10, activeColourEditor.y+5+64-c.getAlpha()/4-1, 0xFF000000); + if(chromaSpeed > 0) { + Gui.drawRect(activeColourEditor.x+5+64+5+10+5+10+5, + activeColourEditor.y+5+64-(int)(chromaSpeed/255f*64), + activeColourEditor.x+5+64+5+10+5+10+5+10, + activeColourEditor.y+5+64-(int)(chromaSpeed/255f*64)+1, 0xFF000000); + } + + Minecraft.getMinecraft().getTextureManager().loadTexture(colourPickerLocation, new DynamicTexture(bufferedImage)); + Minecraft.getMinecraft().getTextureManager().bindTexture(colourPickerLocation); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(activeColourEditor.x+5, activeColourEditor.y+5, 64, 64, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_dot); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(activeColourEditor.x+5+32+selx-4, activeColourEditor.y+5+32+sely-4, 8, 8, GL11.GL_NEAREST); + + Utils.drawStringCenteredScaledMaxWidth(EnumChatFormatting.GRAY.toString()+Math.round(hsv[2]*100)+"", + Minecraft.getMinecraft().fontRendererObj, + activeColourEditor.x+5+64+5+5-(Math.round(hsv[2]*100)==100?1:0), activeColourEditor.y+5+64+5+5, true, 13, -1); + Utils.drawStringCenteredScaledMaxWidth(EnumChatFormatting.GRAY.toString()+Math.round(c.getAlpha()/255f*100)+"", + Minecraft.getMinecraft().fontRendererObj, + activeColourEditor.x+5+64+5+15+5, activeColourEditor.y+5+64+5+5, true, 13, -1); + if(chromaSpeed > 0) { + Utils.drawStringCenteredScaledMaxWidth(EnumChatFormatting.GRAY.toString()+(int)SpecialColour.getSecondsForSpeed(chromaSpeed)+"s", + Minecraft.getMinecraft().fontRendererObj, + activeColourEditor.x+5+64+5+30+6, activeColourEditor.y+5+64+5+5, true, 13, -1); + } + + hexField.setSize(48, 10); + if(!hexField.getFocus()) hexField.setText(Integer.toHexString(c.getRGB() & 0xFFFFFF).toUpperCase()); + + StringBuilder sb = new StringBuilder(EnumChatFormatting.GRAY+"#"); + for(int i=0; i<6-hexField.getText().length(); i++) { + sb.append("0"); + } + sb.append(EnumChatFormatting.WHITE); + + hexField.setPrependText(sb.toString()); + hexField.render(activeColourEditor.x+5+8, activeColourEditor.y+5+64+5); + } + + Utils.pushGuiScale(-1); + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) { + for(Button button : buttons) { + if(mouseX >= guiLeft+button.x && mouseX <= guiLeft+button.x+48 && + mouseY >= guiTop+button.y && mouseY <= guiTop+button.y+16) { + buttonClicked(mouseX, mouseY, button.id); + + xField.otherComponentClick(); + yField.otherComponentClick(); + blurField.otherComponentClick(); + return; + } + } + + + if(mouseY > guiTop+181 && mouseY < guiTop+181+16) { + if(mouseX > guiLeft+20+139 && mouseX < guiLeft+20+139+48) { + blurField.mouseClicked(mouseX, mouseY, mouseButton); + xField.otherComponentClick(); + yField.otherComponentClick(); + return; + } + } else if(mouseY > guiTop+210 && mouseY < guiTop+210+16) { + if(mouseX > guiLeft+20+139 && mouseX < guiLeft+20+139+48) { + xField.mouseClicked(mouseX, mouseY, mouseButton); + yField.otherComponentClick(); + blurField.otherComponentClick(); + return; + } else if(mouseX > guiLeft+84+139 && mouseX < guiLeft+84+139+48) { + yField.mouseClicked(mouseX, mouseY, mouseButton); + xField.otherComponentClick(); + blurField.otherComponentClick(); + return; + } + } + + blurField.otherComponentClick(); + xField.otherComponentClick(); + yField.otherComponentClick(); + } + + @Override + public void handleMouseInput() throws IOException { + super.handleMouseInput(); + + int mouseX = Mouse.getEventX() * this.width / this.mc.displayWidth; + int mouseY = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1; + if(activeColourEditor != null && (Mouse.isButtonDown(0) || Mouse.isButtonDown(1))) { + if(mouseX >= activeColourEditor.x && mouseX <= activeColourEditor.x+119) { + if(mouseY >= activeColourEditor.y && mouseY <= activeColourEditor.y+89) { + if(Mouse.getEventButtonState()) { + if(mouseX > activeColourEditor.x+5+8 && mouseX < activeColourEditor.x+5+8+48) { + if(mouseY > activeColourEditor.y+5+64+5 && mouseY < activeColourEditor.y+5+64+5+10) { + hexField.mouseClicked(mouseX, mouseY, Mouse.getEventButton()); + Utils.pushGuiScale(-1); + return; + } + } + } + hexField.otherComponentClick(); + + int currentColour = SpecialColour.specialToSimpleRGB(activeColourEditor.special); + Color c = new Color(currentColour, true); + float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null); + + int xWheel = mouseX - activeColourEditor.x - 5; + int yWheel = mouseY - activeColourEditor.y - 5; + + if(xWheel > 0 && xWheel < 64) { + if(yWheel > 0 && yWheel < 64) { + float radius = (float) Math.sqrt(((xWheel-32)*(xWheel-32)+(yWheel-32)*(yWheel-32))/1024f); + float angle = (float) Math.toDegrees(Math.atan((32-xWheel)/(yWheel-32+1E-5))+Math.PI/2); + if(yWheel < 32) angle += 180; + + int rgb = Color.getHSBColor(angle/360f, (float)Math.pow(Math.min(1, radius), 1.5f), hsv[2]).getRGB(); + activeColourEditor.special = SpecialColour.special(SpecialColour.getSpeed(activeColourEditor.special), c.getAlpha(), rgb); + activeColourEditor.option.value = (String) activeColourEditor.special; + } + } + + int xValue = mouseX - (activeColourEditor.x+5+64+5); + int y = mouseY - activeColourEditor.y - 5; + + if(y > -5 && y <= 69) { + y = Math.max(0, Math.min(64, y)); + if(xValue > 0 && xValue < 10) { + int rgb = Color.getHSBColor(hsv[0], hsv[1], 1-y/64f).getRGB(); + activeColourEditor.special = SpecialColour.special(SpecialColour.getSpeed(activeColourEditor.special), c.getAlpha(), rgb); + activeColourEditor.option.value = activeColourEditor.special; + } + + int xOpacity = mouseX - (activeColourEditor.x+5+64+5+10+5); + + if(xOpacity > 0 && xOpacity < 10) { + activeColourEditor.special = SpecialColour.special(SpecialColour.getSpeed(activeColourEditor.special), + 255-(int)(y/64f*255), currentColour); + activeColourEditor.option.value = activeColourEditor.special; + } + } + + int chromaSpeed = SpecialColour.getSpeed(activeColourEditor.special); + + int xChroma = mouseX - (activeColourEditor.x+5+64+5+10+5+10+5); + if(xChroma > 0 && xChroma < 10) { + if(chromaSpeed > 0) { + if(y > -5 && y <= 69) { + y = Math.max(0, Math.min(64, y)); + activeColourEditor.special = SpecialColour.special(255-Math.round(y/64f*255), c.getAlpha(), currentColour); + activeColourEditor.option.value = activeColourEditor.special; + } + } else if(mouseY > activeColourEditor.y+5+27 && mouseY < activeColourEditor.y+5+37) { + activeColourEditor.special = SpecialColour.special(200, c.getAlpha(), currentColour); + activeColourEditor.option.value = activeColourEditor.special; + } + } + + try { NotEnoughUpdates.INSTANCE.manager.saveConfig(); } catch(IOException ignored) {} + return; + } + } + if(Mouse.getEventButtonState()) { + activeColourEditor = null; + hexField.otherComponentClick(); + } + } + } + + @Override + public void handleKeyboardInput() throws IOException { + super.handleKeyboardInput(); + + if(activeColourEditor != null && hexField.getFocus()) { + String old = hexField.getText(); + + hexField.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey()); + + if(hexField.getText().length() > 6) { + hexField.setText(old); + } else { + try { + String text = hexField.getText().toLowerCase(); + + int rgb = Integer.parseInt(text, 16); + int alpha = (SpecialColour.specialToSimpleRGB(activeColourEditor.special) >> 24) & 0xFF; + activeColourEditor.special = SpecialColour.special(SpecialColour.getSpeed(activeColourEditor.special), alpha, rgb); + activeColourEditor.option.value = activeColourEditor.special; + } catch(Exception e) {}; + } + } + } + + @Override + protected void keyTyped(char typedChar, int keyCode) throws IOException { + super.keyTyped(typedChar, keyCode); + + if(xField.getFocus()) { + xField.keyTyped(typedChar, keyCode); + + try { + xField.setCustomBorderColour(-1); + NotEnoughUpdates.INSTANCE.manager.config.dmCenterX.setValue(xField.getText()); + try { NotEnoughUpdates.INSTANCE.manager.saveConfig(); } catch(IOException ignored) {} + } catch(Exception e) { + xField.setCustomBorderColour(Color.RED.getRGB()); + } + } else if(yField.getFocus()) { + yField.keyTyped(typedChar, keyCode); + + try { + yField.setCustomBorderColour(-1); + NotEnoughUpdates.INSTANCE.manager.config.dmCenterY.setValue(yField.getText()); + try { NotEnoughUpdates.INSTANCE.manager.saveConfig(); } catch(IOException ignored) {} + } catch(Exception e) { + yField.setCustomBorderColour(Color.RED.getRGB()); + } + } else if(blurField.getFocus()) { + blurField.keyTyped(typedChar, keyCode); + + try { + blurField.setCustomBorderColour(-1); + NotEnoughUpdates.INSTANCE.manager.config.dmBackgroundBlur.setValue(blurField.getText()); + try { NotEnoughUpdates.INSTANCE.manager.saveConfig(); } catch(IOException ignored) {} + } catch(Exception e) { + blurField.setCustomBorderColour(Color.RED.getRGB()); + } + } + } + + private void buttonClicked(int mouseX, int mouseY, int id) { + Options options = NotEnoughUpdates.INSTANCE.manager.config; + switch (id) { + case 0: + options.dmBorderSize.value = 0.0; break; + case 1: + options.dmBorderSize.value = 1.0; break; + case 2: + options.dmBorderSize.value = 2.0; break; + case 30: + options.dmBorderSize.value = 3.0; break; + case 3: + options.dmRoomSize.value = 0.0; break; + case 4: + options.dmRoomSize.value = 1.0; break; + case 5: + options.dmRoomSize.value = 2.0; break; + case 29: + options.dmRoomSize.value = 3.0; break; + case 18: + options.dmEnable.value = !options.dmEnable.value; break; + case 19: + options.dmCenterPlayer.value = !options.dmCenterPlayer.value; break; + case 20: + options.dmRotatePlayer.value = !options.dmRotatePlayer.value; break; + case 21: + options.dmPlayerHeads.value++; + if(options.dmPlayerHeads.value > 3) options.dmPlayerHeads.value = 0.0;break; + case 22: + options.dmOrientCheck.value = !options.dmOrientCheck.value; break; + case 23: + options.dmCenterCheck.value = !options.dmCenterCheck.value; break; + case 24: + options.dmPlayerInterp.value = !options.dmPlayerInterp.value; break; + case 25: + options.dmCompat.value++; + if(options.dmCompat.value > 2) options.dmCompat.value = 0.0; + break; + case 26: + showColourEditor(mouseX, mouseY, options.dmBackgroundColour, options.dmBackgroundColour.value); break; + case 27: + showColourEditor(mouseX, mouseY, options.dmBorderColour, options.dmBorderColour.value); break; + case 28: + options.dmChromaBorder.value = !options.dmChromaBorder.value; break; + default: + if(id >= 6 && id <= 17) { + options.dmBorderStyle.value = (double)id-6; break; + } + } + try { NotEnoughUpdates.INSTANCE.manager.saveConfig(); } catch(IOException ignored) {}; + + } + + private boolean isButtonPressed(int id) { + Options options = NotEnoughUpdates.INSTANCE.manager.config; + + if(id >= 0 && id <= 2) { + return options.dmBorderSize.value == id; + } else if(id >= 3 && id <= 5) { + return options.dmRoomSize.value == id-3; + } else if(id >= 6 && id <= 17) { + return options.dmBorderStyle.value == id-6; + } else if(id == 29) { + return options.dmRoomSize.value == 3; + } else if(id == 30) { + return options.dmBorderSize.value == 3; + } + return false; + } + + Shader blurShaderHorz = null; + Framebuffer blurOutputHorz = null; + Shader blurShaderVert = null; + Framebuffer blurOutputVert = null; + + /** + * Creates a projection matrix that projects from our coordinate space [0->width; 0->height] to OpenGL coordinate + * space [-1 -> 1; 1 -> -1] (Note: flipped y-axis). + * + * This is so that we can render to and from the framebuffer in a way that is familiar to us, instead of needing to + * apply scales and translations manually. + */ + private Matrix4f createProjectionMatrix(int width, int height) { + Matrix4f projMatrix = new Matrix4f(); + projMatrix.setIdentity(); + projMatrix.m00 = 2.0F / (float)width; + projMatrix.m11 = 2.0F / (float)(-height); + projMatrix.m22 = -0.0020001999F; + projMatrix.m33 = 1.0F; + projMatrix.m03 = -1.0F; + projMatrix.m13 = 1.0F; + projMatrix.m23 = -1.0001999F; + return projMatrix; + } + + private double lastBgBlurFactor = -1; + private void blurBackground() { + if(!OpenGlHelper.isFramebufferEnabled()) return; + + int width = Minecraft.getMinecraft().displayWidth; + int height = Minecraft.getMinecraft().displayHeight; + + if(blurOutputHorz == null) { + blurOutputHorz = new Framebuffer(width, height, false); + blurOutputHorz.setFramebufferFilter(GL11.GL_NEAREST); + } + if(blurOutputVert == null) { + blurOutputVert = new Framebuffer(width, height, false); + blurOutputVert.setFramebufferFilter(GL11.GL_NEAREST); + } + if(blurOutputHorz.framebufferWidth != width || blurOutputHorz.framebufferHeight != height) { + blurOutputHorz.createBindFramebuffer(width, height); + blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + if(blurOutputVert.framebufferWidth != width || blurOutputVert.framebufferHeight != height) { + blurOutputVert.createBindFramebuffer(width, height); + blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height)); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + + if(blurShaderHorz == null) { + try { + blurShaderHorz = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", + Minecraft.getMinecraft().getFramebuffer(), blurOutputHorz); + blurShaderHorz.getShaderManager().getShaderUniform("BlurDir").set(1, 0); + blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); + } catch(Exception e) { } + } + if(blurShaderVert == null) { + try { + blurShaderVert = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", + blurOutputHorz, blurOutputVert); + blurShaderVert.getShaderManager().getShaderUniform("BlurDir").set(0, 1); + blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height)); + } catch(Exception e) { } + } + if(blurShaderHorz != null && blurShaderVert != null) { + if(15 != lastBgBlurFactor) { + blurShaderHorz.getShaderManager().getShaderUniform("Radius").set((float)15); + blurShaderVert.getShaderManager().getShaderUniform("Radius").set((float)15); + lastBgBlurFactor = 15; + } + GL11.glPushMatrix(); + blurShaderHorz.loadShader(0); + blurShaderVert.loadShader(0); + GlStateManager.enableDepth(); + GL11.glPopMatrix(); + + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + } + + /** + * Renders a subsection of the blurred framebuffer on to the corresponding section of the screen. + * Essentially, this method will "blur" the background inside the bounds specified by [x->x+blurWidth, y->y+blurHeight] + */ + public void renderBlurredBackground(int width, int height, int x, int y, int blurWidth, int blurHeight) { + if(!OpenGlHelper.isFramebufferEnabled()) return; + + float uMin = x/(float)width; + float uMax = (x+blurWidth)/(float)width; + float vMin = (height-y)/(float)height; + float vMax = (height-y-blurHeight)/(float)height; + + blurOutputVert.bindFramebufferTexture(); + GlStateManager.color(1f, 1f, 1f, 1f); + //Utils.setScreen(width*f, height*f, f); + Utils.drawTexturedRect(x, y, blurWidth, blurHeight, uMin, uMax, vMin, vMax); + //Utils.setScreen(width, height, f); + blurOutputVert.unbindFramebufferTexture(); + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/GuiGamemodes.java b/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/GuiGamemodes.java new file mode 100644 index 00000000..0f479f53 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/GuiGamemodes.java @@ -0,0 +1,303 @@ +package io.github.moulberry.notenoughupdates.gamemodes; + +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; + +import java.awt.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static io.github.moulberry.notenoughupdates.GuiTextures.*; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; + +public class GuiGamemodes extends GuiScreen { + + private String currentProfile; + private SBGamemodes.Gamemode currentGamemode = null; + private boolean upgradeOverride; + + private int guiLeft = 100; + private int guiTop = 100; + private int xSize = 200; + private int ySize = 232; + + public GuiGamemodes(boolean upgradeOverride) { + this.currentProfile = NotEnoughUpdates.INSTANCE.manager.getCurrentProfile(); + this.upgradeOverride = upgradeOverride; + } + + private boolean canChange(int from, int to) { + if(from >= to) { + return true; + } else { + return !currentGamemode.locked || upgradeOverride; + } + } + + @Override + public void updateScreen() { + if(currentGamemode == null) { + currentGamemode = SBGamemodes.getGamemode(); + if(currentGamemode == null) { + Minecraft.getMinecraft().displayGuiScreen(null); + Minecraft.getMinecraft().thePlayer.addChatMessage( + new ChatComponentText(EnumChatFormatting.RED+"Couldn't automatically detect current profile." + + "If you have only 1 profile, try using /api new so that NEU can detect your profile.")); + } + } + + String currentProfile = NotEnoughUpdates.INSTANCE.manager.getCurrentProfile(); + if(!this.currentProfile.equals(currentProfile)) { + Minecraft.getMinecraft().displayGuiScreen(null); + Minecraft.getMinecraft().thePlayer.addChatMessage( + new ChatComponentText(EnumChatFormatting.RED+"Profile change detected. Closing gamemodes menu.")); + } + } + + @Override + public void handleKeyboardInput() throws IOException { + if(Keyboard.getEventKeyState() && Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) { + SBGamemodes.saveToFile(); + } + + super.handleKeyboardInput(); + } + + public void drawStringShadow(String str, float x, float y, int len) { + for(int xOff=-2; xOff<=2; xOff++) { + for(int yOff=-2; yOff<=2; yOff++) { + if(Math.abs(xOff) != Math.abs(yOff)) { + Utils.drawStringScaledMaxWidth(Utils.cleanColourNotModifiers(str), + Minecraft.getMinecraft().fontRendererObj, + x+xOff/2f, y+yOff/2f, false, len, + new Color(20, 20, 20, 100/Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB()); + } + } + } + + Utils.drawStringScaledMaxWidth(str, + Minecraft.getMinecraft().fontRendererObj, + x, y, false, len, + new Color(64, 64, 64, 255).getRGB()); + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { + if(mouseButton == 0) { + SBGamemodes.HardcoreMode setHC = SBGamemodes.HardcoreMode.NORMAL; + SBGamemodes.IronmanMode setIM = SBGamemodes.IronmanMode.NORMAL; + int setMod = 0; + + if(mouseX > guiLeft+xSize-27 && mouseX < guiLeft+xSize-9) { + if(mouseY > guiTop+30 && mouseY < guiTop+30+16) { + setHC = SBGamemodes.HardcoreMode.SOFTCORE; + } else if(mouseY > guiTop+50 && mouseY < guiTop+50+16) { + setHC = SBGamemodes.HardcoreMode.HARDCORE; + } else if(mouseY > guiTop+80 && mouseY < guiTop+80+16) { + setIM = SBGamemodes.IronmanMode.IRONMAN; + } else if(mouseY > guiTop+100 && mouseY < guiTop+100+16) { + setIM = SBGamemodes.IronmanMode.IRONMANPLUS; + } else if(mouseY > guiTop+120 && mouseY < guiTop+120+16) { + setIM = SBGamemodes.IronmanMode.ULTIMATE_IRONMAN; + } else if(mouseY > guiTop+140 && mouseY < guiTop+140+16) { + setIM = SBGamemodes.IronmanMode.ULTIMATE_IRONMANPLUS; + } else if(mouseY > guiTop+170 && mouseY < guiTop+170+16) { + setMod = SBGamemodes.MODIFIER_DEVILISH; + } else if(mouseY > guiTop+190 && mouseY < guiTop+190+16) { + setMod = SBGamemodes.MODIFIER_NOBANK; + } else if(mouseY > guiTop+210 && mouseY < guiTop+210+16) { + setMod = SBGamemodes.MODIFIER_SMALLISLAND; + } + } + + if(setHC != SBGamemodes.HardcoreMode.NORMAL) { + if(currentGamemode.hardcoreMode == setHC) { + currentGamemode.hardcoreMode = SBGamemodes.HardcoreMode.NORMAL; + } else { + if(canChange(currentGamemode.hardcoreMode.ordinal(), setHC.ordinal())) { + currentGamemode.hardcoreMode = setHC; + } + } + } else if(setIM != SBGamemodes.IronmanMode.NORMAL) { + if(currentGamemode.ironmanMode == setIM) { + currentGamemode.ironmanMode = SBGamemodes.IronmanMode.NORMAL; + } else { + if(canChange(currentGamemode.ironmanMode.ordinal(), setIM.ordinal())) { + currentGamemode.ironmanMode = setIM; + } + } + } else if(setMod != 0) { + if(canChange(currentGamemode.gamemodeModifiers, currentGamemode.gamemodeModifiers^setMod)) { + currentGamemode.gamemodeModifiers ^= setMod; + } + } + } + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + super.drawDefaultBackground(); + + guiLeft = (width-xSize)/2; + guiTop = (height-ySize)/2; + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(gamemodes); + Utils.drawTexturedRect(guiLeft, guiTop, xSize, ySize, GL11.GL_NEAREST); + + if(currentGamemode == null) return; + + Utils.drawStringCentered("NEU Skyblock Gamemodes", Minecraft.getMinecraft().fontRendererObj, + guiLeft+xSize/2f, guiTop+14, false, new Color(64, 64, 64).getRGB()); + + drawStringShadow(SBGamemodes.HardcoreMode.SOFTCORE.display, guiLeft+10, guiTop+30, xSize-47); + drawStringShadow(SBGamemodes.HardcoreMode.HARDCORE.display, guiLeft+10, guiTop+50, xSize-47); + + drawStringShadow(SBGamemodes.IronmanMode.IRONMAN.display,guiLeft+10, guiTop+80, xSize-47); + drawStringShadow(SBGamemodes.IronmanMode.IRONMANPLUS.display,guiLeft+10, guiTop+100, xSize-47); + drawStringShadow(SBGamemodes.IronmanMode.ULTIMATE_IRONMAN.display,guiLeft+10, guiTop+120, xSize-47); + drawStringShadow(SBGamemodes.IronmanMode.ULTIMATE_IRONMANPLUS.display,guiLeft+10, guiTop+140, xSize-47); + + drawStringShadow(SBGamemodes.MODIFIER_DEVILISH_DISPLAY,guiLeft+10, guiTop+170, xSize-47); + drawStringShadow(SBGamemodes.MODIFIER_NOBANK_DISPLAY,guiLeft+10, guiTop+190, xSize-47); + drawStringShadow(SBGamemodes.MODIFIER_SMALLISLAND_DISPLAY,guiLeft+10, guiTop+210, xSize-47); + + String tooltipToDisplay = null; + + GlStateManager.color(1, 1, 1, 1); + if(canChange(currentGamemode.hardcoreMode.ordinal(), SBGamemodes.HardcoreMode.SOFTCORE.ordinal())) { + Minecraft.getMinecraft().getTextureManager().bindTexture( + currentGamemode.hardcoreMode == SBGamemodes.HardcoreMode.SOFTCORE ? radial_circle_on : radial_circle_off); + Utils.drawTexturedRect(guiLeft+xSize-26, guiTop+30-4, 16, 16, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().bindTexture(help); + Utils.drawTexturedRect(guiLeft+xSize-47, guiTop+30-4, 16, 16, GL11.GL_NEAREST); + if(mouseX > guiLeft+xSize-47 && mouseX < guiLeft+xSize-31) { + if(mouseY > guiTop+30-4 && mouseY < guiTop+30+12) { + tooltipToDisplay = SBGamemodes.HardcoreMode.SOFTCORE.desc; + } + } + } + if(canChange(currentGamemode.hardcoreMode.ordinal(), SBGamemodes.HardcoreMode.HARDCORE.ordinal())) { + Minecraft.getMinecraft().getTextureManager().bindTexture( + currentGamemode.hardcoreMode == SBGamemodes.HardcoreMode.HARDCORE ? radial_circle_on : radial_circle_off); + Utils.drawTexturedRect(guiLeft+xSize-26, guiTop+50-4, 16, 16, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().bindTexture(help); + Utils.drawTexturedRect(guiLeft+xSize-47, guiTop+50-4, 16, 16, GL11.GL_NEAREST); + if(mouseX > guiLeft+xSize-47 && mouseX < guiLeft+xSize-31) { + if(mouseY > guiTop+50-4 && mouseY < guiTop+50+12) { + tooltipToDisplay = SBGamemodes.HardcoreMode.HARDCORE.desc; + } + } + } + + if(canChange(currentGamemode.ironmanMode.ordinal(), SBGamemodes.IronmanMode.IRONMAN.ordinal())) { + Minecraft.getMinecraft().getTextureManager().bindTexture( + currentGamemode.ironmanMode == SBGamemodes.IronmanMode.IRONMAN ? radial_circle_on : radial_circle_off); + Utils.drawTexturedRect(guiLeft+xSize-26, guiTop+80-4, 16, 16, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().bindTexture(help); + Utils.drawTexturedRect(guiLeft+xSize-47, guiTop+80-4, 16, 16, GL11.GL_NEAREST); + if(mouseX > guiLeft+xSize-47 && mouseX < guiLeft+xSize-31) { + if(mouseY > guiTop+80-4 && mouseY < guiTop+80+12) { + tooltipToDisplay = SBGamemodes.IronmanMode.IRONMAN.desc; + } + } + } + if(canChange(currentGamemode.ironmanMode.ordinal(), SBGamemodes.IronmanMode.IRONMANPLUS.ordinal())) { + Minecraft.getMinecraft().getTextureManager().bindTexture( + currentGamemode.ironmanMode == SBGamemodes.IronmanMode.IRONMANPLUS ? radial_circle_on : radial_circle_off); + Utils.drawTexturedRect(guiLeft+xSize-26, guiTop+100-4, 16, 16, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().bindTexture(help); + Utils.drawTexturedRect(guiLeft+xSize-47, guiTop+100-4, 16, 16, GL11.GL_NEAREST); + if(mouseX > guiLeft+xSize-47 && mouseX < guiLeft+xSize-31) { + if(mouseY > guiTop+100-4 && mouseY < guiTop+100+12) { + tooltipToDisplay = SBGamemodes.IronmanMode.IRONMANPLUS.desc; + } + } + } + if(canChange(currentGamemode.ironmanMode.ordinal(), SBGamemodes.IronmanMode.ULTIMATE_IRONMAN.ordinal())) { + Minecraft.getMinecraft().getTextureManager().bindTexture( + currentGamemode.ironmanMode == SBGamemodes.IronmanMode.ULTIMATE_IRONMAN ? radial_circle_on : radial_circle_off); + Utils.drawTexturedRect(guiLeft+xSize-26, guiTop+120-4, 16, 16, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().bindTexture(help); + Utils.drawTexturedRect(guiLeft+xSize-47, guiTop+120-4, 16, 16, GL11.GL_NEAREST); + if(mouseX > guiLeft+xSize-47 && mouseX < guiLeft+xSize-31) { + if(mouseY > guiTop+120-4 && mouseY < guiTop+120+12) { + tooltipToDisplay = SBGamemodes.IronmanMode.ULTIMATE_IRONMAN.desc; + } + } + } + if(canChange(currentGamemode.ironmanMode.ordinal(), SBGamemodes.IronmanMode.ULTIMATE_IRONMANPLUS.ordinal())) { + Minecraft.getMinecraft().getTextureManager().bindTexture( + currentGamemode.ironmanMode == SBGamemodes.IronmanMode.ULTIMATE_IRONMANPLUS ? radial_circle_on : radial_circle_off); + Utils.drawTexturedRect(guiLeft+xSize-26, guiTop+140-4, 16, 16, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().bindTexture(help); + Utils.drawTexturedRect(guiLeft+xSize-47, guiTop+140-4, 16, 16, GL11.GL_NEAREST); + if(mouseX > guiLeft+xSize-47 && mouseX < guiLeft+xSize-31) { + if(mouseY > guiTop+140-4 && mouseY < guiTop+140+12) { + tooltipToDisplay = SBGamemodes.IronmanMode.ULTIMATE_IRONMANPLUS.desc; + } + } + } + + if(canChange(currentGamemode.gamemodeModifiers, currentGamemode.gamemodeModifiers^SBGamemodes.MODIFIER_DEVILISH)) { + Minecraft.getMinecraft().getTextureManager().bindTexture( + (currentGamemode.gamemodeModifiers & SBGamemodes.MODIFIER_DEVILISH) != 0 ? radial_square_on : radial_square_off); + Utils.drawTexturedRect(guiLeft+xSize-26, guiTop+170-4, 16, 16, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().bindTexture(help); + Utils.drawTexturedRect(guiLeft+xSize-47, guiTop+170-4, 16, 16, GL11.GL_NEAREST); + if(mouseX > guiLeft+xSize-47 && mouseX < guiLeft+xSize-31) { + if(mouseY > guiTop+170-4 && mouseY < guiTop+170+12) { + tooltipToDisplay = SBGamemodes.MODIFIER_DEVILISH_DESC; + } + } + } + if(canChange(currentGamemode.gamemodeModifiers, currentGamemode.gamemodeModifiers^SBGamemodes.MODIFIER_NOBANK)) { + Minecraft.getMinecraft().getTextureManager().bindTexture( + (currentGamemode.gamemodeModifiers & SBGamemodes.MODIFIER_NOBANK) != 0 ? radial_square_on : radial_square_off); + Utils.drawTexturedRect(guiLeft+xSize-26, guiTop+190-4, 16, 16, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().bindTexture(help); + Utils.drawTexturedRect(guiLeft+xSize-47, guiTop+190-4, 16, 16, GL11.GL_NEAREST); + if(mouseX > guiLeft+xSize-47 && mouseX < guiLeft+xSize-31) { + if(mouseY > guiTop+190-4 && mouseY < guiTop+190+12) { + tooltipToDisplay = SBGamemodes.MODIFIER_NOBANK_DESC; + } + } + } + if(canChange(currentGamemode.gamemodeModifiers, currentGamemode.gamemodeModifiers^SBGamemodes.MODIFIER_SMALLISLAND)) { + Minecraft.getMinecraft().getTextureManager().bindTexture( + (currentGamemode.gamemodeModifiers & SBGamemodes.MODIFIER_SMALLISLAND) != 0 ? radial_square_on : radial_square_off); + Utils.drawTexturedRect(guiLeft+xSize-26, guiTop+210-4, 16, 16, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().bindTexture(help); + Utils.drawTexturedRect(guiLeft+xSize-47, guiTop+210-4, 16, 16, GL11.GL_NEAREST); + if(mouseX > guiLeft+xSize-47 && mouseX < guiLeft+xSize-31) { + if(mouseY > guiTop+210-4 && mouseY < guiTop+210+12) { + tooltipToDisplay = SBGamemodes.MODIFIER_SMALLISLAND_DESC; + } + } + } + + if(tooltipToDisplay != null) { + List<String> lines = new ArrayList<>(); + for(String line : tooltipToDisplay.split("\n")) { + lines.add(EnumChatFormatting.GRAY+line); + } + Utils.drawHoveringText(lines, mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj); + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/SBGamemodes.java b/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/SBGamemodes.java new file mode 100644 index 00000000..09f00beb --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/SBGamemodes.java @@ -0,0 +1,349 @@ +package io.github.moulberry.notenoughupdates.gamemodes; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.questing.SBInfo; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.util.Base64; +import java.util.HashMap; + +public class SBGamemodes { + + private static final Gson gson = new Gson(); + + public static final int MODIFIER_DEVILISH = 0b1; + public static final int MODIFIER_NOBANK = 0b10; + public static final int MODIFIER_SMALLISLAND = 0b100; + + public static final String MODIFIER_DEVILISH_DISPLAY = EnumChatFormatting.DARK_PURPLE+"Devilish"; + public static final String MODIFIER_NOBANK_DISPLAY = EnumChatFormatting.RED+"No"+EnumChatFormatting.GOLD+"Bank"; + public static final String MODIFIER_SMALLISLAND_DISPLAY = EnumChatFormatting.GREEN+"SmallIsland"; + + public static final String MODIFIER_DEVILISH_DESC = EnumChatFormatting.DARK_PURPLE+"Devilish\n" + + "You are NOT allowed to use fairy souls."; + public static final String MODIFIER_NOBANK_DESC = EnumChatFormatting.RED+"No"+EnumChatFormatting.GOLD+"Bank\n" + + "You are NOT allowed to use the bank."; + public static final String MODIFIER_SMALLISLAND_DESC = EnumChatFormatting.GREEN+"SmallIsland\n" + + "Your private island is 1/4 the normal size."; + + private static HashMap<String, Gamemode> currentGamemode = new HashMap<>(); + private static long lastDeathExemption = 0; + + public static class Gamemode { + public HardcoreMode hardcoreMode = HardcoreMode.NORMAL; + public IronmanMode ironmanMode = IronmanMode.NORMAL; + public int gamemodeModifiers = 0; + + public boolean locked = true; + } + + public enum HardcoreMode { + NORMAL("Normal", "Normal"), + SOFTCORE(EnumChatFormatting.RED+"Soft"+EnumChatFormatting.DARK_RED+"core\n" + + "You only have 1 life.\nDying will remove your hardcore status.\nDeaths to the void or \'unknown\' are exempted.", + "You died.", "You fell into the void"), + HARDCORE(EnumChatFormatting.DARK_RED+"Hardcore\n" + + "You only have 1 life.\nDying will remove your hardcore status."); + + public final String display; + public final String desc; + private String[] exemptions; + + HardcoreMode(String display, String... exemptions) { + this.display = display.split("\n")[0]; + this.desc = display; + this.exemptions = exemptions; + } + + public boolean isExemption(String line) { + for(String exemption : exemptions) { + if(line.contains(exemption)) return true; + } + return false; + } + } + + public enum IronmanMode { + NORMAL("Normal", "Normal"), + IRONMAN(EnumChatFormatting.WHITE+"Ironman\n" + + "You are NOT allowed to trade or use the auction house.", + "You ", "Auction House", "Auctions Browser", "Auction View"), + IRONMANPLUS(EnumChatFormatting.WHITE+"Ironman"+EnumChatFormatting.GOLD+"+\n" + + "You are NOT allowed to trade, use the auction house or bazaar.", + "You ", "Auction House", "Auctions Browser", "Auction View", "Bazaar"), + ULTIMATE_IRONMAN(EnumChatFormatting.DARK_AQUA+"Ultimate "+EnumChatFormatting.WHITE+"Ironman\n" + + "You are NOT allowed to trade or use the auction house.\n" + + "You are restricted to 1 inventory. (No containers, no echest, no wardrobe).", + "You ", "Auction House", "Auctions Browser", "Auction View", "Chest", + "Wardrobe", "Weapon Rack", "Shelves"), + ULTIMATE_IRONMANPLUS(EnumChatFormatting.DARK_AQUA+"Ultimate "+EnumChatFormatting.WHITE+"Ironman"+EnumChatFormatting.GOLD+"+\n" + + "You are NOT allowed to trade, use the auction house or bazaar.\n" + + "You are restricted to 1 inventory. (No containers, no echest, no wardrobe).", + "You ", "Auction House", "Auctions Browser", "Auction View", "Bazaar", + "Chest", "Wardrobe", "Weapon Rack", "Shelves"); + + public final String display; + public final String desc; + private final String[] bannedInventories; + + IronmanMode(String display, String... bannedInventories) { + this.display = display.split("\n")[0]; + this.desc = display; + this.bannedInventories = bannedInventories; + } + + public boolean isBanned(String inventoryName) { + for(String banned : bannedInventories) { + if(inventoryName.contains(banned + " ") || inventoryName.endsWith(banned)) return true; + } + return false; + } + } + + public static Gamemode getGamemode() { + String currentProfile = NotEnoughUpdates.INSTANCE.manager.getCurrentProfile(); + + if(currentProfile == null || currentProfile.isEmpty()) return null; + + return currentGamemode.computeIfAbsent(currentProfile, k -> new Gamemode()); + } + + public static void loadFromFile() { + File configDir = NotEnoughUpdates.INSTANCE.manager.configLocation; + File gamemodeFile = new File(configDir, + "gamemodes/gamemodes-"+Minecraft.getMinecraft().thePlayer.getUniqueID().toString()+".json"); + gamemodeFile.getParentFile().mkdirs(); + + if(!gamemodeFile.exists()) { + return; + } + + try(BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(gamemodeFile), StandardCharsets.UTF_8))) { + String line = reader.readLine(); + String decoded = decrypt(line); + currentGamemode = gson.fromJson(decoded, GamemodeWrapper.class).currentGamemode; + } catch(Exception e) { + e.printStackTrace(); + } + } + + public static class GamemodeWrapper { + private HashMap<String, Gamemode> currentGamemode; + + public GamemodeWrapper(HashMap<String, Gamemode> currentGamemode) { + this.currentGamemode = currentGamemode; + } + } + + public static void saveToFile() { + File configDir = NotEnoughUpdates.INSTANCE.manager.configLocation; + File gamemodeFile = new File(configDir, + "gamemodes/gamemodes-"+Minecraft.getMinecraft().thePlayer.getUniqueID().toString()+".json"); + gamemodeFile.getParentFile().mkdirs(); + + try { + gamemodeFile.createNewFile(); + + try(BufferedWriter writer = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(gamemodeFile), StandardCharsets.UTF_8))) { + JsonObject obj = new JsonObject(); + writer.write(encrypt(gson.toJson(new GamemodeWrapper(currentGamemode), GamemodeWrapper.class))); + } + } catch(Exception e) { + e.printStackTrace(); + } + } + + public static Key getKeyFromPlayerUUID() { + byte[] bytes = ByteBuffer.allocate(2 * Long.SIZE / Byte.SIZE) + .putLong(Minecraft.getMinecraft().thePlayer.getUniqueID().getLeastSignificantBits()) + .putLong(Minecraft.getMinecraft().thePlayer.getUniqueID().getMostSignificantBits()) + .array(); + SecretKeySpec key = new SecretKeySpec(bytes, "AES"); + + return key; + } + + + public static String encrypt(String value) { + try { + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.ENCRYPT_MODE, getKeyFromPlayerUUID()); + String encrypt = Base64.getEncoder().encodeToString(cipher.doFinal(value.getBytes())); + return encrypt; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static String decrypt(String encrypted) { + try { + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.DECRYPT_MODE, getKeyFromPlayerUUID()); + byte[] b64Decoded = Base64.getDecoder().decode(encrypted); + byte[] bytes = cipher.doFinal(b64Decoded); + + return new String(bytes); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static void setGamemode(Gamemode gamemode) { + String currentProfile = NotEnoughUpdates.INSTANCE.manager.getCurrentProfile(); + + if(currentProfile == null || currentProfile.isEmpty()) return; + + currentGamemode.put(currentProfile, gamemode); + } + + @SubscribeEvent + public void onPlayerInteract(PlayerInteractEvent event) { + if(getGamemode() == null || !NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return; + + if(!"Your Island".equals(SBInfo.getInstance().location)) return; + + if((getGamemode().gamemodeModifiers & MODIFIER_SMALLISLAND) != 0) { + if(event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) { + if(Math.abs(event.pos.getX()) > 40 || Math.abs(event.pos.getZ()) > 40) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.YELLOW+"[NPC] Builder"+ + EnumChatFormatting.WHITE+": Sorry, "+Minecraft.getMinecraft().thePlayer.getName()+ + ", due to budget cuts your skyblock island is now only 80 blocks wide.")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.AQUA+"(Use "+EnumChatFormatting.YELLOW+"/neugamemodes"+ + EnumChatFormatting.AQUA+" if you would like to build further out)")); + + event.setCanceled(true); + } + } + } + } + + @SubscribeEvent + public void onTick(TickEvent.ClientTickEvent event) { + if(getGamemode() == null || !NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return; + + boolean inDungeons = SBInfo.getInstance().getLocation() != null && SBInfo.getInstance().getLocation().equals("dungeon"); + + if("Your Island".equals(SBInfo.getInstance().location) && + (EnumChatFormatting.YELLOW+"Break a log").equals(SBInfo.getInstance().objective)) { + getGamemode().locked = false; + } else { + getGamemode().locked = true; + } + + IronmanMode ironmanMode = getGamemode().ironmanMode; + GuiScreen gui = Minecraft.getMinecraft().currentScreen; + if(gui instanceof GuiChest) { + GuiChest eventGui = (GuiChest) gui; + ContainerChest cc = (ContainerChest) eventGui.inventorySlots; + String containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText(); + + if(containerName.equals("Bank") && (getGamemode().gamemodeModifiers & MODIFIER_NOBANK) != 0) { + Minecraft.getMinecraft().thePlayer.closeScreen(); + + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.YELLOW+"[NPC] Banker"+ + EnumChatFormatting.WHITE+": Hi, "+Minecraft.getMinecraft().thePlayer.getName()+ + ", you would like to create an account and make a deposit?")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW+"[NPC] Banker"+ + EnumChatFormatting.WHITE+": Alright, I've invested your money into ...")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED+"["+ + EnumChatFormatting.WHITE+"YouTube"+EnumChatFormatting.RED+"] Nullzee"+ + EnumChatFormatting.WHITE+": Hows it going everyone, welcome to my ultimate bazaar flipping guide ...")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW+"[NPC] Banker"+ + EnumChatFormatting.WHITE+": Hmm, it seems as though the economy has crashed. All your money is gone. Poof. Vanished.")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW+"[IDIOT] You"+ + EnumChatFormatting.WHITE+": ... never again ...")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.AQUA+"(Use "+EnumChatFormatting.YELLOW+"/neugamemodes"+ + EnumChatFormatting.AQUA+" if you would like to use the bank)")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("")); + } else if(containerName.equals("Fairy") && (getGamemode().gamemodeModifiers & MODIFIER_DEVILISH) != 0) { + Minecraft.getMinecraft().thePlayer.closeScreen(); + + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.YELLOW+"[NPC] "+EnumChatFormatting.LIGHT_PURPLE+"Tia the Fairy"+ + EnumChatFormatting.WHITE+": Oh no, "+Minecraft.getMinecraft().thePlayer.getName()+ + ", you have sold your soul to the devil... please go away!")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.AQUA+"(Use "+EnumChatFormatting.YELLOW+"/neugamemodes"+ + EnumChatFormatting.AQUA+" if you would like to use fairy souls)")); + } else if(!inDungeons && ironmanMode.isBanned(containerName)) { + Minecraft.getMinecraft().thePlayer.closeScreen(); + + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.AQUA+"You cannot access this inventory/menu because of your")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + " "+ironmanMode.display + EnumChatFormatting.AQUA+" status!")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.AQUA+"(Use "+EnumChatFormatting.YELLOW+"/neugamemodes"+ + EnumChatFormatting.AQUA+" if you would like to downgrade the status)")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("")); + } + } + } + + @SubscribeEvent + public void onChatMessage(ClientChatReceivedEvent event) { + if(event.type != 0) return; + + /*if(Keyboard.isKeyDown(Keyboard.KEY_K)) { + boolean has = false; + for(char c : event.message.getFormattedText().toCharArray()) { + if((int)c > 200) { + if(!has) System.out.println("-----START"); + has = true; + System.out.println((int)c); + } + } + if(has) System.out.println("-----END"); + }*/ + if(getGamemode() == null || !NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return; + + String message = event.message.getFormattedText(); + if(message.contains("\u2620")) { //Death symbol ( ☠) + HardcoreMode hardcoreMode = getGamemode().hardcoreMode; + if(hardcoreMode != HardcoreMode.NORMAL) { + if(hardcoreMode.isExemption(message)) { + lastDeathExemption = System.currentTimeMillis(); + } + } + } + + if(System.currentTimeMillis() - lastDeathExemption > 1000 && + message.contains("!") && message.startsWith(EnumChatFormatting.RESET.toString()+EnumChatFormatting.RED+"You died")) { + if(getGamemode().hardcoreMode != HardcoreMode.NORMAL) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.RED.toString()+EnumChatFormatting.OBFUSCATED+"AAA"+ + EnumChatFormatting.RED+" You have lost your "+ + getGamemode().hardcoreMode.display+EnumChatFormatting.RED+" status! "+ + EnumChatFormatting.RED+EnumChatFormatting.OBFUSCATED+"AAA")); + getGamemode().hardcoreMode = HardcoreMode.NORMAL; + } + } + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CollectionLogInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CollectionLogInfoPane.java index 5f9e6af1..d0600796 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CollectionLogInfoPane.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CollectionLogInfoPane.java @@ -5,6 +5,7 @@ import com.google.gson.JsonObject; import io.github.moulberry.notenoughupdates.NEUManager; import io.github.moulberry.notenoughupdates.NEUOverlay; import io.github.moulberry.notenoughupdates.NEUResourceManager; +import io.github.moulberry.notenoughupdates.util.SpecialColour; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.ScaledResolution; @@ -47,13 +48,13 @@ public class CollectionLogInfoPane extends ScrollableInfoPane { private static final int FILTER_ARMOR = 2; private static final int FILTER_ACCESSORY = 3; private static final int FILTER_PET = 4; - private static final int FILTER_TOOL = 5; + private static final int FILTER_DUNGEON = 5; private static final int FILTER_SLAYER_ZOMBIE = 6; private static final int FILTER_SLAYER_WOLF = 7; private static final int FILTER_SLAYER_SPIDER = 8; private int filterMode = FILTER_ALL; private String[] filterPrettyNames = new String[]{"ALL","WEAPON","ARMOR", - "ACCESSORY","PET","TOOL","ZOMBIE SLAYER","WOLF SLAYER","SPIDER SLAYER"}; + "ACCESSORY","PET","DUNGEON","ZOMBIE SLAYER","WOLF SLAYER","SPIDER SLAYER"}; private Framebuffer itemFramebuffer = null; private Framebuffer itemBGFramebuffer = null; @@ -78,7 +79,7 @@ public class CollectionLogInfoPane extends ScrollableInfoPane { private void refreshItems() { items.clear(); for(String internalname : manager.getItemInformation().keySet()) { - if(!manager.isVanillaItem(internalname) && !internalname.matches(mobRegex)) { + if(!manager.auctionManager.isVanillaItem(internalname) && !internalname.matches(mobRegex)) { JsonObject item = manager.getItemInformation().get(internalname); JsonArray lore = manager.getItemInformation().get(internalname).get("lore").getAsJsonArray(); switch(filterMode) { @@ -94,8 +95,8 @@ public class CollectionLogInfoPane extends ScrollableInfoPane { case FILTER_PET: if(!internalname.matches(petRegex) || !item.get("displayname").getAsString().contains("[")) continue; break; - case FILTER_TOOL: - if(overlay.checkItemType(lore, "AXE", "PICKAXE", "FISHING ROD", "SHOVEL", "HOE") < 0) continue; + case FILTER_DUNGEON: + if(Utils.checkItemType(lore, true, "DUNGEON") < 0) continue; break; case FILTER_SLAYER_ZOMBIE: if(!item.has("slayer_req") || !item.get("slayer_req").getAsString().startsWith("ZOMBIE")) continue; @@ -121,8 +122,8 @@ public class CollectionLogInfoPane extends ScrollableInfoPane { float cost1 = manager.auctionManager.getLowestBin(o1); float cost2 = manager.auctionManager.getLowestBin(o2); - if(cost1 == -1) cost1 = manager.getCraftCost(o1).craftCost; - if(cost2 == -1) cost2 = manager.getCraftCost(o2).craftCost; + if(cost1 == -1) cost1 = manager.auctionManager.getCraftCost(o1).craftCost; + if(cost2 == -1) cost2 = manager.auctionManager.getCraftCost(o2).craftCost; if(cost1 < cost2) return 1; if(cost1 > cost2) return -1; @@ -241,19 +242,6 @@ public class CollectionLogInfoPane extends ScrollableInfoPane { } } - private Matrix4f createProjectionMatrix(int width, int height) { - Matrix4f projMatrix = new Matrix4f(); - projMatrix.setIdentity(); - projMatrix.m00 = 2.0F / (float)width; - projMatrix.m11 = 2.0F / (float)(-height); - projMatrix.m22 = -0.0020001999F; - projMatrix.m33 = 1.0F; - projMatrix.m03 = -1.0F; - projMatrix.m13 = 1.0F; - projMatrix.m23 = -1.0001999F; - return projMatrix; - } - public int getCurrentAcquiredCount() { if(getAcquiredItems() == null) return 0; if(!getAcquiredItems().containsKey(manager.getCurrentProfile())) return 0; @@ -268,7 +256,7 @@ public class CollectionLogInfoPane extends ScrollableInfoPane { if(itemFramebuffer != null && grayscaleShader != null && (itemFramebuffer.framebufferWidth != width || itemFramebuffer.framebufferHeight != height)) { - grayscaleShader.setProjectionMatrix(createProjectionMatrix( + grayscaleShader.setProjectionMatrix(Utils.createProjectionMatrix( width*scaledresolution.getScaleFactor(), height*scaledresolution.getScaleFactor())); } @@ -300,7 +288,7 @@ public class CollectionLogInfoPane extends ScrollableInfoPane { grayscaleShader = new Shader(new NEUResourceManager(Minecraft.getMinecraft().getResourceManager()), "grayscale", itemFramebuffer, itemFramebufferGrayscale); - grayscaleShader.setProjectionMatrix(createProjectionMatrix( + grayscaleShader.setProjectionMatrix(Utils.createProjectionMatrix( width*scaledresolution.getScaleFactor(), height*scaledresolution.getScaleFactor())); } catch(Exception e) { return; @@ -316,7 +304,7 @@ public class CollectionLogInfoPane extends ScrollableInfoPane { itemFramebufferGrayscale.bindFramebufferTexture(); - AtomicReference<JsonObject> tooltipToDisplay = new AtomicReference<>(null); + AtomicReference<ItemStack> tooltipToDisplay = new AtomicReference<>(null); AtomicBoolean isTop = new AtomicBoolean(false); AtomicInteger lowestY = new AtomicInteger(-1); @@ -339,7 +327,7 @@ public class CollectionLogInfoPane extends ScrollableInfoPane { if(mouseX > leftI && mouseX < rightI) { if(mouseY > topI && mouseY < bottomI) { - tooltipToDisplay.set(manager.getItemInformation().get(internalname)); + tooltipToDisplay.set(manager.jsonToStack(manager.getItemInformation().get(internalname), true)); } } @@ -373,16 +361,9 @@ public class CollectionLogInfoPane extends ScrollableInfoPane { itemFramebufferGrayscale.unbindFramebufferTexture(); - JsonObject json = tooltipToDisplay.get(); - if(json != null) { - List<String> text = new ArrayList<>(); - text.add(json.get("displayname").getAsString()); - JsonArray lore = json.get("lore").getAsJsonArray(); - - for(int i=0; i<lore.size(); i++) { - text.add(lore.get(i).getAsString()); - } - + ItemStack displayStack = tooltipToDisplay.get(); + if(displayStack != null) { + List<String> text = displayStack.getTooltip(Minecraft.getMinecraft().thePlayer, true); Utils.drawHoveringText(text, mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj); } } @@ -415,9 +396,8 @@ public class CollectionLogInfoPane extends ScrollableInfoPane { } private void renderItemBackgrounds(Color fg, int left, int right, int top, int bottom) { - int opacity = Math.min(255, Math.max(0, manager.config.fgOpacity.value.intValue())); - Color fgGold = new Color(limCol(fg.getRed()+100), limCol(fg.getGreen()+50), limCol(fg.getBlue()-50), opacity); - Color fgCustomOpacity = new Color((fg.getRGB() & 0x00ffffff) | opacity << 24, true); + Color fgCustomOpacity = new Color(SpecialColour.specialToChromaRGB(manager.config.itemBackgroundColour.value), true); + Color fgGold = new Color(SpecialColour.specialToChromaRGB(manager.config.itemFavouriteColour.value), true); String[] items = getItemList(); iterateItemSlots(new ItemSlotConsumer() { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CosmeticsInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CosmeticsInfoPane.java deleted file mode 100644 index 707968e3..00000000 --- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CosmeticsInfoPane.java +++ /dev/null @@ -1,83 +0,0 @@ -package io.github.moulberry.notenoughupdates.infopanes; - -import io.github.moulberry.notenoughupdates.cosmetics.CapeManager; -import io.github.moulberry.notenoughupdates.NEUManager; -import io.github.moulberry.notenoughupdates.NEUOverlay; -import io.github.moulberry.notenoughupdates.util.Utils; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.gui.ScaledResolution; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.util.ResourceLocation; - -import java.awt.*; -import java.util.HashMap; - -public class CosmeticsInfoPane extends InfoPane { - - public CosmeticsInfoPane(NEUOverlay overlay, NEUManager manager) { - super(overlay, manager); - } - - private HashMap<String, ResourceLocation> capeTextures = new HashMap<>(); - - private String selectedCape = null; - - public void render(int width, int height, Color bg, Color fg, ScaledResolution scaledresolution, int mouseX, - int mouseY) { - super.renderDefaultBackground(width, height, bg); - - FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; - int currentY = overlay.getBoxPadding()+10; - fr.drawString("NEU Capes", overlay.getBoxPadding()+10, currentY, Color.WHITE.getRGB(), true); currentY += 10; - - selectedCape = null; - for(String cape : CapeManager.getInstance().getCapes()) { - if(CapeManager.getInstance().getPermissionForCape(Minecraft.getMinecraft().thePlayer.getName(), cape)) { - currentY += renderCapeSelector(cape, currentY, mouseX, mouseY); - currentY += 5; - } - } - } - - public int renderCapeSelector(String capename, int y, int mouseX, int mouseY) { - if(mouseX > overlay.getBoxPadding()+5 && mouseX < overlay.getBoxPadding()+75) { - if(mouseY > y && mouseY < y+100) { - selectedCape = capename; - } - } - boolean selected = capename.equals(CapeManager.getInstance().getCape(Minecraft.getMinecraft().thePlayer.getName())); - - if(selected) { - drawRect(overlay.getBoxPadding()+5, y, overlay.getBoxPadding()+75, y+100, Color.YELLOW.getRGB()); - drawGradientRect(overlay.getBoxPadding()+10, y+5, overlay.getBoxPadding()+70, y+95, Color.GRAY.darker().getRGB(), Color.GRAY.getRGB()); - } else { - drawGradientRect(overlay.getBoxPadding()+5, y, overlay.getBoxPadding()+75, y+100, Color.GRAY.darker().getRGB(), Color.GRAY.getRGB()); - } - - GlStateManager.color(1, 1, 1, 1); - - ResourceLocation capeTex = capeTextures.computeIfAbsent(capename, k -> new ResourceLocation("notenoughupdates:"+capename+".png")); - - Minecraft.getMinecraft().getTextureManager().bindTexture(capeTex); - Utils.drawTexturedRect(overlay.getBoxPadding()+10, y+10, 60, 80, 0, 300/1024f, 0, 425/1024f); - return 100; - } - - public void mouseInput(int width, int height, int mouseX, int mouseY, boolean mouseDown) { - if(mouseDown && selectedCape != null) { - if(selectedCape.equals(CapeManager.getInstance().getCape(Minecraft.getMinecraft().thePlayer.getName()))) { - CapeManager.getInstance().setCape(Minecraft.getMinecraft().thePlayer.getName(), null); - } else { - CapeManager.getInstance().setCape(Minecraft.getMinecraft().thePlayer.getName(), selectedCape); - } - } - } - - @Override - public boolean keyboardInput() { - return false; - } - -} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/DevInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/DevInfoPane.java index ec5f8209..22427cee 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/DevInfoPane.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/DevInfoPane.java @@ -4,10 +4,25 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import io.github.moulberry.notenoughupdates.NEUManager; import io.github.moulberry.notenoughupdates.NEUOverlay; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.ShapedRecipes; +import net.minecraft.item.crafting.ShapelessRecipes; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.oredict.ShapedOreRecipe; +import net.minecraftforge.oredict.ShapelessOreRecipe; import org.lwjgl.input.Keyboard; +import java.io.IOException; import java.util.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -45,7 +60,8 @@ public class DevInfoPane extends TextInfoPane { }*/ //if(true) return text; - for(String internalname : manager.auctionManager.internalnameToAucIdMap.keySet()) { + for(String internalname : manager.auctionManager.getItemAuctionInfoKeySet()) { + if(internalname.contains("-")) continue; if(!manager.getItemInformation().containsKey(internalname)) { text += internalname + "\n"; } @@ -69,12 +85,852 @@ public class DevInfoPane extends TextInfoPane { AtomicBoolean running = new AtomicBoolean(false); ScheduledExecutorService ses = Executors.newScheduledThreadPool(1); + String[] bukkitList = new String[] { + "ACACIA_DOOR_ITEM", + "ACACIA_FENCE", + "ACACIA_FENCE_GATE", + "ACACIA_STAIRS", + "ACTIVATOR_RAIL", + "ANVIL", + "APPLE", + "ARMOR_STAND", + "ARROW", + "BAKED_POTATO", + "BANNER", + "BARRIER", + "BEACON", + "BED", + "BEDROCK", + "BIRCH_DOOR_ITEM", + "BIRCH_FENCE", + "BIRCH_FENCE_GATE", + "BIRCH_WOOD_STAIRS@birch_stairs", + "BLAZE_POWDER", + "BLAZE_ROD", + "BOAT", + "BONE", + "BOOK", + "BOOK_AND_QUILL@writable_book", + "BOOKSHELF", + "BOW", + "BOWL", + "BREAD", + "BREWING_STAND_ITEM", + "BRICK@brick_block", + "BRICK_STAIRS", + "BROWN_MUSHROOM", + "BUCKET", + "CACTUS", + "CAKE", + "CARPET", + "CARROT_ITEM", + "CARROT_STICK@carrot_on_a_stick", + "CAULDRON_ITEM", + "CHAINMAIL_BOOTS", + "CHAINMAIL_CHESTPLATE", + "CHAINMAIL_HELMET", + "CHAINMAIL_LEGGINGS", + "CHEST", + "CLAY", + "CLAY_BALL", + "CLAY_BRICK@brick", + "COAL", + "COAL_BLOCK", + "COAL_ORE", + "COBBLE_WALL@cobblestone_wall", + "COBBLESTONE", + "COBBLESTONE_STAIRS@stone_stairs", + "COMMAND@command_block", + "COMMAND_MINECART@command_block_minecart", + "COMPASS", + "COOKED_BEEF", + "COOKED_CHICKEN", + "COOKED_FISH", + "COOKED_MUTTON", + "COOKED_RABBIT", + "COOKIE", + "DARK_OAK_DOOR_ITEM", + "DARK_OAK_FENCE", + "DARK_OAK_FENCE_GATE", + "DARK_OAK_STAIRS", + "DAYLIGHT_DETECTOR", + "DEAD_BUSH@deadbush", + "DETECTOR_RAIL", + "DIAMOND", + "DIAMOND_AXE", + "DIAMOND_BARDING@diamond_horse_armor", + "DIAMOND_BLOCK", + "DIAMOND_BOOTS", + "DIAMOND_CHESTPLATE", + "DIAMOND_HELMET", + "DIAMOND_HOE", + "DIAMOND_LEGGINGS", + "DIAMOND_ORE", + "DIAMOND_PICKAXE", + "DIAMOND_SPADE@diamond_shovel", + "DIAMOND_SWORD", + "DIODE@repeater", + "DIRT", + "DISPENSER", + "DOUBLE_PLANT", + "DRAGON_EGG", + "DROPPER", + "EGG", + "EMERALD", + "EMERALD_BLOCK", + "EMERALD_ORE", + "EMPTY_MAP@map", + "ENCHANTED_BOOK", + "ENCHANTMENT_TABLE@enchanting_table", + "ENDER_CHEST", + "ENDER_PEARL", + "ENDER_PORTAL_FRAME@end_portal_frame", + "ENDER_STONE@end_stone", + "EXP_BOTTLE@experience_bottle", + "EXPLOSIVE_MINECART@tnt_minecart", + "EYE_OF_ENDER@ender_eye", + "FEATHER", + "FENCE", + "FENCE_GATE", + "FERMENTED_SPIDER_EYE", + "FIREBALL@fire_charge", + "FIREWORK@fireworks", + "FIREWORK_CHARGE", + "FISHING_ROD", + "FLINT", + "FLINT_AND_STEEL", + "FLOWER_POT_ITEM", + "FURNACE", + "GHAST_TEAR", + "GLASS", + "GLASS_BOTTLE", + "GLOWSTONE", + "GLOWSTONE_DUST", + "GOLD_AXE@golden_axe", + "GOLD_BARDING@golden_horse_armor", + "GOLD_BLOCK", + "GOLD_BOOTS@golden_boots", + "GOLD_CHESTPLATE@golden_chestplate", + "GOLD_HELMET@golden_helmet", + "GOLD_HOE@golden_hoe", + "GOLD_INGOT", + "GOLD_LEGGINGS@golden_leggings", + "GOLD_NUGGET", + "GOLD_ORE", + "GOLD_PICKAXE@golden_pickaxe", + "GOLD_PLATE@light_weighted_pressure_plate", + "GOLD_RECORD@record_13", + "GOLD_SPADE@golden_shovel", + "GOLD_SWORD@golden_sword", + "GOLDEN_APPLE", + "GOLDEN_CARROT", + "GRASS", + "GRAVEL", + "GREEN_RECORD@record_cat", + "GRILLED_PORK@cooked_porkchop", + "HARD_CLAY@hardened_clay", + "HAY_BLOCK", + "HOPPER", + "HOPPER_MINECART", + "ICE", + "INK_SACK@dye", + "IRON_AXE", + "IRON_BARDING@iron_horse_armor", + "IRON_BLOCK", + "IRON_BOOTS", + "IRON_CHESTPLATE", + "IRON_DOOR", + "IRON_FENCE@iron_bars", + "IRON_HELMET", + "IRON_HOE", + "IRON_INGOT", + "IRON_LEGGINGS", + "IRON_ORE", + "IRON_PICKAXE", + "IRON_PLATE@heavy_weighted_pressure_plate", + "IRON_SPADE@iron_shovel", + "IRON_SWORD", + "IRON_TRAPDOOR", + "ITEM_FRAME", + "JACK_O_LANTERN@lit_pumpkin", + "JUKEBOX", + "JUNGLE_DOOR_ITEM", + "JUNGLE_FENCE", + "JUNGLE_FENCE_GATE", + "JUNGLE_WOOD_STAIRS@jungle_stairs", + "LADDER", + "LAPIS_BLOCK", + "LAPIS_ORE", + "LAVA_BUCKET", + "LEASH@lead", + "LEATHER", + "LEATHER_BOOTS", + "LEATHER_CHESTPLATE", + "LEATHER_HELMET", + "LEATHER_LEGGINGS", + "LEAVES", + "LEAVES_2@leaves2", + "LEVER", + "LOG", + "LOG_2@log2", + "LONG_GRASS@tallgrass", + "MAGMA_CREAM", + "MAP", + "MELON", + "MELON_BLOCK", + "MELON_SEEDS", + "MILK_BUCKET", + "MINECART", + "MOB_SPAWNER", + "MONSTER_EGG", + "MONSTER_EGGS@spawn_egg", + "MOSSY_COBBLESTONE", + "MUSHROOM_SOUP@mushroom_stew", + "MUTTON", + "MYCEL@mycelium", + "NAME_TAG", + "NETHER_BRICK", + "NETHER_BRICK_ITEM", + "NETHER_BRICK_STAIRS", + "NETHER_FENCE@nether_brick_fence", + "NETHER_STAR", + "NETHER_WARTS@nether_wart", + "NETHERRACK", + "NOTE_BLOCK@noteblock", + "OBSIDIAN", + "PACKED_ICE", + "PAINTING", + "PAPER", + "PISTON_BASE@piston", + "PISTON_STICKY_BASE@sticky_piston", + "POISONOUS_POTATO", + "PORK@porkchop", + "POTATO_ITEM", + "POTION", + "POWERED_MINECART@furnace_minecart", + "POWERED_RAIL@golden_rail", + "PRISMARINE", + "PRISMARINE_CRYSTALS", + "PRISMARINE_SHARD", + "PUMPKIN", + "PUMPKIN_PIE", + "PUMPKIN_SEEDS", + "QUARTZ", + "QUARTZ_BLOCK", + "QUARTZ_ORE", + "QUARTZ_STAIRS", + "RABBIT", + "RABBIT_FOOT", + "RABBIT_HIDE", + "RABBIT_STEW", + "RAILS@rail", + "RAW_BEEF@beef", + "RAW_CHICKEN@chicken", + "RAW_FISH@fish", + "RECORD_10@record_ward", + "RECORD_11", + "RECORD_12@record_wait", + "RECORD_3@record_blocks", + "RECORD_4@record_chirp", + "RECORD_5@record_far", + "RECORD_6@record_mall", + "RECORD_7@record_mellohi", + "RECORD_8@record_stal", + "RECORD_9@record_strad", + "RED_MUSHROOM", + "RED_ROSE@red_flower", + "RED_SANDSTONE", + "RED_SANDSTONE_STAIRS", + "REDSTONE", + "REDSTONE_BLOCK", + "REDSTONE_COMPARATOR@comparator", + "REDSTONE_LAMP_OFF@redstone_lamp", + "REDSTONE_ORE", + "REDSTONE_TORCH_ON@redstone_torch", + "ROTTEN_FLESH", + "SADDLE", + "SAND", + "SANDSTONE", + "SANDSTONE_STAIRS", + "SAPLING", + "SEA_LANTERN", + "SEEDS@wheat_seeds", + "SHEARS", + "SIGN", + "SKULL_ITEM", + "SLIME_BALL", + "SLIME_BLOCK@slime", + "SMOOTH_BRICK@stonebrick", + "SMOOTH_STAIRS@stone_brick_stairs", + "SNOW@snow_layer", + "SNOW_BALL@snowball", + "SNOW_BLOCK@snow", + "SOUL_SAND", + "SPECKLED_MELON", + "SPIDER_EYE", + "SPONGE", + "SPRUCE_DOOR_ITEM", + "SPRUCE_FENCE", + "SPRUCE_FENCE_GATE", + "SPRUCE_WOOD_STAIRS@spruce_stairs", + "STAINED_CLAY@stained_hardened_clay", + "STAINED_GLASS", + "STAINED_GLASS_PANE", + "STEP@stone_slab", + "STICK", + "STONE", + "STONE_AXE", + "STONE_BUTTON", + "STONE_HOE", + "STONE_PICKAXE", + "STONE_PLATE@stone_pressure_plate", + "STONE_SLAB2", + "STONE_SPADE@stone_shovel", + "STONE_SWORD", + "STORAGE_MINECART@chest_minecart", + "STRING", + "SUGAR", + "SUGAR_CANE@reeds", + "SULPHUR@gunpowder", + "THIN_GLASS@glass_pane", + "TNT", + "TORCH", + "TRAP_DOOR@trapdoor", + "TRAPPED_CHEST", + "TRIPWIRE_HOOK", + "VINE", + "WATCH@clock", + "WATER_BUCKET", + "WATER_LILY@waterlily", + "WEB", + "WHEAT", + "WOOD@planks", + "WOOD_AXE@wooden_axe", + "WOOD_BUTTON@wooden_button", + "WOOD_DOOR@wooden_door", + "WOOD_HOE@wooden_hoe", + "WOOD_PICKAXE@wooden_pickaxe", + "WOOD_PLATE@wooden_pressure_plate", + "WOOD_SPADE@wooden_shovel", + "WOOD_STAIRS@oak_stairs", + "WOOD_STEP@wooden_slab", + "WOOD_SWORD@wooden_sword", + "WOOL", + "WORKBENCH@crafting_table", + "WRITTEN_BOOK", + "YELLOW_FLOWER" + }; + + private void addStack(ItemStack stackToAdd, int depth) { + if(depth > 16) return; + + String regName2 = stackToAdd.getItem().getRegistryName().replace("minecraft:", ""); + String internalname = null; + for(String bukkit2 : bukkitList) { + if(bukkit2.equalsIgnoreCase(regName2) || + (bukkit2.contains("@") && bukkit2.split("@")[1].equalsIgnoreCase(regName2))) { + internalname = bukkit2.split("@")[0]; + break; + } + } + if(internalname == null) return; + + if(stackToAdd.getItemDamage() != 0 && stackToAdd.getItemDamage() < 32000) { + internalname += "-" + stackToAdd.getItemDamage(); + } + + if(manager.getItemInformation().containsKey(internalname)) return; + + JsonObject recipeJson = null; + for(IRecipe recipe : CraftingManager.getInstance().getRecipeList()) { + ItemStack out = recipe.getRecipeOutput(); + if(out != null && out.getItem() == stackToAdd.getItem() && + (stackToAdd.getItemDamage() >= 32000 || out.getItemDamage() == stackToAdd.getItemDamage())) { + recipeJson = new JsonObject(); + + if (recipe instanceof ShapedRecipes) { + ShapedRecipes shaped = (ShapedRecipes) recipe; + + String[] x = {"1","2","3"}; + String[] y = {"A","B","C"}; + for(int i=0; i<9; i++) { + int xi = i%3; + int yi = i/3; + + String stacki = ""; + + int recipeIndex = i-(3-shaped.recipeWidth)*yi; + if(xi < shaped.recipeWidth && recipeIndex < shaped.recipeItems.length) { + ItemStack stack = shaped.recipeItems[recipeIndex]; + if(stack != null) { + if(stack.getItem() != stackToAdd.getItem() || + (stackToAdd.getItemDamage() < 32000 && stack.getItemDamage() != stackToAdd.getItemDamage())) addStack(stack, depth+1); + + Item stackItem = stack.getItem(); + String regName = stackItem.getRegistryName().replace("minecraft:", ""); + for(String bukkit2 : bukkitList) { + if(bukkit2.equalsIgnoreCase(regName) || + (bukkit2.contains("@") && bukkit2.split("@")[1].equalsIgnoreCase(regName))) { + stacki = bukkit2.split("@")[0]; + break; + } + } + if(!stacki.isEmpty()) { + if(stack.getItemDamage() != 0 && stack.getItemDamage() < 32000) { + stacki += "-" + stack.getItemDamage(); + } + stacki += ":"+stack.stackSize; + } + } + } + + recipeJson.addProperty(y[yi]+x[xi], stacki); + } + break; + } else if(recipe instanceof ShapedOreRecipe) { + ShapedOreRecipe shaped = (ShapedOreRecipe) recipe; + int width = (int)Utils.getField(ShapedOreRecipe.class, recipe, "width"); + String[] x = {"1","2","3"}; + String[] y = {"A","B","C"}; + for(int i=0; i<9; i++) { + int xi = i%3; + int yi = i/3; + + String stacki = ""; + + int recipeIndex = i - (3 - width) * yi; + if (xi < width && recipeIndex < shaped.getRecipeSize()) { + ItemStack stack = null; + if(recipeIndex < shaped.getRecipeSize()) { + Object o = shaped.getInput()[recipeIndex]; + if(o instanceof ItemStack) { + stack = (ItemStack) o; + } else if(o instanceof List<?>) { + for(Object o2 : (List<?>)o) { + if(o2 instanceof ItemStack) { + stack = (ItemStack) o2; + break; + } + } + } + } + if(stack != null) { + if(stack.getItem() != stackToAdd.getItem() || + (stackToAdd.getItemDamage() < 32000 && stack.getItemDamage() != stackToAdd.getItemDamage())) addStack(stack, depth+1); + Item stackItem = stack.getItem(); + String regName = stackItem.getRegistryName().replace("minecraft:", ""); + for(String bukkit2 : bukkitList) { + if(bukkit2.equalsIgnoreCase(regName) || bukkit2.equalsIgnoreCase(regName+"_ITEM") || + (bukkit2.contains("@") && bukkit2.split("@")[1].equalsIgnoreCase(regName))) { + stacki = bukkit2.split("@")[0]; + break; + } + } + if(!stacki.isEmpty()) { + if(stack.getItemDamage() != 0 && stack.getItemDamage() < 32000) { + stacki += "-" + stack.getItemDamage(); + } + //stacki += ":"+stack.stackSize; + stacki += ":1"; + } + } + } + + recipeJson.addProperty(y[yi]+x[xi], stacki); + } + } else if (recipe instanceof ShapelessRecipes) { + ShapelessRecipes shapeless = (ShapelessRecipes) recipe; + String[] x = {"1","2","3"}; + String[] y = {"A","B","C"}; + for(int i=0; i<9; i++) { + int xi = i%3; + int yi = i/3; + + String stacki = ""; + + ItemStack stack = null; + if(i < shapeless.recipeItems.size()) { + stack = shapeless.recipeItems.get(i); + } + if(stack != null) { + if(stack.getItem() != stackToAdd.getItem() || + (stackToAdd.getItemDamage() < 32000 && stack.getItemDamage() != stackToAdd.getItemDamage())) addStack(stack, depth+1); + Item stackItem = stack.getItem(); + String regName = stackItem.getRegistryName().replace("minecraft:", ""); + for(String bukkit2 : bukkitList) { + if(bukkit2.equalsIgnoreCase(regName) || bukkit2.equalsIgnoreCase(regName+"_ITEM") || + (bukkit2.contains("@") && bukkit2.split("@")[1].equalsIgnoreCase(regName))) { + stacki = bukkit2.split("@")[0]; + break; + } + } + if(!stacki.isEmpty()) { + if(stack.getItemDamage() != 0 && stack.getItemDamage() < 32000) { + stacki += "-" + stack.getItemDamage(); + } + //stacki += ":"+stack.stackSize; + stacki += ":1"; + } + } + + recipeJson.addProperty(y[yi]+x[xi], stacki); + } + break; + } else if (recipe instanceof ShapelessOreRecipe) { + ShapelessOreRecipe shapeless = (ShapelessOreRecipe) recipe; + String[] x = {"1","2","3"}; + String[] y = {"A","B","C"}; + for(int i=0; i<9; i++) { + int xi = i%3; + int yi = i/3; + + String stacki = ""; + + ItemStack stack = null; + if(i < shapeless.getRecipeSize()) { + Object o = shapeless.getInput().get(i);; + if(o instanceof ItemStack) { + stack = (ItemStack) o; + } else if(o instanceof List<?>) { + for(Object o2 : (List<?>)o) { + if(o2 instanceof ItemStack) { + stack = (ItemStack) o2; + break; + } + } + } + } + if(stack != null) { + if(stack.getItem() != stackToAdd.getItem() || + (stackToAdd.getItemDamage() < 32000 && stack.getItemDamage() != stackToAdd.getItemDamage())) addStack(stack, depth+1); + Item stackItem = stack.getItem(); + String regName = stackItem.getRegistryName().replace("minecraft:", ""); + for(String bukkit2 : bukkitList) { + if(bukkit2.equalsIgnoreCase(regName) || bukkit2.equalsIgnoreCase(regName+"_ITEM") || + (bukkit2.contains("@") && bukkit2.split("@")[1].equalsIgnoreCase(regName))) { + stacki = bukkit2.split("@")[0]; + break; + } + } + if(!stacki.isEmpty()) { + if(stack.getItemDamage() != 0 && stack.getItemDamage() < 32000) { + stacki += "-" + stack.getItemDamage(); + } + //stacki += ":"+stack.stackSize; + stacki += ":1"; + } + } + + recipeJson.addProperty(y[yi]+x[xi], stacki); + } + break; + } + } + + } + ItemStack res = Utils.createItemStack(stackToAdd.getItem(), + EnumChatFormatting.WHITE+stackToAdd.getItem().getItemStackDisplayName(stackToAdd), + EnumChatFormatting.WHITE.toString()+EnumChatFormatting.BOLD+"COMMON"); + if(stackToAdd.getItemDamage() != 0 && stackToAdd.getItemDamage() < 32000) { + res.setItemDamage(stackToAdd.getItemDamage()); + } + res.getTagCompound().setInteger("HideFlags", 254); + NBTTagCompound ea = new NBTTagCompound(); + ea.setString("id", internalname); + res.getTagCompound().setTag("ExtraAttributes", ea); + + + JsonObject json = manager.getJsonForItem(res); + if(stackToAdd.getItemDamage() != 0 && stackToAdd.getItemDamage() < 32000) { + json.addProperty("parent", internalname.split("-")[0]); + } + + json.addProperty("internalname", internalname); + json.addProperty("modver", NotEnoughUpdates.VERSION); + json.addProperty("vanilla", true); + + if(recipeJson != null) { + json.add("recipe", recipeJson); + json.addProperty("clickcommand", "viewrecipe"); + } else { + json.addProperty("clickcommand", ""); + } + + json.addProperty("modver", NotEnoughUpdates.VERSION); + + try { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Added: " + internalname)); + manager.writeJsonDefaultDir(json, internalname+".json"); + manager.loadItem(internalname); + } catch(IOException e) {} + } + @Override public boolean keyboardInput() { + if(running.get() || true) return false; if(Keyboard.isKeyDown(Keyboard.KEY_J)) { running.set(!running.get()); - for(Map.Entry<String, JsonObject> item : manager.getItemInformation().entrySet()) { + for(String bukkit : bukkitList) { + String internalname = bukkit.split("@")[0]; + if(true || !manager.getItemInformation().containsKey(internalname)) { + //System.out.println("adding vanilla: " + internalname); + String vanilla = internalname.toLowerCase().replace("_item", ""); + if(bukkit.contains("@")) { + vanilla = bukkit.split("@")[1]; + } + Item item = Item.itemRegistry.getObject(new ResourceLocation(vanilla)); + if(item == null) { + item = Item.getItemFromBlock(Block.blockRegistry.getObject(new ResourceLocation(vanilla))); + } + if(item != null) { + HashMap<Integer, JsonObject> recipeJsonForDamage = new HashMap<>(); + for(IRecipe recipe : CraftingManager.getInstance().getRecipeList()) { + ItemStack out = recipe.getRecipeOutput(); + if(out != null && out.getItem() == item) { + System.out.println("Found recipe for : " + internalname + ":" + recipe); + JsonObject obj = new JsonObject(); + + if (recipe instanceof ShapedRecipes) { + ShapedRecipes shaped = (ShapedRecipes) recipe; + String[] x = {"1", "2", "3"}; + String[] y = {"A", "B", "C"}; + for (int i = 0; i < 9; i++) { + int xi = i % 3; + int yi = i / 3; + + String stacki = ""; + + int recipeIndex = i - (3 - shaped.recipeWidth) * yi; + if (xi < shaped.recipeWidth && recipeIndex < shaped.recipeItems.length) { + ItemStack stack = shaped.recipeItems[recipeIndex]; + if (stack != null) { + addStack(stack, 0); + Item stackItem = stack.getItem(); + String regName = stackItem.getRegistryName().replace("minecraft:", ""); + for (String bukkit2 : bukkitList) { + if (bukkit2.equalsIgnoreCase(regName) || bukkit2.equalsIgnoreCase(regName + "_ITEM") || + (bukkit2.contains("@") && bukkit2.split("@")[1].equalsIgnoreCase(regName))) { + stacki = bukkit2.split("@")[0]; + break; + } + } + if (!stacki.isEmpty()) { + if (stack.getItemDamage() != 0 && stack.getItemDamage() < 32000) { + stacki += "-" + stack.getItemDamage(); + } + //stacki += ":"+stack.stackSize; + stacki += ":1"; + } + } + } + + obj.addProperty(y[yi] + x[xi], stacki); + } + recipeJsonForDamage.put(out.getItemDamage() > 32000 ? 0 : out.getItemDamage(), obj); + } else if(recipe instanceof ShapedOreRecipe) { + ShapedOreRecipe shaped = (ShapedOreRecipe) recipe; + int width = (int)Utils.getField(ShapedOreRecipe.class, recipe, "width"); + String[] x = {"1","2","3"}; + String[] y = {"A","B","C"}; + for(int i=0; i<9; i++) { + int xi = i%3; + int yi = i/3; + + String stacki = ""; + + int recipeIndex = i - (3 - width) * yi; + if (xi < width && recipeIndex < shaped.getRecipeSize()) { + ItemStack stack = null; + if(recipeIndex < shaped.getRecipeSize()) { + Object o = shaped.getInput()[recipeIndex]; + if(o instanceof ItemStack) { + stack = (ItemStack) o; + } else if(o instanceof List<?>) { + for(Object o2 : (List<?>)o) { + if(o2 instanceof ItemStack) { + stack = (ItemStack) o2; + break; + } + } + } + } + if(stack != null) { + addStack(stack, 0); + Item stackItem = stack.getItem(); + String regName = stackItem.getRegistryName().replace("minecraft:", ""); + for(String bukkit2 : bukkitList) { + if(bukkit2.equalsIgnoreCase(regName) || bukkit2.equalsIgnoreCase(regName+"_ITEM") || + (bukkit2.contains("@") && bukkit2.split("@")[1].equalsIgnoreCase(regName))) { + stacki = bukkit2.split("@")[0]; + break; + } + } + if(!stacki.isEmpty()) { + if(stack.getItemDamage() != 0 && stack.getItemDamage() < 32000) { + stacki += "-" + stack.getItemDamage(); + } + //stacki += ":"+stack.stackSize; + stacki += ":1"; + } + } + } + + obj.addProperty(y[yi]+x[xi], stacki); + } + recipeJsonForDamage.put(out.getItemDamage()>32000?0:out.getItemDamage(), obj); + } else if (recipe instanceof ShapelessRecipes) { + ShapelessRecipes shapeless = (ShapelessRecipes) recipe; + String[] x = {"1","2","3"}; + String[] y = {"A","B","C"}; + for(int i=0; i<9; i++) { + int xi = i%3; + int yi = i/3; + + String stacki = ""; + + ItemStack stack = null; + if(i < shapeless.recipeItems.size()) { + stack = shapeless.recipeItems.get(i); + } + if(stack != null) { + addStack(stack, 0); + Item stackItem = stack.getItem(); + String regName = stackItem.getRegistryName().replace("minecraft:", ""); + for(String bukkit2 : bukkitList) { + if(bukkit2.equalsIgnoreCase(regName) || bukkit2.equalsIgnoreCase(regName+"_ITEM") || + (bukkit2.contains("@") && bukkit2.split("@")[1].equalsIgnoreCase(regName))) { + stacki = bukkit2.split("@")[0]; + break; + } + } + if(!stacki.isEmpty()) { + if(stack.getItemDamage() != 0 && stack.getItemDamage() < 32000) { + stacki += "-" + stack.getItemDamage(); + } + //stacki += ":"+stack.stackSize; + stacki += ":1"; + } + } + + obj.addProperty(y[yi]+x[xi], stacki); + } + recipeJsonForDamage.put(out.getItemDamage() > 32000 ? 0 : out.getItemDamage(), obj); + break; + } else if (recipe instanceof ShapelessOreRecipe) { + ShapelessOreRecipe shapeless = (ShapelessOreRecipe) recipe; + String[] x = {"1","2","3"}; + String[] y = {"A","B","C"}; + for(int i=0; i<9; i++) { + int xi = i%3; + int yi = i/3; + + String stacki = ""; + + ItemStack stack = null; + if(i < shapeless.getRecipeSize()) { + Object o = shapeless.getInput().get(i);; + if(o instanceof ItemStack) { + stack = (ItemStack) o; + } else if(o instanceof List<?>) { + for(Object o2 : (List<?>)o) { + if(o2 instanceof ItemStack) { + stack = (ItemStack) o2; + break; + } + } + } + } + if(stack != null) { + addStack(stack, 0); + Item stackItem = stack.getItem(); + String regName = stackItem.getRegistryName().replace("minecraft:", ""); + for(String bukkit2 : bukkitList) { + if(bukkit2.equalsIgnoreCase(regName) || bukkit2.equalsIgnoreCase(regName+"_ITEM") || + (bukkit2.contains("@") && bukkit2.split("@")[1].equalsIgnoreCase(regName))) { + stacki = bukkit2.split("@")[0]; + break; + } + } + if(!stacki.isEmpty()) { + if(stack.getItemDamage() != 0 && stack.getItemDamage() < 32000) { + stacki += "-" + stack.getItemDamage(); + } + //stacki += ":"+stack.stackSize; + stacki += ":1"; + } + } + + obj.addProperty(y[yi]+x[xi], stacki); + } + recipeJsonForDamage.put(out.getItemDamage() > 32000 ? 0 : out.getItemDamage(), obj); + break; + } + } + } + + if(recipeJsonForDamage.isEmpty()) { + ItemStack res = Utils.createItemStack(item, + EnumChatFormatting.WHITE+item.getItemStackDisplayName(new ItemStack(item)), + EnumChatFormatting.WHITE.toString()+EnumChatFormatting.BOLD+"COMMON"); + res.getTagCompound().setInteger("HideFlags", 254); + NBTTagCompound ea = new NBTTagCompound(); + ea.setString("id", internalname); + res.getTagCompound().setTag("ExtraAttributes", ea); + + JsonObject json = manager.getJsonForItem(res); + json.addProperty("internalname", internalname); + + json.addProperty("modver", NotEnoughUpdates.VERSION); + json.addProperty("vanilla", true); + + json.addProperty("clickcommand", ""); + try { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Added: " + internalname)); + manager.writeJsonDefaultDir(json, internalname+".json"); + manager.loadItem(internalname); + } catch(IOException e) {} + } else { + System.out.println("writing with recipe:" + internalname); + for(Map.Entry<Integer, JsonObject> entry : recipeJsonForDamage.entrySet()) { + ItemStack res = Utils.createItemStack(item, + EnumChatFormatting.WHITE+item.getItemStackDisplayName(new ItemStack(item, 1, entry.getKey())), + EnumChatFormatting.WHITE.toString()+EnumChatFormatting.BOLD+"COMMON"); + res.setItemDamage(entry.getKey()); + res.getTagCompound().setInteger("HideFlags", 254); + NBTTagCompound ea = new NBTTagCompound(); + ea.setString("id", internalname); + res.getTagCompound().setTag("ExtraAttributes", ea); + + JsonObject json = manager.getJsonForItem(res); + + if(entry.getKey() != 0 && entry.getKey() < 32000) { + json.addProperty("internalname", internalname+"-"+entry.getKey()); + json.addProperty("parent", internalname); + } else { + json.addProperty("internalname", internalname); + } + + json.addProperty("modver", NotEnoughUpdates.VERSION); + json.addProperty("vanilla", true); + json.addProperty("clickcommand", "viewrecipe"); + json.add("recipe", entry.getValue()); + try { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Added: " + internalname)); + if(entry.getKey() != 0 && entry.getKey() < 32000) { + manager.writeJsonDefaultDir(json, internalname+"-"+entry.getKey()+".json"); + } else { + manager.writeJsonDefaultDir(json, internalname+".json"); + } + manager.loadItem(internalname); + } catch(IOException e) {} + } + } + } + } + } + + //for(Map.Entry<String, JsonObject> item : manager.getItemInformation().entrySet()) { /*if(!item.getValue().has("infoType") || item.getValue().get("infoType").getAsString().isEmpty()) { if(item.getValue().has("info") && item.getValue().get("info").getAsJsonArray().size()>0) { item.getValue().addProperty("infoType", "WIKI_URL"); @@ -167,7 +1023,7 @@ public class DevInfoPane extends TextInfoPane { } }, 1000L, TimeUnit.MILLISECONDS); }*/ - } + //} /*if(Keyboard.isKeyDown(Keyboard.KEY_J) && !running) { running = true; List<String> add = new ArrayList<>(); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java index 3e9cdb3f..c03b98fb 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java @@ -136,6 +136,10 @@ public class HTMLInfoPane extends TextInfoPane { return new HTMLInfoPane(overlay, manager, name, filename, html); } + private String spaceEscape(String str) { + return str.replace(" ", "\\ "); + } + /** * Uses the wkhtmltoimage command-line tool to generate an image from the HTML code. This * generation is done asynchronously as sometimes it can take up to 10 seconds for more @@ -190,9 +194,16 @@ public class HTMLInfoPane extends TextInfoPane { EnumChatFormatting.GRAY+"), please wait..."; Runtime runtime = Runtime.getRuntime(); - Process p = runtime.exec("\""+wkHtmlToImage.getAbsolutePath() + "\" --width "+ + + String[] wkCommand = new String[]{ wkHtmlToImage.getAbsolutePath(), "--width", ""+IMAGE_WIDTH*ZOOM_FACTOR, + "--transparent", "--zoom", ""+ZOOM_FACTOR, input.getAbsolutePath(), output.getAbsolutePath()}; + Process p = runtime.exec(wkCommand); + /*Process p = runtime.exec(spaceEscape(wkHtmlToImage.getAbsolutePath()) + " --width "+ + IMAGE_WIDTH*ZOOM_FACTOR+" --transparent --zoom "+ZOOM_FACTOR + " " + spaceEscape(input.getAbsolutePath()) + + " " + spaceEscape(output.getAbsolutePath()));*/ + /*Process p = runtime.exec("\""+wkHtmlToImage.getAbsolutePath() + "\" --width "+ IMAGE_WIDTH*ZOOM_FACTOR+" --transparent --zoom "+ZOOM_FACTOR+" \"" + input.getAbsolutePath() + - "\" \"" + output.getAbsolutePath() + "\""); + "\" \"" + output.getAbsolutePath() + "\"");*/ /*Process p2 = runtime.exec("\""+wkHtmlToImage.getAbsolutePath() + "\" --width "+ (IMAGE_WIDTH+EXT_WIDTH)*ZOOM_FACTOR+" --transparent --zoom "+ZOOM_FACTOR+" \"" + input.getAbsolutePath() + "\" \"" + outputExt.getAbsolutePath() + "\"");*/ diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java index 60f8ca72..76b500f5 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java @@ -17,6 +17,8 @@ public abstract class InfoPane extends Gui { this.manager = manager; } + public void reset() {} + public void tick() {} public abstract void render(int width, int height, Color bg, Color fg, ScaledResolution scaledresolution, int mouseX, diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/SettingsInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/SettingsInfoPane.java index 2bba6426..4938770d 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/SettingsInfoPane.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/SettingsInfoPane.java @@ -1,19 +1,29 @@ package io.github.moulberry.notenoughupdates.infopanes; +import io.github.moulberry.notenoughupdates.BetterContainers; import io.github.moulberry.notenoughupdates.NEUManager; import io.github.moulberry.notenoughupdates.NEUOverlay; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.SpecialColour; import io.github.moulberry.notenoughupdates.util.Utils; import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField; import io.github.moulberry.notenoughupdates.options.Options; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.entity.item.EntityXPOrb; import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; +import scala.tools.cmd.Spec; import java.awt.*; +import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -25,6 +35,11 @@ import static io.github.moulberry.notenoughupdates.GuiTextures.*; public class SettingsInfoPane extends InfoPane { + private int currentCategory = Options.CAT_ALL; + private final String[] CATEGORY_NAMES = {"All", "Misc", "Features", "Sliders", "Colours"}; + + private GuiElementTextField searchBar = new GuiElementTextField("", 0); + private final Map<Options.Option<?>, GuiElementTextField> textConfigMap = new HashMap<>(); private int page = 0; private int maxPages = 1; @@ -33,19 +48,60 @@ public class SettingsInfoPane extends InfoPane { private int clickedSliderX = 0; private float clickedSliderMult = 0; + private static final int colourEditorBG = new Color(80, 80, 80, 220).getRGB(); + private static ResourceLocation colourPickerLocation = new ResourceLocation("notenoughupdates:dynamic/colourpicker"); + private static ResourceLocation colourPickerBarValueLocation = new ResourceLocation("notenoughupdates:dynamic/colourpickervalue"); + private static ResourceLocation colourPickerBarOpacityLocation = new ResourceLocation("notenoughupdates:dynamic/colourpickeropacity"); + + private GuiElementTextField hexField = new GuiElementTextField("", + GuiElementTextField.SCALE_TEXT | GuiElementTextField.FORCE_CAPS | GuiElementTextField.NO_SPACE); + private ColourEditor activeColourEditor = null; + + private class ColourEditor { + public int x; + public int y; + public Options.Option<String> option; + public String special; + + public ColourEditor(int x, int y, Options.Option<String> option, String special) { + this.x = x; + this.y = y; + this.option = option; + this.special = special; + } + } + public SettingsInfoPane(NEUOverlay overlay, NEUManager manager) { super(overlay, manager); } - public void render(int width, int height, Color bg, Color fg, ScaledResolution scaledresolution, int mouseX, + public void reset() { + textConfigMap.clear(); + activeColourEditor = null; + hexField.otherComponentClick(); + } + + private void showColourEditor(int mouseX, int mouseY, Options.Option<String> option, String special) { + activeColourEditor = new ColourEditor(mouseX, mouseY, option, special); + hexField.otherComponentClick(); + } + + public void render(int width, int height, Color bg, Color fg, ScaledResolution scaledResolution, int mouseX, int mouseY) { + Utils.pushGuiScale(2); + + int widthN = Utils.peekGuiScale().getScaledWidth(); + int heightN = Utils.peekGuiScale().getScaledHeight(); + int mouseXN = Mouse.getX() * widthN / Minecraft.getMinecraft().displayWidth; + int mouseYN = heightN - Mouse.getY() * heightN / Minecraft.getMinecraft().displayHeight - 1; + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; - int paneWidth = (int)(width/3*overlay.getWidthMult()); - int rightSide = (int)(width*overlay.getInfoPaneOffsetFactor()); + int paneWidth = (int)(widthN/3*overlay.getWidthMult()); + int rightSide = (int)(widthN*overlay.getInfoPaneOffsetFactor()); int leftSide = rightSide - paneWidth; - this.renderDefaultBackground(width, height, bg); + this.renderDefaultBackground(widthN, heightN, bg); if(page > maxPages-1) page = maxPages-1; if(page < 0) page = 0; @@ -53,6 +109,29 @@ public class SettingsInfoPane extends InfoPane { overlay.renderNavElement(leftSide+overlay.getBoxPadding(), rightSide-overlay.getBoxPadding(), maxPages,page+1,"Settings: "); + int area = rightSide-leftSide-overlay.getBoxPadding()*2; + int categoryArea = (area-3*4)/5; + int ySize = overlay.getSearchBarYSize(); + int yStartCat = overlay.getBoxPadding()+overlay.getSearchBarYSize()+3; + for(int i=0; i<5; i++) { + boolean pressed = currentCategory == i; + drawRect(leftSide+overlay.getBoxPadding()+i*(categoryArea+3), yStartCat, + leftSide+overlay.getBoxPadding()+i*(categoryArea+3)+categoryArea, yStartCat+ySize, fg.getRGB()); + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(rightarrow_overlay); + Utils.drawTexturedRect(leftSide+overlay.getBoxPadding()+i*(categoryArea+3), + yStartCat, categoryArea, ySize, pressed?0:1, pressed?1:0, pressed?0:1, pressed?1:0, GL11.GL_NEAREST); + + Utils.drawStringCenteredScaledMaxWidth(EnumChatFormatting.BOLD+CATEGORY_NAMES[i], + Minecraft.getMinecraft().fontRendererObj, + leftSide+overlay.getBoxPadding()+i*(categoryArea+3)+categoryArea/2f, + yStartCat+ySize/2f, false, categoryArea-6, 0); + } + + searchBar.setSize(area-5, ySize); + searchBar.setMaxStringLength(45); + searchBar.render(leftSide+overlay.getBoxPadding()+1, overlay.getBoxPadding()+overlay.getSearchBarYSize()*2+7); + AtomicReference<List<String>> textToDisplay = new AtomicReference<>(null); AtomicReference<GuiElementTextField> tfTop = new AtomicReference<>(); AtomicInteger tfTopX = new AtomicInteger(); @@ -61,14 +140,22 @@ public class SettingsInfoPane extends InfoPane { public void consume(int x, int y, int tileWidth, int tileHeight, Options.Option<?> option, Options.Button button) { float mult = tileWidth/90f; - drawRect(x, y, x+tileWidth, y+tileHeight, fg.getRGB()); + drawRect(x+2, y+2, x+tileWidth-2, y+tileHeight-2, fg.getRGB()); + + Minecraft.getMinecraft().getTextureManager().bindTexture(setting_border); + GlStateManager.color(1, 1, 1, 1); + + Utils.drawTexturedRect(x, y, tileWidth, 5, 0, 1, 0, 5/75f, GL11.GL_NEAREST); + Utils.drawTexturedRect(x, y+tileHeight-5, tileWidth, 5, 0, 1, 70/75f, 1, GL11.GL_NEAREST); + Utils.drawTexturedRect(x, y+5, tileWidth, tileHeight-10, 0, 1, 5/75f, 70/75f, GL11.GL_NEAREST); + Utils.drawTexturedRect(x+5, y, tileWidth-10, tileHeight, 5/100f, 95/100f, 0, 1, GL11.GL_NEAREST); if(manager.config.hideApiKey.value && option==manager.config.apiKey) return; if(option == null) { Utils.renderStringTrimWidth(button.displayName, fr, true, x+(int)(8*mult), y+(int)(8*mult), tileWidth-(int)(16*mult), new Color(100,255,150).getRGB(), 3, - 2f/scaledresolution.getScaleFactor()); + 2f/Utils.peekGuiScale().getScaleFactor()); GlStateManager.color(1f, 1f, 1f, 1f); Minecraft.getMinecraft().getTextureManager().bindTexture(button_tex); @@ -78,8 +165,8 @@ public class SettingsInfoPane extends InfoPane { Utils.drawTexturedRect(x + tileWidth/2f + (int) (19 * mult), y + tileHeight - (int) (19 * mult), (int) (14 * mult), (int) (14 * mult)); GlStateManager.bindTexture(0); - if (mouseX > x + tileWidth / 2 + (int) (19 * mult) && mouseX < x + tileWidth / 2 + (int) (19 * mult) + (int) (14 * mult)) { - if (mouseY > y + tileHeight - (int) (19 * mult) && mouseY < y + tileHeight - (int) (19 * mult) + (int) (14 * mult)) { + if (mouseXN > x + tileWidth / 2 + (int) (19 * mult) && mouseXN < x + tileWidth / 2 + (int) (19 * mult) + (int) (14 * mult)) { + if (mouseYN > y + tileHeight - (int) (19 * mult) && mouseYN < y + tileHeight - (int) (19 * mult) + (int) (14 * mult)) { List<String> textLines = new ArrayList<>(); textLines.add(button.displayName); textLines.add(EnumChatFormatting.GRAY + button.desc); @@ -91,7 +178,7 @@ public class SettingsInfoPane extends InfoPane { Utils.renderStringTrimWidth(option.displayName, fr, true, x+(int)(8*mult), y+(int)(8*mult), tileWidth-(int)(16*mult), new Color(100,255,150).getRGB(), 3, - 2f/scaledresolution.getScaleFactor()); + 2f/Utils.peekGuiScale().getScaleFactor()); if(option.value instanceof Boolean) { GlStateManager.color(1f, 1f, 1f, 1f); @@ -102,8 +189,8 @@ public class SettingsInfoPane extends InfoPane { Utils.drawTexturedRect(x + tileWidth/2f + (int) (19 * mult), y + tileHeight - (int) (19 * mult), (int) (14 * mult), (int) (14 * mult)); GlStateManager.bindTexture(0); - if (mouseX > x + tileWidth / 2 + (int) (19 * mult) && mouseX < x + tileWidth / 2 + (int) (19 * mult) + (int) (14 * mult)) { - if (mouseY > y + tileHeight - (int) (19 * mult) && mouseY < y + tileHeight - (int) (19 * mult) + (int) (14 * mult)) { + if (mouseXN > x + tileWidth / 2 + (int) (19 * mult) && mouseXN < x + tileWidth / 2 + (int) (19 * mult) + (int) (14 * mult)) { + if (mouseYN > y + tileHeight - (int) (19 * mult) && mouseYN < y + tileHeight - (int) (19 * mult) + (int) (14 * mult)) { List<String> textLines = new ArrayList<>(); textLines.add(option.displayName); textLines.add(EnumChatFormatting.GRAY + option.desc); @@ -115,6 +202,7 @@ public class SettingsInfoPane extends InfoPane { textConfigMap.put(option, new GuiElementTextField(String.valueOf(option.value), GuiElementTextField.NUM_ONLY | GuiElementTextField.NO_SPACE | GuiElementTextField.SCALE_TEXT)); } + GuiElementTextField tf = textConfigMap.get(option); if(tf.getText().trim().endsWith(".0")) { tf.setText(tf.getText().trim().substring(0, tf.getText().trim().length()-2)); @@ -146,18 +234,46 @@ public class SettingsInfoPane extends InfoPane { Utils.drawTexturedRect(x+1*mult+(float)(54*sliderAmount*mult), y + tileHeight - 20*mult, 8*mult, 16*mult); } else { - if(!textConfigMap.containsKey(option)) { - textConfigMap.put(option, new GuiElementTextField(String.valueOf(option.value), 0)); - } - GuiElementTextField tf = textConfigMap.get(option); - if(tf.getFocus()) { - tf.setSize(Math.max(tileWidth-(int)(20*mult), fr.getStringWidth(tf.getText())+10), (int)(16*mult)); - tfTop.set(tf); - tfTopX.set(x+(int)(10*mult)); - tfTopY.set(y+tileHeight-(int)(20*mult)); + if((option.flags & Options.FLAG_COLOUR) != 0) { + Utils.renderStringTrimWidth(option.displayName, fr, true, x+(int)(8*mult), y+(int)(8*mult), + tileWidth-(int)(16*mult), new Color(100,255,150).getRGB(), 3, + 2f/Utils.peekGuiScale().getScaleFactor()); + + Color c = new Color(SpecialColour.specialToChromaRGB((String)option.value)); + GlStateManager.color( + Math.min(1f, c.getRed()/255f), + Math.min(1f, c.getGreen()/255f), + Math.min(1f, c.getBlue()/255f), 1f); + Minecraft.getMinecraft().getTextureManager().bindTexture(button_white); + Utils.drawTexturedRect(x + tileWidth/2f - (int) (32 * mult), y + tileHeight - (int) (20 * mult), (int) (48 * mult), (int) (16 * mult)); + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(help); + Utils.drawTexturedRect(x + tileWidth/2f + (int) (19 * mult), y + tileHeight - (int) (19 * mult), (int) (14 * mult), (int) (14 * mult)); + GlStateManager.bindTexture(0); + + if (mouseXN > x + tileWidth / 2 + (int) (19 * mult) && mouseXN < x + tileWidth / 2 + (int) (19 * mult) + (int) (14 * mult)) { + if (mouseYN > y + tileHeight - (int) (19 * mult) && mouseYN < y + tileHeight - (int) (19 * mult) + (int) (14 * mult)) { + List<String> textLines = new ArrayList<>(); + textLines.add(option.displayName); + textLines.add(EnumChatFormatting.GRAY + option.desc); + textToDisplay.set(textLines); + } + } } else { - tf.setSize(tileWidth-(int)(20*mult), (int)(16*mult)); - tf.render(x+(int)(10*mult), y+tileHeight-(int)(20*mult)); + if(!textConfigMap.containsKey(option)) { + textConfigMap.put(option, new GuiElementTextField(String.valueOf(option.value), 0)); + } + GuiElementTextField tf = textConfigMap.get(option); + if(tf.getFocus()) { + tf.setSize(Math.max(tileWidth-(int)(20*mult), fr.getStringWidth(tf.getText())+10), (int)(16*mult)); + tfTop.set(tf); + tfTopX.set(x+(int)(10*mult)); + tfTopY.set(y+tileHeight-(int)(20*mult)); + } else { + tf.setSize(tileWidth-(int)(20*mult), (int)(16*mult)); + tf.render(x+(int)(10*mult), y+tileHeight-(int)(20*mult)); + } } } } @@ -165,9 +281,142 @@ public class SettingsInfoPane extends InfoPane { if(tfTop.get() != null) { tfTop.get().render(tfTopX.get(), tfTopY.get()); } + + if(activeColourEditor != null) { + Gui.drawRect(activeColourEditor.x, activeColourEditor.y, activeColourEditor.x+119, activeColourEditor.y+89, colourEditorBG); + + int currentColour = SpecialColour.specialToSimpleRGB(activeColourEditor.special); + Color c = new Color(currentColour, true); + float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null); + + BufferedImage bufferedImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB); + for(int x=0; x<256; x++) { + for(int y=0; y<256; y++) { + float radius = (float) Math.sqrt(((x-128)*(x-128)+(y-128)*(y-128))/16384f); + float angle = (float) Math.toDegrees(Math.atan((128-x)/(y-128+1E-5))+Math.PI/2); + if(y < 128) angle += 180; + if(radius <= 1) { + int rgb = Color.getHSBColor(angle/360f, (float)Math.pow(radius, 1.5f), hsv[2]).getRGB(); + bufferedImage.setRGB(x, y, rgb); + } + } + } + + BufferedImage bufferedImageValue = new BufferedImage(10, 64, BufferedImage.TYPE_INT_ARGB); + for(int x=0; x<10; x++) { + for(int y=0; y<64; y++) { + if((x == 0 || x == 9) && (y == 0 || y == 63)) continue; + + int rgb = Color.getHSBColor(hsv[0], hsv[1], (64-y)/64f).getRGB(); + bufferedImageValue.setRGB(x, y, rgb); + } + } + + BufferedImage bufferedImageOpacity = new BufferedImage(10, 64, BufferedImage.TYPE_INT_ARGB); + for(int x=0; x<10; x++) { + for(int y=0; y<64; y++) { + if((x == 0 || x == 9) && (y == 0 || y == 63)) continue; + + int rgb = (currentColour & 0x00FFFFFF) | (Math.min(255, (64-y)*4) << 24); + bufferedImageOpacity.setRGB(x, y, rgb); + } + } + + float selradius = (float) Math.pow(hsv[1], 1/1.5f)*32; + int selx = (int)(Math.cos(Math.toRadians(hsv[0]*360))*selradius); + int sely = (int)(Math.sin(Math.toRadians(hsv[0]*360))*selradius); + + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_bar_alpha); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(activeColourEditor.x+5+64+5+10+5, activeColourEditor.y+5, 10, 64, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().loadTexture(colourPickerBarValueLocation, new DynamicTexture(bufferedImageValue)); + Minecraft.getMinecraft().getTextureManager().bindTexture(colourPickerBarValueLocation); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(activeColourEditor.x+5+64+5, activeColourEditor.y+5, 10, 64, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().loadTexture(colourPickerBarOpacityLocation, new DynamicTexture(bufferedImageOpacity)); + Minecraft.getMinecraft().getTextureManager().bindTexture(colourPickerBarOpacityLocation); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(activeColourEditor.x+5+64+5+10+5, activeColourEditor.y+5, 10, 64, GL11.GL_NEAREST); + + int chromaSpeed = SpecialColour.getSpeed(activeColourEditor.special); + int currentColourChroma = SpecialColour.specialToChromaRGB(activeColourEditor.special); + Color cChroma = new Color(currentColourChroma, true); + float hsvChroma[] = Color.RGBtoHSB(cChroma.getRed(), cChroma.getGreen(), cChroma.getBlue(), null); + + if(chromaSpeed > 0) { + Gui.drawRect(activeColourEditor.x+5+64+5+10+5+10+5+1, activeColourEditor.y+5+1, + activeColourEditor.x+5+64+5+10+5+10+5+10-1, activeColourEditor.y+5+64-1, + Color.HSBtoRGB(hsvChroma[0], 0.8f, 0.8f)); + } else { + Gui.drawRect(activeColourEditor.x+5+64+5+10+5+10+5+1, activeColourEditor.y+5+27+1, + activeColourEditor.x+5+64+5+10+5+10+5+10-1, activeColourEditor.y+5+37-1, + Color.HSBtoRGB((hsvChroma[0]+(System.currentTimeMillis()-SpecialColour.startTime)/1000f)%1, 0.8f, 0.8f)); + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_bar); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(activeColourEditor.x+5+64+5, activeColourEditor.y+5, 10, 64, GL11.GL_NEAREST); + Utils.drawTexturedRect(activeColourEditor.x+5+64+5+10+5, activeColourEditor.y+5, 10, 64, GL11.GL_NEAREST); + + if(chromaSpeed > 0) { + Utils.drawTexturedRect(activeColourEditor.x+5+64+5+10+5+10+5, activeColourEditor.y+5, 10, 64, GL11.GL_NEAREST); + } else { + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_chroma); + Utils.drawTexturedRect(activeColourEditor.x+5+64+5+10+5+10+5, activeColourEditor.y+5+27, 10, 10, GL11.GL_NEAREST); + } + + Gui.drawRect(activeColourEditor.x+5+64+5, activeColourEditor.y+5+64-(int)(64*hsv[2]), + activeColourEditor.x+5+64+5+10, activeColourEditor.y+5+64-(int)(64*hsv[2])+1, 0xFF000000); + Gui.drawRect(activeColourEditor.x+5+64+5+10+5, activeColourEditor.y+5+64-c.getAlpha()/4, + activeColourEditor.x+5+64+5+10+5+10, activeColourEditor.y+5+64-c.getAlpha()/4-1, 0xFF000000); + if(chromaSpeed > 0) { + Gui.drawRect(activeColourEditor.x+5+64+5+10+5+10+5, + activeColourEditor.y+5+64-(int)(chromaSpeed/255f*64), + activeColourEditor.x+5+64+5+10+5+10+5+10, + activeColourEditor.y+5+64-(int)(chromaSpeed/255f*64)+1, 0xFF000000); + } + + Minecraft.getMinecraft().getTextureManager().loadTexture(colourPickerLocation, new DynamicTexture(bufferedImage)); + Minecraft.getMinecraft().getTextureManager().bindTexture(colourPickerLocation); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(activeColourEditor.x+5, activeColourEditor.y+5, 64, 64, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_dot); + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(activeColourEditor.x+5+32+selx-4, activeColourEditor.y+5+32+sely-4, 8, 8, GL11.GL_NEAREST); + + Utils.drawStringCenteredScaledMaxWidth(EnumChatFormatting.GRAY.toString()+Math.round(hsv[2]*100)+"", + Minecraft.getMinecraft().fontRendererObj, + activeColourEditor.x+5+64+5+5-(Math.round(hsv[2]*100)==100?1:0), activeColourEditor.y+5+64+5+5, true, 13, -1); + Utils.drawStringCenteredScaledMaxWidth(EnumChatFormatting.GRAY.toString()+Math.round(c.getAlpha()/255f*100)+"", + Minecraft.getMinecraft().fontRendererObj, + activeColourEditor.x+5+64+5+15+5, activeColourEditor.y+5+64+5+5, true, 13, -1); + if(chromaSpeed > 0) { + Utils.drawStringCenteredScaledMaxWidth(EnumChatFormatting.GRAY.toString()+(int)SpecialColour.getSecondsForSpeed(chromaSpeed)+"s", + Minecraft.getMinecraft().fontRendererObj, + activeColourEditor.x+5+64+5+30+6, activeColourEditor.y+5+64+5+5, true, 13, -1); + } + + hexField.setSize(48, 10); + if(!hexField.getFocus()) hexField.setText(Integer.toHexString(c.getRGB() & 0xFFFFFF).toUpperCase()); + + StringBuilder sb = new StringBuilder(EnumChatFormatting.GRAY+"#"); + for(int i=0; i<6-hexField.getText().length(); i++) { + sb.append("0"); + } + sb.append(EnumChatFormatting.WHITE); + + hexField.setPrependText(sb.toString()); + hexField.render(activeColourEditor.x+5+8, activeColourEditor.y+5+64+5); + } + if(textToDisplay.get() != null) { - Utils.drawHoveringText(textToDisplay.get(), mouseX, mouseY, width, height, 200, fr); + Utils.drawHoveringText(textToDisplay.get(), mouseXN, mouseYN, widthN, heightN, 200, fr); } + + Utils.pushGuiScale(-1); } private void onTextfieldChange(GuiElementTextField tf, Options.Option<?> option) { @@ -175,6 +424,7 @@ public class SettingsInfoPane extends InfoPane { tf.setCustomBorderColour(-1); option.setValue(tf.getText()); overlay.redrawItems(); + BetterContainers.reset(); } catch(Exception e) { tf.setCustomBorderColour(Color.RED.getRGB()); } @@ -185,28 +435,146 @@ public class SettingsInfoPane extends InfoPane { for(GuiElementTextField tf : textConfigMap.values()) { tf.otherComponentClick(); } + activeColourEditor = null; + hexField.otherComponentClick(); + searchBar.otherComponentClick(); } public void mouseInput(int width, int height, int mouseX, int mouseY, boolean mouseDown) { + Utils.pushGuiScale(2); + + int widthN = Utils.peekGuiScale().getScaledWidth(); + int heightN = Utils.peekGuiScale().getScaledHeight(); + int mouseXN = Mouse.getX() * widthN / Minecraft.getMinecraft().displayWidth; + int mouseYN = heightN - Mouse.getY() * heightN / Minecraft.getMinecraft().displayHeight - 1; + + int paneWidth = (int)(widthN/3*overlay.getWidthMult()); + int rightSide = (int)(widthN*overlay.getInfoPaneOffsetFactor()); + int leftSide = rightSide - paneWidth; + + int area = rightSide-leftSide-overlay.getBoxPadding()*2; + int categoryArea = (area-3*4)/5; + int ySize = overlay.getSearchBarYSize(); + int yStartCat = overlay.getBoxPadding()+overlay.getSearchBarYSize()+3; + for(int i=0; i<5; i++) { + if(mouseDown && mouseXN > leftSide + overlay.getBoxPadding() + i * (categoryArea + 3) && + mouseXN < leftSide + overlay.getBoxPadding() + i * (categoryArea + 3) + categoryArea && + mouseYN > yStartCat && mouseYN < yStartCat + ySize) { + currentCategory = i; + searchBar.otherComponentClick(); + Utils.pushGuiScale(-1); + return; + } + } + + if(mouseDown) { + if(mouseXN > leftSide+overlay.getBoxPadding() && mouseXN < leftSide+overlay.getBoxPadding()+area-3) { + if(mouseYN > overlay.getBoxPadding()+overlay.getSearchBarYSize()*2+7 && + mouseYN < overlay.getBoxPadding()+overlay.getSearchBarYSize()*2+7+ySize) { + searchBar.mouseClicked(mouseXN, mouseYN, Mouse.getEventButton()); + Utils.pushGuiScale(-1); + return; + } + } + searchBar.otherComponentClick(); + } + + if(activeColourEditor != null && (Mouse.isButtonDown(0) || Mouse.isButtonDown(1))) { + if(mouseXN >= activeColourEditor.x && mouseXN <= activeColourEditor.x+119) { + if(mouseYN >= activeColourEditor.y && mouseYN <= activeColourEditor.y+89) { + if(Mouse.getEventButtonState()) { + if(mouseXN > activeColourEditor.x+5+8 && mouseXN < activeColourEditor.x+5+8+48) { + if(mouseYN > activeColourEditor.y+5+64+5 && mouseYN < activeColourEditor.y+5+64+5+10) { + hexField.mouseClicked(mouseXN, mouseYN, Mouse.getEventButton()); + Utils.pushGuiScale(-1); + return; + } + } + } + hexField.otherComponentClick(); + + int currentColour = SpecialColour.specialToSimpleRGB(activeColourEditor.special); + Color c = new Color(currentColour, true); + float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null); + + int xWheel = mouseXN - activeColourEditor.x - 5; + int yWheel = mouseYN - activeColourEditor.y - 5; + + if(xWheel > 0 && xWheel < 64) { + if(yWheel > 0 && yWheel < 64) { + float radius = (float) Math.sqrt(((xWheel-32)*(xWheel-32)+(yWheel-32)*(yWheel-32))/1024f); + float angle = (float) Math.toDegrees(Math.atan((32-xWheel)/(yWheel-32+1E-5))+Math.PI/2); + if(yWheel < 32) angle += 180; + + int rgb = Color.getHSBColor(angle/360f, (float)Math.pow(Math.min(1, radius), 1.5f), hsv[2]).getRGB(); + activeColourEditor.special = SpecialColour.special(SpecialColour.getSpeed(activeColourEditor.special), c.getAlpha(), rgb); + activeColourEditor.option.value = (String) activeColourEditor.special; + } + } + + int xValue = mouseXN - (activeColourEditor.x+5+64+5); + int y = mouseYN - activeColourEditor.y - 5; + + if(y > -5 && y <= 69) { + y = Math.max(0, Math.min(64, y)); + if(xValue > 0 && xValue < 10) { + int rgb = Color.getHSBColor(hsv[0], hsv[1], 1-y/64f).getRGB(); + activeColourEditor.special = SpecialColour.special(SpecialColour.getSpeed(activeColourEditor.special), c.getAlpha(), rgb); + activeColourEditor.option.value = activeColourEditor.special; + } + + int xOpacity = mouseXN - (activeColourEditor.x+5+64+5+10+5); + + if(xOpacity > 0 && xOpacity < 10) { + activeColourEditor.special = SpecialColour.special(SpecialColour.getSpeed(activeColourEditor.special), + 255-(int)(y/64f*255), currentColour); + activeColourEditor.option.value = activeColourEditor.special; + } + } + + int chromaSpeed = SpecialColour.getSpeed(activeColourEditor.special); + + int xChroma = mouseXN - (activeColourEditor.x+5+64+5+10+5+10+5); + if(xChroma > 0 && xChroma < 10) { + if(chromaSpeed > 0) { + if(y > -5 && y <= 69) { + y = Math.max(0, Math.min(64, y)); + activeColourEditor.special = SpecialColour.special(255-Math.round(y/64f*255), c.getAlpha(), currentColour); + activeColourEditor.option.value = activeColourEditor.special; + } + } else if(mouseYN > activeColourEditor.y+5+27 && mouseYN < activeColourEditor.y+5+37) { + activeColourEditor.special = SpecialColour.special(200, c.getAlpha(), currentColour); + activeColourEditor.option.value = activeColourEditor.special; + } + } + + Utils.pushGuiScale(-1); + return; + } + } + if(Mouse.getEventButtonState()) activeColourEditor = null; + } iterateSettingTile(new SettingsTileConsumer() { @Override public void consume(int x, int y, int tileWidth, int tileHeight, Options.Option<?> option, Options.Button button) { float mult = tileWidth/90f; if(option == null) { if(Mouse.getEventButtonState()) { - if(mouseX > x+tileWidth/2-(int)(32*mult) && mouseX < x+tileWidth/2-(int)(32*mult)+(int)(48*mult)) { - if(mouseY > y+tileHeight-(int)(20*mult) && mouseY < y+tileHeight-(int)(20*mult)+(int)(16*mult)) { + if(mouseXN > x+tileWidth/2-(int)(32*mult) && mouseXN < x+tileWidth/2-(int)(32*mult)+(int)(48*mult)) { + if(mouseYN > y+tileHeight-(int)(20*mult) && mouseYN < y+tileHeight-(int)(20*mult)+(int)(16*mult)) { button.click.run(); + Utils.pushGuiScale(-1); return; } } } } else if(option.value instanceof Boolean) { if(Mouse.getEventButtonState()) { - if(mouseX > x+tileWidth/2-(int)(32*mult) && mouseX < x+tileWidth/2-(int)(32*mult)+(int)(48*mult)) { - if(mouseY > y+tileHeight-(int)(20*mult) && mouseY < y+tileHeight-(int)(20*mult)+(int)(16*mult)) { + if(mouseXN > x+tileWidth/2-(int)(32*mult) && mouseXN < x+tileWidth/2-(int)(32*mult)+(int)(48*mult)) { + if(mouseYN > y+tileHeight-(int)(20*mult) && mouseYN < y+tileHeight-(int)(20*mult)+(int)(16*mult)) { ((Options.Option<Boolean>)option).value = !((Boolean)option.value); overlay.redrawItems(); + Utils.pushGuiScale(-1); return; } } @@ -222,17 +590,19 @@ public class SettingsInfoPane extends InfoPane { int tfY = y+tileHeight-(int)(20*mult); int tfWidth = tf.getWidth(); int tfHeight = tf.getHeight(); - if(mouseY > tfY && mouseY < tfY+tfHeight) { - if(mouseX > tfX && mouseX < tfX+tfWidth) { + if(mouseYN > tfY && mouseYN < tfY+tfHeight) { + if(mouseXN > tfX && mouseXN < tfX+tfWidth) { if(Mouse.getEventButtonState()) { - tf.mouseClicked(mouseX, mouseY, Mouse.getEventButton()); + tf.mouseClicked(mouseXN, mouseYN, Mouse.getEventButton()); onTextfieldChange(tf, option); + Utils.pushGuiScale(-1); return; } else if(Mouse.getEventButton() == -1 && mouseDown) { - tf.mouseClickMove(mouseX, mouseY, 0, 0); //last 2 values are unused + tf.mouseClickMove(mouseXN, mouseYN, 0, 0); //last 2 values are unused + Utils.pushGuiScale(-1); return; } - } else if(clickedSlider != option && Mouse.getEventButtonState() && mouseX > x+1*mult && mouseX < x+63*mult) { + } else if(clickedSlider != option && Mouse.getEventButtonState() && mouseXN > x+1*mult && mouseXN < x+63*mult) { clickedSlider = option; clickedSliderX = x; clickedSliderMult = mult; @@ -243,13 +613,13 @@ public class SettingsInfoPane extends InfoPane { float xMin = clickedSliderX+5*clickedSliderMult; float xMax = clickedSliderX+59*clickedSliderMult; - float sliderAmount = (mouseX - xMin)/(xMax - xMin); + float sliderAmount = (mouseXN - xMin)/(xMax - xMin); sliderAmount = Math.max(0, Math.min(1, sliderAmount)); double range = option.maxValue - option.minValue; double value = option.minValue + sliderAmount*range; - if(range >= 10) { + if(range >= 10 || (option.flags & Options.FLAG_INT) != 0) { value = Math.round(value); } else if(range >= 1) { value = Math.round(value*10)/10.0; @@ -269,35 +639,48 @@ public class SettingsInfoPane extends InfoPane { if(Mouse.getEventButtonState()) tf.otherComponentClick(); } else { - if(!textConfigMap.containsKey(option)) { - textConfigMap.put(option, new GuiElementTextField(String.valueOf(option.value), 0)); - } - GuiElementTextField tf = textConfigMap.get(option); - int tfX = x+(int)(10*mult); - int tfY = y+tileHeight-(int)(20*mult); - int tfWidth = tf.getWidth(); - int tfHeight = tf.getHeight(); - if(mouseX > tfX && mouseX < tfX+tfWidth) { - if(mouseY > tfY && mouseY < tfY+tfHeight) { - if(Mouse.getEventButtonState()) { - tf.mouseClicked(mouseX, mouseY, Mouse.getEventButton()); - onTextfieldChange(tf, option); - return; - } else if(Mouse.getEventButton() == -1 && mouseDown) { - tf.mouseClickMove(mouseX, mouseY, 0, 0); //last 2 values are unused - return; + if((option.flags & Options.FLAG_COLOUR) != 0) { + if(Mouse.getEventButtonState()) { + if(mouseXN > x+tileWidth/2-(int)(32*mult) && mouseXN < x+tileWidth/2-(int)(32*mult)+(int)(48*mult)) { + if(mouseYN > y+tileHeight-(int)(20*mult) && mouseYN < y+tileHeight-(int)(20*mult)+(int)(16*mult)) { + int editorX = (int)Math.min(mouseXN, widthN*overlay.getInfoPaneOffsetFactor()-129); + int editorY = Math.min(mouseYN, heightN-99); + showColourEditor(editorX, editorY, (Options.Option<String>) option, (String)option.value); + Utils.pushGuiScale(-1); + return; + } } } + } else { + if(!textConfigMap.containsKey(option)) { + textConfigMap.put(option, new GuiElementTextField(String.valueOf(option.value), 0)); + } + GuiElementTextField tf = textConfigMap.get(option); + int tfX = x+(int)(10*mult); + int tfY = y+tileHeight-(int)(20*mult); + int tfWidth = tf.getWidth(); + int tfHeight = tf.getHeight(); + if(mouseXN > tfX && mouseXN < tfX+tfWidth) { + if(mouseYN > tfY && mouseYN < tfY+tfHeight) { + if(Mouse.getEventButtonState()) { + tf.mouseClicked(mouseXN, mouseYN, Mouse.getEventButton()); + onTextfieldChange(tf, option); + Utils.pushGuiScale(-1); + return; + } else if(Mouse.getEventButton() == -1 && mouseDown) { + tf.mouseClickMove(mouseXN, mouseYN, 0, 0); //last 2 values are unused + Utils.pushGuiScale(-1); + return; + } + } + } + if(Mouse.getEventButtonState()) tf.otherComponentClick(); } - if(Mouse.getEventButtonState()) tf.otherComponentClick(); } } }); if(Mouse.getEventButtonState()) { - int paneWidth = (int)(width/3*overlay.getWidthMult()); - int rightSide = (int)(width*overlay.getInfoPaneOffsetFactor()); - int leftSide = rightSide - paneWidth; rightSide -= overlay.getBoxPadding(); leftSide += overlay.getBoxPadding(); @@ -305,24 +688,31 @@ public class SettingsInfoPane extends InfoPane { float maxStrLen = fr.getStringWidth(EnumChatFormatting.BOLD+"Settings: " + maxPages + "/" + maxPages); float maxButtonXSize = (rightSide-leftSide+2 - maxStrLen*0.5f - 10)/2f; int buttonXSize = (int)Math.min(maxButtonXSize, overlay.getSearchBarYSize()*480/160f); - int ySize = (int)(buttonXSize/480f*160); - int yOffset = (int)((overlay.getSearchBarYSize()-ySize)/2f); + int ySize2 = (int)(buttonXSize/480f*160); + int yOffset = (int)((overlay.getSearchBarYSize()-ySize2)/2f); int top = overlay.getBoxPadding()+yOffset; - if(mouseY >= top && mouseY <= top+ySize) { + if(mouseYN >= top && mouseYN <= top+ySize2) { int leftPrev = leftSide-1; - if(mouseX > leftPrev && mouseX < leftPrev+buttonXSize) { //"Previous" button + if(mouseXN > leftPrev && mouseXN < leftPrev+buttonXSize) { //"Previous" button page--; } int leftNext = rightSide+1-buttonXSize; - if(mouseX > leftNext && mouseX < leftNext+buttonXSize) { //"Next" button + if(mouseXN > leftNext && mouseXN < leftNext+buttonXSize) { //"Next" button page++; } } } + + Utils.pushGuiScale(-1); } public boolean keyboardInput() { + if(searchBar.getFocus()) { + searchBar.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey()); + return true; + } + AtomicBoolean ret = new AtomicBoolean(false); iterateSettingTile(new SettingsTileConsumer() { @Override @@ -330,7 +720,7 @@ public class SettingsInfoPane extends InfoPane { if(option == null) return; if(!textConfigMap.containsKey(option)) { - textConfigMap.put(option, new GuiElementTextField(String.valueOf(option.value), 0)); + return; } GuiElementTextField tf = textConfigMap.get(option); @@ -343,6 +733,24 @@ public class SettingsInfoPane extends InfoPane { } } }); + if(activeColourEditor != null && hexField.getFocus()) { + String old = hexField.getText(); + + hexField.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey()); + + if(hexField.getText().length() > 6) { + hexField.setText(old); + } else { + try { + String text = hexField.getText().toLowerCase(); + + int rgb = Integer.parseInt(text, 16); + int alpha = (SpecialColour.specialToSimpleRGB(activeColourEditor.special) >> 24) & 0xFF; + activeColourEditor.special = SpecialColour.special(SpecialColour.getSpeed(activeColourEditor.special), alpha, rgb); + activeColourEditor.option.value = activeColourEditor.special; + } catch(Exception e) {}; + } + } return ret.get(); } @@ -351,7 +759,7 @@ public class SettingsInfoPane extends InfoPane { } public void iterateSettingTile(SettingsTileConsumer settingsTileConsumer) { - ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + ScaledResolution scaledresolution = Utils.pushGuiScale(2); int width = scaledresolution.getScaledWidth(); int height = scaledresolution.getScaledHeight(); @@ -361,28 +769,64 @@ public class SettingsInfoPane extends InfoPane { int rightSide = (int)(width*overlay.getInfoPaneOffsetFactor()); int leftSide = rightSide - paneWidth; - int boxLeft = leftSide+overlay.getBoxPadding()-5; - int boxRight = rightSide-overlay.getBoxPadding()+5; + int padding = overlay.getBoxPadding(); + + int boxLeft = leftSide+padding-5; + int boxRight = rightSide-padding+5; - int boxBottom = height - overlay.getBoxPadding() + 5; + int boxBottom = height - padding + 5; int boxWidth = boxRight-boxLeft; int tilePadding = 7; int tileWidth = (boxWidth-tilePadding*4)/numHorz; int tileHeight = tileWidth*3/4; + int top = tilePadding+padding+overlay.getSearchBarYSize()*3+3*2; + int bottom = height - padding; + int leftover = (bottom-top)%(tileHeight+tilePadding); + + top += leftover/2; + maxPages=1; int currPage=0; int x=0; - int y=tilePadding+overlay.getBoxPadding()+overlay.getSearchBarYSize(); + int y=top; + int tileCount = 0; + out: for(int i=0; i<manager.config.getOptions().size()+manager.config.getButtons().size(); i++) { - if(i!=0 && i%numHorz==0) { + if(i < manager.config.getButtons().size()) { + if(currentCategory != Options.CAT_ALL || searchBar.getText().trim().length() != 0) { + continue; + } + } else { + Options.Option<?> option = manager.config.getOptions().get(i-manager.config.getButtons().size()); + if(searchBar.getText().trim().length() != 0) { + for(String s : searchBar.getText().split(" ")) { + s = s.replaceAll("[^A-Za-z]", "").toLowerCase(); + boolean contains = false; + for(String tag : option.tags) { + if(tag.contains(s)) { + contains = true; + break; + } + } + if(!contains) { + continue out; + } + } + } + if(currentCategory != Options.CAT_ALL && currentCategory != option.category) { + continue; + } + } + + if(tileCount != 0 && tileCount % numHorz == 0) { x = 0; y += tileHeight+tilePadding; } if(y + tileHeight > boxBottom) { x=0; - y=tilePadding+overlay.getBoxPadding()+overlay.getSearchBarYSize(); + y=top; currPage++; maxPages = currPage+1; } @@ -398,7 +842,10 @@ public class SettingsInfoPane extends InfoPane { } } + tileCount++; x+=tileWidth; } + + Utils.pushGuiScale(-1); } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java index 3c939589..7b279ac9 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java @@ -32,6 +32,8 @@ public class GuiElementTextField extends GuiElement { private int x; private int y; + private String prependText = ""; + private GuiTextField textField = new GuiTextField(0, Minecraft.getMinecraft().fontRendererObj, 0 , 0, 0, 0); @@ -45,6 +47,10 @@ public class GuiElementTextField extends GuiElement { this.options = options; } + public void setMaxStringLength(int len) { + textField.setMaxStringLength(len); + } + public void setCustomBorderColour(int colour) { this.customBorderColour = colour; } @@ -53,8 +59,14 @@ public class GuiElementTextField extends GuiElement { return textField.getText(); } + public void setPrependText(String text) { + this.prependText = text; + } + public void setText(String text) { - textField.setText(text); + if(textField.getText() == null || !textField.getText().equals(text)) { + textField.setText(text); + } } public void setSize(int searchBarXSize, int searchBarYSize) { @@ -113,16 +125,20 @@ public class GuiElementTextField extends GuiElement { int extraSize = (searchBarYSize-8)/2+8; + String renderText = prependText + textField.getText(); + int lineNum = Math.round(((yComp - (searchBarYSize-8)/2))/extraSize); Pattern patternControlCode = Pattern.compile("(?i)\\u00A7([^\\u00B6])(?!\\u00B6)"); - String text = textField.getText(); - String textNoColour = textField.getText(); - while(true) { - Matcher matcher = patternControlCode.matcher(text); - if(!matcher.find() || matcher.groupCount() < 1) break; - String code = matcher.group(1); - text = matcher.replaceFirst("\u00A7"+code+"\u00B6"+code); + String text = renderText; + String textNoColour = renderText; + if((options & COLOUR) != 0) { + while(true) { + Matcher matcher = patternControlCode.matcher(text); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + text = matcher.replaceFirst("\u00A7"+code+"\u00B6"+code); + } } while(true) { Matcher matcher = patternControlCode.matcher(textNoColour); @@ -139,20 +155,31 @@ public class GuiElementTextField extends GuiElement { currentLine++; } } + + String textNC = textNoColour.substring(0, cursorIndex); int colorCodes = StringUtils.countMatches(textNC, "\u00B6"); - String line = text.substring(cursorIndex+colorCodes*2).split("\n")[0]; - String trimmed = Minecraft.getMinecraft().fontRendererObj.trimStringToWidth(line, xComp-5); + String line = text.substring(cursorIndex+(((options & COLOUR) != 0)?colorCodes*2:0)).split("\n")[0]; + int padding = Math.min(5, searchBarXSize-strLenNoColor(line))/2; + String trimmed = Minecraft.getMinecraft().fontRendererObj.trimStringToWidth(line, xComp-padding); int linePos = strLenNoColor(trimmed); if(linePos != strLenNoColor(line)) { char after = line.charAt(linePos); int trimmedWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(trimmed); int charWidth = Minecraft.getMinecraft().fontRendererObj.getCharWidth(after); - if(trimmedWidth + charWidth/2 < xComp-5) { + if(trimmedWidth + charWidth/2 < xComp-padding) { linePos++; } } cursorIndex += linePos; + + int pre = Utils.cleanColour(prependText).length(); + if(cursorIndex < pre) { + cursorIndex = 0; + } else { + cursorIndex -= pre; + } + return cursorIndex; } @@ -300,6 +327,7 @@ public class GuiElementTextField extends GuiElement { if((options & FORCE_CAPS) != 0) typedChar = Character.toUpperCase(typedChar); if((options & NO_SPACE) != 0 && typedChar == ' ') return; + textField.setFocused(true); textField.textboxKeyTyped(typedChar, keyCode); if((options & COLOUR) != 0) { @@ -316,7 +344,6 @@ public class GuiElementTextField extends GuiElement { textField.setCursorPosition(pos+1); } } - } } @@ -333,6 +360,7 @@ public class GuiElementTextField extends GuiElement { private void drawTextbox(int x, int y, int searchBarXSize, int searchBarYSize, int searchBarPadding, GuiTextField textField, boolean focus) { ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + String renderText = prependText + textField.getText(); GlStateManager.disableLighting(); @@ -342,7 +370,7 @@ public class GuiElementTextField extends GuiElement { int paddingUnscaled = searchBarPadding/scaledresolution.getScaleFactor(); if(paddingUnscaled < 1) paddingUnscaled = 1; - int numLines = StringUtils.countMatches(textField.getText(), "\n")+1; + int numLines = StringUtils.countMatches(renderText, "\n")+1; int extraSize = (searchBarYSize-8)/2+8; int bottomTextBox = y + searchBarYSize + extraSize*(numLines-1); @@ -363,13 +391,15 @@ public class GuiElementTextField extends GuiElement { //bar text Pattern patternControlCode = Pattern.compile("(?i)\\u00A7([^\\u00B6\n])(?!\\u00B6)"); - String text = textField.getText(); - String textNoColor = textField.getText(); - while(true) { - Matcher matcher = patternControlCode.matcher(text); - if(!matcher.find() || matcher.groupCount() < 1) break; - String code = matcher.group(1); - text = matcher.replaceFirst("\u00A7"+code+"\u00B6"+code); + String text = renderText; + String textNoColor = renderText; + if((options & COLOUR) != 0) { + while(true) { + Matcher matcher = patternControlCode.matcher(text); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + text = matcher.replaceFirst("\u00A7"+code+"\u00B6"+code); + } } while(true) { Matcher matcher = patternControlCode.matcher(textNoColor); @@ -378,11 +408,18 @@ public class GuiElementTextField extends GuiElement { textNoColor = matcher.replaceFirst("\u00B6"+code); } + int xStartOffset = 5; + float scale = 1; String[] texts = text.split("\n"); for(int yOffI = 0; yOffI < texts.length; yOffI++) { int yOff = yOffI*extraSize; if(isScaling() && Minecraft.getMinecraft().fontRendererObj.getStringWidth(texts[yOffI])>searchBarXSize-10) { + scale = (searchBarXSize-2)/(float)Minecraft.getMinecraft().fontRendererObj.getStringWidth(texts[yOffI]); + if(scale > 1) scale=1; + float newLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth(texts[yOffI])*scale; + xStartOffset = (int)((searchBarXSize-newLen)/2f); + Utils.drawStringCenteredScaledMaxWidth(texts[yOffI], Minecraft.getMinecraft().fontRendererObj, x+searchBarXSize/2f, y+searchBarYSize/2f+yOff, false, searchBarXSize-2, Color.WHITE.getRGB()); @@ -390,13 +427,12 @@ public class GuiElementTextField extends GuiElement { Minecraft.getMinecraft().fontRendererObj.drawString(Utils.trimToWidth(texts[yOffI], searchBarXSize-10), x + 5, y+(searchBarYSize-8)/2+yOff, Color.WHITE.getRGB()); } - } if(focus && System.currentTimeMillis()%1000>500) { - String textNCBeforeCursor = textNoColor.substring(0, textField.getCursorPosition()); + String textNCBeforeCursor = textNoColor.substring(0, textField.getCursorPosition()+prependText.length()); int colorCodes = StringUtils.countMatches(textNCBeforeCursor, "\u00B6"); - String textBeforeCursor = text.substring(0, textField.getCursorPosition()+colorCodes*2); + String textBeforeCursor = text.substring(0, textField.getCursorPosition()+prependText.length()+(((options & COLOUR) != 0) ? colorCodes*2 : 0)); int numLinesBeforeCursor = StringUtils.countMatches(textBeforeCursor, "\n"); int yOff = numLinesBeforeCursor*extraSize; @@ -406,22 +442,20 @@ public class GuiElementTextField extends GuiElement { if(split.length <= numLinesBeforeCursor || split.length == 0) { textBeforeCursorWidth = 0; } else { - textBeforeCursorWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(split[split.length-1]); + textBeforeCursorWidth = (int)(Minecraft.getMinecraft().fontRendererObj.getStringWidth(split[split.length-1])*scale); } - drawRect(x + 5 + textBeforeCursorWidth, + drawRect(x + xStartOffset + textBeforeCursorWidth, y+(searchBarYSize-8)/2-1 + yOff, - x + 5 + textBeforeCursorWidth+1, + x + xStartOffset + textBeforeCursorWidth+1, y+(searchBarYSize-8)/2+9 + yOff, Color.WHITE.getRGB()); } String selectedText = textField.getSelectedText(); if(!selectedText.isEmpty()) { - int leftIndex = textField.getCursorPosition() < textField.getSelectionEnd() ? - textField.getCursorPosition() : textField.getSelectionEnd(); - int rightIndex = textField.getCursorPosition() > textField.getSelectionEnd() ? - textField.getCursorPosition() : textField.getSelectionEnd(); + int leftIndex = Math.min(textField.getCursorPosition()+prependText.length(), textField.getSelectionEnd()+prependText.length()); + int rightIndex = Math.max(textField.getCursorPosition()+prependText.length(), textField.getSelectionEnd()+prependText.length()); - int texX = 0; + float texX = 0; int texY = 0; boolean sectionSignPrev = false; boolean bold = false; @@ -440,9 +474,9 @@ public class GuiElementTextField extends GuiElement { if(c == '\n') { if(i >= leftIndex && i < rightIndex) { - drawRect(x + 5 + texX, + drawRect(x + xStartOffset + (int)texX, y+(searchBarYSize-8)/2-1 + texY, - x + 5 + texX + 3, + x + xStartOffset + (int)texX + 3, y+(searchBarYSize-8)/2+9 + texY, Color.LIGHT_GRAY.getRGB()); } @@ -456,22 +490,22 @@ public class GuiElementTextField extends GuiElement { int len = Minecraft.getMinecraft().fontRendererObj.getStringWidth(String.valueOf(c)); if(bold) len++; if(i >= leftIndex && i < rightIndex) { - drawRect(x + 5 + texX, + drawRect(x + xStartOffset + (int)texX, y+(searchBarYSize-8)/2-1 + texY, - x + 5 + texX + len, + x + xStartOffset + (int)(texX + len*scale), y+(searchBarYSize-8)/2+9 + texY, Color.LIGHT_GRAY.getRGB()); - Minecraft.getMinecraft().fontRendererObj.drawString(String.valueOf(c), - x + 5 + texX, - y+(searchBarYSize-8)/2 + texY, Color.BLACK.getRGB()); + Utils.drawStringScaled(String.valueOf(c), Minecraft.getMinecraft().fontRendererObj, + x + xStartOffset + texX, + y+searchBarYSize/2f-scale*8/2f + texY, false, Color.BLACK.getRGB(), scale); if(bold) { - Minecraft.getMinecraft().fontRendererObj.drawString(String.valueOf(c), - x + 5 + texX +1, - y+(searchBarYSize-8)/2 + texY, Color.BLACK.getRGB()); + Utils.drawStringScaled(String.valueOf(c), Minecraft.getMinecraft().fontRendererObj, + x + xStartOffset + texX + 1, + y+searchBarYSize/2f-scale*8/2f + texY, false, Color.BLACK.getRGB(), scale); } } - texX += len; + texX += len*scale; } } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBAnchorPoint.java b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBAnchorPoint.java index 7f0eb46f..da1b9ddc 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBAnchorPoint.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBAnchorPoint.java @@ -22,27 +22,33 @@ public class MBAnchorPoint implements Serializable { public AnchorPoint anchorPoint; public Vector2f offset; + public boolean inventoryRelative; public MBAnchorPoint(AnchorPoint anchorPoint, Vector2f offset) { + this(anchorPoint, offset, false); + } + + public MBAnchorPoint(AnchorPoint anchorPoint, Vector2f offset, boolean inventoryRelative) { this.anchorPoint = anchorPoint; this.offset = offset; + this.inventoryRelative = inventoryRelative; } public static MBAnchorPoint createFromString(String str) { - if(str == null || str.split(":").length != 3) { + if(str == null || str.split(":").length != 4) { return null; } try { String[] split = str.split(":"); AnchorPoint point = AnchorPoint.valueOf(split[0].toUpperCase()); - Vector2f pos = new Vector2f(Float.valueOf(split[1]), Float.valueOf(split[2])); - return new MBAnchorPoint(point, pos); + Vector2f pos = new Vector2f(Float.parseFloat(split[1]), Float.parseFloat(split[2])); + return new MBAnchorPoint(point, pos, Boolean.parseBoolean(split[3])); } catch(Exception e) { return null; } } @Override public String toString() { - return anchorPoint.toString() + ":" + offset.x + ":" + offset.y; + return anchorPoint.toString() + ":" + offset.x + ":" + offset.y + ":" + inventoryRelative; } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBDeserializer.java b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBDeserializer.java new file mode 100644 index 00000000..8f7d1bc0 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBDeserializer.java @@ -0,0 +1,20 @@ +package io.github.moulberry.notenoughupdates.mbgui; + +import com.google.gson.JsonObject; + +import java.io.IOException; + +public class MBDeserializer { + + public static MBGuiElement deserialize(JsonObject json) { + return null; + } + + public static void serializeAndSave(MBGuiElement element, String filename) throws IOException { + /*JsonObject json = element.serialize(); + + File file = new File(NotEnoughUpdates.INSTANCE.manager.configLocation, filename+".json"); + NotEnoughUpdates.INSTANCE.manager.writeJson(json, file);*/ + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiElement.java b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiElement.java index 56a3f42c..1ff51238 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiElement.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiElement.java @@ -9,4 +9,6 @@ public abstract class MBGuiElement { public abstract void mouseClickOutside(); public abstract void render(float x, float y); + //public abstract JsonObject serialize(); + } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroup.java b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroup.java index 4759d99b..86ff7278 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroup.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroup.java @@ -35,8 +35,10 @@ public abstract class MBGuiGroup extends MBGuiElement { @Override public void mouseClick(float x, float y, int mouseX, int mouseY) { + Map<MBGuiElement, Vector2f> childrenPos = getChildrenPosition(); + for(MBGuiElement child : getChildren()) { - Vector2f childPos = childrenPosition.get(child); + Vector2f childPos = childrenPos.get(child); if(mouseX > x+childPos.x && mouseX < x+childPos.x+child.getWidth()) { if(mouseY > y+childPos.y && mouseY < y+childPos.y+child.getHeight()) { child.mouseClick(x+childPos.x, y+childPos.y, mouseX, mouseY); @@ -54,8 +56,10 @@ public abstract class MBGuiGroup extends MBGuiElement { @Override public void render(float x, float y) { + Map<MBGuiElement, Vector2f> childrenPos = getChildrenPosition(); + for(MBGuiElement child : getChildren()) { - Vector2f childPos = childrenPosition.get(child); + Vector2f childPos = childrenPos.get(child); child.render(x+childPos.x, y+childPos.y); } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupAligned.java b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupAligned.java new file mode 100644 index 00000000..77a28fd5 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupAligned.java @@ -0,0 +1,67 @@ +package io.github.moulberry.notenoughupdates.mbgui; + +import org.lwjgl.util.vector.Vector2f; + +import java.util.Collection; +import java.util.List; + +public abstract class MBGuiGroupAligned extends MBGuiGroup { + + //Serialized + private List<MBGuiElement> children; + private boolean vertical; + + public MBGuiGroupAligned(List<MBGuiElement> children, boolean vertical) { + this.children = children; + this.vertical = vertical; + recalculate(); + } + + public abstract int getPadding(); + + public Collection<MBGuiElement> getChildren() { + return children; + } + + public void recalculate() { + for(MBGuiElement child : children) { + child.recalculate(); + } + + if(vertical) { + height = 0; + for(int i=0; i<children.size(); i++) { + MBGuiElement child = children.get(i); + childrenPosition.put(child, new Vector2f(0, height)); + height += child.getHeight(); + if(i != children.size()-1) height += getPadding(); + } + + width = 0; + for(MBGuiElement child : children) { + int childWidth = child.getWidth(); + if(childWidth > width) { + width = childWidth; + } + } + } else { + width = 0; + for(int i=0; i<children.size(); i++) { + MBGuiElement child = children.get(i); + childrenPosition.put(child, new Vector2f(width, 0)); + width += child.getWidth(); + if(i != children.size()-1) width += getPadding(); + } + + height = 0; + for(MBGuiElement child : children) { + int childHeight = child.getHeight(); + if(childHeight > height) { + height = childHeight; + } + } + } + + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupFloating.java b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupFloating.java index 91cca2d7..293fc241 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupFloating.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupFloating.java @@ -1,11 +1,23 @@ package io.github.moulberry.notenoughupdates.mbgui; +import io.github.moulberry.notenoughupdates.GuiItemRecipe; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.auction.CustomAHGui; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.gui.inventory.GuiContainer; import org.lwjgl.util.vector.Vector2f; import java.util.*; public class MBGuiGroupFloating extends MBGuiGroup { + private GuiScreen lastScreen = null; + private HashMap<MBGuiElement, Vector2f> childrenPositionOffset = new HashMap<>(); + + //Serialized private LinkedHashMap<MBGuiElement, MBAnchorPoint> children; public MBGuiGroupFloating(int width, int height, LinkedHashMap<MBGuiElement, MBAnchorPoint> children) { @@ -20,7 +32,84 @@ public class MBGuiGroupFloating extends MBGuiGroup { } @Override + public Map<MBGuiElement, Vector2f> getChildrenPosition() { + GuiScreen currentScreen = Minecraft.getMinecraft().currentScreen; + + if(currentScreen instanceof GuiContainer || currentScreen instanceof GuiItemRecipe + || currentScreen instanceof CustomAHGui || NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.isRenderOverAuctionView()) { + + if(lastScreen != currentScreen) { + lastScreen = currentScreen; + + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + int screenWidth = scaledResolution.getScaledWidth(); + int screenHeight = scaledResolution.getScaledHeight(); + + int xSize = -1; + int ySize = -1; + int guiLeft = -1; + int guiTop = -1; + + if(currentScreen instanceof GuiContainer) { + GuiContainer currentContainer = (GuiContainer) currentScreen; + + try { + xSize = (int) Utils.getField(GuiContainer.class, currentContainer, "xSize", "field_146999_f"); + ySize = (int) Utils.getField(GuiContainer.class, currentContainer, "ySize", "field_147000_g"); + guiLeft = (int) Utils.getField(GuiContainer.class, currentContainer, "guiLeft", "field_147003_i"); + guiTop = (int) Utils.getField(GuiContainer.class, currentContainer, "guiTop", "field_147009_r"); + } catch(Exception ignored) { + } + } else if(currentScreen instanceof GuiItemRecipe) { + xSize = ((GuiItemRecipe)currentScreen).xSize; + ySize = ((GuiItemRecipe)currentScreen).ySize; + guiLeft = ((GuiItemRecipe)currentScreen).guiLeft; + guiTop = ((GuiItemRecipe)currentScreen).guiTop; + } else if(currentScreen instanceof CustomAHGui || + NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.isRenderOverAuctionView()) { + xSize = NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.getXSize(); + ySize = NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.getYSize(); + guiLeft = NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.guiLeft; + guiTop = NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.guiTop; + } + + if(xSize <= 0 && ySize <= 0 && guiLeft <= 0 && guiTop <= 0) { + lastScreen = null; + return Collections.unmodifiableMap(childrenPosition); + } + + for(Map.Entry<MBGuiElement, MBAnchorPoint> entry : children.entrySet()) { + MBGuiElement child = entry.getKey(); + MBAnchorPoint anchorPoint = entry.getValue(); + + Vector2f childPos; + if(childrenPosition.containsKey(child)) { + childPos = new Vector2f(childrenPosition.get(child)); + } else { + childPos = new Vector2f(); + } + + if(anchorPoint.inventoryRelative) { + int defGuiLeft = (screenWidth - xSize) / 2; + int defGuiTop = (screenHeight - ySize) / 2; + + childPos.x += guiLeft-defGuiLeft + (0.5f-anchorPoint.anchorPoint.x)*xSize; + childPos.y += guiTop-defGuiTop + (0.5f-anchorPoint.anchorPoint.y)*ySize; + } + + childrenPositionOffset.put(child, childPos); + } + } + return Collections.unmodifiableMap(childrenPositionOffset); + } else { + return Collections.unmodifiableMap(childrenPosition); + } + } + + @Override public void recalculate() { + lastScreen = null; + for(MBGuiElement child : children.keySet()) { child.recalculate(); } @@ -30,6 +119,12 @@ public class MBGuiGroupFloating extends MBGuiGroup { MBAnchorPoint anchorPoint = entry.getValue(); float x = anchorPoint.anchorPoint.x * width - anchorPoint.anchorPoint.x * child.getWidth() + anchorPoint.offset.x; float y = anchorPoint.anchorPoint.y * height - anchorPoint.anchorPoint.y * child.getHeight() + anchorPoint.offset.y; + + if(anchorPoint.inventoryRelative) { + x = width*0.5f + anchorPoint.offset.x; + y = height*0.5f + anchorPoint.offset.y; + } + childrenPosition.put(child, new Vector2f(x, y)); } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupHorz.java b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupHorz.java deleted file mode 100644 index cf477eac..00000000 --- a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupHorz.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.github.moulberry.notenoughupdates.mbgui; - -import org.lwjgl.util.vector.Vector2f; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; - -public abstract class MBGuiGroupHorz extends MBGuiGroup { - - private List<MBGuiElement> children; - - public MBGuiGroupHorz(List<MBGuiElement> children) { - this.children = children; - recalculate(); - } - - public abstract int getPadding(); - - public Collection<MBGuiElement> getChildren() { - return children; - } - - public void recalculate() { - for(MBGuiElement child : children) { - child.recalculate(); - } - - width = 0; - for(int i=0; i<children.size(); i++) { - MBGuiElement child = children.get(i); - childrenPosition.put(child, new Vector2f(width, 0)); - width += child.getWidth(); - if(i != children.size()-1) width += getPadding(); - } - - height = 0; - for(MBGuiElement child : children) { - int childHeight = child.getHeight(); - if(childHeight > height) { - height = childHeight; - } - } - } - -} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityPlayer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityPlayer.java new file mode 100644 index 00000000..8757e369 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityPlayer.java @@ -0,0 +1,25 @@ +package io.github.moulberry.notenoughupdates.mixins; + +import io.github.moulberry.notenoughupdates.cosmetics.CapeManager; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EnumPlayerModelParts; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin({EntityPlayer.class}) +public abstract class MixinEntityPlayer { + + @Inject(method="isWearing", at=@At("HEAD"), cancellable = true) + public void isWearing(EnumPlayerModelParts part, CallbackInfoReturnable<Boolean> cir) { + if(part == EnumPlayerModelParts.CAPE) { + EntityPlayer $this = (EntityPlayer)(Object)this; + String uuid = $this.getUniqueID().toString().replace("-", ""); + String cape = CapeManager.getInstance().getCape(uuid); + if(cape != null && !cape.equalsIgnoreCase("null")) { + cir.setReturnValue(false); + } + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityRenderer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityRenderer.java new file mode 100644 index 00000000..1f77b9cc --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityRenderer.java @@ -0,0 +1,72 @@ +package io.github.moulberry.notenoughupdates.mixins; + +import io.github.moulberry.notenoughupdates.CustomItemEffects; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import net.minecraft.client.renderer.EntityRenderer; +import org.lwjgl.util.vector.Vector3f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityRenderer.class) +public class MixinEntityRenderer { + + //orientCamera + @ModifyVariable(method="orientCamera", at=@At(value="STORE"), ordinal = 0) + public double orientCamera_d0(double d0) { + Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition(); + if(currentPosition != null) { + return currentPosition.x; + } + return d0; + } + + @ModifyVariable(method="orientCamera", at=@At(value="STORE"), ordinal = 1) + public double orientCamera_d1(double d1) { + Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition(); + if(currentPosition != null) { + return currentPosition.y; + } + return d1; + } + + @ModifyVariable(method="orientCamera", at=@At(value="STORE"), ordinal = 2) + public double orientCamera_d2(double d2) { + Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition(); + if(currentPosition != null) { + return currentPosition.z; + } + return d2; + } + + //renderWorldPass + @ModifyVariable(method="renderWorldPass", at=@At(value="STORE"), ordinal = 0) + public double renderWorldPass_d0(double d0) { + Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition(); + if(currentPosition != null) { + return currentPosition.x; + } + return d0; + } + + @ModifyVariable(method="renderWorldPass", at=@At(value="STORE"), ordinal = 1) + public double renderWorldPass_d1(double d1) { + Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition(); + if(currentPosition != null) { + return currentPosition.y; + } + return d1; + } + + @ModifyVariable(method="renderWorldPass", at=@At(value="STORE"), ordinal = 2) + public double renderWorldPass_d2(double d2) { + Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition(); + if(currentPosition != null) { + return currentPosition.z; + } + return d2; + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiChest.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiChest.java new file mode 100644 index 00000000..bd74b44c --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiChest.java @@ -0,0 +1,52 @@ +package io.github.moulberry.notenoughupdates.mixins; + +import io.github.moulberry.notenoughupdates.BetterContainers; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.StreamerMode; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiIngame; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.scoreboard.ScorePlayerTeam; +import net.minecraft.scoreboard.Team; +import net.minecraft.util.ResourceLocation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin({GuiChest.class}) +public class MixinGuiChest { + + private static final String TARGET = "Lnet/minecraft/client/renderer/texture/TextureManager;" + + "bindTexture(Lnet/minecraft/util/ResourceLocation;)V"; + @Redirect(method="drawGuiContainerBackgroundLayer", at=@At(value="INVOKE", target=TARGET)) + public void drawGuiContainerBackgroundLayer_bindTexture(TextureManager textureManager, ResourceLocation location) { + BetterContainers.bindHook(textureManager, location); + } + + private static final String TARGET_DRAWSTRING = "Lnet/minecraft/client/gui/FontRenderer;drawString(Ljava/lang/String;III)I"; + @Redirect(method="drawGuiContainerForegroundLayer", at=@At(value="INVOKE", target = TARGET_DRAWSTRING)) + public int drawGuiContainerForegroundLayer_drawString(FontRenderer fontRenderer, String text, int x, int y, int color) { + return fontRenderer.drawString(text, x, y, BetterContainers.isOverriding() ? BetterContainers.getTextColour() : color); + } + + private static final String TARGET_SBADRAWSTRING = "Lcodes/biscuit/skyblockaddons/asm/hooks/GuiChestHook;" + + "drawString(Lnet/minecraft/client/gui/FontRenderer;Ljava/lang/String;III)I"; + @Redirect(method="drawGuiContainerForegroundLayer", at=@At(value="INVOKE", target = TARGET_SBADRAWSTRING, remap = false)) + public int drawGuiContainerForegroundLayer_SBA_drawString(FontRenderer fontRenderer, String text, int x, int y, int color) { + try { + return (int)Class.forName("codes.biscuit.skyblockaddons.asm.hooks.GuiChestHook") + .getDeclaredMethod("drawString", FontRenderer.class, String.class, int.class, int.class, int.class) + .invoke(null, fontRenderer, text, x, y, BetterContainers.isOverriding() ? BetterContainers.getTextColour() : color); + } catch(Exception e) {} + return fontRenderer.drawString(text, x, y, BetterContainers.isOverriding() ? BetterContainers.getTextColour() : color); + } + + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java new file mode 100644 index 00000000..2290e4a7 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java @@ -0,0 +1,118 @@ +package io.github.moulberry.notenoughupdates.mixins; + +import io.github.moulberry.notenoughupdates.BetterContainers; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GuiContainer.class) +public abstract class MixinGuiContainer { + + @Inject(method="drawSlot", at=@At("HEAD"), cancellable = true) + public void drawSlot(Slot slot, CallbackInfo ci) { + if(slot == null) return; + + GuiContainer $this = (GuiContainer)(Object)this; + ItemStack stack = slot.getStack(); + + if(stack == null && System.currentTimeMillis() - BetterContainers.lastRenderMillis < 300 && $this instanceof GuiChest) { + Container container = ((GuiChest)$this).inventorySlots; + if(container instanceof ContainerChest) { + IInventory lower = ((ContainerChest)container).getLowerChestInventory(); + int size = lower.getSizeInventory(); + if(slot.slotNumber < size) { + boolean found = false; + for(int index=0; index<size; index++) { + if(lower.getStackInSlot(index) != null) { + found = true; + break; + } + } + if(!found) { + stack = BetterContainers.itemCache.get(slot.slotNumber); + } + } + + } + } + + if(BetterContainers.isOverriding() && !BetterContainers.shouldRenderStack(stack)) { + ci.cancel(); + } + } + + private static final String TARGET_GETSTACK = "Lnet/minecraft/inventory/Slot;getStack()Lnet/minecraft/item/ItemStack;"; + @Redirect(method="drawSlot", at=@At(value="INVOKE", target=TARGET_GETSTACK)) + public ItemStack drawSlot_getStack(Slot slot) { + GuiContainer $this = (GuiContainer)(Object)this; + ItemStack stack = slot.getStack(); + + if($this instanceof GuiChest) { + Container container = ((GuiChest)$this).inventorySlots; + if(container instanceof ContainerChest) { + IInventory lower = ((ContainerChest)container).getLowerChestInventory(); + int size = lower.getSizeInventory(); + if(slot.slotNumber >= size) { + return stack; + } + if(System.currentTimeMillis() - BetterContainers.lastRenderMillis < 300 && stack == null) { + for(int index=0; index<size; index++) { + if(lower.getStackInSlot(index) != null) { + BetterContainers.itemCache.put(slot.slotNumber, null); + return null; + } + } + return BetterContainers.itemCache.get(slot.slotNumber); + } else { + BetterContainers.itemCache.put(slot.slotNumber, stack); + } + } + } + return stack; + } + + private static final String TARGET_CANBEHOVERED = "Lnet/minecraft/inventory/Slot;canBeHovered()Z"; + @Redirect(method="drawScreen", at=@At(value="INVOKE", target=TARGET_CANBEHOVERED)) + public boolean drawScreen_canBeHovered(Slot slot) { + if(NotEnoughUpdates.INSTANCE.manager.config.hideEmptyPanes.value && + BetterContainers.isOverriding() && BetterContainers.isBlankStack(slot.getStack())) { + return false; + } + return slot.canBeHovered(); + } + + @Inject(method="handleMouseClick", at=@At(value="HEAD"), cancellable = true) + public void handleMouseClick(Slot slotIn, int slotId, int clickedButton, int clickType, CallbackInfo ci) { + if(slotIn != null && BetterContainers.isOverriding() && (BetterContainers.isBlankStack(slotIn.getStack()) || + BetterContainers.isButtonStack(slotIn.getStack()))) { + System.out.println("handling click"); + BetterContainers.clickSlot(slotIn.getSlotIndex()); + Utils.playPressSound(); + + if(BetterContainers.isBlankStack(slotIn.getStack())) { + System.out.println("cancelling click"); + GuiContainer $this = (GuiContainer)(Object)this; + $this.mc.playerController.windowClick($this.inventorySlots.windowId, slotId, 2, clickType, $this.mc.thePlayer); + ci.cancel(); + } + } + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryEffectRenderer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryEffectRenderer.java index 51c85b19..00fdc873 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryEffectRenderer.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryEffectRenderer.java @@ -4,6 +4,7 @@ import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import net.minecraft.client.renderer.InventoryEffectRenderer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyVariable; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemStack.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemStack.java index 123c8cb9..34f1ea62 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemStack.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemStack.java @@ -1,8 +1,12 @@ package io.github.moulberry.notenoughupdates.mixins; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -17,4 +21,37 @@ public class MixinItemStack { } } + @Shadow + private NBTTagCompound stackTagCompound; + + @Inject(method="getDisplayName",at=@At("HEAD"), cancellable=true) + public void getDisplayName(CallbackInfoReturnable<String> returnable) { + try { + String customName = NotEnoughUpdates.INSTANCE.manager.itemRenameJson + .get(stackTagCompound.getCompoundTag("ExtraAttributes").getString("uuid")).getAsString(); + if(customName != null && !customName.equals("")) { + String prefix = EnumChatFormatting.RESET.toString(); + if (stackTagCompound != null && stackTagCompound.hasKey("display", 10)) { + NBTTagCompound nbttagcompound = stackTagCompound.getCompoundTag("display"); + + if (nbttagcompound.hasKey("Name", 8)) { + String name = nbttagcompound.getString("Name"); + char[] chars = name.toCharArray(); + + int i; + for(i=0; i<chars.length; i+=2) { + if(chars[i] != '\u00a7'){ + break; + } + } + + prefix = name.substring(0, i); + } + } + returnable.setReturnValue(prefix+customName); + } + } catch(Exception e) { } + } + + } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java new file mode 100644 index 00000000..0bb84f44 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java @@ -0,0 +1,29 @@ +package io.github.moulberry.notenoughupdates.mixins; + +import io.github.moulberry.notenoughupdates.CustomItemEffects; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.StreamerMode; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.scoreboard.ScorePlayerTeam; +import net.minecraft.scoreboard.Team; +import org.lwjgl.util.vector.Vector3f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(NetHandlerPlayClient.class) +public class MixinNetHandlerPlayClient { + + private static final String TARGET = "Lnet/minecraft/entity/player/EntityPlayer;" + + "setPositionAndRotation(DDDFF)V"; + @Redirect(method="handlePlayerPosLook", at=@At(value="INVOKE", target=TARGET)) + public void handlePlayerPosLook_setPositionAndRotation(EntityPlayer player, double x, double y, double z, float yaw, float pitch) { + if(CustomItemEffects.INSTANCE.aoteTeleportationCurr != null) { + CustomItemEffects.INSTANCE.aoteTeleportationMillis += + Math.max(0, Math.min(300, NotEnoughUpdates.INSTANCE.manager.config.smoothAoteMillis.value)); + } + player.setPositionAndRotation(x, y, z, yaw, pitch); + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRender.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRender.java new file mode 100644 index 00000000..2c92a0b1 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRender.java @@ -0,0 +1,31 @@ +package io.github.moulberry.notenoughupdates.mixins; + +import io.github.moulberry.notenoughupdates.dungeons.DungeonBlocks; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.SpecialColour; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.entity.Entity; +import net.minecraft.entity.passive.EntityBat; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(Render.class) +public class MixinRender { + + @Inject(method="bindEntityTexture", at=@At("HEAD"), cancellable = true) + public void bindEntityTexture(Entity entity, CallbackInfoReturnable<Boolean> cir) { + if(entity instanceof EntityBat && DungeonBlocks.isOverriding()) { + if(DungeonBlocks.bindModifiedTexture(new ResourceLocation("textures/entity/bat.png"), + SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.manager.config.dungChestColour.value))) { + cir.setReturnValue(true); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST_MIPMAP_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + } + } + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderFish.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderFish.java new file mode 100644 index 00000000..fc536267 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderFish.java @@ -0,0 +1,139 @@ +package io.github.moulberry.notenoughupdates.mixins; + +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.SpecialColour; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderFish; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.entity.projectile.EntityFishHook; +import net.minecraft.init.Items; +import net.minecraft.util.MathHelper; +import net.minecraft.util.Vec3; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.awt.*; + +@Mixin(RenderFish.class) +public abstract class MixinRenderFish extends Render<EntityFishHook> { + + protected MixinRenderFish(RenderManager renderManager) { + super(renderManager); + } + + @Inject(method = "doRender(Lnet/minecraft/entity/projectile/EntityFishHook;DDDFF)V", at=@At(value = "HEAD"), cancellable = true) + public void render(EntityFishHook entity, double x, double y, double z, float entityYaw, float partialTicks, CallbackInfo ci) { + if(!NotEnoughUpdates.INSTANCE.manager.config.rodColours.value || entity == null) return; + + String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(entity.angler.getHeldItem()); + if (NotEnoughUpdates.INSTANCE.isOnSkyblock() && internalname != null && entity.angler != null && + entity.angler.getHeldItem().getItem().equals(Items.fishing_rod)) { + if (!internalname.equals("GRAPPLING_HOOK") && !internalname.endsWith("_WHIP")) { + ci.cancel(); + + GlStateManager.pushMatrix(); + GlStateManager.translate((float)x, (float)y, (float)z); + GlStateManager.enableRescaleNormal(); + GlStateManager.scale(0.5F, 0.5F, 0.5F); + this.bindEntityTexture(entity); + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + GlStateManager.rotate(180.0F - this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(-this.renderManager.playerViewX, 1.0F, 0.0F, 0.0F); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_NORMAL); + worldrenderer.pos(-0.5D, -0.5D, 0.0D).tex(0.0625D, 0.1875D).normal(0.0F, 1.0F, 0.0F).endVertex(); + worldrenderer.pos(0.5D, -0.5D, 0.0D).tex(0.125D, 0.1875D).normal(0.0F, 1.0F, 0.0F).endVertex(); + worldrenderer.pos(0.5D, 0.5D, 0.0D).tex(0.125D, 0.125D).normal(0.0F, 1.0F, 0.0F).endVertex(); + worldrenderer.pos(-0.5D, 0.5D, 0.0D).tex(0.0625D, 0.125D).normal(0.0F, 1.0F, 0.0F).endVertex(); + tessellator.draw(); + GlStateManager.disableRescaleNormal(); + GlStateManager.popMatrix(); + + double playerVecX; + double playerVecY; + double playerVecZ; + double startY; + if(this.renderManager.options.thirdPersonView == 0 && entity.angler == Minecraft.getMinecraft().thePlayer) { + float f7 = entity.angler.getSwingProgress(partialTicks); + float sqrtSinSwing = MathHelper.sin(MathHelper.sqrt_float(f7) * (float)Math.PI); + + double decimalFov = (this.renderManager.options.fovSetting / 110.0D); + Vec3 fppOffset = new Vec3((-decimalFov + (decimalFov / 2.5) - (decimalFov / 8)) + 0.025, -0.045D * (this.renderManager.options.fovSetting / 100.0D), 0.4D); + fppOffset = fppOffset.rotatePitch(-mathLerp(partialTicks, entity.angler.prevRotationPitch, entity.angler.rotationPitch) * ((float)Math.PI / 180.0F)); + fppOffset = fppOffset.rotateYaw(-mathLerp(partialTicks, entity.angler.prevRotationYaw, entity.angler.rotationYaw) * ((float)Math.PI / 180.0F)); + fppOffset = fppOffset.rotateYaw(sqrtSinSwing * 0.5F); + fppOffset = fppOffset.rotatePitch(-sqrtSinSwing * 0.7F); + + playerVecX = entity.angler.prevPosX + (entity.angler.posX - entity.angler.prevPosX) * (double)partialTicks + fppOffset.xCoord; + playerVecY = entity.angler.prevPosY + (entity.angler.posY - entity.angler.prevPosY) * (double)partialTicks + fppOffset.yCoord; + playerVecZ = entity.angler.prevPosZ + (entity.angler.posZ - entity.angler.prevPosZ) * (double)partialTicks + fppOffset.zCoord; + startY = entity.angler.getEyeHeight(); + } else { + float angle = (entity.angler.prevRenderYawOffset + (entity.angler.renderYawOffset - entity.angler.prevRenderYawOffset) * partialTicks) * (float)Math.PI / 180.0F; + double d4 = MathHelper.sin(angle); + double d6 = MathHelper.cos(angle); + playerVecX = entity.angler.prevPosX + (entity.angler.posX - entity.angler.prevPosX) * (double)partialTicks - d6 * 0.35D - d4 * 0.8D; + playerVecY = entity.angler.prevPosY + entity.angler.getEyeHeight() + (entity.angler.posY - entity.angler.prevPosY) * (double)partialTicks - 0.45D; + playerVecZ = entity.angler.prevPosZ + (entity.angler.posZ - entity.angler.prevPosZ) * (double)partialTicks - d4 * 0.35D + d6 * 0.8D; + startY = entity.angler.isSneaking() ? -0.1875D : 0.0D; + } + + double d13 = entity.prevPosX + (entity.posX - entity.prevPosX) * (double)partialTicks; + double d5 = entity.prevPosY + (entity.posY - entity.prevPosY) * (double)partialTicks + 0.25D; + double d7 = entity.prevPosZ + (entity.posZ - entity.prevPosZ) * (double)partialTicks; + double d9 = (double)((float)(playerVecX - d13)); + double d11 = (double)((float)(playerVecY - d5)) + startY; + double d12 = (double)((float)(playerVecZ - d7)); + GlStateManager.disableTexture2D(); + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + worldrenderer.begin(3, DefaultVertexFormats.POSITION_COLOR); + + String specialColour; + if (entity.angler.getUniqueID().equals(Minecraft.getMinecraft().thePlayer.getUniqueID())) { + specialColour = NotEnoughUpdates.INSTANCE.manager.config.selfRodLineColour.value; + } else { + specialColour = NotEnoughUpdates.INSTANCE.manager.config.otherRodLineColour.value; + } + int colourI = SpecialColour.specialToChromaRGB(specialColour); + + for (int l = 0; l <= 16; ++l) { + if(SpecialColour.getSpeed(specialColour) > 0) { //has chroma + colourI = SpecialColour.rotateHue(colourI, 10); + } + Color colour = new Color(colourI, true); + + float f10 = (float)l / 16.0F; + worldrenderer.pos(x + d9 * (double)f10, y + d11 * (double)(f10 * f10 + f10) * 0.5D + 0.25D, z + d12 * (double)f10) + .color(colour.getRed(), colour.getGreen(), colour.getBlue(), colour.getAlpha()).endVertex(); + } + + tessellator.draw(); + GlStateManager.disableBlend(); + GlStateManager.enableLighting(); + GlStateManager.enableTexture2D(); + } + } + } + + private static float mathLerp(float var1, float var2, float var3) { + return var2 + var1 * (var3 - var2); + } + + private static double mathLerp(double var1, double var2, double var3) { + return var2 + var1 * (var3 - var2); + } + +}
\ No newline at end of file diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderGlobal.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderGlobal.java new file mode 100644 index 00000000..2bb5503b --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderGlobal.java @@ -0,0 +1,69 @@ +package io.github.moulberry.notenoughupdates.mixins; + +import io.github.moulberry.notenoughupdates.CustomItemEffects; +import net.minecraft.client.renderer.RenderGlobal; +import org.lwjgl.util.vector.Vector3f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(RenderGlobal.class) +public class MixinRenderGlobal { + + //setupTerrain + @ModifyVariable(method="setupTerrain", at=@At(value="STORE"), ordinal = 4) + public double setupTerrain_d0(double d3) { + Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition(); + if(currentPosition != null) { + return currentPosition.x; + } + return d3; + } + + @ModifyVariable(method="setupTerrain", at=@At(value="STORE"), ordinal = 5) + public double setupTerrain_d1(double d4) { + Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition(); + if(currentPosition != null) { + return currentPosition.y; + } + return d4; + } + + @ModifyVariable(method="setupTerrain", at=@At(value="STORE"), ordinal = 6) + public double setupTerrain_d2(double d5) { + Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition(); + if(currentPosition != null) { + return currentPosition.z; + } + return d5; + } + + //renderEntities + @ModifyVariable(method="renderEntities", at=@At(value="STORE"), ordinal = 3) + public double renderEntities_d0(double d3) { + Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition(); + if(currentPosition != null) { + return currentPosition.x; + } + return d3; + } + + @ModifyVariable(method="renderEntities", at=@At(value="STORE"), ordinal = 4) + public double renderEntities_d1(double d4) { + Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition(); + if(currentPosition != null) { + return currentPosition.y; + } + return d4; + } + + @ModifyVariable(method="renderEntities", at=@At(value="STORE"), ordinal = 5) + public double renderEntities_d2(double d5) { + Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition(); + if(currentPosition != null) { + return currentPosition.z; + } + return d5; + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java new file mode 100644 index 00000000..67f0f7dc --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java @@ -0,0 +1,53 @@ +package io.github.moulberry.notenoughupdates.mixins; + +import io.github.moulberry.notenoughupdates.ItemRarityHalo; +import io.github.moulberry.notenoughupdates.NEUResourceManager; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.resources.model.IBakedModel; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.client.shader.Shader; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Matrix4f; +import org.lwjgl.BufferUtils; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; +import org.lwjgl.opengl.GL30; +import org.lwjgl.util.vector.Vector4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import javax.vecmath.Vector3f; +import java.awt.*; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.HashMap; + +@Mixin({RenderItem.class}) +public abstract class MixinRenderItem { + + //Lnet/minecraft/client/renderer/entity/RenderItem;renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/resources/model/IBakedModel;)V + @Inject(method="Lnet/minecraft/client/renderer/entity/RenderItem;renderItemIntoGUI(Lnet/minecraft/item/ItemStack;II)V", + at=@At("HEAD"), cancellable = true) + public void renderItemIntoGUI(ItemStack stack, int x, int y, CallbackInfo ci) { + if(x == 0 && y == 0 || true) return; + ItemRarityHalo.onItemRender(stack, x, y); + + if(Keyboard.isKeyDown(Keyboard.KEY_H)) ci.cancel(); + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderList.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderList.java new file mode 100644 index 00000000..ffaf9ebb --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderList.java @@ -0,0 +1,24 @@ +package io.github.moulberry.notenoughupdates.mixins; + +import io.github.moulberry.notenoughupdates.dungeons.DungeonBlocks; +import net.minecraft.client.renderer.*; +import net.minecraft.util.EnumWorldBlockLayer; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin({RenderList.class}) +public abstract class MixinRenderList { + + @Inject(method="renderChunkLayer", at=@At("HEAD")) + public void renderChunkLayer(EnumWorldBlockLayer layer, CallbackInfo ci) { + if(DungeonBlocks.textureExists()) { + DungeonBlocks.bindTextureIfExists(); + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST_MIPMAP_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTileEntitySpecialRenderer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTileEntitySpecialRenderer.java new file mode 100644 index 00000000..d53f62c9 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTileEntitySpecialRenderer.java @@ -0,0 +1,35 @@ +package io.github.moulberry.notenoughupdates.mixins; + +import io.github.moulberry.notenoughupdates.dungeons.DungeonBlocks; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.SpecialColour; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin({TileEntitySpecialRenderer.class}) +public abstract class MixinTileEntitySpecialRenderer { + + @Inject(method="bindTexture", at=@At("HEAD"), cancellable = true) + public void bindTexture(ResourceLocation location, CallbackInfo info) { + if(DungeonBlocks.isOverriding()) { + if(location.getResourcePath().equals("textures/entity/chest/normal.png") || + location.getResourcePath().equals("textures/entity/chest/normal_double.png") || + location.getResourcePath().equals("textures/entity/chest/trapped.png") || + location.getResourcePath().equals("textures/entity/chest/trapped_double.png")) { + String colour = location.getResourcePath().contains("trapped") ? NotEnoughUpdates.INSTANCE.manager.config.dungTrappedChestColour.value : + NotEnoughUpdates.INSTANCE.manager.config.dungChestColour.value; + if(DungeonBlocks.bindModifiedTexture(location, + SpecialColour.specialToChromaRGB(colour))) { + info.cancel(); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST_MIPMAP_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + } + } + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinVboRenderList.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinVboRenderList.java new file mode 100644 index 00000000..42d81781 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinVboRenderList.java @@ -0,0 +1,24 @@ +package io.github.moulberry.notenoughupdates.mixins; + +import io.github.moulberry.notenoughupdates.dungeons.DungeonBlocks; +import net.minecraft.client.renderer.VboRenderList; +import net.minecraft.util.EnumWorldBlockLayer; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin({VboRenderList.class}) +public abstract class MixinVboRenderList { + + @Inject(method="renderChunkLayer", at=@At("HEAD")) + public void renderChunkLayer(EnumWorldBlockLayer layer, CallbackInfo ci) { + if(DungeonBlocks.textureExists()) { + DungeonBlocks.bindTextureIfExists(); + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST_MIPMAP_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/Options.java b/src/main/java/io/github/moulberry/notenoughupdates/options/Options.java index 1c8a6e07..0aedc306 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/Options.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/Options.java @@ -1,15 +1,12 @@ package io.github.moulberry.notenoughupdates.options; import com.google.gson.*; +import io.github.moulberry.notenoughupdates.dungeons.GuiDungeonMapEditor; +import io.github.moulberry.notenoughupdates.GuiEnchantColour; import io.github.moulberry.notenoughupdates.NEUOverlayPlacements; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; -import io.github.moulberry.notenoughupdates.mbgui.MBAnchorPoint; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; -import net.minecraft.util.Util; -import net.minecraftforge.client.ClientCommandHandler; -import net.minecraftforge.client.ForgeHooksClient; -import org.lwjgl.util.vector.Vector2f; import java.awt.*; import java.io.*; @@ -27,131 +24,330 @@ public class Options { * variables with defaults values/etc. It works. I'm happy. */ + public static final transient int FLAG_COLOUR = 0b1; + public static final transient int FLAG_INT = 0b10; + + public static final int CAT_ALL = 0; + public static final int CAT_MISC = 1; + public static final int CAT_FEATURES = 2; + public static final int CAT_SLIDERS = 3; + public static final int CAT_COLOURS = 4; + public Option<Boolean> enableItemEditing = new Option( false, "Enable Item Editing", true, - "Dev Feature."); + "Dev Feature.", CAT_ALL); public Option<Boolean> onlyShowOnSkyblock = new Option( true, "Only Show On Skyblock", false, - "NEU Overlay only appears when you are playing Skyblock."); + "NEU Overlay only appears when you are playing Skyblock.", CAT_MISC); + public Option<Boolean> showVanillaItems = new Option( + true, + "Show Vanilla Items", + false, + "Shows vanilla items in the itemlist.", CAT_MISC); public Option<Boolean> hidePotionEffect = new Option( true, "Hide Potion Effects", false, - "Potion effects are hidden in the inventory GUI. Contrib: All the gamers that play on GUI AUTO"); + "Potion effects are hidden in the inventory GUI. Contrib: All the gamers that play on GUI AUTO", CAT_MISC); public Option<Boolean> showQuickCommands = new Option( true, "Quick Commands", false, - "Shows QuickCommandsâ„¢ above search bar."); + "Shows QuickCommands\u2122 above search bar.", CAT_FEATURES); public Option<Boolean> showUpdateMsg = new Option( true, "Show Update Notifs", false, - "Shows update messages if NEU is out-of-date."); + "Shows update messages if NEU is out-of-date.", CAT_MISC); public Option<Boolean> tooltipBorderColours = new Option( true, "Coloured Tooltip Borders", false, - "Makes the border of tooltips coloured. (Only NEU Tooltips)"); + "Makes the border of tooltips coloured. (Only NEU Tooltips)", CAT_MISC); + public Option<Boolean> disableAhScroll = new Option( + false, + "No NeuAH Scroll", + false, + "Disables Scrolling in NeuAH", CAT_MISC); public Option<Boolean> advancedPriceInfo = new Option( false, "Adv. Item Price Info", false, - "Shows some extra information about item prices."); + "Shows some extra information about item prices.", CAT_MISC); public Option<Boolean> cacheRenderedItempane = new Option( true, "Cache Itempane", false, - "Caches the drawn itempane, drastically improving performance. Animated textures will not work."); + "Caches the drawn itempane, drastically improving performance. Animated textures will not work.", CAT_MISC); public Option<Boolean> streamerMode = new Option( false, "Streamer Mode", false, - "Hides or randomises some stuff on your screen to prevent sniping."); - public Option<Boolean> hideApiKey = new Option( + "Hides or randomises some stuff on your screen to prevent sniping", CAT_MISC); + public Option<Boolean> disableTreecapOverlay = new Option( false, - "Hide Apikey Setting", + "Disable Treecap Overlay", + false, + "Disables the treecapitator overlay effect", CAT_FEATURES); + public Option<Boolean> disableWandOverlay = new Option( false, - "Hides the Apikey setting (please try not to leak Apikey if you're recording)"); - public Option<Boolean> quickAHUpdate = new Option( + "Disable Builder's Wand Overlay", + false, + "Disables the builder's wand overlay effect", CAT_FEATURES); + public Option<Boolean> wandBlockCount = new Option( + true, + "Builder's Wand Block Count", false, - "NeuAH Quick Update", + "If true, will show how many blocks you have remaining when holding a builder's wand.", CAT_MISC); + public Option<Boolean> hideApiKey = new Option( + false, + "Hide Apikey Setting", false, - "Will instantly update the whole AH when an api update is detected (aka as fast as possible). Warning: Uses lots of data."); + "Hides the Apikey setting (please try not to leak Apikey if you're recording)", CAT_MISC); public Option<Double> bgBlurFactor = new Option( 5.0, "Background Blur", false, - "Changes the strength of pane background blur. 0-50.", 0, 50); + "Changes the strength of pane background blur. 0-50.", 0, 50, CAT_SLIDERS); public Option<String> apiKey = new Option( "", "Api Key", false, - "Type /api new to receive key and put it here."); + "Type /api new to receive key and put it here.", CAT_MISC); public Option<Boolean> autoupdate = new Option( true, "Automatically Update Items", false, - "If true, updated items will automatically download from the remote repository when you start the game. \nHIGHLY RECOMMENDED."); + "If true, updated items will automatically download from the remote repository when you start the game. \nHIGHLY RECOMMENDED.", CAT_MISC); public Option<Boolean> quickcommandMousePress = new Option( false, "QuickCommand on Mouse Press", false, - "If true, quickcommands will trigger on mouse down instead of mouse up."); + "If true, quickcommands will trigger on mouse down instead of mouse up.", CAT_MISC); public Option<Boolean> disableItemTabOpen = new Option( false, "No Tab Open", false, - "If True, moving your mouse to the item tab on the right side won't open the itempane."); + "If True, moving your mouse to the item tab on the right side won't open the itempane.", CAT_MISC); public Option<Boolean> keepopen = new Option( false, "Keep Itempane Open", false, - "If true, the itempane will stay open after the gui is closed."); + "If true, the itempane will stay open after the gui is closed.", CAT_MISC); public Option<Boolean> itemStyle = new Option( true, "Circular Item Style", false, - "Uses the circular item background style instead of the square style. Contrib: Calyps0"); + "Uses the circular item background style instead of the square style. Contrib: Calyps0", CAT_MISC); public Option<Boolean> hideEmptyPanes = new Option( true, "Hide GUI Filler Tooltips", false, - "Hides the tooltip of glass panes in skyblock GUIs. Contrib: ThatGravyBoat"); + "Hides the tooltip of glass panes in skyblock GUIs. Contrib: ThatGravyBoat", CAT_MISC); + public Option<Boolean> dungeonProfitLore = new Option( + false, + "Dungeon Profit in Lore", + false, + "If true, will show the dungeon profit on the tooltip of the 'reward chest' instead of as a GUI.", CAT_MISC); + public Option<Boolean> auctionPriceInfo = new Option( + true, + "Price Info in Auction Lore", + false, + "If true, will show price information about an item inside the auction house item tooltip.", CAT_MISC); + public Option<Boolean> useCustomTrade = new Option( + true, + "Custom Trade", + false, + "If true, uses the custom trade window for skyblock trades.", CAT_FEATURES); + public Option<Boolean> invBazaarPrice = new Option( + false, + "Show Bazaar Price In Inventory", + false, + "If true, shows the bazaar price for the item you hover in your inventory.", CAT_MISC); + public Option<Boolean> invAuctionPrice = new Option( + false, + "Show Auction Price In Inventory", + false, + "If true, shows the auction price for the item you hover in your inventory.", CAT_MISC); + public Option<Boolean> dungeonBlocksEverywhere = new Option( + false, + "Show Dungeon Block Overlay Everywhere", + false, + "If true, will show the overlay for cracked bricks, etc. even when not in dungeons.", CAT_MISC); + public Option<Boolean> disableDungeonBlocks = new Option( + true, + "Disable the dungeon blocks feature", + false, + "If true, the dungeon block overlay will be disabled. WARNING: May cause memory/fps issues on some machines", CAT_FEATURES); + public Option<Boolean> slowDungeonBlocks = new Option( + false, + "Slowly Update Dungeon Block Textures", + false, + "If true, dungeon blocks will only update once every second.\n" + + "Use this option if you are having performance\n" + + "issues relating to the dungeon blocks.", CAT_MISC); + public Option<Boolean> missingEnchantList = new Option( + true, + "Missing Enchant List", + false, + "If true, will show enchants that are missing on an enchanted item when LSHIFT is pressed.", CAT_FEATURES); + public Option<Boolean> neuAuctionHouse = new Option( + false, + "NEU Auction House", + false, + "Enables the auction house which can be found using /neuah.\n" + + "Don't enable this option unless you use /neuah\n" + + "You *may* need to restart after enabling this for the auctions to download properly", CAT_FEATURES); + public Option<Boolean> accessoryBagOverlay = new Option( + true, + "Accessory Bag Overlay", + false, + "If true, will an overlay with useful information in your accessory bag.", CAT_FEATURES); + public Option<Boolean> rodColours = new Option( + true, + "Custom Rod Line Colours", + false, + "If true, will use custom colours for fishing line rods in skyblock.", CAT_FEATURES); + public Option<Double> paneGuiScale = new Option( + 0.0, + "Pane GUI Scale", + false, + "Changes the GUI scale of the item pane. 0 = use game default. 1-4 = scale", FLAG_INT, 0, 4, CAT_SLIDERS); public Option<Double> paneWidthMult = new Option( 1.0, "Pane Width", false, - "Changes how wide the item and info panes are. Value between 0.5-1.5.", 0.5, 1.5); - public Option<Double> bgOpacity = new Option( - 30.0, - "Pane Background Opacity", + "Changes how wide the item and info panes are. Value between 0.5-1.5.", 0.5, 1.5, CAT_SLIDERS); + public Option<Double> smoothAoteMillis = new Option( + 175.0, + "Smooth AOTE Milliseconds", false, - "Changes the background colour opacity of item and info panes. Value between 0-255.", 0, 255); - public Option<Double> fgOpacity = new Option( - 255.0, - "Item Background Opacity", + "How long teleporting with the AOTE takes. 0 = disable.", 0, 300, CAT_SLIDERS); + public Option<Double> itemHighlightOpacity = new Option( + 178.0, + "Item Highlight Opacity", false, - "Changes the opacity of item background. Value between 0-255.", 0, 255); + "Changes the opacity of item highlights. Value between 0-255.", 0, 255, CAT_SLIDERS); public Option<Double> panePadding = new Option( 10.0, "Pane Padding", false, - "Changes the padding of the panes. Value between 0-20.", 0, 20); + "Changes the padding of the panes. Value between 0-20.", 0, 20, CAT_SLIDERS); public Option<Double> ahNotification = new Option( 2.0, "AH Notification (Mins, 0 = off)", false, - "Minutes before AH ends to notify. 0-10.", 0, 10); + "Minutes before AH ends to notify. 0-10.", 0, 10, CAT_SLIDERS); public Option<Double> tooltipBorderOpacity = new Option( 200.0, "Coloured Tooltip Border Opacity", false, - "Coloured tooltips only apply to tooltips in my GUIs. Value between 0-255.", 0, 255); + "Coloured tooltips only apply to tooltips in my GUIs. Value between 0-255.", 0, 255, CAT_SLIDERS); + public Option<Double> dynamicMenuBackgroundStyle = new Option( + 1.0, + "SBMenu Background Style", + false, + "Style of the background used for the skyblock menu.", 0, 10, CAT_FEATURES); + public Option<Double> dynamicMenuButtonStyle = new Option( + 1.0, + "SBMenu Button Style", + false, + "Style of the buttons used for the skyblock menu.", 0, 10, CAT_FEATURES); + public Option<Double> dungeonWinMillis = new Option( + 5000.0, + "Dungeon Victory Screen Millis", + false, + "Changes how long the victory screen at the end of dungeons appears for. 0 = off", FLAG_INT, 0, 15000, CAT_SLIDERS); + + public Option<String> itemBackgroundColour = new Option( + "00:255:100:100:100", + "Item BG Colour", + false, + "Item BG Colour", + FLAG_COLOUR, CAT_COLOURS); + public Option<String> itemFavouriteColour = new Option( + "00:255:200:150:50", + "Item BG Favourite Colour", + false, + "Item BG Favourite Colour", + FLAG_COLOUR, CAT_COLOURS); + public Option<String> paneBackgroundColour = new Option( + "15:6:0:0:255", + "Pane Background Colour", + false, + "Pane Background Colour", + FLAG_COLOUR, CAT_COLOURS); + public Option<String> treecapOverlayColour = new Option( + "00:50:64:224:208", + "Treecapitator Overlay Colour", + false, + "Treecapitator Overlay Colour", + FLAG_COLOUR, CAT_COLOURS); + public Option<String> wandOverlayColour = new Option( + "00:50:64:224:208", + "Builder's Wand Overlay Colour", + false, + "Builder's Wand Overlay Colour", + FLAG_COLOUR, CAT_COLOURS); + + public Option<String> dungCrackedColour = new Option( + "0:252:7:255:217", + "Dungeon Cracked Brick Colour", + false, + "Dungeon Cracked Brick Colour", + FLAG_COLOUR, CAT_COLOURS); + public Option<String> dungDispenserColour = new Option( + "0:255:255:76:0", + "Dungeon Dispenser Colour", + false, + "Dungeon Dispenser Colour", + FLAG_COLOUR, CAT_COLOURS); + public Option<String> dungLeverColour = new Option( + "0:252:24:249:255", + "Dungeon Lever Colour", + false, + "Dungeon Lever Colour", + FLAG_COLOUR, CAT_COLOURS); + public Option<String> dungTripWireColour = new Option( + "0:255:255:0:0", + "Dungeon Trip Wire Colour", + false, + "Dungeon Trip Wire Colour", + FLAG_COLOUR, CAT_COLOURS); + public Option<String> dungChestColour = new Option( + "0:255:0:163:36", + "Dungeon Chest Colour", + false, + "Dungeon Chest Colour", + FLAG_COLOUR, CAT_COLOURS); + public Option<String> dungTrappedChestColour = new Option( + "0:255:0:163:36", + "Dungeon Trapped Chest Colour", + false, + "Dungeon Trapped Chest Colour", + FLAG_COLOUR, CAT_COLOURS); + public Option<String> dungBatColour = new Option( + "0:255:12:255:0", + "Dungeon Bat Colour", + false, + "Dungeon Bat Colour", + FLAG_COLOUR, CAT_COLOURS); + public Option<String> selfRodLineColour = new Option( + "0:255:0:0:0", + "Your Rod Line Colour", + false, + "Changes the colour of your rod's fishing line.\nContrib: ThatGravyBoat", + FLAG_COLOUR, CAT_COLOURS); + public Option<String> otherRodLineColour = new Option( + "0:255:0:0:0", + "Other Rod Line Colour", + false, + "Changes the colour of other players' rod's fishing line.\nContrib: ThatGravyBoat", + FLAG_COLOUR, CAT_COLOURS); /** * OPTIONS THAT DON'T SHOW IN GUI @@ -160,52 +356,165 @@ public class Options { false, "Show Dev Options", true, - "Dev Feature. Please don't use."); + "Dev Feature. Please don't use.", CAT_ALL); + public Option<Boolean> loadedModBefore = new Option( + false, + "loadedModBefore", + true, + "loadedModBefore", CAT_ALL); + public Option<Boolean> customTradePrices = new Option( + true, + "Trade Item Values", + true, + "If true, shows a window with the total item value of either side", CAT_ALL); + public Option<Boolean> customTradePriceStyle = new Option( + true, + "Trade Prices Style", + true, + "Changes the style of the top item prices", CAT_ALL); public Option<String> selectedCape = new Option( "", "Selected Cape", true, - "Selected Cape"); + "Selected Cape", CAT_ALL); public Option<Double> compareMode = new Option( 0.0, "Compare Mode", false, - "Compare Mode"); + "Compare Mode", CAT_ALL); public Option<Double> sortMode = new Option( 0.0, "Sort Mode", false, - "Sort Mode"); + "Sort Mode", CAT_ALL); public Option<ArrayList<Boolean>> compareAscending = new Option( Utils.createList(true, true, true), "Compare Ascending", false, - "Compare Ascending"); + "Compare Ascending", CAT_ALL); public Option<ArrayList<String>> favourites = new Option( new ArrayList<String>(), "Favourites", false, - "Favourites"); + "Favourites", CAT_ALL); public Option<Map<String, ArrayList<String>>> collectionLog = new Option( new HashMap<String, ArrayList<String>>(), "CollectionLog", false, - "CollectionLog"); + "CollectionLog", CAT_ALL); public Option<ArrayList<String>> quickCommands = new Option( createDefaultQuickCommands(), "Quick Commands", false, - "Quick Commands"); + "Quick Commands", CAT_ALL); public Option<String> overlaySearchBar = new Option( "", "OverlaySearchBar", false, - "OverlaySearchBar"); + "OverlaySearchBar", CAT_ALL); public Option<String> overlayQuickCommand = new Option( "", "OverlaySearchBar", false, - "OverlaySearchBar"); + "OverlaySearchBar", CAT_ALL); + public Option<List<String>> enchantColours = new Option( + Utils.createList("[a-zA-Z\\- ]+:\u003e:9:6", + "[a-zA-Z\\- ]+:\u003e:6:c", + "[a-zA-Z\\- ]+:\u003e:5:5", + "Experience:\u003e:3:5", + "Life Steal:\u003e:3:5", + "Scavenger:\u003e:3:5", + "Looting:\u003e:3:5"), + "enchantColours", + false, + "enchantColours", CAT_ALL); + + //Dungeon Map Options + public Option<Double> dmBorderSize = new Option( + 1.0, + "Border Size", + false, + "Changes the size of the map border, without changing the size of the contents\nSmall = 90x\nMedium = 120x\nLarge = 160x", CAT_ALL); + public Option<Double> dmRoomSize = new Option( + 1.0, + "Room Size", + false, + "Changes the size of rooms. Useful for higher dungeons with larger maps\nSmall = 12x\nMedium = 16x\nLarge = 20x\nXLarge = 24x", CAT_ALL); + public Option<Double> dmBorderStyle = new Option( + 0.0, + "Border Style", + false, + "Various custom borders from various talented artists.\nUse 'custom' if your texture pack has a custom border", CAT_ALL); + public Option<Boolean> dmEnable = new Option( + true, + "Show Dungeon Map", + false, + "Show/hide the NEU dungeon map", CAT_ALL); + public Option<Boolean> dmCenterPlayer = new Option( + false, + "Map Center", + false, + "Center on rooms, or center on your player", CAT_ALL); + public Option<Boolean> dmRotatePlayer = new Option( + true, + "Rotate with Player", + false, + "Rotate the map to face the same direction as your player", CAT_ALL); + public Option<Boolean> dmOrientCheck = new Option( + true, + "Orient Checkmarks", + false, + "Checkmarks will always show vertically, regardless of rotation", CAT_ALL); + public Option<Boolean> dmCenterCheck = new Option( + false, + "Center Checkmarks", + false, + "Checkmarks will show closer to the center of rooms", CAT_ALL); + public Option<Double> dmPlayerHeads = new Option( + 0.0, + "Player Icon Style", + false, + "Various player icon styles", CAT_ALL); + public Option<Boolean> dmPlayerInterp = new Option( + true, + "Interpolate Far Players", + false, + "Will make players far away move smoothly", CAT_ALL); + public Option<Double> dmCompat = new Option( + 0.0, + "OpenGL Compatibility", + false, + "Compatiblity options for people with bad computers. ONLY use this if you know what you are doing, otherwise the map will look worse", CAT_ALL); + public Option<String> dmBackgroundColour = new Option( + "00:170:75:75:75", + "Background Colour", + false, + "Colour of the map background. Supports opacity & chroma", FLAG_COLOUR, CAT_ALL); + public Option<String> dmBorderColour = new Option( + "00:0:0:0:0", + "Border Colour", + false, + "Colour of the map border. Supports opacity & chroma. Turn off custom borders to see", FLAG_COLOUR, CAT_ALL); + public Option<Boolean> dmChromaBorder = new Option( + false, + "Chroma Border Mode", + false, + "Applies a hue offset around the map border", CAT_ALL); + public Option<Double> dmBackgroundBlur = new Option( + 3.0, + "Background Blur Factor", + false, + "Changes the blur factor behind the map. Set to 0 to disable blur", CAT_ALL); + public Option<Double> dmCenterX = new Option( + 8.5, + "Center X (%)", + false, + "The horizontal position of the map", CAT_ALL); + public Option<Double> dmCenterY = new Option( + 15.0, + "Center Y (%)", + false, + "The vertical position of the map", CAT_ALL); private ArrayList<String> createDefaultQuickCommands() { ArrayList<String> arr = new ArrayList<>(); @@ -233,14 +542,16 @@ public class Options { } private transient List<Button> buttons = new ArrayList<>(); + { buttons.add(new Button("Open Config Folder", "Opens the config folder. Be careful.", () -> { - if(Desktop.isDesktopSupported()) { + if (Desktop.isDesktopSupported()) { Desktop desktop = Desktop.getDesktop(); - if(NotEnoughUpdates.INSTANCE.manager.configFile.getParentFile().exists()) { + if (NotEnoughUpdates.INSTANCE.manager.configFile.getParentFile().exists()) { try { desktop.open(NotEnoughUpdates.INSTANCE.manager.configFile.getParentFile()); - } catch(IOException ignored) {} + } catch (IOException ignored) { + } } } })); @@ -248,6 +559,15 @@ public class Options { buttons.add(new Button("Edit Gui Positions", "Allows you to change the position of the search bar, etc.", () -> { Minecraft.getMinecraft().displayGuiScreen(new NEUOverlayPlacements()); })); + + buttons.add(new Button("Edit Enchant Colours", "Allows you to change the colour of any enchant at any level.", () -> { + Minecraft.getMinecraft().displayGuiScreen(new GuiEnchantColour()); + })); + + + buttons.add(new Button("Edit Dungeon Map", "Allows you to configure the NEU dungeon map.", () -> { + Minecraft.getMinecraft().displayGuiScreen(new GuiDungeonMapEditor()); + })); } public List<Button> getButtons() { @@ -257,39 +577,77 @@ public class Options { public List<Option> getOptions() { List<Option> options = new ArrayList<>(); + //Pane width near top so less scuffed + tryAddOption(paneWidthMult, options); //Buttons tryAddOption(enableItemEditing, options); tryAddOption(onlyShowOnSkyblock, options); + tryAddOption(showVanillaItems, options); tryAddOption(showQuickCommands, options); tryAddOption(hidePotionEffect, options); tryAddOption(hideEmptyPanes, options); - //tryAddOption(advancedPriceInfo, options); + tryAddOption(advancedPriceInfo, options); tryAddOption(showUpdateMsg, options); tryAddOption(tooltipBorderColours, options); + tryAddOption(disableAhScroll, options); tryAddOption(hideApiKey, options); tryAddOption(streamerMode, options); - tryAddOption(quickAHUpdate, options); + tryAddOption(disableTreecapOverlay, options); + tryAddOption(disableWandOverlay, options); + tryAddOption(wandBlockCount, options); tryAddOption(autoupdate, options); tryAddOption(cacheRenderedItempane, options); tryAddOption(itemStyle, options); tryAddOption(keepopen, options); tryAddOption(disableItemTabOpen, options); + tryAddOption(dungeonProfitLore, options); + tryAddOption(auctionPriceInfo, options); + tryAddOption(useCustomTrade, options); + tryAddOption(customTradePrices, options); + tryAddOption(customTradePriceStyle, options); + tryAddOption(invBazaarPrice, options); + tryAddOption(invAuctionPrice, options); + tryAddOption(dungeonBlocksEverywhere, options); + tryAddOption(disableDungeonBlocks, options); + tryAddOption(slowDungeonBlocks, options); + tryAddOption(missingEnchantList, options); + tryAddOption(accessoryBagOverlay, options); + tryAddOption(rodColours, options); + tryAddOption(neuAuctionHouse, options); //Sliders + tryAddOption(paneGuiScale, options); + tryAddOption(smoothAoteMillis, options); tryAddOption(bgBlurFactor, options); - tryAddOption(paneWidthMult, options); tryAddOption(ahNotification, options); - tryAddOption(bgOpacity, options); - tryAddOption(fgOpacity, options); tryAddOption(panePadding, options); tryAddOption(tooltipBorderOpacity, options); + tryAddOption(dynamicMenuBackgroundStyle, options); + tryAddOption(dynamicMenuButtonStyle, options); + tryAddOption(dungeonWinMillis, options); //Text tryAddOption(apiKey, options); + //Colour + tryAddOption(paneBackgroundColour, options); + tryAddOption(itemBackgroundColour, options); + tryAddOption(itemFavouriteColour, options); + tryAddOption(treecapOverlayColour, options); + tryAddOption(wandOverlayColour, options); + tryAddOption(selfRodLineColour, options); + tryAddOption(otherRodLineColour, options); + + tryAddOption(dungCrackedColour, options); + tryAddOption(dungDispenserColour, options); + tryAddOption(dungLeverColour, options); + tryAddOption(dungTripWireColour, options); + tryAddOption(dungChestColour, options); + tryAddOption(dungTrappedChestColour, options); + tryAddOption(dungBatColour, options); return options; } private void tryAddOption(Option<?> option, List<Option> list) { - if(!option.secret) {// || dev.value) { + if (!option.secret) {// || dev.value) { list.add(option); } } @@ -300,37 +658,64 @@ public class Options { public final transient String displayName; public final transient boolean secret; public final transient String desc; + public final transient int flags; public final transient double minValue; public final transient double maxValue; + public final transient int category; + public final transient ArrayList<String> tags; - public Option(T defaultValue, String displayName, boolean secret, String desc) { - this(defaultValue, displayName, secret, desc, 0, 100); + public Option(T defaultValue, String displayName, boolean secret, String desc, int category) { + this(defaultValue, displayName, secret, desc, 0, 0, 100, category); } - public Option(T defaultValue, String displayName, boolean secret, String desc, double minValue, double maxValue) { + public Option(T defaultValue, String displayName, boolean secret, String desc, int flags, int category) { + this(defaultValue, displayName, secret, desc, flags, 0, 100, category); + } + + public Option(T defaultValue, String displayName, boolean secret, String desc, double minValue, double maxValue, int category) { + this(defaultValue, displayName, secret, desc, 0, minValue, maxValue, category); + } + + public Option(T defaultValue, String displayName, boolean secret, String desc, int flags, double minValue, double maxValue, int category) { this.value = defaultValue; this.defaultValue = defaultValue; this.displayName = displayName; this.secret = secret; this.desc = desc; + this.flags = flags; this.minValue = minValue; this.maxValue = maxValue; + this.category = category; + + this.tags = new ArrayList<>(); + for(String s : displayName.split(" ")) { + s = s.replaceAll("[^A-Za-z]", "").toLowerCase(); + if(s.length() > 0) { + tags.add(s); + } + } + for(String s : desc.split(" ")) { + s = s.replaceAll("[^A-Za-z]", "").toLowerCase(); + if(s.length() >= 4) { + tags.add(s); + } + } } public void setValue(String value) { - if(this.value instanceof Boolean) { + if (this.value instanceof Boolean) { ((Option<Boolean>) this).value = Boolean.valueOf(value); - } else if(this.value instanceof Double) { - ((Option<Double>)this).value = Double.valueOf(value); - } else if(this.value instanceof String) { - ((Option<String>)this).value = value; + } else if (this.value instanceof Double) { + ((Option<Double>) this).value = Double.valueOf(value); + } else if (this.value instanceof String) { + ((Option<String>) this).value = value; } } } public static JsonSerializer<Option<?>> createSerializer() { return (src, typeOfSrc, context) -> { - if(src.secret && src.defaultValue.equals(src.value)) { + if (src.secret && src.defaultValue.equals(src.value)) { return null; } return context.serialize(src.value); @@ -340,35 +725,38 @@ public class Options { public static JsonDeserializer<Option<?>> createDeserializer() { return (json, typeOfT, context) -> { try { - return new Option(context.deserialize(json, Object.class), "unknown", false, "unknown"); - } catch(Exception e) { + return new Option(context.deserialize(json, Object.class), "unknown", false, "unknown", CAT_ALL); + } catch (Exception e) { return null; } }; } public static Options loadFromFile(Gson gson, File file) throws IOException { - InputStream in = new FileInputStream(file); - BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); - - Options oLoad = gson.fromJson(reader, Options.class); - Options oDefault = new Options(); - if(oLoad == null) return oDefault; + try(BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) { + Options oLoad = gson.fromJson(reader, Options.class); + Options oDefault = new Options(); + if (oLoad == null) return oDefault; - for(Field f : Options.class.getDeclaredFields()) { - try { - if(((Option)f.get(oDefault)).value instanceof List) { - //If the default size of the list is greater than the loaded size, use the default value. - if(((List<?>)((Option)f.get(oDefault)).value).size() > ((List<?>)((Option)f.get(oLoad)).value).size()) { - continue; + for (Field f : Options.class.getDeclaredFields()) { + try { + if (((Option<?>) f.get(oDefault)).value instanceof List) { + //If the default size of the list is greater than the loaded size, use the default value. + //if(((List<?>)((Option)f.get(oDefault)).value).size() > ((List<?>)((Option)f.get(oLoad)).value).size()) { + // continue; + //} + } + if(((Option<?>) f.get(oDefault)).value.getClass().isAssignableFrom(((Option<?>) f.get(oLoad)).value.getClass())) { + ((Option) f.get(oDefault)).value = ((Option) f.get(oLoad)).value; } + } catch (Exception e) { } - ((Option)f.get(oDefault)).value = ((Option)f.get(oLoad)).value; - } catch (Exception e) { } + } + return oDefault; } - return oDefault; } + public void saveToFile(Gson gson, File file) throws IOException { file.createNewFile(); @@ -377,6 +765,4 @@ public class Options { writer.write(gson.toJson(this)); } } - - -} +}
\ No newline at end of file diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java new file mode 100644 index 00000000..8e3a5015 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java @@ -0,0 +1,2499 @@ +package io.github.moulberry.notenoughupdates.profileviewer; + +import com.google.common.base.Splitter; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.minecraft.MinecraftProfileTexture; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.SBAIntegration; +import io.github.moulberry.notenoughupdates.cosmetics.ShaderManager; +import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField; +import io.github.moulberry.notenoughupdates.questing.SBInfo; +import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityOtherPlayerMP; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.resources.DefaultPlayerSkin; +import net.minecraft.client.resources.SkinManager; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.client.shader.Shader; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EnumPlayerModelParts; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.*; +import net.minecraft.util.*; +import org.apache.commons.lang3.text.WordUtils; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; +import org.lwjgl.opengl.GL20; + +import java.awt.*; +import java.io.IOException; +import java.text.NumberFormat; +import java.util.*; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class GuiProfileViewer extends GuiScreen { + + private static final ResourceLocation CHEST_GUI_TEXTURE = new ResourceLocation("textures/gui/container/generic_54.png"); + public static final ResourceLocation pv_basic = new ResourceLocation("notenoughupdates:pv_basic.png"); + public static final ResourceLocation pv_extra = new ResourceLocation("notenoughupdates:pv_extra.png"); + public static final ResourceLocation pv_invs = new ResourceLocation("notenoughupdates:pv_invs.png"); + public static final ResourceLocation pv_cols = new ResourceLocation("notenoughupdates:pv_cols.png"); + public static final ResourceLocation pv_pets = new ResourceLocation("notenoughupdates:pv_pets.png"); + public static final ResourceLocation pv_dropdown = new ResourceLocation("notenoughupdates:pv_dropdown.png"); + public static final ResourceLocation pv_bg = new ResourceLocation("notenoughupdates:pv_bg.png"); + public static final ResourceLocation pv_elements = new ResourceLocation("notenoughupdates:pv_elements.png"); + public static final ResourceLocation resource_packs = new ResourceLocation("minecraft:textures/gui/resource_packs.png"); + public static final ResourceLocation icons = new ResourceLocation("textures/gui/icons.png"); + + private static final NumberFormat numberFormat = NumberFormat.getInstance(Locale.US); + + private final ProfileViewer.Profile profile; + private ProfileViewerPage currentPage = ProfileViewerPage.BASIC; + private int sizeX; + private int sizeY; + private int guiLeft; + private int guiTop; + + private float backgroundRotation = 0; + + private long currentTime = 0; + private long lastTime = 0; + private long startTime = 0; + + private List<String> tooltipToDisplay = null; + + private String profileId = null; + private boolean profileDropdownSelected = false; + + public enum ProfileViewerPage { + LOADING(null), + INVALID_NAME(null), + BASIC(new ItemStack(Items.paper)), + EXTRA(new ItemStack(Items.book)), + INVS(new ItemStack(Item.getItemFromBlock(Blocks.ender_chest))), + COLS(new ItemStack(Items.painting)), + PETS(new ItemStack(Items.bone)); + + public final ItemStack stack; + + + ProfileViewerPage(ItemStack stack) { + this.stack = stack; + } + } + + public GuiProfileViewer(ProfileViewer.Profile profile) { + this.profile = profile; + String name = ""; + if(profile != null) { + name = profile.getHypixelProfile().get("displayname").getAsString(); + } + playerNameTextField = new GuiElementTextField(name, + GuiElementTextField.SCALE_TEXT); + playerNameTextField.setSize(100, 20); + } + + private GuiElementTextField playerNameTextField; + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + currentTime = System.currentTimeMillis(); + if(startTime == 0) startTime = currentTime; + + if(profile == null) { + currentPage = ProfileViewerPage.INVALID_NAME; + } + if(profileId == null && profile != null && profile.getLatestProfile() != null) { + profileId = profile.getLatestProfile(); + } + + this.sizeX = 431; + this.sizeY = 202; + this.guiLeft = (this.width-this.sizeX)/2; + this.guiTop = (this.height-this.sizeY)/2; + + super.drawScreen(mouseX, mouseY, partialTicks); + drawDefaultBackground(); + + blurBackground(); + renderBlurredBackground(width, height, guiLeft+2, guiTop+2, sizeX-4, sizeY-4); + + GlStateManager.enableDepth(); + GlStateManager.translate(0, 0, 5); + renderTabs(true); + GlStateManager.translate(0, 0, -3); + + GlStateManager.disableDepth(); + GlStateManager.translate(0, 0, -2); + renderTabs(false); + GlStateManager.translate(0, 0, 2); + + GlStateManager.disableLighting(); + GlStateManager.enableDepth(); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.enableAlpha(); + GlStateManager.alphaFunc(516, 0.1F); + + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_bg); + Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST); + + if(!(currentPage == ProfileViewerPage.LOADING) && profileId != null) { + playerNameTextField.render(guiLeft+sizeX-100, guiTop+sizeY+5); + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + + if(profile != null) { + renderBlurredBackground(width, height, guiLeft+2, guiTop+sizeY+3+2, 100-4, 20-4); + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_dropdown); + Utils.drawTexturedRect(guiLeft, guiTop+sizeY+3, 100, 20, + 0, 100/200f, 0, 20/185f, GL11.GL_NEAREST); + Utils.drawStringCenteredScaledMaxWidth(profileId, Minecraft.getMinecraft().fontRendererObj, guiLeft+50, + guiTop+sizeY+3+10, true, 90, new Color(63, 224, 208, 255).getRGB()); + + if(profileDropdownSelected && !profile.getProfileIds().isEmpty() && scaledResolution.getScaleFactor() != 4) { + int dropdownOptionSize = scaledResolution.getScaleFactor()==3?10:20; + + int numProfiles = profile.getProfileIds().size(); + int sizeYDropdown = numProfiles*dropdownOptionSize; + renderBlurredBackground(width, height, guiLeft+2, guiTop+sizeY+23, 100-4, sizeYDropdown-2); + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_dropdown); + Utils.drawTexturedRect(guiLeft, guiTop+sizeY+23-3, 100, 3, + 100/200f, 1, 0, 3/185f, GL11.GL_NEAREST); + Utils.drawTexturedRect(guiLeft, guiTop+sizeY+23+sizeYDropdown-4, 100, 4, + 100/200f, 1, 181/185f, 1, GL11.GL_NEAREST); + Utils.drawTexturedRect(guiLeft, guiTop+sizeY+23, 100, sizeYDropdown-4, + 100/200f, 1, (181-sizeYDropdown)/185f, 181/185f, GL11.GL_NEAREST); + + for(int yIndex = 0; yIndex<profile.getProfileIds().size(); yIndex++) { + String otherProfileId = profile.getProfileIds().get(yIndex); + Utils.drawStringCenteredScaledMaxWidth(otherProfileId, Minecraft.getMinecraft().fontRendererObj, guiLeft+50, + guiTop+sizeY+23+dropdownOptionSize/2f+dropdownOptionSize*yIndex, true, 90, new Color(33, 112, 104, 255).getRGB()); + } + + } + } + } + + GlStateManager.color(1, 1, 1, 1); + switch (currentPage) { + case BASIC: + drawBasicPage(mouseX, mouseY, partialTicks); + break; + case EXTRA: + drawExtraPage(mouseX, mouseY, partialTicks); + break; + case INVS: + drawInvsPage(mouseX, mouseY, partialTicks); + break; + case COLS: + drawColsPage(mouseX, mouseY, partialTicks); + break; + case PETS: + drawPetsPage(mouseX, mouseY, partialTicks); + break; + case LOADING: + Utils.drawStringCentered(EnumChatFormatting.YELLOW+"Loading player profiles...", Minecraft.getMinecraft().fontRendererObj, + guiLeft+sizeX/2f, guiTop+101, true, 0); + break; + case INVALID_NAME: + Utils.drawStringCentered(EnumChatFormatting.RED+"Invalid name or API is down!", Minecraft.getMinecraft().fontRendererObj, + guiLeft+sizeX/2f, guiTop+101, true, 0); + break; + } + + lastTime = currentTime; + + if(tooltipToDisplay != null) { + List<String> grayTooltip = new ArrayList<>(tooltipToDisplay.size()); + for(String line : tooltipToDisplay) { + grayTooltip.add(EnumChatFormatting.GRAY + line); + } + Utils.drawHoveringText(grayTooltip, mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj); + tooltipToDisplay = null; + } + } + + private boolean isLoadedProfile() { + return profile.getProfileInformation(profileId) != null; + } + + private void renderTabs(boolean renderPressed) { + int ignoredTabs = 0; + for(int i=0; i<ProfileViewerPage.values().length; i++) { + ProfileViewerPage page = ProfileViewerPage.values()[i]; + if(page.stack == null) { + ignoredTabs++; + continue; + } + boolean pressed = page == currentPage; + if(pressed == renderPressed) { + renderTab(page.stack, i-ignoredTabs, pressed); + } + } + } + + private void renderTab(ItemStack stack, int xIndex, boolean pressed) { + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.enableAlpha(); + GlStateManager.alphaFunc(516, 0.1F); + + int x = guiLeft+xIndex*28; + int y = guiTop-28; + + float uMin = 0; + float uMax = 28/256f; + float vMin = 20/256f; + float vMax = 51/256f; + if(pressed) { + vMin = 52/256f; + vMax = 84/256f; + + if(xIndex != 0) { + uMin = 28/256f; + uMax = 56/256f; + } + + renderBlurredBackground(width, height, x+2, y+2, 28-4, 28-4); + } else { + renderBlurredBackground(width, height, x+2, y+4, 28-4, 28-4); + } + + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.enableAlpha(); + GlStateManager.alphaFunc(516, 0.1F); + + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); + Utils.drawTexturedRect(x, y, 28, pressed?32:31, uMin, uMax, vMin, vMax, GL11.GL_NEAREST); + + GlStateManager.enableDepth(); + Utils.drawItemStack(stack, x+6, y+9); + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { + if(currentPage != ProfileViewerPage.LOADING && currentPage != ProfileViewerPage.INVALID_NAME) { + int ignoredTabs = 0; + for(int i=0; i<ProfileViewerPage.values().length; i++) { + ProfileViewerPage page = ProfileViewerPage.values()[i]; + if(page.stack == null) { + ignoredTabs++; + continue; + } + int i2 = i - ignoredTabs; + int x = guiLeft+i2*28; + int y = guiTop-28; + + if(mouseX > x && mouseX < x+28) { + if(mouseY > y && mouseY < y+32) { + if(currentPage != page) Utils.playPressSound(); + currentPage = page; + inventoryTextField.otherComponentClick(); + playerNameTextField.otherComponentClick(); + return; + } + } + } + } + switch (currentPage) { + case INVS: + inventoryTextField.setSize(88, 20); + if(mouseX > guiLeft+19 && mouseX < guiLeft+19+88) { + if(mouseY > guiTop+sizeY-26-20 && mouseY < guiTop+sizeY-26) { + inventoryTextField.mouseClicked(mouseX, mouseY, mouseButton); + playerNameTextField.otherComponentClick(); + return; + } + } + break; + case PETS: + if(sortedPets == null) break; + for(int i=petsPage*20; i<Math.min(petsPage*20+20, sortedPets.size()); i++) { + int xIndex = (i%20) % COLLS_XCOUNT; + int yIndex = (i%20) / COLLS_XCOUNT; + + float x = 5 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex; + float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex; + + if(mouseX > guiLeft+x && mouseX < guiLeft+x+20) { + if(mouseY > guiTop+y && mouseY < guiTop+y+20) { + selectedPet = i; + return; + } + } + } + break; + } + if(mouseX > guiLeft+sizeX-100 && mouseX < guiLeft+sizeX) { + if(mouseY > guiTop+sizeY+5 && mouseY < guiTop+sizeY+25) { + playerNameTextField.mouseClicked(mouseX, mouseY, mouseButton); + inventoryTextField.otherComponentClick(); + return; + } + } + if(mouseX > guiLeft && mouseX < guiLeft+100 && profile != null && !profile.getProfileIds().isEmpty()) { + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + if(mouseY > guiTop+sizeY+3 && mouseY < guiTop+sizeY+23) { + if(scaledResolution.getScaleFactor() == 4) { + profileDropdownSelected = false; + int profileNum = 0; + for(int index = 0; index<profile.getProfileIds().size(); index++) { + if(profile.getProfileIds().get(index).equals(profileId)) { + profileNum = index; + break; + } + } + if(mouseButton == 0) { + profileNum++; + } else { + profileNum--; + } + if(profileNum >= profile.getProfileIds().size()) profileNum = 0; + if(profileNum < 0) profileNum = profile.getProfileIds().size()-1; + + String newProfileId = profile.getProfileIds().get(profileNum); + if(profileId != null && !profileId.equals(newProfileId)) { + resetCache(); + } + profileId = newProfileId; + } else { + profileDropdownSelected = !profileDropdownSelected; + } + } else if(scaledResolution.getScaleFactor() != 4 && profileDropdownSelected) { + int dropdownOptionSize = scaledResolution.getScaleFactor()==3?10:20; + int extraY = mouseY - (guiTop+sizeY+23); + int index = extraY/dropdownOptionSize; + if(index >= 0 && index < profile.getProfileIds().size()) { + String newProfileId = profile.getProfileIds().get(index); + if(profileId != null && !profileId.equals(newProfileId)) { + resetCache(); + } + profileId = newProfileId; + } + } + playerNameTextField.otherComponentClick(); + inventoryTextField.otherComponentClick(); + return; + } + profileDropdownSelected = false; + playerNameTextField.otherComponentClick(); + inventoryTextField.otherComponentClick(); + } + + @Override + protected void keyTyped(char typedChar, int keyCode) throws IOException { + super.keyTyped(typedChar, keyCode); + SBAIntegration.keyTyped(keyCode); + switch (currentPage) { + case INVS: + keyTypedInvs(typedChar, keyCode); + inventoryTextField.keyTyped(typedChar, keyCode); + break; + case COLS: + keyTypedCols(typedChar, keyCode); + break; + } + if(playerNameTextField.getFocus() && !(currentPage == ProfileViewerPage.LOADING)) { + if(keyCode == Keyboard.KEY_RETURN) { + currentPage = ProfileViewerPage.LOADING; + NotEnoughUpdates.profileViewer.getProfileByName(playerNameTextField.getText(), profile -> { //todo: invalid name + if(profile != null) profile.resetCache(); + Minecraft.getMinecraft().displayGuiScreen(new GuiProfileViewer(profile)); + }); + } + playerNameTextField.keyTyped(typedChar, keyCode); + } + } + + @Override + protected void mouseReleased(int mouseX, int mouseY, int mouseButton) { + super.mouseReleased(mouseX, mouseY, mouseButton); + + switch (currentPage) { + case INVS: + mouseReleasedInvs(mouseX, mouseY, mouseButton); + break; + case COLS: + mouseReleasedCols(mouseX, mouseY, mouseButton); + break; + case PETS: + mouseReleasedPets(mouseX, mouseY, mouseButton); + } + } + + protected void keyTypedInvs(char typedChar, int keyCode) throws IOException { + switch(keyCode) { + case Keyboard.KEY_1: + case Keyboard.KEY_NUMPAD1: + selectedInventory = "inv_contents"; break; + case Keyboard.KEY_2: + case Keyboard.KEY_NUMPAD2: + selectedInventory = "ender_chest_contents"; break; + case Keyboard.KEY_3: + case Keyboard.KEY_NUMPAD3: + selectedInventory = "talisman_bag"; break; + case Keyboard.KEY_4: + case Keyboard.KEY_NUMPAD4: + selectedInventory = "wardrobe_contents"; break; + case Keyboard.KEY_5: + case Keyboard.KEY_NUMPAD5: + selectedInventory = "fishing_bag"; break; + case Keyboard.KEY_6: + case Keyboard.KEY_NUMPAD6: + selectedInventory = "potion_bag"; break; + } + Utils.playPressSound(); + } + + protected void keyTypedCols(char typedChar, int keyCode) throws IOException { + ItemStack stack = null; + Iterator<ItemStack> items = ProfileViewer.getCollectionCatToCollectionMap().keySet().iterator(); + switch(keyCode) { + case Keyboard.KEY_5: + case Keyboard.KEY_NUMPAD5: + stack = items.next(); + case Keyboard.KEY_4: + case Keyboard.KEY_NUMPAD4: + stack = items.next(); + case Keyboard.KEY_3: + case Keyboard.KEY_NUMPAD3: + stack = items.next(); + case Keyboard.KEY_2: + case Keyboard.KEY_NUMPAD2: + stack = items.next(); + case Keyboard.KEY_1: + case Keyboard.KEY_NUMPAD1: + stack = items.next(); + } + if(stack != null) { + selectedCollectionCategory = stack; + } + Utils.playPressSound(); + } + + private void mouseReleasedPets(int mouseX, int mouseY, int mouseButton) { + if(mouseY > guiTop+6 && mouseY < guiTop+22) { + if(mouseX > guiLeft+100-15-12 && mouseX < guiLeft+100-20) { + if(petsPage > 0) { + petsPage--; + } + return; + } else if(mouseX > guiLeft+100+15 && mouseX < guiLeft+100+20+12) { + if(sortedPets != null && petsPage < Math.ceil(sortedPets.size()/20f)-1) { + petsPage++; + } + return; + } + } + } + + private void mouseReleasedInvs(int mouseX, int mouseY, int mouseButton) { + if(mouseButton == 0) { + int i=0; + for(Map.Entry<String, ItemStack> entry : invNameToDisplayMap.entrySet()) { + int xIndex = i%3; + int yIndex = i/3; + + int x = guiLeft+19+34*xIndex; + int y = guiTop+26+34*yIndex; + + if(mouseX >= x && mouseX <= x+16) { + if(mouseY >= y && mouseY <= y+16) { + if(selectedInventory != entry.getKey()) Utils.playPressSound(); + selectedInventory = entry.getKey(); + return; + } + } + + i++; + } + + JsonObject inventoryInfo = profile.getInventoryInfo(profileId); + if(inventoryInfo == null) return; + JsonObject collectionInfo = profile.getCollectionInfo(profileId); + if(collectionInfo == null) return; + + ItemStack[][][] inventories = getItemsForInventory(inventoryInfo, collectionInfo, selectedInventory); + if(currentInventoryIndex >= inventories.length) currentInventoryIndex = inventories.length-1; + if(currentInventoryIndex < 0) currentInventoryIndex = 0; + + ItemStack[][] inventory = inventories[currentInventoryIndex]; + if(inventory == null) return; + + int inventoryRows = inventory.length; + int invSizeY = inventoryRows*18+17+7; + + int y = guiTop+101-invSizeY/2; + + if(mouseY > y+invSizeY && mouseY < y+invSizeY+16) { + if(mouseX > guiLeft+320-12 && mouseX < guiLeft+320+12) { + if(mouseX < guiLeft+320) { + currentInventoryIndex--; + } else { + currentInventoryIndex++; + } + } + } + } + } + + private ItemStack selectedCollectionCategory = null; + + private void mouseReleasedCols(int mouseX, int mouseY, int mouseButton) { + int collectionCatSize = ProfileViewer.getCollectionCatToCollectionMap().size(); + int collectionCatYSize = (int)(162f/(collectionCatSize-1+0.0000001f)); + int yIndex = 0; + for(ItemStack stack : ProfileViewer.getCollectionCatToCollectionMap().keySet()) { + if(mouseX > guiLeft+7 && mouseX < guiLeft+7+20) { + if(mouseY > guiTop+10+collectionCatYSize*yIndex && mouseY < guiTop+10+collectionCatYSize*yIndex+20) { + selectedCollectionCategory = stack; + Utils.playPressSound(); + return; + } + } + yIndex++; + } + } + + private class Level { + float level; + float currentLevelRequirement; + float maxXP; + } + + public Level getLevel(JsonArray levels, int offset, float exp) { + float xpTotal = 0; + float level = 1; + float currentLevelRequirement = 0; + float remainingToNextLevel = 0; + + boolean addLevel = true; + + for(int i=offset; i<offset+99; i++) { + + if(addLevel) { + currentLevelRequirement = levels.get(i).getAsFloat(); + xpTotal += currentLevelRequirement; + if(xpTotal > exp) { + remainingToNextLevel = (exp-(xpTotal-currentLevelRequirement))/currentLevelRequirement; + addLevel = false; + } else { + level += 1; + } + } else { + xpTotal += levels.get(i).getAsFloat(); + } + } + + level += remainingToNextLevel; + if(level <= 0) { + level = 1; + } else if(level > 100) { + level = 100; + } + Level levelObj = new Level(); + levelObj.level = level; + levelObj.currentLevelRequirement = currentLevelRequirement; + levelObj.maxXP = xpTotal; + return levelObj; + } + + private static final HashMap<String, HashMap<String, Float>> PET_STAT_BOOSTS = new HashMap<>(); + static { + HashMap<String, Float> bigTeeth = new HashMap<>(); + bigTeeth.put("CRIT_CHANCE", 5f); + PET_STAT_BOOSTS.put("PET_ITEM_BIG_TEETH_COMMON", bigTeeth); + + HashMap<String, Float> hardenedScales = new HashMap<>(); + hardenedScales.put("DEFENCE", 25f); + PET_STAT_BOOSTS.put("PET_ITEM_HARDENED_SCALES_UNCOMMON", hardenedScales); + + HashMap<String, Float> luckyClover = new HashMap<>(); + luckyClover.put("MAGIC_FIND", 7f); + PET_STAT_BOOSTS.put("PET_ITEM_LUCKY_CLOVER", luckyClover); + + HashMap<String, Float> sharpenedClaws = new HashMap<>(); + sharpenedClaws.put("CRIT_DAMAGE", 15f); + PET_STAT_BOOSTS.put("PET_ITEM_SHARPENED_CLAWS_UNCOMMON", sharpenedClaws); + } + private static final HashMap<String, HashMap<String, Float>> PET_STAT_BOOSTS_MULT = new HashMap<>(); + static { + HashMap<String, Float> ironClaws = new HashMap<>(); + ironClaws.put("CRIT_DAMAGE", 1.4f); + ironClaws.put("CRIT_CHANCE", 1.4f); + PET_STAT_BOOSTS_MULT.put("PET_ITEM_IRON_CLAWS_COMMON", ironClaws); + + HashMap<String, Float> textbook = new HashMap<>(); + textbook.put("INTELLIGENCE", 2f); + PET_STAT_BOOSTS_MULT.put("PET_ITEM_TEXTBOOK", textbook); + } + + private int selectedPet = -1; + private int petsPage = 0; + private List<JsonObject> sortedPets = null; + private List<ItemStack> sortedPetsStack = null; + private static HashMap<String, String> minionRarityToNumMap = new HashMap<>(); + static { + minionRarityToNumMap.put("COMMON", "0"); + minionRarityToNumMap.put("UNCOMMON", "1"); + minionRarityToNumMap.put("RARE", "2"); + minionRarityToNumMap.put("EPIC", "3"); + minionRarityToNumMap.put("LEGENDARY", "4"); + } + private void drawPetsPage(int mouseX, int mouseY, float partialTicks) { + JsonObject petsInfo = profile.getPetsInfo(profileId); + if(petsInfo == null) return; + JsonObject petsJson = Constants.PETS; + if(petsJson == null) return; + + String location = null; + JsonObject status = profile.getPlayerStatus(); + if(status != null && status.has("mode")) { + location = status.get("mode").getAsString(); + } + + backgroundRotation += (currentTime - lastTime)/400f; + backgroundRotation %= 360; + + String panoramaIdentifier = "day"; + if(SBInfo.getInstance().currentTimeDate != null) { + if(SBInfo.getInstance().currentTimeDate.getHours() <= 6 || + SBInfo.getInstance().currentTimeDate.getHours() >= 20) { + panoramaIdentifier = "night"; + } + } + + JsonArray pets = petsInfo.get("pets").getAsJsonArray(); + if(sortedPets == null) { + sortedPets = new ArrayList<>(); + sortedPetsStack = new ArrayList<>(); + for(int i=0; i<pets.size(); i++) { + sortedPets.add(pets.get(i).getAsJsonObject()); + } + sortedPets.sort((pet1, pet2) -> { + String tier1 = pet1.get("tier").getAsString(); + String tierNum1 = minionRarityToNumMap.get(tier1); + int tierNum1I = Integer.parseInt(tierNum1); + float exp1 = pet1.get("exp").getAsFloat(); + + String tier2 = pet2.get("tier").getAsString(); + String tierNum2 = minionRarityToNumMap.get(tier2); + int tierNum2I = Integer.parseInt(tierNum2); + float exp2 = pet2.get("exp").getAsFloat(); + + if(tierNum1I != tierNum2I) { + return tierNum2I - tierNum1I; + } else { + return (int)(exp2 - exp1); + } + }); + for(JsonObject pet : sortedPets) { + String petname = pet.get("type").getAsString(); + String tier = pet.get("tier").getAsString(); + String heldItem = Utils.getElementAsString(pet.get("heldItem"), null); + JsonObject heldItemJson = heldItem==null?null:NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(heldItem); + String tierNum = minionRarityToNumMap.get(tier); + float exp = pet.get("exp").getAsFloat(); + if(tierNum == null) continue; + + if(pet.has("heldItem") && !pet.get("heldItem").isJsonNull() && pet.get("heldItem").getAsString().equals("PET_ITEM_TIER_BOOST")) { + tierNum = ""+(Integer.parseInt(tierNum)+1); + } + + int petRarityOffset = petsJson.get("pet_rarity_offset").getAsJsonObject().get(tier).getAsInt(); + JsonArray levelsArr = petsJson.get("pet_levels").getAsJsonArray(); + + Level levelObj = getLevel(levelsArr, petRarityOffset, exp); + float level = levelObj.level; + float currentLevelRequirement = levelObj.currentLevelRequirement; + float maxXP = levelObj.maxXP; + pet.addProperty("level", level); + pet.addProperty("currentLevelRequirement", currentLevelRequirement); + pet.addProperty("maxXP", maxXP); + + JsonObject petItem = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(petname+";"+tierNum); + if(petItem == null) continue; + + ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(petItem, false, false); + HashMap<String, String> replacements = NotEnoughUpdates.INSTANCE.manager.getLoreReplacements(petname, tier, (int)Math.floor(level)); + + if(heldItem != null) { + HashMap<String, Float> petStatBoots = PET_STAT_BOOSTS.get(heldItem); + HashMap<String, Float> petStatBootsMult = PET_STAT_BOOSTS_MULT.get(heldItem); + if(petStatBoots != null) { + for(Map.Entry<String, Float> entryBoost : petStatBoots.entrySet()) { + try { + float value = Float.parseFloat(replacements.get(entryBoost.getKey())); + replacements.put(entryBoost.getKey(), String.valueOf((int)Math.floor(value+entryBoost.getValue()))); + } catch(Exception ignored) {} + } + + } + if(petStatBootsMult != null) { + for(Map.Entry<String, Float> entryBoost : petStatBootsMult.entrySet()) { + try { + float value = Float.parseFloat(replacements.get(entryBoost.getKey())); + replacements.put(entryBoost.getKey(), String.valueOf((int)Math.floor(value*entryBoost.getValue()))); + } catch(Exception ignored) {} + } + } + } + + NBTTagCompound tag = stack.getTagCompound()==null?new NBTTagCompound():stack.getTagCompound(); + if(tag.hasKey("display", 10)) { + NBTTagCompound display = tag.getCompoundTag("display"); + if(display.hasKey("Lore", 9)) { + NBTTagList newNewLore = new NBTTagList(); + NBTTagList newLore = new NBTTagList(); + NBTTagList lore = display.getTagList("Lore", 8); + HashMap<Integer, Integer> blankLocations = new HashMap<>(); + for(int j=0; j<lore.tagCount(); j++) { + String line = lore.getStringTagAt(j); + if(line.trim().isEmpty()) { + blankLocations.put(blankLocations.size(), j); + } + for(Map.Entry<String, String> replacement : replacements.entrySet()) { + line = line.replace("{"+replacement.getKey()+"}", replacement.getValue()); + } + newLore.appendTag(new NBTTagString(line)); + } + Integer secondLastBlank = blankLocations.get(blankLocations.size()-2); + if(heldItemJson != null && secondLastBlank != null) { + for(int j=0; j<newLore.tagCount(); j++) { + String line = newLore.getStringTagAt(j); + + if(j == secondLastBlank.intValue()) { + newNewLore.appendTag(new NBTTagString("")); + newNewLore.appendTag(new NBTTagString(EnumChatFormatting.GOLD+"Held Item: "+heldItemJson.get("displayname").getAsString())); + int blanks = 0; + JsonArray heldItemLore = heldItemJson.get("lore").getAsJsonArray(); + for(int k=0; k<heldItemLore.size(); k++) { + String heldItemLine = heldItemLore.get(k).getAsString(); + if(heldItemLine.trim().isEmpty()) { + blanks++; + } else if(blanks==2) { + newNewLore.appendTag(new NBTTagString(heldItemLine)); + } else if(blanks>2) { + break; + } + } + } + + newNewLore.appendTag(new NBTTagString(line)); + } + display.setTag("Lore", newNewLore); + } else { + display.setTag("Lore", newLore); + } + } + if(display.hasKey("Name", 8)) { + String displayName = display.getString("Name"); + for(Map.Entry<String, String> replacement : replacements.entrySet()) { + displayName = displayName.replace("{"+replacement.getKey()+"}", replacement.getValue()); + } + display.setTag("Name", new NBTTagString(displayName)); + } + tag.setTag("display", display); + } + stack.setTagCompound(tag); + + sortedPetsStack.add(stack); + } + } + + Panorama.drawPanorama(-backgroundRotation, guiLeft+212, guiTop+44, 81, 108, -0.37f, 0.6f, + getPanoramasForLocation(location==null?"dynamic":location, panoramaIdentifier)); + + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_pets); + Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST); + + Utils.drawStringCentered(EnumChatFormatting.DARK_PURPLE+"Pets", Minecraft.getMinecraft().fontRendererObj, + guiLeft+100, guiTop+14, true, 4210752); + GlStateManager.color(1, 1, 1, 1); + + JsonElement activePetElement = petsInfo.get("active_pet"); + if(selectedPet == -1 && activePetElement != null && activePetElement.isJsonObject()) { + JsonObject active = activePetElement.getAsJsonObject(); + for(int i=0; i<sortedPets.size(); i++) { + if(sortedPets.get(i) == active) { + selectedPet = i; + break; + } + } + } + + boolean leftHovered = false; + boolean rightHovered = false; + if(Mouse.isButtonDown(0)) { + if(mouseY > guiTop+6 && mouseY < guiTop+22) { + if(mouseX > guiLeft+100-20-12 && mouseX < guiLeft+100-20) { + leftHovered = true; + } else if(mouseX > guiLeft+100+20 && mouseX < guiLeft+100+20+12) { + rightHovered = true; + } + } + } + Minecraft.getMinecraft().getTextureManager().bindTexture(resource_packs); + + if(petsPage > 0) { + Utils.drawTexturedRect(guiLeft+100-15-12, guiTop+6, 12, 16, + 29/256f, 53/256f, !leftHovered?0:32/256f, !leftHovered?32/256f:64/256f, GL11.GL_NEAREST); + } + if(petsPage < Math.ceil(pets.size()/20f)-1) { + Utils.drawTexturedRect( guiLeft+100+15, guiTop+6, 12, 16, + 5/256f, 29/256f, !rightHovered?0:32/256f, !rightHovered?32/256f:64/256f, GL11.GL_NEAREST); + } + + for(int i=petsPage*20; i<Math.min(petsPage*20+20, sortedPets.size()); i++) { + JsonObject pet = sortedPets.get(i); + ItemStack stack = sortedPetsStack.get(i); + if(pet != null) { + int xIndex = (i%20) % COLLS_XCOUNT; + int yIndex = (i%20) / COLLS_XCOUNT; + + float x = 5 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex; + float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex; + + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); + if(i == selectedPet) { + GlStateManager.color(1, 185/255f, 0, 1); + Utils.drawTexturedRect(guiLeft+x, guiTop+y, 20, 20, + 0, 20/256f, 0, 20/256f, GL11.GL_NEAREST); + } else { + GlStateManager.color(1, 1, 1, 1); + Utils.drawTexturedRect(guiLeft+x, guiTop+y, 20, 20, + 0, 20/256f, 0, 20/256f, GL11.GL_NEAREST); + } + + Utils.drawItemStack(stack, guiLeft+(int)x+2, guiTop+(int)y+2); + + if(mouseX > guiLeft+x && mouseX < guiLeft+x+20) { + if(mouseY > guiTop+y && mouseY < guiTop+y+20) { + tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + } + } + } + } + + if(selectedPet >= 0) { + ItemStack petStack = sortedPetsStack.get(selectedPet); + String display = petStack.getDisplayName(); + JsonObject pet = sortedPets.get(selectedPet); + String type = pet.get("type").getAsString(); + + for(int i=0; i<4; i++) { + JsonObject item = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(type+";"+i); + if(item != null) { + int x = guiLeft+280; + float y = guiTop+67+15*(float)Math.sin(((currentTime-startTime)/800f)%(2*Math.PI)); + + int displayLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth(display); + int halfDisplayLen = displayLen/2; + + GlStateManager.translate(x, y, 0); + + drawRect(-halfDisplayLen-1-28, -1, halfDisplayLen+1-28, 8, new Color(0, 0, 0, 100).getRGB()); + + Minecraft.getMinecraft().fontRendererObj.drawString(display, -halfDisplayLen-28, 0, 0, true); + + ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(item); + GlStateManager.scale(-3.5f, 3.5f, 1); + GlStateManager.enableDepth(); + Utils.drawItemStack(stack, 0, 0); + GlStateManager.scale(-1/3.5f, 1/3.5f, 1); + GlStateManager.translate(-x, -y, 0); + break; + } + } + + float level = pet.get("level").getAsFloat(); + float currentLevelRequirement = pet.get("currentLevelRequirement").getAsFloat(); + float exp = pet.get("exp").getAsFloat(); + float maxXP = pet.get("maxXP").getAsFloat(); + + String[] split = display.split("] "); + String colouredName = split[split.length-1]; + + renderAlignedString(colouredName, EnumChatFormatting.WHITE+"Level "+(int)Math.floor(level), guiLeft+319, guiTop+28, 98); + + //Utils.drawStringCenteredScaledMaxWidth(, Minecraft.getMinecraft().fontRendererObj, guiLeft+368, guiTop+28+4, true, 98, 0); + //renderAlignedString(display, EnumChatFormatting.YELLOW+"[LVL "+Math.floor(level)+"]", guiLeft+319, guiTop+28, 98); + renderBar(guiLeft+319, guiTop+38, 98, (float)Math.floor(level)/100f); + + renderAlignedString(EnumChatFormatting.YELLOW+"To Next LVL", EnumChatFormatting.WHITE.toString()+(int)(level%1*100)+"%", guiLeft+319, guiTop+46, 98); + renderBar(guiLeft+319, guiTop+56, 98, level%1); + + renderAlignedString(EnumChatFormatting.YELLOW+"To Max LVL", EnumChatFormatting.WHITE.toString()+Math.min(100, (int)(exp/maxXP*100))+"%", guiLeft+319, guiTop+64, 98); + renderBar(guiLeft+319, guiTop+74, 98, exp/maxXP); + + renderAlignedString(EnumChatFormatting.YELLOW+"Total XP", EnumChatFormatting.WHITE.toString()+shortNumberFormat(exp, 0), guiLeft+319, guiTop+125, 98); + renderAlignedString(EnumChatFormatting.YELLOW+"Current LVL XP", + EnumChatFormatting.WHITE.toString()+shortNumberFormat((level%1)*currentLevelRequirement, 0), guiLeft+319, guiTop+143, 98); + renderAlignedString(EnumChatFormatting.YELLOW+"Required LVL XP", EnumChatFormatting.WHITE.toString()+shortNumberFormat(currentLevelRequirement, 0), guiLeft+319, guiTop+161, 98); + } + } + + private String[] romans = new String[]{"I","II","III","IV","V","VI","VII","VIII","IX","X","XI", + "XII","XIII","XIV","XV","XVI","XVII","XIX","XX"}; + + private final int COLLS_XCOUNT = 5; + private final int COLLS_YCOUNT = 4; + private final float COLLS_XPADDING = (190-COLLS_XCOUNT*20)/(float)(COLLS_XCOUNT+1); + private final float COLLS_YPADDING = (202-COLLS_YCOUNT*20)/(float)(COLLS_YCOUNT+1); + + private void drawColsPage(int mouseX, int mouseY, float partialTicks) { + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_cols); + Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST); + + JsonObject collectionInfo = profile.getCollectionInfo(profileId); + if(collectionInfo == null) { + Utils.drawStringCentered(EnumChatFormatting.RED+"Collection API not enabled!", Minecraft.getMinecraft().fontRendererObj, + guiLeft+134, guiTop+101, true, 0); + return; + } + JsonObject resourceCollectionInfo = ProfileViewer.getResourceCollectionInformation(); + if(resourceCollectionInfo == null) return; + + int collectionCatSize = ProfileViewer.getCollectionCatToCollectionMap().size(); + int collectionCatYSize = (int)(162f/(collectionCatSize-1+0.0000001f)); + { + int yIndex = 0; + for(ItemStack stack : ProfileViewer.getCollectionCatToCollectionMap().keySet()) { + if(selectedCollectionCategory == null) selectedCollectionCategory = stack; + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); + if(stack == selectedCollectionCategory) { + Utils.drawTexturedRect(guiLeft+7, guiTop+10+collectionCatYSize*yIndex, 20, 20, + 20/256f, 0, 20/256f, 0, GL11.GL_NEAREST); + Utils.drawItemStackWithText(stack, guiLeft+10, guiTop+13+collectionCatYSize*yIndex, ""+(yIndex+1)); + } else { + Utils.drawTexturedRect(guiLeft+7, guiTop+10+collectionCatYSize*yIndex, 20, 20, + 0, 20/256f, 0, 20/256f, GL11.GL_NEAREST); + Utils.drawItemStackWithText(stack, guiLeft+9, guiTop+12+collectionCatYSize*yIndex, ""+(yIndex+1)); + } + yIndex++; + } + } + + Utils.drawStringCentered(selectedCollectionCategory.getDisplayName() + " Collections", Minecraft.getMinecraft().fontRendererObj, + guiLeft+134, guiTop+14, true, 4210752); + + JsonObject minionTiers = collectionInfo.get("minion_tiers").getAsJsonObject(); + JsonObject collectionTiers = collectionInfo.get("collection_tiers").getAsJsonObject(); + JsonObject maxAmounts = collectionInfo.get("max_amounts").getAsJsonObject(); + JsonObject totalAmounts = collectionInfo.get("total_amounts").getAsJsonObject(); + JsonObject personalAmounts = collectionInfo.get("personal_amounts").getAsJsonObject(); + + List<String> collections = ProfileViewer.getCollectionCatToCollectionMap().get(selectedCollectionCategory); + if(collections != null) { + for(int i=0; i<collections.size(); i++) { + String collection = collections.get(i); + if(collection != null) { + ItemStack collectionItem = ProfileViewer.getCollectionToCollectionDisplayMap().get(collection); + if(collectionItem != null) { + int xIndex = i%COLLS_XCOUNT; + int yIndex = i/COLLS_XCOUNT; + + float x = 39+COLLS_XPADDING+(COLLS_XPADDING+20)*xIndex; + float y = 7+COLLS_YPADDING+(COLLS_YPADDING+20)*yIndex; + + String tierString; + int tier = (int)Utils.getElementAsFloat(collectionTiers.get(collection), 0); + if(tier > 20 || tier < 0) { + tierString = String.valueOf(tier); + } else { + tierString = romans[tier]; + } + float amount = Utils.getElementAsFloat(totalAmounts.get(collection), 0); + float maxAmount = Utils.getElementAsFloat(maxAmounts.get(collection), 0); + Color color = new Color(128, 128, 128, 255); + int tierStringColour = color.getRGB(); + float completedness = 0; + if(maxAmount > 0) { + completedness = amount/maxAmount; + } + completedness = Math.min(1, completedness); + if(maxAmounts.has(collection) && completedness >= 1) { + tierStringColour = new Color(255, 215, 0).getRGB(); + } + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); + Utils.drawTexturedRect(guiLeft+x, guiTop+y, 20, 20*(1-completedness), + 0, 20/256f, 0, 20*(1-completedness)/256f, GL11.GL_NEAREST); + GlStateManager.color(1, 185/255f, 0, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); + Utils.drawTexturedRect(guiLeft+x, guiTop+y+20*(1-completedness), 20, 20*(completedness), + 0, 20/256f, 20*(1-completedness)/256f, 20/256f, GL11.GL_NEAREST); + Utils.drawItemStack(collectionItem, guiLeft+(int)x+2, guiTop+(int)y+2); + + if(mouseX > guiLeft+(int)x+2 && mouseX < guiLeft+(int)x+18) { + if(mouseY > guiTop+(int)y+2 && mouseY < guiTop+(int)y+18) { + tooltipToDisplay = new ArrayList<>(); + tooltipToDisplay.add(collectionItem.getDisplayName() + " " + + (completedness>=1?EnumChatFormatting.GOLD:EnumChatFormatting.GRAY) + tierString); + tooltipToDisplay.add("Collected: " + numberFormat.format(Utils.getElementAsFloat(personalAmounts.get(collection), 0))); + tooltipToDisplay.add("Total Collected: " + numberFormat.format(amount)); + } + } + + GlStateManager.color(1, 1, 1, 1); + if(tier >= 0) { + Utils.drawStringCentered(tierString, fontRendererObj, + guiLeft+x+10, guiTop+y-4, true, + tierStringColour); + } + + Utils.drawStringCentered(shortNumberFormat(amount, 0)+"", fontRendererObj, + guiLeft+x+10, guiTop+y+26, true, + color.getRGB()); + } + } + } + } + + Utils.drawStringCentered(selectedCollectionCategory.getDisplayName() + " Minions", Minecraft.getMinecraft().fontRendererObj, + guiLeft+326, guiTop+14, true, 4210752); + + float MAX_MINION_TIER = 11f; + List<String> minions = ProfileViewer.getCollectionCatToMinionMap().get(selectedCollectionCategory); + if(minions != null) { + for(int i=0; i<minions.size(); i++) { + String minion = minions.get(i); + if(minion != null) { + JsonObject minionJson = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(minion+"_GENERATOR_1"); + if(minionJson != null) { + int xIndex = i%COLLS_XCOUNT; + int yIndex = i/COLLS_XCOUNT; + + float x = 231+COLLS_XPADDING+(COLLS_XPADDING+20)*xIndex; + float y = 7+COLLS_YPADDING+(COLLS_YPADDING+20)*yIndex; + + String tierString; + int tier = (int)Utils.getElementAsFloat(minionTiers.get(minion), 0); + if(tier-1 >= romans.length || tier-1 < 0) { + tierString = String.valueOf(tier); + } else { + tierString = romans[tier-1]; + } + + Color color = new Color(128, 128, 128, 255); + int tierStringColour = color.getRGB(); + float completedness = tier/MAX_MINION_TIER; + + completedness = Math.min(1, completedness); + if(completedness >= 1) { + tierStringColour = new Color(255, 215, 0).getRGB(); + } + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); + Utils.drawTexturedRect(guiLeft+x, guiTop+y, 20, 20*(1-completedness), + 0, 20/256f, 0, 20*(1-completedness)/256f, GL11.GL_NEAREST); + GlStateManager.color(1, 185/255f, 0, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); + Utils.drawTexturedRect(guiLeft+x, guiTop+y+20*(1-completedness), 20, 20*(completedness), + 0, 20/256f, 20*(1-completedness)/256f, 20/256f, GL11.GL_NEAREST); + + Utils.drawItemStack(NotEnoughUpdates.INSTANCE.manager.jsonToStack(minionJson), guiLeft+(int)x+2, guiTop+(int)y+2); + + if(mouseX > guiLeft+(int)x+2 && mouseX < guiLeft+(int)x+18) { + if(mouseY > guiTop+(int)y+2 && mouseY < guiTop+(int)y+18) { + tooltipToDisplay = NotEnoughUpdates.INSTANCE.manager.jsonToStack(minionJson) + .getTooltip(Minecraft.getMinecraft().thePlayer, false); + } + } + + GlStateManager.color(1, 1, 1, 1); + if(tier >= 0) { + Utils.drawStringCentered(tierString, fontRendererObj, + guiLeft+x+10, guiTop+y-4, true, + tierStringColour); + } + } + } + } + } + + //190 + } + + private static final LinkedHashMap<String, ItemStack> invNameToDisplayMap = new LinkedHashMap<>(); + static { + invNameToDisplayMap.put("inv_contents", Utils.createItemStack(Item.getItemFromBlock(Blocks.chest), EnumChatFormatting.GRAY+"Inventory")); + invNameToDisplayMap.put("ender_chest_contents", Utils.createItemStack(Item.getItemFromBlock(Blocks.ender_chest), EnumChatFormatting.GRAY+"Ender Chest")); + invNameToDisplayMap.put("talisman_bag", Utils.createItemStack(Items.golden_apple, EnumChatFormatting.GRAY+"Accessory Bag")); + invNameToDisplayMap.put("wardrobe_contents", Utils.createItemStack(Items.leather_chestplate, EnumChatFormatting.GRAY+"Wardrobe")); + invNameToDisplayMap.put("fishing_bag", Utils.createItemStack(Items.fish, EnumChatFormatting.GRAY+"Fishing Bag")); + invNameToDisplayMap.put("potion_bag", Utils.createItemStack(Items.potionitem, EnumChatFormatting.GRAY+"Potion Bag")); + } + + public int countItemsInInventory(String internalname, JsonObject inventoryInfo, String... invsToSearch) { + int count = 0; + for(String inv : invsToSearch) { + JsonArray invItems = inventoryInfo.get(inv).getAsJsonArray(); + for(int i=0; i<invItems.size(); i++) { + if(invItems.get(i) == null || !invItems.get(i).isJsonObject()) continue; + JsonObject item = invItems.get(i).getAsJsonObject(); + if(item.get("internalname").getAsString().equals(internalname)) { + if(item.has("count")) { + count += item.get("count").getAsInt(); + } else { + count += 1; + } + } + } + } + return count; + } + + private static final Pattern DAMAGE_PATTERN = Pattern.compile("^Damage: \\+([0-9]+)"); + private static final Pattern STRENGTH_PATTERN = Pattern.compile("^Strength: \\+([0-9]+)"); + private static final Pattern FISHSPEED_PATTERN = Pattern.compile("^Increases fishing speed by \\+([0-9]+)"); + + private ItemStack[] findBestItems(JsonObject inventoryInfo, int numItems, String[] invsToSearch, String[] typeMatches, Pattern... importantPatterns) { + ItemStack[] bestItems = new ItemStack[numItems]; + TreeMap<Integer, Set<ItemStack>> map = new TreeMap<>(); + for(String inv : invsToSearch) { + JsonArray invItems = inventoryInfo.get(inv).getAsJsonArray(); + for(int i=0; i<invItems.size(); i++) { + if(invItems.get(i) == null || !invItems.get(i).isJsonObject()) continue; + JsonObject item = invItems.get(i).getAsJsonObject(); + JsonArray lore = item.get("lore").getAsJsonArray(); + if(Utils.checkItemType(lore, true, typeMatches) >= 0) { + int importance = 0; + for(int j=0; j<lore.size(); j++) { + String line = lore.get(j).getAsString(); + for(Pattern pattern : importantPatterns) { + Matcher matcher = pattern.matcher(Utils.cleanColour(line)); + if(matcher.find()) { + importance += Integer.parseInt(matcher.group(1)); + } + } + } + map.computeIfAbsent(importance, k->new HashSet<>()).add( + NotEnoughUpdates.INSTANCE.manager.jsonToStack(item, false)); + } + } + } + int i=0; + outer: + for(int key : map.descendingKeySet()) { + Set<ItemStack> items = map.get(key); + for(ItemStack item : items) { + bestItems[i] = item; + if(++i >= bestItems.length) break outer; + } + } + + return bestItems; + } + + private int getRowsForInventory(String invName) { + switch(invName) { + case "wardrobe_contents": + return 4; + } + return 6; + } + + private int getIgnoredRowsForInventory(String invName) { + switch(invName) { + case "talisman_bag": + case "fishing_bag": + case "potion_bag": + return 1; + } + return 0; + } + + private int getAvailableSlotsForInventory(JsonObject inventoryInfo, JsonObject collectionInfo, String invName) { + if(collectionInfo == null) return -1; + JsonObject misc = Constants.MISC; + if(misc == null) return -1; + JsonElement sizesElement = Utils.getElement(misc, "bag_size."+invName+".sizes"); + JsonElement collectionElement = Utils.getElement(misc, "bag_size."+invName+".collection"); + + if(sizesElement == null || !sizesElement.isJsonArray()) return -1; + if(collectionElement == null || !collectionElement.isJsonPrimitive()) return -1; + + JsonArray sizes = sizesElement.getAsJsonArray(); + String collection = collectionElement.getAsString(); + + JsonElement tierElement = Utils.getElement(collectionInfo, "collection_tiers."+collection); + + if(tierElement == null || !tierElement.isJsonPrimitive()) { + return 0; + } + int tier = tierElement.getAsInt(); + + int currentSlots = 0; + for(int i=0; i<sizes.size(); i++) { + JsonObject sizeInfo = sizes.get(i).getAsJsonObject(); + if(sizeInfo.get("tier").getAsInt() <= tier) { + currentSlots = sizeInfo.get("slots").getAsInt(); + } + } + return currentSlots; + } + + private ItemStack fillerStack = new ItemStack(Item.getItemFromBlock(Blocks.stained_glass_pane), 1, 15); + public ItemStack[][][] getItemsForInventory(JsonObject inventoryInfo, JsonObject collectionInfo, String invName) { + if(inventoryItems.containsKey(invName)) return inventoryItems.get(invName); + + JsonArray jsonInv = Utils.getElement(inventoryInfo, invName).getAsJsonArray(); + + int rowSize = 9; + int rows = jsonInv.size()/rowSize; + int maxRowsPerPage = getRowsForInventory(invName); + int ignoredRows = getIgnoredRowsForInventory(invName); + int maxInvSize = rowSize*maxRowsPerPage; + + int numInventories = (jsonInv.size()-1)/maxInvSize+1; + + ItemStack[][][] inventories = new ItemStack[numInventories][][]; + + int availableSlots = getAvailableSlotsForInventory(inventoryInfo, collectionInfo, invName); + + for(int i=0; i<numInventories; i++) { + int thisRows = Math.min(maxRowsPerPage, rows-maxRowsPerPage*i)-ignoredRows; + if(thisRows <= 0) break; + + ItemStack[][] items = new ItemStack[thisRows][rowSize]; + + int invSize = Math.min(jsonInv.size(), maxInvSize+maxInvSize*i); + for(int j=maxInvSize*i; j<invSize; j++) { + int xIndex = (j%maxInvSize)%rowSize; + int yIndex = (j%maxInvSize)/rowSize; + if(invName.equals("inv_contents")) { + yIndex--; + if(yIndex < 0) yIndex = rows-1; + } + if(yIndex >= thisRows) { + break; + } + + if(jsonInv.get(j) == null || !jsonInv.get(j).isJsonObject()) { + if(availableSlots >= 0) { + if(j >= availableSlots) { + items[yIndex][xIndex] = fillerStack; + } + } + continue; + } + + JsonObject item = jsonInv.get(j).getAsJsonObject(); + ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(item, false); + if(item.has("item_contents")) { + JsonArray bytesArr = item.get("item_contents").getAsJsonArray(); + byte[] bytes = new byte[bytesArr.size()]; + for(int bytesArrI=0; bytesArrI<bytesArr.size(); bytesArrI++) { + bytes[bytesArrI] = bytesArr.get(bytesArrI).getAsByte(); + } + //byte[] bytes2 = null; + NBTTagCompound tag = stack.getTagCompound(); + if(tag != null && tag.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + for(String key : ea.getKeySet()) { + if(key.endsWith("backpack_data") || key.equals("new_year_cake_bag_data")) { + ea.setTag(key, new NBTTagByteArray(bytes)); + break; + } + } + tag.setTag("ExtraAttributes", ea); + stack.setTagCompound(tag); + } + } + items[yIndex][xIndex] = stack; + } + inventories[i] = items; + } + + inventoryItems.put(invName, inventories); + return inventories; + } + + + private ItemStack[] bestWeapons = null; + private ItemStack[] bestRods = null; + private ItemStack[] armorItems = null; + private HashMap<String, ItemStack[][][]> inventoryItems = new HashMap<>(); + private String selectedInventory = "inv_contents"; + private int currentInventoryIndex = 0; + private int arrowCount = -1; + private int greenCandyCount = -1; + private int purpleCandyCount = -1; + private GuiElementTextField inventoryTextField = new GuiElementTextField("", GuiElementTextField.SCALE_TEXT); + private ItemStack lastBackpack; + private int lastBackpackX; + private int lastBackpackY; + private void drawInvsPage(int mouseX, int mouseY, float partialTicks) { + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_invs); + Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST); + inventoryTextField.setSize(88, 20); + + JsonObject inventoryInfo = profile.getInventoryInfo(profileId); + if(inventoryInfo == null) return; + JsonObject collectionInfo = profile.getCollectionInfo(profileId); + + int invNameIndex=0; + for(Map.Entry<String, ItemStack> entry : invNameToDisplayMap.entrySet()) { + int xIndex = invNameIndex%3; + int yIndex = invNameIndex/3; + + int x = 19+34*xIndex; + int y = 26+34*yIndex; + + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); + if(entry.getKey().equals(selectedInventory)) { + Utils.drawTexturedRect(guiLeft+x-2, guiTop+y-2, 20, 20, 20/256f, 0, + 20/256f, 0, GL11.GL_NEAREST); + x++; + y++; + } else { + Utils.drawTexturedRect(guiLeft+x-2, guiTop+y-2, 20, 20, 0, 20/256f, + 0, 20/256f, GL11.GL_NEAREST); + } + + Utils.drawItemStackWithText(entry.getValue(), guiLeft+x, guiTop+y, ""+(invNameIndex+1)); + + if(mouseX >= guiLeft+x && mouseX <= guiLeft+x+16) { + if(mouseY >= guiTop+y && mouseY <= guiTop+y+16) { + tooltipToDisplay = entry.getValue().getTooltip(Minecraft.getMinecraft().thePlayer, false); + } + } + + invNameIndex++; + } + + inventoryTextField.render(guiLeft+19, guiTop+sizeY-26-20); + + if(armorItems == null) { + armorItems = new ItemStack[4]; + JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray(); + for(int i=0; i<armor.size(); i++) { + if(armor.get(i) == null || !armor.get(i).isJsonObject()) continue; + armorItems[i] = NotEnoughUpdates.INSTANCE.manager.jsonToStack(armor.get(i).getAsJsonObject(), false); + } + } + + for(int i=0; i<armorItems.length; i++) { + ItemStack stack = armorItems[i]; + if(stack != null) { + Utils.drawItemStack(stack, guiLeft+173, guiTop+67-18*i); + if(stack != fillerStack) { + if(mouseX >= guiLeft+173-1 && mouseX <= guiLeft+173+16+1) { + if(mouseY >= guiTop+67-18*i-1 && mouseY <= guiTop+67-18*i+16+1) { + tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, + Minecraft.getMinecraft().gameSettings.advancedItemTooltips); + } + } + } + } + } + + ItemStack[][][] inventories = getItemsForInventory(inventoryInfo, collectionInfo, selectedInventory); + if(currentInventoryIndex >= inventories.length) currentInventoryIndex = inventories.length-1; + if(currentInventoryIndex < 0) currentInventoryIndex = 0; + + ItemStack[][] inventory = inventories[currentInventoryIndex]; + if(inventory == null) { + Utils.drawStringCentered(EnumChatFormatting.RED+"Inventory API not enabled!", Minecraft.getMinecraft().fontRendererObj, + guiLeft+317, guiTop+101, true, 0); + return; + } + + if(bestWeapons == null) { + bestWeapons = findBestItems(inventoryInfo, 6, new String[]{"inv_contents", "ender_chest_contents"}, + new String[]{"SWORD","BOW"}, DAMAGE_PATTERN, STRENGTH_PATTERN); + } + if(bestRods == null) { + bestRods = findBestItems(inventoryInfo, 3, new String[]{"inv_contents", "ender_chest_contents"}, + new String[]{"FISHING ROD"}, FISHSPEED_PATTERN); + } + + for(int i=0; i<bestWeapons.length; i++) { + if(bestWeapons[i] == null) continue; + ItemStack stack = bestWeapons[i]; + Utils.drawItemStack(stack, guiLeft+143, guiTop+13+18*i); + if(mouseX >= guiLeft+143-1 && mouseX <= guiLeft+143+16+1) { + if(mouseY >= guiTop+13+18*i-1 && mouseY <= guiTop+13+18*i+16+1) { + tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + } + } + } + + for(int i=0; i<bestRods.length; i++) { + if(bestRods[i] == null) continue; + ItemStack stack = bestRods[i]; + Utils.drawItemStack(stack, guiLeft+143, guiTop+137+18*i); + if(mouseX >= guiLeft+143-1 && mouseX <= guiLeft+143+16+1) { + if(mouseY >= guiTop+137+18*i-1 && mouseY <= guiTop+137+18*i+16+1) { + tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + } + } + } + + if(arrowCount == -1) { + arrowCount = countItemsInInventory("ARROW", inventoryInfo, "quiver"); + } + if(greenCandyCount == -1) { + greenCandyCount = countItemsInInventory("GREEN_CANDY", inventoryInfo, "candy_inventory_contents"); + } + if(purpleCandyCount == -1) { + purpleCandyCount = countItemsInInventory("PURPLE_CANDY", inventoryInfo, "candy_inventory_contents"); + } + + Utils.drawItemStackWithText(NotEnoughUpdates.INSTANCE.manager.jsonToStack( + NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("ARROW")), guiLeft+173, guiTop+101, + ""+(arrowCount>999?shortNumberFormat(arrowCount, 0):arrowCount)); + Utils.drawItemStackWithText(NotEnoughUpdates.INSTANCE.manager.jsonToStack( + NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("GREEN_CANDY")), guiLeft+173, guiTop+119, ""+greenCandyCount); + Utils.drawItemStackWithText(NotEnoughUpdates.INSTANCE.manager.jsonToStack( + NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("PURPLE_CANDY")), guiLeft+173, guiTop+137, ""+purpleCandyCount); + if(mouseX > guiLeft+173 && mouseX < guiLeft+173+16) { + if(mouseY > guiTop+101 && mouseY < guiTop+137+16) { + if(mouseY < guiTop+101+17) { + tooltipToDisplay = Utils.createList(EnumChatFormatting.WHITE+"Arrow "+EnumChatFormatting.GRAY+"x"+arrowCount); + } else if(mouseY < guiTop+119+17) { + tooltipToDisplay = Utils.createList(EnumChatFormatting.GREEN+"Green Candy "+EnumChatFormatting.GRAY+"x"+greenCandyCount); + } else { + tooltipToDisplay = Utils.createList(EnumChatFormatting.DARK_PURPLE+"Purple Candy "+EnumChatFormatting.GRAY+"x"+purpleCandyCount); + } + } + } + + int inventoryRows = inventory.length; + + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + Minecraft.getMinecraft().getTextureManager().bindTexture(CHEST_GUI_TEXTURE); + + int invSizeY = inventoryRows*18+17+7; + + int x = guiLeft+320-176/2; + int y = guiTop+101-invSizeY/2; + + this.drawTexturedModalRect(x, y, 0, 0, 176, inventoryRows*18+17); + this.drawTexturedModalRect(x, y+inventoryRows*18+17, 0, 215, 176, 7); + + boolean leftHovered = false; + boolean rightHovered = false; + if(Mouse.isButtonDown(0)) { + if(mouseY > y+invSizeY && mouseY < y+invSizeY+16) { + if(mouseX > guiLeft+320-12 && mouseX < guiLeft+320+12) { + if(mouseX < guiLeft+320) { + leftHovered = true; + } else { + rightHovered = true; + } + } + } + } + Minecraft.getMinecraft().getTextureManager().bindTexture(resource_packs); + + if(currentInventoryIndex > 0) { + Utils.drawTexturedRect(guiLeft+320-12, y+invSizeY, 12, 16, + 29/256f, 53/256f, !leftHovered?0:32/256f, !leftHovered?32/256f:64/256f, GL11.GL_NEAREST); + } + if(currentInventoryIndex < inventories.length-1) { + Utils.drawTexturedRect(guiLeft+320, y+invSizeY, 12, 16, + 5/256f, 29/256f, !rightHovered?0:32/256f, !rightHovered?32/256f:64/256f, GL11.GL_NEAREST); + } + + fontRendererObj.drawString(Utils.cleanColour(invNameToDisplayMap.get(selectedInventory).getDisplayName()), x+8, y+6, 4210752); + + ItemStack stackToRender = null; + int overlay = new Color(0, 0, 0, 100).getRGB(); + for(int yIndex=0; yIndex<inventory.length; yIndex++) { + if(inventory[yIndex] == null) continue; + + for(int xIndex=0; xIndex<inventory[yIndex].length; xIndex++) { + ItemStack stack = inventory[yIndex][xIndex]; + + if(stack != null) Utils.drawItemStack(stack, x+8+xIndex*18, y+18+yIndex*18); + + if(inventoryTextField.getText() != null && !inventoryTextField.getText().isEmpty() && + (stack == null || !NotEnoughUpdates.INSTANCE.manager.doesStackMatchSearch(stack, inventoryTextField.getText()))) { + GlStateManager.translate(0, 0, 50); + drawRect(x+8+xIndex*18, y+18+yIndex*18, x+8+xIndex*18+16, y+18+yIndex*18+16, overlay); + GlStateManager.translate(0, 0, -50); + } + + if(stack == null || stack == fillerStack) continue; + + if(mouseX >= x+8+xIndex*18 && mouseX <= x+8+xIndex*18+16) { + if(mouseY >= y+18+yIndex*18 && mouseY <= y+18+yIndex*18+16) { + stackToRender = stack; + } + } + } + } + if(stackToRender == null && !SBAIntegration.isFreezeBackpack()) lastBackpack = null; + if(SBAIntegration.isFreezeBackpack()) { + if(lastBackpack != null) { + SBAIntegration.setActiveBackpack(lastBackpack, lastBackpackX, lastBackpackY); + GlStateManager.translate(0, 0, 100); + SBAIntegration.renderActiveBackpack(mouseX, mouseY, fontRendererObj); + GlStateManager.translate(0, 0, -100); + } + } else { + if(stackToRender != null) { + String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stackToRender); + boolean renderedBackpack; + if(internalname != null && (internalname.endsWith("BACKPACK") || internalname.equals("NEW_YEAR_CAKE_BAG"))) { + lastBackpack = stackToRender; + lastBackpackX = mouseX; + lastBackpackY = mouseY; + renderedBackpack = SBAIntegration.setActiveBackpack(lastBackpack, lastBackpackX, lastBackpackY); + if(renderedBackpack) { + GlStateManager.translate(0, 0, 100); + renderedBackpack = SBAIntegration.renderActiveBackpack(mouseX, mouseY, fontRendererObj); + GlStateManager.translate(0, 0, -100); + } + } else { + renderedBackpack = false; + } + if(!renderedBackpack) { + lastBackpack = null; + tooltipToDisplay = stackToRender.getTooltip(Minecraft.getMinecraft().thePlayer, false); + } + } + } + } + + private String niceUuid(String uuidStr) { + if(uuidStr.length()!=32) return uuidStr; + + StringBuilder niceAucId = new StringBuilder(); + niceAucId.append(uuidStr, 0, 8); + niceAucId.append("-"); + niceAucId.append(uuidStr, 8, 12); + niceAucId.append("-"); + niceAucId.append(uuidStr, 12, 16); + niceAucId.append("-"); + niceAucId.append(uuidStr, 16, 20); + niceAucId.append("-"); + niceAucId.append(uuidStr, 20, 32); + return niceAucId.toString(); + } + + public EntityOtherPlayerMP getEntityPlayer() { + return entityPlayer; + } + + private EntityOtherPlayerMP entityPlayer = null; + private ResourceLocation playerLocationSkin = null; + private ResourceLocation playerLocationCape = null; + private String skinType = null; + + private HashMap<String, ResourceLocation[]> panoramasMap = new HashMap<>(); + + public ResourceLocation[] getPanoramasForLocation(String location, String identifier) { + if(panoramasMap.containsKey(location+identifier)) return panoramasMap.get(location+identifier); + try { + ResourceLocation[] panoramasArray = new ResourceLocation[6]; + for(int i=0; i<6; i++) { + panoramasArray[i] = new ResourceLocation("notenoughupdates:panoramas/"+location+"_"+identifier+"/panorama_"+i+".jpg"); + Minecraft.getMinecraft().getResourceManager().getResource(panoramasArray[i]); + } + panoramasMap.put(location+identifier, panoramasArray); + return panoramasArray; + } catch(IOException e) { + try { + ResourceLocation[] panoramasArray = new ResourceLocation[6]; + for(int i=0; i<6; i++) { + panoramasArray[i] = new ResourceLocation("notenoughupdates:panoramas/"+location+"/panorama_"+i+".jpg"); + Minecraft.getMinecraft().getResourceManager().getResource(panoramasArray[i]); + } + panoramasMap.put(location+identifier, panoramasArray); + return panoramasArray; + } catch(IOException e2) { + ResourceLocation[] panoramasArray = new ResourceLocation[6]; + for(int i=0; i<6; i++) { + panoramasArray[i] = new ResourceLocation("notenoughupdates:panoramas/unknown/panorama_"+i+".jpg"); + } + panoramasMap.put(location+identifier, panoramasArray); + return panoramasArray; + } + } + } + + private TreeMap<Integer, Set<String>> topKills = null; + private TreeMap<Integer, Set<String>> topDeaths = null; + + private void drawExtraPage(int mouseX, int mouseY, float partialTicks) { + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_extra); + Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST); + + JsonObject profileInfo = profile.getProfileInformation(profileId); + if(profileInfo == null) return; + JsonObject skillInfo = profile.getSkillInfo(profileId); + + float xStart = 22; + float xOffset = 103; + float yStartTop = 27; + float yStartBottom = 109; + float yOffset = 10; + + float bankBalance = Utils.getElementAsFloat(Utils.getElement(profileInfo, "banking.balance"), 0); + float purseBalance = Utils.getElementAsFloat(Utils.getElement(profileInfo, "coin_purse"), 0); + + renderAlignedString(EnumChatFormatting.GOLD+"Bank Balance", EnumChatFormatting.WHITE.toString()+shortNumberFormat(bankBalance, 0), + guiLeft+xStart, guiTop+yStartTop, 76); + renderAlignedString(EnumChatFormatting.GOLD+"Purse", EnumChatFormatting.WHITE.toString()+shortNumberFormat(purseBalance, 0), + guiLeft+xStart, guiTop+yStartTop+yOffset, 76); + + + float fairySouls = Utils.getElementAsFloat(Utils.getElement(profileInfo, "fairy_souls_collected"), 0); + renderAlignedString(EnumChatFormatting.LIGHT_PURPLE+"Fairy Souls", EnumChatFormatting.WHITE.toString()+(int)fairySouls+"/209", + guiLeft+xStart, guiTop+yStartBottom, 76); + if(skillInfo != null) { + float totalSkillLVL = 0; + float totalTrueSkillLVL = 0; + float totalSlayerLVL = 0; + float totalSkillCount = 0; + float totalSlayerCount = 0; + + for(Map.Entry<String, JsonElement> entry : skillInfo.entrySet()) { + if(entry.getKey().startsWith("level_skill")) { + if(entry.getKey().contains("runecrafting")) continue; + if(entry.getKey().contains("carpentry")) continue; + if(entry.getKey().contains("catacombs")) continue; + + totalSkillLVL += entry.getValue().getAsFloat(); + totalTrueSkillLVL += Math.floor(entry.getValue().getAsFloat()); + totalSkillCount++; + } else if(entry.getKey().startsWith("level_slayer")) { + totalSlayerLVL += entry.getValue().getAsFloat(); + totalSlayerCount++; + } + } + + float avgSkillLVL = totalSkillLVL/totalSkillCount; + float avgTrueSkillLVL = totalTrueSkillLVL/totalSkillCount; + float avgSlayerLVL = totalSlayerLVL/totalSlayerCount; + + renderAlignedString(EnumChatFormatting.RED+"AVG Skill Level", EnumChatFormatting.WHITE.toString()+Math.floor(avgSkillLVL*10)/10, + guiLeft+xStart, guiTop+yStartBottom+yOffset, 76); + renderAlignedString(EnumChatFormatting.RED+"AVG Slayer Level", EnumChatFormatting.WHITE.toString()+Math.floor(avgSlayerLVL*10)/10, + guiLeft+xStart, guiTop+yStartBottom+yOffset*2, 76); + renderAlignedString(EnumChatFormatting.RED+"True AVG Skill Level", EnumChatFormatting.WHITE.toString()+Math.floor(avgTrueSkillLVL*10)/10, + guiLeft+xStart, guiTop+yStartBottom+yOffset*3, 76); + } + + + float auctions_bids = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_bids"), 0); + float auctions_highest_bid = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_highest_bid"), 0); + float auctions_won = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_won"), 0); + float auctions_created = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_created"), 0); + float auctions_gold_spent = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_gold_spent"), 0); + float auctions_gold_earned = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_gold_earned"), 0); + + renderAlignedString(EnumChatFormatting.DARK_PURPLE+"Auction Bids", EnumChatFormatting.WHITE.toString()+(int)auctions_bids, + guiLeft+xStart+xOffset, guiTop+yStartTop, 76); + renderAlignedString(EnumChatFormatting.DARK_PURPLE+"Highest Bid", EnumChatFormatting.WHITE.toString()+shortNumberFormat(auctions_highest_bid, 0), + guiLeft+xStart+xOffset, guiTop+yStartTop+yOffset, 76); + renderAlignedString(EnumChatFormatting.DARK_PURPLE+"Auctions Won", EnumChatFormatting.WHITE.toString()+(int)auctions_won, + guiLeft+xStart+xOffset, guiTop+yStartTop+yOffset*2, 76); + renderAlignedString(EnumChatFormatting.DARK_PURPLE+"Auctions Created", EnumChatFormatting.WHITE.toString()+(int)auctions_created, + guiLeft+xStart+xOffset, guiTop+yStartTop+yOffset*3, 76); + renderAlignedString(EnumChatFormatting.DARK_PURPLE+"Gold Spent", EnumChatFormatting.WHITE.toString()+shortNumberFormat(auctions_gold_spent, 0), + guiLeft+xStart+xOffset, guiTop+yStartTop+yOffset*4, 76); + renderAlignedString(EnumChatFormatting.DARK_PURPLE+"Gold Earned", EnumChatFormatting.WHITE.toString()+shortNumberFormat(auctions_gold_earned, 0), + guiLeft+xStart+xOffset, guiTop+yStartTop+yOffset*5, 76); + + + float zombie_boss_kills_tier_2 = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.zombie.boss_kills_tier_2"), 0); + float zombie_boss_kills_tier_3 = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.zombie.boss_kills_tier_3"), 0); + float spider_boss_kills_tier_2 = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.spider.boss_kills_tier_2"), 0); + float spider_boss_kills_tier_3 = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.spider.boss_kills_tier_3"), 0); + float wolf_boss_kills_tier_2 = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.wolf.boss_kills_tier_2"), 0); + float wolf_boss_kills_tier_3 = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.wolf.boss_kills_tier_3"), 0); + + renderAlignedString(EnumChatFormatting.DARK_AQUA+"Revenant T3", EnumChatFormatting.WHITE.toString()+(int)zombie_boss_kills_tier_2, + guiLeft+xStart+xOffset, guiTop+yStartBottom, 76); + renderAlignedString(EnumChatFormatting.DARK_AQUA+"Revenant T4", EnumChatFormatting.WHITE.toString()+(int)zombie_boss_kills_tier_3, + guiLeft+xStart+xOffset, guiTop+yStartBottom+yOffset, 76); + renderAlignedString(EnumChatFormatting.DARK_AQUA+"Sven T3", EnumChatFormatting.WHITE.toString()+(int)wolf_boss_kills_tier_2, + guiLeft+xStart+xOffset, guiTop+yStartBottom+yOffset*2, 76); + renderAlignedString(EnumChatFormatting.DARK_AQUA+"Sven T4", EnumChatFormatting.WHITE.toString()+(int)wolf_boss_kills_tier_3, + guiLeft+xStart+xOffset, guiTop+yStartBottom+yOffset*3, 76); + renderAlignedString(EnumChatFormatting.DARK_AQUA+"Tarantula T3", EnumChatFormatting.WHITE.toString()+(int)spider_boss_kills_tier_2, + guiLeft+xStart+xOffset, guiTop+yStartBottom+yOffset*4, 76); + renderAlignedString(EnumChatFormatting.DARK_AQUA+"Tarantula T4", EnumChatFormatting.WHITE.toString()+(int)spider_boss_kills_tier_3, + guiLeft+xStart+xOffset, guiTop+yStartBottom+yOffset*5, 76); + + float pet_milestone_ores_mined = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.pet_milestone_ores_mined"), 0); + float pet_milestone_sea_creatures_killed = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.pet_milestone_sea_creatures_killed"), 0); + + float items_fished = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.items_fished"), 0); + float items_fished_treasure = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.items_fished_treasure"), 0); + float items_fished_large_treasure = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.items_fished_large_treasure"), 0); + + renderAlignedString(EnumChatFormatting.GREEN+"Ores Mined", EnumChatFormatting.WHITE.toString()+(int)pet_milestone_ores_mined, + guiLeft+xStart+xOffset*2, guiTop+yStartTop, 76); + renderAlignedString(EnumChatFormatting.GREEN+"Sea Creatures Killed", EnumChatFormatting.WHITE.toString()+(int)pet_milestone_sea_creatures_killed, + guiLeft+xStart+xOffset*2, guiTop+yStartTop+yOffset, 76); + + renderAlignedString(EnumChatFormatting.GREEN+"Items Fished", EnumChatFormatting.WHITE.toString()+(int)items_fished, + guiLeft+xStart+xOffset*2, guiTop+yStartTop+yOffset*3, 76); + renderAlignedString(EnumChatFormatting.GREEN+"Treasures Fished", EnumChatFormatting.WHITE.toString()+(int)items_fished_treasure, + guiLeft+xStart+xOffset*2, guiTop+yStartTop+yOffset*4, 76); + renderAlignedString(EnumChatFormatting.GREEN+"Large Treasures", EnumChatFormatting.WHITE.toString()+(int)items_fished_large_treasure, + guiLeft+xStart+xOffset*2, guiTop+yStartTop+yOffset*5, 76); + + if(topKills == null) { + topKills = new TreeMap<>(); + JsonObject stats = profileInfo.get("stats").getAsJsonObject(); + for(Map.Entry<String, JsonElement> entry : stats.entrySet()) { + if(entry.getKey().startsWith("kills_")) { + if(entry.getValue().isJsonPrimitive()) { + JsonPrimitive prim = (JsonPrimitive) entry.getValue(); + if(prim.isNumber()) { + String name = WordUtils.capitalizeFully(entry.getKey().substring("kills_".length()).replace("_", " ")); + Set<String> kills = topKills.computeIfAbsent(prim.getAsInt(), k->new HashSet<>()); + kills.add(name); + } + } + } + } + } + if(topDeaths == null) { + topDeaths = new TreeMap<>(); + JsonObject stats = profileInfo.get("stats").getAsJsonObject(); + for(Map.Entry<String, JsonElement> entry : stats.entrySet()) { + if(entry.getKey().startsWith("deaths_")) { + if(entry.getValue().isJsonPrimitive()) { + JsonPrimitive prim = (JsonPrimitive) entry.getValue(); + if(prim.isNumber()) { + String name = WordUtils.capitalizeFully(entry.getKey().substring("deaths_".length()).replace("_", " ")); + Set<String> deaths = topDeaths.computeIfAbsent(prim.getAsInt(), k->new HashSet<>()); + deaths.add(name); + } + } + } + } + } + + int index = 0; + for(int killCount : topKills.descendingKeySet()) { + if(index >= 6) break; + Set<String> kills = topKills.get(killCount); + for(String killType : kills) { + if(index >= 6) break; + renderAlignedString(EnumChatFormatting.YELLOW+killType+" Kills", EnumChatFormatting.WHITE.toString()+killCount, + guiLeft+xStart+xOffset*3, guiTop+yStartTop+yOffset*index, 76); + index++; + } + } + index = 0; + for(int deathCount : topDeaths.descendingKeySet()) { + if(index >= 6) break; + Set<String> deaths = topDeaths.get(deathCount); + for(String deathType : deaths) { + if(index >= 6) break; + renderAlignedString(EnumChatFormatting.YELLOW+"Deaths: "+ deathType, EnumChatFormatting.WHITE.toString()+deathCount, + guiLeft+xStart+xOffset*3, guiTop+yStartBottom+yOffset*index, 76); + index++; + } + } + } + + private int backgroundClickedX = -1; + + private static char[] c = new char[]{'k', 'm', 'b', 't'}; + + public static String shortNumberFormat(double n, int iteration) { + double d = ((long) n / 100) / 10.0; + boolean isRound = (d * 10) %10 == 0; + return (d < 1000? + ((d > 99.9 || isRound || (!isRound && d > 9.99)? + (int) d * 10 / 10 : d + "" + ) + "" + c[iteration]) + : shortNumberFormat(d, iteration+1)); + } + + private void renderAlignedString(String first, String second, float x, float y, int length) { + if(fontRendererObj.getStringWidth(first + " " + second) >= length) { + for(int xOff=-2; xOff<=2; xOff++) { + for(int yOff=-2; yOff<=2; yOff++) { + if(Math.abs(xOff) != Math.abs(yOff)) { + Utils.drawStringCenteredScaledMaxWidth(Utils.cleanColourNotModifiers(first + " " + second), Minecraft.getMinecraft().fontRendererObj, + x+length/2f+xOff/2f, y+4+yOff/2f, false, length, + new Color(0, 0, 0, 200/Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB()); + } + } + } + + GlStateManager.color(1, 1, 1, 1); + Utils.drawStringCenteredScaledMaxWidth(first + " " + second, Minecraft.getMinecraft().fontRendererObj, + x+length/2f, y+4, false, length, 4210752); + } else { + for(int xOff=-2; xOff<=2; xOff++) { + for(int yOff=-2; yOff<=2; yOff++) { + if(Math.abs(xOff) != Math.abs(yOff)) { + fontRendererObj.drawString(Utils.cleanColourNotModifiers(first), + x+xOff/2f, y+yOff/2f, + new Color(0, 0, 0, 200/Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB(), false); + } + } + } + + int secondLen = fontRendererObj.getStringWidth(second); + GlStateManager.color(1, 1, 1, 1); + fontRendererObj.drawString(first, x, y, 4210752, false); + for(int xOff=-2; xOff<=2; xOff++) { + for(int yOff=-2; yOff<=2; yOff++) { + if(Math.abs(xOff) != Math.abs(yOff)) { + fontRendererObj.drawString(Utils.cleanColourNotModifiers(second), + x+length-secondLen+xOff/2f, y+yOff/2f, + new Color(0, 0, 0, 200/Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB(), false); + } + } + } + + GlStateManager.color(1, 1, 1, 1); + fontRendererObj.drawString(second, x+length-secondLen, y, 4210752, false); + } + } + + private void drawBasicPage(int mouseX, int mouseY, float partialTicks) { + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + + String location = null; + JsonObject status = profile.getPlayerStatus(); + if(status != null && status.has("mode")) { + location = status.get("mode").getAsString(); + } + + int extraRotation = 0; + if(Mouse.isButtonDown(0) || Mouse.isButtonDown(1)) { + if(backgroundClickedX == -1) { + if(mouseX > guiLeft+23 && mouseX < guiLeft+23+81) { + if(mouseY > guiTop+44 && mouseY < guiTop+44+108) { + backgroundClickedX = mouseX; + } + } + } + } else { + if(backgroundClickedX != -1) { + backgroundRotation += mouseX - backgroundClickedX; + backgroundClickedX = -1; + } + } + if(backgroundClickedX == -1) { + backgroundRotation += (currentTime - lastTime)/400f; + } else { + extraRotation = mouseX - backgroundClickedX; + } + backgroundRotation %= 360; + + String panoramaIdentifier = "day"; + if(SBInfo.getInstance().currentTimeDate != null) { + if(SBInfo.getInstance().currentTimeDate.getHours() <= 6 || + SBInfo.getInstance().currentTimeDate.getHours() >= 20) { + panoramaIdentifier = "night"; + } + } + + Panorama.drawPanorama(-backgroundRotation-extraRotation, guiLeft+23, guiTop+44, 81, 108, 0.37f, 0.8f, + getPanoramasForLocation(location==null?"unknown":location, panoramaIdentifier)); + + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_basic); + Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST); + + if(entityPlayer != null && profile.getHypixelProfile() != null) { + String playerName = null; + if(profile.getHypixelProfile().has("prefix")) { + playerName = Utils.getElementAsString(profile.getHypixelProfile().get("prefix"), "") + " " + entityPlayer.getName(); + } else { + String rank = Utils.getElementAsString(profile.getHypixelProfile().get("rank"), + Utils.getElementAsString(profile.getHypixelProfile().get("newPackageRank"), "NONE"));; + String monthlyPackageRank = Utils.getElementAsString(profile.getHypixelProfile().get("monthlyPackageRank"), "NONE"); + if(!rank.equals("YOUTUBER") && !monthlyPackageRank.equals("NONE")) { + rank = monthlyPackageRank; + } + EnumChatFormatting rankPlusColorECF = EnumChatFormatting.getValueByName(Utils.getElementAsString(profile.getHypixelProfile().get("rankPlusColor"), "WHITE")); + String rankPlusColor = EnumChatFormatting.WHITE.toString(); + if(rankPlusColorECF != null) { + rankPlusColor = rankPlusColorECF.toString(); + } + + JsonObject misc = Constants.MISC; + if(misc != null) { + if(misc.has("ranks")) { + String rankName = Utils.getElementAsString(Utils.getElement(misc, "ranks."+rank+".tag"), null); + String rankColor = Utils.getElementAsString(Utils.getElement(misc, "ranks."+rank+".color"), "7"); + String rankPlus = Utils.getElementAsString(Utils.getElement(misc, "ranks."+rank+".plus"), ""); + + String name = entityPlayer.getName(); + + if(misc.has("special_bois")) { + JsonArray special_bois = misc.get("special_bois").getAsJsonArray(); + for(int i=0; i<special_bois.size(); i++) { + if(special_bois.get(i).getAsString().equals(profile.getUuid())) { + name = Utils.chromaString(name); + break; + } + } + } + + playerName = EnumChatFormatting.GRAY.toString() + name; + if(rankName != null) { + StringBuilder sb = new StringBuilder(); + sb.append("\u00A7"+rankColor); + sb.append("["); + sb.append(rankName); + sb.append(rankPlusColor); + sb.append(rankPlus); + sb.append("\u00A7"+rankColor); + sb.append("] "); + sb.append(name); + playerName = sb.toString(); + } + } + } + + } + if(playerName != null) { + int rankPrefixLen = fr.getStringWidth(playerName); + int halfRankPrefixLen = rankPrefixLen/2; + + int x = guiLeft+63; + int y = guiTop+54; + + drawRect(x-halfRankPrefixLen-1, y-1, x+halfRankPrefixLen+1, y+8, new Color(0, 0, 0, 64).getRGB()); + + fr.drawString(playerName, x-halfRankPrefixLen, y, 0, true); + } + } + + long networth = profile.getNetWorth(profileId); + if(networth > 0) { + Utils.drawStringCentered(EnumChatFormatting.GREEN+"Net Worth: "+EnumChatFormatting.GOLD+numberFormat.format(networth), fr, guiLeft+63, guiTop+38, true, 0); + try { + double networthInCookies = (networth / NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo("BOOSTER_COOKIE").get("avg_buy").getAsDouble()); + String networthIRLMoney = Long.toString(Math.round(((networthInCookies * 325) / 675) * 4.99)); + + if(mouseX > guiLeft+8 && mouseX < guiLeft+8+fontRendererObj.getStringWidth("Net Worth: " + numberFormat.format(networth))) { + if(mouseY > guiTop+32 && mouseY < guiTop+32+fontRendererObj.FONT_HEIGHT) { + tooltipToDisplay = new ArrayList<>(); + tooltipToDisplay.add(EnumChatFormatting.GREEN+"Net worth in IRL money: "+EnumChatFormatting.DARK_GREEN+"$" +EnumChatFormatting.GOLD+networthIRLMoney); + tooltipToDisplay.add(""); + if(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) { + tooltipToDisplay.add(EnumChatFormatting.RED+"This is calculated using the current"); + tooltipToDisplay.add(EnumChatFormatting.RED+"price of booster cookies on bazaar and the price"); + tooltipToDisplay.add(EnumChatFormatting.RED+"for cookies using gems, then the price of gems"); + tooltipToDisplay.add(EnumChatFormatting.RED+"is where we get the amount of IRL money you" ); + tooltipToDisplay.add(EnumChatFormatting.RED+"theoretically have on skyblock in net worth."); + } else { + tooltipToDisplay.add(EnumChatFormatting.GRAY+"[SHIFT for Info]"); + } + tooltipToDisplay.add(""); + tooltipToDisplay.add(EnumChatFormatting.RED+"THIS IS IN NO WAY ENDORSING IRL TRADING!"); + + } + } + } catch(Exception e){} + } + + if(status != null) { + JsonElement onlineElement = Utils.getElement(status, "online"); + boolean online = onlineElement != null && onlineElement.isJsonPrimitive() && onlineElement.getAsBoolean(); + String statusStr = online ? EnumChatFormatting.GREEN + "ONLINE" : EnumChatFormatting.RED + "OFFLINE"; + String locationStr = null; + if(profile.getUuid().equals("20934ef9488c465180a78f861586b4cf")) { + locationStr = "Ignoring DMs"; + } else { + if(location != null) { + JsonObject misc = Constants.MISC; + if(misc != null) { + locationStr = Utils.getElementAsString(Utils.getElement(misc, "area_names."+location), "Unknown"); + } + } + } + if(locationStr != null) { + statusStr += EnumChatFormatting.GRAY+" - "+EnumChatFormatting.GREEN+locationStr; + } + + Utils.drawStringCentered(statusStr, fr, guiLeft+63, guiTop+160, true, 0); + } + + if(entityPlayer == null) { + UUID playerUUID = UUID.fromString(niceUuid(profile.getUuid())); + GameProfile fakeProfile = Minecraft.getMinecraft().getSessionService().fillProfileProperties(new GameProfile(playerUUID, "CoolGuy123"), false); + entityPlayer = new EntityOtherPlayerMP(Minecraft.getMinecraft().theWorld, fakeProfile) { + public ResourceLocation getLocationSkin() { + return playerLocationSkin == null ? DefaultPlayerSkin.getDefaultSkin(this.getUniqueID()) : playerLocationSkin; + } + + public ResourceLocation getLocationCape() { + return playerLocationCape; + } + + public String getSkinType() { + return skinType == null ? DefaultPlayerSkin.getSkinType(this.getUniqueID()) : skinType; + } + }; + entityPlayer.setAlwaysRenderNameTag(false); + entityPlayer.setCustomNameTag(""); + } else { + entityPlayer.refreshDisplayName(); + byte b = 0; + for(EnumPlayerModelParts part : EnumPlayerModelParts.values()) { + b |= part.getPartMask(); + } + entityPlayer.getDataWatcher().updateObject(10, b); + } + + JsonObject profileInfo = profile.getProfileInformation(profileId); + if(profileInfo == null) return; + + JsonObject skillInfo = profile.getSkillInfo(profileId); + JsonObject inventoryInfo = profile.getInventoryInfo(profileId); + + if(backgroundClickedX != -1 && Mouse.isButtonDown(1)) { + for(int i=0; i<entityPlayer.inventory.armorInventory.length; i++) { + entityPlayer.inventory.armorInventory[i] = null; + } + } else { + if(inventoryInfo != null && inventoryInfo.has("inv_armor")) { + JsonArray items = inventoryInfo.get("inv_armor").getAsJsonArray(); + if(items != null && items.size() == 4) { + for(int i=0; i<entityPlayer.inventory.armorInventory.length; i++) { + JsonElement itemElement = items.get(i); + if(itemElement != null && itemElement.isJsonObject()) { + entityPlayer.inventory.armorInventory[i] = NotEnoughUpdates.INSTANCE.manager.jsonToStack(itemElement.getAsJsonObject(), false); + } + } + } + } + } + + if(playerLocationSkin == null) { + try { + Minecraft.getMinecraft().getSkinManager().loadProfileTextures(entityPlayer.getGameProfile(), new SkinManager.SkinAvailableCallback() { + public void skinAvailable(MinecraftProfileTexture.Type type, ResourceLocation location, MinecraftProfileTexture profileTexture) { + switch (type) { + case SKIN: + playerLocationSkin = location; + skinType = profileTexture.getMetadata("model"); + + if(skinType == null) { + skinType = "default"; + } + + break; + case CAPE: + playerLocationCape = location; + } + } + }, false); + } catch(Exception e){} + } + + GlStateManager.color(1, 1, 1, 1); + JsonObject petsInfo = profile.getPetsInfo(profileId); + if(petsInfo != null) { + JsonElement activePetElement = petsInfo.get("active_pet"); + if(activePetElement != null && activePetElement.isJsonObject()) { + JsonObject activePet = activePetElement.getAsJsonObject(); + + String type = activePet.get("type").getAsString(); + + for(int i=0; i<4; i++) { + JsonObject item = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(type+";"+i); + if(item != null) { + int x = guiLeft+50; + float y = guiTop+82+15*(float)Math.sin(((currentTime-startTime)/800f)%(2*Math.PI)); + GlStateManager.translate(x, y, 0); + ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(item, false); + + //Remove extra attributes so no CIT + NBTTagCompound stackTag = stack.getTagCompound()==null?new NBTTagCompound():stack.getTagCompound(); + stackTag.removeTag("ExtraAttributes"); + stack.setTagCompound(stackTag); + + GlStateManager.scale(-1.5f, 1.5f, 1); + GlStateManager.enableDepth(); + Utils.drawItemStack(stack, 0, 0); + GlStateManager.scale(-1/1.5f, 1/1.5f, 1); + GlStateManager.translate(-x, -y, 0); + break; + } + } + } + } + drawEntityOnScreen(guiLeft+63, guiTop+128+7, 36, guiLeft+63-mouseX, guiTop+129-mouseY, entityPlayer); + + PlayerStats.Stats stats = profile.getStats(profileId); + + if(stats != null) { + Splitter splitter = Splitter.on(" ").omitEmptyStrings().limit(2); + for(int i=0; i<PlayerStats.defaultStatNames.length; i++) { + String statName = PlayerStats.defaultStatNames[i]; + String statNamePretty = PlayerStats.defaultStatNamesPretty[i]; + + int val = Math.round(stats.get(statName)); + + GlStateManager.color(1, 1, 1, 1); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + renderAlignedString(statNamePretty, EnumChatFormatting.WHITE.toString()+val, guiLeft+132, guiTop+32+12.5f*i, 80); + + if(mouseX > guiLeft+132 && mouseX < guiLeft+212) { + if(mouseY > guiTop+32+12.5f*i && mouseY < guiTop+40+12.5f*i) { + List<String> split = splitter.splitToList(statNamePretty); + PlayerStats.Stats baseStats = PlayerStats.getBaseStats(); + tooltipToDisplay = new ArrayList<>(); + tooltipToDisplay.add(statNamePretty); + int base = Math.round(baseStats.get(statName)); + tooltipToDisplay.add(EnumChatFormatting.GRAY+"Base "+split.get(1)+": "+EnumChatFormatting.GREEN+base+" "+split.get(0)); + int passive = Math.round(profile.getPassiveStats(profileId).get(statName)-baseStats.get(statName)); + tooltipToDisplay.add(EnumChatFormatting.GRAY+"Passive "+split.get(1)+" Bonus: +"+EnumChatFormatting.YELLOW+passive+" "+split.get(0)); + int itemBonus = Math.round(stats.get(statName)-profile.getPassiveStats(profileId).get(statName)); + tooltipToDisplay.add(EnumChatFormatting.GRAY+"Item "+split.get(1)+" Bonus: +"+EnumChatFormatting.DARK_PURPLE+itemBonus+" "+split.get(0)); + int finalStat = Math.round(stats.get(statName)); + tooltipToDisplay.add(EnumChatFormatting.GRAY+"Final "+split.get(1)+": +"+EnumChatFormatting.RED+finalStat+" "+split.get(0)); + } + } + } + } else { + Utils.drawStringCentered(EnumChatFormatting.RED+"Skill/Inv/Coll", Minecraft.getMinecraft().fontRendererObj, + guiLeft+172, guiTop+101-10, true, 0); + Utils.drawStringCentered(EnumChatFormatting.RED+"APIs not", Minecraft.getMinecraft().fontRendererObj, + guiLeft+172, guiTop+101, true, 0); + Utils.drawStringCentered(EnumChatFormatting.RED+"enabled!", Minecraft.getMinecraft().fontRendererObj, + guiLeft+172, guiTop+101+10, true, 0); + } + + if(skillInfo != null) { + int position = 0; + for(Map.Entry<String, ItemStack> entry : ProfileViewer.getSkillToSkillDisplayMap().entrySet()) { + if(entry.getValue() == null || entry.getKey() == null) { + position++; + continue; + } + + int yPosition = position % 7; + int xPosition = position / 7; + + String skillName = entry.getValue().getDisplayName(); + + float level = Utils.getElementAsFloat(skillInfo.get("level_"+entry.getKey()), 0); + int levelFloored = (int)Math.floor(level); + + int x = guiLeft+237+86*xPosition; + int y = guiTop+31+21*yPosition; + + renderAlignedString(skillName, EnumChatFormatting.WHITE.toString()+levelFloored, x+14, y-4, 60); + + if(skillInfo.get("maxed_"+entry.getKey()).getAsBoolean()) { + renderGoldBar(x, y+6, 80); + } else { + renderBar(x, y+6, 80, level%1); + } + + if(mouseX > x && mouseX < x+80) { + if(mouseY > y-4 && mouseY < y+13) { + String levelStr; + if(skillInfo.get("maxed_"+entry.getKey()).getAsBoolean()) { + levelStr = EnumChatFormatting.GOLD+"MAXED!"; + } else { + int maxXp = (int)skillInfo.get("maxxp_"+entry.getKey()).getAsFloat(); + levelStr = EnumChatFormatting.DARK_PURPLE.toString() + shortNumberFormat(Math.round((level%1)*maxXp), 0) + "/" + shortNumberFormat(maxXp, 0); + } + + tooltipToDisplay = Utils.createList(levelStr); + } + } + + GL11.glTranslatef((x), (y-6f), 0); + GL11.glScalef(0.7f, 0.7f, 1); + Utils.drawItemStackLinear(entry.getValue(), 0, 0); + GL11.glScalef(1/0.7f, 1/0.7f, 1); + GL11.glTranslatef(-(x), -(y-6f), 0); + + position++; + } + } else { + Utils.drawStringCentered(EnumChatFormatting.RED+"Skills API not enabled!", Minecraft.getMinecraft().fontRendererObj, + guiLeft+322, guiTop+101, true, 0); + } + } + + private void renderGoldBar(float x, float y, float xSize) { + if(!OpenGlHelper.areShadersSupported()) { + renderBar(x, y, xSize, 1); + return; + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(icons); + ShaderManager shaderManager = ShaderManager.getInstance(); + shaderManager.loadShader("make_gold"); + shaderManager.loadData("make_gold", "amount", (startTime-System.currentTimeMillis())/10000f); + + Utils.drawTexturedRect(x, y, xSize/2f, 5, 0/256f, (xSize/2f)/256f, 79/256f, 84/256f, GL11.GL_NEAREST); + Utils.drawTexturedRect(x+xSize/2f, y, xSize/2f, 5, (182-xSize/2f)/256f, 182/256f, 79/256f, 84/256f, GL11.GL_NEAREST); + + GL20.glUseProgram(0); + } + + private void renderBar(float x, float y, float xSize, float completed) { + Minecraft.getMinecraft().getTextureManager().bindTexture(icons); + + completed = Math.round(completed/0.05f)*0.05f; + + float notcompleted = 1-completed; + + int displayNum = 0;//tl.x%5; + + GlStateManager.color(1, 1, 1, 1); + float width = 0; + + if(completed < 0.5f && (displayNum == 1 || displayNum == 0)) { + width = (0.5f - completed) * xSize; + Utils.drawTexturedRect(x+xSize*completed, y, width, 5, xSize*completed/256f, (xSize/2f)/256f, 74/256f, 79/256f, GL11.GL_NEAREST); + } + if(completed < 1f && (displayNum == 2 || displayNum == 0)) { + width = Math.min(xSize*notcompleted, xSize/2f); + Utils.drawTexturedRect(x+(xSize/2f)+Math.max(xSize*(completed-0.5f), 0), y, width, 5, + (182-(xSize/2f)+Math.max(xSize*(completed-0.5f), 0))/256f, 182/256f, 74/256f, 79/256f, GL11.GL_NEAREST); + } + + if(completed > 0f && (displayNum == 3 || displayNum == 0)) { + width = Math.min(xSize*completed, xSize/2f); + Utils.drawTexturedRect(x, y, width, 5, + 0/256f, width/256f, 79/256f, 84/256f, GL11.GL_NEAREST); + } + if(completed > 0.5f && (displayNum == 4 || displayNum == 0)) { + width = Math.min(xSize*(completed-0.5f), xSize/2f); + Utils.drawTexturedRect(x+(xSize/2f), y, width, 5, + (182-(xSize/2f))/256f, (182-(xSize/2f)+width)/256f, 79/256f, 84/256f, GL11.GL_NEAREST); + } + } + + private static final ResourceLocation shadowTextures = new ResourceLocation("textures/misc/shadow.png"); + public static void drawEntityOnScreen(int posX, int posY, int scale, float mouseX, float mouseY, EntityLivingBase ent) { + GlStateManager.enableColorMaterial(); + GlStateManager.pushMatrix(); + GlStateManager.translate((float)posX, (float)posY, 50.0F); + GlStateManager.scale((float)(-scale), (float)scale, (float)scale); + GlStateManager.rotate(180.0F, 0.0F, 0.0F, 1.0F); + float renderYawOffset = ent.renderYawOffset; + float f1 = ent.rotationYaw; + float f2 = ent.rotationPitch; + float f3 = ent.prevRotationYawHead; + float f4 = ent.rotationYawHead; + GlStateManager.rotate(135.0F, 0.0F, 1.0F, 0.0F); + RenderHelper.enableStandardItemLighting(); + GlStateManager.rotate(-135.0F, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(25, 1.0F, 0.0F, 0.0F); + ent.renderYawOffset = (float)Math.atan((double)(mouseX / 40.0F)) * 20.0F; + ent.rotationYaw = (float)Math.atan((double)(mouseX / 40.0F)) * 40.0F; + ent.rotationPitch = -((float)Math.atan((double)(mouseY / 40.0F))) * 20.0F; + ent.rotationYawHead = ent.rotationYaw; + ent.prevRotationYawHead = ent.rotationYaw; + RenderManager rendermanager = Minecraft.getMinecraft().getRenderManager(); + rendermanager.setPlayerViewY(180.0F); + rendermanager.setRenderShadow(false); + rendermanager.renderEntityWithPosYaw(ent, 0.0D, 0.0D, 0.0D, 0.0F, 1.0F); + + /*{ + GlStateManager.enableBlend(); + GlStateManager.blendFunc(770, 771); + rendermanager.renderEngine.bindTexture(shadowTextures); + GlStateManager.depthMask(false); + float f = 0.5f; + + if (ent instanceof EntityLiving) { + EntityLiving entityliving = (EntityLiving)ent; + f *= entityliving.getRenderSizeModifier(); + + if (entityliving.isChild()) + { + f *= 0.5F; + } + } + + /*Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + + GlStateManager.color(1, 1, 1, 0.5f); + Utils.drawTexturedRect(-0.5f*tl.x, -0.5f*tl.x, 1*tl.x, 1*tl.x); + + /*for (BlockPos blockpos : BlockPos.getAllInBoxMutable(new BlockPos(i, k, i1), new BlockPos(j, l, j1))) { + Block block = world.getBlockState(blockpos.down()).getBlock(); + + if (block.getRenderType() != -1 && world.getLightFromNeighbors(blockpos) > 3) { + this.func_180549_a(block, x, y, z, blockpos, shadowAlpha, f, d2, d3, d4); + } + } + + GlStateManager.disableBlend(); + GlStateManager.depthMask(true); + }*/ + + ent.renderYawOffset = renderYawOffset; + ent.rotationYaw = f1; + ent.rotationPitch = f2; + ent.prevRotationYawHead = f3; + ent.rotationYawHead = f4; + GlStateManager.popMatrix(); + RenderHelper.disableStandardItemLighting(); + GlStateManager.disableRescaleNormal(); + GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit); + GlStateManager.disableTexture2D(); + GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit); + } + + public void resetCache() { + bestWeapons = null; + bestRods = null; + armorItems = null; + inventoryItems = new HashMap<>(); + currentInventoryIndex = 0; + arrowCount = -1; + greenCandyCount = -1; + purpleCandyCount = -1; + entityPlayer = null; + playerLocationSkin = null; + playerLocationCape = null; + skinType = null; + petsPage = 0; + sortedPets = null; + sortedPetsStack = null; + selectedPet = -1; + } + + Shader blurShaderHorz = null; + Framebuffer blurOutputHorz = null; + Shader blurShaderVert = null; + Framebuffer blurOutputVert = null; + + /** + * Creates a projection matrix that projects from our coordinate space [0->width; 0->height] to OpenGL coordinate + * space [-1 -> 1; 1 -> -1] (Note: flipped y-axis). + * + * This is so that we can render to and from the framebuffer in a way that is familiar to us, instead of needing to + * apply scales and translations manually. + */ + private Matrix4f createProjectionMatrix(int width, int height) { + Matrix4f projMatrix = new Matrix4f(); + projMatrix.setIdentity(); + projMatrix.m00 = 2.0F / (float)width; + projMatrix.m11 = 2.0F / (float)(-height); + projMatrix.m22 = -0.0020001999F; + projMatrix.m33 = 1.0F; + projMatrix.m03 = -1.0F; + projMatrix.m13 = 1.0F; + projMatrix.m23 = -1.0001999F; + return projMatrix; + } + + /** + * Renders whatever is currently in the Minecraft framebuffer to our two framebuffers, applying a horizontal + * and vertical blur separately in order to significantly save computation time. + * This is only possible if framebuffers are supported by the system, so this method will exit prematurely + * if framebuffers are not available. (Apple machines, for example, have poor framebuffer support). + */ + private double lastBgBlurFactor = -1; + private void blurBackground() { + if(!OpenGlHelper.isFramebufferEnabled()) return; + + int width = Minecraft.getMinecraft().displayWidth; + int height = Minecraft.getMinecraft().displayHeight; + + if(blurOutputHorz == null) { + blurOutputHorz = new Framebuffer(width, height, false); + blurOutputHorz.setFramebufferFilter(GL11.GL_NEAREST); + } + if(blurOutputVert == null) { + blurOutputVert = new Framebuffer(width, height, false); + blurOutputVert.setFramebufferFilter(GL11.GL_NEAREST); + } + if(blurOutputHorz.framebufferWidth != width || blurOutputHorz.framebufferHeight != height) { + blurOutputHorz.createBindFramebuffer(width, height); + blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + if(blurOutputVert.framebufferWidth != width || blurOutputVert.framebufferHeight != height) { + blurOutputVert.createBindFramebuffer(width, height); + blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height)); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + + if(blurShaderHorz == null) { + try { + blurShaderHorz = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", + Minecraft.getMinecraft().getFramebuffer(), blurOutputHorz); + blurShaderHorz.getShaderManager().getShaderUniform("BlurDir").set(1, 0); + blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); + } catch(Exception e) { } + } + if(blurShaderVert == null) { + try { + blurShaderVert = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", + blurOutputHorz, blurOutputVert); + blurShaderVert.getShaderManager().getShaderUniform("BlurDir").set(0, 1); + blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height)); + } catch(Exception e) { } + } + if(blurShaderHorz != null && blurShaderVert != null) { + if(15 != lastBgBlurFactor) { + blurShaderHorz.getShaderManager().getShaderUniform("Radius").set((float)15); + blurShaderVert.getShaderManager().getShaderUniform("Radius").set((float)15); + lastBgBlurFactor = 15; + } + GL11.glPushMatrix(); + blurShaderHorz.loadShader(0); + blurShaderVert.loadShader(0); + GlStateManager.enableDepth(); + GL11.glPopMatrix(); + + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + } + + /** + * Renders a subsection of the blurred framebuffer on to the corresponding section of the screen. + * Essentially, this method will "blur" the background inside the bounds specified by [x->x+blurWidth, y->y+blurHeight] + */ + public void renderBlurredBackground(int width, int height, int x, int y, int blurWidth, int blurHeight) { + if(!OpenGlHelper.isFramebufferEnabled()) return; + + float uMin = x/(float)width; + float uMax = (x+blurWidth)/(float)width; + float vMin = (height-y)/(float)height; + float vMax = (height-y-blurHeight)/(float)height; + + blurOutputVert.bindFramebufferTexture(); + GlStateManager.color(1f, 1f, 1f, 1f); + //Utils.setScreen(width*f, height*f, f); + Utils.drawTexturedRect(x, y, blurWidth, blurHeight, uMin, uMax, vMin, vMax); + //Utils.setScreen(width, height, f); + blurOutputVert.unbindFramebufferTexture(); + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java new file mode 100644 index 00000000..379935ad --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java @@ -0,0 +1,157 @@ +package io.github.moulberry.notenoughupdates.profileviewer; + +import io.github.moulberry.notenoughupdates.util.TexLoc; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.glu.Project; + +public class Panorama { + + private static TexLoc tl = new TexLoc(97, 19, Keyboard.KEY_P); + private static TexLoc tl2 = new TexLoc(37, 80, Keyboard.KEY_L); + + private static ResourceLocation backgroundTexture = null; + + private static int lastWidth = 0; + private static int lastHeight = 0; + + public static void drawPanorama(float angle, int x, int y, int width, int height, float yOffset, float zOffset, ResourceLocation[] panoramas) { + if(!OpenGlHelper.isFramebufferEnabled()) { + Minecraft.getMinecraft().getTextureManager().bindTexture(panoramas[0]); + + float aspect = width/(float)height; + Utils.drawTexturedRect(x, y, width, height, 0.5f-aspect/2, 0.5f+aspect/2, 0, 1); + + return; + } + + Minecraft.getMinecraft().getFramebuffer().unbindFramebuffer(); + + ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + + GL11.glViewport(0, 0, width*scaledresolution.getScaleFactor(), height*scaledresolution.getScaleFactor()); + + float fov = 97; + + { + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + GlStateManager.matrixMode(5889); + GlStateManager.pushMatrix(); + GlStateManager.loadIdentity(); + Project.gluPerspective(fov, (float)height/width, 0.05F, 10.0F); + GlStateManager.matrixMode(5888); + GlStateManager.pushMatrix(); + GlStateManager.loadIdentity(); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + GlStateManager.rotate(180F, 1.0F, 0.0F, 0.0F); + GlStateManager.rotate(90, 0.0F, 0.0F, 1.0F); + GlStateManager.rotate(19, 1.0F, 0.0F, 0.0F); + //GlStateManager.rotate(tl.x, 0.0F, 0.0F, 1.0F); + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.disableCull(); + GlStateManager.depthMask(false); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + + GlStateManager.pushMatrix(); + + GlStateManager.translate(0, yOffset, zOffset); + + GlStateManager.rotate(angle, 0.0F, 1.0F, 0.0F); + + for (int k = 0; k < 6; ++k) { + GlStateManager.pushMatrix(); + + switch (k) { + case 1: + GlStateManager.rotate(90.0F, 0.0F, 1.0F, 0.0F); break; + case 2: + GlStateManager.rotate(180.0F, 0.0F, 1.0F, 0.0F); break; + case 3: + GlStateManager.rotate(-90.0F, 0.0F, 1.0F, 0.0F); break; + case 4: + GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F); break; + case 5: + GlStateManager.rotate(-90.0F, 1.0F, 0.0F, 0.0F); break; + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(panoramas[k]); + float splits = 0.1f; + for(float x1=0; x1<1; x1+=splits) { + for(float y1=0; y1<1; y1+=splits) { + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + + for(int i=0; i<4; i++) { + float x2 = (i == 0 || i == 3) ? x1 : x1+splits; + float y2 = (i >= 2) ? y1 : y1+splits; + + float xr = x2*2-1; + float yr = y2*2-1; + + float distSq = xr*xr+yr*yr+1; + float scale = (float)Math.sqrt(3/distSq); + + worldrenderer.pos(xr*scale , yr*scale , scale).tex(x2, y2).color(255, 255, 255, 255).endVertex(); + + } + + tessellator.draw(); + } + } + + GlStateManager.popMatrix(); + } + + GlStateManager.popMatrix(); + GlStateManager.colorMask(true, true, true, false); + + worldrenderer.setTranslation(0.0D, 0.0D, 0.0D); + GlStateManager.colorMask(true, true, true, true); + GlStateManager.matrixMode(5889); + GlStateManager.popMatrix(); + GlStateManager.matrixMode(5888); + GlStateManager.popMatrix(); + GlStateManager.depthMask(true); + GlStateManager.enableCull(); + GlStateManager.enableDepth(); + } + + if(backgroundTexture == null || lastWidth != width*scaledresolution.getScaleFactor() || lastHeight != height*scaledresolution.getScaleFactor()) { + DynamicTexture viewportTexture = new DynamicTexture(width*scaledresolution.getScaleFactor(), height*scaledresolution.getScaleFactor()); + backgroundTexture = Minecraft.getMinecraft().getTextureManager().getDynamicTextureLocation("background", viewportTexture); + lastWidth = width*scaledresolution.getScaleFactor(); + lastHeight = height*scaledresolution.getScaleFactor(); + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(backgroundTexture); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, width*scaledresolution.getScaleFactor(), height*scaledresolution.getScaleFactor()); + + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true); + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer.pos(x, y+height, 0) + .tex(0, 1).endVertex(); + worldrenderer.pos(x+width, y+height, 0) + .tex(0, 0).endVertex(); + worldrenderer.pos(x+width, y, 0) + .tex(1, 0).endVertex(); + worldrenderer.pos(x, y, 0) + .tex(1, 1).endVertex(); + tessellator.draw(); + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java new file mode 100644 index 00000000..5223e127 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java @@ -0,0 +1,514 @@ +package io.github.moulberry.notenoughupdates.profileviewer; + +import com.google.gson.*; +import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.nbt.*; +import net.minecraft.util.EnumChatFormatting; +import org.apache.commons.lang3.StringUtils; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Base64; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PlayerStats { + public static final String HEALTH = "health"; + public static final String DEFENCE = "defence"; + public static final String STRENGTH = "strength"; + public static final String SPEED = "speed"; + public static final String CRIT_CHANCE = "crit_chance"; + public static final String CRIT_DAMAGE = "crit_damage"; + public static final String BONUS_ATTACK_SPEED = "bonus_attack_speed"; + public static final String INTELLIGENCE = "intelligence"; + public static final String SEA_CREATURE_CHANCE = "sea_creature_chance"; + public static final String MAGIC_FIND = "magic_find"; + public static final String PET_LUCK = "pet_luck"; + + public static final String[] defaultStatNames = new String[]{"health","defence","strength","speed","crit_chance", + "crit_damage","bonus_attack_speed","intelligence","sea_creature_chance","magic_find","pet_luck"}; + public static final String[] defaultStatNamesPretty = new String[]{EnumChatFormatting.RED+"\u2764 Health",EnumChatFormatting.GREEN+"\u2748 Defence", + EnumChatFormatting.RED+"\u2741 Strength",EnumChatFormatting.WHITE+"\u2726 Speed",EnumChatFormatting.BLUE+"\u2623 Crit Chance", + EnumChatFormatting.BLUE+"\u2620 Crit Damage",EnumChatFormatting.YELLOW+"\u2694 Attack Speed",EnumChatFormatting.AQUA+"\u270e Intelligence", + EnumChatFormatting.DARK_AQUA+"\u03b1 SC Chance",EnumChatFormatting.AQUA+"\u272f Magic Find",EnumChatFormatting.LIGHT_PURPLE+"\u2663 Pet Luck"}; + + public static class Stats { + JsonObject statsJson = new JsonObject(); + + /*public float health; + public float defence; + public float strength; + public float speed; + public float crit_chance; + public float crit_damage; + public float bonus_attack_speed; + public float intelligence; + public float sea_creature_chance; + public float magic_find; + public float pet_luck;*/ + + public Stats(Stats... statses) { + for(Stats stats : statses) { + add(stats); + } + } + + /*@Override + public String toString() { + return String.format("{health=%s,defence=%s,strength=%s,speed=%s,crit_chance=%s,crit_damage=%s," + + "bonus_attack_speed=%s,intelligence=%s,sea_creature_chance=%s,magic_find=%s,pet_luck=%s}", + stats.get("health"), defence, strength, speed, crit_chance, crit_damage, bonus_attack_speed, intelligence, + sea_creature_chance, magic_find, pet_luck); + }*/ + + public float get(String statName) { + if(statsJson.has(statName)) { + return statsJson.get(statName).getAsFloat(); + } else { + return 0; + } + } + + public Stats add(Stats stats) { + for(Map.Entry<String, JsonElement> statEntry : stats.statsJson.entrySet()) { + if(statEntry.getValue().isJsonPrimitive() && ((JsonPrimitive)statEntry.getValue()).isNumber()) { + if(!statsJson.has(statEntry.getKey())) { + statsJson.add(statEntry.getKey(), statEntry.getValue()); + } else { + JsonPrimitive e = statsJson.get(statEntry.getKey()).getAsJsonPrimitive(); + float statNum = e.getAsFloat() + statEntry.getValue().getAsFloat(); + statsJson.add(statEntry.getKey(), new JsonPrimitive(statNum)); + } + } + } + return this; + } + + public void scaleAll(float scale) { + for(Map.Entry<String, JsonElement> statEntry : statsJson.entrySet()) { + statsJson.add(statEntry.getKey(), new JsonPrimitive(statEntry.getValue().getAsFloat()*scale)); + } + } + + public void addStat(String statName, float amount) { + if(!statsJson.has(statName)) { + statsJson.add(statName, new JsonPrimitive(amount)); + } else { + JsonPrimitive e = statsJson.get(statName).getAsJsonPrimitive(); + statsJson.add(statName, new JsonPrimitive(e.getAsFloat() + amount)); + } + } + } + + public static Stats getBaseStats() { + JsonObject misc = Constants.MISC; + if(misc == null) return null; + + Stats stats = new Stats(); + for(String statName : defaultStatNames) { + stats.addStat(statName, Utils.getElementAsFloat(Utils.getElement(misc, "base_stats."+statName), 0)); + } + return stats; + } + + private static Stats getFairyBonus(int fairyExchanges) { + Stats bonus = new Stats(); + + bonus.addStat(SPEED, fairyExchanges/10); + + for(int i=0; i<fairyExchanges; i++) { + bonus.addStat(STRENGTH, (i + 1) % 5 == 0 ? 2 : 1); + bonus.addStat(DEFENCE, (i + 1) % 5 == 0 ? 2 : 1); + bonus.addStat(HEALTH, 3 + i / 2); + } + + return bonus; + } + + private static Stats getSkillBonus(JsonObject skillInfo) { + JsonObject bonuses = Constants.BONUSES; + if(bonuses == null) return null; + + Stats skillBonus = new Stats(); + + for(Map.Entry<String, JsonElement> entry : skillInfo.entrySet()) { + if(entry.getKey().startsWith("level_")) { + String skill = entry.getKey().substring("level_".length()); + JsonElement element = Utils.getElement(bonuses, "bonus_stats."+skill); + if(element != null && element.isJsonObject()) { + JsonObject skillStatMap = element.getAsJsonObject(); + + Stats currentBonus = new Stats(); + for(int i=1; i<=entry.getValue().getAsFloat(); i++) { + if(skillStatMap.has(""+i)) { + currentBonus = new Stats(); + for(Map.Entry<String, JsonElement> entry2 : skillStatMap.get(""+i).getAsJsonObject().entrySet()) { + currentBonus.addStat(entry2.getKey(), entry2.getValue().getAsFloat()); + } + } + skillBonus.add(currentBonus); + } + } + } + } + + return skillBonus; + } + + private static Stats getPetBonus(JsonObject profile) { + JsonObject bonuses = Constants.BONUSES; + if(bonuses == null) return null; + + JsonElement petsElement = Utils.getElement(profile, "pets"); + if(petsElement == null) return new Stats(); + + JsonArray pets = petsElement.getAsJsonArray(); + + HashMap<String, String> highestRarityMap = new HashMap<>(); + + for(int i=0; i<pets.size(); i++) { + JsonObject pet = pets.get(i).getAsJsonObject(); + highestRarityMap.put(pet.get("type").getAsString(), pet.get("tier").getAsString()); + } + + int petScore = 0; + for(String value : highestRarityMap.values()) { + petScore += Utils.getElementAsFloat(Utils.getElement(bonuses, "pet_value."+value.toUpperCase()), 0); + } + + JsonElement petRewardsElement = Utils.getElement(bonuses, "pet_rewards"); + if(petRewardsElement == null) return null; + JsonObject petRewards = petRewardsElement.getAsJsonObject(); + + Stats petBonus = new Stats(); + for(int i=0; i<=petScore; i++) { + if(petRewards.has(""+i)) { + petBonus = new Stats(); + for(Map.Entry<String, JsonElement> entry : petRewards.get(""+i).getAsJsonObject().entrySet()) { + petBonus.addStat(entry.getKey(), entry.getValue().getAsFloat()); + } + } + } + return petBonus; + } + + private static float harpBonus(JsonObject profile) { + String talk_to_melody = Utils.getElementAsString(Utils.getElement(profile, "objectives.talk_to_melody.status"), "INCOMPLETE"); + if(talk_to_melody.equalsIgnoreCase("COMPLETE")) { + return 26; + } else { + return 0; + } + } + + + public static Stats getPassiveBonuses(JsonObject skillInfo, JsonObject profile) { + Stats passiveBonuses = new Stats(); + + Stats fairyBonus = getFairyBonus((int)Utils.getElementAsFloat(Utils.getElement(profile, "fairy_exchanges"), 0)); + Stats skillBonus = getSkillBonus(skillInfo); + Stats petBonus = getPetBonus(profile); + + if(fairyBonus == null || skillBonus == null || petBonus == null) { + System.out.println(petBonus); + return null; + } + + passiveBonuses.add(fairyBonus); + passiveBonuses.add(skillBonus); + passiveBonuses.addStat(INTELLIGENCE, harpBonus(profile)); + passiveBonuses.add(petBonus); + + return passiveBonuses; + } + + private static String getFullset(JsonArray armor, int ignore) { + String fullset = null; + for(int i=0; i<armor.size(); i++) { + if(i == ignore) continue; + + JsonElement itemElement = armor.get(i); + if(itemElement == null || !itemElement.isJsonObject()) { + fullset = null; + break; + } + JsonObject item = itemElement.getAsJsonObject(); + String internalname = item.get("internalname").getAsString(); + + String[] split = internalname.split("_"); + split[split.length-1] = ""; + String armorname = StringUtils.join(split, "_"); + + if(fullset == null) { + fullset = armorname; + } else if(!fullset.equalsIgnoreCase(armorname)){ + fullset = null; + break; + } + } + return fullset; + } + + private static Stats getSetBonuses(Stats stats, JsonObject inventoryInfo, JsonObject collectionInfo, JsonObject skillInfo, JsonObject profile) { + JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray(); + + Stats bonuses = new Stats(); + + String fullset = getFullset(armor, -1); + + if(fullset != null) { + switch(fullset) { + case "LAPIS_ARMOR_": + bonuses.addStat(HEALTH, 60); + break; + case "EMERALD_ARMOR_": + { + int bonus = (int)Math.floor(Utils.getElementAsFloat(Utils.getElement(collectionInfo, "EMERALD"), 0)/3000); + bonuses.addStat(HEALTH, bonus); + bonuses.addStat(DEFENCE, bonus); + } + break; + case "FAIRY_": + bonuses.addStat(HEALTH, Utils.getElementAsFloat(Utils.getElement(profile, "fairy_souls_collected"), 0)); + break; + case "SPEEDSTER_": + bonuses.addStat(SPEED, 20); + break; + case "YOUNG_DRAGON_": + bonuses.addStat(SPEED, 70); + break; + case "MASTIFF_": + bonuses.addStat(HEALTH, 50*Math.round(stats.get(CRIT_DAMAGE))); + break; + case "ANGLER_": + bonuses.addStat(HEALTH, 10*(float)Math.floor(Utils.getElementAsFloat(Utils.getElement(skillInfo, "level_skill_fishing"), 0))); + bonuses.addStat(SEA_CREATURE_CHANCE, 4); + break; + case "ARMOR_OF_MAGMA_": + int bonus = (int)Math.min(200, Math.floor(Utils.getElementAsFloat(Utils.getElement(profile, "stats.kills_magma_cube"), 0)/10)); + bonuses.addStat(HEALTH, bonus); + bonuses.addStat(INTELLIGENCE, bonus); + case "OLD_DRAGON_": + bonuses.addStat(HEALTH, 200); + bonuses.addStat(DEFENCE, 40); + break; + } + } + + JsonElement chestplateElement = armor.get(2); + if(chestplateElement != null && chestplateElement.isJsonObject()) { + JsonObject chestplate = chestplateElement.getAsJsonObject(); + if(chestplate.get("internalname").getAsString().equals("OBSIDIAN_CHESTPLATE")) { + JsonArray inventory = Utils.getElement(inventoryInfo, "inv_contents").getAsJsonArray(); + for(int i=0; i<inventory.size(); i++) { + JsonElement itemElement = inventory.get(i); + if(itemElement != null && itemElement.isJsonObject()) { + JsonObject item = itemElement.getAsJsonObject(); + if(item.get("internalname").getAsString().equals("OBSIDIAN")) { + int count = 1; + if(item.has("count")) { + count = item.get("count").getAsInt(); + } + bonuses.addStat(SPEED, count/20); + } + } + } + } + } + + return bonuses; + } + + private static final Pattern HEALTH_PATTERN = Pattern.compile("^Health: ((?:\\+|-)[0-9]+)"); + private static final Pattern DEFENCE_PATTERN = Pattern.compile("^Defense: ((?:\\+|-)[0-9]+)"); + private static final Pattern STRENGTH_PATTERN = Pattern.compile("^Strength: ((?:\\+|-)[0-9]+)"); + private static final Pattern SPEED_PATTERN = Pattern.compile("^Speed: ((?:\\+|-)[0-9]+)"); + private static final Pattern CC_PATTERN = Pattern.compile("^Crit Chance: ((?:\\+|-)[0-9]+)"); + private static final Pattern CD_PATTERN = Pattern.compile("^Crit Damage: ((?:\\+|-)[0-9]+)"); + private static final Pattern ATKSPEED_PATTERN = Pattern.compile("^Bonus Attack Speed: ((?:\\+|-)[0-9]+)"); + private static final Pattern INTELLIGENCE_PATTERN = Pattern.compile("^Intelligence: ((?:\\+|-)[0-9]+)"); + private static final Pattern SCC_PATTERN = Pattern.compile("^Sea Creature Chance: ((?:\\+|-)[0-9]+)"); + private static final HashMap<String, Pattern> STAT_PATTERN_MAP = new HashMap<>(); + static { + STAT_PATTERN_MAP.put("health", HEALTH_PATTERN); + STAT_PATTERN_MAP.put("defence", DEFENCE_PATTERN); + STAT_PATTERN_MAP.put("strength", STRENGTH_PATTERN); + STAT_PATTERN_MAP.put("speed", SPEED_PATTERN); + STAT_PATTERN_MAP.put("crit_chance", CC_PATTERN); + STAT_PATTERN_MAP.put("crit_damage", CD_PATTERN); + STAT_PATTERN_MAP.put("bonus_attack_speed", ATKSPEED_PATTERN); + STAT_PATTERN_MAP.put("intelligence", INTELLIGENCE_PATTERN); + STAT_PATTERN_MAP.put("sea_creature_chance", SCC_PATTERN); + } + private static Stats getStatForItem(String internalname, JsonObject item, JsonArray lore) { + Stats stats = new Stats(); + for(int i=0; i<lore.size(); i++) { + String line = lore.get(i).getAsString(); + for(Map.Entry<String, Pattern> entry : STAT_PATTERN_MAP.entrySet()) { + Matcher matcher = entry.getValue().matcher(Utils.cleanColour(line)); + if(matcher.find()) { + int bonus = Integer.parseInt(matcher.group(1)); + stats.addStat(entry.getKey(), bonus); + } + } + } + if(internalname.equals("DAY_CRYSTAL") || internalname.equals("NIGHT_CRYSTAL")) { + stats.addStat(STRENGTH, 2.5f); + stats.addStat(DEFENCE, 2.5f); + } + if(internalname.equals("NEW_YEAR_CAKE_BAG") && item.has("item_contents")) { + JsonArray bytesArr = item.get("item_contents").getAsJsonArray(); + byte[] bytes = new byte[bytesArr.size()]; + for(int i=0; i<bytesArr.size(); i++) { + bytes[i] = bytesArr.get(i).getAsByte(); + } + try { + NBTTagCompound contents_nbt = CompressedStreamTools.readCompressed(new ByteArrayInputStream(bytes)); + NBTTagList items = contents_nbt.getTagList("i", 10); + HashSet<Integer> cakes = new HashSet<>(); + for(int j=0; j<items.tagCount(); j++) { + if(items.getCompoundTagAt(j).getKeySet().size() > 0) { + NBTTagCompound nbt = items.getCompoundTagAt(j).getCompoundTag("tag"); + if(nbt != null && nbt.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = nbt.getCompoundTag("ExtraAttributes"); + if (ea.hasKey("new_years_cake")) { + cakes.add(ea.getInteger("new_years_cake")); + } + } + } + } + stats.addStat(HEALTH, cakes.size()); + } catch(IOException e) { + e.printStackTrace(); + return stats; + } + } + return stats; + } + private static Stats getItemBonuses(boolean talismanOnly, JsonArray... inventories) { + JsonObject misc = Constants.MISC; + if(misc == null) return null; + JsonElement talisman_upgrades_element = misc.get("talisman_upgrades"); + if(talisman_upgrades_element == null) return null; + JsonObject talisman_upgrades = talisman_upgrades_element.getAsJsonObject(); + + HashMap<String, Stats> itemBonuses = new HashMap<>(); + for(JsonArray inventory : inventories) { + for(int i=0; i<inventory.size(); i++) { + JsonElement itemElement = inventory.get(i); + if(itemElement != null && itemElement.isJsonObject()) { + JsonObject item = itemElement.getAsJsonObject(); + String internalname = item.get("internalname").getAsString(); + if(itemBonuses.containsKey(internalname)) { + continue; + } + if(!talismanOnly || Utils.checkItemType(item.get("lore").getAsJsonArray(), true, "ACCESSORY", "HATCCESSORY") >= 0) { + Stats itemBonus = getStatForItem(internalname, item, item.get("lore").getAsJsonArray()); + + itemBonuses.put(internalname, itemBonus); + + for(Map.Entry<String, JsonElement> talisman_upgrades_item : talisman_upgrades.entrySet()) { + JsonArray upgrades = talisman_upgrades_item.getValue().getAsJsonArray(); + for(int j=0; j<upgrades.size(); j++) { + String upgrade = upgrades.get(j).getAsString(); + if(upgrade.equals(internalname)) { + itemBonuses.put(talisman_upgrades_item.getKey(), new Stats()); + break; + } + } + } + } + } + } + } + Stats itemBonusesStats = new Stats(); + for(Stats stats : itemBonuses.values()) { + itemBonusesStats.add(stats); + } + return itemBonusesStats; + } + + private static float getStatMult(JsonObject inventoryInfo) { + float mult = 1f; + + JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray(); + + String fullset = getFullset(armor, -1); + + if(fullset != null && fullset.equals("SUPERIOR_DRAGON_")) { + mult *= 1.05f; + } + + for(int i=0; i<armor.size(); i++) { + JsonElement itemElement = armor.get(i); + if(itemElement == null || !itemElement.isJsonObject()) continue; + + JsonObject item = itemElement.getAsJsonObject(); + String internalname = item.get("internalname").getAsString(); + + String reforge = Utils.getElementAsString(Utils.getElement(item, "ExtraAttributes.modifier"), ""); + + if(reforge.equals("renowned")) { + mult *= 1.01f; + } + } + + return mult; + } + + private static void applyLimits(Stats stats, JsonObject inventoryInfo) { + //>0 + JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray(); + + String fullset = getFullset(armor, 3); + + if(fullset != null) { + switch(fullset) { + case "CHEAP_TUXEDO_": + stats.statsJson.add(HEALTH, new JsonPrimitive(Math.min(75, stats.get(HEALTH)))); + case "FANCY_TUXEDO_": + stats.statsJson.add(HEALTH, new JsonPrimitive(Math.min(150, stats.get(HEALTH)))); + case "ELEGANT_TUXEDO_": + stats.statsJson.add(HEALTH, new JsonPrimitive(Math.min(250, stats.get(HEALTH)))); + } + } + + for(Map.Entry<String, JsonElement> statEntry : stats.statsJson.entrySet()) { + if(statEntry.getKey().equals(CRIT_DAMAGE) || + statEntry.getKey().equals(INTELLIGENCE) || + statEntry.getKey().equals(BONUS_ATTACK_SPEED)) continue; + stats.statsJson.add(statEntry.getKey(), new JsonPrimitive(Math.max(0, statEntry.getValue().getAsFloat()))); + } + } + + public static Stats getStats(JsonObject skillInfo, JsonObject inventoryInfo, JsonObject collectionInfo, JsonObject profile) { + if(skillInfo == null || inventoryInfo == null || collectionInfo == null || profile == null) return null; + + JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray(); + JsonArray inventory = Utils.getElement(inventoryInfo, "inv_contents").getAsJsonArray(); + JsonArray talisman_bag = Utils.getElement(inventoryInfo, "talisman_bag").getAsJsonArray(); + + Stats passiveBonuses = getPassiveBonuses(skillInfo, profile); + Stats armorBonuses = getItemBonuses(false, armor); + Stats talismanBonuses = getItemBonuses(true, inventory, talisman_bag); + + if(passiveBonuses == null || armorBonuses == null || talismanBonuses == null) { + return null; + } + + Stats stats = getBaseStats().add(passiveBonuses).add(armorBonuses).add(talismanBonuses); + + stats.add(getSetBonuses(stats, inventoryInfo, collectionInfo, skillInfo, profile)); + + stats.scaleAll(getStatMult(inventoryInfo)); + + applyLimits(stats, inventoryInfo); + + return stats; + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java new file mode 100644 index 00000000..e4ab29d2 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java @@ -0,0 +1,1017 @@ +package io.github.moulberry.notenoughupdates.profileviewer; + +import com.google.common.base.Splitter; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import io.github.moulberry.notenoughupdates.NEUManager; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ProfileViewer { + + private final NEUManager manager; + + public ProfileViewer(NEUManager manager) { + this.manager = manager; + } + + + private static HashMap<String, String> petRarityToNumMap = new HashMap<>(); + static { + petRarityToNumMap.put("COMMON", "0"); + petRarityToNumMap.put("UNCOMMON", "1"); + petRarityToNumMap.put("RARE", "2"); + petRarityToNumMap.put("EPIC", "3"); + petRarityToNumMap.put("LEGENDARY", "4"); + } + + private static final LinkedHashMap<String, ItemStack> skillToSkillDisplayMap = new LinkedHashMap<>(); + static { + skillToSkillDisplayMap.put("skill_taming", Utils.createItemStack(Items.spawn_egg, EnumChatFormatting.LIGHT_PURPLE+"Taming")); + skillToSkillDisplayMap.put("skill_mining", Utils.createItemStack(Items.stone_pickaxe, EnumChatFormatting.GRAY+"Mining")); + skillToSkillDisplayMap.put("skill_foraging", Utils.createItemStack(Item.getItemFromBlock(Blocks.sapling), EnumChatFormatting.DARK_GREEN+"Foraging")); + skillToSkillDisplayMap.put("skill_enchanting", Utils.createItemStack(Item.getItemFromBlock(Blocks.enchanting_table), EnumChatFormatting.GREEN+"Enchanting")); + skillToSkillDisplayMap.put("skill_carpentry", Utils.createItemStack(Item.getItemFromBlock(Blocks.crafting_table), EnumChatFormatting.DARK_RED+"Carpentry")); + skillToSkillDisplayMap.put("skill_farming", Utils.createItemStack(Items.golden_hoe, EnumChatFormatting.YELLOW+"Farming")); + skillToSkillDisplayMap.put("skill_combat", Utils.createItemStack(Items.stone_sword, EnumChatFormatting.RED+"Combat")); + skillToSkillDisplayMap.put("skill_fishing", Utils.createItemStack(Items.fishing_rod, EnumChatFormatting.AQUA+"Fishing")); + skillToSkillDisplayMap.put("skill_alchemy", Utils.createItemStack(Items.brewing_stand, EnumChatFormatting.BLUE+"Alchemy")); + skillToSkillDisplayMap.put("skill_runecrafting", Utils.createItemStack(Items.magma_cream, EnumChatFormatting.DARK_PURPLE+"Runecrafting")); + skillToSkillDisplayMap.put("skill_catacombs", Utils.createItemStack(Item.getItemFromBlock(Blocks.deadbush), EnumChatFormatting.GOLD+"Catacombs")); + skillToSkillDisplayMap.put("slayer_zombie", Utils.createItemStack(Items.rotten_flesh, EnumChatFormatting.GOLD+"Rev Slayer")); + skillToSkillDisplayMap.put("slayer_spider", Utils.createItemStack(Items.spider_eye, EnumChatFormatting.GOLD+"Tara Slayer")); + skillToSkillDisplayMap.put("slayer_wolf", Utils.createItemStack(Items.bone, EnumChatFormatting.GOLD+"Sven Slayer")); + } + + private static final ItemStack CAT_FARMING = Utils.createItemStack(Items.golden_hoe, EnumChatFormatting.YELLOW+"Farming"); + private static final ItemStack CAT_MINING = Utils.createItemStack(Items.stone_pickaxe, EnumChatFormatting.GRAY+"Mining"); + private static final ItemStack CAT_COMBAT = Utils.createItemStack(Items.stone_sword, EnumChatFormatting.RED+"Combat"); + private static final ItemStack CAT_FORAGING = Utils.createItemStack(Item.getItemFromBlock(Blocks.sapling), EnumChatFormatting.DARK_GREEN+"Foraging"); + private static final ItemStack CAT_FISHING = Utils.createItemStack(Items.fishing_rod, EnumChatFormatting.AQUA+"Fishing"); + + private static final LinkedHashMap<ItemStack, List<String>> collectionCatToCollectionMap = new LinkedHashMap<>(); + static { + collectionCatToCollectionMap.put(CAT_FARMING, + Utils.createList("WHEAT", "CARROT_ITEM", "POTATO_ITEM", "PUMPKIN", "MELON", "SEEDS", "MUSHROOM_COLLECTION", + "INK_SACK:3", "CACTUS", "SUGAR_CANE", "FEATHER", "LEATHER", "PORK", "RAW_CHICKEN", "MUTTON", + "RABBIT", "NETHER_STALK")); + collectionCatToCollectionMap.put(CAT_MINING, + Utils.createList("COBBLESTONE", "COAL", "IRON_INGOT", "GOLD_INGOT", "DIAMOND", "INK_SACK:4", + "EMERALD", "REDSTONE", "QUARTZ", "OBSIDIAN", "GLOWSTONE_DUST", "GRAVEL", "ICE", "NETHERRACK", + "SAND", "ENDER_STONE")); + collectionCatToCollectionMap.put(CAT_COMBAT, + Utils.createList("ROTTEN_FLESH", "BONE", "STRING", "SPIDER_EYE", "SULPHUR", "ENDER_PEARL", + "GHAST_TEAR", "SLIME_BALL", "BLAZE_ROD", "MAGMA_CREAM")); + collectionCatToCollectionMap.put(CAT_FORAGING, + Utils.createList("LOG", "LOG:1", "LOG:2", "LOG_2:1", "LOG_2", "LOG:3")); + collectionCatToCollectionMap.put(CAT_FISHING, + Utils.createList("RAW_FISH", "RAW_FISH:1", "RAW_FISH:2", "RAW_FISH:3", "PRISMARINE_SHARD", + "PRISMARINE_CRYSTALS", "CLAY_BALL", "WATER_LILY", "INK_SACK", "SPONGE")); + } + + private static final LinkedHashMap<ItemStack, List<String>> collectionCatToMinionMap = new LinkedHashMap<>(); + static { + collectionCatToMinionMap.put(CAT_FARMING, + Utils.createList("WHEAT", "CARROT", "POTATO", "PUMPKIN", "MELON", null, "MUSHROOM", + "COCOA", "CACTUS", "SUGAR_CANE", "CHICKEN", "COW", "PIG", null, "SHEEP", + "RABBIT", "NETHER_WARTS")); + collectionCatToMinionMap.put(CAT_MINING, + Utils.createList("COBBLESTONE", "COAL", "IRON", "GOLD", "DIAMOND", "LAPIS", + "EMERALD", "REDSTONE", "QUARTZ", "OBSIDIAN", "GLOWSTONE", "GRAVEL", "ICE", null, + "SAND", "ENDER_STONE")); + collectionCatToMinionMap.put(CAT_COMBAT, + Utils.createList("ZOMBIE", "SKELETON", "SPIDER", "CAVESPIDER", "CREEPER", "ENDERMAN", + "GHAST", "SLIME", "BLAZE", "MAGMA_CUBE")); + collectionCatToMinionMap.put(CAT_FORAGING, + Utils.createList("OAK", "SPRUCE", "BIRCH", "DARK_OAK", "ACACIA", "JUNGLE")); + collectionCatToMinionMap.put(CAT_FISHING, + Utils.createList("FISHING", null, null, null, null, + null, "CLAY", null, null, null)); + } + + private static final LinkedHashMap<String, ItemStack> collectionToCollectionDisplayMap = new LinkedHashMap<>(); + static { + /** FARMING COLLECTIONS **/ + collectionToCollectionDisplayMap.put("WHEAT", Utils.createItemStack(Items.wheat, + EnumChatFormatting.YELLOW+"Wheat")); + collectionToCollectionDisplayMap.put("CARROT_ITEM", Utils.createItemStack(Items.carrot, + EnumChatFormatting.YELLOW+"Carrot")); + collectionToCollectionDisplayMap.put("POTATO_ITEM", Utils.createItemStack(Items.potato, + EnumChatFormatting.YELLOW+"Potato")); + collectionToCollectionDisplayMap.put("PUMPKIN", Utils.createItemStack(Item.getItemFromBlock(Blocks.pumpkin), + EnumChatFormatting.YELLOW+"Pumpkin")); + collectionToCollectionDisplayMap.put("MELON", Utils.createItemStack(Items.melon, + EnumChatFormatting.YELLOW+"Melon")); + collectionToCollectionDisplayMap.put("SEEDS", Utils.createItemStack(Items.wheat_seeds, + EnumChatFormatting.YELLOW+"Seeds")); + collectionToCollectionDisplayMap.put("MUSHROOM_COLLECTION", + Utils.createItemStack(Item.getItemFromBlock(Blocks.red_mushroom) + , EnumChatFormatting.YELLOW+"Mushroom")); + collectionToCollectionDisplayMap.put("INK_SACK:3", Utils.createItemStack(Items.dye, + EnumChatFormatting.YELLOW+"Cocoa Beans", 3)); + collectionToCollectionDisplayMap.put("CACTUS", Utils.createItemStack(Item.getItemFromBlock(Blocks.cactus), + EnumChatFormatting.YELLOW+"Cactus")); + collectionToCollectionDisplayMap.put("SUGAR_CANE", Utils.createItemStack(Items.reeds, + EnumChatFormatting.YELLOW+"Sugar Cane")); + collectionToCollectionDisplayMap.put("FEATHER", Utils.createItemStack(Items.feather, + EnumChatFormatting.YELLOW+"Feather")); + collectionToCollectionDisplayMap.put("LEATHER", Utils.createItemStack(Items.leather, + EnumChatFormatting.YELLOW+"Leather")); + collectionToCollectionDisplayMap.put("PORK", Utils.createItemStack(Items.porkchop, + EnumChatFormatting.YELLOW+"Porkchop")); + collectionToCollectionDisplayMap.put("RAW_CHICKEN", Utils.createItemStack(Items.chicken, + EnumChatFormatting.YELLOW+"Chicken")); + collectionToCollectionDisplayMap.put("MUTTON", Utils.createItemStack(Items.mutton, + EnumChatFormatting.YELLOW+"Mutton")); + collectionToCollectionDisplayMap.put("RABBIT", Utils.createItemStack(Items.rabbit, + EnumChatFormatting.YELLOW+"Rabbit")); + collectionToCollectionDisplayMap.put("NETHER_STALK", Utils.createItemStack(Items.nether_wart, + EnumChatFormatting.YELLOW+"Nether Wart")); + + /** MINING COLLECTIONS **/ + collectionToCollectionDisplayMap.put("COBBLESTONE", Utils.createItemStack(Item.getItemFromBlock(Blocks.cobblestone), + EnumChatFormatting.GRAY+"Cobblestone")); + collectionToCollectionDisplayMap.put("COAL", Utils.createItemStack(Items.coal, + EnumChatFormatting.GRAY+"Coal")); + collectionToCollectionDisplayMap.put("IRON_INGOT", Utils.createItemStack(Items.iron_ingot, + EnumChatFormatting.GRAY+"Iron Ingot")); + collectionToCollectionDisplayMap.put("GOLD_INGOT", Utils.createItemStack(Items.gold_ingot, + EnumChatFormatting.GRAY+"Gold Ingot")); + collectionToCollectionDisplayMap.put("DIAMOND", Utils.createItemStack(Items.diamond, + EnumChatFormatting.GRAY+"Diamond")); + collectionToCollectionDisplayMap.put("INK_SACK:4", Utils.createItemStack(Items.dye, + EnumChatFormatting.GRAY+"Lapis Lazuli", 4)); + collectionToCollectionDisplayMap.put("EMERALD", Utils.createItemStack(Items.emerald, + EnumChatFormatting.GRAY+"Emerald")); + collectionToCollectionDisplayMap.put("REDSTONE", Utils.createItemStack(Items.redstone, + EnumChatFormatting.GRAY+"Redstone")); + collectionToCollectionDisplayMap.put("QUARTZ", Utils.createItemStack(Items.quartz, + EnumChatFormatting.GRAY+"Nether Quartz")); + collectionToCollectionDisplayMap.put("OBSIDIAN", Utils.createItemStack(Item.getItemFromBlock(Blocks.obsidian), + EnumChatFormatting.GRAY+"Obsidian")); + collectionToCollectionDisplayMap.put("GLOWSTONE_DUST", Utils.createItemStack(Items.glowstone_dust, + EnumChatFormatting.GRAY+"Glowstone")); + collectionToCollectionDisplayMap.put("GRAVEL", Utils.createItemStack(Item.getItemFromBlock(Blocks.gravel), + EnumChatFormatting.GRAY+"Gravel")); + collectionToCollectionDisplayMap.put("ICE", Utils.createItemStack(Item.getItemFromBlock(Blocks.ice), + EnumChatFormatting.GRAY+"Ice")); + collectionToCollectionDisplayMap.put("NETHERRACK", Utils.createItemStack(Item.getItemFromBlock(Blocks.netherrack), + EnumChatFormatting.GRAY+"Netherrack")); + collectionToCollectionDisplayMap.put("SAND", Utils.createItemStack(Item.getItemFromBlock(Blocks.sand), + EnumChatFormatting.GRAY+"Sand")); + collectionToCollectionDisplayMap.put("ENDER_STONE", Utils.createItemStack(Item.getItemFromBlock(Blocks.end_stone), + EnumChatFormatting.GRAY+"End Stone")); + + /** COMBAT COLLECTIONS **/ + collectionToCollectionDisplayMap.put("ROTTEN_FLESH", Utils.createItemStack(Items.rotten_flesh, + EnumChatFormatting.RED+"Rotten Flesh")); + collectionToCollectionDisplayMap.put("BONE", Utils.createItemStack(Items.bone, + EnumChatFormatting.RED+"Bone")); + collectionToCollectionDisplayMap.put("STRING", Utils.createItemStack(Items.string, + EnumChatFormatting.RED+"String")); + collectionToCollectionDisplayMap.put("SPIDER_EYE", Utils.createItemStack(Items.spider_eye, + EnumChatFormatting.RED+"Spider Eye")); + collectionToCollectionDisplayMap.put("SULPHUR", Utils.createItemStack(Items.gunpowder, + EnumChatFormatting.RED+"Gunpowder")); + collectionToCollectionDisplayMap.put("ENDER_PEARL", Utils.createItemStack(Items.ender_pearl, + EnumChatFormatting.RED+"Ender Pearl")); + collectionToCollectionDisplayMap.put("GHAST_TEAR", Utils.createItemStack(Items.ghast_tear, + EnumChatFormatting.RED+"Ghast Tear")); + collectionToCollectionDisplayMap.put("SLIME_BALL", Utils.createItemStack(Items.slime_ball, + EnumChatFormatting.RED+"Slimeball")); + collectionToCollectionDisplayMap.put("BLAZE_ROD", Utils.createItemStack(Items.blaze_rod, + EnumChatFormatting.RED+"Blaze Rod")); + collectionToCollectionDisplayMap.put("MAGMA_CREAM", Utils.createItemStack(Items.magma_cream, + EnumChatFormatting.RED+"Magma Cream")); + + /** FORAGING COLLECTIONS **/ + collectionToCollectionDisplayMap.put("LOG", Utils.createItemStack(Item.getItemFromBlock(Blocks.log), + EnumChatFormatting.DARK_GREEN+"Oak")); + collectionToCollectionDisplayMap.put("LOG:1", Utils.createItemStack(Item.getItemFromBlock(Blocks.log), + EnumChatFormatting.DARK_GREEN+"Birch", 1)); + collectionToCollectionDisplayMap.put("LOG:2", Utils.createItemStack(Item.getItemFromBlock(Blocks.log), + EnumChatFormatting.DARK_GREEN+"Spruce", 2)); + collectionToCollectionDisplayMap.put("LOG_2:1", Utils.createItemStack(Item.getItemFromBlock(Blocks.log2), + EnumChatFormatting.DARK_GREEN+"Dark Oak", 1)); + collectionToCollectionDisplayMap.put("LOG_2", Utils.createItemStack(Item.getItemFromBlock(Blocks.log2), + EnumChatFormatting.DARK_GREEN+"Acacia")); + collectionToCollectionDisplayMap.put("LOG:3", Utils.createItemStack(Item.getItemFromBlock(Blocks.log), + EnumChatFormatting.DARK_GREEN+"Jungle", 3)); + + /** FISHING COLLECTIONS **/ + collectionToCollectionDisplayMap.put("RAW_FISH", Utils.createItemStack(Items.fish, + EnumChatFormatting.AQUA+"Fish")); + collectionToCollectionDisplayMap.put("RAW_FISH:1", Utils.createItemStack(Items.fish, + EnumChatFormatting.AQUA+"Salmon", 1)); + collectionToCollectionDisplayMap.put("RAW_FISH:2", Utils.createItemStack(Items.fish, + EnumChatFormatting.AQUA+"Clownfish", 2)); + collectionToCollectionDisplayMap.put("RAW_FISH:3", Utils.createItemStack(Items.fish, + EnumChatFormatting.AQUA+"Pufferfish", 3)); + collectionToCollectionDisplayMap.put("PRISMARINE_SHARD", Utils.createItemStack(Items.prismarine_shard, + EnumChatFormatting.AQUA+"Prismarine Shard")); + collectionToCollectionDisplayMap.put("PRISMARINE_CRYSTALS", Utils.createItemStack(Items.prismarine_crystals, + EnumChatFormatting.AQUA+"Prismarine Crystals")); + collectionToCollectionDisplayMap.put("CLAY_BALL", Utils.createItemStack(Items.clay_ball, + EnumChatFormatting.AQUA+"Clay")); + collectionToCollectionDisplayMap.put("WATER_LILY", Utils.createItemStack(Item.getItemFromBlock(Blocks.waterlily), + EnumChatFormatting.AQUA+"Lilypad")); + collectionToCollectionDisplayMap.put("INK_SACK", Utils.createItemStack(Items.dye, + EnumChatFormatting.AQUA+"Ink Sack")); + collectionToCollectionDisplayMap.put("SPONGE", Utils.createItemStack(Item.getItemFromBlock(Blocks.sponge), + EnumChatFormatting.AQUA+"Sponge")); + } + + public static LinkedHashMap<ItemStack, List<String>> getCollectionCatToMinionMap() { + return collectionCatToMinionMap; + } + + public static LinkedHashMap<String, ItemStack> getCollectionToCollectionDisplayMap() { + return collectionToCollectionDisplayMap; + } + + public static LinkedHashMap<ItemStack, List<String>> getCollectionCatToCollectionMap() { + return collectionCatToCollectionMap; + } + + public static Map<String, ItemStack> getSkillToSkillDisplayMap() { + return Collections.unmodifiableMap(skillToSkillDisplayMap); + } + + public class Profile { + private final String uuid; + private String latestProfile = null; + + private JsonArray playerInformation = null; + private JsonObject basicInfo = null; + + private final HashMap<String, JsonObject> profileMap = new HashMap<>(); + private final HashMap<String, JsonObject> petsInfoMap = new HashMap<>(); + private final HashMap<String, List<JsonObject>> coopProfileMap = new HashMap<>(); + private final HashMap<String, JsonObject> skillInfoMap = new HashMap<>(); + private final HashMap<String, JsonObject> inventoryInfoMap = new HashMap<>(); + private final HashMap<String, JsonObject> collectionInfoMap = new HashMap<>(); + private List<String> profileIds = new ArrayList<>(); + private JsonObject playerStatus = null; + private HashMap<String, PlayerStats.Stats> stats = new HashMap<>(); + private HashMap<String, PlayerStats.Stats> passiveStats = new HashMap<>(); + private long networth = -1; + + public Profile(String uuid) { + this.uuid = uuid; + } + + private AtomicBoolean updatingPlayerInfoState = new AtomicBoolean(false); + private AtomicBoolean updatingPlayerStatusState = new AtomicBoolean(false); + + public JsonObject getPlayerStatus() { + if(playerStatus != null) return playerStatus; + if(updatingPlayerStatusState.get()) return null; + + updatingPlayerStatusState.set(true); + + HashMap<String, String> args = new HashMap<>(); + args.put("uuid", ""+uuid); + manager.hypixelApi.getHypixelApiAsync(manager.config.apiKey.value, "status", + args, jsonObject -> { + if(jsonObject == null) return; + + updatingPlayerStatusState.set(false); + if(jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) { + playerStatus = jsonObject.get("session").getAsJsonObject(); + } + }, () -> updatingPlayerStatusState.set(false) + ); + + return null; + } + + public long getNetWorth(String profileId) { + if(networth != -1) return networth; + if(getProfileInformation(profileId) == null) return -1; + if(getInventoryInfo(profileId) == null) return -1; + + JsonObject inventoryInfo = getInventoryInfo(profileId); + JsonObject profileInfo = getProfileInformation(profileId); + + long networth = 0; + for(Map.Entry<String, JsonElement> entry : inventoryInfo.entrySet()) { + if(entry.getValue().isJsonArray()) { + for(JsonElement element : entry.getValue().getAsJsonArray()) { + if(element != null && element.isJsonObject()) { + JsonObject item = element.getAsJsonObject(); + String internalname = item.get("internalname").getAsString(); + + if(manager.auctionManager.isVanillaItem(internalname)) continue; + + JsonObject info = manager.auctionManager.getItemAuctionInfo(internalname); + if(info == null || !info.has("price") || !info.has("count")) continue; + + int auctionPrice = (int)(info.get("price").getAsFloat() / info.get("count").getAsFloat()); + + try { + if(item.has("item_contents")) { + JsonArray bytesArr = item.get("item_contents").getAsJsonArray(); + byte[] bytes = new byte[bytesArr.size()]; + for (int bytesArrI = 0; bytesArrI < bytesArr.size(); bytesArrI++) { + bytes[bytesArrI] = bytesArr.get(bytesArrI).getAsByte(); + } + NBTTagCompound contents_nbt = CompressedStreamTools.readCompressed(new ByteArrayInputStream(bytes)); + NBTTagList items = contents_nbt.getTagList("i", 10); + for(int j=0; j<items.tagCount(); j++) { + if(items.getCompoundTagAt(j).getKeySet().size() > 0) { + NBTTagCompound nbt = items.getCompoundTagAt(j).getCompoundTag("tag"); + String internalname2 = manager.getInternalnameFromNBT(nbt); + if(internalname2 != null) { + if(manager.auctionManager.isVanillaItem(internalname2)) continue; + + JsonObject info2 = manager.auctionManager.getItemAuctionInfo(internalname2); + if(info2 == null || !info2.has("price") || !info2.has("count")) continue; + int auctionPrice2 = (int)(info2.get("price").getAsFloat() / info2.get("count").getAsFloat()); + + int count2 = items.getCompoundTagAt(j).getByte("Count"); + networth += auctionPrice2 * count2; + } + } + } + } + } catch(IOException ignored) {} + + int count = 1; + if(element.getAsJsonObject().has("count")) { + count = element.getAsJsonObject().get("count").getAsInt(); + } + + networth += auctionPrice * count; + } + } + } + } + if(networth == 0) return -1; + + JsonObject petsInfo = getPetsInfo(profileId); + if(petsInfo != null && petsInfo.has("pets")) { + if(petsInfo.get("pets").isJsonArray()) { + JsonArray pets = petsInfo.get("pets").getAsJsonArray(); + for(JsonElement element : pets) { + if(element.isJsonObject()) { + JsonObject pet = element.getAsJsonObject(); + + String petname = pet.get("type").getAsString(); + String tier = pet.get("tier").getAsString(); + String tierNum = petRarityToNumMap.get(tier); + if(tierNum != null) { + String internalname2 = petname+";"+tierNum; + JsonObject info2 = manager.auctionManager.getItemAuctionInfo(internalname2); + if(info2 == null || !info2.has("price") || !info2.has("count")) continue; + int auctionPrice2 = (int)(info2.get("price").getAsFloat() / info2.get("count").getAsFloat()); + + networth += auctionPrice2; + } + } + } + } + } + + float bankBalance = Utils.getElementAsFloat(Utils.getElement(profileInfo, "banking.balance"), 0); + float purseBalance = Utils.getElementAsFloat(Utils.getElement(profileInfo, "coin_purse"), 0); + + networth += bankBalance+purseBalance; + + this.networth = networth; + return networth; + } + + public String getLatestProfile() { + return latestProfile; + } + + public JsonArray getPlayerInformation(Runnable runnable) { + if (playerInformation != null) return playerInformation; + if (updatingPlayerInfoState.get()) return null; + + updatingPlayerInfoState.set(true); + + HashMap<String, String> args = new HashMap<>(); + args.put("uuid", "" + uuid); + manager.hypixelApi.getHypixelApiAsync(manager.config.apiKey.value, "skyblock/profiles", + args, jsonObject -> { + if (jsonObject == null) return; + + updatingPlayerInfoState.set(false); + if (jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) { + playerInformation = jsonObject.get("profiles").getAsJsonArray(); + if (playerInformation == null) return; + String backup = null; + long backupLastSave = 0; + + profileIds.clear(); + + for (int i = 0; i < playerInformation.size(); i++) { + JsonObject profile = playerInformation.get(i).getAsJsonObject(); + + if (!profile.has("members")) continue; + JsonObject members = profile.get("members").getAsJsonObject(); + + if (members.has(uuid)) { + JsonObject member = members.get(uuid).getAsJsonObject(); + + if(member.has("coop_invitation")) { + JsonObject coop_invitation = member.get("coop_invitation").getAsJsonObject(); + if(!coop_invitation.get("confirmed").getAsBoolean()) { + continue; + } + } + + String cute_name = profile.get("cute_name").getAsString(); + if (backup == null) backup = cute_name; + profileIds.add(cute_name); + if (member.has("last_save")) { + long last_save = member.get("last_save").getAsLong(); + if (last_save > backupLastSave) { + backupLastSave = last_save; + backup = cute_name; + } + } + + } + } + if (runnable != null) runnable.run(); + latestProfile = backup; + } + }, () -> { + updatingPlayerInfoState.set(false); + } + ); + + return null; + } + + public List<String> getProfileIds() { + return profileIds; + } + + public JsonObject getProfileInformation(String profileId) { + JsonArray playerInfo = getPlayerInformation(() -> {}); + if(playerInfo == null) return null; + if(profileId == null) profileId = latestProfile; + if(profileMap.containsKey(profileId)) return profileMap.get(profileId); + + for(int i=0; i<playerInformation.size(); i++) { + if(!playerInformation.get(i).isJsonObject()) { + playerInformation = null; + return null; + } + JsonObject profile = playerInformation.get(i).getAsJsonObject(); + if(profile.get("cute_name").getAsString().equalsIgnoreCase(profileId)) { + if(!profile.has("members")) return null; + JsonObject members = profile.get("members").getAsJsonObject(); + if(!members.has(uuid)) continue; + JsonObject profileInfo = members.get(uuid).getAsJsonObject(); + if(profile.has("banking")) { + profileInfo.add("banking", profile.get("banking").getAsJsonObject()); + } + profileMap.put(profileId, profileInfo); + return profileInfo; + } + } + + return null; + } + + public List<JsonObject> getCoopProfileInformation(String profileId) { + JsonArray playerInfo = getPlayerInformation(() -> {}); + if(playerInfo == null) return null; + if(profileId == null) profileId = latestProfile; + if(coopProfileMap.containsKey(profileId)) return coopProfileMap.get(profileId); + + for(int i=0; i<playerInformation.size(); i++) { + if(!playerInformation.get(i).isJsonObject()) { + playerInformation = null; + return null; + } + JsonObject profile = playerInformation.get(i).getAsJsonObject(); + if(profile.get("cute_name").getAsString().equalsIgnoreCase(profileId)) { + if(!profile.has("members")) return null; + JsonObject members = profile.get("members").getAsJsonObject(); + if(!members.has(uuid)) return null; + List<JsonObject> coopList = new ArrayList<>(); + for(Map.Entry<String, JsonElement> islandMember : members.entrySet()) { + if(!islandMember.getKey().equals(uuid)) { + JsonObject coopProfileInfo = islandMember.getValue().getAsJsonObject(); + coopList.add(coopProfileInfo); + } + } + coopProfileMap.put(profileId, coopList); + return coopList; + } + } + + return null; + } + + public void resetCache() { + playerInformation = null; + basicInfo = null; + playerStatus = null; + stats.clear(); + passiveStats.clear(); + profileIds.clear(); + profileMap.clear(); + coopProfileMap.clear(); + petsInfoMap.clear(); + skillInfoMap.clear(); + inventoryInfoMap.clear(); + collectionInfoMap.clear(); + networth = -1; + } + + private class Level { + private float level = 0; + private float maxXpForLevel = 0; + private boolean maxed = false; + } + + public Level getLevel(JsonArray levelingArray, float xp, boolean cumulative) { + Level levelObj = new Level(); + for(int level=0; level<levelingArray.size(); level++) { + float levelXp = levelingArray.get(level).getAsFloat(); + if(levelXp > xp) { + if(cumulative) { + float previous = 0; + if(level > 0) previous = levelingArray.get(level-1).getAsFloat(); + levelObj.maxXpForLevel = (levelXp-previous); + levelObj.level = 1 + level + (xp-levelXp)/levelObj.maxXpForLevel; + } else { + levelObj.maxXpForLevel = levelXp; + levelObj.level = level + xp/levelXp; + } + return levelObj; + } else { + if(!cumulative) xp -= levelXp; + } + } + levelObj.level = levelingArray.size(); + levelObj.maxed = true; + return levelObj; + } + + public JsonObject getSkillInfo(String profileId) { + JsonObject profileInfo = getProfileInformation(profileId); + if(profileInfo == null) return null; + if(profileId == null) profileId = latestProfile; + if(skillInfoMap.containsKey(profileId)) return skillInfoMap.get(profileId); + JsonObject leveling = Constants.LEVELING; + if(leveling == null) return null; + + float experience_skill_taming = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_taming"), 0); + float experience_skill_mining = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_mining"), 0); + float experience_skill_foraging = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_foraging"), 0); + float experience_skill_enchanting = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_enchanting"), 0); + float experience_skill_carpentry = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_carpentry"), 0); + float experience_skill_farming = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_farming"), 0); + float experience_skill_combat = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_combat"), 0); + float experience_skill_fishing = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_fishing"), 0); + float experience_skill_alchemy = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_alchemy"), 0); + float experience_skill_runecrafting = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_runecrafting"), 0); + + float experience_skill_catacombs = Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.experience"), 0); + if(uuid.equals("d14403fd77664905929ee1a6e365e623")) experience_skill_catacombs = 569809640; //lvl 50 + + float experience_slayer_zombie = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.zombie.xp"), 0); + float experience_slayer_spider = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.spider.xp"), 0); + float experience_slayer_wolf = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.wolf.xp"), 0); + + float totalSkillXP = experience_skill_taming + experience_skill_mining + experience_skill_foraging + + experience_skill_enchanting + experience_skill_carpentry + experience_skill_farming + + experience_skill_combat + experience_skill_fishing + experience_skill_alchemy + + experience_skill_catacombs + + experience_skill_runecrafting; + + if(totalSkillXP <= 0) { + return null; + } + + JsonObject skillInfo = new JsonObject(); + + skillInfo.addProperty("experience_skill_taming", experience_skill_taming); + skillInfo.addProperty("experience_skill_mining", experience_skill_mining); + skillInfo.addProperty("experience_skill_foraging", experience_skill_foraging); + skillInfo.addProperty("experience_skill_enchanting", experience_skill_enchanting); + skillInfo.addProperty("experience_skill_carpentry", experience_skill_carpentry); + skillInfo.addProperty("experience_skill_farming", experience_skill_farming); + skillInfo.addProperty("experience_skill_combat", experience_skill_combat); + skillInfo.addProperty("experience_skill_fishing", experience_skill_fishing); + skillInfo.addProperty("experience_skill_alchemy", experience_skill_alchemy); + skillInfo.addProperty("experience_skill_runecrafting", experience_skill_runecrafting); + + skillInfo.addProperty("experience_skill_catacombs", experience_skill_catacombs); + + skillInfo.addProperty("experience_slayer_zombie", experience_slayer_zombie); + skillInfo.addProperty("experience_slayer_spider", experience_slayer_spider); + skillInfo.addProperty("experience_slayer_wolf", experience_slayer_wolf); + + Level level_skill_taming = getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_taming, false); + Level level_skill_mining = getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_mining, false); + Level level_skill_foraging = getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_foraging, false); + Level level_skill_enchanting = getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_enchanting, false); + Level level_skill_carpentry = getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_carpentry, false); + Level level_skill_farming = getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_farming, false); + Level level_skill_combat = getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_combat, false); + Level level_skill_fishing = getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_fishing, false); + Level level_skill_alchemy = getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_alchemy, false); + Level level_skill_runecrafting = getLevel(Utils.getElement(leveling, "runecrafting_xp").getAsJsonArray(), experience_skill_runecrafting, false); + + Level level_skill_catacombs = getLevel(Utils.getElement(leveling, "catacombs").getAsJsonArray(), experience_skill_catacombs, false); + + Level level_slayer_zombie = getLevel(Utils.getElement(leveling, "slayer_xp.zombie").getAsJsonArray(), experience_slayer_zombie, true); + Level level_slayer_spider = getLevel(Utils.getElement(leveling, "slayer_xp.spider").getAsJsonArray(), experience_slayer_spider, true); + Level level_slayer_wolf = getLevel(Utils.getElement(leveling, "slayer_xp.wolf").getAsJsonArray(), experience_slayer_wolf, true); + + skillInfo.addProperty("level_skill_taming", level_skill_taming.level); + skillInfo.addProperty("level_skill_mining", level_skill_mining.level); + skillInfo.addProperty("level_skill_foraging", level_skill_foraging.level); + skillInfo.addProperty("level_skill_enchanting", level_skill_enchanting.level); + skillInfo.addProperty("level_skill_carpentry", level_skill_carpentry.level); + skillInfo.addProperty("level_skill_farming", level_skill_farming.level); + skillInfo.addProperty("level_skill_combat", level_skill_combat.level); + skillInfo.addProperty("level_skill_fishing", level_skill_fishing.level); + skillInfo.addProperty("level_skill_alchemy", level_skill_alchemy.level); + skillInfo.addProperty("level_skill_runecrafting", level_skill_runecrafting.level); + + skillInfo.addProperty("level_skill_catacombs", level_skill_catacombs.level); + + skillInfo.addProperty("level_slayer_zombie", level_slayer_zombie.level); + skillInfo.addProperty("level_slayer_spider", level_slayer_spider.level); + skillInfo.addProperty("level_slayer_wolf", level_slayer_wolf.level); + + skillInfo.addProperty("maxed_skill_taming", level_skill_taming.maxed); + skillInfo.addProperty("maxed_skill_mining", level_skill_mining.maxed); + skillInfo.addProperty("maxed_skill_foraging", level_skill_foraging.maxed); + skillInfo.addProperty("maxed_skill_enchanting", level_skill_enchanting.maxed); + skillInfo.addProperty("maxed_skill_carpentry", level_skill_carpentry.maxed); + skillInfo.addProperty("maxed_skill_farming", level_skill_farming.maxed); + skillInfo.addProperty("maxed_skill_combat", level_skill_combat.maxed); + skillInfo.addProperty("maxed_skill_fishing", level_skill_fishing.maxed); + skillInfo.addProperty("maxed_skill_alchemy", level_skill_alchemy.maxed); + skillInfo.addProperty("maxed_skill_runecrafting", level_skill_runecrafting.maxed); + + skillInfo.addProperty("maxed_skill_catacombs", level_skill_catacombs.maxed); + + skillInfo.addProperty("maxed_slayer_zombie", level_slayer_zombie.maxed); + skillInfo.addProperty("maxed_slayer_spider", level_slayer_spider.maxed); + skillInfo.addProperty("maxed_slayer_wolf", level_slayer_wolf.maxed); + + skillInfo.addProperty("maxxp_skill_taming", level_skill_taming.maxXpForLevel); + skillInfo.addProperty("maxxp_skill_mining", level_skill_mining.maxXpForLevel); + skillInfo.addProperty("maxxp_skill_foraging", level_skill_foraging.maxXpForLevel); + skillInfo.addProperty("maxxp_skill_enchanting", level_skill_enchanting.maxXpForLevel); + skillInfo.addProperty("maxxp_skill_carpentry", level_skill_carpentry.maxXpForLevel); + skillInfo.addProperty("maxxp_skill_farming", level_skill_farming.maxXpForLevel); + skillInfo.addProperty("maxxp_skill_combat", level_skill_combat.maxXpForLevel); + skillInfo.addProperty("maxxp_skill_fishing", level_skill_fishing.maxXpForLevel); + skillInfo.addProperty("maxxp_skill_alchemy", level_skill_alchemy.maxXpForLevel); + skillInfo.addProperty("maxxp_skill_runecrafting", level_skill_runecrafting.maxXpForLevel); + + skillInfo.addProperty("maxxp_skill_catacombs", level_skill_catacombs.maxXpForLevel); + + skillInfo.addProperty("maxxp_slayer_zombie", level_slayer_zombie.maxXpForLevel); + skillInfo.addProperty("maxxp_slayer_spider", level_slayer_spider.maxXpForLevel); + skillInfo.addProperty("maxxp_slayer_wolf", level_slayer_wolf.maxXpForLevel); + + return skillInfo; + } + + public JsonObject getInventoryInfo(String profileId) { + JsonObject profileInfo = getProfileInformation(profileId); + if(profileInfo == null) return null; + if(profileId == null) profileId = latestProfile; + if(inventoryInfoMap.containsKey(profileId)) return inventoryInfoMap.get(profileId); + + String inv_armor_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "inv_armor.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA="); + String fishing_bag_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "fishing_bag.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA="); + String quiver_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "quiver.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA="); + String ender_chest_contents_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "ender_chest_contents.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA="); + String wardrobe_contents_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "wardrobe_contents.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA="); + String potion_bag_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "potion_bag.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA="); + String inv_contents_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "inv_contents.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA="); + String talisman_bag_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "talisman_bag.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA="); + String candy_inventory_contents_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "candy_inventory_contents.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA="); + + JsonObject inventoryInfo = new JsonObject(); + + String[] inv_names = new String[]{"inv_armor", "fishing_bag", "quiver", "ender_chest_contents", "wardrobe_contents", + "potion_bag", "inv_contents", "talisman_bag", "candy_inventory_contents"}; + String[] inv_bytes = new String[]{inv_armor_bytes, fishing_bag_bytes, quiver_bytes, ender_chest_contents_bytes, wardrobe_contents_bytes, + potion_bag_bytes, inv_contents_bytes, talisman_bag_bytes, candy_inventory_contents_bytes}; + for(int i=0; i<inv_bytes.length; i++) { + try { + String bytes = inv_bytes[i]; + + JsonArray contents = new JsonArray(); + NBTTagCompound inv_contents_nbt = CompressedStreamTools.readCompressed(new ByteArrayInputStream(Base64.getDecoder().decode(bytes))); + NBTTagList items = inv_contents_nbt.getTagList("i", 10); + for(int j=0; j<items.tagCount(); j++) { + JsonObject item = manager.getJsonFromNBTEntry(items.getCompoundTagAt(j)); + contents.add(item); + } + inventoryInfo.add(inv_names[i], contents); + } catch(IOException e) { + inventoryInfo.add(inv_names[i], new JsonArray()); + } + } + + inventoryInfoMap.put(profileId, inventoryInfo); + + return inventoryInfo; + } + + public JsonObject getPetsInfo(String profileId) { + JsonObject profileInfo = getProfileInformation(profileId); + if(profileInfo == null) return null; + if(petsInfoMap.containsKey(profileId)) return petsInfoMap.get(profileId); + + JsonObject petsInfo = new JsonObject(); + JsonElement petsElement = profileInfo.get("pets"); + if(petsElement != null && petsElement.isJsonArray()) { + JsonObject activePet = null; + JsonArray pets = petsElement.getAsJsonArray(); + for(int i=0; i<pets.size(); i++) { + JsonObject pet = pets.get(i).getAsJsonObject(); + if(pet.has("active") && pet.get("active").getAsJsonPrimitive().getAsBoolean()) { + activePet = pet; + break; + } + } + petsInfo.add("active_pet", activePet); + petsInfo.add("pets", pets); + petsInfoMap.put(profileId, petsInfo); + return petsInfo; + } + return null; + } + + private final Pattern COLL_TIER_PATTERN = Pattern.compile("_(-?[0-9]+)"); + public JsonObject getCollectionInfo(String profileId) { + JsonObject profileInfo = getProfileInformation(profileId); + if(profileInfo == null) return null; + JsonObject resourceCollectionInfo = getResourceCollectionInformation(); + if(resourceCollectionInfo == null) return null; + if(profileId == null) profileId = latestProfile; + if(collectionInfoMap.containsKey(profileId)) return collectionInfoMap.get(profileId); + + JsonElement unlocked_coll_tiers_element = Utils.getElement(profileInfo, "unlocked_coll_tiers"); + JsonElement crafted_generators_element = Utils.getElement(profileInfo, "crafted_generators"); + JsonElement collectionInfoElement = Utils.getElement(profileInfo, "collection"); + + if(unlocked_coll_tiers_element == null || crafted_generators_element == null || collectionInfoElement == null) { + return null; + } + + JsonObject collectionInfo = new JsonObject(); + JsonObject collectionTiers = new JsonObject(); + JsonObject minionTiers = new JsonObject(); + JsonObject personalAmounts = new JsonObject(); + JsonObject totalAmounts = new JsonObject(); + + if(collectionInfoElement.isJsonObject()) { + personalAmounts = collectionInfoElement.getAsJsonObject(); + } + + for(Map.Entry<String, JsonElement> entry : personalAmounts.entrySet()) { + totalAmounts.addProperty(entry.getKey(), entry.getValue().getAsInt()); + } + + List<JsonObject> coopProfiles = getCoopProfileInformation(profileId); + if(coopProfiles != null) { + for(JsonObject coopProfile : coopProfiles) { + JsonElement coopCollectionInfoElement = Utils.getElement(coopProfile, "collection"); + if(coopCollectionInfoElement != null && coopCollectionInfoElement.isJsonObject()) { + for(Map.Entry<String, JsonElement> entry : coopCollectionInfoElement.getAsJsonObject().entrySet()) { + float existing = Utils.getElementAsFloat(totalAmounts.get(entry.getKey()), 0); + totalAmounts.addProperty(entry.getKey(), existing+entry.getValue().getAsInt()); + } + } + } + } + + if(unlocked_coll_tiers_element != null && unlocked_coll_tiers_element.isJsonArray()) { + JsonArray unlocked_coll_tiers = unlocked_coll_tiers_element.getAsJsonArray(); + for(int i=0; i<unlocked_coll_tiers.size(); i++) { + String unlocked = unlocked_coll_tiers.get(i).getAsString(); + + Matcher matcher = COLL_TIER_PATTERN.matcher(unlocked); + + if(matcher.find()) { + String tier_str = matcher.group(1); + int tier = Integer.parseInt(tier_str); + String coll = unlocked.substring(0, unlocked.length()-(matcher.group().length())); + if(!collectionTiers.has(coll) || collectionTiers.get(coll).getAsInt() < tier) { + collectionTiers.addProperty(coll, tier); + } + } + } + } + + if(crafted_generators_element != null && crafted_generators_element.isJsonArray()) { + JsonArray crafted_generators = crafted_generators_element.getAsJsonArray(); + for(int i=0; i<crafted_generators.size(); i++) { + String unlocked = crafted_generators.get(i).getAsString(); + + Matcher matcher = COLL_TIER_PATTERN.matcher(unlocked); + + if(matcher.find()) { + String tier_str = matcher.group(1); + int tier = Integer.parseInt(tier_str); + String coll = unlocked.substring(0, unlocked.length()-(matcher.group().length())); + if(!minionTiers.has(coll) || minionTiers.get(coll).getAsInt() < tier) { + minionTiers.addProperty(coll, tier); + } + } + } + } + + JsonObject maxAmount = new JsonObject(); + JsonObject updatedCollectionTiers = new JsonObject(); + for(Map.Entry<String, JsonElement> totalAmountsEntry : totalAmounts.entrySet()) { + String collName = totalAmountsEntry.getKey(); + int collTier = (int)Utils.getElementAsFloat(collectionTiers.get(collName), 0); + + int currentAmount = (int)Utils.getElementAsFloat(totalAmounts.get(collName), 0); + if(currentAmount > 0) { + for(Map.Entry<String, JsonElement> resourceEntry : resourceCollectionInfo.entrySet()) { + JsonElement tiersElement = Utils.getElement(resourceEntry.getValue(), "items."+collName+".tiers"); + if(tiersElement != null && tiersElement.isJsonArray()) { + JsonArray tiers = tiersElement.getAsJsonArray(); + int maxTierAcquired = -1; + int maxAmountRequired = -1; + for(int i=0; i<tiers.size(); i++) { + JsonObject tierInfo = tiers.get(i).getAsJsonObject(); + int tier = tierInfo.get("tier").getAsInt(); + int amountRequired = tierInfo.get("amountRequired").getAsInt(); + if(currentAmount >= amountRequired) { + maxTierAcquired = tier; + } + maxAmountRequired = amountRequired; + } + if(maxTierAcquired >= 0 && maxTierAcquired > collTier) { + updatedCollectionTiers.addProperty(collName, maxTierAcquired); + } + maxAmount.addProperty(collName, maxAmountRequired); + } + } + } + } + + for(Map.Entry<String, JsonElement> collectionTiersEntry : updatedCollectionTiers.entrySet()) { + collectionTiers.add(collectionTiersEntry.getKey(), collectionTiersEntry.getValue()); + } + + collectionInfo.add("minion_tiers", minionTiers); + collectionInfo.add("max_amounts", maxAmount); + collectionInfo.add("personal_amounts", personalAmounts); + collectionInfo.add("total_amounts", totalAmounts); + collectionInfo.add("collection_tiers", collectionTiers); + + return collectionInfo; + } + + public PlayerStats.Stats getPassiveStats(String profileId) { + if(passiveStats.get(profileId) != null) return passiveStats.get(profileId); + JsonObject profileInfo = getProfileInformation(profileId); + if(profileInfo == null) return null; + + PlayerStats.Stats passiveStats = PlayerStats.getPassiveBonuses(getSkillInfo(profileId), profileInfo); + + if(passiveStats != null) { + passiveStats.add(PlayerStats.getBaseStats()); + } + + this.passiveStats.put(profileId, passiveStats); + + return passiveStats; + } + + public PlayerStats.Stats getStats(String profileId) { + //if(stats.get(profileId) != null) return stats.get(profileId); + JsonObject profileInfo = getProfileInformation(profileId); + if(profileInfo == null) { + return null; + } + + PlayerStats.Stats stats = PlayerStats.getStats(getSkillInfo(profileId), getInventoryInfo(profileId), getCollectionInfo(profileId), profileInfo); + this.stats.put(profileId, stats); + return stats; + } + + public String getUuid() { + return uuid; + } + + public JsonObject getHypixelProfile() { + if(uuidToHypixelProfile.containsKey(uuid)) return uuidToHypixelProfile.get(uuid); + return null; + } + } + + private HashMap<String, JsonObject> nameToHypixelProfile = new HashMap<>(); + private HashMap<String, JsonObject> uuidToHypixelProfile = new HashMap<>(); + private HashMap<String, Profile> uuidToProfileMap = new HashMap<>(); + + public void getHypixelProfile(String name, Consumer<JsonObject> callback) { + HashMap<String, String> args = new HashMap<>(); + args.put("name", ""+name); + manager.hypixelApi.getHypixelApiAsync(manager.config.apiKey.value, "player", + args, jsonObject -> { + if(jsonObject != null && jsonObject.has("success") && jsonObject.get("success").getAsBoolean() + && jsonObject.get("player").isJsonObject()) { + nameToHypixelProfile.put(name, jsonObject.get("player").getAsJsonObject()); + uuidToHypixelProfile.put(jsonObject.get("player").getAsJsonObject().get("uuid").getAsString(), jsonObject.get("player").getAsJsonObject()); + if(callback != null) callback.accept(jsonObject); + } else { + if(callback != null) callback.accept(null); + return; + } + } + ); + } + + public Profile getProfileByName(String name, Consumer<Profile> callback) { + if(nameToHypixelProfile.containsKey(name)) { + Profile profile = getProfileReset(nameToHypixelProfile.get(name).get("uuid").getAsString(), ignored -> {}); + callback.accept(profile); + return profile; + } else { + getHypixelProfile(name, jsonObject -> { + if(jsonObject == null) { + callback.accept(null); + } else { + callback.accept(getProfileReset(jsonObject.get("player").getAsJsonObject().get("uuid").getAsString(), ignored -> {})); + } + + }); + } + return null; + } + + public Profile getProfile(String uuid, Consumer<Profile> callback) { + Profile profile = uuidToProfileMap.computeIfAbsent(uuid, k -> new Profile(uuid)); + if(profile.playerInformation != null) { + callback.accept(profile); + } else { + profile.getPlayerInformation(() -> callback.accept(profile)); + } + return profile; + } + + public Profile getProfileReset(String uuid, Consumer<Profile> callback) { + Profile profile = getProfile(uuid, callback); + profile.resetCache(); + return profile; + } + + private static JsonObject resourceCollection = null; + private static AtomicBoolean updatingResourceCollection = new AtomicBoolean(false); + public static JsonObject getResourceCollectionInformation() { + if(resourceCollection != null) return resourceCollection; + if(updatingResourceCollection.get()) return null; + + updatingResourceCollection.set(true); + + HashMap<String, String> args = new HashMap<>(); + NotEnoughUpdates.INSTANCE.manager.hypixelApi.getHypixelApiAsync(NotEnoughUpdates.INSTANCE.manager.config.apiKey.value, "resources/skyblock/collections", + args, jsonObject -> { + updatingResourceCollection.set(false); + if(jsonObject != null && jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) { + resourceCollection = jsonObject.get("collections").getAsJsonObject(); + } + }, () -> { + updatingResourceCollection.set(false); + } + ); + + return null; + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/questing/NEUQuesting.java b/src/main/java/io/github/moulberry/notenoughupdates/questing/NEUQuesting.java deleted file mode 100644 index 8be12c95..00000000 --- a/src/main/java/io/github/moulberry/notenoughupdates/questing/NEUQuesting.java +++ /dev/null @@ -1,67 +0,0 @@ -package io.github.moulberry.notenoughupdates.questing; - -import io.github.moulberry.notenoughupdates.NotEnoughUpdates; -import io.github.moulberry.notenoughupdates.util.Utils; -import net.minecraft.client.Minecraft; -import net.minecraft.scoreboard.Score; -import net.minecraft.scoreboard.ScoreObjective; -import net.minecraft.scoreboard.ScorePlayerTeam; -import net.minecraft.scoreboard.Scoreboard; -import net.minecraft.util.EnumChatFormatting; - -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class NEUQuesting { - - private static final NEUQuesting INSTANCE = new NEUQuesting(); - - private static final Pattern locationPattern = Pattern.compile("(\\u00a7)(?!.*\\u00a7).+"); - private static final Pattern timePattern = Pattern.compile(".+(am|pm)"); - - public String location = ""; - public String date = ""; - public String time = ""; - - public static NEUQuesting getInstance() { - return INSTANCE; - } - - public void tick() { - Scoreboard scoreboard = Minecraft.getMinecraft().thePlayer.getWorldScoreboard(); - - ScoreObjective sidebarObjective = scoreboard.getObjectiveInDisplaySlot(1); //§707/14/20 - - List<Score> scores = new ArrayList<>(); - for(Score score : scoreboard.getSortedScores(sidebarObjective)) { - scores.add(score); - } - List<String> lines = new ArrayList<>(); - for(int i=scores.size()-1; i>=0; i--) { - Score score = scores.get(i); - ScorePlayerTeam scoreplayerteam1 = scoreboard.getPlayersTeam(score.getPlayerName()); - String line = ScorePlayerTeam.formatPlayerName(scoreplayerteam1, score.getPlayerName()); - line = Utils.cleanDuplicateColourCodes(line); - lines.add(line); - } - if(lines.size() >= 5) { - date = Utils.cleanColour(lines.get(2)).trim(); - //§74:40am - Matcher matcher = timePattern.matcher(lines.get(3)); - if(matcher.find()) { - time = Utils.cleanColour(matcher.group()).trim(); - } - matcher = locationPattern.matcher(lines.get(4)); - if(matcher.find()) { - location = Utils.cleanColour(matcher.group()).trim(); - } - } - //System.out.println(date + ":" + time + ":" + location); - } - -} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/questing/SBInfo.java b/src/main/java/io/github/moulberry/notenoughupdates/questing/SBInfo.java new file mode 100644 index 00000000..2d594ccf --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/questing/SBInfo.java @@ -0,0 +1,128 @@ +package io.github.moulberry.notenoughupdates.questing; + +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.scoreboard.Score; +import net.minecraft.scoreboard.ScoreObjective; +import net.minecraft.scoreboard.ScorePlayerTeam; +import net.minecraft.scoreboard.Scoreboard; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.event.world.WorldEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SBInfo { + + private static final SBInfo INSTANCE = new SBInfo(); + + private static final Pattern timePattern = Pattern.compile(".+(am|pm)"); + + public String location = ""; + public String date = ""; + public String time = ""; + public String objective = ""; + + public String mode = ""; + + public Date currentTimeDate = null; + + public static SBInfo getInstance() { + return INSTANCE; + } + + private long lastLocRaw = -1; + private JsonObject locraw = null; + + @SubscribeEvent + public void onWorldChange(WorldEvent.Load event) { + lastLocRaw = -1; + locraw = null; + } + + @SubscribeEvent + public void onChatMessage(ClientChatReceivedEvent event) { + if(event.message.getUnformattedText().startsWith("{")) { + try { + JsonObject obj = NotEnoughUpdates.INSTANCE.manager.gson.fromJson(event.message.getUnformattedText(), JsonObject.class); + if(obj.has("server")) { + event.setCanceled(true); + if(obj.has("gametype") && obj.has("mode") && obj.has("map")) { + locraw = obj; + } + } + + } catch(Exception e) { + e.printStackTrace(); + } + } + } + + public String getLocation() { + if(locraw == null) { + return null; + } + return locraw.get("mode").getAsString(); + } + + public void tick() { + if(locraw == null && (System.currentTimeMillis() - lastLocRaw) > 20000) { + lastLocRaw = System.currentTimeMillis(); + NotEnoughUpdates.INSTANCE.sendChatMessage("/locraw"); + } + + try { + Scoreboard scoreboard = Minecraft.getMinecraft().thePlayer.getWorldScoreboard(); + + ScoreObjective sidebarObjective = scoreboard.getObjectiveInDisplaySlot(1); //§707/14/20 + + List<Score> scores = new ArrayList<>(); + for(Score score : scoreboard.getSortedScores(sidebarObjective)) { + scores.add(score); + } + List<String> lines = new ArrayList<>(); + for(int i=scores.size()-1; i>=0; i--) { + Score score = scores.get(i); + ScorePlayerTeam scoreplayerteam1 = scoreboard.getPlayersTeam(score.getPlayerName()); + String line = ScorePlayerTeam.formatPlayerName(scoreplayerteam1, score.getPlayerName()); + line = Utils.cleanDuplicateColourCodes(line); + lines.add(line); + } + if(lines.size() >= 5) { + date = Utils.cleanColour(lines.get(1)).trim(); + //§74:40am + Matcher matcher = timePattern.matcher(lines.get(2)); + if(matcher.find()) { + time = Utils.cleanColour(matcher.group()).trim(); + try { + String timeSpace = time.replace("am", " am").replace("pm", " pm"); + SimpleDateFormat parseFormat = new SimpleDateFormat("hh:mm a"); + currentTimeDate = parseFormat.parse(timeSpace); + } catch (ParseException e) {} + } + location = Utils.cleanColour(lines.get(3)).replaceAll("[^A-Za-z0-9() ]", "").trim(); + } + objective = null; + + boolean objTextLast = false; + for(String line : lines) { + if(objTextLast) { + objective = line; + } + + objTextLast = line.equals("Objective"); + } + } catch(Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/questing/requirements/RequirementApi.java b/src/main/java/io/github/moulberry/notenoughupdates/questing/requirements/RequirementApi.java index 951cfa50..16da64fe 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/questing/requirements/RequirementApi.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/questing/requirements/RequirementApi.java @@ -3,10 +3,8 @@ package io.github.moulberry.notenoughupdates.questing.requirements; import com.google.common.base.Splitter; import com.google.gson.*; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; -import io.github.moulberry.notenoughupdates.questing.NEUQuesting; import java.util.List; -import java.util.Map; public class RequirementApi extends Requirement { @@ -40,7 +38,6 @@ public class RequirementApi extends Requirement { private static JsonElement getElement(JsonElement element, String path) { List<String> path_split = PATH_SPLITTER.splitToList(path); if(element instanceof JsonObject) { - System.out.println(path_split.get(0)); JsonElement e = element.getAsJsonObject().get(path_split.get(0)); if(path_split.size() > 1) { return getElement(e, path_split.get(1)); @@ -100,12 +97,12 @@ public class RequirementApi extends Requirement { @Override public void updateRequirement() { if(valid) { - JsonObject profile = NotEnoughUpdates.INSTANCE.manager.auctionManager.getPlayerInformation(); + /*JsonObject profile = NotEnoughUpdates.INSTANCE.manager.auctionManager.getPlayerInformation(); if(profile != null) { System.out.println("-----------"); JsonElement element = getElement(profile, requirementLeft); completed = checkElementSatisfiesComparison(element, op, requirementRight); - } + }*/ } } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/questing/requirements/RequirementIslandType.java b/src/main/java/io/github/moulberry/notenoughupdates/questing/requirements/RequirementIslandType.java index 5ee005f5..c0aef344 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/questing/requirements/RequirementIslandType.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/questing/requirements/RequirementIslandType.java @@ -1,6 +1,6 @@ package io.github.moulberry.notenoughupdates.questing.requirements; -import io.github.moulberry.notenoughupdates.questing.NEUQuesting; +import io.github.moulberry.notenoughupdates.questing.SBInfo; public class RequirementIslandType extends Requirement { @@ -14,6 +14,6 @@ public class RequirementIslandType extends Requirement { @Override public void updateRequirement() { - completed = islandType.equalsIgnoreCase(NEUQuesting.getInstance().location); + completed = islandType.equalsIgnoreCase(SBInfo.getInstance().location); } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java new file mode 100644 index 00000000..f70d3a3c --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java @@ -0,0 +1,15 @@ +package io.github.moulberry.notenoughupdates.util; + +import com.google.gson.JsonObject; + +public class Constants { + + public static final JsonObject BONUSES = Utils.getConstant("bonuses"); + public static final JsonObject DISABLE = Utils.getConstant("disable"); + public static final JsonObject ENCHANTS = Utils.getConstant("enchants"); + public static final JsonObject LEVELING = Utils.getConstant("leveling"); + public static final JsonObject MISC = Utils.getConstant("misc"); + public static final JsonObject PETNUMS = Utils.getConstant("petnums"); + public static final JsonObject PETS = Utils.getConstant("pets"); + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java b/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java index c271d63a..2e6b29da 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java @@ -2,6 +2,7 @@ package io.github.moulberry.notenoughupdates.util; import com.google.gson.Gson; import com.google.gson.JsonObject; +import org.apache.commons.io.IOUtils; import java.io.BufferedReader; import java.io.IOException; @@ -16,57 +17,99 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.function.Consumer; +import java.util.zip.GZIPInputStream; public class HypixelApi { - - /** - * Not currently used as of BETA-1.6. - */ - private Gson gson = new Gson(); - private ExecutorService es = Executors.newCachedThreadPool(); + private ExecutorService es = Executors.newFixedThreadPool(3); + + private int myApiErrors = 0; + private String[] myApiURLs = {"https://moulberry.codes/", "http://51.75.78.252/", "http://moulberry.codes/" }; public void getHypixelApiAsync(String apiKey, String method, HashMap<String, String> args, Consumer<JsonObject> consumer) { - getHypixelApiAsync(generateApiUrl(apiKey.trim(), method, args), consumer); + getHypixelApiAsync(apiKey, method, args, consumer, () -> {}); + } + + public void getHypixelApiAsync(String apiKey, String method, HashMap<String, String> args, Consumer<JsonObject> consumer, Runnable error) { + getApiAsync(generateApiUrl(apiKey.trim(), method, args), consumer, error); + } + + private String getMyApiURL() { + return myApiURLs[myApiErrors%myApiURLs.length]; } - public void getHypixelApiAsync(String urlS, Consumer<JsonObject> consumer) { + public void getApiAsync(String urlS, Consumer<JsonObject> consumer, Runnable error) { es.submit(() -> { - consumer.accept(getHypixelApiSync(urlS)); + try { + consumer.accept(getApiSync(urlS)); + } catch(Exception e) { + error.run(); + } }); } - public JsonObject getHypixelApiSync(String urlS) { - URLConnection connection; - try { - URL url = new URL(urlS); - connection = url.openConnection(); - connection.setConnectTimeout(3000); - } catch(IOException e) { - return null; - } + public void getMyApiAsync(String urlS, Consumer<JsonObject> consumer, Runnable error) { + es.submit(() -> { + try { + consumer.accept(getApiSync(getMyApiURL()+urlS)); + } catch(Exception e) { + myApiErrors++; + error.run(); + } + }); + } + + public void getMyApiGZIPAsync(String urlS, Consumer<JsonObject> consumer, Runnable error) { + es.submit(() -> { + try { + consumer.accept(getApiGZIPSync(getMyApiURL()+urlS)); + } catch(Exception e) { + myApiErrors++; + error.run(); + } + }); + } - try(BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { - StringBuilder builder = new StringBuilder(); - int codePoint; - while((codePoint = reader.read()) != -1) { - builder.append(((char)codePoint)); + public void getApiGZIPAsync(String urlS, Consumer<JsonObject> consumer, Runnable error) { + es.submit(() -> { + try { + consumer.accept(getApiGZIPSync(urlS)); + } catch(Exception e) { + error.run(); } - String response = builder.toString(); + }); + } - JsonObject json = gson.fromJson(response, JsonObject.class); - return json; - } catch(IOException e) { - return null; - } + public JsonObject getApiSync(String urlS) throws IOException { + URL url = new URL(urlS); + URLConnection connection = url.openConnection(); + connection.setConnectTimeout(10000); + connection.setReadTimeout(10000); + + String response = IOUtils.toString(connection.getInputStream(), StandardCharsets.UTF_8); + + JsonObject json = gson.fromJson(response, JsonObject.class); + return json; + } + + public JsonObject getApiGZIPSync(String urlS) throws IOException { + URL url = new URL(urlS); + URLConnection connection = url.openConnection(); + connection.setConnectTimeout(10000); + connection.setReadTimeout(10000); + + String response = IOUtils.toString(new GZIPInputStream(connection.getInputStream()), StandardCharsets.UTF_8); + + JsonObject json = gson.fromJson(response, JsonObject.class); + return json; } public String generateApiUrl(String apiKey, String method, HashMap<String, String> args) { - String url = "https://api.hypixel.net/" + method + "?key=" + apiKey; + StringBuilder url = new StringBuilder("https://api.hypixel.net/" + method + "?key=" + apiKey); for(Map.Entry<String, String> entry : args.entrySet()) { - url += "&" + entry.getKey() + "=" + entry.getValue(); + url.append("&").append(entry.getKey()).append("=").append(entry.getValue()); } - return url; + return url.toString(); } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/SpecialColour.java b/src/main/java/io/github/moulberry/notenoughupdates/util/SpecialColour.java new file mode 100644 index 00000000..5bcd23c3 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/SpecialColour.java @@ -0,0 +1,95 @@ +package io.github.moulberry.notenoughupdates.util; + +import java.awt.*; + +public class SpecialColour { + + public static String special(int chromaSpeed, int alpha, int rgb) { + return special(chromaSpeed, alpha, (rgb & 0xFF0000) >> 16, (rgb & 0x00FF00) >> 8, (rgb & 0x0000FF)); + } + + private static final int RADIX = 10; + + public static String special(int chromaSpeed, int alpha, int r, int g, int b) { + StringBuilder sb = new StringBuilder(); + sb.append(Integer.toString(chromaSpeed, RADIX)).append(":"); + sb.append(Integer.toString(alpha, RADIX)).append(":"); + sb.append(Integer.toString(r, RADIX)).append(":"); + sb.append(Integer.toString(g, RADIX)).append(":"); + sb.append(Integer.toString(b, RADIX)); + return sb.toString(); + } + + private static int[] decompose(String csv) { + String[] split = csv.split(":"); + + int[] arr = new int[split.length]; + + + for(int i=0; i<split.length; i++) { + arr[i] = Integer.parseInt(split[split.length-1-i], RADIX); + } + return arr; + } + + public static int specialToSimpleRGB(String special) { + int[] d = decompose(special); + int r = d[2]; + int g = d[1]; + int b = d[0]; + int a = d[3]; + int chr = d[4]; + + return (a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF); + } + + public static int getSpeed(String special) { + return decompose(special)[4]; + } + + public static float getSecondsForSpeed(int speed) { + return (255-speed)/254f*(MAX_CHROMA_SECS-MIN_CHROMA_SECS)+MIN_CHROMA_SECS; + } + + private static final int MIN_CHROMA_SECS = 1; + private static final int MAX_CHROMA_SECS = 60; + + public static long startTime = -1; + public static int specialToChromaRGB(String special) { + if(startTime < 0) startTime = System.currentTimeMillis(); + + int[] d = decompose(special); + int chr = d[4]; + int a = d[3]; + int r = d[2]; + int g = d[1]; + int b = d[0]; + + float[] hsv = Color.RGBtoHSB(r, g, b, null); + + if(chr > 0) { + float seconds = getSecondsForSpeed(chr); + hsv[0] += (System.currentTimeMillis()-startTime)/1000f/seconds; + hsv[0] %= 1; + if(hsv[0] < 0) hsv[0] += 1; + } + + return (a & 0xFF) << 24 | (Color.HSBtoRGB(hsv[0], hsv[1], hsv[2]) & 0x00FFFFFF); + } + + public static int rotateHue(int argb, int degrees) { + int a = (argb >> 24) & 0xFF; + int r = (argb >> 16) & 0xFF; + int g = (argb >> 8) & 0xFF; + int b = (argb) & 0xFF; + + float[] hsv = Color.RGBtoHSB(r, g, b, null); + + hsv[0] += degrees/360f; + hsv[0] %= 1; + + return (a & 0xFF) << 24 | (Color.HSBtoRGB(hsv[0], hsv[1], hsv[2]) & 0x00FFFFFF); + } + + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java b/src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java index 48eea22d..5e792cf5 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java @@ -20,7 +20,7 @@ public class TexLoc { this.toggleKey = toggleKey; } - public void handleKeyboardInput() { + public boolean handleKeyboardInput() { int mult=1; if(Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)) mult=10; if(Keyboard.isKeyDown(toggleKey)) { @@ -31,7 +31,7 @@ public class TexLoc { } else { pressedLastTick = false; } - if(toggled) { + if(toggled || toggleKey == 0) { if(Keyboard.isKeyDown(Keyboard.KEY_LEFT)) { if(!dirPressed) x-=mult; dirPressed = true; @@ -46,10 +46,12 @@ public class TexLoc { dirPressed = true; } else { dirPressed = false; - return; + return false; } System.out.println("X: " + x + " ; Y: " + y); + return true; } + return false; } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java index 57b89a0a..e2faa5aa 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java @@ -1,5 +1,10 @@ package io.github.moulberry.notenoughupdates.util; +import com.google.common.base.Splitter; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; import com.mojang.authlib.Agent; import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication; @@ -9,13 +14,15 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.audio.SoundHandler; import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.gui.inventory.GuiContainer; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.block.model.ItemCameraTransforms; import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.resources.model.IBakedModel; import net.minecraft.event.ClickEvent; import net.minecraft.event.HoverEvent; import net.minecraft.inventory.Slot; @@ -24,11 +31,15 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; +import net.minecraft.potion.Potion; import net.minecraft.server.MinecraftServer; import net.minecraft.util.*; +import net.minecraftforge.fml.common.Loader; +import org.lwjgl.BufferUtils; import org.lwjgl.input.Keyboard; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL14; +import org.lwjgl.util.glu.Project; import javax.swing.*; import java.awt.*; @@ -37,16 +48,22 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.Proxy; +import java.nio.FloatBuffer; import java.nio.file.Files; -import java.util.ArrayList; +import java.util.*; import java.util.List; -import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Utils { private static boolean hasEffectOverride = false; + public static boolean disableCustomDungColours = false; + private static LinkedList<Integer> guiScales = new LinkedList<>(); + private static ScaledResolution lastScale = new ScaledResolution(Minecraft.getMinecraft()); + //Labymod compatibility + private static FloatBuffer projectionMatrixOld = BufferUtils.createFloatBuffer(16); + private static FloatBuffer modelviewMatrixOld = BufferUtils.createFloatBuffer(16); public static <T> ArrayList<T> createList(T... values) { ArrayList<T> list = new ArrayList<>(); @@ -54,6 +71,74 @@ public class Utils { return list; } + public static void resetGuiScale() { + guiScales.clear(); + } + + public static ScaledResolution peekGuiScale() { + return lastScale; + } + + public static ScaledResolution pushGuiScale(int scale) { + if(guiScales.size() == 0) { + if(Loader.isModLoaded("labymod")) { + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projectionMatrixOld); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelviewMatrixOld); + } + } + + if(scale < 0) { + if(guiScales.size() > 0) { + guiScales.pop(); + } + } else { + if(scale == 0) { + guiScales.push(Minecraft.getMinecraft().gameSettings.guiScale); + } else { + guiScales.push(scale); + } + } + + int newScale = guiScales.size() > 0 ? Math.max(1, Math.min(4, guiScales.peek())) : Minecraft.getMinecraft().gameSettings.guiScale; + if(newScale == 0) newScale = Minecraft.getMinecraft().gameSettings.guiScale; + + int oldScale = Minecraft.getMinecraft().gameSettings.guiScale; + Minecraft.getMinecraft().gameSettings.guiScale = newScale; + ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + Minecraft.getMinecraft().gameSettings.guiScale = oldScale; + + if(guiScales.size() > 0) { + GlStateManager.viewport(0, 0, Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight); + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GlStateManager.loadIdentity(); + GlStateManager.ortho(0.0D, + scaledresolution.getScaledWidth_double(), + scaledresolution.getScaledHeight_double(), 0.0D, 1000.0D, 3000.0D); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + GlStateManager.loadIdentity(); + GlStateManager.translate(0.0F, 0.0F, -2000.0F); + } else { + if(Loader.isModLoaded("labymod") && projectionMatrixOld.limit() > 0 && modelviewMatrixOld.limit() > 0) { + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GL11.glLoadMatrix(projectionMatrixOld); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + GL11.glLoadMatrix(modelviewMatrixOld); + } else { + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GlStateManager.loadIdentity(); + GlStateManager.ortho(0.0D, + scaledresolution.getScaledWidth_double(), + scaledresolution.getScaledHeight_double(), 0.0D, 1000.0D, 3000.0D); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + GlStateManager.loadIdentity(); + GlStateManager.translate(0.0F, 0.0F, -2000.0F); + } + } + + lastScale = scaledresolution; + return scaledresolution; + } + public static boolean getHasEffectOverride() { return hasEffectOverride; } @@ -61,6 +146,7 @@ public class Utils { public static void drawItemStackWithoutGlint(ItemStack stack, int x, int y) { RenderItem itemRender = Minecraft.getMinecraft().getRenderItem(); + disableCustomDungColours = true; RenderHelper.enableGUIStandardItemLighting(); itemRender.zLevel = -145; //Negates the z-offset of the below method. hasEffectOverride = true; @@ -70,21 +156,129 @@ public class Utils { hasEffectOverride = false; itemRender.zLevel = 0; RenderHelper.disableStandardItemLighting(); + disableCustomDungColours = false; } - public static void drawItemStack(ItemStack stack, int x, int y) { + public static void drawItemStackWithText(ItemStack stack, int x, int y, String text) { if(stack == null)return; RenderItem itemRender = Minecraft.getMinecraft().getRenderItem(); + disableCustomDungColours = true; RenderHelper.enableGUIStandardItemLighting(); itemRender.zLevel = -145; //Negates the z-offset of the below method. itemRender.renderItemAndEffectIntoGUI(stack, x, y); + itemRender.renderItemOverlayIntoGUI(Minecraft.getMinecraft().fontRendererObj, stack, x, y, text); + itemRender.zLevel = 0; + RenderHelper.disableStandardItemLighting(); + disableCustomDungColours = false; + } + + public static void drawItemStack(ItemStack stack, int x, int y) { + if(stack == null) return; + + drawItemStackWithText(stack, x, y, null); + } + + private static final EnumChatFormatting[] rainbow = new EnumChatFormatting[]{ + EnumChatFormatting.RED, + EnumChatFormatting.GOLD, + EnumChatFormatting.YELLOW, + EnumChatFormatting.GREEN, + EnumChatFormatting.AQUA, + EnumChatFormatting.LIGHT_PURPLE, + EnumChatFormatting.DARK_PURPLE + }; + + public static String chromaString(String str) { + return chromaString(str, 0, false); + } + + private static long startTime = 0; + public static String chromaString(String str, float offset, boolean bold) { + str = cleanColour(str); + + long currentTimeMillis = System.currentTimeMillis(); + if(startTime == 0) startTime = currentTimeMillis; + + StringBuilder rainbowText = new StringBuilder(); + int len = 0; + for(int i=0; i<str.length(); i++) { + char c = str.charAt(i); + int index = ((int)(offset+len/12f-(currentTimeMillis-startTime)/100))%rainbow.length; + len += Minecraft.getMinecraft().fontRendererObj.getCharWidth(c); + if(bold) len++; + + if(index < 0) index += rainbow.length; + rainbowText.append(rainbow[index]); + if(bold) rainbowText.append(EnumChatFormatting.BOLD); + rainbowText.append(c); + } + return rainbowText.toString(); + } + + private static char[] c = new char[]{'k', 'm', 'b', 't'}; + public static String shortNumberFormat(double n, int iteration) { + double d = ((long) n / 100) / 10.0; + boolean isRound = (d * 10) %10 == 0; + return (d < 1000? + ((d > 99.9 || isRound || (!isRound && d > 9.99)? + (int) d * 10 / 10 : d + "" + ) + "" + c[iteration]) + : shortNumberFormat(d, iteration+1)); + } + + public static void drawItemStackLinear(ItemStack stack, int x, int y) { + if(stack == null)return; + + RenderItem itemRender = Minecraft.getMinecraft().getRenderItem(); + + RenderHelper.enableGUIStandardItemLighting(); + itemRender.zLevel = -145; //Negates the z-offset of the below method. + + IBakedModel ibakedmodel = itemRender.getItemModelMesher().getItemModel(stack); + GlStateManager.pushMatrix(); + Minecraft.getMinecraft().getTextureManager().bindTexture(TextureMap.locationBlocksTexture); + Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.locationBlocksTexture).setBlurMipmap(true, true); + GlStateManager.enableRescaleNormal(); + GlStateManager.enableAlpha(); + GlStateManager.alphaFunc(516, 0.1F); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(770, 771); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + setupGuiTransform(x, y, ibakedmodel.isGui3d()); + ibakedmodel = net.minecraftforge.client.ForgeHooksClient.handleCameraTransforms(ibakedmodel, ItemCameraTransforms.TransformType.GUI); + itemRender.renderItem(stack, ibakedmodel); + GlStateManager.disableAlpha(); + GlStateManager.disableRescaleNormal(); + GlStateManager.disableLighting(); + GlStateManager.popMatrix(); + Minecraft.getMinecraft().getTextureManager().bindTexture(TextureMap.locationBlocksTexture); + Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.locationBlocksTexture).restoreLastBlurMipmap(); + itemRender.renderItemOverlays(Minecraft.getMinecraft().fontRendererObj, stack, x, y); itemRender.zLevel = 0; RenderHelper.disableStandardItemLighting(); } + private static void setupGuiTransform(int xPosition, int yPosition, boolean isGui3d) { + GlStateManager.translate((float)xPosition, (float)yPosition, 5); + GlStateManager.translate(8.0F, 8.0F, 0.0F); + GlStateManager.scale(1.0F, 1.0F, -1.0F); + GlStateManager.scale(0.5F, 0.5F, 0.5F); + + if (isGui3d) { + GlStateManager.scale(40.0F, 40.0F, 40.0F); + GlStateManager.rotate(210.0F, 1.0F, 0.0F, 0.0F); + GlStateManager.rotate(-135.0F, 0.0F, 1.0F, 0.0F); + GlStateManager.enableLighting(); + } else { + GlStateManager.scale(64.0F, 64.0F, 64.0F); + GlStateManager.rotate(180.0F, 1.0F, 0.0F, 0.0F); + GlStateManager.disableLighting(); + } + } + public static Method getMethod(Class<?> clazz, Class<?>[] params, String... methodNames) { for(String methodName : methodNames) { try { @@ -144,6 +338,33 @@ public class Utils { return str.substring(0, 1).toUpperCase() + str.substring(1).toLowerCase(); } + private static String[] rarityArr = new String[] { + "COMMON", "UNCOMMON", "RARE", "EPIC", "LEGENDARY", "MYTHIC", "SPECIAL", "VERY SPECIAL", + }; + public static int checkItemType(JsonArray lore, boolean contains, String... typeMatches) { + for(int i=lore.size()-1; i>=0; i--) { + String line = lore.get(i).getAsString(); + for(String rarity : rarityArr) { + for(int j=0; j<typeMatches.length; j++) { + if(contains) { + if(line.trim().contains(rarity + " " + typeMatches[j])) { + return j; + } else if(line.trim().contains(rarity + " DUNGEON " + typeMatches[j])) { + return j; + } + } else { + if(line.trim().endsWith(rarity + " " + typeMatches[j])) { + return j; + } else if(line.trim().endsWith(rarity + " DUNGEON " + typeMatches[j])) { + return j; + } + } + } + } + } + return -1; + } + public static void playPressSound() { Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.create( new ResourceLocation("gui.button.press"), 1.0F)); @@ -205,8 +426,39 @@ public class Utils { GlStateManager.disableBlend(); } + public static void drawTexturedRectNoBlend(float x, float y, float width, float height, float uMin, float uMax, float vMin, float vMax, int filter) { + GlStateManager.enableTexture2D(); + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter); + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer + .pos(x, y+height, 0.0D) + .tex(uMin, vMax).endVertex(); + worldrenderer + .pos(x+width, y+height, 0.0D) + .tex(uMax, vMax).endVertex(); + worldrenderer + .pos(x+width, y, 0.0D) + .tex(uMax, vMin).endVertex(); + worldrenderer + .pos(x, y, 0.0D) + .tex(uMin, vMin).endVertex(); + tessellator.draw(); + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + } + public static ItemStack createItemStack(Item item, String displayname, String... lore) { - ItemStack stack = new ItemStack(item); + return createItemStack(item, displayname, 0, lore); + } + + public static ItemStack createItemStack(Item item, String displayname, int damage, String... lore) { + ItemStack stack = new ItemStack(item, 1, damage); NBTTagCompound tag = new NBTTagCompound(); NBTTagCompound display = new NBTTagCompound(); NBTTagList Lore = new NBTTagList(); @@ -219,12 +471,19 @@ public class Utils { display.setTag("Lore", Lore); tag.setTag("display", display); + tag.setInteger("HideFlags", 254); stack.setTagCompound(tag); return stack; } + public static void drawStringF(String str, FontRenderer fr, float x, float y, boolean shadow, int colour) { + GL11.glTranslatef(x, y, 0); + fr.drawString(str, 0, 0, colour, shadow); + GL11.glTranslatef(-x, -y, 0); + } + public static void drawStringScaledMaxWidth(String str, FontRenderer fr, float x, float y, boolean shadow, int len, int colour) { int strLen = fr.getStringWidth(str); float factor = len/(float)strLen; @@ -261,6 +520,19 @@ public class Utils { drawStringScaled(str, fr, x-newLen/2, y-fontHeight/2, shadow, colour, factor); } + public static Matrix4f createProjectionMatrix(int width, int height) { + Matrix4f projMatrix = new Matrix4f(); + projMatrix.setIdentity(); + projMatrix.m00 = 2.0F / (float)width; + projMatrix.m11 = 2.0F / (float)(-height); + projMatrix.m22 = -0.0020001999F; + projMatrix.m33 = 1.0F; + projMatrix.m03 = -1.0F; + projMatrix.m13 = 1.0F; + projMatrix.m23 = -1.0001999F; + return projMatrix; + } + public static void drawStringCenteredScaled(String str, FontRenderer fr, float x, float y, boolean shadow, int len, int colour) { int strLen = fr.getStringWidth(str); float factor = len/(float)strLen; @@ -277,6 +549,15 @@ public class Utils { drawStringScaled(str, fr, x, y-fontHeight/2, shadow, colour, factor); } + public static void drawStringCenteredYScaledMaxWidth(String str, FontRenderer fr, float x, float y, boolean shadow, int len, int colour) { + int strLen = fr.getStringWidth(str); + float factor = len/(float)strLen; + factor = Math.min(1, factor); + float fontHeight = 8*factor; + + drawStringScaled(str, fr, x, y-fontHeight/2, shadow, colour, factor); + } + public static int renderStringTrimWidth(String str, FontRenderer fr, boolean shadow, int x, int y, int len, int colour, int maxLines) { return renderStringTrimWidth(str, fr, shadow, x, y, len, colour, maxLines, 1); } @@ -372,10 +653,82 @@ public class Utils { GlStateManager.enableTexture2D(); } + public static void drawGradientRectHorz(int left, int top, int right, int bottom, int startColor, int endColor) { + float f = (float)(startColor >> 24 & 255) / 255.0F; + float f1 = (float)(startColor >> 16 & 255) / 255.0F; + float f2 = (float)(startColor >> 8 & 255) / 255.0F; + float f3 = (float)(startColor & 255) / 255.0F; + float f4 = (float)(endColor >> 24 & 255) / 255.0F; + float f5 = (float)(endColor >> 16 & 255) / 255.0F; + float f6 = (float)(endColor >> 8 & 255) / 255.0F; + float f7 = (float)(endColor & 255) / 255.0F; + GlStateManager.disableTexture2D(); + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.shadeModel(7425); + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_COLOR); + worldrenderer.pos((double)right, (double)top, 0).color(f5, f6, f7, f4).endVertex(); + worldrenderer.pos((double)left, (double)top, 0).color(f1, f2, f3, f).endVertex(); + worldrenderer.pos((double)left, (double)bottom, 0).color(f1, f2, f3, f).endVertex(); + worldrenderer.pos((double)right, (double)bottom, 0).color(f5, f6, f7, f4).endVertex(); + tessellator.draw(); + GlStateManager.shadeModel(7424); + GlStateManager.disableBlend(); + GlStateManager.enableAlpha(); + GlStateManager.enableTexture2D(); + } + public static void drawHoveringText(List<String> textLines, final int mouseX, final int mouseY, final int screenWidth, final int screenHeight, final int maxTextWidth, FontRenderer font) { drawHoveringText(textLines, mouseX, mouseY, screenWidth, screenHeight, maxTextWidth, font, true); } + public static JsonObject getConstant(String constant) { + File repo = NotEnoughUpdates.INSTANCE.manager.repoLocation; + if(repo.exists()) { + File jsonFile = new File(repo, "constants/"+constant+".json"); + try { + return NotEnoughUpdates.INSTANCE.manager.getJsonFromFile(jsonFile); + } catch (Exception ignored) { + } + } + System.out.println(constant + " = null"); + return null; + } + + public static float getElementAsFloat(JsonElement element, float def) { + if(element == null) return def; + if(!element.isJsonPrimitive()) return def; + JsonPrimitive prim = element.getAsJsonPrimitive(); + if(!prim.isNumber()) return def; + return prim.getAsFloat(); + } + + public static String getElementAsString(JsonElement element, String def) { + if(element == null) return def; + if(!element.isJsonPrimitive()) return def; + JsonPrimitive prim = element.getAsJsonPrimitive(); + if(!prim.isString()) return def; + return prim.getAsString(); + } + + public static Splitter PATH_SPLITTER = Splitter.on(".").omitEmptyStrings().limit(2); + public static JsonElement getElement(JsonElement element, String path) { + List<String> path_split = PATH_SPLITTER.splitToList(path); + if(element instanceof JsonObject) { + JsonElement e = element.getAsJsonObject().get(path_split.get(0)); + if(path_split.size() > 1) { + return getElement(e, path_split.get(1)); + } else { + return e; + } + } else { + return element; + } + } + public static ChatStyle createClickStyle(ClickEvent.Action action, String value) { ChatStyle style = new ChatStyle(); style.setChatClickEvent(new ClickEvent(action, value)); @@ -392,6 +745,45 @@ public class Utils { file.delete(); } + public static Color getPrimaryColour(String displayname) { + int lastColourCode = -99; + int currentColour = 0; + int[] mostCommon = new int[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + for(int i=0; i<displayname.length(); i++) { + char c = displayname.charAt(i); + if(c == '\u00A7') { + lastColourCode = i; + } else if(lastColourCode == i-1) { + int colIndex = "0123456789abcdef".indexOf(c); + if(colIndex >= 0) { + currentColour = colIndex; + } else { + currentColour = 0; + } + } else if("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(c) >= 0){ + if(currentColour > 0) { + mostCommon[currentColour]++; + } + } + } + int mostCommonCount = 0; + for(int index=0; index<mostCommon.length; index++) { + if(mostCommon[index] > mostCommonCount) { + mostCommonCount = mostCommon[index]; + currentColour = index; + } + } + + int colourInt = Minecraft.getMinecraft().fontRendererObj.getColorCode("0123456789abcdef".charAt(currentColour)); + return new Color(colourInt).darker(); + } + + public static void scrollTooltip(int dY) { + scrollY.setTarget(scrollY.getTarget()+dY/10f); + scrollY.resetTimer(); + } + + private static LerpingFloat scrollY = new LerpingFloat(0, 100); public static void drawHoveringText(List<String> textLines, final int mouseX, final int mouseY, final int screenWidth, final int screenHeight, final int maxTextWidth, FontRenderer font, boolean coloured) { if (!textLines.isEmpty()) { @@ -485,9 +877,24 @@ public class Utils { } } + //Scrollable tooltips + if(tooltipHeight + 6 > screenHeight) { + if(scrollY.getTarget() < 0) { + scrollY.setTarget(0); + scrollY.resetTimer(); + } else if(screenHeight - tooltipHeight - 12 + (int)scrollY.getTarget() > 0) { + scrollY.setTarget(-screenHeight + tooltipHeight + 12); + scrollY.resetTimer(); + } + } else { + scrollY.setValue(0); + scrollY.resetTimer(); + } + scrollY.tick(); + if (tooltipY + tooltipHeight + 6 > screenHeight) { - tooltipY = screenHeight - tooltipHeight - 6; + tooltipY = screenHeight - tooltipHeight - 6 + (int)scrollY.getValue(); } final int zLevel = 300; @@ -502,36 +909,7 @@ public class Utils { if(NotEnoughUpdates.INSTANCE.manager.config.tooltipBorderColours.value && coloured) { if(textLines.size() > 0) { String first = textLines.get(0); - int lastColourCode = -99; - int currentColour = 0; - int[] mostCommon = new int[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - for(int i=0; i<first.length(); i++) { - char c = first.charAt(i); - if(c == '\u00A7') { - lastColourCode = i; - } else if(lastColourCode == i-1) { - int colIndex = "0123456789abcdef".indexOf(c); - if(colIndex >= 0) { - currentColour = colIndex; - } else { - currentColour = 0; - } - } else if("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(c) >= 0){ - if(currentColour > 0) { - mostCommon[currentColour]++; - } - } - } - int mostCommonCount = 0; - for(int index=0; index<mostCommon.length; index++) { - if(mostCommon[index] > mostCommonCount) { - mostCommonCount = mostCommon[index]; - currentColour = index; - } - } - - int colourInt = font.getColorCode("0123456789abcdef".charAt(currentColour)); - borderColorStart = new Color(colourInt).darker().getRGB() & 0x00FFFFFF | + borderColorStart = getPrimaryColour(first).getRGB() & 0x00FFFFFF | ((NotEnoughUpdates.INSTANCE.manager.config.tooltipBorderOpacity.value.intValue()) << 24); } } @@ -593,4 +971,34 @@ public class Utils { GlStateManager.enableTexture2D(); } + public static void drawRectNoBlend(int left, int top, int right, int bottom, int color) { + if (left < right) { + int i = left; + left = right; + right = i; + } + + if (top < bottom) { + int j = top; + top = bottom; + bottom = j; + } + + float f3 = (float)(color >> 24 & 255) / 255.0F; + float f = (float)(color >> 16 & 255) / 255.0F; + float f1 = (float)(color >> 8 & 255) / 255.0F; + float f2 = (float)(color & 255) / 255.0F; + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + GlStateManager.disableTexture2D(); + GlStateManager.color(f, f1, f2, f3); + worldrenderer.begin(7, DefaultVertexFormats.POSITION); + worldrenderer.pos((double)left, (double)bottom, 0.0D).endVertex(); + worldrenderer.pos((double)right, (double)bottom, 0.0D).endVertex(); + worldrenderer.pos((double)right, (double)top, 0.0D).endVertex(); + worldrenderer.pos((double)left, (double)top, 0.0D).endVertex(); + tessellator.draw(); + GlStateManager.enableTexture2D(); + } + } diff --git a/src/main/resources/assets/notenoughupdates/accessory_bag_overlay.png b/src/main/resources/assets/notenoughupdates/accessory_bag_overlay.png Binary files differnew file mode 100644 index 00000000..6fcac4d1 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/accessory_bag_overlay.png diff --git a/src/main/resources/assets/notenoughupdates/button20x.png b/src/main/resources/assets/notenoughupdates/button20x.png Binary files differnew file mode 100644 index 00000000..8d723798 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/button20x.png diff --git a/src/main/resources/assets/notenoughupdates/button_white.png b/src/main/resources/assets/notenoughupdates/button_white.png Binary files differnew file mode 100644 index 00000000..7763716d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/button_white.png diff --git a/src/main/resources/assets/notenoughupdates/contrib.png b/src/main/resources/assets/notenoughupdates/capes/contrib.png Binary files differindex 51699e6e..51699e6e 100644 --- a/src/main/resources/assets/notenoughupdates/contrib.png +++ b/src/main/resources/assets/notenoughupdates/capes/contrib.png diff --git a/src/main/resources/assets/notenoughupdates/fade.png b/src/main/resources/assets/notenoughupdates/capes/fade.png Binary files differindex d898ec4d..d898ec4d 100644 --- a/src/main/resources/assets/notenoughupdates/fade.png +++ b/src/main/resources/assets/notenoughupdates/capes/fade.png diff --git a/src/main/resources/assets/notenoughupdates/gravy.png b/src/main/resources/assets/notenoughupdates/capes/gravy.png Binary files differindex e43ba7d2..e43ba7d2 100644 --- a/src/main/resources/assets/notenoughupdates/gravy.png +++ b/src/main/resources/assets/notenoughupdates/capes/gravy.png diff --git a/src/main/resources/assets/notenoughupdates/capes/lava.png b/src/main/resources/assets/notenoughupdates/capes/lava.png Binary files differnew file mode 100644 index 00000000..8f60a03e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/capes/lava.png diff --git a/src/main/resources/assets/notenoughupdates/capes/lightning.png b/src/main/resources/assets/notenoughupdates/capes/lightning.png Binary files differnew file mode 100644 index 00000000..dc0afce1 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/capes/lightning.png diff --git a/src/main/resources/assets/notenoughupdates/capes/mbstaff.png b/src/main/resources/assets/notenoughupdates/capes/mbstaff.png Binary files differnew file mode 100644 index 00000000..15961c7c --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/capes/mbstaff.png diff --git a/src/main/resources/assets/notenoughupdates/capes/mcworld.png b/src/main/resources/assets/notenoughupdates/capes/mcworld.png Binary files differnew file mode 100644 index 00000000..89b3b367 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/capes/mcworld.png diff --git a/src/main/resources/assets/notenoughupdates/nullzee.png b/src/main/resources/assets/notenoughupdates/capes/nullzee.png Binary files differindex 5939034b..5939034b 100644 --- a/src/main/resources/assets/notenoughupdates/nullzee.png +++ b/src/main/resources/assets/notenoughupdates/capes/nullzee.png diff --git a/src/main/resources/assets/notenoughupdates/capes/packshq.png b/src/main/resources/assets/notenoughupdates/capes/packshq.png Binary files differnew file mode 100644 index 00000000..860b10f5 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/capes/packshq.png diff --git a/src/main/resources/assets/notenoughupdates/capes/patreon1.png b/src/main/resources/assets/notenoughupdates/capes/patreon1.png Binary files differnew file mode 100644 index 00000000..aba027bc --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/capes/patreon1.png diff --git a/src/main/resources/assets/notenoughupdates/capes/patreon2.png b/src/main/resources/assets/notenoughupdates/capes/patreon2.png Binary files differnew file mode 100644 index 00000000..1c5a848a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/capes/patreon2.png diff --git a/src/main/resources/assets/notenoughupdates/capes/space.png b/src/main/resources/assets/notenoughupdates/capes/space.png Binary files differnew file mode 100644 index 00000000..ba239e22 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/capes/space.png diff --git a/src/main/resources/assets/notenoughupdates/testcape.png b/src/main/resources/assets/notenoughupdates/capes/testcape.png Binary files differindex 4b8ba499..4b8ba499 100644 --- a/src/main/resources/assets/notenoughupdates/testcape.png +++ b/src/main/resources/assets/notenoughupdates/capes/testcape.png diff --git a/src/main/resources/assets/notenoughupdates/colour_selector_bar.png b/src/main/resources/assets/notenoughupdates/colour_selector_bar.png Binary files differnew file mode 100644 index 00000000..f176af90 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/colour_selector_bar.png diff --git a/src/main/resources/assets/notenoughupdates/colour_selector_bar_alpha.png b/src/main/resources/assets/notenoughupdates/colour_selector_bar_alpha.png Binary files differnew file mode 100644 index 00000000..7a89510c --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/colour_selector_bar_alpha.png diff --git a/src/main/resources/assets/notenoughupdates/colour_selector_chroma.png b/src/main/resources/assets/notenoughupdates/colour_selector_chroma.png Binary files differnew file mode 100644 index 00000000..ea273959 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/colour_selector_chroma.png diff --git a/src/main/resources/assets/notenoughupdates/colour_selector_dot.png b/src/main/resources/assets/notenoughupdates/colour_selector_dot.png Binary files differnew file mode 100644 index 00000000..1150c8bb --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/colour_selector_dot.png diff --git a/src/main/resources/assets/notenoughupdates/cosmetics_fg.png b/src/main/resources/assets/notenoughupdates/cosmetics_fg.png Binary files differnew file mode 100644 index 00000000..445753ac --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/cosmetics_fg.png diff --git a/src/main/resources/assets/notenoughupdates/custom_ench_colour.png b/src/main/resources/assets/notenoughupdates/custom_ench_colour.png Binary files differnew file mode 100644 index 00000000..2c1c717e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/custom_ench_colour.png diff --git a/src/main/resources/assets/notenoughupdates/custom_trade.png b/src/main/resources/assets/notenoughupdates/custom_trade.png Binary files differnew file mode 100644 index 00000000..1b6c82a6 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/custom_trade.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_chest_worth.png b/src/main/resources/assets/notenoughupdates/dungeon_chest_worth.png Binary files differindex 48b4af95..37ad163e 100644 --- a/src/main/resources/assets/notenoughupdates/dungeon_chest_worth.png +++ b/src/main/resources/assets/notenoughupdates/dungeon_chest_worth.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/1.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/1.json new file mode 100644 index 00000000..23e86d67 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/1.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.25 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/10.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/10.json new file mode 100644 index 00000000..23e86d67 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/10.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.25 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/10.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/10.png Binary files differnew file mode 100644 index 00000000..6cd64ed1 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/10.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/11.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/11.json new file mode 100644 index 00000000..23e86d67 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/11.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.25 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/11.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/11.png Binary files differnew file mode 100644 index 00000000..65898e8f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/11.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/2.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/2.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/2.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/2.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/2.png Binary files differnew file mode 100644 index 00000000..6f0daba0 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/2.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/3.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/3.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/3.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/3.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/3.png Binary files differnew file mode 100644 index 00000000..4c123e77 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/3.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/4.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/4.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/4.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/4.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/4.png Binary files differnew file mode 100644 index 00000000..833b9017 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/4.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/5.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/5.json new file mode 100644 index 00000000..23e86d67 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/5.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.25 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/5.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/5.png Binary files differnew file mode 100644 index 00000000..93bef87d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/5.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/6.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/6.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/6.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/6.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/6.png Binary files differnew file mode 100644 index 00000000..43d71ad1 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/6.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/7.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/7.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/7.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/7.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/7.png Binary files differnew file mode 100644 index 00000000..054e0e84 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/7.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/8.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/8.json new file mode 100644 index 00000000..b2625fc5 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/8.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.21 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/8.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/8.png Binary files differnew file mode 100644 index 00000000..54db6fbc --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/8.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/9.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/9.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/9.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/9.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/9.png Binary files differnew file mode 100644 index 00000000..c5fedff9 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/9.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/map_border_dragon_stone.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/map_border_dragon_stone.png Binary files differnew file mode 100644 index 00000000..c79eee7f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/map_border_dragon_stone.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/1.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/1.json new file mode 100644 index 00000000..23e86d67 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/1.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.25 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/10.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/10.json new file mode 100644 index 00000000..23e86d67 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/10.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.25 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/10.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/10.png Binary files differnew file mode 100644 index 00000000..4f4b1dc7 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/10.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/11.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/11.json new file mode 100644 index 00000000..23e86d67 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/11.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.25 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/11.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/11.png Binary files differnew file mode 100644 index 00000000..3730ab57 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/11.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/2.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/2.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/2.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/2.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/2.png Binary files differnew file mode 100644 index 00000000..3627d35e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/2.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/3.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/3.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/3.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/3.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/3.png Binary files differnew file mode 100644 index 00000000..68824d04 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/3.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/4.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/4.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/4.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/4.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/4.png Binary files differnew file mode 100644 index 00000000..3b8776e7 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/4.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/5.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/5.json new file mode 100644 index 00000000..23e86d67 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/5.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.25 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/5.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/5.png Binary files differnew file mode 100644 index 00000000..3a708494 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/5.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/6.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/6.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/6.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/6.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/6.png Binary files differnew file mode 100644 index 00000000..149c4117 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/6.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/7.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/7.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/7.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/7.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/7.png Binary files differnew file mode 100644 index 00000000..8b3ae258 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/7.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/8.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/8.json new file mode 100644 index 00000000..8c12699d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/8.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.22 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/8.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/8.png Binary files differnew file mode 100644 index 00000000..c131badf --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/8.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/9.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/9.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/9.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/9.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/9.png Binary files differnew file mode 100644 index 00000000..a42870f2 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/9.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/1.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/1.json new file mode 100644 index 00000000..23e86d67 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/1.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.25 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/10.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/10.json new file mode 100644 index 00000000..23e86d67 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/10.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.25 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/10.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/10.png Binary files differnew file mode 100644 index 00000000..b9bcac1d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/10.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/11.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/11.json new file mode 100644 index 00000000..23e86d67 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/11.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.25 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/11.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/11.png Binary files differnew file mode 100644 index 00000000..2fdbe252 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/11.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/2.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/2.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/2.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/2.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/2.png Binary files differnew file mode 100644 index 00000000..c1b2e303 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/2.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/3.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/3.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/3.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/3.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/3.png Binary files differnew file mode 100644 index 00000000..fe0ba4b9 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/3.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/4.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/4.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/4.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/4.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/4.png Binary files differnew file mode 100644 index 00000000..bd580c8e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/4.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/5.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/5.json new file mode 100644 index 00000000..23e86d67 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/5.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.25 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/5.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/5.png Binary files differnew file mode 100644 index 00000000..6f2bdc29 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/5.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/6.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/6.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/6.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/6.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/6.png Binary files differnew file mode 100644 index 00000000..0bf30077 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/6.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/7.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/7.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/7.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/7.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/7.png Binary files differnew file mode 100644 index 00000000..a060875a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/7.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/8.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/8.json new file mode 100644 index 00000000..8c12699d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/8.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 0.22 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/8.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/8.png Binary files differnew file mode 100644 index 00000000..5dd06a89 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/8.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/9.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/9.json new file mode 100644 index 00000000..9576ae4f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/9.json @@ -0,0 +1,3 @@ +{ + "radiusSq": 1 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/9.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/9.png Binary files differnew file mode 100644 index 00000000..1d275525 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/9.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/steampunk.png b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/steampunk.png Binary files differnew file mode 100644 index 00000000..3d1c0833 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/steampunk.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/corners_default/brown_corner.png b/src/main/resources/assets/notenoughupdates/dungeon_map/corners_default/brown_corner.png Binary files differnew file mode 100644 index 00000000..23ae39fd --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/corners_default/brown_corner.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/brown_corridor.png b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/brown_corridor.png Binary files differnew file mode 100644 index 00000000..abc06bab --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/brown_corridor.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/gray_corridor.png b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/gray_corridor.png Binary files differnew file mode 100644 index 00000000..78deccbb --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/gray_corridor.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/green_corridor.png b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/green_corridor.png Binary files differnew file mode 100644 index 00000000..8ae999fc --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/green_corridor.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/orange_corridor.png b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/orange_corridor.png Binary files differnew file mode 100644 index 00000000..62515723 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/orange_corridor.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/pink_corridor.png b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/pink_corridor.png Binary files differnew file mode 100644 index 00000000..89dfc4b3 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/pink_corridor.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/purple_corridor.png b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/purple_corridor.png Binary files differnew file mode 100644 index 00000000..a1fcfc83 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/purple_corridor.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/red_corridor.png b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/red_corridor.png Binary files differnew file mode 100644 index 00000000..ec80a4c5 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/red_corridor.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/yellow_corridor.png b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/yellow_corridor.png Binary files differnew file mode 100644 index 00000000..cc10b875 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/corridors_default/yellow_corridor.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/cross.png b/src/main/resources/assets/notenoughupdates/dungeon_map/cross.png Binary files differnew file mode 100644 index 00000000..e98151a8 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/cross.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/dividers_default/brown_divider.png b/src/main/resources/assets/notenoughupdates/dungeon_map/dividers_default/brown_divider.png Binary files differnew file mode 100644 index 00000000..30a0357c --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/dividers_default/brown_divider.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/editor/background.png b/src/main/resources/assets/notenoughupdates/dungeon_map/editor/background.png Binary files differnew file mode 100644 index 00000000..7e8f68ea --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/editor/background.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/green_check.png b/src/main/resources/assets/notenoughupdates/dungeon_map/green_check.png Binary files differnew file mode 100644 index 00000000..eeef275d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/green_check.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/question.png b/src/main/resources/assets/notenoughupdates/dungeon_map/question.png Binary files differnew file mode 100644 index 00000000..79c4c100 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/question.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/brown_room.png b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/brown_room.png Binary files differnew file mode 100644 index 00000000..2d2ec6b1 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/brown_room.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/gray_room.png b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/gray_room.png Binary files differnew file mode 100644 index 00000000..41db61f0 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/gray_room.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/green_room.png b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/green_room.png Binary files differnew file mode 100644 index 00000000..acda8072 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/green_room.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/orange_room.png b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/orange_room.png Binary files differnew file mode 100644 index 00000000..5e32636a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/orange_room.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/pink_room.png b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/pink_room.png Binary files differnew file mode 100644 index 00000000..19104f7c --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/pink_room.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/purple_room.png b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/purple_room.png Binary files differnew file mode 100644 index 00000000..b7f5ebd5 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/purple_room.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/red_room.png b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/red_room.png Binary files differnew file mode 100644 index 00000000..48e0ecac --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/red_room.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/yellow_room.png b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/yellow_room.png Binary files differnew file mode 100644 index 00000000..f5846150 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/rooms_default/yellow_room.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/white_check.png b/src/main/resources/assets/notenoughupdates/dungeon_map/white_check.png Binary files differnew file mode 100644 index 00000000..8e8d8685 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_map/white_check.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_win/a.png b/src/main/resources/assets/notenoughupdates/dungeon_win/a.png Binary files differnew file mode 100644 index 00000000..85322946 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_win/a.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_win/b.png b/src/main/resources/assets/notenoughupdates/dungeon_win/b.png Binary files differnew file mode 100644 index 00000000..11c7384c --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_win/b.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_win/c.png b/src/main/resources/assets/notenoughupdates/dungeon_win/c.png Binary files differnew file mode 100644 index 00000000..2009179f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_win/c.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_win/confetti.png b/src/main/resources/assets/notenoughupdates/dungeon_win/confetti.png Binary files differnew file mode 100644 index 00000000..a5529dc8 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_win/confetti.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_win/d.png b/src/main/resources/assets/notenoughupdates/dungeon_win/d.png Binary files differnew file mode 100644 index 00000000..c08baaf4 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_win/d.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_win/s.png b/src/main/resources/assets/notenoughupdates/dungeon_win/s.png Binary files differnew file mode 100644 index 00000000..a514f285 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_win/s.png diff --git a/src/main/resources/assets/notenoughupdates/dungeon_win/splus.png b/src/main/resources/assets/notenoughupdates/dungeon_win/splus.png Binary files differnew file mode 100644 index 00000000..732d30a3 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dungeon_win/splus.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_54.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_54.png Binary files differnew file mode 100644 index 00000000..a8c9eac9 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_54.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_54_button_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_54_button_ctm.png Binary files differnew file mode 100644 index 00000000..a29a685d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_54_button_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_54_slot_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_54_slot_ctm.png Binary files differnew file mode 100644 index 00000000..7eaecfc2 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_54_slot_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_config.json b/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_config.json new file mode 100644 index 00000000..05dbf61a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_config.json @@ -0,0 +1,3 @@ +{ + "text-colour": "FF000000" +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_54.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_54.png Binary files differnew file mode 100644 index 00000000..63479a74 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_54.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_54_button_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_54_button_ctm.png Binary files differnew file mode 100644 index 00000000..4b28ee06 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_54_button_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_54_slot_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_54_slot_ctm.png Binary files differnew file mode 100644 index 00000000..7eaecfc2 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_54_slot_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_config.json b/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_config.json new file mode 100644 index 00000000..05dbf61a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_config.json @@ -0,0 +1,3 @@ +{ + "text-colour": "FF000000" +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_54.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_54.png Binary files differnew file mode 100644 index 00000000..d14f0ed1 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_54.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_54_button_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_54_button_ctm.png Binary files differnew file mode 100644 index 00000000..800acade --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_54_button_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_54_slot_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_54_slot_ctm.png Binary files differnew file mode 100644 index 00000000..800acade --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_54_slot_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_config.json b/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_config.json new file mode 100644 index 00000000..5ae75066 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_config.json @@ -0,0 +1,3 @@ +{ + "text-colour": "FFC8C8C8" +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style4/dynamic_54.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style4/dynamic_54.png Binary files differnew file mode 100644 index 00000000..934f6b4a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style4/dynamic_54.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style4/dynamic_54_button_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style4/dynamic_54_button_ctm.png Binary files differnew file mode 100644 index 00000000..956d085a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style4/dynamic_54_button_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style4/dynamic_54_slot_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style4/dynamic_54_slot_ctm.png Binary files differnew file mode 100644 index 00000000..fa43a0ed --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style4/dynamic_54_slot_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style5/dynamic_54.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style5/dynamic_54.png Binary files differnew file mode 100644 index 00000000..73711ee8 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style5/dynamic_54.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style5/dynamic_54_button_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style5/dynamic_54_button_ctm.png Binary files differnew file mode 100644 index 00000000..bab0eab7 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style5/dynamic_54_button_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style5/dynamic_54_slot_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style5/dynamic_54_slot_ctm.png Binary files differnew file mode 100644 index 00000000..fa43a0ed --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style5/dynamic_54_slot_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style6/dynamic_54.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style6/dynamic_54.png Binary files differnew file mode 100644 index 00000000..3a24654d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style6/dynamic_54.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style6/dynamic_54_button_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style6/dynamic_54_button_ctm.png Binary files differnew file mode 100644 index 00000000..fa43a0ed --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style6/dynamic_54_button_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style6/dynamic_54_slot_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style6/dynamic_54_slot_ctm.png Binary files differnew file mode 100644 index 00000000..fa43a0ed --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style6/dynamic_54_slot_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style7/dynamic_54.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style7/dynamic_54.png Binary files differnew file mode 100644 index 00000000..934f6b4a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style7/dynamic_54.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style7/dynamic_54_button_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style7/dynamic_54_button_ctm.png Binary files differnew file mode 100644 index 00000000..ea57f0d0 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style7/dynamic_54_button_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style7/dynamic_54_slot_ctm.png b/src/main/resources/assets/notenoughupdates/dynamic_54/style7/dynamic_54_slot_ctm.png Binary files differnew file mode 100644 index 00000000..fa43a0ed --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style7/dynamic_54_slot_ctm.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/toggle_off.png b/src/main/resources/assets/notenoughupdates/dynamic_54/toggle_off.png Binary files differnew file mode 100644 index 00000000..7a1aa4a4 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/toggle_off.png diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/toggle_on.png b/src/main/resources/assets/notenoughupdates/dynamic_54/toggle_on.png Binary files differnew file mode 100644 index 00000000..5f4960f9 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/dynamic_54/toggle_on.png diff --git a/src/main/resources/assets/notenoughupdates/folder.png b/src/main/resources/assets/notenoughupdates/folder.png Binary files differnew file mode 100644 index 00000000..f4af7353 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/folder.png diff --git a/src/main/resources/assets/notenoughupdates/gamemodes.png b/src/main/resources/assets/notenoughupdates/gamemodes.png Binary files differnew file mode 100644 index 00000000..8a1aa2fa --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/gamemodes.png diff --git a/src/main/resources/assets/notenoughupdates/item_haschild.png b/src/main/resources/assets/notenoughupdates/item_haschild.png Binary files differnew file mode 100644 index 00000000..c3f3369a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/item_haschild.png diff --git a/src/main/resources/assets/notenoughupdates/item_pane_tab_arrow.png b/src/main/resources/assets/notenoughupdates/item_pane_tab_arrow.png Binary files differindex d8fc8530..fd23cc35 100644 --- a/src/main/resources/assets/notenoughupdates/item_pane_tab_arrow.png +++ b/src/main/resources/assets/notenoughupdates/item_pane_tab_arrow.png diff --git a/src/main/resources/assets/notenoughupdates/maps/F1Full.json b/src/main/resources/assets/notenoughupdates/maps/F1Full.json new file mode 100644 index 00000000..44d72fc8 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/maps/F1Full.json @@ -0,0 +1,16386 @@ +{ + "0:0": 268435456, + "1:0": 402653184, + "2:0": 268435456, + "3:0": 402653184, + "4:0": 268435456, + "5:0": 402653184, + "6:0": 268435456, + "7:0": 402653184, + "8:0": 268435456, + "9:0": 402653184, + "10:0": 268435456, + "11:0": 402653184, + "12:0": 268435456, + "13:0": 402653184, + "14:0": 268435456, + "15:0": 402653184, + "16:0": 268435456, + "17:0": 402653184, + "18:0": 268435456, + "19:0": 402653184, + "20:0": 268435456, + "21:0": 402653184, + "22:0": 268435456, + "23:0": 402653184, + "24:0": 268435456, + "25:0": 402653184, + "26:0": 268435456, + "27:0": 402653184, + "28:0": 268435456, + "29:0": 402653184, + "30:0": 268435456, + "31:0": 402653184, + "32:0": 268435456, + "33:0": 402653184, + "34:0": 268435456, + "35:0": 402653184, + "36:0": 268435456, + "37:0": 402653184, + "38:0": 268435456, + "39:0": 402653184, + "40:0": 268435456, + "41:0": 402653184, + "42:0": 268435456, + "43:0": 402653184, + "44:0": 268435456, + "45:0": 402653184, + "46:0": 268435456, + "47:0": 402653184, + "48:0": 268435456, + "49:0": 402653184, + "50:0": 268435456, + "51:0": 402653184, + "52:0": 268435456, + "53:0": 402653184, + "54:0": 268435456, + "55:0": 402653184, + "56:0": 268435456, + "57:0": 402653184, + "58:0": 268435456, + "59:0": 402653184, + "60:0": 268435456, + "61:0": 402653184, + "62:0": 268435456, + "63:0": 402653184, + "64:0": 268435456, + "65:0": 402653184, + "66:0": 268435456, + "67:0": 402653184, + "68:0": 268435456, + "69:0": 402653184, + "70:0": 268435456, + "71:0": 402653184, + "72:0": 268435456, + "73:0": 402653184, + "74:0": 268435456, + "75:0": 402653184, + "76:0": 268435456, + "77:0": 402653184, + "78:0": 268435456, + "79:0": 402653184, + "80:0": 268435456, + "81:0": 402653184, + "82:0": 268435456, + "83:0": 402653184, + "84:0": 268435456, + "85:0": 402653184, + "86:0": 268435456, + "87:0": 402653184, + "88:0": 268435456, + "89:0": 402653184, + "90:0": 268435456, + "91:0": 402653184, + "92:0": 268435456, + "93:0": 402653184, + "94:0": 268435456, + "95:0": 402653184, + "96:0": 268435456, + "97:0": 402653184, + "98:0": 268435456, + "99:0": 402653184, + "100:0": 268435456, + "101:0": 402653184, + "102:0": 268435456, + "103:0": 402653184, + "104:0": 268435456, + "105:0": 402653184, + "106:0": 268435456, + "107:0": 402653184, + "108:0": 268435456, + "109:0": 402653184, + "110:0": 268435456, + "111:0": 402653184, + "112:0": 268435456, + "113:0": 402653184, + "114:0": 268435456, + "115:0": 402653184, + "116:0": 268435456, + "117:0": 402653184, + "118:0": 268435456, + "119:0": 402653184, + "120:0": 268435456, + "121:0": 402653184, + "122:0": 268435456, + "123:0": 402653184, + "124:0": 268435456, + "125:0": 402653184, + "126:0": 268435456, + "127:0": 402653184, + "0:1": 402653184, + "1:1": 268435456, + "2:1": 402653184, + "3:1": 268435456, + "4:1": 402653184, + "5:1": 268435456, + "6:1": 402653184, + "7:1": 268435456, + "8:1": 402653184, + "9:1": 268435456, + "10:1": 402653184, + "11:1": 268435456, + "12:1": 402653184, + "13:1": 268435456, + "14:1": 402653184, + "15:1": 268435456, + "16:1": 402653184, + "17:1": 268435456, + "18:1": 402653184, + "19:1": 268435456, + "20:1": 402653184, + "21:1": 268435456, + "22:1": 402653184, + "23:1": 268435456, + "24:1": 402653184, + "25:1": 268435456, + "26:1": 402653184, + "27:1": 268435456, + "28:1": 402653184, + "29:1": 268435456, + "30:1": 402653184, + "31:1": 268435456, + "32:1": 402653184, + "33:1": 268435456, + "34:1": 402653184, + "35:1": 268435456, + "36:1": 402653184, + "37:1": 268435456, + "38:1": 402653184, + "39:1": 268435456, + "40:1": 402653184, + "41:1": 268435456, + "42:1": 402653184, + "43:1": 268435456, + "44:1": 402653184, + "45:1": 268435456, + "46:1": 402653184, + "47:1": 268435456, + "48:1": 402653184, + "49:1": 268435456, + "50:1": 402653184, + "51:1": 268435456, + "52:1": 402653184, + "53:1": 268435456, + "54:1": 402653184, + "55:1": 268435456, + "56:1": 402653184, + "57:1": 268435456, + "58:1": 402653184, + "59:1": 268435456, + "60:1": 402653184, + "61:1": 268435456, + "62:1": 402653184, + "63:1": 268435456, + "64:1": 402653184, + "65:1": 268435456, + "66:1": 402653184, + "67:1": 268435456, + "68:1": 402653184, + "69:1": 268435456, + "70:1": 402653184, + "71:1": 268435456, + "72:1": 402653184, + "73:1": 268435456, + "74:1": 402653184, + "75:1": 268435456, + "76:1": 402653184, + "77:1": 268435456, + "78:1": 402653184, + "79:1": 268435456, + "80:1": 402653184, + "81:1": 268435456, + "82:1": 402653184, + "83:1": 268435456, + "84:1": 402653184, + "85:1": 268435456, + "86:1": 402653184, + "87:1": 268435456, + "88:1": 402653184, + "89:1": 268435456, + "90:1": 402653184, + "91:1": 268435456, + "92:1": 402653184, + "93:1": 268435456, + "94:1": 402653184, + "95:1": 268435456, + "96:1": 402653184, + "97:1": 268435456, + "98:1": 402653184, + "99:1": 268435456, + "100:1": 402653184, + "101:1": 268435456, + "102:1": 402653184, + "103:1": 268435456, + "104:1": 402653184, + "105:1": 268435456, + "106:1": 402653184, + "107:1": 268435456, + "108:1": 402653184, + "109:1": 268435456, + "110:1": 402653184, + "111:1": 268435456, + "112:1": 402653184, + "113:1": 268435456, + "114:1": 402653184, + "115:1": 268435456, + "116:1": 402653184, + "117:1": 268435456, + "118:1": 402653184, + "119:1": 268435456, + "120:1": 402653184, + "121:1": 268435456, + "122:1": 402653184, + "123:1": 268435456, + "124:1": 402653184, + "125:1": 268435456, + "126:1": 402653184, + "127:1": 268435456, + "0:2": 268435456, + "1:2": 402653184, + "2:2": 268435456, + "3:2": 402653184, + "4:2": 268435456, + "5:2": 402653184, + "6:2": 268435456, + "7:2": 402653184, + "8:2": 268435456, + "9:2": 402653184, + "10:2": 268435456, + "11:2": 402653184, + "12:2": 268435456, + "13:2": 402653184, + "14:2": 268435456, + "15:2": 402653184, + "16:2": 268435456, + "17:2": 402653184, + "18:2": 268435456, + "19:2": 402653184, + "20:2": 268435456, + "21:2": 402653184, + "22:2": 268435456, + "23:2": 402653184, + "24:2": 268435456, + "25:2": 402653184, + "26:2": 268435456, + "27:2": 402653184, + "28:2": 268435456, + "29:2": 402653184, + "30:2": 268435456, + "31:2": 402653184, + "32:2": 268435456, + "33:2": 402653184, + "34:2": 268435456, + "35:2": 402653184, + "36:2": 268435456, + "37:2": 402653184, + "38:2": 268435456, + "39:2": 402653184, + "40:2": 268435456, + "41:2": 402653184, + "42:2": 268435456, + "43:2": 402653184, + "44:2": 268435456, + "45:2": 402653184, + "46:2": 268435456, + "47:2": 402653184, + "48:2": 268435456, + "49:2": 402653184, + "50:2": 268435456, + "51:2": 402653184, + "52:2": 268435456, + "53:2": 402653184, + "54:2": 268435456, + "55:2": 402653184, + "56:2": 268435456, + "57:2": 402653184, + "58:2": 268435456, + "59:2": 402653184, + "60:2": 268435456, + "61:2": 402653184, + "62:2": 268435456, + "63:2": 402653184, + "64:2": 268435456, + "65:2": 402653184, + "66:2": 268435456, + "67:2": 402653184, + "68:2": 268435456, + "69:2": 402653184, + "70:2": 268435456, + "71:2": 402653184, + "72:2": 268435456, + "73:2": 402653184, + "74:2": 268435456, + "75:2": 402653184, + "76:2": 268435456, + "77:2": 402653184, + "78:2": 268435456, + "79:2": 402653184, + "80:2": 268435456, + "81:2": 402653184, + "82:2": 268435456, + "83:2": 402653184, + "84:2": 268435456, + "85:2": 402653184, + "86:2": 268435456, + "87:2": 402653184, + "88:2": 268435456, + "89:2": 402653184, + "90:2": 268435456, + "91:2": 402653184, + "92:2": 268435456, + "93:2": 402653184, + "94:2": 268435456, + "95:2": 402653184, + "96:2": 268435456, + "97:2": 402653184, + "98:2": 268435456, + "99:2": 402653184, + "100:2": 268435456, + "101:2": 402653184, + "102:2": 268435456, + "103:2": 402653184, + "104:2": 268435456, + "105:2": 402653184, + "106:2": 268435456, + "107:2": 402653184, + "108:2": 268435456, + "109:2": 402653184, + "110:2": 268435456, + "111:2": 402653184, + "112:2": 268435456, + "113:2": 402653184, + "114:2": 268435456, + "115:2": 402653184, + "116:2": 268435456, + "117:2": 402653184, + "118:2": 268435456, + "119:2": 402653184, + "120:2": 268435456, + "121:2": 402653184, + "122:2": 268435456, + "123:2": 402653184, + "124:2": 268435456, + "125:2": 402653184, + "126:2": 268435456, + "127:2": 402653184, + "0:3": 402653184, + "1:3": 268435456, + "2:3": 402653184, + "3:3": 268435456, + "4:3": 402653184, + "5:3": 268435456, + "6:3": 402653184, + "7:3": 268435456, + "8:3": 402653184, + "9:3": 268435456, + "10:3": 402653184, + "11:3": 268435456, + "12:3": 402653184, + "13:3": 268435456, + "14:3": 402653184, + "15:3": 268435456, + "16:3": 402653184, + "17:3": 268435456, + "18:3": 402653184, + "19:3": 268435456, + "20:3": 402653184, + "21:3": 268435456, + "22:3": 402653184, + "23:3": 268435456, + "24:3": 402653184, + "25:3": 268435456, + "26:3": 402653184, + "27:3": 268435456, + "28:3": 402653184, + "29:3": 268435456, + "30:3": 402653184, + "31:3": 268435456, + "32:3": 402653184, + "33:3": 268435456, + "34:3": 402653184, + "35:3": 268435456, + "36:3": 402653184, + "37:3": 268435456, + "38:3": 402653184, + "39:3": 268435456, + "40:3": 402653184, + "41:3": 268435456, + "42:3": 402653184, + "43:3": 268435456, + "44:3": 402653184, + "45:3": 268435456, + "46:3": 402653184, + "47:3": 268435456, + "48:3": 402653184, + "49:3": 268435456, + "50:3": 402653184, + "51:3": 268435456, + "52:3": 402653184, + "53:3": 268435456, + "54:3": 402653184, + "55:3": 268435456, + "56:3": 402653184, + "57:3": 268435456, + "58:3": 402653184, + "59:3": 268435456, + "60:3": 402653184, + "61:3": 268435456, + "62:3": 402653184, + "63:3": 268435456, + "64:3": 402653184, + "65:3": 268435456, + "66:3": 402653184, + "67:3": 268435456, + "68:3": 402653184, + "69:3": 268435456, + "70:3": 402653184, + "71:3": 268435456, + "72:3": 402653184, + "73:3": 268435456, + "74:3": 402653184, + "75:3": 268435456, + "76:3": 402653184, + "77:3": 268435456, + "78:3": 402653184, + "79:3": 268435456, + "80:3": 402653184, + "81:3": 268435456, + "82:3": 402653184, + "83:3": 268435456, + "84:3": 402653184, + "85:3": 268435456, + "86:3": 402653184, + "87:3": 268435456, + "88:3": 402653184, + "89:3": 268435456, + "90:3": 402653184, + "91:3": 268435456, + "92:3": 402653184, + "93:3": 268435456, + "94:3": 402653184, + "95:3": 268435456, + "96:3": 402653184, + "97:3": 268435456, + "98:3": 402653184, + "99:3": 268435456, + "100:3": 402653184, + "101:3": 268435456, + "102:3": 402653184, + "103:3": 268435456, + "104:3": 402653184, + "105:3": 268435456, + "106:3": 402653184, + "107:3": 268435456, + "108:3": 402653184, + "109:3": 268435456, + "110:3": 402653184, + "111:3": 268435456, + "112:3": 402653184, + "113:3": 268435456, + "114:3": 402653184, + "115:3": 268435456, + "116:3": 402653184, + "117:3": 268435456, + "118:3": 402653184, + "119:3": 268435456, + "120:3": 402653184, + "121:3": 268435456, + "122:3": 402653184, + "123:3": 268435456, + "124:3": 402653184, + "125:3": 268435456, + "126:3": 402653184, + "127:3": 268435456, + "0:4": 268435456, + "1:4": 402653184, + "2:4": 268435456, + "3:4": 402653184, + "4:4": 268435456, + "5:4": 402653184, + "6:4": 268435456, + "7:4": 402653184, + "8:4": 268435456, + "9:4": 402653184, + "10:4": 268435456, + "11:4": 402653184, + "12:4": 268435456, + "13:4": 402653184, + "14:4": 268435456, + "15:4": 402653184, + "16:4": 268435456, + "17:4": 402653184, + "18:4": 268435456, + "19:4": 402653184, + "20:4": 268435456, + "21:4": 402653184, + "22:4": 268435456, + "23:4": 402653184, + "24:4": 268435456, + "25:4": 402653184, + "26:4": 268435456, + "27:4": 402653184, + "28:4": 268435456, + "29:4": 402653184, + "30:4": 268435456, + "31:4": 402653184, + "32:4": 268435456, + "33:4": 402653184, + "34:4": 268435456, + "35:4": 402653184, + "36:4": 268435456, + "37:4": 402653184, + "38:4": 268435456, + "39:4": 402653184, + "40:4": 268435456, + "41:4": 402653184, + "42:4": 268435456, + "43:4": 402653184, + "44:4": 268435456, + "45:4": 402653184, + "46:4": 268435456, + "47:4": 402653184, + "48:4": 268435456, + "49:4": 402653184, + "50:4": 268435456, + "51:4": 402653184, + "52:4": 268435456, + "53:4": 402653184, + "54:4": 268435456, + "55:4": 402653184, + "56:4": 268435456, + "57:4": 402653184, + "58:4": 268435456, + "59:4": 402653184, + "60:4": 268435456, + "61:4": 402653184, + "62:4": 268435456, + "63:4": 402653184, + "64:4": 268435456, + "65:4": 402653184, + "66:4": 268435456, + "67:4": 402653184, + "68:4": 268435456, + "69:4": 402653184, + "70:4": 268435456, + "71:4": 402653184, + "72:4": 268435456, + "73:4": 402653184, + "74:4": 268435456, + "75:4": 402653184, + "76:4": 268435456, + "77:4": 402653184, + "78:4": 268435456, + "79:4": 402653184, + "80:4": 268435456, + "81:4": 402653184, + "82:4": 268435456, + "83:4": 402653184, + "84:4": 268435456, + "85:4": 402653184, + "86:4": 268435456, + "87:4": 402653184, + "88:4": 268435456, + "89:4": 402653184, + "90:4": 268435456, + "91:4": 402653184, + "92:4": 268435456, + "93:4": 402653184, + "94:4": 268435456, + "95:4": 402653184, + "96:4": 268435456, + "97:4": 402653184, + "98:4": 268435456, + "99:4": 402653184, + "100:4": 268435456, + "101:4": 402653184, + "102:4": 268435456, + "103:4": 402653184, + "104:4": 268435456, + "105:4": 402653184, + "106:4": 268435456, + "107:4": 402653184, + "108:4": 268435456, + "109:4": 402653184, + "110:4": 268435456, + "111:4": 402653184, + "112:4": 268435456, + "113:4": 402653184, + "114:4": 268435456, + "115:4": 402653184, + "116:4": 268435456, + "117:4": 402653184, + "118:4": 268435456, + "119:4": 402653184, + "120:4": 268435456, + "121:4": 402653184, + "122:4": 268435456, + "123:4": 402653184, + "124:4": 268435456, + "125:4": 402653184, + "126:4": 268435456, + "127:4": 402653184, + "0:5": 402653184, + "1:5": 268435456, + "2:5": 402653184, + "3:5": 268435456, + "4:5": 402653184, + "5:5": 268435456, + "6:5": 402653184, + "7:5": 268435456, + "8:5": 402653184, + "9:5": 268435456, + "10:5": 402653184, + "11:5": 268435456, + "12:5": 402653184, + "13:5": 268435456, + "14:5": 402653184, + "15:5": 268435456, + "16:5": 402653184, + "17:5": 268435456, + "18:5": 402653184, + "19:5": 268435456, + "20:5": 402653184, + "21:5": 268435456, + "22:5": 402653184, + "23:5": 268435456, + "24:5": 402653184, + "25:5": 268435456, + "26:5": 402653184, + "27:5": 268435456, + "28:5": 402653184, + "29:5": 268435456, + "30:5": 402653184, + "31:5": 268435456, + "32:5": 402653184, + "33:5": 268435456, + "34:5": 402653184, + "35:5": 268435456, + "36:5": 402653184, + "37:5": 268435456, + "38:5": 402653184, + "39:5": 268435456, + "40:5": 402653184, + "41:5": 268435456, + "42:5": 402653184, + "43:5": 268435456, + "44:5": 402653184, + "45:5": 268435456, + "46:5": 402653184, + "47:5": 268435456, + "48:5": 402653184, + "49:5": 268435456, + "50:5": 402653184, + "51:5": 268435456, + "52:5": 402653184, + "53:5": 268435456, + "54:5": 402653184, + "55:5": 268435456, + "56:5": 402653184, + "57:5": 268435456, + "58:5": 402653184, + "59:5": 268435456, + "60:5": 402653184, + "61:5": 268435456, + "62:5": 402653184, + "63:5": 268435456, + "64:5": 402653184, + "65:5": 268435456, + "66:5": 402653184, + "67:5": 268435456, + "68:5": 402653184, + "69:5": 268435456, + "70:5": 402653184, + "71:5": 268435456, + "72:5": 402653184, + "73:5": 268435456, + "74:5": 402653184, + "75:5": 268435456, + "76:5": 402653184, + "77:5": 268435456, + "78:5": 402653184, + "79:5": 268435456, + "80:5": 402653184, + "81:5": 268435456, + "82:5": 402653184, + "83:5": 268435456, + "84:5": 402653184, + "85:5": 268435456, + "86:5": 402653184, + "87:5": 268435456, + "88:5": 402653184, + "89:5": 268435456, + "90:5": 402653184, + "91:5": 268435456, + "92:5": 402653184, + "93:5": 268435456, + "94:5": 402653184, + "95:5": 268435456, + "96:5": 402653184, + "97:5": 268435456, + "98:5": 402653184, + "99:5": 268435456, + "100:5": 402653184, + "101:5": 268435456, + "102:5": 402653184, + "103:5": 268435456, + "104:5": 402653184, + "105:5": 268435456, + "106:5": 402653184, + "107:5": 268435456, + "108:5": 402653184, + "109:5": 268435456, + "110:5": 402653184, + "111:5": 268435456, + "112:5": 402653184, + "113:5": 268435456, + "114:5": 402653184, + "115:5": 268435456, + "116:5": 402653184, + "117:5": 268435456, + "118:5": 402653184, + "119:5": 268435456, + "120:5": 402653184, + "121:5": 268435456, + "122:5": 402653184, + "123:5": 268435456, + "124:5": 402653184, + "125:5": 268435456, + "126:5": 402653184, + "127:5": 268435456, + "0:6": 268435456, + "1:6": 402653184, + "2:6": 268435456, + "3:6": 402653184, + "4:6": 268435456, + "5:6": 402653184, + "6:6": 268435456, + "7:6": 402653184, + "8:6": 268435456, + "9:6": 402653184, + "10:6": 268435456, + "11:6": 402653184, + "12:6": 268435456, + "13:6": 402653184, + "14:6": 268435456, + "15:6": 402653184, + "16:6": 268435456, + "17:6": 402653184, + "18:6": 268435456, + "19:6": 402653184, + "20:6": 268435456, + "21:6": 402653184, + "22:6": 268435456, + "23:6": 402653184, + "24:6": 268435456, + "25:6": 402653184, + "26:6": 268435456, + "27:6": 402653184, + "28:6": 268435456, + "29:6": 402653184, + "30:6": 268435456, + "31:6": 402653184, + "32:6": 268435456, + "33:6": 402653184, + "34:6": 268435456, + "35:6": 402653184, + "36:6": 268435456, + "37:6": 402653184, + "38:6": 268435456, + "39:6": 402653184, + "40:6": 268435456, + "41:6": 402653184, + "42:6": 268435456, + "43:6": 402653184, + "44:6": 268435456, + "45:6": 402653184, + "46:6": 268435456, + "47:6": 402653184, + "48:6": 268435456, + "49:6": 402653184, + "50:6": 268435456, + "51:6": 402653184, + "52:6": 268435456, + "53:6": 402653184, + "54:6": 268435456, + "55:6": 402653184, + "56:6": 268435456, + "57:6": 402653184, + "58:6": 268435456, + "59:6": 402653184, + "60:6": 268435456, + "61:6": 402653184, + "62:6": 268435456, + "63:6": 402653184, + "64:6": 268435456, + "65:6": 402653184, + "66:6": 268435456, + "67:6": 402653184, + "68:6": 268435456, + "69:6": 402653184, + "70:6": 268435456, + "71:6": 402653184, + "72:6": 268435456, + "73:6": 402653184, + "74:6": 268435456, + "75:6": 402653184, + "76:6": 268435456, + "77:6": 402653184, + "78:6": 268435456, + "79:6": 402653184, + "80:6": 268435456, + "81:6": 402653184, + "82:6": 268435456, + "83:6": 402653184, + "84:6": 268435456, + "85:6": 402653184, + "86:6": 268435456, + "87:6": 402653184, + "88:6": 268435456, + "89:6": 402653184, + "90:6": 268435456, + "91:6": 402653184, + "92:6": 268435456, + "93:6": 402653184, + "94:6": 268435456, + "95:6": 402653184, + "96:6": 268435456, + "97:6": 402653184, + "98:6": 268435456, + "99:6": 402653184, + "100:6": 268435456, + "101:6": 402653184, + "102:6": 268435456, + "103:6": 402653184, + "104:6": 268435456, + "105:6": 402653184, + "106:6": 268435456, + "107:6": 402653184, + "108:6": 268435456, + "109:6": 402653184, + "110:6": 268435456, + "111:6": 402653184, + "112:6": 268435456, + "113:6": 402653184, + "114:6": 268435456, + "115:6": 402653184, + "116:6": 268435456, + "117:6": 402653184, + "118:6": 268435456, + "119:6": 402653184, + "120:6": 268435456, + "121:6": 402653184, + "122:6": 268435456, + "123:6": 402653184, + "124:6": 268435456, + "125:6": 402653184, + "126:6": 268435456, + "127:6": 402653184, + "0:7": 402653184, + "1:7": 268435456, + "2:7": 402653184, + "3:7": 268435456, + "4:7": 402653184, + "5:7": 268435456, + "6:7": 402653184, + "7:7": 268435456, + "8:7": 402653184, + "9:7": 268435456, + "10:7": 402653184, + "11:7": 268435456, + "12:7": 402653184, + "13:7": 268435456, + "14:7": 402653184, + "15:7": 268435456, + "16:7": 402653184, + "17:7": 268435456, + "18:7": 402653184, + "19:7": 268435456, + "20:7": 402653184, + "21:7": 268435456, + "22:7": 402653184, + "23:7": 268435456, + "24:7": 402653184, + "25:7": 268435456, + "26:7": 402653184, + "27:7": 268435456, + "28:7": 402653184, + "29:7": 268435456, + "30:7": 402653184, + "31:7": 268435456, + "32:7": 402653184, + "33:7": 268435456, + "34:7": 402653184, + "35:7": 268435456, + "36:7": 402653184, + "37:7": 268435456, + "38:7": 402653184, + "39:7": 268435456, + "40:7": 402653184, + "41:7": 268435456, + "42:7": 402653184, + "43:7": 268435456, + "44:7": 402653184, + "45:7": 268435456, + "46:7": 402653184, + "47:7": 268435456, + "48:7": 402653184, + "49:7": 268435456, + "50:7": 402653184, + "51:7": 268435456, + "52:7": 402653184, + "53:7": 268435456, + "54:7": 402653184, + "55:7": 268435456, + "56:7": 402653184, + "57:7": 268435456, + "58:7": 402653184, + "59:7": 268435456, + "60:7": 402653184, + "61:7": 268435456, + "62:7": 402653184, + "63:7": 268435456, + "64:7": 402653184, + "65:7": 268435456, + "66:7": 402653184, + "67:7": 268435456, + "68:7": 402653184, + "69:7": 268435456, + "70:7": 402653184, + "71:7": 268435456, + "72:7": 402653184, + "73:7": 268435456, + "74:7": 402653184, + "75:7": 268435456, + "76:7": 402653184, + "77:7": 268435456, + "78:7": 402653184, + "79:7": 268435456, + "80:7": 402653184, + "81:7": 268435456, + "82:7": 402653184, + "83:7": 268435456, + "84:7": 402653184, + "85:7": 268435456, + "86:7": 402653184, + "87:7": 268435456, + "88:7": 402653184, + "89:7": 268435456, + "90:7": 402653184, + "91:7": 268435456, + "92:7": 402653184, + "93:7": 268435456, + "94:7": 402653184, + "95:7": 268435456, + "96:7": 402653184, + "97:7": 268435456, + "98:7": 402653184, + "99:7": 268435456, + "100:7": 402653184, + "101:7": 268435456, + "102:7": 402653184, + "103:7": 268435456, + "104:7": 402653184, + "105:7": 268435456, + "106:7": 402653184, + "107:7": 268435456, + "108:7": 402653184, + "109:7": 268435456, + "110:7": 402653184, + "111:7": 268435456, + "112:7": 402653184, + "113:7": 268435456, + "114:7": 402653184, + "115:7": 268435456, + "116:7": 402653184, + "117:7": 268435456, + "118:7": 402653184, + "119:7": 268435456, + "120:7": 402653184, + "121:7": 268435456, + "122:7": 402653184, + "123:7": 268435456, + "124:7": 402653184, + "125:7": 268435456, + "126:7": 402653184, + "127:7": 268435456, + "0:8": 268435456, + "1:8": 402653184, + "2:8": 268435456, + "3:8": 402653184, + "4:8": 268435456, + "5:8": 402653184, + "6:8": 268435456, + "7:8": 402653184, + "8:8": 268435456, + "9:8": 402653184, + "10:8": 268435456, + "11:8": 402653184, + "12:8": 268435456, + "13:8": 402653184, + "14:8": 268435456, + "15:8": 402653184, + "16:8": 268435456, + "17:8": 402653184, + "18:8": 268435456, + "19:8": 402653184, + "20:8": 268435456, + "21:8": 402653184, + "22:8": 268435456, + "23:8": 402653184, + "24:8": 268435456, + "25:8": 402653184, + "26:8": 268435456, + "27:8": 402653184, + "28:8": 268435456, + "29:8": 402653184, + "30:8": 268435456, + "31:8": 402653184, + "32:8": 268435456, + "33:8": 402653184, + "34:8": 268435456, + "35:8": 402653184, + "36:8": 268435456, + "37:8": 402653184, + "38:8": 268435456, + "39:8": 402653184, + "40:8": 268435456, + "41:8": 402653184, + "42:8": 268435456, + "43:8": 402653184, + "44:8": 268435456, + "45:8": 402653184, + "46:8": 268435456, + "47:8": 402653184, + "48:8": 268435456, + "49:8": 402653184, + "50:8": 268435456, + "51:8": 402653184, + "52:8": 268435456, + "53:8": 402653184, + "54:8": 268435456, + "55:8": 402653184, + "56:8": 268435456, + "57:8": 402653184, + "58:8": 268435456, + "59:8": 402653184, + "60:8": 268435456, + "61:8": 402653184, + "62:8": 268435456, + "63:8": 402653184, + "64:8": 268435456, + "65:8": 402653184, + "66:8": 268435456, + "67:8": 402653184, + "68:8": 268435456, + "69:8": 402653184, + "70:8": 268435456, + "71:8": 402653184, + "72:8": 268435456, + "73:8": 402653184, + "74:8": 268435456, + "75:8": 402653184, + "76:8": 268435456, + "77:8": 402653184, + "78:8": 268435456, + "79:8": 402653184, + "80:8": 268435456, + "81:8": 402653184, + "82:8": 268435456, + "83:8": 402653184, + "84:8": 268435456, + "85:8": 402653184, + "86:8": 268435456, + "87:8": 402653184, + "88:8": 268435456, + "89:8": 402653184, + "90:8": 268435456, + "91:8": 402653184, + "92:8": 268435456, + "93:8": 402653184, + "94:8": 268435456, + "95:8": 402653184, + "96:8": 268435456, + "97:8": 402653184, + "98:8": 268435456, + "99:8": 402653184, + "100:8": 268435456, + "101:8": 402653184, + "102:8": 268435456, + "103:8": 402653184, + "104:8": 268435456, + "105:8": 402653184, + "106:8": 268435456, + "107:8": 402653184, + "108:8": 268435456, + "109:8": 402653184, + "110:8": 268435456, + "111:8": 402653184, + "112:8": 268435456, + "113:8": 402653184, + "114:8": 268435456, + "115:8": 402653184, + "116:8": 268435456, + "117:8": 402653184, + "118:8": 268435456, + "119:8": 402653184, + "120:8": 268435456, + "121:8": 402653184, + "122:8": 268435456, + "123:8": 402653184, + "124:8": 268435456, + "125:8": 402653184, + "126:8": 268435456, + "127:8": 402653184, + "0:9": 402653184, + "1:9": 268435456, + "2:9": 402653184, + "3:9": 268435456, + "4:9": 402653184, + "5:9": 268435456, + "6:9": 402653184, + "7:9": 268435456, + "8:9": 402653184, + "9:9": 268435456, + "10:9": 402653184, + "11:9": 268435456, + "12:9": 402653184, + "13:9": 268435456, + "14:9": 402653184, + "15:9": 268435456, + "16:9": 402653184, + "17:9": 268435456, + "18:9": 402653184, + "19:9": 268435456, + "20:9": 402653184, + "21:9": 268435456, + "22:9": 402653184, + "23:9": 268435456, + "24:9": 402653184, + "25:9": 268435456, + "26:9": 402653184, + "27:9": 268435456, + "28:9": 402653184, + "29:9": 268435456, + "30:9": 402653184, + "31:9": 268435456, + "32:9": 402653184, + "33:9": 268435456, + "34:9": 402653184, + "35:9": 268435456, + "36:9": 402653184, + "37:9": 268435456, + "38:9": 402653184, + "39:9": 268435456, + "40:9": 402653184, + "41:9": 268435456, + "42:9": 402653184, + "43:9": 268435456, + "44:9": 402653184, + "45:9": 268435456, + "46:9": 402653184, + "47:9": 268435456, + "48:9": 402653184, + "49:9": 268435456, + "50:9": 402653184, + "51:9": 268435456, + "52:9": 402653184, + "53:9": 268435456, + "54:9": 402653184, + "55:9": 268435456, + "56:9": 402653184, + "57:9": 268435456, + "58:9": 402653184, + "59:9": 268435456, + "60:9": 402653184, + "61:9": 268435456, + "62:9": 402653184, + "63:9": 268435456, + "64:9": 402653184, + "65:9": 268435456, + "66:9": 402653184, + "67:9": 268435456, + "68:9": 402653184, + "69:9": 268435456, + "70:9": 402653184, + "71:9": 268435456, + "72:9": 402653184, + "73:9": 268435456, + "74:9": 402653184, + "75:9": 268435456, + "76:9": 402653184, + "77:9": 268435456, + "78:9": 402653184, + "79:9": 268435456, + "80:9": 402653184, + "81:9": 268435456, + "82:9": 402653184, + "83:9": 268435456, + "84:9": 402653184, + "85:9": 268435456, + "86:9": 402653184, + "87:9": 268435456, + "88:9": 402653184, + "89:9": 268435456, + "90:9": 402653184, + "91:9": 268435456, + "92:9": 402653184, + "93:9": 268435456, + "94:9": 402653184, + "95:9": 268435456, + "96:9": 402653184, + "97:9": 268435456, + "98:9": 402653184, + "99:9": 268435456, + "100:9": 402653184, + "101:9": 268435456, + "102:9": 402653184, + "103:9": 268435456, + "104:9": 402653184, + "105:9": 268435456, + "106:9": 402653184, + "107:9": 268435456, + "108:9": 402653184, + "109:9": 268435456, + "110:9": 402653184, + "111:9": 268435456, + "112:9": 402653184, + "113:9": 268435456, + "114:9": 402653184, + "115:9": 268435456, + "116:9": 402653184, + "117:9": 268435456, + "118:9": 402653184, + "119:9": 268435456, + "120:9": 402653184, + "121:9": 268435456, + "122:9": 402653184, + "123:9": 268435456, + "124:9": 402653184, + "125:9": 268435456, + "126:9": 402653184, + "127:9": 268435456, + "0:10": 268435456, + "1:10": 402653184, + "2:10": 268435456, + "3:10": 402653184, + "4:10": 268435456, + "5:10": 402653184, + "6:10": 268435456, + "7:10": 402653184, + "8:10": 268435456, + "9:10": 402653184, + "10:10": 268435456, + "11:10": 402653184, + "12:10": 268435456, + "13:10": 402653184, + "14:10": 268435456, + "15:10": 402653184, + "16:10": 268435456, + "17:10": 402653184, + "18:10": 268435456, + "19:10": 402653184, + "20:10": 268435456, + "21:10": 402653184, + "22:10": 268435456, + "23:10": 402653184, + "24:10": 268435456, + "25:10": 402653184, + "26:10": 268435456, + "27:10": 402653184, + "28:10": 268435456, + "29:10": 402653184, + "30:10": 268435456, + "31:10": 402653184, + "32:10": 268435456, + "33:10": 402653184, + "34:10": 268435456, + "35:10": 402653184, + "36:10": 268435456, + "37:10": 402653184, + "38:10": 268435456, + "39:10": 402653184, + "40:10": 268435456, + "41:10": 402653184, + "42:10": 268435456, + "43:10": 402653184, + "44:10": 268435456, + "45:10": 402653184, + "46:10": 268435456, + "47:10": 402653184, + "48:10": 268435456, + "49:10": 402653184, + "50:10": 268435456, + "51:10": 402653184, + "52:10": 268435456, + "53:10": 402653184, + "54:10": 268435456, + "55:10": 402653184, + "56:10": 268435456, + "57:10": 402653184, + "58:10": 268435456, + "59:10": 402653184, + "60:10": 268435456, + "61:10": 402653184, + "62:10": 268435456, + "63:10": 402653184, + "64:10": 268435456, + "65:10": 402653184, + "66:10": 268435456, + "67:10": 402653184, + "68:10": 268435456, + "69:10": 402653184, + "70:10": 268435456, + "71:10": 402653184, + "72:10": 268435456, + "73:10": 402653184, + "74:10": 268435456, + "75:10": 402653184, + "76:10": 268435456, + "77:10": 402653184, + "78:10": 268435456, + "79:10": 402653184, + "80:10": 268435456, + "81:10": 402653184, + "82:10": 268435456, + "83:10": 402653184, + "84:10": 268435456, + "85:10": 402653184, + "86:10": 268435456, + "87:10": 402653184, + "88:10": 268435456, + "89:10": 402653184, + "90:10": 268435456, + "91:10": 402653184, + "92:10": 268435456, + "93:10": 402653184, + "94:10": 268435456, + "95:10": 402653184, + "96:10": 268435456, + "97:10": 402653184, + "98:10": 268435456, + "99:10": 402653184, + "100:10": 268435456, + "101:10": 402653184, + "102:10": 268435456, + "103:10": 402653184, + "104:10": 268435456, + "105:10": 402653184, + "106:10": 268435456, + "107:10": 402653184, + "108:10": 268435456, + "109:10": 402653184, + "110:10": 268435456, + "111:10": 402653184, + "112:10": 268435456, + "113:10": 402653184, + "114:10": 268435456, + "115:10": 402653184, + "116:10": 268435456, + "117:10": 402653184, + "118:10": 268435456, + "119:10": 402653184, + "120:10": 268435456, + "121:10": 402653184, + "122:10": 268435456, + "123:10": 402653184, + "124:10": 268435456, + "125:10": 402653184, + "126:10": 268435456, + "127:10": 402653184, + "0:11": 402653184, + "1:11": 268435456, + "2:11": 402653184, + "3:11": 268435456, + "4:11": 402653184, + "5:11": 268435456, + "6:11": 402653184, + "7:11": 268435456, + "8:11": 402653184, + "9:11": 268435456, + "10:11": 402653184, + "11:11": 268435456, + "12:11": 402653184, + "13:11": 268435456, + "14:11": 402653184, + "15:11": 268435456, + "16:11": 402653184, + "17:11": 268435456, + "18:11": 402653184, + "19:11": 268435456, + "20:11": 402653184, + "21:11": 268435456, + "22:11": -9288933, + "23:11": -9288933, + "24:11": -9288933, + "25:11": -9288933, + "26:11": -9288933, + "27:11": -9288933, + "28:11": -9288933, + "29:11": -9288933, + "30:11": -9288933, + "31:11": -9288933, + "32:11": -9288933, + "33:11": -9288933, + "34:11": -9288933, + "35:11": -9288933, + "36:11": -9288933, + "37:11": -9288933, + "38:11": -9288933, + "39:11": -9288933, + "40:11": -9288933, + "41:11": -9288933, + "42:11": -9288933, + "43:11": -9288933, + "44:11": -9288933, + "45:11": -9288933, + "46:11": -9288933, + "47:11": -9288933, + "48:11": -9288933, + "49:11": -9288933, + "50:11": -9288933, + "51:11": -9288933, + "52:11": -9288933, + "53:11": -9288933, + "54:11": -9288933, + "55:11": -9288933, + "56:11": -9288933, + "57:11": -9288933, + "58:11": -9288933, + "59:11": -9288933, + "60:11": -9288933, + "61:11": -9288933, + "62:11": 402653184, + "63:11": 268435456, + "64:11": 402653184, + "65:11": 268435456, + "66:11": -16745472, + "67:11": -16745472, + "68:11": -16745472, + "69:11": -16745472, + "70:11": -16745472, + "71:11": -16745472, + "72:11": -16745472, + "73:11": -16745472, + "74:11": -16745472, + "75:11": -16745472, + "76:11": -16745472, + "77:11": -16745472, + "78:11": -16745472, + "79:11": -16745472, + "80:11": -16745472, + "81:11": -16745472, + "82:11": -16745472, + "83:11": -16745472, + "84:11": 402653184, + "85:11": 268435456, + "86:11": 402653184, + "87:11": 268435456, + "88:11": -9288933, + "89:11": -9288933, + "90:11": -9288933, + "91:11": -9288933, + "92:11": -9288933, + "93:11": -9288933, + "94:11": -9288933, + "95:11": -9288933, + "96:11": -9288933, + "97:11": -9288933, + "98:11": -9288933, + "99:11": -9288933, + "100:11": -9288933, + "101:11": -9288933, + "102:11": -9288933, + "103:11": -9288933, + "104:11": -9288933, + "105:11": -9288933, + "106:11": 402653184, + "107:11": 268435456, + "108:11": 402653184, + "109:11": 268435456, + "110:11": 402653184, + "111:11": 268435456, + "112:11": 402653184, + "113:11": 268435456, + "114:11": 402653184, + "115:11": 268435456, + "116:11": 402653184, + "117:11": 268435456, + "118:11": 402653184, + "119:11": 268435456, + "120:11": 402653184, + "121:11": 268435456, + "122:11": 402653184, + "123:11": 268435456, + "124:11": 402653184, + "125:11": 268435456, + "126:11": 402653184, + "127:11": 268435456, + "0:12": 268435456, + "1:12": 402653184, + "2:12": 268435456, + "3:12": 402653184, + "4:12": 268435456, + "5:12": 402653184, + "6:12": 268435456, + "7:12": 402653184, + "8:12": 268435456, + "9:12": 402653184, + "10:12": 268435456, + "11:12": 402653184, + "12:12": 268435456, + "13:12": 402653184, + "14:12": 268435456, + "15:12": 402653184, + "16:12": 268435456, + "17:12": 402653184, + "18:12": 268435456, + "19:12": 402653184, + "20:12": 268435456, + "21:12": 402653184, + "22:12": -9288933, + "23:12": -9288933, + "24:12": -9288933, + "25:12": -9288933, + "26:12": -9288933, + "27:12": -9288933, + "28:12": -9288933, + "29:12": -9288933, + "30:12": -9288933, + "31:12": -9288933, + "32:12": -9288933, + "33:12": -9288933, + "34:12": -9288933, + "35:12": -9288933, + "36:12": -9288933, + "37:12": -9288933, + "38:12": -9288933, + "39:12": -9288933, + "40:12": -9288933, + "41:12": -9288933, + "42:12": -9288933, + "43:12": -9288933, + "44:12": -9288933, + "45:12": -9288933, + "46:12": -9288933, + "47:12": -9288933, + "48:12": -9288933, + "49:12": -9288933, + "50:12": -9288933, + "51:12": -9288933, + "52:12": -9288933, + "53:12": -9288933, + "54:12": -9288933, + "55:12": -9288933, + "56:12": -9288933, + "57:12": -9288933, + "58:12": -9288933, + "59:12": -9288933, + "60:12": -9288933, + "61:12": -9288933, + "62:12": 268435456, + "63:12": 402653184, + "64:12": 268435456, + "65:12": 402653184, + "66:12": -16745472, + "67:12": -16745472, + "68:12": -16745472, + "69:12": -16745472, + "70:12": -16745472, + "71:12": -16745472, + "72:12": -16745472, + "73:12": -16745472, + "74:12": -16745472, + "75:12": -16745472, + "76:12": -16745472, + "77:12": -16745472, + "78:12": -16745472, + "79:12": -16745472, + "80:12": -16745472, + "81:12": -16745472, + "82:12": -16745472, + "83:12": -16745472, + "84:12": 268435456, + "85:12": 402653184, + "86:12": 268435456, + "87:12": 402653184, + "88:12": -9288933, + "89:12": -9288933, + "90:12": -9288933, + "91:12": -9288933, + "92:12": -9288933, + "93:12": -9288933, + "94:12": -9288933, + "95:12": -9288933, + "96:12": -9288933, + "97:12": -9288933, + "98:12": -9288933, + "99:12": -9288933, + "100:12": -9288933, + "101:12": -9288933, + "102:12": -9288933, + "103:12": -9288933, + "104:12": -9288933, + "105:12": -9288933, + "106:12": 268435456, + "107:12": 402653184, + "108:12": 268435456, + "109:12": 402653184, + "110:12": 268435456, + "111:12": 402653184, + "112:12": 268435456, + "113:12": 402653184, + "114:12": 268435456, + "115:12": 402653184, + "116:12": 268435456, + "117:12": 402653184, + "118:12": 268435456, + "119:12": 402653184, + "120:12": 268435456, + "121:12": 402653184, + "122:12": 268435456, + "123:12": 402653184, + "124:12": 268435456, + "125:12": 402653184, + "126:12": 268435456, + "127:12": 402653184, + "0:13": 402653184, + "1:13": 268435456, + "2:13": 402653184, + "3:13": 268435456, + "4:13": 402653184, + "5:13": 268435456, + "6:13": 402653184, + "7:13": 268435456, + "8:13": 402653184, + "9:13": 268435456, + "10:13": 402653184, + "11:13": 268435456, + "12:13": 402653184, + "13:13": 268435456, + "14:13": 402653184, + "15:13": 268435456, + "16:13": 402653184, + "17:13": 268435456, + "18:13": 402653184, + "19:13": 268435456, + "20:13": 402653184, + "21:13": 268435456, + "22:13": -9288933, + "23:13": -9288933, + "24:13": -9288933, + "25:13": -9288933, + "26:13": -9288933, + "27:13": -9288933, + "28:13": -9288933, + "29:13": -9288933, + "30:13": -9288933, + "31:13": -9288933, + "32:13": -9288933, + "33:13": -9288933, + "34:13": -9288933, + "35:13": -9288933, + "36:13": -9288933, + "37:13": -9288933, + "38:13": -9288933, + "39:13": -9288933, + "40:13": -9288933, + "41:13": -9288933, + "42:13": -9288933, + "43:13": -9288933, + "44:13": -9288933, + "45:13": -9288933, + "46:13": -9288933, + "47:13": -9288933, + "48:13": -9288933, + "49:13": -9288933, + "50:13": -9288933, + "51:13": -9288933, + "52:13": -9288933, + "53:13": -9288933, + "54:13": -9288933, + "55:13": -9288933, + "56:13": -9288933, + "57:13": -9288933, + "58:13": -9288933, + "59:13": -9288933, + "60:13": -9288933, + "61:13": -9288933, + "62:13": 402653184, + "63:13": 268435456, + "64:13": 402653184, + "65:13": 268435456, + "66:13": -16745472, + "67:13": -16745472, + "68:13": -16745472, + "69:13": -16745472, + "70:13": -16745472, + "71:13": -16745472, + "72:13": -16745472, + "73:13": -16745472, + "74:13": -16745472, + "75:13": -16745472, + "76:13": -16745472, + "77:13": -16745472, + "78:13": -16745472, + "79:13": -16745472, + "80:13": -16745472, + "81:13": -16745472, + "82:13": -16745472, + "83:13": -16745472, + "84:13": 402653184, + "85:13": 268435456, + "86:13": 402653184, + "87:13": 268435456, + "88:13": -9288933, + "89:13": -9288933, + "90:13": -9288933, + "91:13": -9288933, + "92:13": -9288933, + "93:13": -9288933, + "94:13": -9288933, + "95:13": -9288933, + "96:13": -9288933, + "97:13": -9288933, + "98:13": -9288933, + "99:13": -9288933, + "100:13": -9288933, + "101:13": -9288933, + "102:13": -9288933, + "103:13": -9288933, + "104:13": -9288933, + "105:13": -9288933, + "106:13": 402653184, + "107:13": 268435456, + "108:13": 402653184, + "109:13": 268435456, + "110:13": 402653184, + "111:13": 268435456, + "112:13": 402653184, + "113:13": 268435456, + "114:13": 402653184, + "115:13": 268435456, + "116:13": 402653184, + "117:13": 268435456, + "118:13": 402653184, + "119:13": 268435456, + "120:13": 402653184, + "121:13": 268435456, + "122:13": 402653184, + "123:13": 268435456, + "124:13": 402653184, + "125:13": 268435456, + "126:13": 402653184, + "127:13": 268435456, + "0:14": 268435456, + "1:14": 402653184, + "2:14": 268435456, + "3:14": 402653184, + "4:14": 268435456, + "5:14": 402653184, + "6:14": 268435456, + "7:14": 402653184, + "8:14": 268435456, + "9:14": 402653184, + "10:14": 268435456, + "11:14": 402653184, + "12:14": 268435456, + "13:14": 402653184, + "14:14": 268435456, + "15:14": 402653184, + "16:14": 268435456, + "17:14": 402653184, + "18:14": 268435456, + "19:14": 402653184, + "20:14": 268435456, + "21:14": 402653184, + "22:14": -9288933, + "23:14": -9288933, + "24:14": -9288933, + "25:14": -9288933, + "26:14": -9288933, + "27:14": -9288933, + "28:14": -9288933, + "29:14": -9288933, + "30:14": -9288933, + "31:14": -9288933, + "32:14": -9288933, + "33:14": -9288933, + "34:14": -9288933, + "35:14": -9288933, + "36:14": -9288933, + "37:14": -9288933, + "38:14": -9288933, + "39:14": -9288933, + "40:14": -9288933, + "41:14": -9288933, + "42:14": -9288933, + "43:14": -9288933, + "44:14": -9288933, + "45:14": -9288933, + "46:14": -9288933, + "47:14": -9288933, + "48:14": -9288933, + "49:14": -9288933, + "50:14": -9288933, + "51:14": -9288933, + "52:14": -9288933, + "53:14": -9288933, + "54:14": -9288933, + "55:14": -9288933, + "56:14": -9288933, + "57:14": -9288933, + "58:14": -9288933, + "59:14": -9288933, + "60:14": -9288933, + "61:14": -9288933, + "62:14": 268435456, + "63:14": 402653184, + "64:14": 268435456, + "65:14": 402653184, + "66:14": -16745472, + "67:14": -16745472, + "68:14": -16745472, + "69:14": -16745472, + "70:14": -16745472, + "71:14": -16745472, + "72:14": -16745472, + "73:14": -16745472, + "74:14": -16745472, + "75:14": -16745472, + "76:14": -16745472, + "77:14": -16745472, + "78:14": -16745472, + "79:14": -16745472, + "80:14": -16745472, + "81:14": -16745472, + "82:14": -16745472, + "83:14": -16745472, + "84:14": 268435456, + "85:14": 402653184, + "86:14": 268435456, + "87:14": 402653184, + "88:14": -9288933, + "89:14": -9288933, + "90:14": -9288933, + "91:14": -9288933, + "92:14": -9288933, + "93:14": -9288933, + "94:14": -9288933, + "95:14": -9288933, + "96:14": -9288933, + "97:14": -9288933, + "98:14": -9288933, + "99:14": -9288933, + "100:14": -9288933, + "101:14": -9288933, + "102:14": -9288933, + "103:14": -9288933, + "104:14": -9288933, + "105:14": -9288933, + "106:14": 268435456, + "107:14": 402653184, + "108:14": 268435456, + "109:14": 402653184, + "110:14": 268435456, + "111:14": 402653184, + "112:14": 268435456, + "113:14": 402653184, + "114:14": 268435456, + "115:14": 402653184, + "116:14": 268435456, + "117:14": 402653184, + "118:14": 268435456, + "119:14": 402653184, + "120:14": 268435456, + "121:14": 402653184, + "122:14": 268435456, + "123:14": 402653184, + "124:14": 268435456, + "125:14": 402653184, + "126:14": 268435456, + "127:14": 402653184, + "0:15": 402653184, + "1:15": 268435456, + "2:15": 402653184, + "3:15": 268435456, + "4:15": 402653184, + "5:15": 268435456, + "6:15": 402653184, + "7:15": 268435456, + "8:15": 402653184, + "9:15": 268435456, + "10:15": 402653184, + "11:15": 268435456, + "12:15": 402653184, + "13:15": 268435456, + "14:15": 402653184, + "15:15": 268435456, + "16:15": 402653184, + "17:15": 268435456, + "18:15": 402653184, + "19:15": 268435456, + "20:15": 402653184, + "21:15": 268435456, + "22:15": -9288933, + "23:15": -9288933, + "24:15": -9288933, + "25:15": -9288933, + "26:15": -9288933, + "27:15": -9288933, + "28:15": -9288933, + "29:15": -9288933, + "30:15": -9288933, + "31:15": -9288933, + "32:15": -9288933, + "33:15": -9288933, + "34:15": -9288933, + "35:15": -9288933, + "36:15": -9288933, + "37:15": -9288933, + "38:15": -9288933, + "39:15": -9288933, + "40:15": -9288933, + "41:15": -9288933, + "42:15": -9288933, + "43:15": -9288933, + "44:15": -9288933, + "45:15": -9288933, + "46:15": -9288933, + "47:15": -9288933, + "48:15": -9288933, + "49:15": -9288933, + "50:15": -9288933, + "51:15": -9288933, + "52:15": -9288933, + "53:15": -9288933, + "54:15": -9288933, + "55:15": -9288933, + "56:15": -9288933, + "57:15": -9288933, + "58:15": -9288933, + "59:15": -9288933, + "60:15": -9288933, + "61:15": -9288933, + "62:15": 402653184, + "63:15": 268435456, + "64:15": 402653184, + "65:15": 268435456, + "66:15": -16745472, + "67:15": -16745472, + "68:15": -16745472, + "69:15": -16745472, + "70:15": -16745472, + "71:15": -16745472, + "72:15": -16745472, + "73:15": -16745472, + "74:15": -16745472, + "75:15": -16745472, + "76:15": -16745472, + "77:15": -16745472, + "78:15": -16745472, + "79:15": -16745472, + "80:15": -16745472, + "81:15": -16745472, + "82:15": -16745472, + "83:15": -16745472, + "84:15": 402653184, + "85:15": 268435456, + "86:15": 402653184, + "87:15": 268435456, + "88:15": -9288933, + "89:15": -9288933, + "90:15": -9288933, + "91:15": -9288933, + "92:15": -9288933, + "93:15": -9288933, + "94:15": -9288933, + "95:15": -9288933, + "96:15": -9288933, + "97:15": -9288933, + "98:15": -9288933, + "99:15": -9288933, + "100:15": -9288933, + "101:15": -9288933, + "102:15": -9288933, + "103:15": -9288933, + "104:15": -9288933, + "105:15": -9288933, + "106:15": 402653184, + "107:15": 268435456, + "108:15": 402653184, + "109:15": 268435456, + "110:15": 402653184, + "111:15": 268435456, + "112:15": 402653184, + "113:15": 268435456, + "114:15": 402653184, + "115:15": 268435456, + "116:15": 402653184, + "117:15": 268435456, + "118:15": 402653184, + "119:15": 268435456, + "120:15": 402653184, + "121:15": 268435456, + "122:15": 402653184, + "123:15": 268435456, + "124:15": 402653184, + "125:15": 268435456, + "126:15": 402653184, + "127:15": 268435456, + "0:16": 268435456, + "1:16": 402653184, + "2:16": 268435456, + "3:16": 402653184, + "4:16": 268435456, + "5:16": 402653184, + "6:16": 268435456, + "7:16": 402653184, + "8:16": 268435456, + "9:16": 402653184, + "10:16": 268435456, + "11:16": 402653184, + "12:16": 268435456, + "13:16": 402653184, + "14:16": 268435456, + "15:16": 402653184, + "16:16": 268435456, + "17:16": 402653184, + "18:16": 268435456, + "19:16": 402653184, + "20:16": 268435456, + "21:16": 402653184, + "22:16": -9288933, + "23:16": -9288933, + "24:16": -9288933, + "25:16": -9288933, + "26:16": -9288933, + "27:16": -9288933, + "28:16": -9288933, + "29:16": -9288933, + "30:16": -9288933, + "31:16": -9288933, + "32:16": -9288933, + "33:16": -9288933, + "34:16": -9288933, + "35:16": -9288933, + "36:16": -9288933, + "37:16": -9288933, + "38:16": -9288933, + "39:16": -9288933, + "40:16": -9288933, + "41:16": -9288933, + "42:16": -9288933, + "43:16": -9288933, + "44:16": -9288933, + "45:16": -9288933, + "46:16": -9288933, + "47:16": -9288933, + "48:16": -9288933, + "49:16": -9288933, + "50:16": -9288933, + "51:16": -9288933, + "52:16": -9288933, + "53:16": -9288933, + "54:16": -9288933, + "55:16": -9288933, + "56:16": -9288933, + "57:16": -9288933, + "58:16": -9288933, + "59:16": -9288933, + "60:16": -9288933, + "61:16": -9288933, + "62:16": 268435456, + "63:16": 402653184, + "64:16": 268435456, + "65:16": 402653184, + "66:16": -16745472, + "67:16": -16745472, + "68:16": -16745472, + "69:16": -16745472, + "70:16": -16745472, + "71:16": -16745472, + "72:16": -16745472, + "73:16": -16745472, + "74:16": -16745472, + "75:16": -16745472, + "76:16": -16745472, + "77:16": -16745472, + "78:16": -16745472, + "79:16": -16745472, + "80:16": -16745472, + "81:16": -16745472, + "82:16": -16745472, + "83:16": -16745472, + "84:16": 268435456, + "85:16": 402653184, + "86:16": 268435456, + "87:16": 402653184, + "88:16": -9288933, + "89:16": -9288933, + "90:16": -9288933, + "91:16": -9288933, + "92:16": -9288933, + "93:16": -9288933, + "94:16": -9288933, + "95:16": -9288933, + "96:16": -9288933, + "97:16": -9288933, + "98:16": -9288933, + "99:16": -9288933, + "100:16": -9288933, + "101:16": -9288933, + "102:16": -9288933, + "103:16": -9288933, + "104:16": -9288933, + "105:16": -9288933, + "106:16": 268435456, + "107:16": 402653184, + "108:16": 268435456, + "109:16": 402653184, + "110:16": 268435456, + "111:16": 402653184, + "112:16": 268435456, + "113:16": 402653184, + "114:16": 268435456, + "115:16": 402653184, + "116:16": 268435456, + "117:16": 402653184, + "118:16": 268435456, + "119:16": 402653184, + "120:16": 268435456, + "121:16": 402653184, + "122:16": 268435456, + "123:16": 402653184, + "124:16": 268435456, + "125:16": 402653184, + "126:16": 268435456, + "127:16": 402653184, + "0:17": 402653184, + "1:17": 268435456, + "2:17": 402653184, + "3:17": 268435456, + "4:17": 402653184, + "5:17": 268435456, + "6:17": 402653184, + "7:17": 268435456, + "8:17": 402653184, + "9:17": 268435456, + "10:17": 402653184, + "11:17": 268435456, + "12:17": 402653184, + "13:17": 268435456, + "14:17": 402653184, + "15:17": 268435456, + "16:17": 402653184, + "17:17": 268435456, + "18:17": 402653184, + "19:17": 268435456, + "20:17": 402653184, + "21:17": 268435456, + "22:17": -9288933, + "23:17": -9288933, + "24:17": -9288933, + "25:17": -9288933, + "26:17": -9288933, + "27:17": -9288933, + "28:17": -9288933, + "29:17": -9288933, + "30:17": -9288933, + "31:17": -9288933, + "32:17": -9288933, + "33:17": -9288933, + "34:17": -9288933, + "35:17": -9288933, + "36:17": -9288933, + "37:17": -9288933, + "38:17": -9288933, + "39:17": -9288933, + "40:17": -9288933, + "41:17": -9288933, + "42:17": -9288933, + "43:17": -9288933, + "44:17": -9288933, + "45:17": -9288933, + "46:17": -9288933, + "47:17": -9288933, + "48:17": -9288933, + "49:17": -9288933, + "50:17": -9288933, + "51:17": -9288933, + "52:17": -9288933, + "53:17": -9288933, + "54:17": -9288933, + "55:17": -9288933, + "56:17": -9288933, + "57:17": -9288933, + "58:17": -9288933, + "59:17": -9288933, + "60:17": -9288933, + "61:17": -9288933, + "62:17": -9288933, + "63:17": -9288933, + "64:17": -9288933, + "65:17": -9288933, + "66:17": -16745472, + "67:17": -16745472, + "68:17": -16745472, + "69:17": -16745472, + "70:17": -16745472, + "71:17": -16745472, + "72:17": -16745472, + "73:17": -16745472, + "74:17": -16745472, + "75:17": -16745472, + "76:17": -16745472, + "77:17": -16745472, + "78:17": -16745472, + "79:17": -16745472, + "80:17": -16745472, + "81:17": -16745472, + "82:17": -16745472, + "83:17": -16745472, + "84:17": 402653184, + "85:17": 268435456, + "86:17": 402653184, + "87:17": 268435456, + "88:17": -9288933, + "89:17": -9288933, + "90:17": -9288933, + "91:17": -9288933, + "92:17": -9288933, + "93:17": -9288933, + "94:17": -9288933, + "95:17": -9288933, + "96:17": -9288933, + "97:17": -9288933, + "98:17": -9288933, + "99:17": -9288933, + "100:17": -9288933, + "101:17": -9288933, + "102:17": -9288933, + "103:17": -9288933, + "104:17": -9288933, + "105:17": -9288933, + "106:17": 402653184, + "107:17": 268435456, + "108:17": 402653184, + "109:17": 268435456, + "110:17": 402653184, + "111:17": 268435456, + "112:17": 402653184, + "113:17": 268435456, + "114:17": 402653184, + "115:17": 268435456, + "116:17": 402653184, + "117:17": 268435456, + "118:17": 402653184, + "119:17": 268435456, + "120:17": 402653184, + "121:17": 268435456, + "122:17": 402653184, + "123:17": 268435456, + "124:17": 402653184, + "125:17": 268435456, + "126:17": 402653184, + "127:17": 268435456, + "0:18": 268435456, + "1:18": 402653184, + "2:18": 268435456, + "3:18": 402653184, + "4:18": 268435456, + "5:18": 402653184, + "6:18": 268435456, + "7:18": 402653184, + "8:18": 268435456, + "9:18": 402653184, + "10:18": 268435456, + "11:18": 402653184, + "12:18": 268435456, + "13:18": 402653184, + "14:18": 268435456, + "15:18": 402653184, + "16:18": 268435456, + "17:18": 402653184, + "18:18": 268435456, + "19:18": 402653184, + "20:18": 268435456, + "21:18": 402653184, + "22:18": -9288933, + "23:18": -9288933, + "24:18": -9288933, + "25:18": -9288933, + "26:18": -9288933, + "27:18": -9288933, + "28:18": -9288933, + "29:18": -9288933, + "30:18": -9288933, + "31:18": -9288933, + "32:18": -1, + "33:18": -1, + "34:18": -1, + "35:18": -9288933, + "36:18": -9288933, + "37:18": -9288933, + "38:18": -9288933, + "39:18": -9288933, + "40:18": -9288933, + "41:18": -9288933, + "42:18": -9288933, + "43:18": -9288933, + "44:18": -9288933, + "45:18": -9288933, + "46:18": -9288933, + "47:18": -9288933, + "48:18": -9288933, + "49:18": -9288933, + "50:18": -9288933, + "51:18": -9288933, + "52:18": -9288933, + "53:18": -9288933, + "54:18": -9288933, + "55:18": -9288933, + "56:18": -9288933, + "57:18": -9288933, + "58:18": -9288933, + "59:18": -9288933, + "60:18": -9288933, + "61:18": -9288933, + "62:18": -9288933, + "63:18": -9288933, + "64:18": -9288933, + "65:18": -9288933, + "66:18": -16745472, + "67:18": -16745472, + "68:18": -16745472, + "69:18": -16745472, + "70:18": -16745472, + "71:18": -16745472, + "72:18": -16745472, + "73:18": -16745472, + "74:18": -16745472, + "75:18": -16745472, + "76:18": -16745472, + "77:18": -16745472, + "78:18": -16745472, + "79:18": -16745472, + "80:18": -16745472, + "81:18": -16745472, + "82:18": -16745472, + "83:18": -16745472, + "84:18": 268435456, + "85:18": 402653184, + "86:18": 268435456, + "87:18": 402653184, + "88:18": -9288933, + "89:18": -9288933, + "90:18": -9288933, + "91:18": -9288933, + "92:18": -9288933, + "93:18": -9288933, + "94:18": -9288933, + "95:18": -9288933, + "96:18": -9288933, + "97:18": -9288933, + "98:18": -1, + "99:18": -1, + "100:18": -1, + "101:18": -9288933, + "102:18": -9288933, + "103:18": -9288933, + "104:18": -9288933, + "105:18": -9288933, + "106:18": 268435456, + "107:18": 402653184, + "108:18": 268435456, + "109:18": 402653184, + "110:18": 268435456, + "111:18": 402653184, + "112:18": 268435456, + "113:18": 402653184, + "114:18": 268435456, + "115:18": 402653184, + "116:18": 268435456, + "117:18": 402653184, + "118:18": 268435456, + "119:18": 402653184, + "120:18": 268435456, + "121:18": 402653184, + "122:18": 268435456, + "123:18": 402653184, + "124:18": 268435456, + "125:18": 402653184, + "126:18": 268435456, + "127:18": 402653184, + "0:19": 402653184, + "1:19": 268435456, + "2:19": 402653184, + "3:19": 268435456, + "4:19": 402653184, + "5:19": 268435456, + "6:19": 402653184, + "7:19": 268435456, + "8:19": 402653184, + "9:19": 268435456, + "10:19": 402653184, + "11:19": 268435456, + "12:19": 402653184, + "13:19": 268435456, + "14:19": 402653184, + "15:19": 268435456, + "16:19": 402653184, + "17:19": 268435456, + "18:19": 402653184, + "19:19": 268435456, + "20:19": 402653184, + "21:19": 268435456, + "22:19": -9288933, + "23:19": -9288933, + "24:19": -9288933, + "25:19": -9288933, + "26:19": -9288933, + "27:19": -9288933, + "28:19": -9288933, + "29:19": -9288933, + "30:19": -9288933, + "31:19": -1, + "32:19": -1, + "33:19": -1, + "34:19": -9288933, + "35:19": -9288933, + "36:19": -9288933, + "37:19": -9288933, + "38:19": -9288933, + "39:19": -9288933, + "40:19": -9288933, + "41:19": -9288933, + "42:19": -9288933, + "43:19": -9288933, + "44:19": -9288933, + "45:19": -9288933, + "46:19": -9288933, + "47:19": -9288933, + "48:19": -9288933, + "49:19": -9288933, + "50:19": -9288933, + "51:19": -9288933, + "52:19": -9288933, + "53:19": -9288933, + "54:19": -9288933, + "55:19": -9288933, + "56:19": -9288933, + "57:19": -9288933, + "58:19": -9288933, + "59:19": -9288933, + "60:19": -9288933, + "61:19": -9288933, + "62:19": -9288933, + "63:19": -9288933, + "64:19": -9288933, + "65:19": -9288933, + "66:19": -16745472, + "67:19": -16745472, + "68:19": -16745472, + "69:19": -16745472, + "70:19": -16745472, + "71:19": -16745472, + "72:19": -16745472, + "73:19": -16745472, + "74:19": -16745472, + "75:19": -16745472, + "76:19": -16745472, + "77:19": -16745472, + "78:19": -16745472, + "79:19": -16745472, + "80:19": -16745472, + "81:19": -16745472, + "82:19": -16745472, + "83:19": -16745472, + "84:19": 402653184, + "85:19": 268435456, + "86:19": 402653184, + "87:19": 268435456, + "88:19": -9288933, + "89:19": -9288933, + "90:19": -9288933, + "91:19": -9288933, + "92:19": -9288933, + "93:19": -9288933, + "94:19": -9288933, + "95:19": -9288933, + "96:19": -9288933, + "97:19": -1, + "98:19": -1, + "99:19": -1, + "100:19": -9288933, + "101:19": -9288933, + "102:19": -9288933, + "103:19": -9288933, + "104:19": -9288933, + "105:19": -9288933, + "106:19": 402653184, + "107:19": 268435456, + "108:19": 402653184, + "109:19": 268435456, + "110:19": 402653184, + "111:19": 268435456, + "112:19": 402653184, + "113:19": 268435456, + "114:19": 402653184, + "115:19": 268435456, + "116:19": 402653184, + "117:19": 268435456, + "118:19": 402653184, + "119:19": 268435456, + "120:19": 402653184, + "121:19": 268435456, + "122:19": 402653184, + "123:19": 268435456, + "124:19": 402653184, + "125:19": 268435456, + "126:19": 402653184, + "127:19": 268435456, + "0:20": 268435456, + "1:20": 402653184, + "2:20": 268435456, + "3:20": 402653184, + "4:20": 268435456, + "5:20": 402653184, + "6:20": 268435456, + "7:20": 402653184, + "8:20": 268435456, + "9:20": 402653184, + "10:20": 268435456, + "11:20": 402653184, + "12:20": 268435456, + "13:20": 402653184, + "14:20": 268435456, + "15:20": 402653184, + "16:20": 268435456, + "17:20": 402653184, + "18:20": 268435456, + "19:20": 402653184, + "20:20": 268435456, + "21:20": 402653184, + "22:20": -9288933, + "23:20": -9288933, + "24:20": -9288933, + "25:20": -9288933, + "26:20": -9288933, + "27:20": -9288933, + "28:20": -9288933, + "29:20": -9288933, + "30:20": -9288933, + "31:20": -1, + "32:20": -1, + "33:20": -9288933, + "34:20": -9288933, + "35:20": -9288933, + "36:20": -9288933, + "37:20": -9288933, + "38:20": -9288933, + "39:20": -9288933, + "40:20": -9288933, + "41:20": -9288933, + "42:20": -9288933, + "43:20": -9288933, + "44:20": -9288933, + "45:20": -9288933, + "46:20": -9288933, + "47:20": -9288933, + "48:20": -9288933, + "49:20": -9288933, + "50:20": -9288933, + "51:20": -9288933, + "52:20": -9288933, + "53:20": -9288933, + "54:20": -9288933, + "55:20": -9288933, + "56:20": -9288933, + "57:20": -9288933, + "58:20": -9288933, + "59:20": -9288933, + "60:20": -9288933, + "61:20": -9288933, + "62:20": -9288933, + "63:20": -9288933, + "64:20": -9288933, + "65:20": -9288933, + "66:20": -16745472, + "67:20": -16745472, + "68:20": -16745472, + "69:20": -16745472, + "70:20": -16745472, + "71:20": -16745472, + "72:20": -16745472, + "73:20": -16745472, + "74:20": -16745472, + "75:20": -16745472, + "76:20": -16745472, + "77:20": -16745472, + "78:20": -16745472, + "79:20": -16745472, + "80:20": -16745472, + "81:20": -16745472, + "82:20": -16745472, + "83:20": -16745472, + "84:20": 268435456, + "85:20": 402653184, + "86:20": 268435456, + "87:20": 402653184, + "88:20": -9288933, + "89:20": -9288933, + "90:20": -9288933, + "91:20": -9288933, + "92:20": -9288933, + "93:20": -9288933, + "94:20": -9288933, + "95:20": -9288933, + "96:20": -9288933, + "97:20": -1, + "98:20": -1, + "99:20": -9288933, + "100:20": -9288933, + "101:20": -9288933, + "102:20": -9288933, + "103:20": -9288933, + "104:20": -9288933, + "105:20": -9288933, + "106:20": 268435456, + "107:20": 402653184, + "108:20": 268435456, + "109:20": 402653184, + "110:20": 268435456, + "111:20": 402653184, + "112:20": 268435456, + "113:20": 402653184, + "114:20": 268435456, + "115:20": 402653184, + "116:20": 268435456, + "117:20": 402653184, + "118:20": 268435456, + "119:20": 402653184, + "120:20": 268435456, + "121:20": 402653184, + "122:20": 268435456, + "123:20": 402653184, + "124:20": 268435456, + "125:20": 402653184, + "126:20": 268435456, + "127:20": 402653184, + "0:21": 402653184, + "1:21": 268435456, + "2:21": 402653184, + "3:21": 268435456, + "4:21": 402653184, + "5:21": 268435456, + "6:21": 402653184, + "7:21": 268435456, + "8:21": 402653184, + "9:21": 268435456, + "10:21": 402653184, + "11:21": 268435456, + "12:21": 402653184, + "13:21": 268435456, + "14:21": 402653184, + "15:21": 268435456, + "16:21": 402653184, + "17:21": 268435456, + "18:21": 402653184, + "19:21": 268435456, + "20:21": 402653184, + "21:21": 268435456, + "22:21": -9288933, + "23:21": -9288933, + "24:21": -9288933, + "25:21": -9288933, + "26:21": -9288933, + "27:21": -9288933, + "28:21": -1, + "29:21": -1, + "30:21": -9288933, + "31:21": -1, + "32:21": -1, + "33:21": -9288933, + "34:21": -9288933, + "35:21": -9288933, + "36:21": -9288933, + "37:21": -9288933, + "38:21": -9288933, + "39:21": -9288933, + "40:21": -9288933, + "41:21": -9288933, + "42:21": -9288933, + "43:21": -9288933, + "44:21": -9288933, + "45:21": -9288933, + "46:21": -9288933, + "47:21": -9288933, + "48:21": -9288933, + "49:21": -9288933, + "50:21": -9288933, + "51:21": -9288933, + "52:21": -9288933, + "53:21": -9288933, + "54:21": -9288933, + "55:21": -9288933, + "56:21": -9288933, + "57:21": -9288933, + "58:21": -9288933, + "59:21": -9288933, + "60:21": -9288933, + "61:21": -9288933, + "62:21": -9288933, + "63:21": -9288933, + "64:21": -9288933, + "65:21": -9288933, + "66:21": -16745472, + "67:21": -16745472, + "68:21": -16745472, + "69:21": -16745472, + "70:21": -16745472, + "71:21": -16745472, + "72:21": -16745472, + "73:21": -16745472, + "74:21": -16745472, + "75:21": -16745472, + "76:21": -16745472, + "77:21": -16745472, + "78:21": -16745472, + "79:21": -16745472, + "80:21": -16745472, + "81:21": -16745472, + "82:21": -16745472, + "83:21": -16745472, + "84:21": 402653184, + "85:21": 268435456, + "86:21": 402653184, + "87:21": 268435456, + "88:21": -9288933, + "89:21": -9288933, + "90:21": -9288933, + "91:21": -9288933, + "92:21": -9288933, + "93:21": -9288933, + "94:21": -1, + "95:21": -1, + "96:21": -9288933, + "97:21": -1, + "98:21": -1, + "99:21": -9288933, + "100:21": -9288933, + "101:21": -9288933, + "102:21": -9288933, + "103:21": -9288933, + "104:21": -9288933, + "105:21": -9288933, + "106:21": 402653184, + "107:21": 268435456, + "108:21": 402653184, + "109:21": 268435456, + "110:21": 402653184, + "111:21": 268435456, + "112:21": 402653184, + "113:21": 268435456, + "114:21": 402653184, + "115:21": 268435456, + "116:21": 402653184, + "117:21": 268435456, + "118:21": 402653184, + "119:21": 268435456, + "120:21": 402653184, + "121:21": 268435456, + "122:21": 402653184, + "123:21": 268435456, + "124:21": 402653184, + "125:21": 268435456, + "126:21": 402653184, + "127:21": 268435456, + "0:22": 268435456, + "1:22": 402653184, + "2:22": 268435456, + "3:22": 402653184, + "4:22": 268435456, + "5:22": 402653184, + "6:22": 268435456, + "7:22": 402653184, + "8:22": 268435456, + "9:22": 402653184, + "10:22": 268435456, + "11:22": 402653184, + "12:22": 268435456, + "13:22": 402653184, + "14:22": 268435456, + "15:22": 402653184, + "16:22": 268435456, + "17:22": 402653184, + "18:22": 268435456, + "19:22": 402653184, + "20:22": 268435456, + "21:22": 402653184, + "22:22": -9288933, + "23:22": -9288933, + "24:22": -9288933, + "25:22": -9288933, + "26:22": -9288933, + "27:22": -9288933, + "28:22": -9288933, + "29:22": -1, + "30:22": -1, + "31:22": -1, + "32:22": -9288933, + "33:22": -9288933, + "34:22": -9288933, + "35:22": -9288933, + "36:22": -9288933, + "37:22": -9288933, + "38:22": -9288933, + "39:22": -9288933, + "40:22": -9288933, + "41:22": -9288933, + "42:22": -9288933, + "43:22": -9288933, + "44:22": -9288933, + "45:22": -9288933, + "46:22": -9288933, + "47:22": -9288933, + "48:22": -9288933, + "49:22": -9288933, + "50:22": -9288933, + "51:22": -9288933, + "52:22": -9288933, + "53:22": -9288933, + "54:22": -9288933, + "55:22": -9288933, + "56:22": -9288933, + "57:22": -9288933, + "58:22": -9288933, + "59:22": -9288933, + "60:22": -9288933, + "61:22": -9288933, + "62:22": -9288933, + "63:22": -9288933, + "64:22": -9288933, + "65:22": -9288933, + "66:22": -16745472, + "67:22": -16745472, + "68:22": -16745472, + "69:22": -16745472, + "70:22": -16745472, + "71:22": -16745472, + "72:22": -16745472, + "73:22": -16745472, + "74:22": -16745472, + "75:22": -16745472, + "76:22": -16745472, + "77:22": -16745472, + "78:22": -16745472, + "79:22": -16745472, + "80:22": -16745472, + "81:22": -16745472, + "82:22": -16745472, + "83:22": -16745472, + "84:22": 268435456, + "85:22": 402653184, + "86:22": 268435456, + "87:22": 402653184, + "88:22": -9288933, + "89:22": -9288933, + "90:22": -9288933, + "91:22": -9288933, + "92:22": -9288933, + "93:22": -9288933, + "94:22": -9288933, + "95:22": -1, + "96:22": -1, + "97:22": -1, + "98:22": -9288933, + "99:22": -9288933, + "100:22": -9288933, + "101:22": -9288933, + "102:22": -9288933, + "103:22": -9288933, + "104:22": -9288933, + "105:22": -9288933, + "106:22": 268435456, + "107:22": 402653184, + "108:22": 268435456, + "109:22": 402653184, + "110:22": 268435456, + "111:22": 402653184, + "112:22": 268435456, + "113:22": 402653184, + "114:22": 268435456, + "115:22": 402653184, + "116:22": 268435456, + "117:22": 402653184, + "118:22": 268435456, + "119:22": 402653184, + "120:22": 268435456, + "121:22": 402653184, + "122:22": 268435456, + "123:22": 402653184, + "124:22": 268435456, + "125:22": 402653184, + "126:22": 268435456, + "127:22": 402653184, + "0:23": 402653184, + "1:23": 268435456, + "2:23": 402653184, + "3:23": 268435456, + "4:23": 402653184, + "5:23": 268435456, + "6:23": 402653184, + "7:23": 268435456, + "8:23": 402653184, + "9:23": 268435456, + "10:23": 402653184, + "11:23": 268435456, + "12:23": 402653184, + "13:23": 268435456, + "14:23": 402653184, + "15:23": 268435456, + "16:23": 402653184, + "17:23": 268435456, + "18:23": 402653184, + "19:23": 268435456, + "20:23": 402653184, + "21:23": 268435456, + "22:23": -9288933, + "23:23": -9288933, + "24:23": -9288933, + "25:23": -9288933, + "26:23": -9288933, + "27:23": -9288933, + "28:23": -9288933, + "29:23": -1, + "30:23": -1, + "31:23": -1, + "32:23": -9288933, + "33:23": -9288933, + "34:23": -9288933, + "35:23": -9288933, + "36:23": -9288933, + "37:23": -9288933, + "38:23": -9288933, + "39:23": -9288933, + "40:23": -9288933, + "41:23": -9288933, + "42:23": -9288933, + "43:23": -9288933, + "44:23": -9288933, + "45:23": -9288933, + "46:23": -9288933, + "47:23": -9288933, + "48:23": -9288933, + "49:23": -9288933, + "50:23": -9288933, + "51:23": -9288933, + "52:23": -9288933, + "53:23": -9288933, + "54:23": -9288933, + "55:23": -9288933, + "56:23": -9288933, + "57:23": -9288933, + "58:23": -9288933, + "59:23": -9288933, + "60:23": -9288933, + "61:23": -9288933, + "62:23": -9288933, + "63:23": -9288933, + "64:23": -9288933, + "65:23": -9288933, + "66:23": -16745472, + "67:23": -16745472, + "68:23": -16745472, + "69:23": -16745472, + "70:23": -16745472, + "71:23": -16745472, + "72:23": -16745472, + "73:23": -16745472, + "74:23": -16745472, + "75:23": -16745472, + "76:23": -16745472, + "77:23": -16745472, + "78:23": -16745472, + "79:23": -16745472, + "80:23": -16745472, + "81:23": -16745472, + "82:23": -16745472, + "83:23": -16745472, + "84:23": 402653184, + "85:23": 268435456, + "86:23": 402653184, + "87:23": 268435456, + "88:23": -9288933, + "89:23": -9288933, + "90:23": -9288933, + "91:23": -9288933, + "92:23": -9288933, + "93:23": -9288933, + "94:23": -9288933, + "95:23": -1, + "96:23": -1, + "97:23": -1, + "98:23": -9288933, + "99:23": -9288933, + "100:23": -9288933, + "101:23": -9288933, + "102:23": -9288933, + "103:23": -9288933, + "104:23": -9288933, + "105:23": -9288933, + "106:23": 402653184, + "107:23": 268435456, + "108:23": 402653184, + "109:23": 268435456, + "110:23": 402653184, + "111:23": 268435456, + "112:23": 402653184, + "113:23": 268435456, + "114:23": 402653184, + "115:23": 268435456, + "116:23": 402653184, + "117:23": 268435456, + "118:23": 402653184, + "119:23": 268435456, + "120:23": 402653184, + "121:23": 268435456, + "122:23": 402653184, + "123:23": 268435456, + "124:23": 402653184, + "125:23": 268435456, + "126:23": 402653184, + "127:23": 268435456, + "0:24": 268435456, + "1:24": 402653184, + "2:24": 268435456, + "3:24": 402653184, + "4:24": 268435456, + "5:24": 402653184, + "6:24": 268435456, + "7:24": 402653184, + "8:24": 268435456, + "9:24": 402653184, + "10:24": 268435456, + "11:24": 402653184, + "12:24": 268435456, + "13:24": 402653184, + "14:24": 268435456, + "15:24": 402653184, + "16:24": 268435456, + "17:24": 402653184, + "18:24": 268435456, + "19:24": 402653184, + "20:24": 268435456, + "21:24": 402653184, + "22:24": -9288933, + "23:24": -9288933, + "24:24": -9288933, + "25:24": -9288933, + "26:24": -9288933, + "27:24": -9288933, + "28:24": -9288933, + "29:24": -9288933, + "30:24": -9288933, + "31:24": -9288933, + "32:24": -9288933, + "33:24": -9288933, + "34:24": -9288933, + "35:24": -9288933, + "36:24": -9288933, + "37:24": -9288933, + "38:24": -9288933, + "39:24": -9288933, + "40:24": -9288933, + "41:24": -9288933, + "42:24": -9288933, + "43:24": -9288933, + "44:24": -9288933, + "45:24": -9288933, + "46:24": -9288933, + "47:24": -9288933, + "48:24": -9288933, + "49:24": -9288933, + "50:24": -9288933, + "51:24": -9288933, + "52:24": -9288933, + "53:24": -9288933, + "54:24": -9288933, + "55:24": -9288933, + "56:24": -9288933, + "57:24": -9288933, + "58:24": -9288933, + "59:24": -9288933, + "60:24": -9288933, + "61:24": -9288933, + "62:24": 268435456, + "63:24": 402653184, + "64:24": 268435456, + "65:24": 402653184, + "66:24": -16745472, + "67:24": -16745472, + "68:24": -16745472, + "69:24": -16745472, + "70:24": -16745472, + "71:24": -16745472, + "72:24": -16745472, + "73:24": -16745472, + "74:24": -16745472, + "75:24": -16745472, + "76:24": -16745472, + "77:24": -16745472, + "78:24": -16745472, + "79:24": -16745472, + "80:24": -16745472, + "81:24": -16745472, + "82:24": -16745472, + "83:24": -16745472, + "84:24": 268435456, + "85:24": 402653184, + "86:24": 268435456, + "87:24": 402653184, + "88:24": -9288933, + "89:24": -9288933, + "90:24": -9288933, + "91:24": -9288933, + "92:24": -9288933, + "93:24": -9288933, + "94:24": -9288933, + "95:24": -9288933, + "96:24": -9288933, + "97:24": -9288933, + "98:24": -9288933, + "99:24": -9288933, + "100:24": -9288933, + "101:24": -9288933, + "102:24": -9288933, + "103:24": -9288933, + "104:24": -9288933, + "105:24": -9288933, + "106:24": 268435456, + "107:24": 402653184, + "108:24": 268435456, + "109:24": 402653184, + "110:24": 268435456, + "111:24": 402653184, + "112:24": 268435456, + "113:24": 402653184, + "114:24": 268435456, + "115:24": 402653184, + "116:24": 268435456, + "117:24": 402653184, + "118:24": 268435456, + "119:24": 402653184, + "120:24": 268435456, + "121:24": 402653184, + "122:24": 268435456, + "123:24": 402653184, + "124:24": 268435456, + "125:24": 402653184, + "126:24": 268435456, + "127:24": 402653184, + "0:25": 402653184, + "1:25": 268435456, + "2:25": 402653184, + "3:25": 268435456, + "4:25": 402653184, + "5:25": 268435456, + "6:25": 402653184, + "7:25": 268435456, + "8:25": 402653184, + "9:25": 268435456, + "10:25": 402653184, + "11:25": 268435456, + "12:25": 402653184, + "13:25": 268435456, + "14:25": 402653184, + "15:25": 268435456, + "16:25": 402653184, + "17:25": 268435456, + "18:25": 402653184, + "19:25": 268435456, + "20:25": 402653184, + "21:25": 268435456, + "22:25": -9288933, + "23:25": -9288933, + "24:25": -9288933, + "25:25": -9288933, + "26:25": -9288933, + "27:25": -9288933, + "28:25": -9288933, + "29:25": -9288933, + "30:25": -9288933, + "31:25": -9288933, + "32:25": -9288933, + "33:25": -9288933, + "34:25": -9288933, + "35:25": -9288933, + "36:25": -9288933, + "37:25": -9288933, + "38:25": -9288933, + "39:25": -9288933, + "40:25": -9288933, + "41:25": -9288933, + "42:25": -9288933, + "43:25": -9288933, + "44:25": -9288933, + "45:25": -9288933, + "46:25": -9288933, + "47:25": -9288933, + "48:25": -9288933, + "49:25": -9288933, + "50:25": -9288933, + "51:25": -9288933, + "52:25": -9288933, + "53:25": -9288933, + "54:25": -9288933, + "55:25": -9288933, + "56:25": -9288933, + "57:25": -9288933, + "58:25": -9288933, + "59:25": -9288933, + "60:25": -9288933, + "61:25": -9288933, + "62:25": 402653184, + "63:25": 268435456, + "64:25": 402653184, + "65:25": 268435456, + "66:25": -16745472, + "67:25": -16745472, + "68:25": -16745472, + "69:25": -16745472, + "70:25": -16745472, + "71:25": -16745472, + "72:25": -16745472, + "73:25": -16745472, + "74:25": -16745472, + "75:25": -16745472, + "76:25": -16745472, + "77:25": -16745472, + "78:25": -16745472, + "79:25": -16745472, + "80:25": -16745472, + "81:25": -16745472, + "82:25": -16745472, + "83:25": -16745472, + "84:25": 402653184, + "85:25": 268435456, + "86:25": 402653184, + "87:25": 268435456, + "88:25": -9288933, + "89:25": -9288933, + "90:25": -9288933, + "91:25": -9288933, + "92:25": -9288933, + "93:25": -9288933, + "94:25": -9288933, + "95:25": -9288933, + "96:25": -9288933, + "97:25": -9288933, + "98:25": -9288933, + "99:25": -9288933, + "100:25": -9288933, + "101:25": -9288933, + "102:25": -9288933, + "103:25": -9288933, + "104:25": -9288933, + "105:25": -9288933, + "106:25": 402653184, + "107:25": 268435456, + "108:25": 402653184, + "109:25": 268435456, + "110:25": 402653184, + "111:25": 268435456, + "112:25": 402653184, + "113:25": 268435456, + "114:25": 402653184, + "115:25": 268435456, + "116:25": 402653184, + "117:25": 268435456, + "118:25": 402653184, + "119:25": 268435456, + "120:25": 402653184, + "121:25": 268435456, + "122:25": 402653184, + "123:25": 268435456, + "124:25": 402653184, + "125:25": 268435456, + "126:25": 402653184, + "127:25": 268435456, + "0:26": 268435456, + "1:26": 402653184, + "2:26": 268435456, + "3:26": 402653184, + "4:26": 268435456, + "5:26": 402653184, + "6:26": 268435456, + "7:26": 402653184, + "8:26": 268435456, + "9:26": 402653184, + "10:26": 268435456, + "11:26": 402653184, + "12:26": 268435456, + "13:26": 402653184, + "14:26": 268435456, + "15:26": 402653184, + "16:26": 268435456, + "17:26": 402653184, + "18:26": 268435456, + "19:26": 402653184, + "20:26": 268435456, + "21:26": 402653184, + "22:26": -9288933, + "23:26": -9288933, + "24:26": -9288933, + "25:26": -9288933, + "26:26": -9288933, + "27:26": -9288933, + "28:26": -9288933, + "29:26": -9288933, + "30:26": -9288933, + "31:26": -9288933, + "32:26": -9288933, + "33:26": -9288933, + "34:26": -9288933, + "35:26": -9288933, + "36:26": -9288933, + "37:26": -9288933, + "38:26": -9288933, + "39:26": -9288933, + "40:26": -9288933, + "41:26": -9288933, + "42:26": -9288933, + "43:26": -9288933, + "44:26": -9288933, + "45:26": -9288933, + "46:26": -9288933, + "47:26": -9288933, + "48:26": -9288933, + "49:26": -9288933, + "50:26": -9288933, + "51:26": -9288933, + "52:26": -9288933, + "53:26": -9288933, + "54:26": -9288933, + "55:26": -9288933, + "56:26": -9288933, + "57:26": -9288933, + "58:26": -9288933, + "59:26": -9288933, + "60:26": -9288933, + "61:26": -9288933, + "62:26": 268435456, + "63:26": 402653184, + "64:26": 268435456, + "65:26": 402653184, + "66:26": -16745472, + "67:26": -16745472, + "68:26": -16745472, + "69:26": -16745472, + "70:26": -16745472, + "71:26": -16745472, + "72:26": -16745472, + "73:26": -16745472, + "74:26": -16745472, + "75:26": -16745472, + "76:26": -16745472, + "77:26": -16745472, + "78:26": -16745472, + "79:26": -16745472, + "80:26": -16745472, + "81:26": -16745472, + "82:26": -16745472, + "83:26": -16745472, + "84:26": 268435456, + "85:26": 402653184, + "86:26": 268435456, + "87:26": 402653184, + "88:26": -9288933, + "89:26": -9288933, + "90:26": -9288933, + "91:26": -9288933, + "92:26": -9288933, + "93:26": -9288933, + "94:26": -9288933, + "95:26": -9288933, + "96:26": -9288933, + "97:26": -9288933, + "98:26": -9288933, + "99:26": -9288933, + "100:26": -9288933, + "101:26": -9288933, + "102:26": -9288933, + "103:26": -9288933, + "104:26": -9288933, + "105:26": -9288933, + "106:26": 268435456, + "107:26": 402653184, + "108:26": 268435456, + "109:26": 402653184, + "110:26": 268435456, + "111:26": 402653184, + "112:26": 268435456, + "113:26": 402653184, + "114:26": 268435456, + "115:26": 402653184, + "116:26": 268435456, + "117:26": 402653184, + "118:26": 268435456, + "119:26": 402653184, + "120:26": 268435456, + "121:26": 402653184, + "122:26": 268435456, + "123:26": 402653184, + "124:26": 268435456, + "125:26": 402653184, + "126:26": 268435456, + "127:26": 402653184, + "0:27": 402653184, + "1:27": 268435456, + "2:27": 402653184, + "3:27": 268435456, + "4:27": 402653184, + "5:27": 268435456, + "6:27": 402653184, + "7:27": 268435456, + "8:27": 402653184, + "9:27": 268435456, + "10:27": 402653184, + "11:27": 268435456, + "12:27": 402653184, + "13:27": 268435456, + "14:27": 402653184, + "15:27": 268435456, + "16:27": 402653184, + "17:27": 268435456, + "18:27": 402653184, + "19:27": 268435456, + "20:27": 402653184, + "21:27": 268435456, + "22:27": -9288933, + "23:27": -9288933, + "24:27": -9288933, + "25:27": -9288933, + "26:27": -9288933, + "27:27": -9288933, + "28:27": -9288933, + "29:27": -9288933, + "30:27": -9288933, + "31:27": -9288933, + "32:27": -9288933, + "33:27": -9288933, + "34:27": -9288933, + "35:27": -9288933, + "36:27": -9288933, + "37:27": -9288933, + "38:27": -9288933, + "39:27": -9288933, + "40:27": -9288933, + "41:27": -9288933, + "42:27": -9288933, + "43:27": -9288933, + "44:27": -9288933, + "45:27": -9288933, + "46:27": -9288933, + "47:27": -9288933, + "48:27": -9288933, + "49:27": -9288933, + "50:27": -9288933, + "51:27": -9288933, + "52:27": -9288933, + "53:27": -9288933, + "54:27": -9288933, + "55:27": -9288933, + "56:27": -9288933, + "57:27": -9288933, + "58:27": -9288933, + "59:27": -9288933, + "60:27": -9288933, + "61:27": -9288933, + "62:27": 402653184, + "63:27": 268435456, + "64:27": 402653184, + "65:27": 268435456, + "66:27": -16745472, + "67:27": -16745472, + "68:27": -16745472, + "69:27": -16745472, + "70:27": -16745472, + "71:27": -16745472, + "72:27": -16745472, + "73:27": -16745472, + "74:27": -16745472, + "75:27": -16745472, + "76:27": -16745472, + "77:27": -16745472, + "78:27": -16745472, + "79:27": -16745472, + "80:27": -16745472, + "81:27": -16745472, + "82:27": -16745472, + "83:27": -16745472, + "84:27": 402653184, + "85:27": 268435456, + "86:27": 402653184, + "87:27": 268435456, + "88:27": -9288933, + "89:27": -9288933, + "90:27": -9288933, + "91:27": -9288933, + "92:27": -9288933, + "93:27": -9288933, + "94:27": -9288933, + "95:27": -9288933, + "96:27": -9288933, + "97:27": -9288933, + "98:27": -9288933, + "99:27": -9288933, + "100:27": -9288933, + "101:27": -9288933, + "102:27": -9288933, + "103:27": -9288933, + "104:27": -9288933, + "105:27": -9288933, + "106:27": 402653184, + "107:27": 268435456, + "108:27": 402653184, + "109:27": 268435456, + "110:27": 402653184, + "111:27": 268435456, + "112:27": 402653184, + "113:27": 268435456, + "114:27": 402653184, + "115:27": 268435456, + "116:27": 402653184, + "117:27": 268435456, + "118:27": 402653184, + "119:27": 268435456, + "120:27": 402653184, + "121:27": 268435456, + "122:27": 402653184, + "123:27": 268435456, + "124:27": 402653184, + "125:27": 268435456, + "126:27": 402653184, + "127:27": 268435456, + "0:28": 268435456, + "1:28": 402653184, + "2:28": 268435456, + "3:28": 402653184, + "4:28": 268435456, + "5:28": 402653184, + "6:28": 268435456, + "7:28": 402653184, + "8:28": 268435456, + "9:28": 402653184, + "10:28": 268435456, + "11:28": 402653184, + "12:28": 268435456, + "13:28": 402653184, + "14:28": 268435456, + "15:28": 402653184, + "16:28": 268435456, + "17:28": 402653184, + "18:28": 268435456, + "19:28": 402653184, + "20:28": 268435456, + "21:28": 402653184, + "22:28": -9288933, + "23:28": -9288933, + "24:28": -9288933, + "25:28": -9288933, + "26:28": -9288933, + "27:28": -9288933, + "28:28": -9288933, + "29:28": -9288933, + "30:28": -9288933, + "31:28": -9288933, + "32:28": -9288933, + "33:28": -9288933, + "34:28": -9288933, + "35:28": -9288933, + "36:28": -9288933, + "37:28": -9288933, + "38:28": -9288933, + "39:28": -9288933, + "40:28": -9288933, + "41:28": -9288933, + "42:28": -9288933, + "43:28": -9288933, + "44:28": -9288933, + "45:28": -9288933, + "46:28": -9288933, + "47:28": -9288933, + "48:28": -9288933, + "49:28": -9288933, + "50:28": -9288933, + "51:28": -9288933, + "52:28": -9288933, + "53:28": -9288933, + "54:28": -9288933, + "55:28": -9288933, + "56:28": -9288933, + "57:28": -9288933, + "58:28": -9288933, + "59:28": -9288933, + "60:28": -9288933, + "61:28": -9288933, + "62:28": 268435456, + "63:28": 402653184, + "64:28": 268435456, + "65:28": 402653184, + "66:28": -16745472, + "67:28": -16745472, + "68:28": -16745472, + "69:28": -16745472, + "70:28": -16745472, + "71:28": -16745472, + "72:28": -16745472, + "73:28": -16745472, + "74:28": -16745472, + "75:28": -16745472, + "76:28": -16745472, + "77:28": -16745472, + "78:28": -16745472, + "79:28": -16745472, + "80:28": -16745472, + "81:28": -16745472, + "82:28": -16745472, + "83:28": -16745472, + "84:28": 268435456, + "85:28": 402653184, + "86:28": 268435456, + "87:28": 402653184, + "88:28": -9288933, + "89:28": -9288933, + "90:28": -9288933, + "91:28": -9288933, + "92:28": -9288933, + "93:28": -9288933, + "94:28": -9288933, + "95:28": -9288933, + "96:28": -9288933, + "97:28": -9288933, + "98:28": -9288933, + "99:28": -9288933, + "100:28": -9288933, + "101:28": -9288933, + "102:28": -9288933, + "103:28": -9288933, + "104:28": -9288933, + "105:28": -9288933, + "106:28": 268435456, + "107:28": 402653184, + "108:28": 268435456, + "109:28": 402653184, + "110:28": 268435456, + "111:28": 402653184, + "112:28": 268435456, + "113:28": 402653184, + "114:28": 268435456, + "115:28": 402653184, + "116:28": 268435456, + "117:28": 402653184, + "118:28": 268435456, + "119:28": 402653184, + "120:28": 268435456, + "121:28": 402653184, + "122:28": 268435456, + "123:28": 402653184, + "124:28": 268435456, + "125:28": 402653184, + "126:28": 268435456, + "127:28": 402653184, + "0:29": 402653184, + "1:29": 268435456, + "2:29": 402653184, + "3:29": 268435456, + "4:29": 402653184, + "5:29": 268435456, + "6:29": 402653184, + "7:29": 268435456, + "8:29": 402653184, + "9:29": 268435456, + "10:29": 402653184, + "11:29": 268435456, + "12:29": 402653184, + "13:29": 268435456, + "14:29": 402653184, + "15:29": 268435456, + "16:29": 402653184, + "17:29": 268435456, + "18:29": 402653184, + "19:29": 268435456, + "20:29": 402653184, + "21:29": 268435456, + "22:29": -9288933, + "23:29": -9288933, + "24:29": -9288933, + "25:29": -9288933, + "26:29": -9288933, + "27:29": -9288933, + "28:29": -9288933, + "29:29": -9288933, + "30:29": -9288933, + "31:29": -9288933, + "32:29": -9288933, + "33:29": -9288933, + "34:29": -9288933, + "35:29": -9288933, + "36:29": -9288933, + "37:29": -9288933, + "38:29": -9288933, + "39:29": -9288933, + "40:29": -9288933, + "41:29": -9288933, + "42:29": -9288933, + "43:29": -9288933, + "44:29": -9288933, + "45:29": -9288933, + "46:29": -9288933, + "47:29": -9288933, + "48:29": -9288933, + "49:29": -9288933, + "50:29": -9288933, + "51:29": -9288933, + "52:29": -9288933, + "53:29": -9288933, + "54:29": -9288933, + "55:29": -9288933, + "56:29": -9288933, + "57:29": -9288933, + "58:29": -9288933, + "59:29": -9288933, + "60:29": -9288933, + "61:29": -9288933, + "62:29": 402653184, + "63:29": 268435456, + "64:29": 402653184, + "65:29": 268435456, + "66:29": 402653184, + "67:29": 268435456, + "68:29": 402653184, + "69:29": 268435456, + "70:29": 402653184, + "71:29": 268435456, + "72:29": 402653184, + "73:29": 268435456, + "74:29": 402653184, + "75:29": 268435456, + "76:29": 402653184, + "77:29": 268435456, + "78:29": 402653184, + "79:29": 268435456, + "80:29": 402653184, + "81:29": 268435456, + "82:29": 402653184, + "83:29": 268435456, + "84:29": 402653184, + "85:29": 268435456, + "86:29": 402653184, + "87:29": 268435456, + "88:29": -9288933, + "89:29": -9288933, + "90:29": -9288933, + "91:29": -9288933, + "92:29": -9288933, + "93:29": -9288933, + "94:29": -9288933, + "95:29": -9288933, + "96:29": -9288933, + "97:29": -9288933, + "98:29": -9288933, + "99:29": -9288933, + "100:29": -9288933, + "101:29": -9288933, + "102:29": -9288933, + "103:29": -9288933, + "104:29": -9288933, + "105:29": -9288933, + "106:29": 402653184, + "107:29": 268435456, + "108:29": 402653184, + "109:29": 268435456, + "110:29": 402653184, + "111:29": 268435456, + "112:29": 402653184, + "113:29": 268435456, + "114:29": 402653184, + "115:29": 268435456, + "116:29": 402653184, + "117:29": 268435456, + "118:29": 402653184, + "119:29": 268435456, + "120:29": 402653184, + "121:29": 268435456, + "122:29": 402653184, + "123:29": 268435456, + "124:29": 402653184, + "125:29": 268435456, + "126:29": 402653184, + "127:29": 268435456, + "0:30": 268435456, + "1:30": 402653184, + "2:30": 268435456, + "3:30": 402653184, + "4:30": 268435456, + "5:30": 402653184, + "6:30": 268435456, + "7:30": 402653184, + "8:30": 268435456, + "9:30": 402653184, + "10:30": 268435456, + "11:30": 402653184, + "12:30": 268435456, + "13:30": 402653184, + "14:30": 268435456, + "15:30": 402653184, + "16:30": 268435456, + "17:30": 402653184, + "18:30": 268435456, + "19:30": 402653184, + "20:30": 268435456, + "21:30": 402653184, + "22:30": -9288933, + "23:30": -9288933, + "24:30": -9288933, + "25:30": -9288933, + "26:30": -9288933, + "27:30": -9288933, + "28:30": -9288933, + "29:30": -9288933, + "30:30": -9288933, + "31:30": -9288933, + "32:30": -9288933, + "33:30": -9288933, + "34:30": -9288933, + "35:30": -9288933, + "36:30": -9288933, + "37:30": -9288933, + "38:30": -9288933, + "39:30": -9288933, + "40:30": -9288933, + "41:30": -9288933, + "42:30": -9288933, + "43:30": -9288933, + "44:30": -9288933, + "45:30": -9288933, + "46:30": -9288933, + "47:30": -9288933, + "48:30": -9288933, + "49:30": -9288933, + "50:30": -9288933, + "51:30": -9288933, + "52:30": -9288933, + "53:30": -9288933, + "54:30": -9288933, + "55:30": -9288933, + "56:30": -9288933, + "57:30": -9288933, + "58:30": -9288933, + "59:30": -9288933, + "60:30": -9288933, + "61:30": -9288933, + "62:30": 268435456, + "63:30": 402653184, + "64:30": 268435456, + "65:30": 402653184, + "66:30": 268435456, + "67:30": 402653184, + "68:30": 268435456, + "69:30": 402653184, + "70:30": 268435456, + "71:30": 402653184, + "72:30": 268435456, + "73:30": 402653184, + "74:30": 268435456, + "75:30": 402653184, + "76:30": 268435456, + "77:30": 402653184, + "78:30": 268435456, + "79:30": 402653184, + "80:30": 268435456, + "81:30": 402653184, + "82:30": 268435456, + "83:30": 402653184, + "84:30": 268435456, + "85:30": 402653184, + "86:30": 268435456, + "87:30": 402653184, + "88:30": -9288933, + "89:30": -9288933, + "90:30": -9288933, + "91:30": -9288933, + "92:30": -9288933, + "93:30": -9288933, + "94:30": -9288933, + "95:30": -9288933, + "96:30": -9288933, + "97:30": -9288933, + "98:30": -9288933, + "99:30": -9288933, + "100:30": -9288933, + "101:30": -9288933, + "102:30": -9288933, + "103:30": -9288933, + "104:30": -9288933, + "105:30": -9288933, + "106:30": 268435456, + "107:30": 402653184, + "108:30": 268435456, + "109:30": 402653184, + "110:30": 268435456, + "111:30": 402653184, + "112:30": 268435456, + "113:30": 402653184, + "114:30": 268435456, + "115:30": 402653184, + "116:30": 268435456, + "117:30": 402653184, + "118:30": 268435456, + "119:30": 402653184, + "120:30": 268435456, + "121:30": 402653184, + "122:30": 268435456, + "123:30": 402653184, + "124:30": 268435456, + "125:30": 402653184, + "126:30": 268435456, + "127:30": 402653184, + "0:31": 402653184, + "1:31": 268435456, + "2:31": 402653184, + "3:31": 268435456, + "4:31": 402653184, + "5:31": 268435456, + "6:31": 402653184, + "7:31": 268435456, + "8:31": 402653184, + "9:31": 268435456, + "10:31": 402653184, + "11:31": 268435456, + "12:31": 402653184, + "13:31": 268435456, + "14:31": 402653184, + "15:31": 268435456, + "16:31": 402653184, + "17:31": 268435456, + "18:31": 402653184, + "19:31": 268435456, + "20:31": 402653184, + "21:31": 268435456, + "22:31": -9288933, + "23:31": -9288933, + "24:31": -9288933, + "25:31": -9288933, + "26:31": -9288933, + "27:31": -9288933, + "28:31": -9288933, + "29:31": -9288933, + "30:31": -9288933, + "31:31": -9288933, + "32:31": -9288933, + "33:31": -9288933, + "34:31": -9288933, + "35:31": -9288933, + "36:31": -9288933, + "37:31": -9288933, + "38:31": -9288933, + "39:31": -9288933, + "40:31": -9288933, + "41:31": -9288933, + "42:31": -9288933, + "43:31": -9288933, + "44:31": -9288933, + "45:31": -9288933, + "46:31": -9288933, + "47:31": -9288933, + "48:31": -9288933, + "49:31": -9288933, + "50:31": -9288933, + "51:31": -9288933, + "52:31": -9288933, + "53:31": -9288933, + "54:31": -9288933, + "55:31": -9288933, + "56:31": -9288933, + "57:31": -9288933, + "58:31": -9288933, + "59:31": -9288933, + "60:31": -9288933, + "61:31": -9288933, + "62:31": 402653184, + "63:31": 268435456, + "64:31": 402653184, + "65:31": 268435456, + "66:31": 402653184, + "67:31": 268435456, + "68:31": 402653184, + "69:31": 268435456, + "70:31": 402653184, + "71:31": 268435456, + "72:31": 402653184, + "73:31": 268435456, + "74:31": 402653184, + "75:31": 268435456, + "76:31": 402653184, + "77:31": 268435456, + "78:31": 402653184, + "79:31": 268435456, + "80:31": 402653184, + "81:31": 268435456, + "82:31": 402653184, + "83:31": 268435456, + "84:31": 402653184, + "85:31": 268435456, + "86:31": 402653184, + "87:31": 268435456, + "88:31": -9288933, + "89:31": -9288933, + "90:31": -9288933, + "91:31": -9288933, + "92:31": -9288933, + "93:31": -9288933, + "94:31": -9288933, + "95:31": -9288933, + "96:31": -9288933, + "97:31": -9288933, + "98:31": -9288933, + "99:31": -9288933, + "100:31": -9288933, + "101:31": -9288933, + "102:31": -9288933, + "103:31": -9288933, + "104:31": -9288933, + "105:31": -9288933, + "106:31": 402653184, + "107:31": 268435456, + "108:31": 402653184, + "109:31": 268435456, + "110:31": 402653184, + "111:31": 268435456, + "112:31": 402653184, + "113:31": 268435456, + "114:31": 402653184, + "115:31": 268435456, + "116:31": 402653184, + "117:31": 268435456, + "118:31": 402653184, + "119:31": 268435456, + "120:31": 402653184, + "121:31": 268435456, + "122:31": 402653184, + "123:31": 268435456, + "124:31": 402653184, + "125:31": 268435456, + "126:31": 402653184, + "127:31": 268435456, + "0:32": 268435456, + "1:32": 402653184, + "2:32": 268435456, + "3:32": 402653184, + "4:32": 268435456, + "5:32": 402653184, + "6:32": 268435456, + "7:32": 402653184, + "8:32": 268435456, + "9:32": 402653184, + "10:32": 268435456, + "11:32": 402653184, + "12:32": 268435456, + "13:32": 402653184, + "14:32": 268435456, + "15:32": 402653184, + "16:32": 268435456, + "17:32": 402653184, + "18:32": 268435456, + "19:32": 402653184, + "20:32": 268435456, + "21:32": 402653184, + "22:32": -9288933, + "23:32": -9288933, + "24:32": -9288933, + "25:32": -9288933, + "26:32": -9288933, + "27:32": -9288933, + "28:32": -9288933, + "29:32": -9288933, + "30:32": -9288933, + "31:32": -9288933, + "32:32": -9288933, + "33:32": -9288933, + "34:32": -9288933, + "35:32": -9288933, + "36:32": -9288933, + "37:32": -9288933, + "38:32": -9288933, + "39:32": -9288933, + "40:32": -9288933, + "41:32": -9288933, + "42:32": -9288933, + "43:32": -9288933, + "44:32": -9288933, + "45:32": -9288933, + "46:32": -9288933, + "47:32": -9288933, + "48:32": -9288933, + "49:32": -9288933, + "50:32": -9288933, + "51:32": -9288933, + "52:32": -9288933, + "53:32": -9288933, + "54:32": -9288933, + "55:32": -9288933, + "56:32": -9288933, + "57:32": -9288933, + "58:32": -9288933, + "59:32": -9288933, + "60:32": -9288933, + "61:32": -9288933, + "62:32": 268435456, + "63:32": 402653184, + "64:32": 268435456, + "65:32": 402653184, + "66:32": 268435456, + "67:32": 402653184, + "68:32": 268435456, + "69:32": 402653184, + "70:32": 268435456, + "71:32": 402653184, + "72:32": 268435456, + "73:32": 402653184, + "74:32": 268435456, + "75:32": 402653184, + "76:32": 268435456, + "77:32": 402653184, + "78:32": 268435456, + "79:32": 402653184, + "80:32": 268435456, + "81:32": 402653184, + "82:32": 268435456, + "83:32": 402653184, + "84:32": 268435456, + "85:32": 402653184, + "86:32": 268435456, + "87:32": 402653184, + "88:32": -9288933, + "89:32": -9288933, + "90:32": -9288933, + "91:32": -9288933, + "92:32": -9288933, + "93:32": -9288933, + "94:32": -9288933, + "95:32": -9288933, + "96:32": -9288933, + "97:32": -9288933, + "98:32": -9288933, + "99:32": -9288933, + "100:32": -9288933, + "101:32": -9288933, + "102:32": -9288933, + "103:32": -9288933, + "104:32": -9288933, + "105:32": -9288933, + "106:32": 268435456, + "107:32": 402653184, + "108:32": 268435456, + "109:32": 402653184, + "110:32": 268435456, + "111:32": 402653184, + "112:32": 268435456, + "113:32": 402653184, + "114:32": 268435456, + "115:32": 402653184, + "116:32": 268435456, + "117:32": 402653184, + "118:32": 268435456, + "119:32": 402653184, + "120:32": 268435456, + "121:32": 402653184, + "122:32": 268435456, + "123:32": 402653184, + "124:32": 268435456, + "125:32": 402653184, + "126:32": 268435456, + "127:32": 402653184, + "0:33": 402653184, + "1:33": 268435456, + "2:33": 402653184, + "3:33": 268435456, + "4:33": 402653184, + "5:33": 268435456, + "6:33": 402653184, + "7:33": 268435456, + "8:33": 402653184, + "9:33": 268435456, + "10:33": 402653184, + "11:33": 268435456, + "12:33": 402653184, + "13:33": 268435456, + "14:33": 402653184, + "15:33": 268435456, + "16:33": 402653184, + "17:33": 268435456, + "18:33": 402653184, + "19:33": 268435456, + "20:33": 402653184, + "21:33": 268435456, + "22:33": -9288933, + "23:33": -9288933, + "24:33": -9288933, + "25:33": -9288933, + "26:33": -9288933, + "27:33": -9288933, + "28:33": -9288933, + "29:33": -9288933, + "30:33": -9288933, + "31:33": -9288933, + "32:33": -9288933, + "33:33": -9288933, + "34:33": -9288933, + "35:33": -9288933, + "36:33": -9288933, + "37:33": -9288933, + "38:33": -9288933, + "39:33": -9288933, + "40:33": -9288933, + "41:33": -9288933, + "42:33": -9288933, + "43:33": -9288933, + "44:33": -9288933, + "45:33": -9288933, + "46:33": -9288933, + "47:33": -9288933, + "48:33": -9288933, + "49:33": -9288933, + "50:33": -9288933, + "51:33": -9288933, + "52:33": -9288933, + "53:33": -9288933, + "54:33": -9288933, + "55:33": -9288933, + "56:33": -9288933, + "57:33": -9288933, + "58:33": -9288933, + "59:33": -9288933, + "60:33": -9288933, + "61:33": -9288933, + "62:33": 402653184, + "63:33": 268435456, + "64:33": 402653184, + "65:33": 268435456, + "66:33": -9288933, + "67:33": -9288933, + "68:33": -9288933, + "69:33": -9288933, + "70:33": -9288933, + "71:33": -9288933, + "72:33": -9288933, + "73:33": -9288933, + "74:33": -9288933, + "75:33": -9288933, + "76:33": -9288933, + "77:33": -9288933, + "78:33": -9288933, + "79:33": -9288933, + "80:33": -9288933, + "81:33": -9288933, + "82:33": -9288933, + "83:33": -9288933, + "84:33": 402653184, + "85:33": 268435456, + "86:33": 402653184, + "87:33": 268435456, + "88:33": -9288933, + "89:33": -9288933, + "90:33": -9288933, + "91:33": -9288933, + "92:33": -9288933, + "93:33": -9288933, + "94:33": -9288933, + "95:33": -9288933, + "96:33": -9288933, + "97:33": -9288933, + "98:33": -9288933, + "99:33": -9288933, + "100:33": -9288933, + "101:33": -9288933, + "102:33": -9288933, + "103:33": -9288933, + "104:33": -9288933, + "105:33": -9288933, + "106:33": 402653184, + "107:33": 268435456, + "108:33": 402653184, + "109:33": 268435456, + "110:33": 402653184, + "111:33": 268435456, + "112:33": 402653184, + "113:33": 268435456, + "114:33": 402653184, + "115:33": 268435456, + "116:33": 402653184, + "117:33": 268435456, + "118:33": 402653184, + "119:33": 268435456, + "120:33": 402653184, + "121:33": 268435456, + "122:33": 402653184, + "123:33": 268435456, + "124:33": 402653184, + "125:33": 268435456, + "126:33": 402653184, + "127:33": 268435456, + "0:34": 268435456, + "1:34": 402653184, + "2:34": 268435456, + "3:34": 402653184, + "4:34": 268435456, + "5:34": 402653184, + "6:34": 268435456, + "7:34": 402653184, + "8:34": 268435456, + "9:34": 402653184, + "10:34": 268435456, + "11:34": 402653184, + "12:34": 268435456, + "13:34": 402653184, + "14:34": 268435456, + "15:34": 402653184, + "16:34": 268435456, + "17:34": 402653184, + "18:34": 268435456, + "19:34": 402653184, + "20:34": 268435456, + "21:34": 402653184, + "22:34": -9288933, + "23:34": -9288933, + "24:34": -9288933, + "25:34": -9288933, + "26:34": -9288933, + "27:34": -9288933, + "28:34": -9288933, + "29:34": -9288933, + "30:34": -9288933, + "31:34": -9288933, + "32:34": -9288933, + "33:34": -9288933, + "34:34": -9288933, + "35:34": -9288933, + "36:34": -9288933, + "37:34": -9288933, + "38:34": -9288933, + "39:34": -9288933, + "40:34": -9288933, + "41:34": -9288933, + "42:34": -9288933, + "43:34": -9288933, + "44:34": -9288933, + "45:34": -9288933, + "46:34": -9288933, + "47:34": -9288933, + "48:34": -9288933, + "49:34": -9288933, + "50:34": -9288933, + "51:34": -9288933, + "52:34": -9288933, + "53:34": -9288933, + "54:34": -9288933, + "55:34": -9288933, + "56:34": -9288933, + "57:34": -9288933, + "58:34": -9288933, + "59:34": -9288933, + "60:34": -9288933, + "61:34": -9288933, + "62:34": 268435456, + "63:34": 402653184, + "64:34": 268435456, + "65:34": 402653184, + "66:34": -9288933, + "67:34": -9288933, + "68:34": -9288933, + "69:34": -9288933, + "70:34": -9288933, + "71:34": -9288933, + "72:34": -9288933, + "73:34": -9288933, + "74:34": -9288933, + "75:34": -9288933, + "76:34": -9288933, + "77:34": -9288933, + "78:34": -9288933, + "79:34": -9288933, + "80:34": -9288933, + "81:34": -9288933, + "82:34": -9288933, + "83:34": -9288933, + "84:34": 268435456, + "85:34": 402653184, + "86:34": 268435456, + "87:34": 402653184, + "88:34": -9288933, + "89:34": -9288933, + "90:34": -9288933, + "91:34": -9288933, + "92:34": -9288933, + "93:34": -9288933, + "94:34": -9288933, + "95:34": -9288933, + "96:34": -9288933, + "97:34": -9288933, + "98:34": -9288933, + "99:34": -9288933, + "100:34": -9288933, + "101:34": -9288933, + "102:34": -9288933, + "103:34": -9288933, + "104:34": -9288933, + "105:34": -9288933, + "106:34": 268435456, + "107:34": 402653184, + "108:34": 268435456, + "109:34": 402653184, + "110:34": 268435456, + "111:34": 402653184, + "112:34": 268435456, + "113:34": 402653184, + "114:34": 268435456, + "115:34": 402653184, + "116:34": 268435456, + "117:34": 402653184, + "118:34": 268435456, + "119:34": 402653184, + "120:34": 268435456, + "121:34": 402653184, + "122:34": 268435456, + "123:34": 402653184, + "124:34": 268435456, + "125:34": 402653184, + "126:34": 268435456, + "127:34": 402653184, + "0:35": 402653184, + "1:35": 268435456, + "2:35": 402653184, + "3:35": 268435456, + "4:35": 402653184, + "5:35": 268435456, + "6:35": 402653184, + "7:35": 268435456, + "8:35": 402653184, + "9:35": 268435456, + "10:35": 402653184, + "11:35": 268435456, + "12:35": 402653184, + "13:35": 268435456, + "14:35": 402653184, + "15:35": 268435456, + "16:35": 402653184, + "17:35": 268435456, + "18:35": 402653184, + "19:35": 268435456, + "20:35": 402653184, + "21:35": 268435456, + "22:35": -9288933, + "23:35": -9288933, + "24:35": -9288933, + "25:35": -9288933, + "26:35": -9288933, + "27:35": -9288933, + "28:35": -9288933, + "29:35": -9288933, + "30:35": -9288933, + "31:35": -9288933, + "32:35": -9288933, + "33:35": -9288933, + "34:35": -9288933, + "35:35": -9288933, + "36:35": -9288933, + "37:35": -9288933, + "38:35": -9288933, + "39:35": -9288933, + "40:35": -9288933, + "41:35": -9288933, + "42:35": -9288933, + "43:35": -9288933, + "44:35": -9288933, + "45:35": -9288933, + "46:35": -9288933, + "47:35": -9288933, + "48:35": -9288933, + "49:35": -9288933, + "50:35": -9288933, + "51:35": -9288933, + "52:35": -9288933, + "53:35": -9288933, + "54:35": -9288933, + "55:35": -9288933, + "56:35": -9288933, + "57:35": -9288933, + "58:35": -9288933, + "59:35": -9288933, + "60:35": -9288933, + "61:35": -9288933, + "62:35": 402653184, + "63:35": 268435456, + "64:35": 402653184, + "65:35": 268435456, + "66:35": -9288933, + "67:35": -9288933, + "68:35": -9288933, + "69:35": -9288933, + "70:35": -9288933, + "71:35": -9288933, + "72:35": -9288933, + "73:35": -9288933, + "74:35": -9288933, + "75:35": -9288933, + "76:35": -9288933, + "77:35": -9288933, + "78:35": -9288933, + "79:35": -9288933, + "80:35": -9288933, + "81:35": -9288933, + "82:35": -9288933, + "83:35": -9288933, + "84:35": 402653184, + "85:35": 268435456, + "86:35": 402653184, + "87:35": 268435456, + "88:35": -9288933, + "89:35": -9288933, + "90:35": -9288933, + "91:35": -9288933, + "92:35": -9288933, + "93:35": -9288933, + "94:35": -9288933, + "95:35": -9288933, + "96:35": -9288933, + "97:35": -9288933, + "98:35": -9288933, + "99:35": -9288933, + "100:35": -9288933, + "101:35": -9288933, + "102:35": -9288933, + "103:35": -9288933, + "104:35": -9288933, + "105:35": -9288933, + "106:35": 402653184, + "107:35": 268435456, + "108:35": 402653184, + "109:35": 268435456, + "110:35": 402653184, + "111:35": 268435456, + "112:35": 402653184, + "113:35": 268435456, + "114:35": 402653184, + "115:35": 268435456, + "116:35": 402653184, + "117:35": 268435456, + "118:35": 402653184, + "119:35": 268435456, + "120:35": 402653184, + "121:35": 268435456, + "122:35": 402653184, + "123:35": 268435456, + "124:35": 402653184, + "125:35": 268435456, + "126:35": 402653184, + "127:35": 268435456, + "0:36": 268435456, + "1:36": 402653184, + "2:36": 268435456, + "3:36": 402653184, + "4:36": 268435456, + "5:36": 402653184, + "6:36": 268435456, + "7:36": 402653184, + "8:36": 268435456, + "9:36": 402653184, + "10:36": 268435456, + "11:36": 402653184, + "12:36": 268435456, + "13:36": 402653184, + "14:36": 268435456, + "15:36": 402653184, + "16:36": 268435456, + "17:36": 402653184, + "18:36": 268435456, + "19:36": 402653184, + "20:36": 268435456, + "21:36": 402653184, + "22:36": -9288933, + "23:36": -9288933, + "24:36": -9288933, + "25:36": -9288933, + "26:36": -9288933, + "27:36": -9288933, + "28:36": -9288933, + "29:36": -9288933, + "30:36": -9288933, + "31:36": -9288933, + "32:36": -9288933, + "33:36": -9288933, + "34:36": -9288933, + "35:36": -9288933, + "36:36": -9288933, + "37:36": -9288933, + "38:36": -9288933, + "39:36": -9288933, + "40:36": -9288933, + "41:36": -9288933, + "42:36": -9288933, + "43:36": -9288933, + "44:36": -9288933, + "45:36": -9288933, + "46:36": -9288933, + "47:36": -9288933, + "48:36": -9288933, + "49:36": -9288933, + "50:36": -9288933, + "51:36": -9288933, + "52:36": -9288933, + "53:36": -9288933, + "54:36": -9288933, + "55:36": -9288933, + "56:36": -9288933, + "57:36": -9288933, + "58:36": -9288933, + "59:36": -9288933, + "60:36": -9288933, + "61:36": -9288933, + "62:36": 268435456, + "63:36": 402653184, + "64:36": 268435456, + "65:36": 402653184, + "66:36": -9288933, + "67:36": -9288933, + "68:36": -9288933, + "69:36": -9288933, + "70:36": -9288933, + "71:36": -9288933, + "72:36": -9288933, + "73:36": -9288933, + "74:36": -9288933, + "75:36": -9288933, + "76:36": -9288933, + "77:36": -9288933, + "78:36": -9288933, + "79:36": -9288933, + "80:36": -9288933, + "81:36": -9288933, + "82:36": -9288933, + "83:36": -9288933, + "84:36": 268435456, + "85:36": 402653184, + "86:36": 268435456, + "87:36": 402653184, + "88:36": -9288933, + "89:36": -9288933, + "90:36": -9288933, + "91:36": -9288933, + "92:36": -9288933, + "93:36": -9288933, + "94:36": -9288933, + "95:36": -9288933, + "96:36": -9288933, + "97:36": -9288933, + "98:36": -9288933, + "99:36": -9288933, + "100:36": -9288933, + "101:36": -9288933, + "102:36": -9288933, + "103:36": -9288933, + "104:36": -9288933, + "105:36": -9288933, + "106:36": 268435456, + "107:36": 402653184, + "108:36": 268435456, + "109:36": 402653184, + "110:36": 268435456, + "111:36": 402653184, + "112:36": 268435456, + "113:36": 402653184, + "114:36": 268435456, + "115:36": 402653184, + "116:36": 268435456, + "117:36": 402653184, + "118:36": 268435456, + "119:36": 402653184, + "120:36": 268435456, + "121:36": 402653184, + "122:36": 268435456, + "123:36": 402653184, + "124:36": 268435456, + "125:36": 402653184, + "126:36": 268435456, + "127:36": 402653184, + "0:37": 402653184, + "1:37": 268435456, + "2:37": 402653184, + "3:37": 268435456, + "4:37": 402653184, + "5:37": 268435456, + "6:37": 402653184, + "7:37": 268435456, + "8:37": 402653184, + "9:37": 268435456, + "10:37": 402653184, + "11:37": 268435456, + "12:37": 402653184, + "13:37": 268435456, + "14:37": 402653184, + "15:37": 268435456, + "16:37": 402653184, + "17:37": 268435456, + "18:37": 402653184, + "19:37": 268435456, + "20:37": 402653184, + "21:37": 268435456, + "22:37": -9288933, + "23:37": -9288933, + "24:37": -9288933, + "25:37": -9288933, + "26:37": -9288933, + "27:37": -9288933, + "28:37": -9288933, + "29:37": -9288933, + "30:37": -9288933, + "31:37": -9288933, + "32:37": -9288933, + "33:37": -9288933, + "34:37": -9288933, + "35:37": -9288933, + "36:37": -9288933, + "37:37": -9288933, + "38:37": -9288933, + "39:37": -9288933, + "40:37": -9288933, + "41:37": -9288933, + "42:37": -9288933, + "43:37": -9288933, + "44:37": -9288933, + "45:37": -9288933, + "46:37": -9288933, + "47:37": -9288933, + "48:37": -9288933, + "49:37": -9288933, + "50:37": -9288933, + "51:37": -9288933, + "52:37": -9288933, + "53:37": -9288933, + "54:37": -9288933, + "55:37": -9288933, + "56:37": -9288933, + "57:37": -9288933, + "58:37": -9288933, + "59:37": -9288933, + "60:37": -9288933, + "61:37": -9288933, + "62:37": 402653184, + "63:37": 268435456, + "64:37": 402653184, + "65:37": 268435456, + "66:37": -9288933, + "67:37": -9288933, + "68:37": -9288933, + "69:37": -9288933, + "70:37": -9288933, + "71:37": -9288933, + "72:37": -9288933, + "73:37": -9288933, + "74:37": -9288933, + "75:37": -9288933, + "76:37": -9288933, + "77:37": -9288933, + "78:37": -9288933, + "79:37": -9288933, + "80:37": -9288933, + "81:37": -9288933, + "82:37": -9288933, + "83:37": -9288933, + "84:37": 402653184, + "85:37": 268435456, + "86:37": 402653184, + "87:37": 268435456, + "88:37": -9288933, + "89:37": -9288933, + "90:37": -9288933, + "91:37": -9288933, + "92:37": -9288933, + "93:37": -9288933, + "94:37": -9288933, + "95:37": -9288933, + "96:37": -9288933, + "97:37": -9288933, + "98:37": -9288933, + "99:37": -9288933, + "100:37": -9288933, + "101:37": -9288933, + "102:37": -9288933, + "103:37": -9288933, + "104:37": -9288933, + "105:37": -9288933, + "106:37": 402653184, + "107:37": 268435456, + "108:37": 402653184, + "109:37": 268435456, + "110:37": 402653184, + "111:37": 268435456, + "112:37": 402653184, + "113:37": 268435456, + "114:37": 402653184, + "115:37": 268435456, + "116:37": 402653184, + "117:37": 268435456, + "118:37": 402653184, + "119:37": 268435456, + "120:37": 402653184, + "121:37": 268435456, + "122:37": 402653184, + "123:37": 268435456, + "124:37": 402653184, + "125:37": 268435456, + "126:37": 402653184, + "127:37": 268435456, + "0:38": 268435456, + "1:38": 402653184, + "2:38": 268435456, + "3:38": 402653184, + "4:38": 268435456, + "5:38": 402653184, + "6:38": 268435456, + "7:38": 402653184, + "8:38": 268435456, + "9:38": 402653184, + "10:38": 268435456, + "11:38": 402653184, + "12:38": 268435456, + "13:38": 402653184, + "14:38": 268435456, + "15:38": 402653184, + "16:38": 268435456, + "17:38": 402653184, + "18:38": 268435456, + "19:38": 402653184, + "20:38": 268435456, + "21:38": 402653184, + "22:38": -9288933, + "23:38": -9288933, + "24:38": -9288933, + "25:38": -9288933, + "26:38": -9288933, + "27:38": -9288933, + "28:38": -9288933, + "29:38": -9288933, + "30:38": -9288933, + "31:38": -9288933, + "32:38": -9288933, + "33:38": -9288933, + "34:38": -9288933, + "35:38": -9288933, + "36:38": -9288933, + "37:38": -9288933, + "38:38": -9288933, + "39:38": -9288933, + "40:38": -9288933, + "41:38": -9288933, + "42:38": -9288933, + "43:38": -9288933, + "44:38": -9288933, + "45:38": -9288933, + "46:38": -9288933, + "47:38": -9288933, + "48:38": -9288933, + "49:38": -9288933, + "50:38": -9288933, + "51:38": -9288933, + "52:38": -9288933, + "53:38": -9288933, + "54:38": -9288933, + "55:38": -9288933, + "56:38": -9288933, + "57:38": -9288933, + "58:38": -9288933, + "59:38": -9288933, + "60:38": -9288933, + "61:38": -9288933, + "62:38": 268435456, + "63:38": 402653184, + "64:38": 268435456, + "65:38": 402653184, + "66:38": -9288933, + "67:38": -9288933, + "68:38": -9288933, + "69:38": -9288933, + "70:38": -9288933, + "71:38": -9288933, + "72:38": -9288933, + "73:38": -9288933, + "74:38": -9288933, + "75:38": -9288933, + "76:38": -9288933, + "77:38": -9288933, + "78:38": -9288933, + "79:38": -9288933, + "80:38": -9288933, + "81:38": -9288933, + "82:38": -9288933, + "83:38": -9288933, + "84:38": 268435456, + "85:38": 402653184, + "86:38": 268435456, + "87:38": 402653184, + "88:38": -9288933, + "89:38": -9288933, + "90:38": -9288933, + "91:38": -9288933, + "92:38": -9288933, + "93:38": -9288933, + "94:38": -9288933, + "95:38": -9288933, + "96:38": -9288933, + "97:38": -9288933, + "98:38": -9288933, + "99:38": -9288933, + "100:38": -9288933, + "101:38": -9288933, + "102:38": -9288933, + "103:38": -9288933, + "104:38": -9288933, + "105:38": -9288933, + "106:38": 268435456, + "107:38": 402653184, + "108:38": 268435456, + "109:38": 402653184, + "110:38": 268435456, + "111:38": 402653184, + "112:38": 268435456, + "113:38": 402653184, + "114:38": 268435456, + "115:38": 402653184, + "116:38": 268435456, + "117:38": 402653184, + "118:38": 268435456, + "119:38": 402653184, + "120:38": 268435456, + "121:38": 402653184, + "122:38": 268435456, + "123:38": 402653184, + "124:38": 268435456, + "125:38": 402653184, + "126:38": 268435456, + "127:38": 402653184, + "0:39": 402653184, + "1:39": 268435456, + "2:39": 402653184, + "3:39": 268435456, + "4:39": 402653184, + "5:39": 268435456, + "6:39": 402653184, + "7:39": 268435456, + "8:39": 402653184, + "9:39": 268435456, + "10:39": 402653184, + "11:39": 268435456, + "12:39": 402653184, + "13:39": 268435456, + "14:39": 402653184, + "15:39": 268435456, + "16:39": 402653184, + "17:39": 268435456, + "18:39": 402653184, + "19:39": 268435456, + "20:39": 402653184, + "21:39": 268435456, + "22:39": -9288933, + "23:39": -9288933, + "24:39": -9288933, + "25:39": -9288933, + "26:39": -9288933, + "27:39": -9288933, + "28:39": -9288933, + "29:39": -9288933, + "30:39": -9288933, + "31:39": -9288933, + "32:39": -9288933, + "33:39": -9288933, + "34:39": -9288933, + "35:39": -9288933, + "36:39": -9288933, + "37:39": -9288933, + "38:39": -9288933, + "39:39": -9288933, + "40:39": -9288933, + "41:39": -9288933, + "42:39": -9288933, + "43:39": -9288933, + "44:39": -9288933, + "45:39": -9288933, + "46:39": -9288933, + "47:39": -9288933, + "48:39": -9288933, + "49:39": -9288933, + "50:39": -9288933, + "51:39": -9288933, + "52:39": -9288933, + "53:39": -9288933, + "54:39": -9288933, + "55:39": -9288933, + "56:39": -9288933, + "57:39": -9288933, + "58:39": -9288933, + "59:39": -9288933, + "60:39": -9288933, + "61:39": -9288933, + "62:39": 402653184, + "63:39": 268435456, + "64:39": 402653184, + "65:39": 268435456, + "66:39": -9288933, + "67:39": -9288933, + "68:39": -9288933, + "69:39": -9288933, + "70:39": -9288933, + "71:39": -9288933, + "72:39": -9288933, + "73:39": -9288933, + "74:39": -9288933, + "75:39": -9288933, + "76:39": -9288933, + "77:39": -9288933, + "78:39": -9288933, + "79:39": -9288933, + "80:39": -9288933, + "81:39": -9288933, + "82:39": -9288933, + "83:39": -9288933, + "84:39": 402653184, + "85:39": 268435456, + "86:39": 402653184, + "87:39": 268435456, + "88:39": -9288933, + "89:39": -9288933, + "90:39": -9288933, + "91:39": -9288933, + "92:39": -9288933, + "93:39": -9288933, + "94:39": -9288933, + "95:39": -9288933, + "96:39": -9288933, + "97:39": -9288933, + "98:39": -9288933, + "99:39": -9288933, + "100:39": -9288933, + "101:39": -9288933, + "102:39": -9288933, + "103:39": -9288933, + "104:39": -9288933, + "105:39": -9288933, + "106:39": 402653184, + "107:39": 268435456, + "108:39": 402653184, + "109:39": 268435456, + "110:39": 402653184, + "111:39": 268435456, + "112:39": 402653184, + "113:39": 268435456, + "114:39": 402653184, + "115:39": 268435456, + "116:39": 402653184, + "117:39": 268435456, + "118:39": 402653184, + "119:39": 268435456, + "120:39": 402653184, + "121:39": 268435456, + "122:39": 402653184, + "123:39": 268435456, + "124:39": 402653184, + "125:39": 268435456, + "126:39": 402653184, + "127:39": 268435456, + "0:40": 268435456, + "1:40": 402653184, + "2:40": 268435456, + "3:40": 402653184, + "4:40": 268435456, + "5:40": 402653184, + "6:40": 268435456, + "7:40": 402653184, + "8:40": 268435456, + "9:40": 402653184, + "10:40": 268435456, + "11:40": 402653184, + "12:40": 268435456, + "13:40": 402653184, + "14:40": 268435456, + "15:40": 402653184, + "16:40": 268435456, + "17:40": 402653184, + "18:40": 268435456, + "19:40": 402653184, + "20:40": 268435456, + "21:40": 402653184, + "22:40": -9288933, + "23:40": -9288933, + "24:40": -9288933, + "25:40": -9288933, + "26:40": -9288933, + "27:40": -9288933, + "28:40": -9288933, + "29:40": -9288933, + "30:40": -9288933, + "31:40": -9288933, + "32:40": -9288933, + "33:40": -9288933, + "34:40": -9288933, + "35:40": -9288933, + "36:40": -9288933, + "37:40": -9288933, + "38:40": -9288933, + "39:40": -9288933, + "40:40": -9288933, + "41:40": -9288933, + "42:40": -9288933, + "43:40": -9288933, + "44:40": -9288933, + "45:40": -9288933, + "46:40": -9288933, + "47:40": -9288933, + "48:40": -9288933, + "49:40": -9288933, + "50:40": -9288933, + "51:40": -9288933, + "52:40": -9288933, + "53:40": -9288933, + "54:40": -9288933, + "55:40": -9288933, + "56:40": -9288933, + "57:40": -9288933, + "58:40": -9288933, + "59:40": -9288933, + "60:40": -9288933, + "61:40": -9288933, + "62:40": 268435456, + "63:40": 402653184, + "64:40": 268435456, + "65:40": 402653184, + "66:40": -9288933, + "67:40": -9288933, + "68:40": -9288933, + "69:40": -9288933, + "70:40": -9288933, + "71:40": -9288933, + "72:40": -9288933, + "73:40": -9288933, + "74:40": -9288933, + "75:40": -9288933, + "76:40": -1, + "77:40": -1, + "78:40": -1, + "79:40": -9288933, + "80:40": -9288933, + "81:40": -9288933, + "82:40": -9288933, + "83:40": -9288933, + "84:40": 268435456, + "85:40": 402653184, + "86:40": 268435456, + "87:40": 402653184, + "88:40": -9288933, + "89:40": -9288933, + "90:40": -9288933, + "91:40": -9288933, + "92:40": -9288933, + "93:40": -9288933, + "94:40": -9288933, + "95:40": -9288933, + "96:40": -9288933, + "97:40": -9288933, + "98:40": -9288933, + "99:40": -9288933, + "100:40": -9288933, + "101:40": -9288933, + "102:40": -9288933, + "103:40": -9288933, + "104:40": -9288933, + "105:40": -9288933, + "106:40": 268435456, + "107:40": 402653184, + "108:40": 268435456, + "109:40": 402653184, + "110:40": 268435456, + "111:40": 402653184, + "112:40": 268435456, + "113:40": 402653184, + "114:40": 268435456, + "115:40": 402653184, + "116:40": 268435456, + "117:40": 402653184, + "118:40": 268435456, + "119:40": 402653184, + "120:40": 268435456, + "121:40": 402653184, + "122:40": 268435456, + "123:40": 402653184, + "124:40": 268435456, + "125:40": 402653184, + "126:40": 268435456, + "127:40": 402653184, + "0:41": 402653184, + "1:41": 268435456, + "2:41": 402653184, + "3:41": 268435456, + "4:41": 402653184, + "5:41": 268435456, + "6:41": 402653184, + "7:41": 268435456, + "8:41": 402653184, + "9:41": 268435456, + "10:41": 402653184, + "11:41": 268435456, + "12:41": 402653184, + "13:41": 268435456, + "14:41": 402653184, + "15:41": 268435456, + "16:41": 402653184, + "17:41": 268435456, + "18:41": 402653184, + "19:41": 268435456, + "20:41": 402653184, + "21:41": 268435456, + "22:41": -9288933, + "23:41": -9288933, + "24:41": -9288933, + "25:41": -9288933, + "26:41": -9288933, + "27:41": -9288933, + "28:41": -9288933, + "29:41": -9288933, + "30:41": -9288933, + "31:41": -9288933, + "32:41": -9288933, + "33:41": -9288933, + "34:41": -9288933, + "35:41": -9288933, + "36:41": -9288933, + "37:41": -9288933, + "38:41": -9288933, + "39:41": -9288933, + "40:41": -9288933, + "41:41": -9288933, + "42:41": -9288933, + "43:41": -9288933, + "44:41": -9288933, + "45:41": -9288933, + "46:41": -9288933, + "47:41": -9288933, + "48:41": -9288933, + "49:41": -9288933, + "50:41": -9288933, + "51:41": -9288933, + "52:41": -9288933, + "53:41": -9288933, + "54:41": -9288933, + "55:41": -9288933, + "56:41": -9288933, + "57:41": -9288933, + "58:41": -9288933, + "59:41": -9288933, + "60:41": -9288933, + "61:41": -9288933, + "62:41": 402653184, + "63:41": 268435456, + "64:41": 402653184, + "65:41": 268435456, + "66:41": -9288933, + "67:41": -9288933, + "68:41": -9288933, + "69:41": -9288933, + "70:41": -9288933, + "71:41": -9288933, + "72:41": -9288933, + "73:41": -9288933, + "74:41": -9288933, + "75:41": -1, + "76:41": -1, + "77:41": -1, + "78:41": -9288933, + "79:41": -9288933, + "80:41": -9288933, + "81:41": -9288933, + "82:41": -9288933, + "83:41": -9288933, + "84:41": 402653184, + "85:41": 268435456, + "86:41": 402653184, + "87:41": 268435456, + "88:41": -9288933, + "89:41": -9288933, + "90:41": -9288933, + "91:41": -9288933, + "92:41": -9288933, + "93:41": -9288933, + "94:41": -9288933, + "95:41": -9288933, + "96:41": -9288933, + "97:41": -9288933, + "98:41": -9288933, + "99:41": -9288933, + "100:41": -9288933, + "101:41": -9288933, + "102:41": -9288933, + "103:41": -9288933, + "104:41": -9288933, + "105:41": -9288933, + "106:41": 402653184, + "107:41": 268435456, + "108:41": 402653184, + "109:41": 268435456, + "110:41": 402653184, + "111:41": 268435456, + "112:41": 402653184, + "113:41": 268435456, + "114:41": 402653184, + "115:41": 268435456, + "116:41": 402653184, + "117:41": 268435456, + "118:41": 402653184, + "119:41": 268435456, + "120:41": 402653184, + "121:41": 268435456, + "122:41": 402653184, + "123:41": 268435456, + "124:41": 402653184, + "125:41": 268435456, + "126:41": 402653184, + "127:41": 268435456, + "0:42": 268435456, + "1:42": 402653184, + "2:42": 268435456, + "3:42": 402653184, + "4:42": 268435456, + "5:42": 402653184, + "6:42": 268435456, + "7:42": 402653184, + "8:42": 268435456, + "9:42": 402653184, + "10:42": 268435456, + "11:42": 402653184, + "12:42": 268435456, + "13:42": 402653184, + "14:42": 268435456, + "15:42": 402653184, + "16:42": 268435456, + "17:42": 402653184, + "18:42": 268435456, + "19:42": 402653184, + "20:42": 268435456, + "21:42": 402653184, + "22:42": -9288933, + "23:42": -9288933, + "24:42": -9288933, + "25:42": -9288933, + "26:42": -9288933, + "27:42": -9288933, + "28:42": -9288933, + "29:42": -9288933, + "30:42": -9288933, + "31:42": -9288933, + "32:42": -9288933, + "33:42": -9288933, + "34:42": -9288933, + "35:42": -9288933, + "36:42": -9288933, + "37:42": -9288933, + "38:42": -9288933, + "39:42": -9288933, + "40:42": -9288933, + "41:42": -9288933, + "42:42": -9288933, + "43:42": -9288933, + "44:42": -9288933, + "45:42": -9288933, + "46:42": -9288933, + "47:42": -9288933, + "48:42": -9288933, + "49:42": -9288933, + "50:42": -9288933, + "51:42": -9288933, + "52:42": -9288933, + "53:42": -9288933, + "54:42": -9288933, + "55:42": -9288933, + "56:42": -9288933, + "57:42": -9288933, + "58:42": -9288933, + "59:42": -9288933, + "60:42": -9288933, + "61:42": -9288933, + "62:42": 268435456, + "63:42": 402653184, + "64:42": 268435456, + "65:42": 402653184, + "66:42": -9288933, + "67:42": -9288933, + "68:42": -9288933, + "69:42": -9288933, + "70:42": -9288933, + "71:42": -9288933, + "72:42": -9288933, + "73:42": -9288933, + "74:42": -9288933, + "75:42": -1, + "76:42": -1, + "77:42": -9288933, + "78:42": -9288933, + "79:42": -9288933, + "80:42": -9288933, + "81:42": -9288933, + "82:42": -9288933, + "83:42": -9288933, + "84:42": 268435456, + "85:42": 402653184, + "86:42": 268435456, + "87:42": 402653184, + "88:42": -9288933, + "89:42": -9288933, + "90:42": -9288933, + "91:42": -9288933, + "92:42": -9288933, + "93:42": -9288933, + "94:42": -9288933, + "95:42": -9288933, + "96:42": -9288933, + "97:42": -9288933, + "98:42": -9288933, + "99:42": -9288933, + "100:42": -9288933, + "101:42": -9288933, + "102:42": -9288933, + "103:42": -9288933, + "104:42": -9288933, + "105:42": -9288933, + "106:42": 268435456, + "107:42": 402653184, + "108:42": 268435456, + "109:42": 402653184, + "110:42": 268435456, + "111:42": 402653184, + "112:42": 268435456, + "113:42": 402653184, + "114:42": 268435456, + "115:42": 402653184, + "116:42": 268435456, + "117:42": 402653184, + "118:42": 268435456, + "119:42": 402653184, + "120:42": 268435456, + "121:42": 402653184, + "122:42": 268435456, + "123:42": 402653184, + "124:42": 268435456, + "125:42": 402653184, + "126:42": 268435456, + "127:42": 402653184, + "0:43": 402653184, + "1:43": 268435456, + "2:43": 402653184, + "3:43": 268435456, + "4:43": 402653184, + "5:43": 268435456, + "6:43": 402653184, + "7:43": 268435456, + "8:43": 402653184, + "9:43": 268435456, + "10:43": 402653184, + "11:43": 268435456, + "12:43": 402653184, + "13:43": 268435456, + "14:43": 402653184, + "15:43": 268435456, + "16:43": 402653184, + "17:43": 268435456, + "18:43": 402653184, + "19:43": 268435456, + "20:43": 402653184, + "21:43": 268435456, + "22:43": -9288933, + "23:43": -9288933, + "24:43": -9288933, + "25:43": -9288933, + "26:43": -9288933, + "27:43": -9288933, + "28:43": -9288933, + "29:43": -9288933, + "30:43": -9288933, + "31:43": -9288933, + "32:43": -9288933, + "33:43": -9288933, + "34:43": -9288933, + "35:43": -9288933, + "36:43": -9288933, + "37:43": -9288933, + "38:43": -9288933, + "39:43": -9288933, + "40:43": -9288933, + "41:43": -9288933, + "42:43": -9288933, + "43:43": -9288933, + "44:43": -9288933, + "45:43": -9288933, + "46:43": -9288933, + "47:43": -9288933, + "48:43": -9288933, + "49:43": -9288933, + "50:43": -9288933, + "51:43": -9288933, + "52:43": -9288933, + "53:43": -9288933, + "54:43": -9288933, + "55:43": -9288933, + "56:43": -9288933, + "57:43": -9288933, + "58:43": -9288933, + "59:43": -9288933, + "60:43": -9288933, + "61:43": -9288933, + "62:43": 402653184, + "63:43": 268435456, + "64:43": 402653184, + "65:43": 268435456, + "66:43": -9288933, + "67:43": -9288933, + "68:43": -9288933, + "69:43": -9288933, + "70:43": -9288933, + "71:43": -9288933, + "72:43": -1, + "73:43": -1, + "74:43": -9288933, + "75:43": -1, + "76:43": -1, + "77:43": -9288933, + "78:43": -9288933, + "79:43": -9288933, + "80:43": -9288933, + "81:43": -9288933, + "82:43": -9288933, + "83:43": -9288933, + "84:43": 402653184, + "85:43": 268435456, + "86:43": 402653184, + "87:43": 268435456, + "88:43": -9288933, + "89:43": -9288933, + "90:43": -9288933, + "91:43": -9288933, + "92:43": -9288933, + "93:43": -9288933, + "94:43": -9288933, + "95:43": -9288933, + "96:43": -9288933, + "97:43": -9288933, + "98:43": -9288933, + "99:43": -9288933, + "100:43": -9288933, + "101:43": -9288933, + "102:43": -9288933, + "103:43": -9288933, + "104:43": -9288933, + "105:43": -9288933, + "106:43": 402653184, + "107:43": 268435456, + "108:43": 402653184, + "109:43": 268435456, + "110:43": 402653184, + "111:43": 268435456, + "112:43": 402653184, + "113:43": 268435456, + "114:43": 402653184, + "115:43": 268435456, + "116:43": 402653184, + "117:43": 268435456, + "118:43": 402653184, + "119:43": 268435456, + "120:43": 402653184, + "121:43": 268435456, + "122:43": 402653184, + "123:43": 268435456, + "124:43": 402653184, + "125:43": 268435456, + "126:43": 402653184, + "127:43": 268435456, + "0:44": 268435456, + "1:44": 402653184, + "2:44": 268435456, + "3:44": 402653184, + "4:44": 268435456, + "5:44": 402653184, + "6:44": 268435456, + "7:44": 402653184, + "8:44": 268435456, + "9:44": 402653184, + "10:44": 268435456, + "11:44": 402653184, + "12:44": 268435456, + "13:44": 402653184, + "14:44": 268435456, + "15:44": 402653184, + "16:44": 268435456, + "17:44": 402653184, + "18:44": 268435456, + "19:44": 402653184, + "20:44": 268435456, + "21:44": 402653184, + "22:44": -9288933, + "23:44": -9288933, + "24:44": -9288933, + "25:44": -9288933, + "26:44": -9288933, + "27:44": -9288933, + "28:44": -9288933, + "29:44": -9288933, + "30:44": -9288933, + "31:44": -9288933, + "32:44": -9288933, + "33:44": -9288933, + "34:44": -9288933, + "35:44": -9288933, + "36:44": -9288933, + "37:44": -9288933, + "38:44": -9288933, + "39:44": -9288933, + "40:44": -9288933, + "41:44": -9288933, + "42:44": -9288933, + "43:44": -9288933, + "44:44": -9288933, + "45:44": -9288933, + "46:44": -9288933, + "47:44": -9288933, + "48:44": -9288933, + "49:44": -9288933, + "50:44": -9288933, + "51:44": -9288933, + "52:44": -9288933, + "53:44": -9288933, + "54:44": -9288933, + "55:44": -9288933, + "56:44": -9288933, + "57:44": -9288933, + "58:44": -9288933, + "59:44": -9288933, + "60:44": -9288933, + "61:44": -9288933, + "62:44": 268435456, + "63:44": 402653184, + "64:44": 268435456, + "65:44": 402653184, + "66:44": -9288933, + "67:44": -9288933, + "68:44": -9288933, + "69:44": -9288933, + "70:44": -9288933, + "71:44": -9288933, + "72:44": -9288933, + "73:44": -1, + "74:44": -1, + "75:44": -1, + "76:44": -9288933, + "77:44": -9288933, + "78:44": -9288933, + "79:44": -9288933, + "80:44": -9288933, + "81:44": -9288933, + "82:44": -9288933, + "83:44": -9288933, + "84:44": 268435456, + "85:44": 402653184, + "86:44": 268435456, + "87:44": 402653184, + "88:44": -9288933, + "89:44": -9288933, + "90:44": -9288933, + "91:44": -9288933, + "92:44": -9288933, + "93:44": -9288933, + "94:44": -9288933, + "95:44": -9288933, + "96:44": -9288933, + "97:44": -9288933, + "98:44": -9288933, + "99:44": -9288933, + "100:44": -9288933, + "101:44": -9288933, + "102:44": -9288933, + "103:44": -9288933, + "104:44": -9288933, + "105:44": -9288933, + "106:44": 268435456, + "107:44": 402653184, + "108:44": 268435456, + "109:44": 402653184, + "110:44": 268435456, + "111:44": 402653184, + "112:44": 268435456, + "113:44": 402653184, + "114:44": 268435456, + "115:44": 402653184, + "116:44": 268435456, + "117:44": 402653184, + "118:44": 268435456, + "119:44": 402653184, + "120:44": 268435456, + "121:44": 402653184, + "122:44": 268435456, + "123:44": 402653184, + "124:44": 268435456, + "125:44": 402653184, + "126:44": 268435456, + "127:44": 402653184, + "0:45": 402653184, + "1:45": 268435456, + "2:45": 402653184, + "3:45": 268435456, + "4:45": 402653184, + "5:45": 268435456, + "6:45": 402653184, + "7:45": 268435456, + "8:45": 402653184, + "9:45": 268435456, + "10:45": 402653184, + "11:45": 268435456, + "12:45": 402653184, + "13:45": 268435456, + "14:45": 402653184, + "15:45": 268435456, + "16:45": 402653184, + "17:45": 268435456, + "18:45": 402653184, + "19:45": 268435456, + "20:45": 402653184, + "21:45": 268435456, + "22:45": -9288933, + "23:45": -9288933, + "24:45": -9288933, + "25:45": -9288933, + "26:45": -9288933, + "27:45": -9288933, + "28:45": -9288933, + "29:45": -9288933, + "30:45": -9288933, + "31:45": -9288933, + "32:45": -9288933, + "33:45": -9288933, + "34:45": -9288933, + "35:45": -9288933, + "36:45": -9288933, + "37:45": -9288933, + "38:45": -9288933, + "39:45": -9288933, + "40:45": -9288933, + "41:45": -9288933, + "42:45": -9288933, + "43:45": -9288933, + "44:45": -9288933, + "45:45": -9288933, + "46:45": -9288933, + "47:45": -9288933, + "48:45": -9288933, + "49:45": -9288933, + "50:45": -9288933, + "51:45": -9288933, + "52:45": -9288933, + "53:45": -9288933, + "54:45": -9288933, + "55:45": -9288933, + "56:45": -9288933, + "57:45": -9288933, + "58:45": -9288933, + "59:45": -9288933, + "60:45": -9288933, + "61:45": -9288933, + "62:45": 402653184, + "63:45": 268435456, + "64:45": 402653184, + "65:45": 268435456, + "66:45": -9288933, + "67:45": -9288933, + "68:45": -9288933, + "69:45": -9288933, + "70:45": -9288933, + "71:45": -9288933, + "72:45": -9288933, + "73:45": -1, + "74:45": -1, + "75:45": -1, + "76:45": -9288933, + "77:45": -9288933, + "78:45": -9288933, + "79:45": -9288933, + "80:45": -9288933, + "81:45": -9288933, + "82:45": -9288933, + "83:45": -9288933, + "84:45": 402653184, + "85:45": 268435456, + "86:45": 402653184, + "87:45": 268435456, + "88:45": -9288933, + "89:45": -9288933, + "90:45": -9288933, + "91:45": -9288933, + "92:45": -9288933, + "93:45": -9288933, + "94:45": -9288933, + "95:45": -9288933, + "96:45": -9288933, + "97:45": -9288933, + "98:45": -9288933, + "99:45": -9288933, + "100:45": -9288933, + "101:45": -9288933, + "102:45": -9288933, + "103:45": -9288933, + "104:45": -9288933, + "105:45": -9288933, + "106:45": 402653184, + "107:45": 268435456, + "108:45": 402653184, + "109:45": 268435456, + "110:45": 402653184, + "111:45": 268435456, + "112:45": 402653184, + "113:45": 268435456, + "114:45": 402653184, + "115:45": 268435456, + "116:45": 402653184, + "117:45": 268435456, + "118:45": 402653184, + "119:45": 268435456, + "120:45": 402653184, + "121:45": 268435456, + "122:45": 402653184, + "123:45": 268435456, + "124:45": 402653184, + "125:45": 268435456, + "126:45": 402653184, + "127:45": 268435456, + "0:46": 268435456, + "1:46": 402653184, + "2:46": 268435456, + "3:46": 402653184, + "4:46": 268435456, + "5:46": 402653184, + "6:46": 268435456, + "7:46": 402653184, + "8:46": 268435456, + "9:46": 402653184, + "10:46": 268435456, + "11:46": 402653184, + "12:46": 268435456, + "13:46": 402653184, + "14:46": 268435456, + "15:46": 402653184, + "16:46": 268435456, + "17:46": 402653184, + "18:46": 268435456, + "19:46": 402653184, + "20:46": 268435456, + "21:46": 402653184, + "22:46": -9288933, + "23:46": -9288933, + "24:46": -9288933, + "25:46": -9288933, + "26:46": -9288933, + "27:46": -9288933, + "28:46": -9288933, + "29:46": -9288933, + "30:46": -9288933, + "31:46": -9288933, + "32:46": -9288933, + "33:46": -9288933, + "34:46": -9288933, + "35:46": -9288933, + "36:46": -9288933, + "37:46": -9288933, + "38:46": -9288933, + "39:46": -9288933, + "40:46": -9288933, + "41:46": -9288933, + "42:46": -9288933, + "43:46": -9288933, + "44:46": -9288933, + "45:46": -9288933, + "46:46": -9288933, + "47:46": -9288933, + "48:46": -9288933, + "49:46": -9288933, + "50:46": -9288933, + "51:46": -9288933, + "52:46": -9288933, + "53:46": -9288933, + "54:46": -9288933, + "55:46": -9288933, + "56:46": -9288933, + "57:46": -9288933, + "58:46": -9288933, + "59:46": -9288933, + "60:46": -9288933, + "61:46": -9288933, + "62:46": 268435456, + "63:46": 402653184, + "64:46": 268435456, + "65:46": 402653184, + "66:46": -9288933, + "67:46": -9288933, + "68:46": -9288933, + "69:46": -9288933, + "70:46": -9288933, + "71:46": -9288933, + "72:46": -9288933, + "73:46": -9288933, + "74:46": -9288933, + "75:46": -9288933, + "76:46": -9288933, + "77:46": -9288933, + "78:46": -9288933, + "79:46": -9288933, + "80:46": -9288933, + "81:46": -9288933, + "82:46": -9288933, + "83:46": -9288933, + "84:46": 268435456, + "85:46": 402653184, + "86:46": 268435456, + "87:46": 402653184, + "88:46": -9288933, + "89:46": -9288933, + "90:46": -9288933, + "91:46": -9288933, + "92:46": -9288933, + "93:46": -9288933, + "94:46": -9288933, + "95:46": -9288933, + "96:46": -9288933, + "97:46": -9288933, + "98:46": -9288933, + "99:46": -9288933, + "100:46": -9288933, + "101:46": -9288933, + "102:46": -9288933, + "103:46": -9288933, + "104:46": -9288933, + "105:46": -9288933, + "106:46": 268435456, + "107:46": 402653184, + "108:46": 268435456, + "109:46": 402653184, + "110:46": 268435456, + "111:46": 402653184, + "112:46": 268435456, + "113:46": 402653184, + "114:46": 268435456, + "115:46": 402653184, + "116:46": 268435456, + "117:46": 402653184, + "118:46": 268435456, + "119:46": 402653184, + "120:46": 268435456, + "121:46": 402653184, + "122:46": 268435456, + "123:46": 402653184, + "124:46": 268435456, + "125:46": 402653184, + "126:46": 268435456, + "127:46": 402653184, + "0:47": 402653184, + "1:47": 268435456, + "2:47": 402653184, + "3:47": 268435456, + "4:47": 402653184, + "5:47": 268435456, + "6:47": 402653184, + "7:47": 268435456, + "8:47": 402653184, + "9:47": 268435456, + "10:47": 402653184, + "11:47": 268435456, + "12:47": 402653184, + "13:47": 268435456, + "14:47": 402653184, + "15:47": 268435456, + "16:47": 402653184, + "17:47": 268435456, + "18:47": 402653184, + "19:47": 268435456, + "20:47": 402653184, + "21:47": 268435456, + "22:47": -9288933, + "23:47": -9288933, + "24:47": -9288933, + "25:47": -9288933, + "26:47": -9288933, + "27:47": -9288933, + "28:47": -9288933, + "29:47": -9288933, + "30:47": -9288933, + "31:47": -9288933, + "32:47": -9288933, + "33:47": -9288933, + "34:47": -9288933, + "35:47": -9288933, + "36:47": -9288933, + "37:47": -9288933, + "38:47": -9288933, + "39:47": -9288933, + "40:47": -9288933, + "41:47": -9288933, + "42:47": -9288933, + "43:47": -9288933, + "44:47": -9288933, + "45:47": -9288933, + "46:47": -9288933, + "47:47": -9288933, + "48:47": -9288933, + "49:47": -9288933, + "50:47": -9288933, + "51:47": -9288933, + "52:47": -9288933, + "53:47": -9288933, + "54:47": -9288933, + "55:47": -9288933, + "56:47": -9288933, + "57:47": -9288933, + "58:47": -9288933, + "59:47": -9288933, + "60:47": -9288933, + "61:47": -9288933, + "62:47": 402653184, + "63:47": 268435456, + "64:47": 402653184, + "65:47": 268435456, + "66:47": -9288933, + "67:47": -9288933, + "68:47": -9288933, + "69:47": -9288933, + "70:47": -9288933, + "71:47": -9288933, + "72:47": -9288933, + "73:47": -9288933, + "74:47": -9288933, + "75:47": -9288933, + "76:47": -9288933, + "77:47": -9288933, + "78:47": -9288933, + "79:47": -9288933, + "80:47": -9288933, + "81:47": -9288933, + "82:47": -9288933, + "83:47": -9288933, + "84:47": 402653184, + "85:47": 268435456, + "86:47": 402653184, + "87:47": 268435456, + "88:47": -9288933, + "89:47": -9288933, + "90:47": -9288933, + "91:47": -9288933, + "92:47": -9288933, + "93:47": -9288933, + "94:47": -9288933, + "95:47": -9288933, + "96:47": -9288933, + "97:47": -9288933, + "98:47": -9288933, + "99:47": -9288933, + "100:47": -9288933, + "101:47": -9288933, + "102:47": -9288933, + "103:47": -9288933, + "104:47": -9288933, + "105:47": -9288933, + "106:47": 402653184, + "107:47": 268435456, + "108:47": 402653184, + "109:47": 268435456, + "110:47": 402653184, + "111:47": 268435456, + "112:47": 402653184, + "113:47": 268435456, + "114:47": 402653184, + "115:47": 268435456, + "116:47": 402653184, + "117:47": 268435456, + "118:47": 402653184, + "119:47": 268435456, + "120:47": 402653184, + "121:47": 268435456, + "122:47": 402653184, + "123:47": 268435456, + "124:47": 402653184, + "125:47": 268435456, + "126:47": 402653184, + "127:47": 268435456, + "0:48": 268435456, + "1:48": 402653184, + "2:48": 268435456, + "3:48": 402653184, + "4:48": 268435456, + "5:48": 402653184, + "6:48": 268435456, + "7:48": 402653184, + "8:48": 268435456, + "9:48": 402653184, + "10:48": 268435456, + "11:48": 402653184, + "12:48": 268435456, + "13:48": 402653184, + "14:48": 268435456, + "15:48": 402653184, + "16:48": 268435456, + "17:48": 402653184, + "18:48": 268435456, + "19:48": 402653184, + "20:48": 268435456, + "21:48": 402653184, + "22:48": -9288933, + "23:48": -9288933, + "24:48": -9288933, + "25:48": -9288933, + "26:48": -9288933, + "27:48": -9288933, + "28:48": -9288933, + "29:48": -9288933, + "30:48": -9288933, + "31:48": -9288933, + "32:48": -9288933, + "33:48": -9288933, + "34:48": -9288933, + "35:48": -9288933, + "36:48": -9288933, + "37:48": -9288933, + "38:48": -9288933, + "39:48": -9288933, + "40:48": -9288933, + "41:48": -9288933, + "42:48": -9288933, + "43:48": -9288933, + "44:48": -9288933, + "45:48": -9288933, + "46:48": -9288933, + "47:48": -9288933, + "48:48": -9288933, + "49:48": -9288933, + "50:48": -9288933, + "51:48": -9288933, + "52:48": -9288933, + "53:48": -9288933, + "54:48": -9288933, + "55:48": -9288933, + "56:48": -9288933, + "57:48": -9288933, + "58:48": -9288933, + "59:48": -9288933, + "60:48": -9288933, + "61:48": -9288933, + "62:48": 268435456, + "63:48": 402653184, + "64:48": 268435456, + "65:48": 402653184, + "66:48": -9288933, + "67:48": -9288933, + "68:48": -9288933, + "69:48": -9288933, + "70:48": -9288933, + "71:48": -9288933, + "72:48": -9288933, + "73:48": -9288933, + "74:48": -9288933, + "75:48": -9288933, + "76:48": -9288933, + "77:48": -9288933, + "78:48": -9288933, + "79:48": -9288933, + "80:48": -9288933, + "81:48": -9288933, + "82:48": -9288933, + "83:48": -9288933, + "84:48": 268435456, + "85:48": 402653184, + "86:48": 268435456, + "87:48": 402653184, + "88:48": -9288933, + "89:48": -9288933, + "90:48": -9288933, + "91:48": -9288933, + "92:48": -9288933, + "93:48": -9288933, + "94:48": -9288933, + "95:48": -9288933, + "96:48": -9288933, + "97:48": -9288933, + "98:48": -9288933, + "99:48": -9288933, + "100:48": -9288933, + "101:48": -9288933, + "102:48": -9288933, + "103:48": -9288933, + "104:48": -9288933, + "105:48": -9288933, + "106:48": 268435456, + "107:48": 402653184, + "108:48": 268435456, + "109:48": 402653184, + "110:48": 268435456, + "111:48": 402653184, + "112:48": 268435456, + "113:48": 402653184, + "114:48": 268435456, + "115:48": 402653184, + "116:48": 268435456, + "117:48": 402653184, + "118:48": 268435456, + "119:48": 402653184, + "120:48": 268435456, + "121:48": 402653184, + "122:48": 268435456, + "123:48": 402653184, + "124:48": 268435456, + "125:48": 402653184, + "126:48": 268435456, + "127:48": 402653184, + "0:49": 402653184, + "1:49": 268435456, + "2:49": 402653184, + "3:49": 268435456, + "4:49": 402653184, + "5:49": 268435456, + "6:49": 402653184, + "7:49": 268435456, + "8:49": 402653184, + "9:49": 268435456, + "10:49": 402653184, + "11:49": 268435456, + "12:49": 402653184, + "13:49": 268435456, + "14:49": 402653184, + "15:49": 268435456, + "16:49": 402653184, + "17:49": 268435456, + "18:49": 402653184, + "19:49": 268435456, + "20:49": 402653184, + "21:49": 268435456, + "22:49": -9288933, + "23:49": -9288933, + "24:49": -9288933, + "25:49": -9288933, + "26:49": -9288933, + "27:49": -9288933, + "28:49": -9288933, + "29:49": -9288933, + "30:49": -9288933, + "31:49": -9288933, + "32:49": -9288933, + "33:49": -9288933, + "34:49": -9288933, + "35:49": -9288933, + "36:49": -9288933, + "37:49": -9288933, + "38:49": -9288933, + "39:49": -9288933, + "40:49": -9288933, + "41:49": -9288933, + "42:49": -9288933, + "43:49": -9288933, + "44:49": -9288933, + "45:49": -9288933, + "46:49": -9288933, + "47:49": -9288933, + "48:49": -9288933, + "49:49": -9288933, + "50:49": -9288933, + "51:49": -9288933, + "52:49": -9288933, + "53:49": -9288933, + "54:49": -9288933, + "55:49": -9288933, + "56:49": -9288933, + "57:49": -9288933, + "58:49": -9288933, + "59:49": -9288933, + "60:49": -9288933, + "61:49": -9288933, + "62:49": 402653184, + "63:49": 268435456, + "64:49": 402653184, + "65:49": 268435456, + "66:49": -9288933, + "67:49": -9288933, + "68:49": -9288933, + "69:49": -9288933, + "70:49": -9288933, + "71:49": -9288933, + "72:49": -9288933, + "73:49": -9288933, + "74:49": -9288933, + "75:49": -9288933, + "76:49": -9288933, + "77:49": -9288933, + "78:49": -9288933, + "79:49": -9288933, + "80:49": -9288933, + "81:49": -9288933, + "82:49": -9288933, + "83:49": -9288933, + "84:49": 402653184, + "85:49": 268435456, + "86:49": 402653184, + "87:49": 268435456, + "88:49": -9288933, + "89:49": -9288933, + "90:49": -9288933, + "91:49": -9288933, + "92:49": -9288933, + "93:49": -9288933, + "94:49": -9288933, + "95:49": -9288933, + "96:49": -9288933, + "97:49": -9288933, + "98:49": -9288933, + "99:49": -9288933, + "100:49": -9288933, + "101:49": -9288933, + "102:49": -9288933, + "103:49": -9288933, + "104:49": -9288933, + "105:49": -9288933, + "106:49": 402653184, + "107:49": 268435456, + "108:49": 402653184, + "109:49": 268435456, + "110:49": 402653184, + "111:49": 268435456, + "112:49": 402653184, + "113:49": 268435456, + "114:49": 402653184, + "115:49": 268435456, + "116:49": 402653184, + "117:49": 268435456, + "118:49": 402653184, + "119:49": 268435456, + "120:49": 402653184, + "121:49": 268435456, + "122:49": 402653184, + "123:49": 268435456, + "124:49": 402653184, + "125:49": 268435456, + "126:49": 402653184, + "127:49": 268435456, + "0:50": 268435456, + "1:50": 402653184, + "2:50": 268435456, + "3:50": 402653184, + "4:50": 268435456, + "5:50": 402653184, + "6:50": 268435456, + "7:50": 402653184, + "8:50": 268435456, + "9:50": 402653184, + "10:50": 268435456, + "11:50": 402653184, + "12:50": 268435456, + "13:50": 402653184, + "14:50": 268435456, + "15:50": 402653184, + "16:50": 268435456, + "17:50": 402653184, + "18:50": 268435456, + "19:50": 402653184, + "20:50": 268435456, + "21:50": 402653184, + "22:50": -9288933, + "23:50": -9288933, + "24:50": -9288933, + "25:50": -9288933, + "26:50": -9288933, + "27:50": -9288933, + "28:50": -9288933, + "29:50": -9288933, + "30:50": -9288933, + "31:50": -9288933, + "32:50": -9288933, + "33:50": -9288933, + "34:50": -9288933, + "35:50": -9288933, + "36:50": -9288933, + "37:50": -9288933, + "38:50": -9288933, + "39:50": -9288933, + "40:50": -9288933, + "41:50": -9288933, + "42:50": -9288933, + "43:50": -9288933, + "44:50": -9288933, + "45:50": -9288933, + "46:50": -9288933, + "47:50": -9288933, + "48:50": -9288933, + "49:50": -9288933, + "50:50": -9288933, + "51:50": -9288933, + "52:50": -9288933, + "53:50": -9288933, + "54:50": -9288933, + "55:50": -9288933, + "56:50": -9288933, + "57:50": -9288933, + "58:50": -9288933, + "59:50": -9288933, + "60:50": -9288933, + "61:50": -9288933, + "62:50": 268435456, + "63:50": 402653184, + "64:50": 268435456, + "65:50": 402653184, + "66:50": -9288933, + "67:50": -9288933, + "68:50": -9288933, + "69:50": -9288933, + "70:50": -9288933, + "71:50": -9288933, + "72:50": -9288933, + "73:50": -9288933, + "74:50": -9288933, + "75:50": -9288933, + "76:50": -9288933, + "77:50": -9288933, + "78:50": -9288933, + "79:50": -9288933, + "80:50": -9288933, + "81:50": -9288933, + "82:50": -9288933, + "83:50": -9288933, + "84:50": 268435456, + "85:50": 402653184, + "86:50": 268435456, + "87:50": 402653184, + "88:50": -9288933, + "89:50": -9288933, + "90:50": -9288933, + "91:50": -9288933, + "92:50": -9288933, + "93:50": -9288933, + "94:50": -9288933, + "95:50": -9288933, + "96:50": -9288933, + "97:50": -9288933, + "98:50": -9288933, + "99:50": -9288933, + "100:50": -9288933, + "101:50": -9288933, + "102:50": -9288933, + "103:50": -9288933, + "104:50": -9288933, + "105:50": -9288933, + "106:50": 268435456, + "107:50": 402653184, + "108:50": 268435456, + "109:50": 402653184, + "110:50": 268435456, + "111:50": 402653184, + "112:50": 268435456, + "113:50": 402653184, + "114:50": 268435456, + "115:50": 402653184, + "116:50": 268435456, + "117:50": 402653184, + "118:50": 268435456, + "119:50": 402653184, + "120:50": 268435456, + "121:50": 402653184, + "122:50": 268435456, + "123:50": 402653184, + "124:50": 268435456, + "125:50": 402653184, + "126:50": 268435456, + "127:50": 402653184, + "0:51": 402653184, + "1:51": 268435456, + "2:51": 402653184, + "3:51": 268435456, + "4:51": 402653184, + "5:51": 268435456, + "6:51": 402653184, + "7:51": 268435456, + "8:51": 402653184, + "9:51": 268435456, + "10:51": 402653184, + "11:51": 268435456, + "12:51": 402653184, + "13:51": 268435456, + "14:51": 402653184, + "15:51": 268435456, + "16:51": 402653184, + "17:51": 268435456, + "18:51": 402653184, + "19:51": 268435456, + "20:51": 402653184, + "21:51": 268435456, + "22:51": 402653184, + "23:51": 268435456, + "24:51": 402653184, + "25:51": 268435456, + "26:51": 402653184, + "27:51": 268435456, + "28:51": 402653184, + "29:51": 268435456, + "30:51": 402653184, + "31:51": 268435456, + "32:51": 402653184, + "33:51": 268435456, + "34:51": 402653184, + "35:51": 268435456, + "36:51": 402653184, + "37:51": 268435456, + "38:51": 402653184, + "39:51": 268435456, + "40:51": 402653184, + "41:51": 268435456, + "42:51": 402653184, + "43:51": 268435456, + "44:51": 402653184, + "45:51": 268435456, + "46:51": 402653184, + "47:51": 268435456, + "48:51": 402653184, + "49:51": 268435456, + "50:51": -884827, + "51:51": -884827, + "52:51": -884827, + "53:51": -884827, + "54:51": -884827, + "55:51": -884827, + "56:51": -884827, + "57:51": 268435456, + "58:51": 402653184, + "59:51": 268435456, + "60:51": 402653184, + "61:51": 268435456, + "62:51": 402653184, + "63:51": 268435456, + "64:51": 402653184, + "65:51": 268435456, + "66:51": -9288933, + "67:51": -9288933, + "68:51": -9288933, + "69:51": -9288933, + "70:51": -9288933, + "71:51": -9288933, + "72:51": -9288933, + "73:51": -9288933, + "74:51": -9288933, + "75:51": -9288933, + "76:51": -9288933, + "77:51": -9288933, + "78:51": -9288933, + "79:51": -9288933, + "80:51": -9288933, + "81:51": -9288933, + "82:51": -9288933, + "83:51": -9288933, + "84:51": 402653184, + "85:51": 268435456, + "86:51": 402653184, + "87:51": 268435456, + "88:51": -9288933, + "89:51": -9288933, + "90:51": -9288933, + "91:51": -9288933, + "92:51": -9288933, + "93:51": -9288933, + "94:51": -9288933, + "95:51": -9288933, + "96:51": -9288933, + "97:51": -9288933, + "98:51": -9288933, + "99:51": -9288933, + "100:51": -9288933, + "101:51": -9288933, + "102:51": -9288933, + "103:51": -9288933, + "104:51": -9288933, + "105:51": -9288933, + "106:51": 402653184, + "107:51": 268435456, + "108:51": 402653184, + "109:51": 268435456, + "110:51": 402653184, + "111:51": 268435456, + "112:51": 402653184, + "113:51": 268435456, + "114:51": 402653184, + "115:51": 268435456, + "116:51": 402653184, + "117:51": 268435456, + "118:51": 402653184, + "119:51": 268435456, + "120:51": 402653184, + "121:51": 268435456, + "122:51": 402653184, + "123:51": 268435456, + "124:51": 402653184, + "125:51": 268435456, + "126:51": 402653184, + "127:51": 268435456, + "0:52": 268435456, + "1:52": 402653184, + "2:52": 268435456, + "3:52": 402653184, + "4:52": 268435456, + "5:52": 402653184, + "6:52": 268435456, + "7:52": 402653184, + "8:52": 268435456, + "9:52": 402653184, + "10:52": 268435456, + "11:52": 402653184, + "12:52": 268435456, + "13:52": 402653184, + "14:52": 268435456, + "15:52": 402653184, + "16:52": 268435456, + "17:52": 402653184, + "18:52": 268435456, + "19:52": 402653184, + "20:52": 268435456, + "21:52": 402653184, + "22:52": 268435456, + "23:52": 402653184, + "24:52": 268435456, + "25:52": 402653184, + "26:52": 268435456, + "27:52": 402653184, + "28:52": 268435456, + "29:52": 402653184, + "30:52": 268435456, + "31:52": 402653184, + "32:52": 268435456, + "33:52": 402653184, + "34:52": 268435456, + "35:52": 402653184, + "36:52": 268435456, + "37:52": 402653184, + "38:52": 268435456, + "39:52": 402653184, + "40:52": 268435456, + "41:52": 402653184, + "42:52": 268435456, + "43:52": 402653184, + "44:52": 268435456, + "45:52": 402653184, + "46:52": 268435456, + "47:52": 402653184, + "48:52": 268435456, + "49:52": 402653184, + "50:52": -884827, + "51:52": -884827, + "52:52": -884827, + "53:52": -884827, + "54:52": -884827, + "55:52": -884827, + "56:52": -884827, + "57:52": 402653184, + "58:52": 268435456, + "59:52": 402653184, + "60:52": 268435456, + "61:52": 402653184, + "62:52": 268435456, + "63:52": 402653184, + "64:52": 268435456, + "65:52": 402653184, + "66:52": -9288933, + "67:52": -9288933, + "68:52": -9288933, + "69:52": -9288933, + "70:52": -9288933, + "71:52": -9288933, + "72:52": -9288933, + "73:52": -9288933, + "74:52": -9288933, + "75:52": -9288933, + "76:52": -9288933, + "77:52": -9288933, + "78:52": -9288933, + "79:52": -9288933, + "80:52": -9288933, + "81:52": -9288933, + "82:52": -9288933, + "83:52": -9288933, + "84:52": 268435456, + "85:52": 402653184, + "86:52": 268435456, + "87:52": 402653184, + "88:52": -9288933, + "89:52": -9288933, + "90:52": -9288933, + "91:52": -9288933, + "92:52": -9288933, + "93:52": -9288933, + "94:52": -9288933, + "95:52": -9288933, + "96:52": -9288933, + "97:52": -9288933, + "98:52": -9288933, + "99:52": -9288933, + "100:52": -9288933, + "101:52": -9288933, + "102:52": -9288933, + "103:52": -9288933, + "104:52": -9288933, + "105:52": -9288933, + "106:52": 268435456, + "107:52": 402653184, + "108:52": 268435456, + "109:52": 402653184, + "110:52": 268435456, + "111:52": 402653184, + "112:52": 268435456, + "113:52": 402653184, + "114:52": 268435456, + "115:52": 402653184, + "116:52": 268435456, + "117:52": 402653184, + "118:52": 268435456, + "119:52": 402653184, + "120:52": 268435456, + "121:52": 402653184, + "122:52": 268435456, + "123:52": 402653184, + "124:52": 268435456, + "125:52": 402653184, + "126:52": 268435456, + "127:52": 402653184, + "0:53": 402653184, + "1:53": 268435456, + "2:53": 402653184, + "3:53": 268435456, + "4:53": 402653184, + "5:53": 268435456, + "6:53": 402653184, + "7:53": 268435456, + "8:53": 402653184, + "9:53": 268435456, + "10:53": 402653184, + "11:53": 268435456, + "12:53": 402653184, + "13:53": 268435456, + "14:53": 402653184, + "15:53": 268435456, + "16:53": 402653184, + "17:53": 268435456, + "18:53": 402653184, + "19:53": 268435456, + "20:53": 402653184, + "21:53": 268435456, + "22:53": 402653184, + "23:53": 268435456, + "24:53": 402653184, + "25:53": 268435456, + "26:53": 402653184, + "27:53": 268435456, + "28:53": 402653184, + "29:53": 268435456, + "30:53": 402653184, + "31:53": 268435456, + "32:53": 402653184, + "33:53": 268435456, + "34:53": 402653184, + "35:53": 268435456, + "36:53": 402653184, + "37:53": 268435456, + "38:53": 402653184, + "39:53": 268435456, + "40:53": 402653184, + "41:53": 268435456, + "42:53": 402653184, + "43:53": 268435456, + "44:53": 402653184, + "45:53": 268435456, + "46:53": 402653184, + "47:53": 268435456, + "48:53": 402653184, + "49:53": 268435456, + "50:53": -884827, + "51:53": -884827, + "52:53": -884827, + "53:53": -884827, + "54:53": -884827, + "55:53": -884827, + "56:53": -884827, + "57:53": 268435456, + "58:53": 402653184, + "59:53": 268435456, + "60:53": 402653184, + "61:53": 268435456, + "62:53": 402653184, + "63:53": 268435456, + "64:53": 402653184, + "65:53": 268435456, + "66:53": -9288933, + "67:53": -9288933, + "68:53": -9288933, + "69:53": -9288933, + "70:53": -9288933, + "71:53": -9288933, + "72:53": -9288933, + "73:53": -9288933, + "74:53": -9288933, + "75:53": -9288933, + "76:53": -9288933, + "77:53": -9288933, + "78:53": -9288933, + "79:53": -9288933, + "80:53": -9288933, + "81:53": -9288933, + "82:53": -9288933, + "83:53": -9288933, + "84:53": 402653184, + "85:53": 268435456, + "86:53": 402653184, + "87:53": 268435456, + "88:53": -9288933, + "89:53": -9288933, + "90:53": -9288933, + "91:53": -9288933, + "92:53": -9288933, + "93:53": -9288933, + "94:53": -9288933, + "95:53": -9288933, + "96:53": -9288933, + "97:53": -9288933, + "98:53": -9288933, + "99:53": -9288933, + "100:53": -9288933, + "101:53": -9288933, + "102:53": -9288933, + "103:53": -9288933, + "104:53": -9288933, + "105:53": -9288933, + "106:53": 402653184, + "107:53": 268435456, + "108:53": 402653184, + "109:53": 268435456, + "110:53": 402653184, + "111:53": 268435456, + "112:53": 402653184, + "113:53": 268435456, + "114:53": 402653184, + "115:53": 268435456, + "116:53": 402653184, + "117:53": 268435456, + "118:53": 402653184, + "119:53": 268435456, + "120:53": 402653184, + "121:53": 268435456, + "122:53": 402653184, + "123:53": 268435456, + "124:53": 402653184, + "125:53": 268435456, + "126:53": 402653184, + "127:53": 268435456, + "0:54": 268435456, + "1:54": 402653184, + "2:54": 268435456, + "3:54": 402653184, + "4:54": 268435456, + "5:54": 402653184, + "6:54": 268435456, + "7:54": 402653184, + "8:54": 268435456, + "9:54": 402653184, + "10:54": 268435456, + "11:54": 402653184, + "12:54": 268435456, + "13:54": 402653184, + "14:54": 268435456, + "15:54": 402653184, + "16:54": 268435456, + "17:54": 402653184, + "18:54": 268435456, + "19:54": 402653184, + "20:54": 268435456, + "21:54": 402653184, + "22:54": 268435456, + "23:54": 402653184, + "24:54": 268435456, + "25:54": 402653184, + "26:54": 268435456, + "27:54": 402653184, + "28:54": 268435456, + "29:54": 402653184, + "30:54": 268435456, + "31:54": 402653184, + "32:54": 268435456, + "33:54": 402653184, + "34:54": 268435456, + "35:54": 402653184, + "36:54": 268435456, + "37:54": 402653184, + "38:54": 268435456, + "39:54": 402653184, + "40:54": 268435456, + "41:54": 402653184, + "42:54": 268435456, + "43:54": 402653184, + "44:54": 268435456, + "45:54": 402653184, + "46:54": 268435456, + "47:54": 402653184, + "48:54": 268435456, + "49:54": 402653184, + "50:54": -884827, + "51:54": -884827, + "52:54": -884827, + "53:54": -884827, + "54:54": -884827, + "55:54": -884827, + "56:54": -884827, + "57:54": 402653184, + "58:54": 268435456, + "59:54": 402653184, + "60:54": 268435456, + "61:54": 402653184, + "62:54": 268435456, + "63:54": 402653184, + "64:54": 268435456, + "65:54": 402653184, + "66:54": -9288933, + "67:54": -9288933, + "68:54": -9288933, + "69:54": -9288933, + "70:54": -9288933, + "71:54": -9288933, + "72:54": -9288933, + "73:54": -9288933, + "74:54": -9288933, + "75:54": -9288933, + "76:54": -9288933, + "77:54": -9288933, + "78:54": -9288933, + "79:54": -9288933, + "80:54": -9288933, + "81:54": -9288933, + "82:54": -9288933, + "83:54": -9288933, + "84:54": 268435456, + "85:54": 402653184, + "86:54": 268435456, + "87:54": 402653184, + "88:54": -9288933, + "89:54": -9288933, + "90:54": -9288933, + "91:54": -9288933, + "92:54": -9288933, + "93:54": -9288933, + "94:54": -9288933, + "95:54": -9288933, + "96:54": -9288933, + "97:54": -9288933, + "98:54": -9288933, + "99:54": -9288933, + "100:54": -9288933, + "101:54": -9288933, + "102:54": -9288933, + "103:54": -9288933, + "104:54": -9288933, + "105:54": -9288933, + "106:54": 268435456, + "107:54": 402653184, + "108:54": 268435456, + "109:54": 402653184, + "110:54": 268435456, + "111:54": 402653184, + "112:54": 268435456, + "113:54": 402653184, + "114:54": 268435456, + "115:54": 402653184, + "116:54": 268435456, + "117:54": 402653184, + "118:54": 268435456, + "119:54": 402653184, + "120:54": 268435456, + "121:54": 402653184, + "122:54": 268435456, + "123:54": 402653184, + "124:54": 268435456, + "125:54": 402653184, + "126:54": 268435456, + "127:54": 402653184, + "0:55": 402653184, + "1:55": 268435456, + "2:55": 402653184, + "3:55": 268435456, + "4:55": 402653184, + "5:55": 268435456, + "6:55": 402653184, + "7:55": 268435456, + "8:55": 402653184, + "9:55": 268435456, + "10:55": 402653184, + "11:55": 268435456, + "12:55": 402653184, + "13:55": 268435456, + "14:55": 402653184, + "15:55": 268435456, + "16:55": 402653184, + "17:55": 268435456, + "18:55": 402653184, + "19:55": 268435456, + "20:55": 402653184, + "21:55": 268435456, + "22:55": -5092136, + "23:55": -5092136, + "24:55": -5092136, + "25:55": -5092136, + "26:55": -5092136, + "27:55": -5092136, + "28:55": -5092136, + "29:55": -5092136, + "30:55": -5092136, + "31:55": -5092136, + "32:55": -5092136, + "33:55": -5092136, + "34:55": -5092136, + "35:55": -5092136, + "36:55": -5092136, + "37:55": -5092136, + "38:55": -5092136, + "39:55": -5092136, + "40:55": 402653184, + "41:55": 268435456, + "42:55": 402653184, + "43:55": 268435456, + "44:55": -884827, + "45:55": -884827, + "46:55": -884827, + "47:55": -884827, + "48:55": -884827, + "49:55": -884827, + "50:55": -884827, + "51:55": -884827, + "52:55": -884827, + "53:55": -884827, + "54:55": -884827, + "55:55": -884827, + "56:55": -884827, + "57:55": -884827, + "58:55": -884827, + "59:55": -884827, + "60:55": -884827, + "61:55": -884827, + "62:55": 402653184, + "63:55": 268435456, + "64:55": 402653184, + "65:55": 268435456, + "66:55": -9288933, + "67:55": -9288933, + "68:55": -9288933, + "69:55": -9288933, + "70:55": -9288933, + "71:55": -9288933, + "72:55": -9288933, + "73:55": -9288933, + "74:55": -9288933, + "75:55": -9288933, + "76:55": -9288933, + "77:55": -9288933, + "78:55": -9288933, + "79:55": -9288933, + "80:55": -9288933, + "81:55": -9288933, + "82:55": -9288933, + "83:55": -9288933, + "84:55": 402653184, + "85:55": 268435456, + "86:55": 402653184, + "87:55": 268435456, + "88:55": -9288933, + "89:55": -9288933, + "90:55": -9288933, + "91:55": -9288933, + "92:55": -9288933, + "93:55": -9288933, + "94:55": -9288933, + "95:55": -9288933, + "96:55": -9288933, + "97:55": -9288933, + "98:55": -9288933, + "99:55": -9288933, + "100:55": -9288933, + "101:55": -9288933, + "102:55": -9288933, + "103:55": -9288933, + "104:55": -9288933, + "105:55": -9288933, + "106:55": 402653184, + "107:55": 268435456, + "108:55": 402653184, + "109:55": 268435456, + "110:55": 402653184, + "111:55": 268435456, + "112:55": 402653184, + "113:55": 268435456, + "114:55": 402653184, + "115:55": 268435456, + "116:55": 402653184, + "117:55": 268435456, + "118:55": 402653184, + "119:55": 268435456, + "120:55": 402653184, + "121:55": 268435456, + "122:55": 402653184, + "123:55": 268435456, + "124:55": 402653184, + "125:55": 268435456, + "126:55": 402653184, + "127:55": 268435456, + "0:56": 268435456, + "1:56": 402653184, + "2:56": 268435456, + "3:56": 402653184, + "4:56": 268435456, + "5:56": 402653184, + "6:56": 268435456, + "7:56": 402653184, + "8:56": 268435456, + "9:56": 402653184, + "10:56": 268435456, + "11:56": 402653184, + "12:56": 268435456, + "13:56": 402653184, + "14:56": 268435456, + "15:56": 402653184, + "16:56": 268435456, + "17:56": 402653184, + "18:56": 268435456, + "19:56": 402653184, + "20:56": 268435456, + "21:56": 402653184, + "22:56": -5092136, + "23:56": -5092136, + "24:56": -5092136, + "25:56": -5092136, + "26:56": -5092136, + "27:56": -5092136, + "28:56": -5092136, + "29:56": -5092136, + "30:56": -5092136, + "31:56": -5092136, + "32:56": -5092136, + "33:56": -5092136, + "34:56": -5092136, + "35:56": -5092136, + "36:56": -5092136, + "37:56": -5092136, + "38:56": -5092136, + "39:56": -5092136, + "40:56": 268435456, + "41:56": 402653184, + "42:56": 268435456, + "43:56": 402653184, + "44:56": -884827, + "45:56": -884827, + "46:56": -884827, + "47:56": -884827, + "48:56": -884827, + "49:56": -884827, + "50:56": -884827, + "51:56": -884827, + "52:56": -884827, + "53:56": -884827, + "54:56": -884827, + "55:56": -884827, + "56:56": -884827, + "57:56": -884827, + "58:56": -884827, + "59:56": -884827, + "60:56": -884827, + "61:56": -884827, + "62:56": 268435456, + "63:56": 402653184, + "64:56": 268435456, + "65:56": 402653184, + "66:56": -9288933, + "67:56": -9288933, + "68:56": -9288933, + "69:56": -9288933, + "70:56": -9288933, + "71:56": -9288933, + "72:56": -9288933, + "73:56": -9288933, + "74:56": -9288933, + "75:56": -9288933, + "76:56": -9288933, + "77:56": -9288933, + "78:56": -9288933, + "79:56": -9288933, + "80:56": -9288933, + "81:56": -9288933, + "82:56": -9288933, + "83:56": -9288933, + "84:56": 268435456, + "85:56": 402653184, + "86:56": 268435456, + "87:56": 402653184, + "88:56": -9288933, + "89:56": -9288933, + "90:56": -9288933, + "91:56": -9288933, + "92:56": -9288933, + "93:56": -9288933, + "94:56": -9288933, + "95:56": -9288933, + "96:56": -9288933, + "97:56": -9288933, + "98:56": -9288933, + "99:56": -9288933, + "100:56": -9288933, + "101:56": -9288933, + "102:56": -9288933, + "103:56": -9288933, + "104:56": -9288933, + "105:56": -9288933, + "106:56": 268435456, + "107:56": 402653184, + "108:56": 268435456, + "109:56": 402653184, + "110:56": 268435456, + "111:56": 402653184, + "112:56": 268435456, + "113:56": 402653184, + "114:56": 268435456, + "115:56": 402653184, + "116:56": 268435456, + "117:56": 402653184, + "118:56": 268435456, + "119:56": 402653184, + "120:56": 268435456, + "121:56": 402653184, + "122:56": 268435456, + "123:56": 402653184, + "124:56": 268435456, + "125:56": 402653184, + "126:56": 268435456, + "127:56": 402653184, + "0:57": 402653184, + "1:57": 268435456, + "2:57": 402653184, + "3:57": 268435456, + "4:57": 402653184, + "5:57": 268435456, + "6:57": 402653184, + "7:57": 268435456, + "8:57": 402653184, + "9:57": 268435456, + "10:57": 402653184, + "11:57": 268435456, + "12:57": 402653184, + "13:57": 268435456, + "14:57": 402653184, + "15:57": 268435456, + "16:57": 402653184, + "17:57": 268435456, + "18:57": 402653184, + "19:57": 268435456, + "20:57": 402653184, + "21:57": 268435456, + "22:57": -5092136, + "23:57": -5092136, + "24:57": -5092136, + "25:57": -5092136, + "26:57": -5092136, + "27:57": -5092136, + "28:57": -5092136, + "29:57": -5092136, + "30:57": -5092136, + "31:57": -5092136, + "32:57": -5092136, + "33:57": -5092136, + "34:57": -5092136, + "35:57": -5092136, + "36:57": -5092136, + "37:57": -5092136, + "38:57": -5092136, + "39:57": -5092136, + "40:57": 402653184, + "41:57": 268435456, + "42:57": 402653184, + "43:57": 268435456, + "44:57": -884827, + "45:57": -884827, + "46:57": -884827, + "47:57": -884827, + "48:57": -884827, + "49:57": -884827, + "50:57": -884827, + "51:57": -884827, + "52:57": -884827, + "53:57": -884827, + "54:57": -884827, + "55:57": -884827, + "56:57": -884827, + "57:57": -884827, + "58:57": -884827, + "59:57": -884827, + "60:57": -884827, + "61:57": -884827, + "62:57": 402653184, + "63:57": 268435456, + "64:57": 402653184, + "65:57": 268435456, + "66:57": -9288933, + "67:57": -9288933, + "68:57": -9288933, + "69:57": -9288933, + "70:57": -9288933, + "71:57": -9288933, + "72:57": -9288933, + "73:57": -9288933, + "74:57": -9288933, + "75:57": -9288933, + "76:57": -9288933, + "77:57": -9288933, + "78:57": -9288933, + "79:57": -9288933, + "80:57": -9288933, + "81:57": -9288933, + "82:57": -9288933, + "83:57": -9288933, + "84:57": 402653184, + "85:57": 268435456, + "86:57": 402653184, + "87:57": 268435456, + "88:57": -9288933, + "89:57": -9288933, + "90:57": -9288933, + "91:57": -9288933, + "92:57": -9288933, + "93:57": -9288933, + "94:57": -9288933, + "95:57": -9288933, + "96:57": -9288933, + "97:57": -9288933, + "98:57": -9288933, + "99:57": -9288933, + "100:57": -9288933, + "101:57": -9288933, + "102:57": -9288933, + "103:57": -9288933, + "104:57": -9288933, + "105:57": -9288933, + "106:57": 402653184, + "107:57": 268435456, + "108:57": 402653184, + "109:57": 268435456, + "110:57": 402653184, + "111:57": 268435456, + "112:57": 402653184, + "113:57": 268435456, + "114:57": 402653184, + "115:57": 268435456, + "116:57": 402653184, + "117:57": 268435456, + "118:57": 402653184, + "119:57": 268435456, + "120:57": 402653184, + "121:57": 268435456, + "122:57": 402653184, + "123:57": 268435456, + "124:57": 402653184, + "125:57": 268435456, + "126:57": 402653184, + "127:57": 268435456, + "0:58": 268435456, + "1:58": 402653184, + "2:58": 268435456, + "3:58": 402653184, + "4:58": 268435456, + "5:58": 402653184, + "6:58": 268435456, + "7:58": 402653184, + "8:58": 268435456, + "9:58": 402653184, + "10:58": 268435456, + "11:58": 402653184, + "12:58": 268435456, + "13:58": 402653184, + "14:58": 268435456, + "15:58": 402653184, + "16:58": 268435456, + "17:58": 402653184, + "18:58": 268435456, + "19:58": 402653184, + "20:58": 268435456, + "21:58": 402653184, + "22:58": -5092136, + "23:58": -5092136, + "24:58": -5092136, + "25:58": -5092136, + "26:58": -5092136, + "27:58": -5092136, + "28:58": -5092136, + "29:58": -5092136, + "30:58": -5092136, + "31:58": -5092136, + "32:58": -5092136, + "33:58": -5092136, + "34:58": -5092136, + "35:58": -5092136, + "36:58": -5092136, + "37:58": -5092136, + "38:58": -5092136, + "39:58": -5092136, + "40:58": 268435456, + "41:58": 402653184, + "42:58": 268435456, + "43:58": 402653184, + "44:58": -884827, + "45:58": -884827, + "46:58": -884827, + "47:58": -884827, + "48:58": -884827, + "49:58": -884827, + "50:58": -884827, + "51:58": -884827, + "52:58": -884827, + "53:58": -884827, + "54:58": -884827, + "55:58": -884827, + "56:58": -884827, + "57:58": -884827, + "58:58": -884827, + "59:58": -884827, + "60:58": -884827, + "61:58": -884827, + "62:58": 268435456, + "63:58": 402653184, + "64:58": 268435456, + "65:58": 402653184, + "66:58": -9288933, + "67:58": -9288933, + "68:58": -9288933, + "69:58": -9288933, + "70:58": -9288933, + "71:58": -9288933, + "72:58": -9288933, + "73:58": -9288933, + "74:58": -9288933, + "75:58": -9288933, + "76:58": -9288933, + "77:58": -9288933, + "78:58": -9288933, + "79:58": -9288933, + "80:58": -9288933, + "81:58": -9288933, + "82:58": -9288933, + "83:58": -9288933, + "84:58": 268435456, + "85:58": 402653184, + "86:58": 268435456, + "87:58": 402653184, + "88:58": -9288933, + "89:58": -9288933, + "90:58": -9288933, + "91:58": -9288933, + "92:58": -9288933, + "93:58": -9288933, + "94:58": -9288933, + "95:58": -9288933, + "96:58": -9288933, + "97:58": -9288933, + "98:58": -9288933, + "99:58": -9288933, + "100:58": -9288933, + "101:58": -9288933, + "102:58": -9288933, + "103:58": -9288933, + "104:58": -9288933, + "105:58": -9288933, + "106:58": 268435456, + "107:58": 402653184, + "108:58": 268435456, + "109:58": 402653184, + "110:58": 268435456, + "111:58": 402653184, + "112:58": 268435456, + "113:58": 402653184, + "114:58": 268435456, + "115:58": 402653184, + "116:58": 268435456, + "117:58": 402653184, + "118:58": 268435456, + "119:58": 402653184, + "120:58": 268435456, + "121:58": 402653184, + "122:58": 268435456, + "123:58": 402653184, + "124:58": 268435456, + "125:58": 402653184, + "126:58": 268435456, + "127:58": 402653184, + "0:59": 402653184, + "1:59": 268435456, + "2:59": 402653184, + "3:59": 268435456, + "4:59": 402653184, + "5:59": 268435456, + "6:59": 402653184, + "7:59": 268435456, + "8:59": 402653184, + "9:59": 268435456, + "10:59": 402653184, + "11:59": 268435456, + "12:59": 402653184, + "13:59": 268435456, + "14:59": 402653184, + "15:59": 268435456, + "16:59": 402653184, + "17:59": 268435456, + "18:59": 402653184, + "19:59": 268435456, + "20:59": 402653184, + "21:59": 268435456, + "22:59": -5092136, + "23:59": -5092136, + "24:59": -5092136, + "25:59": -5092136, + "26:59": -5092136, + "27:59": -5092136, + "28:59": -5092136, + "29:59": -5092136, + "30:59": -5092136, + "31:59": -5092136, + "32:59": -5092136, + "33:59": -5092136, + "34:59": -5092136, + "35:59": -5092136, + "36:59": -5092136, + "37:59": -5092136, + "38:59": -5092136, + "39:59": -5092136, + "40:59": 402653184, + "41:59": 268435456, + "42:59": 402653184, + "43:59": 268435456, + "44:59": -884827, + "45:59": -884827, + "46:59": -884827, + "47:59": -884827, + "48:59": -884827, + "49:59": -884827, + "50:59": -884827, + "51:59": -884827, + "52:59": -884827, + "53:59": -884827, + "54:59": -884827, + "55:59": -884827, + "56:59": -884827, + "57:59": -884827, + "58:59": -884827, + "59:59": -884827, + "60:59": -884827, + "61:59": -884827, + "62:59": 402653184, + "63:59": 268435456, + "64:59": 402653184, + "65:59": 268435456, + "66:59": -9288933, + "67:59": -9288933, + "68:59": -9288933, + "69:59": -9288933, + "70:59": -9288933, + "71:59": -9288933, + "72:59": -9288933, + "73:59": -9288933, + "74:59": -9288933, + "75:59": -9288933, + "76:59": -9288933, + "77:59": -9288933, + "78:59": -9288933, + "79:59": -9288933, + "80:59": -9288933, + "81:59": -9288933, + "82:59": -9288933, + "83:59": -9288933, + "84:59": 402653184, + "85:59": 268435456, + "86:59": 402653184, + "87:59": 268435456, + "88:59": -9288933, + "89:59": -9288933, + "90:59": -9288933, + "91:59": -9288933, + "92:59": -9288933, + "93:59": -9288933, + "94:59": -9288933, + "95:59": -9288933, + "96:59": -9288933, + "97:59": -9288933, + "98:59": -9288933, + "99:59": -9288933, + "100:59": -9288933, + "101:59": -9288933, + "102:59": -9288933, + "103:59": -9288933, + "104:59": -9288933, + "105:59": -9288933, + "106:59": 402653184, + "107:59": 268435456, + "108:59": 402653184, + "109:59": 268435456, + "110:59": 402653184, + "111:59": 268435456, + "112:59": 402653184, + "113:59": 268435456, + "114:59": 402653184, + "115:59": 268435456, + "116:59": 402653184, + "117:59": 268435456, + "118:59": 402653184, + "119:59": 268435456, + "120:59": 402653184, + "121:59": 268435456, + "122:59": 402653184, + "123:59": 268435456, + "124:59": 402653184, + "125:59": 268435456, + "126:59": 402653184, + "127:59": 268435456, + "0:60": 268435456, + "1:60": 402653184, + "2:60": 268435456, + "3:60": 402653184, + "4:60": 268435456, + "5:60": 402653184, + "6:60": 268435456, + "7:60": 402653184, + "8:60": 268435456, + "9:60": 402653184, + "10:60": 268435456, + "11:60": 402653184, + "12:60": 268435456, + "13:60": 402653184, + "14:60": 268435456, + "15:60": 402653184, + "16:60": 268435456, + "17:60": 402653184, + "18:60": 268435456, + "19:60": 402653184, + "20:60": 268435456, + "21:60": 402653184, + "22:60": -5092136, + "23:60": -5092136, + "24:60": -5092136, + "25:60": -5092136, + "26:60": -5092136, + "27:60": -5092136, + "28:60": -5092136, + "29:60": -5092136, + "30:60": -5092136, + "31:60": -5092136, + "32:60": -5092136, + "33:60": -5092136, + "34:60": -5092136, + "35:60": -5092136, + "36:60": -5092136, + "37:60": -5092136, + "38:60": -5092136, + "39:60": -5092136, + "40:60": 268435456, + "41:60": 402653184, + "42:60": 268435456, + "43:60": 402653184, + "44:60": -884827, + "45:60": -884827, + "46:60": -884827, + "47:60": -884827, + "48:60": -884827, + "49:60": -884827, + "50:60": -884827, + "51:60": -884827, + "52:60": -884827, + "53:60": -884827, + "54:60": -884827, + "55:60": -884827, + "56:60": -884827, + "57:60": -884827, + "58:60": -884827, + "59:60": -884827, + "60:60": -884827, + "61:60": -884827, + "62:60": 268435456, + "63:60": 402653184, + "64:60": 268435456, + "65:60": 402653184, + "66:60": -9288933, + "67:60": -9288933, + "68:60": -9288933, + "69:60": -9288933, + "70:60": -9288933, + "71:60": -9288933, + "72:60": -9288933, + "73:60": -9288933, + "74:60": -9288933, + "75:60": -9288933, + "76:60": -9288933, + "77:60": -9288933, + "78:60": -9288933, + "79:60": -9288933, + "80:60": -9288933, + "81:60": -9288933, + "82:60": -9288933, + "83:60": -9288933, + "84:60": 268435456, + "85:60": 402653184, + "86:60": 268435456, + "87:60": 402653184, + "88:60": -9288933, + "89:60": -9288933, + "90:60": -9288933, + "91:60": -9288933, + "92:60": -9288933, + "93:60": -9288933, + "94:60": -9288933, + "95:60": -9288933, + "96:60": -9288933, + "97:60": -9288933, + "98:60": -9288933, + "99:60": -9288933, + "100:60": -9288933, + "101:60": -9288933, + "102:60": -9288933, + "103:60": -9288933, + "104:60": -9288933, + "105:60": -9288933, + "106:60": 268435456, + "107:60": 402653184, + "108:60": 268435456, + "109:60": 402653184, + "110:60": 268435456, + "111:60": 402653184, + "112:60": 268435456, + "113:60": 402653184, + "114:60": 268435456, + "115:60": 402653184, + "116:60": 268435456, + "117:60": 402653184, + "118:60": 268435456, + "119:60": 402653184, + "120:60": 268435456, + "121:60": 402653184, + "122:60": 268435456, + "123:60": 402653184, + "124:60": 268435456, + "125:60": 402653184, + "126:60": 268435456, + "127:60": 402653184, + "0:61": 402653184, + "1:61": 268435456, + "2:61": 402653184, + "3:61": 268435456, + "4:61": 402653184, + "5:61": 268435456, + "6:61": 402653184, + "7:61": 268435456, + "8:61": 402653184, + "9:61": 268435456, + "10:61": 402653184, + "11:61": 268435456, + "12:61": 402653184, + "13:61": 268435456, + "14:61": 402653184, + "15:61": 268435456, + "16:61": 402653184, + "17:61": 268435456, + "18:61": 402653184, + "19:61": 268435456, + "20:61": 402653184, + "21:61": 268435456, + "22:61": -5092136, + "23:61": -5092136, + "24:61": -5092136, + "25:61": -5092136, + "26:61": -5092136, + "27:61": -5092136, + "28:61": -5092136, + "29:61": -5092136, + "30:61": -5092136, + "31:61": -5092136, + "32:61": -5092136, + "33:61": -5092136, + "34:61": -5092136, + "35:61": -5092136, + "36:61": -5092136, + "37:61": -5092136, + "38:61": -5092136, + "39:61": -5092136, + "40:61": -5092136, + "41:61": -5092136, + "42:61": -5092136, + "43:61": -5092136, + "44:61": -884827, + "45:61": -884827, + "46:61": -884827, + "47:61": -884827, + "48:61": -884827, + "49:61": -884827, + "50:61": -884827, + "51:61": -884827, + "52:61": -884827, + "53:61": -884827, + "54:61": -884827, + "55:61": -884827, + "56:61": -884827, + "57:61": -884827, + "58:61": -884827, + "59:61": -884827, + "60:61": -884827, + "61:61": -884827, + "62:61": -9288933, + "63:61": -9288933, + "64:61": -9288933, + "65:61": -9288933, + "66:61": -9288933, + "67:61": -9288933, + "68:61": -9288933, + "69:61": -9288933, + "70:61": -9288933, + "71:61": -9288933, + "72:61": -9288933, + "73:61": -9288933, + "74:61": -9288933, + "75:61": -9288933, + "76:61": -9288933, + "77:61": -9288933, + "78:61": -9288933, + "79:61": -9288933, + "80:61": -9288933, + "81:61": -9288933, + "82:61": -9288933, + "83:61": -9288933, + "84:61": -9288933, + "85:61": -9288933, + "86:61": -9288933, + "87:61": -9288933, + "88:61": -9288933, + "89:61": -9288933, + "90:61": -9288933, + "91:61": -9288933, + "92:61": -9288933, + "93:61": -9288933, + "94:61": -9288933, + "95:61": -9288933, + "96:61": -9288933, + "97:61": -9288933, + "98:61": -9288933, + "99:61": -9288933, + "100:61": -9288933, + "101:61": -9288933, + "102:61": -9288933, + "103:61": -9288933, + "104:61": -9288933, + "105:61": -9288933, + "106:61": 402653184, + "107:61": 268435456, + "108:61": 402653184, + "109:61": 268435456, + "110:61": 402653184, + "111:61": 268435456, + "112:61": 402653184, + "113:61": 268435456, + "114:61": 402653184, + "115:61": 268435456, + "116:61": 402653184, + "117:61": 268435456, + "118:61": 402653184, + "119:61": 268435456, + "120:61": 402653184, + "121:61": 268435456, + "122:61": 402653184, + "123:61": 268435456, + "124:61": 402653184, + "125:61": 268435456, + "126:61": 402653184, + "127:61": 268435456, + "0:62": 268435456, + "1:62": 402653184, + "2:62": 268435456, + "3:62": 402653184, + "4:62": 268435456, + "5:62": 402653184, + "6:62": 268435456, + "7:62": 402653184, + "8:62": 268435456, + "9:62": 402653184, + "10:62": 268435456, + "11:62": 402653184, + "12:62": 268435456, + "13:62": 402653184, + "14:62": 268435456, + "15:62": 402653184, + "16:62": 268435456, + "17:62": 402653184, + "18:62": 268435456, + "19:62": 402653184, + "20:62": 268435456, + "21:62": 402653184, + "22:62": -5092136, + "23:62": -5092136, + "24:62": -5092136, + "25:62": -5092136, + "26:62": -5092136, + "27:62": -5092136, + "28:62": -5092136, + "29:62": -5092136, + "30:62": -5092136, + "31:62": -5092136, + "32:62": -16745472, + "33:62": -16745472, + "34:62": -16745472, + "35:62": -5092136, + "36:62": -5092136, + "37:62": -5092136, + "38:62": -5092136, + "39:62": -5092136, + "40:62": -5092136, + "41:62": -5092136, + "42:62": -5092136, + "43:62": -5092136, + "44:62": -884827, + "45:62": -884827, + "46:62": -884827, + "47:62": -884827, + "48:62": -884827, + "49:62": -884827, + "50:62": -884827, + "51:62": -884827, + "52:62": -884827, + "53:62": -884827, + "54:62": -16745472, + "55:62": -16745472, + "56:62": -16745472, + "57:62": -884827, + "58:62": -884827, + "59:62": -884827, + "60:62": -884827, + "61:62": -884827, + "62:62": -9288933, + "63:62": -9288933, + "64:62": -9288933, + "65:62": -9288933, + "66:62": -9288933, + "67:62": -9288933, + "68:62": -9288933, + "69:62": -9288933, + "70:62": -9288933, + "71:62": -9288933, + "72:62": -9288933, + "73:62": -9288933, + "74:62": -9288933, + "75:62": -9288933, + "76:62": -9288933, + "77:62": -9288933, + "78:62": -9288933, + "79:62": -9288933, + "80:62": -9288933, + "81:62": -9288933, + "82:62": -9288933, + "83:62": -9288933, + "84:62": -9288933, + "85:62": -9288933, + "86:62": -9288933, + "87:62": -9288933, + "88:62": -9288933, + "89:62": -9288933, + "90:62": -9288933, + "91:62": -9288933, + "92:62": -9288933, + "93:62": -9288933, + "94:62": -9288933, + "95:62": -9288933, + "96:62": -9288933, + "97:62": -9288933, + "98:62": -9288933, + "99:62": -9288933, + "100:62": -9288933, + "101:62": -9288933, + "102:62": -9288933, + "103:62": -9288933, + "104:62": -9288933, + "105:62": -9288933, + "106:62": 268435456, + "107:62": 402653184, + "108:62": 268435456, + "109:62": 402653184, + "110:62": 268435456, + "111:62": 402653184, + "112:62": 268435456, + "113:62": 402653184, + "114:62": 268435456, + "115:62": 402653184, + "116:62": 268435456, + "117:62": 402653184, + "118:62": 268435456, + "119:62": 402653184, + "120:62": 268435456, + "121:62": 402653184, + "122:62": 268435456, + "123:62": 402653184, + "124:62": 268435456, + "125:62": 402653184, + "126:62": 268435456, + "127:62": 402653184, + "0:63": 402653184, + "1:63": 268435456, + "2:63": 402653184, + "3:63": 268435456, + "4:63": 402653184, + "5:63": 268435456, + "6:63": 402653184, + "7:63": 268435456, + "8:63": 402653184, + "9:63": 268435456, + "10:63": 402653184, + "11:63": 268435456, + "12:63": 402653184, + "13:63": 268435456, + "14:63": 402653184, + "15:63": 268435456, + "16:63": 402653184, + "17:63": 268435456, + "18:63": 402653184, + "19:63": 268435456, + "20:63": 402653184, + "21:63": 268435456, + "22:63": -5092136, + "23:63": -5092136, + "24:63": -5092136, + "25:63": -5092136, + "26:63": -5092136, + "27:63": -5092136, + "28:63": -5092136, + "29:63": -5092136, + "30:63": -5092136, + "31:63": -16745472, + "32:63": -16745472, + "33:63": -16745472, + "34:63": -5092136, + "35:63": -5092136, + "36:63": -5092136, + "37:63": -5092136, + "38:63": -5092136, + "39:63": -5092136, + "40:63": -5092136, + "41:63": -5092136, + "42:63": -5092136, + "43:63": -5092136, + "44:63": -884827, + "45:63": -884827, + "46:63": -884827, + "47:63": -884827, + "48:63": -884827, + "49:63": -884827, + "50:63": -884827, + "51:63": -884827, + "52:63": -884827, + "53:63": -16745472, + "54:63": -16745472, + "55:63": -16745472, + "56:63": -884827, + "57:63": -884827, + "58:63": -884827, + "59:63": -884827, + "60:63": -884827, + "61:63": -884827, + "62:63": -9288933, + "63:63": -9288933, + "64:63": -9288933, + "65:63": -9288933, + "66:63": -9288933, + "67:63": -9288933, + "68:63": -9288933, + "69:63": -9288933, + "70:63": -9288933, + "71:63": -9288933, + "72:63": -9288933, + "73:63": -9288933, + "74:63": -9288933, + "75:63": -9288933, + "76:63": -9288933, + "77:63": -9288933, + "78:63": -9288933, + "79:63": -9288933, + "80:63": -9288933, + "81:63": -9288933, + "82:63": -9288933, + "83:63": -9288933, + "84:63": -9288933, + "85:63": -9288933, + "86:63": -9288933, + "87:63": -9288933, + "88:63": -9288933, + "89:63": -9288933, + "90:63": -9288933, + "91:63": -9288933, + "92:63": -9288933, + "93:63": -9288933, + "94:63": -9288933, + "95:63": -9288933, + "96:63": -9288933, + "97:63": -9288933, + "98:63": -9288933, + "99:63": -9288933, + "100:63": -9288933, + "101:63": -9288933, + "102:63": -9288933, + "103:63": -9288933, + "104:63": -9288933, + "105:63": -9288933, + "106:63": 402653184, + "107:63": 268435456, + "108:63": 402653184, + "109:63": 268435456, + "110:63": 402653184, + "111:63": 268435456, + "112:63": 402653184, + "113:63": 268435456, + "114:63": 402653184, + "115:63": 268435456, + "116:63": 402653184, + "117:63": 268435456, + "118:63": 402653184, + "119:63": 268435456, + "120:63": 402653184, + "121:63": 268435456, + "122:63": 402653184, + "123:63": 268435456, + "124:63": 402653184, + "125:63": 268435456, + "126:63": 402653184, + "127:63": 268435456, + "0:64": 268435456, + "1:64": 402653184, + "2:64": 268435456, + "3:64": 402653184, + "4:64": 268435456, + "5:64": 402653184, + "6:64": 268435456, + "7:64": 402653184, + "8:64": 268435456, + "9:64": 402653184, + "10:64": 268435456, + "11:64": 402653184, + "12:64": 268435456, + "13:64": 402653184, + "14:64": 268435456, + "15:64": 402653184, + "16:64": 268435456, + "17:64": 402653184, + "18:64": 268435456, + "19:64": 402653184, + "20:64": 268435456, + "21:64": 402653184, + "22:64": -5092136, + "23:64": -5092136, + "24:64": -5092136, + "25:64": -5092136, + "26:64": -5092136, + "27:64": -5092136, + "28:64": -5092136, + "29:64": -5092136, + "30:64": -5092136, + "31:64": -16745472, + "32:64": -16745472, + "33:64": -5092136, + "34:64": -5092136, + "35:64": -5092136, + "36:64": -5092136, + "37:64": -5092136, + "38:64": -5092136, + "39:64": -5092136, + "40:64": -5092136, + "41:64": -5092136, + "42:64": -5092136, + "43:64": -5092136, + "44:64": -884827, + "45:64": -884827, + "46:64": -884827, + "47:64": -884827, + "48:64": -884827, + "49:64": -884827, + "50:64": -884827, + "51:64": -884827, + "52:64": -884827, + "53:64": -16745472, + "54:64": -16745472, + "55:64": -884827, + "56:64": -884827, + "57:64": -884827, + "58:64": -884827, + "59:64": -884827, + "60:64": -884827, + "61:64": -884827, + "62:64": -9288933, + "63:64": -9288933, + "64:64": -9288933, + "65:64": -9288933, + "66:64": -9288933, + "67:64": -9288933, + "68:64": -9288933, + "69:64": -9288933, + "70:64": -9288933, + "71:64": -9288933, + "72:64": -9288933, + "73:64": -9288933, + "74:64": -9288933, + "75:64": -9288933, + "76:64": -9288933, + "77:64": -9288933, + "78:64": -9288933, + "79:64": -9288933, + "80:64": -9288933, + "81:64": -9288933, + "82:64": -9288933, + "83:64": -9288933, + "84:64": -9288933, + "85:64": -9288933, + "86:64": -9288933, + "87:64": -9288933, + "88:64": -9288933, + "89:64": -9288933, + "90:64": -9288933, + "91:64": -9288933, + "92:64": -9288933, + "93:64": -9288933, + "94:64": -9288933, + "95:64": -9288933, + "96:64": -9288933, + "97:64": -9288933, + "98:64": -9288933, + "99:64": -9288933, + "100:64": -9288933, + "101:64": -9288933, + "102:64": -9288933, + "103:64": -9288933, + "104:64": -9288933, + "105:64": -9288933, + "106:64": 268435456, + "107:64": 402653184, + "108:64": 268435456, + "109:64": 402653184, + "110:64": 268435456, + "111:64": 402653184, + "112:64": 268435456, + "113:64": 402653184, + "114:64": 268435456, + "115:64": 402653184, + "116:64": 268435456, + "117:64": 402653184, + "118:64": 268435456, + "119:64": 402653184, + "120:64": 268435456, + "121:64": 402653184, + "122:64": 268435456, + "123:64": 402653184, + "124:64": 268435456, + "125:64": 402653184, + "126:64": 268435456, + "127:64": 402653184, + "0:65": 402653184, + "1:65": 268435456, + "2:65": 402653184, + "3:65": 268435456, + "4:65": 402653184, + "5:65": 268435456, + "6:65": 402653184, + "7:65": 268435456, + "8:65": 402653184, + "9:65": 268435456, + "10:65": 402653184, + "11:65": 268435456, + "12:65": 402653184, + "13:65": 268435456, + "14:65": 402653184, + "15:65": 268435456, + "16:65": 402653184, + "17:65": 268435456, + "18:65": 402653184, + "19:65": 268435456, + "20:65": 402653184, + "21:65": 268435456, + "22:65": -5092136, + "23:65": -5092136, + "24:65": -5092136, + "25:65": -5092136, + "26:65": -5092136, + "27:65": -5092136, + "28:65": -16745472, + "29:65": -16745472, + "30:65": -5092136, + "31:65": -16745472, + "32:65": -16745472, + "33:65": -5092136, + "34:65": -5092136, + "35:65": -5092136, + "36:65": -5092136, + "37:65": -5092136, + "38:65": -5092136, + "39:65": -5092136, + "40:65": -5092136, + "41:65": -5092136, + "42:65": -5092136, + "43:65": -5092136, + "44:65": -884827, + "45:65": -884827, + "46:65": -884827, + "47:65": -884827, + "48:65": -884827, + "49:65": -884827, + "50:65": -16745472, + "51:65": -16745472, + "52:65": -884827, + "53:65": -16745472, + "54:65": -16745472, + "55:65": -884827, + "56:65": -884827, + "57:65": -884827, + "58:65": -884827, + "59:65": -884827, + "60:65": -884827, + "61:65": -884827, + "62:65": -9288933, + "63:65": -9288933, + "64:65": -9288933, + "65:65": -9288933, + "66:65": -9288933, + "67:65": -9288933, + "68:65": -9288933, + "69:65": -9288933, + "70:65": -9288933, + "71:65": -9288933, + "72:65": -9288933, + "73:65": -9288933, + "74:65": -9288933, + "75:65": -9288933, + "76:65": -9288933, + "77:65": -9288933, + "78:65": -9288933, + "79:65": -9288933, + "80:65": -9288933, + "81:65": -9288933, + "82:65": -9288933, + "83:65": -9288933, + "84:65": -9288933, + "85:65": -9288933, + "86:65": -9288933, + "87:65": -9288933, + "88:65": -9288933, + "89:65": -9288933, + "90:65": -9288933, + "91:65": -9288933, + "92:65": -9288933, + "93:65": -9288933, + "94:65": -9288933, + "95:65": -9288933, + "96:65": -9288933, + "97:65": -9288933, + "98:65": -9288933, + "99:65": -9288933, + "100:65": -9288933, + "101:65": -9288933, + "102:65": -9288933, + "103:65": -9288933, + "104:65": -9288933, + "105:65": -9288933, + "106:65": 402653184, + "107:65": 268435456, + "108:65": 402653184, + "109:65": 268435456, + "110:65": 402653184, + "111:65": 268435456, + "112:65": 402653184, + "113:65": 268435456, + "114:65": 402653184, + "115:65": 268435456, + "116:65": 402653184, + "117:65": 268435456, + "118:65": 402653184, + "119:65": 268435456, + "120:65": 402653184, + "121:65": 268435456, + "122:65": 402653184, + "123:65": 268435456, + "124:65": 402653184, + "125:65": 268435456, + "126:65": 402653184, + "127:65": 268435456, + "0:66": 268435456, + "1:66": 402653184, + "2:66": 268435456, + "3:66": 402653184, + "4:66": 268435456, + "5:66": 402653184, + "6:66": 268435456, + "7:66": 402653184, + "8:66": 268435456, + "9:66": 402653184, + "10:66": 268435456, + "11:66": 402653184, + "12:66": 268435456, + "13:66": 402653184, + "14:66": 268435456, + "15:66": 402653184, + "16:66": 268435456, + "17:66": 402653184, + "18:66": 268435456, + "19:66": 402653184, + "20:66": 268435456, + "21:66": 402653184, + "22:66": -5092136, + "23:66": -5092136, + "24:66": -5092136, + "25:66": -5092136, + "26:66": -5092136, + "27:66": -5092136, + "28:66": -5092136, + "29:66": -16745472, + "30:66": -16745472, + "31:66": -16745472, + "32:66": -5092136, + "33:66": -5092136, + "34:66": -5092136, + "35:66": -5092136, + "36:66": -5092136, + "37:66": -5092136, + "38:66": -5092136, + "39:66": -5092136, + "40:66": -5092136, + "41:66": -5092136, + "42:66": -5092136, + "43:66": -5092136, + "44:66": -884827, + "45:66": -884827, + "46:66": -884827, + "47:66": -884827, + "48:66": -884827, + "49:66": -884827, + "50:66": -884827, + "51:66": -16745472, + "52:66": -16745472, + "53:66": -16745472, + "54:66": -884827, + "55:66": -884827, + "56:66": -884827, + "57:66": -884827, + "58:66": -884827, + "59:66": -884827, + "60:66": -884827, + "61:66": -884827, + "62:66": -9288933, + "63:66": -9288933, + "64:66": -9288933, + "65:66": -9288933, + "66:66": -9288933, + "67:66": -9288933, + "68:66": -9288933, + "69:66": -9288933, + "70:66": -9288933, + "71:66": -9288933, + "72:66": -9288933, + "73:66": -9288933, + "74:66": -9288933, + "75:66": -9288933, + "76:66": -9288933, + "77:66": -9288933, + "78:66": -9288933, + "79:66": -9288933, + "80:66": -9288933, + "81:66": -9288933, + "82:66": -9288933, + "83:66": -9288933, + "84:66": -9288933, + "85:66": -9288933, + "86:66": -9288933, + "87:66": -9288933, + "88:66": -9288933, + "89:66": -9288933, + "90:66": -9288933, + "91:66": -9288933, + "92:66": -9288933, + "93:66": -9288933, + "94:66": -9288933, + "95:66": -9288933, + "96:66": -9288933, + "97:66": -9288933, + "98:66": -9288933, + "99:66": -9288933, + "100:66": -9288933, + "101:66": -9288933, + "102:66": -9288933, + "103:66": -9288933, + "104:66": -9288933, + "105:66": -9288933, + "106:66": 268435456, + "107:66": 402653184, + "108:66": 268435456, + "109:66": 402653184, + "110:66": 268435456, + "111:66": 402653184, + "112:66": 268435456, + "113:66": 402653184, + "114:66": 268435456, + "115:66": 402653184, + "116:66": 268435456, + "117:66": 402653184, + "118:66": 268435456, + "119:66": 402653184, + "120:66": 268435456, + "121:66": 402653184, + "122:66": 268435456, + "123:66": 402653184, + "124:66": 268435456, + "125:66": 402653184, + "126:66": 268435456, + "127:66": 402653184, + "0:67": 402653184, + "1:67": 268435456, + "2:67": 402653184, + "3:67": 268435456, + "4:67": 402653184, + "5:67": 268435456, + "6:67": 402653184, + "7:67": 268435456, + "8:67": 402653184, + "9:67": 268435456, + "10:67": 402653184, + "11:67": 268435456, + "12:67": 402653184, + "13:67": 268435456, + "14:67": 402653184, + "15:67": 268435456, + "16:67": 402653184, + "17:67": 268435456, + "18:67": 402653184, + "19:67": 268435456, + "20:67": 402653184, + "21:67": 268435456, + "22:67": -5092136, + "23:67": -5092136, + "24:67": -5092136, + "25:67": -5092136, + "26:67": -5092136, + "27:67": -5092136, + "28:67": -5092136, + "29:67": -16745472, + "30:67": -16745472, + "31:67": -16745472, + "32:67": -5092136, + "33:67": -5092136, + "34:67": -5092136, + "35:67": -5092136, + "36:67": -5092136, + "37:67": -5092136, + "38:67": -5092136, + "39:67": -5092136, + "40:67": -5092136, + "41:67": -5092136, + "42:67": -5092136, + "43:67": -5092136, + "44:67": -884827, + "45:67": -884827, + "46:67": -884827, + "47:67": -884827, + "48:67": -884827, + "49:67": -884827, + "50:67": -884827, + "51:67": -16745472, + "52:67": -16745472, + "53:67": -16745472, + "54:67": -884827, + "55:67": -884827, + "56:67": -884827, + "57:67": -884827, + "58:67": -884827, + "59:67": -884827, + "60:67": -884827, + "61:67": -884827, + "62:67": -9288933, + "63:67": -9288933, + "64:67": -9288933, + "65:67": -9288933, + "66:67": -9288933, + "67:67": -9288933, + "68:67": -9288933, + "69:67": -9288933, + "70:67": -9288933, + "71:67": -9288933, + "72:67": -9288933, + "73:67": -9288933, + "74:67": -9288933, + "75:67": -9288933, + "76:67": -9288933, + "77:67": -9288933, + "78:67": -9288933, + "79:67": -9288933, + "80:67": -9288933, + "81:67": -9288933, + "82:67": -9288933, + "83:67": -9288933, + "84:67": -9288933, + "85:67": -9288933, + "86:67": -9288933, + "87:67": -9288933, + "88:67": -9288933, + "89:67": -9288933, + "90:67": -9288933, + "91:67": -9288933, + "92:67": -9288933, + "93:67": -9288933, + "94:67": -9288933, + "95:67": -9288933, + "96:67": -9288933, + "97:67": -9288933, + "98:67": -9288933, + "99:67": -9288933, + "100:67": -9288933, + "101:67": -9288933, + "102:67": -9288933, + "103:67": -9288933, + "104:67": -9288933, + "105:67": -9288933, + "106:67": 402653184, + "107:67": 268435456, + "108:67": 402653184, + "109:67": 268435456, + "110:67": 402653184, + "111:67": 268435456, + "112:67": 402653184, + "113:67": 268435456, + "114:67": 402653184, + "115:67": 268435456, + "116:67": 402653184, + "117:67": 268435456, + "118:67": 402653184, + "119:67": 268435456, + "120:67": 402653184, + "121:67": 268435456, + "122:67": 402653184, + "123:67": 268435456, + "124:67": 402653184, + "125:67": 268435456, + "126:67": 402653184, + "127:67": 268435456, + "0:68": 268435456, + "1:68": 402653184, + "2:68": 268435456, + "3:68": 402653184, + "4:68": 268435456, + "5:68": 402653184, + "6:68": 268435456, + "7:68": 402653184, + "8:68": 268435456, + "9:68": 402653184, + "10:68": 268435456, + "11:68": 402653184, + "12:68": 268435456, + "13:68": 402653184, + "14:68": 268435456, + "15:68": 402653184, + "16:68": 268435456, + "17:68": 402653184, + "18:68": 268435456, + "19:68": 402653184, + "20:68": 268435456, + "21:68": 402653184, + "22:68": -5092136, + "23:68": -5092136, + "24:68": -5092136, + "25:68": -5092136, + "26:68": -5092136, + "27:68": -5092136, + "28:68": -5092136, + "29:68": -5092136, + "30:68": -5092136, + "31:68": -5092136, + "32:68": -5092136, + "33:68": -5092136, + "34:68": -5092136, + "35:68": -5092136, + "36:68": -5092136, + "37:68": -5092136, + "38:68": -5092136, + "39:68": -5092136, + "40:68": 268435456, + "41:68": 402653184, + "42:68": 268435456, + "43:68": 402653184, + "44:68": -884827, + "45:68": -884827, + "46:68": -884827, + "47:68": -884827, + "48:68": -884827, + "49:68": -884827, + "50:68": -884827, + "51:68": -884827, + "52:68": -884827, + "53:68": -884827, + "54:68": -884827, + "55:68": -884827, + "56:68": -884827, + "57:68": -884827, + "58:68": -884827, + "59:68": -884827, + "60:68": -884827, + "61:68": -884827, + "62:68": 268435456, + "63:68": 402653184, + "64:68": 268435456, + "65:68": 402653184, + "66:68": -9288933, + "67:68": -9288933, + "68:68": -9288933, + "69:68": -9288933, + "70:68": -9288933, + "71:68": -9288933, + "72:68": -9288933, + "73:68": -9288933, + "74:68": -9288933, + "75:68": -9288933, + "76:68": -9288933, + "77:68": -9288933, + "78:68": -9288933, + "79:68": -9288933, + "80:68": -9288933, + "81:68": -9288933, + "82:68": -9288933, + "83:68": -9288933, + "84:68": 268435456, + "85:68": 402653184, + "86:68": 268435456, + "87:68": 402653184, + "88:68": -9288933, + "89:68": -9288933, + "90:68": -9288933, + "91:68": -9288933, + "92:68": -9288933, + "93:68": -9288933, + "94:68": -9288933, + "95:68": -9288933, + "96:68": -9288933, + "97:68": -9288933, + "98:68": -9288933, + "99:68": -9288933, + "100:68": -9288933, + "101:68": -9288933, + "102:68": -9288933, + "103:68": -9288933, + "104:68": -9288933, + "105:68": -9288933, + "106:68": 268435456, + "107:68": 402653184, + "108:68": 268435456, + "109:68": 402653184, + "110:68": 268435456, + "111:68": 402653184, + "112:68": 268435456, + "113:68": 402653184, + "114:68": 268435456, + "115:68": 402653184, + "116:68": 268435456, + "117:68": 402653184, + "118:68": 268435456, + "119:68": 402653184, + "120:68": 268435456, + "121:68": 402653184, + "122:68": 268435456, + "123:68": 402653184, + "124:68": 268435456, + "125:68": 402653184, + "126:68": 268435456, + "127:68": 402653184, + "0:69": 402653184, + "1:69": 268435456, + "2:69": 402653184, + "3:69": 268435456, + "4:69": 402653184, + "5:69": 268435456, + "6:69": 402653184, + "7:69": 268435456, + "8:69": 402653184, + "9:69": 268435456, + "10:69": 402653184, + "11:69": 268435456, + "12:69": 402653184, + "13:69": 268435456, + "14:69": 402653184, + "15:69": 268435456, + "16:69": 402653184, + "17:69": 268435456, + "18:69": 402653184, + "19:69": 268435456, + "20:69": 402653184, + "21:69": 268435456, + "22:69": -5092136, + "23:69": -5092136, + "24:69": -5092136, + "25:69": -5092136, + "26:69": -5092136, + "27:69": -5092136, + "28:69": -5092136, + "29:69": -5092136, + "30:69": -5092136, + "31:69": -5092136, + "32:69": -5092136, + "33:69": -5092136, + "34:69": -5092136, + "35:69": -5092136, + "36:69": -5092136, + "37:69": -5092136, + "38:69": -5092136, + "39:69": -5092136, + "40:69": 402653184, + "41:69": 268435456, + "42:69": 402653184, + "43:69": 268435456, + "44:69": -884827, + "45:69": -884827, + "46:69": -884827, + "47:69": -884827, + "48:69": -884827, + "49:69": -884827, + "50:69": -884827, + "51:69": -884827, + "52:69": -884827, + "53:69": -884827, + "54:69": -884827, + "55:69": -884827, + "56:69": -884827, + "57:69": -884827, + "58:69": -884827, + "59:69": -884827, + "60:69": -884827, + "61:69": -884827, + "62:69": 402653184, + "63:69": 268435456, + "64:69": 402653184, + "65:69": 268435456, + "66:69": -9288933, + "67:69": -9288933, + "68:69": -9288933, + "69:69": -9288933, + "70:69": -9288933, + "71:69": -9288933, + "72:69": -9288933, + "73:69": -9288933, + "74:69": -9288933, + "75:69": -9288933, + "76:69": -9288933, + "77:69": -9288933, + "78:69": -9288933, + "79:69": -9288933, + "80:69": -9288933, + "81:69": -9288933, + "82:69": -9288933, + "83:69": -9288933, + "84:69": 402653184, + "85:69": 268435456, + "86:69": 402653184, + "87:69": 268435456, + "88:69": -9288933, + "89:69": -9288933, + "90:69": -9288933, + "91:69": -9288933, + "92:69": -9288933, + "93:69": -9288933, + "94:69": -9288933, + "95:69": -9288933, + "96:69": -9288933, + "97:69": -9288933, + "98:69": -9288933, + "99:69": -9288933, + "100:69": -9288933, + "101:69": -9288933, + "102:69": -9288933, + "103:69": -9288933, + "104:69": -9288933, + "105:69": -9288933, + "106:69": 402653184, + "107:69": 268435456, + "108:69": 402653184, + "109:69": 268435456, + "110:69": 402653184, + "111:69": 268435456, + "112:69": 402653184, + "113:69": 268435456, + "114:69": 402653184, + "115:69": 268435456, + "116:69": 402653184, + "117:69": 268435456, + "118:69": 402653184, + "119:69": 268435456, + "120:69": 402653184, + "121:69": 268435456, + "122:69": 402653184, + "123:69": 268435456, + "124:69": 402653184, + "125:69": 268435456, + "126:69": 402653184, + "127:69": 268435456, + "0:70": 268435456, + "1:70": 402653184, + "2:70": 268435456, + "3:70": 402653184, + "4:70": 268435456, + "5:70": 402653184, + "6:70": 268435456, + "7:70": 402653184, + "8:70": 268435456, + "9:70": 402653184, + "10:70": 268435456, + "11:70": 402653184, + "12:70": 268435456, + "13:70": 402653184, + "14:70": 268435456, + "15:70": 402653184, + "16:70": 268435456, + "17:70": 402653184, + "18:70": 268435456, + "19:70": 402653184, + "20:70": 268435456, + "21:70": 402653184, + "22:70": -5092136, + "23:70": -5092136, + "24:70": -5092136, + "25:70": -5092136, + "26:70": -5092136, + "27:70": -5092136, + "28:70": -5092136, + "29:70": -5092136, + "30:70": -5092136, + "31:70": -5092136, + "32:70": -5092136, + "33:70": -5092136, + "34:70": -5092136, + "35:70": -5092136, + "36:70": -5092136, + "37:70": -5092136, + "38:70": -5092136, + "39:70": -5092136, + "40:70": 268435456, + "41:70": 402653184, + "42:70": 268435456, + "43:70": 402653184, + "44:70": -884827, + "45:70": -884827, + "46:70": -884827, + "47:70": -884827, + "48:70": -884827, + "49:70": -884827, + "50:70": -884827, + "51:70": -884827, + "52:70": -884827, + "53:70": -884827, + "54:70": -884827, + "55:70": -884827, + "56:70": -884827, + "57:70": -884827, + "58:70": -884827, + "59:70": -884827, + "60:70": -884827, + "61:70": -884827, + "62:70": 268435456, + "63:70": 402653184, + "64:70": 268435456, + "65:70": 402653184, + "66:70": -9288933, + "67:70": -9288933, + "68:70": -9288933, + "69:70": -9288933, + "70:70": -9288933, + "71:70": -9288933, + "72:70": -9288933, + "73:70": -9288933, + "74:70": -9288933, + "75:70": -9288933, + "76:70": -9288933, + "77:70": -9288933, + "78:70": -9288933, + "79:70": -9288933, + "80:70": -9288933, + "81:70": -9288933, + "82:70": -9288933, + "83:70": -9288933, + "84:70": 268435456, + "85:70": 402653184, + "86:70": 268435456, + "87:70": 402653184, + "88:70": -9288933, + "89:70": -9288933, + "90:70": -9288933, + "91:70": -9288933, + "92:70": -9288933, + "93:70": -9288933, + "94:70": -9288933, + "95:70": -9288933, + "96:70": -9288933, + "97:70": -9288933, + "98:70": -9288933, + "99:70": -9288933, + "100:70": -9288933, + "101:70": -9288933, + "102:70": -9288933, + "103:70": -9288933, + "104:70": -9288933, + "105:70": -9288933, + "106:70": 268435456, + "107:70": 402653184, + "108:70": 268435456, + "109:70": 402653184, + "110:70": 268435456, + "111:70": 402653184, + "112:70": 268435456, + "113:70": 402653184, + "114:70": 268435456, + "115:70": 402653184, + "116:70": 268435456, + "117:70": 402653184, + "118:70": 268435456, + "119:70": 402653184, + "120:70": 268435456, + "121:70": 402653184, + "122:70": 268435456, + "123:70": 402653184, + "124:70": 268435456, + "125:70": 402653184, + "126:70": 268435456, + "127:70": 402653184, + "0:71": 402653184, + "1:71": 268435456, + "2:71": 402653184, + "3:71": 268435456, + "4:71": 402653184, + "5:71": 268435456, + "6:71": 402653184, + "7:71": 268435456, + "8:71": 402653184, + "9:71": 268435456, + "10:71": 402653184, + "11:71": 268435456, + "12:71": 402653184, + "13:71": 268435456, + "14:71": 402653184, + "15:71": 268435456, + "16:71": 402653184, + "17:71": 268435456, + "18:71": 402653184, + "19:71": 268435456, + "20:71": 402653184, + "21:71": 268435456, + "22:71": -5092136, + "23:71": -5092136, + "24:71": -5092136, + "25:71": -5092136, + "26:71": -5092136, + "27:71": -5092136, + "28:71": -5092136, + "29:71": -5092136, + "30:71": -5092136, + "31:71": -5092136, + "32:71": -5092136, + "33:71": -5092136, + "34:71": -5092136, + "35:71": -5092136, + "36:71": -5092136, + "37:71": -5092136, + "38:71": -5092136, + "39:71": -5092136, + "40:71": 402653184, + "41:71": 268435456, + "42:71": 402653184, + "43:71": 268435456, + "44:71": -884827, + "45:71": -884827, + "46:71": -884827, + "47:71": -884827, + "48:71": -884827, + "49:71": -884827, + "50:71": -884827, + "51:71": -884827, + "52:71": -884827, + "53:71": -884827, + "54:71": -884827, + "55:71": -884827, + "56:71": -884827, + "57:71": -884827, + "58:71": -884827, + "59:71": -884827, + "60:71": -884827, + "61:71": -884827, + "62:71": 402653184, + "63:71": 268435456, + "64:71": 402653184, + "65:71": 268435456, + "66:71": -9288933, + "67:71": -9288933, + "68:71": -9288933, + "69:71": -9288933, + "70:71": -9288933, + "71:71": -9288933, + "72:71": -9288933, + "73:71": -9288933, + "74:71": -9288933, + "75:71": -9288933, + "76:71": -9288933, + "77:71": -9288933, + "78:71": -9288933, + "79:71": -9288933, + "80:71": -9288933, + "81:71": -9288933, + "82:71": -9288933, + "83:71": -9288933, + "84:71": 402653184, + "85:71": 268435456, + "86:71": 402653184, + "87:71": 268435456, + "88:71": -9288933, + "89:71": -9288933, + "90:71": -9288933, + "91:71": -9288933, + "92:71": -9288933, + "93:71": -9288933, + "94:71": -9288933, + "95:71": -9288933, + "96:71": -9288933, + "97:71": -9288933, + "98:71": -9288933, + "99:71": -9288933, + "100:71": -9288933, + "101:71": -9288933, + "102:71": -9288933, + "103:71": -9288933, + "104:71": -9288933, + "105:71": -9288933, + "106:71": 402653184, + "107:71": 268435456, + "108:71": 402653184, + "109:71": 268435456, + "110:71": 402653184, + "111:71": 268435456, + "112:71": 402653184, + "113:71": 268435456, + "114:71": 402653184, + "115:71": 268435456, + "116:71": 402653184, + "117:71": 268435456, + "118:71": 402653184, + "119:71": 268435456, + "120:71": 402653184, + "121:71": 268435456, + "122:71": 402653184, + "123:71": 268435456, + "124:71": 402653184, + "125:71": 268435456, + "126:71": 402653184, + "127:71": 268435456, + "0:72": 268435456, + "1:72": 402653184, + "2:72": 268435456, + "3:72": 402653184, + "4:72": 268435456, + "5:72": 402653184, + "6:72": 268435456, + "7:72": 402653184, + "8:72": 268435456, + "9:72": 402653184, + "10:72": 268435456, + "11:72": 402653184, + "12:72": 268435456, + "13:72": 402653184, + "14:72": 268435456, + "15:72": 402653184, + "16:72": 268435456, + "17:72": 402653184, + "18:72": 268435456, + "19:72": 402653184, + "20:72": 268435456, + "21:72": 402653184, + "22:72": -5092136, + "23:72": -5092136, + "24:72": -5092136, + "25:72": -5092136, + "26:72": -5092136, + "27:72": -5092136, + "28:72": -5092136, + "29:72": -5092136, + "30:72": -5092136, + "31:72": -5092136, + "32:72": -5092136, + "33:72": -5092136, + "34:72": -5092136, + "35:72": -5092136, + "36:72": -5092136, + "37:72": -5092136, + "38:72": -5092136, + "39:72": -5092136, + "40:72": 268435456, + "41:72": 402653184, + "42:72": 268435456, + "43:72": 402653184, + "44:72": -884827, + "45:72": -884827, + "46:72": -884827, + "47:72": -884827, + "48:72": -884827, + "49:72": -884827, + "50:72": -884827, + "51:72": -884827, + "52:72": -884827, + "53:72": -884827, + "54:72": -884827, + "55:72": -884827, + "56:72": -884827, + "57:72": -884827, + "58:72": -884827, + "59:72": -884827, + "60:72": -884827, + "61:72": -884827, + "62:72": 268435456, + "63:72": 402653184, + "64:72": 268435456, + "65:72": 402653184, + "66:72": -9288933, + "67:72": -9288933, + "68:72": -9288933, + "69:72": -9288933, + "70:72": -9288933, + "71:72": -9288933, + "72:72": -9288933, + "73:72": -9288933, + "74:72": -9288933, + "75:72": -9288933, + "76:72": -9288933, + "77:72": -9288933, + "78:72": -9288933, + "79:72": -9288933, + "80:72": -9288933, + "81:72": -9288933, + "82:72": -9288933, + "83:72": -9288933, + "84:72": 268435456, + "85:72": 402653184, + "86:72": 268435456, + "87:72": 402653184, + "88:72": -9288933, + "89:72": -9288933, + "90:72": -9288933, + "91:72": -9288933, + "92:72": -9288933, + "93:72": -9288933, + "94:72": -9288933, + "95:72": -9288933, + "96:72": -9288933, + "97:72": -9288933, + "98:72": -9288933, + "99:72": -9288933, + "100:72": -9288933, + "101:72": -9288933, + "102:72": -9288933, + "103:72": -9288933, + "104:72": -9288933, + "105:72": -9288933, + "106:72": 268435456, + "107:72": 402653184, + "108:72": 268435456, + "109:72": 402653184, + "110:72": 268435456, + "111:72": 402653184, + "112:72": 268435456, + "113:72": 402653184, + "114:72": 268435456, + "115:72": 402653184, + "116:72": 268435456, + "117:72": 402653184, + "118:72": 268435456, + "119:72": 402653184, + "120:72": 268435456, + "121:72": 402653184, + "122:72": 268435456, + "123:72": 402653184, + "124:72": 268435456, + "125:72": 402653184, + "126:72": 268435456, + "127:72": 402653184, + "0:73": 402653184, + "1:73": 268435456, + "2:73": 402653184, + "3:73": 268435456, + "4:73": 402653184, + "5:73": 268435456, + "6:73": 402653184, + "7:73": 268435456, + "8:73": 402653184, + "9:73": 268435456, + "10:73": 402653184, + "11:73": 268435456, + "12:73": 402653184, + "13:73": 268435456, + "14:73": 402653184, + "15:73": 268435456, + "16:73": 402653184, + "17:73": 268435456, + "18:73": 402653184, + "19:73": 268435456, + "20:73": 402653184, + "21:73": 268435456, + "22:73": 402653184, + "23:73": 268435456, + "24:73": 402653184, + "25:73": 268435456, + "26:73": 402653184, + "27:73": 268435456, + "28:73": 402653184, + "29:73": 268435456, + "30:73": 402653184, + "31:73": 268435456, + "32:73": 402653184, + "33:73": 268435456, + "34:73": 402653184, + "35:73": 268435456, + "36:73": 402653184, + "37:73": 268435456, + "38:73": 402653184, + "39:73": 268435456, + "40:73": 402653184, + "41:73": 268435456, + "42:73": 402653184, + "43:73": 268435456, + "44:73": 402653184, + "45:73": 268435456, + "46:73": 402653184, + "47:73": 268435456, + "48:73": 402653184, + "49:73": 268435456, + "50:73": -9288933, + "51:73": -9288933, + "52:73": -9288933, + "53:73": -9288933, + "54:73": -9288933, + "55:73": -9288933, + "56:73": -9288933, + "57:73": 268435456, + "58:73": 402653184, + "59:73": 268435456, + "60:73": 402653184, + "61:73": 268435456, + "62:73": 402653184, + "63:73": 268435456, + "64:73": 402653184, + "65:73": 268435456, + "66:73": 402653184, + "67:73": 268435456, + "68:73": 402653184, + "69:73": 268435456, + "70:73": 402653184, + "71:73": 268435456, + "72:73": 402653184, + "73:73": 268435456, + "74:73": 402653184, + "75:73": 268435456, + "76:73": 402653184, + "77:73": 268435456, + "78:73": 402653184, + "79:73": 268435456, + "80:73": 402653184, + "81:73": 268435456, + "82:73": 402653184, + "83:73": 268435456, + "84:73": 402653184, + "85:73": 268435456, + "86:73": 402653184, + "87:73": 268435456, + "88:73": 402653184, + "89:73": 268435456, + "90:73": 402653184, + "91:73": 268435456, + "92:73": 402653184, + "93:73": 268435456, + "94:73": -65536, + "95:73": -65536, + "96:73": -65536, + "97:73": -65536, + "98:73": -65536, + "99:73": -65536, + "100:73": -65536, + "101:73": 268435456, + "102:73": 402653184, + "103:73": 268435456, + "104:73": 402653184, + "105:73": 268435456, + "106:73": 402653184, + "107:73": 268435456, + "108:73": 402653184, + "109:73": 268435456, + "110:73": 402653184, + "111:73": 268435456, + "112:73": 402653184, + "113:73": 268435456, + "114:73": 402653184, + "115:73": 268435456, + "116:73": 402653184, + "117:73": 268435456, + "118:73": 402653184, + "119:73": 268435456, + "120:73": 402653184, + "121:73": 268435456, + "122:73": 402653184, + "123:73": 268435456, + "124:73": 402653184, + "125:73": 268435456, + "126:73": 402653184, + "127:73": 268435456, + "0:74": 268435456, + "1:74": 402653184, + "2:74": 268435456, + "3:74": 402653184, + "4:74": 268435456, + "5:74": 402653184, + "6:74": 268435456, + "7:74": 402653184, + "8:74": 268435456, + "9:74": 402653184, + "10:74": 268435456, + "11:74": 402653184, + "12:74": 268435456, + "13:74": 402653184, + "14:74": 268435456, + "15:74": 402653184, + "16:74": 268435456, + "17:74": 402653184, + "18:74": 268435456, + "19:74": 402653184, + "20:74": 268435456, + "21:74": 402653184, + "22:74": 268435456, + "23:74": 402653184, + "24:74": 268435456, + "25:74": 402653184, + "26:74": 268435456, + "27:74": 402653184, + "28:74": 268435456, + "29:74": 402653184, + "30:74": 268435456, + "31:74": 402653184, + "32:74": 268435456, + "33:74": 402653184, + "34:74": 268435456, + "35:74": 402653184, + "36:74": 268435456, + "37:74": 402653184, + "38:74": 268435456, + "39:74": 402653184, + "40:74": 268435456, + "41:74": 402653184, + "42:74": 268435456, + "43:74": 402653184, + "44:74": 268435456, + "45:74": 402653184, + "46:74": 268435456, + "47:74": 402653184, + "48:74": 268435456, + "49:74": 402653184, + "50:74": -9288933, + "51:74": -9288933, + "52:74": -9288933, + "53:74": -9288933, + "54:74": -9288933, + "55:74": -9288933, + "56:74": -9288933, + "57:74": 402653184, + "58:74": 268435456, + "59:74": 402653184, + "60:74": 268435456, + "61:74": 402653184, + "62:74": 268435456, + "63:74": 402653184, + "64:74": 268435456, + "65:74": 402653184, + "66:74": 268435456, + "67:74": 402653184, + "68:74": 268435456, + "69:74": 402653184, + "70:74": 268435456, + "71:74": 402653184, + "72:74": 268435456, + "73:74": 402653184, + "74:74": 268435456, + "75:74": 402653184, + "76:74": 268435456, + "77:74": 402653184, + "78:74": 268435456, + "79:74": 402653184, + "80:74": 268435456, + "81:74": 402653184, + "82:74": 268435456, + "83:74": 402653184, + "84:74": 268435456, + "85:74": 402653184, + "86:74": 268435456, + "87:74": 402653184, + "88:74": 268435456, + "89:74": 402653184, + "90:74": 268435456, + "91:74": 402653184, + "92:74": 268435456, + "93:74": 402653184, + "94:74": -65536, + "95:74": -65536, + "96:74": -65536, + "97:74": -65536, + "98:74": -65536, + "99:74": -65536, + "100:74": -65536, + "101:74": 402653184, + "102:74": 268435456, + "103:74": 402653184, + "104:74": 268435456, + "105:74": 402653184, + "106:74": 268435456, + "107:74": 402653184, + "108:74": 268435456, + "109:74": 402653184, + "110:74": 268435456, + "111:74": 402653184, + "112:74": 268435456, + "113:74": 402653184, + "114:74": 268435456, + "115:74": 402653184, + "116:74": 268435456, + "117:74": 402653184, + "118:74": 268435456, + "119:74": 402653184, + "120:74": 268435456, + "121:74": 402653184, + "122:74": 268435456, + "123:74": 402653184, + "124:74": 268435456, + "125:74": 402653184, + "126:74": 268435456, + "127:74": 402653184, + "0:75": 402653184, + "1:75": 268435456, + "2:75": 402653184, + "3:75": 268435456, + "4:75": 402653184, + "5:75": 268435456, + "6:75": 402653184, + "7:75": 268435456, + "8:75": 402653184, + "9:75": 268435456, + "10:75": 402653184, + "11:75": 268435456, + "12:75": 402653184, + "13:75": 268435456, + "14:75": 402653184, + "15:75": 268435456, + "16:75": 402653184, + "17:75": 268435456, + "18:75": 402653184, + "19:75": 268435456, + "20:75": 402653184, + "21:75": 268435456, + "22:75": 402653184, + "23:75": 268435456, + "24:75": 402653184, + "25:75": 268435456, + "26:75": 402653184, + "27:75": 268435456, + "28:75": 402653184, + "29:75": 268435456, + "30:75": 402653184, + "31:75": 268435456, + "32:75": 402653184, + "33:75": 268435456, + "34:75": 402653184, + "35:75": 268435456, + "36:75": 402653184, + "37:75": 268435456, + "38:75": 402653184, + "39:75": 268435456, + "40:75": 402653184, + "41:75": 268435456, + "42:75": 402653184, + "43:75": 268435456, + "44:75": 402653184, + "45:75": 268435456, + "46:75": 402653184, + "47:75": 268435456, + "48:75": 402653184, + "49:75": 268435456, + "50:75": -9288933, + "51:75": -9288933, + "52:75": -9288933, + "53:75": -9288933, + "54:75": -9288933, + "55:75": -9288933, + "56:75": -9288933, + "57:75": 268435456, + "58:75": 402653184, + "59:75": 268435456, + "60:75": 402653184, + "61:75": 268435456, + "62:75": 402653184, + "63:75": 268435456, + "64:75": 402653184, + "65:75": 268435456, + "66:75": 402653184, + "67:75": 268435456, + "68:75": 402653184, + "69:75": 268435456, + "70:75": 402653184, + "71:75": 268435456, + "72:75": 402653184, + "73:75": 268435456, + "74:75": 402653184, + "75:75": 268435456, + "76:75": 402653184, + "77:75": 268435456, + "78:75": 402653184, + "79:75": 268435456, + "80:75": 402653184, + "81:75": 268435456, + "82:75": 402653184, + "83:75": 268435456, + "84:75": 402653184, + "85:75": 268435456, + "86:75": 402653184, + "87:75": 268435456, + "88:75": 402653184, + "89:75": 268435456, + "90:75": 402653184, + "91:75": 268435456, + "92:75": 402653184, + "93:75": 268435456, + "94:75": -65536, + "95:75": -65536, + "96:75": -65536, + "97:75": -65536, + "98:75": -65536, + "99:75": -65536, + "100:75": -65536, + "101:75": 268435456, + "102:75": 402653184, + "103:75": 268435456, + "104:75": 402653184, + "105:75": 268435456, + "106:75": 402653184, + "107:75": 268435456, + "108:75": 402653184, + "109:75": 268435456, + "110:75": 402653184, + "111:75": 268435456, + "112:75": 402653184, + "113:75": 268435456, + "114:75": 402653184, + "115:75": 268435456, + "116:75": 402653184, + "117:75": 268435456, + "118:75": 402653184, + "119:75": 268435456, + "120:75": 402653184, + "121:75": 268435456, + "122:75": 402653184, + "123:75": 268435456, + "124:75": 402653184, + "125:75": 268435456, + "126:75": 402653184, + "127:75": 268435456, + "0:76": 268435456, + "1:76": 402653184, + "2:76": 268435456, + "3:76": 402653184, + "4:76": 268435456, + "5:76": 402653184, + "6:76": 268435456, + "7:76": 402653184, + "8:76": 268435456, + "9:76": 402653184, + "10:76": 268435456, + "11:76": 402653184, + "12:76": 268435456, + "13:76": 402653184, + "14:76": 268435456, + "15:76": 402653184, + "16:76": 268435456, + "17:76": 402653184, + "18:76": 268435456, + "19:76": 402653184, + "20:76": 268435456, + "21:76": 402653184, + "22:76": 268435456, + "23:76": 402653184, + "24:76": 268435456, + "25:76": 402653184, + "26:76": 268435456, + "27:76": 402653184, + "28:76": 268435456, + "29:76": 402653184, + "30:76": 268435456, + "31:76": 402653184, + "32:76": 268435456, + "33:76": 402653184, + "34:76": 268435456, + "35:76": 402653184, + "36:76": 268435456, + "37:76": 402653184, + "38:76": 268435456, + "39:76": 402653184, + "40:76": 268435456, + "41:76": 402653184, + "42:76": 268435456, + "43:76": 402653184, + "44:76": 268435456, + "45:76": 402653184, + "46:76": 268435456, + "47:76": 402653184, + "48:76": 268435456, + "49:76": 402653184, + "50:76": -9288933, + "51:76": -9288933, + "52:76": -9288933, + "53:76": -9288933, + "54:76": -9288933, + "55:76": -9288933, + "56:76": -9288933, + "57:76": 402653184, + "58:76": 268435456, + "59:76": 402653184, + "60:76": 268435456, + "61:76": 402653184, + "62:76": 268435456, + "63:76": 402653184, + "64:76": 268435456, + "65:76": 402653184, + "66:76": 268435456, + "67:76": 402653184, + "68:76": 268435456, + "69:76": 402653184, + "70:76": 268435456, + "71:76": 402653184, + "72:76": 268435456, + "73:76": 402653184, + "74:76": 268435456, + "75:76": 402653184, + "76:76": 268435456, + "77:76": 402653184, + "78:76": 268435456, + "79:76": 402653184, + "80:76": 268435456, + "81:76": 402653184, + "82:76": 268435456, + "83:76": 402653184, + "84:76": 268435456, + "85:76": 402653184, + "86:76": 268435456, + "87:76": 402653184, + "88:76": 268435456, + "89:76": 402653184, + "90:76": 268435456, + "91:76": 402653184, + "92:76": 268435456, + "93:76": 402653184, + "94:76": -65536, + "95:76": -65536, + "96:76": -65536, + "97:76": -65536, + "98:76": -65536, + "99:76": -65536, + "100:76": -65536, + "101:76": 402653184, + "102:76": 268435456, + "103:76": 402653184, + "104:76": 268435456, + "105:76": 402653184, + "106:76": 268435456, + "107:76": 402653184, + "108:76": 268435456, + "109:76": 402653184, + "110:76": 268435456, + "111:76": 402653184, + "112:76": 268435456, + "113:76": 402653184, + "114:76": 268435456, + "115:76": 402653184, + "116:76": 268435456, + "117:76": 402653184, + "118:76": 268435456, + "119:76": 402653184, + "120:76": 268435456, + "121:76": 402653184, + "122:76": 268435456, + "123:76": 402653184, + "124:76": 268435456, + "125:76": 402653184, + "126:76": 268435456, + "127:76": 402653184, + "0:77": 402653184, + "1:77": 268435456, + "2:77": 402653184, + "3:77": 268435456, + "4:77": 402653184, + "5:77": 268435456, + "6:77": 402653184, + "7:77": 268435456, + "8:77": 402653184, + "9:77": 268435456, + "10:77": 402653184, + "11:77": 268435456, + "12:77": 402653184, + "13:77": 268435456, + "14:77": 402653184, + "15:77": 268435456, + "16:77": 402653184, + "17:77": 268435456, + "18:77": 402653184, + "19:77": 268435456, + "20:77": 402653184, + "21:77": 268435456, + "22:77": -9288933, + "23:77": -9288933, + "24:77": -9288933, + "25:77": -9288933, + "26:77": -9288933, + "27:77": -9288933, + "28:77": -9288933, + "29:77": -9288933, + "30:77": -9288933, + "31:77": -9288933, + "32:77": -9288933, + "33:77": -9288933, + "34:77": -9288933, + "35:77": -9288933, + "36:77": -9288933, + "37:77": -9288933, + "38:77": -9288933, + "39:77": -9288933, + "40:77": -9288933, + "41:77": -9288933, + "42:77": -9288933, + "43:77": -9288933, + "44:77": -9288933, + "45:77": -9288933, + "46:77": -9288933, + "47:77": -9288933, + "48:77": -9288933, + "49:77": -9288933, + "50:77": -9288933, + "51:77": -9288933, + "52:77": -9288933, + "53:77": -9288933, + "54:77": -9288933, + "55:77": -9288933, + "56:77": -9288933, + "57:77": -9288933, + "58:77": -9288933, + "59:77": -9288933, + "60:77": -9288933, + "61:77": -9288933, + "62:77": 402653184, + "63:77": 268435456, + "64:77": 402653184, + "65:77": 268435456, + "66:77": -9288933, + "67:77": -9288933, + "68:77": -9288933, + "69:77": -9288933, + "70:77": -9288933, + "71:77": -9288933, + "72:77": -9288933, + "73:77": -9288933, + "74:77": -9288933, + "75:77": -9288933, + "76:77": -9288933, + "77:77": -9288933, + "78:77": -9288933, + "79:77": -9288933, + "80:77": -9288933, + "81:77": -9288933, + "82:77": -9288933, + "83:77": -9288933, + "84:77": 402653184, + "85:77": 268435456, + "86:77": 402653184, + "87:77": 268435456, + "88:77": -65536, + "89:77": -65536, + "90:77": -65536, + "91:77": -65536, + "92:77": -65536, + "93:77": -65536, + "94:77": -65536, + "95:77": -65536, + "96:77": -65536, + "97:77": -65536, + "98:77": -65536, + "99:77": -65536, + "100:77": -65536, + "101:77": -65536, + "102:77": -65536, + "103:77": -65536, + "104:77": -65536, + "105:77": -65536, + "106:77": 402653184, + "107:77": 268435456, + "108:77": 402653184, + "109:77": 268435456, + "110:77": 402653184, + "111:77": 268435456, + "112:77": 402653184, + "113:77": 268435456, + "114:77": 402653184, + "115:77": 268435456, + "116:77": 402653184, + "117:77": 268435456, + "118:77": 402653184, + "119:77": 268435456, + "120:77": 402653184, + "121:77": 268435456, + "122:77": 402653184, + "123:77": 268435456, + "124:77": 402653184, + "125:77": 268435456, + "126:77": 402653184, + "127:77": 268435456, + "0:78": 268435456, + "1:78": 402653184, + "2:78": 268435456, + "3:78": 402653184, + "4:78": 268435456, + "5:78": 402653184, + "6:78": 268435456, + "7:78": 402653184, + "8:78": 268435456, + "9:78": 402653184, + "10:78": 268435456, + "11:78": 402653184, + "12:78": 268435456, + "13:78": 402653184, + "14:78": 268435456, + "15:78": 402653184, + "16:78": 268435456, + "17:78": 402653184, + "18:78": 268435456, + "19:78": 402653184, + "20:78": 268435456, + "21:78": 402653184, + "22:78": -9288933, + "23:78": -9288933, + "24:78": -9288933, + "25:78": -9288933, + "26:78": -9288933, + "27:78": -9288933, + "28:78": -9288933, + "29:78": -9288933, + "30:78": -9288933, + "31:78": -9288933, + "32:78": -9288933, + "33:78": -9288933, + "34:78": -9288933, + "35:78": -9288933, + "36:78": -9288933, + "37:78": -9288933, + "38:78": -9288933, + "39:78": -9288933, + "40:78": -9288933, + "41:78": -9288933, + "42:78": -9288933, + "43:78": -9288933, + "44:78": -9288933, + "45:78": -9288933, + "46:78": -9288933, + "47:78": -9288933, + "48:78": -9288933, + "49:78": -9288933, + "50:78": -9288933, + "51:78": -9288933, + "52:78": -9288933, + "53:78": -9288933, + "54:78": -9288933, + "55:78": -9288933, + "56:78": -9288933, + "57:78": -9288933, + "58:78": -9288933, + "59:78": -9288933, + "60:78": -9288933, + "61:78": -9288933, + "62:78": 268435456, + "63:78": 402653184, + "64:78": 268435456, + "65:78": 402653184, + "66:78": -9288933, + "67:78": -9288933, + "68:78": -9288933, + "69:78": -9288933, + "70:78": -9288933, + "71:78": -9288933, + "72:78": -9288933, + "73:78": -9288933, + "74:78": -9288933, + "75:78": -9288933, + "76:78": -9288933, + "77:78": -9288933, + "78:78": -9288933, + "79:78": -9288933, + "80:78": -9288933, + "81:78": -9288933, + "82:78": -9288933, + "83:78": -9288933, + "84:78": 268435456, + "85:78": 402653184, + "86:78": 268435456, + "87:78": 402653184, + "88:78": -65536, + "89:78": -65536, + "90:78": -65536, + "91:78": -65536, + "92:78": -65536, + "93:78": -65536, + "94:78": -65536, + "95:78": -65536, + "96:78": -65536, + "97:78": -65536, + "98:78": -65536, + "99:78": -65536, + "100:78": -65536, + "101:78": -65536, + "102:78": -65536, + "103:78": -65536, + "104:78": -65536, + "105:78": -65536, + "106:78": 268435456, + "107:78": 402653184, + "108:78": 268435456, + "109:78": 402653184, + "110:78": 268435456, + "111:78": 402653184, + "112:78": 268435456, + "113:78": 402653184, + "114:78": 268435456, + "115:78": 402653184, + "116:78": 268435456, + "117:78": 402653184, + "118:78": 268435456, + "119:78": 402653184, + "120:78": 268435456, + "121:78": 402653184, + "122:78": 268435456, + "123:78": 402653184, + "124:78": 268435456, + "125:78": 402653184, + "126:78": 268435456, + "127:78": 402653184, + "0:79": 402653184, + "1:79": 268435456, + "2:79": 402653184, + "3:79": 268435456, + "4:79": 402653184, + "5:79": 268435456, + "6:79": 402653184, + "7:79": 268435456, + "8:79": 402653184, + "9:79": 268435456, + "10:79": 402653184, + "11:79": 268435456, + "12:79": 402653184, + "13:79": 268435456, + "14:79": 402653184, + "15:79": 268435456, + "16:79": 402653184, + "17:79": 268435456, + "18:79": 402653184, + "19:79": 268435456, + "20:79": 402653184, + "21:79": 268435456, + "22:79": -9288933, + "23:79": -9288933, + "24:79": -9288933, + "25:79": -9288933, + "26:79": -9288933, + "27:79": -9288933, + "28:79": -9288933, + "29:79": -9288933, + "30:79": -9288933, + "31:79": -9288933, + "32:79": -9288933, + "33:79": -9288933, + "34:79": -9288933, + "35:79": -9288933, + "36:79": -9288933, + "37:79": -9288933, + "38:79": -9288933, + "39:79": -9288933, + "40:79": -9288933, + "41:79": -9288933, + "42:79": -9288933, + "43:79": -9288933, + "44:79": -9288933, + "45:79": -9288933, + "46:79": -9288933, + "47:79": -9288933, + "48:79": -9288933, + "49:79": -9288933, + "50:79": -9288933, + "51:79": -9288933, + "52:79": -9288933, + "53:79": -9288933, + "54:79": -9288933, + "55:79": -9288933, + "56:79": -9288933, + "57:79": -9288933, + "58:79": -9288933, + "59:79": -9288933, + "60:79": -9288933, + "61:79": -9288933, + "62:79": 402653184, + "63:79": 268435456, + "64:79": 402653184, + "65:79": 268435456, + "66:79": -9288933, + "67:79": -9288933, + "68:79": -9288933, + "69:79": -9288933, + "70:79": -9288933, + "71:79": -9288933, + "72:79": -9288933, + "73:79": -9288933, + "74:79": -9288933, + "75:79": -9288933, + "76:79": -9288933, + "77:79": -9288933, + "78:79": -9288933, + "79:79": -9288933, + "80:79": -9288933, + "81:79": -9288933, + "82:79": -9288933, + "83:79": -9288933, + "84:79": 402653184, + "85:79": 268435456, + "86:79": 402653184, + "87:79": 268435456, + "88:79": -65536, + "89:79": -65536, + "90:79": -65536, + "91:79": -65536, + "92:79": -65536, + "93:79": -65536, + "94:79": -65536, + "95:79": -65536, + "96:79": -65536, + "97:79": -65536, + "98:79": -65536, + "99:79": -65536, + "100:79": -65536, + "101:79": -65536, + "102:79": -65536, + "103:79": -65536, + "104:79": -65536, + "105:79": -65536, + "106:79": 402653184, + "107:79": 268435456, + "108:79": 402653184, + "109:79": 268435456, + "110:79": 402653184, + "111:79": 268435456, + "112:79": 402653184, + "113:79": 268435456, + "114:79": 402653184, + "115:79": 268435456, + "116:79": 402653184, + "117:79": 268435456, + "118:79": 402653184, + "119:79": 268435456, + "120:79": 402653184, + "121:79": 268435456, + "122:79": 402653184, + "123:79": 268435456, + "124:79": 402653184, + "125:79": 268435456, + "126:79": 402653184, + "127:79": 268435456, + "0:80": 268435456, + "1:80": 402653184, + "2:80": 268435456, + "3:80": 402653184, + "4:80": 268435456, + "5:80": 402653184, + "6:80": 268435456, + "7:80": 402653184, + "8:80": 268435456, + "9:80": 402653184, + "10:80": 268435456, + "11:80": 402653184, + "12:80": 268435456, + "13:80": 402653184, + "14:80": 268435456, + "15:80": 402653184, + "16:80": 268435456, + "17:80": 402653184, + "18:80": 268435456, + "19:80": 402653184, + "20:80": 268435456, + "21:80": 402653184, + "22:80": -9288933, + "23:80": -9288933, + "24:80": -9288933, + "25:80": -9288933, + "26:80": -9288933, + "27:80": -9288933, + "28:80": -9288933, + "29:80": -9288933, + "30:80": -9288933, + "31:80": -9288933, + "32:80": -9288933, + "33:80": -9288933, + "34:80": -9288933, + "35:80": -9288933, + "36:80": -9288933, + "37:80": -9288933, + "38:80": -9288933, + "39:80": -9288933, + "40:80": -9288933, + "41:80": -9288933, + "42:80": -9288933, + "43:80": -9288933, + "44:80": -9288933, + "45:80": -9288933, + "46:80": -9288933, + "47:80": -9288933, + "48:80": -9288933, + "49:80": -9288933, + "50:80": -9288933, + "51:80": -9288933, + "52:80": -9288933, + "53:80": -9288933, + "54:80": -9288933, + "55:80": -9288933, + "56:80": -9288933, + "57:80": -9288933, + "58:80": -9288933, + "59:80": -9288933, + "60:80": -9288933, + "61:80": -9288933, + "62:80": 268435456, + "63:80": 402653184, + "64:80": 268435456, + "65:80": 402653184, + "66:80": -9288933, + "67:80": -9288933, + "68:80": -9288933, + "69:80": -9288933, + "70:80": -9288933, + "71:80": -9288933, + "72:80": -9288933, + "73:80": -9288933, + "74:80": -9288933, + "75:80": -9288933, + "76:80": -9288933, + "77:80": -9288933, + "78:80": -9288933, + "79:80": -9288933, + "80:80": -9288933, + "81:80": -9288933, + "82:80": -9288933, + "83:80": -9288933, + "84:80": 268435456, + "85:80": 402653184, + "86:80": 268435456, + "87:80": 402653184, + "88:80": -65536, + "89:80": -65536, + "90:80": -65536, + "91:80": -65536, + "92:80": -65536, + "93:80": -65536, + "94:80": -65536, + "95:80": -65536, + "96:80": -65536, + "97:80": -65536, + "98:80": -65536, + "99:80": -65536, + "100:80": -65536, + "101:80": -65536, + "102:80": -65536, + "103:80": -65536, + "104:80": -65536, + "105:80": -65536, + "106:80": 268435456, + "107:80": 402653184, + "108:80": 268435456, + "109:80": 402653184, + "110:80": 268435456, + "111:80": 402653184, + "112:80": 268435456, + "113:80": 402653184, + "114:80": 268435456, + "115:80": 402653184, + "116:80": 268435456, + "117:80": 402653184, + "118:80": 268435456, + "119:80": 402653184, + "120:80": 268435456, + "121:80": 402653184, + "122:80": 268435456, + "123:80": 402653184, + "124:80": 268435456, + "125:80": 402653184, + "126:80": 268435456, + "127:80": 402653184, + "0:81": 402653184, + "1:81": 268435456, + "2:81": 402653184, + "3:81": 268435456, + "4:81": 402653184, + "5:81": 268435456, + "6:81": 402653184, + "7:81": 268435456, + "8:81": 402653184, + "9:81": 268435456, + "10:81": 402653184, + "11:81": 268435456, + "12:81": 402653184, + "13:81": 268435456, + "14:81": 402653184, + "15:81": 268435456, + "16:81": 402653184, + "17:81": 268435456, + "18:81": 402653184, + "19:81": 268435456, + "20:81": 402653184, + "21:81": 268435456, + "22:81": -9288933, + "23:81": -9288933, + "24:81": -9288933, + "25:81": -9288933, + "26:81": -9288933, + "27:81": -9288933, + "28:81": -9288933, + "29:81": -9288933, + "30:81": -9288933, + "31:81": -9288933, + "32:81": -9288933, + "33:81": -9288933, + "34:81": -9288933, + "35:81": -9288933, + "36:81": -9288933, + "37:81": -9288933, + "38:81": -9288933, + "39:81": -9288933, + "40:81": -9288933, + "41:81": -9288933, + "42:81": -9288933, + "43:81": -9288933, + "44:81": -9288933, + "45:81": -9288933, + "46:81": -9288933, + "47:81": -9288933, + "48:81": -9288933, + "49:81": -9288933, + "50:81": -9288933, + "51:81": -9288933, + "52:81": -9288933, + "53:81": -9288933, + "54:81": -9288933, + "55:81": -9288933, + "56:81": -9288933, + "57:81": -9288933, + "58:81": -9288933, + "59:81": -9288933, + "60:81": -9288933, + "61:81": -9288933, + "62:81": 402653184, + "63:81": 268435456, + "64:81": 402653184, + "65:81": 268435456, + "66:81": -9288933, + "67:81": -9288933, + "68:81": -9288933, + "69:81": -9288933, + "70:81": -9288933, + "71:81": -9288933, + "72:81": -9288933, + "73:81": -9288933, + "74:81": -9288933, + "75:81": -9288933, + "76:81": -9288933, + "77:81": -9288933, + "78:81": -9288933, + "79:81": -9288933, + "80:81": -9288933, + "81:81": -9288933, + "82:81": -9288933, + "83:81": -9288933, + "84:81": 402653184, + "85:81": 268435456, + "86:81": 402653184, + "87:81": 268435456, + "88:81": -65536, + "89:81": -65536, + "90:81": -65536, + "91:81": -65536, + "92:81": -65536, + "93:81": -65536, + "94:81": -65536, + "95:81": -65536, + "96:81": -65536, + "97:81": -65536, + "98:81": -65536, + "99:81": -65536, + "100:81": -65536, + "101:81": -65536, + "102:81": -65536, + "103:81": -65536, + "104:81": -65536, + "105:81": -65536, + "106:81": 402653184, + "107:81": 268435456, + "108:81": 402653184, + "109:81": 268435456, + "110:81": 402653184, + "111:81": 268435456, + "112:81": 402653184, + "113:81": 268435456, + "114:81": 402653184, + "115:81": 268435456, + "116:81": 402653184, + "117:81": 268435456, + "118:81": 402653184, + "119:81": 268435456, + "120:81": 402653184, + "121:81": 268435456, + "122:81": 402653184, + "123:81": 268435456, + "124:81": 402653184, + "125:81": 268435456, + "126:81": 402653184, + "127:81": 268435456, + "0:82": 268435456, + "1:82": 402653184, + "2:82": 268435456, + "3:82": 402653184, + "4:82": 268435456, + "5:82": 402653184, + "6:82": 268435456, + "7:82": 402653184, + "8:82": 268435456, + "9:82": 402653184, + "10:82": 268435456, + "11:82": 402653184, + "12:82": 268435456, + "13:82": 402653184, + "14:82": 268435456, + "15:82": 402653184, + "16:82": 268435456, + "17:82": 402653184, + "18:82": 268435456, + "19:82": 402653184, + "20:82": 268435456, + "21:82": 402653184, + "22:82": -9288933, + "23:82": -9288933, + "24:82": -9288933, + "25:82": -9288933, + "26:82": -9288933, + "27:82": -9288933, + "28:82": -9288933, + "29:82": -9288933, + "30:82": -9288933, + "31:82": -9288933, + "32:82": -9288933, + "33:82": -9288933, + "34:82": -9288933, + "35:82": -9288933, + "36:82": -9288933, + "37:82": -9288933, + "38:82": -9288933, + "39:82": -9288933, + "40:82": -9288933, + "41:82": -9288933, + "42:82": -9288933, + "43:82": -9288933, + "44:82": -9288933, + "45:82": -9288933, + "46:82": -9288933, + "47:82": -9288933, + "48:82": -9288933, + "49:82": -9288933, + "50:82": -9288933, + "51:82": -9288933, + "52:82": -9288933, + "53:82": -9288933, + "54:82": -9288933, + "55:82": -9288933, + "56:82": -9288933, + "57:82": -9288933, + "58:82": -9288933, + "59:82": -9288933, + "60:82": -9288933, + "61:82": -9288933, + "62:82": 268435456, + "63:82": 402653184, + "64:82": 268435456, + "65:82": 402653184, + "66:82": -9288933, + "67:82": -9288933, + "68:82": -9288933, + "69:82": -9288933, + "70:82": -9288933, + "71:82": -9288933, + "72:82": -9288933, + "73:82": -9288933, + "74:82": -9288933, + "75:82": -9288933, + "76:82": -9288933, + "77:82": -9288933, + "78:82": -9288933, + "79:82": -9288933, + "80:82": -9288933, + "81:82": -9288933, + "82:82": -9288933, + "83:82": -9288933, + "84:82": 268435456, + "85:82": 402653184, + "86:82": 268435456, + "87:82": 402653184, + "88:82": -65536, + "89:82": -65536, + "90:82": -65536, + "91:82": -65536, + "92:82": -65536, + "93:82": -65536, + "94:82": -65536, + "95:82": -65536, + "96:82": -65536, + "97:82": -65536, + "98:82": -65536, + "99:82": -65536, + "100:82": -65536, + "101:82": -65536, + "102:82": -65536, + "103:82": -65536, + "104:82": -65536, + "105:82": -65536, + "106:82": 268435456, + "107:82": 402653184, + "108:82": 268435456, + "109:82": 402653184, + "110:82": 268435456, + "111:82": 402653184, + "112:82": 268435456, + "113:82": 402653184, + "114:82": 268435456, + "115:82": 402653184, + "116:82": 268435456, + "117:82": 402653184, + "118:82": 268435456, + "119:82": 402653184, + "120:82": 268435456, + "121:82": 402653184, + "122:82": 268435456, + "123:82": 402653184, + "124:82": 268435456, + "125:82": 402653184, + "126:82": 268435456, + "127:82": 402653184, + "0:83": 402653184, + "1:83": 268435456, + "2:83": 402653184, + "3:83": 268435456, + "4:83": 402653184, + "5:83": 268435456, + "6:83": 402653184, + "7:83": 268435456, + "8:83": 402653184, + "9:83": 268435456, + "10:83": 402653184, + "11:83": 268435456, + "12:83": 402653184, + "13:83": 268435456, + "14:83": 402653184, + "15:83": 268435456, + "16:83": 402653184, + "17:83": 268435456, + "18:83": 402653184, + "19:83": 268435456, + "20:83": 402653184, + "21:83": 268435456, + "22:83": -9288933, + "23:83": -9288933, + "24:83": -9288933, + "25:83": -9288933, + "26:83": -9288933, + "27:83": -9288933, + "28:83": -9288933, + "29:83": -9288933, + "30:83": -9288933, + "31:83": -9288933, + "32:83": -9288933, + "33:83": -9288933, + "34:83": -9288933, + "35:83": -9288933, + "36:83": -9288933, + "37:83": -9288933, + "38:83": -9288933, + "39:83": -9288933, + "40:83": -9288933, + "41:83": -9288933, + "42:83": -9288933, + "43:83": -9288933, + "44:83": -9288933, + "45:83": -9288933, + "46:83": -9288933, + "47:83": -9288933, + "48:83": -9288933, + "49:83": -9288933, + "50:83": -9288933, + "51:83": -9288933, + "52:83": -9288933, + "53:83": -9288933, + "54:83": -9288933, + "55:83": -9288933, + "56:83": -9288933, + "57:83": -9288933, + "58:83": -9288933, + "59:83": -9288933, + "60:83": -9288933, + "61:83": -9288933, + "62:83": -9288933, + "63:83": -9288933, + "64:83": -9288933, + "65:83": -9288933, + "66:83": -9288933, + "67:83": -9288933, + "68:83": -9288933, + "69:83": -9288933, + "70:83": -9288933, + "71:83": -9288933, + "72:83": -9288933, + "73:83": -9288933, + "74:83": -9288933, + "75:83": -9288933, + "76:83": -9288933, + "77:83": -9288933, + "78:83": -9288933, + "79:83": -9288933, + "80:83": -9288933, + "81:83": -9288933, + "82:83": -9288933, + "83:83": -9288933, + "84:83": 402653184, + "85:83": 268435456, + "86:83": 402653184, + "87:83": 268435456, + "88:83": -65536, + "89:83": -65536, + "90:83": -65536, + "91:83": -65536, + "92:83": -65536, + "93:83": -65536, + "94:83": -65536, + "95:83": -65536, + "96:83": -65536, + "97:83": -65536, + "98:83": -65536, + "99:83": -65536, + "100:83": -65536, + "101:83": -65536, + "102:83": -65536, + "103:83": -65536, + "104:83": -65536, + "105:83": -65536, + "106:83": 402653184, + "107:83": 268435456, + "108:83": 402653184, + "109:83": 268435456, + "110:83": 402653184, + "111:83": 268435456, + "112:83": 402653184, + "113:83": 268435456, + "114:83": 402653184, + "115:83": 268435456, + "116:83": 402653184, + "117:83": 268435456, + "118:83": 402653184, + "119:83": 268435456, + "120:83": 402653184, + "121:83": 268435456, + "122:83": 402653184, + "123:83": 268435456, + "124:83": 402653184, + "125:83": 268435456, + "126:83": 402653184, + "127:83": 268435456, + "0:84": 268435456, + "1:84": 402653184, + "2:84": 268435456, + "3:84": 402653184, + "4:84": 268435456, + "5:84": 402653184, + "6:84": 268435456, + "7:84": 402653184, + "8:84": 268435456, + "9:84": 402653184, + "10:84": 268435456, + "11:84": 402653184, + "12:84": 268435456, + "13:84": 402653184, + "14:84": 268435456, + "15:84": 402653184, + "16:84": 268435456, + "17:84": 402653184, + "18:84": 268435456, + "19:84": 402653184, + "20:84": 268435456, + "21:84": 402653184, + "22:84": -9288933, + "23:84": -9288933, + "24:84": -9288933, + "25:84": -9288933, + "26:84": -9288933, + "27:84": -9288933, + "28:84": -9288933, + "29:84": -9288933, + "30:84": -9288933, + "31:84": -9288933, + "32:84": -1, + "33:84": -1, + "34:84": -1, + "35:84": -9288933, + "36:84": -9288933, + "37:84": -9288933, + "38:84": -9288933, + "39:84": -9288933, + "40:84": -9288933, + "41:84": -9288933, + "42:84": -9288933, + "43:84": -9288933, + "44:84": -9288933, + "45:84": -9288933, + "46:84": -9288933, + "47:84": -9288933, + "48:84": -9288933, + "49:84": -9288933, + "50:84": -9288933, + "51:84": -9288933, + "52:84": -9288933, + "53:84": -9288933, + "54:84": -9288933, + "55:84": -9288933, + "56:84": -9288933, + "57:84": -9288933, + "58:84": -9288933, + "59:84": -9288933, + "60:84": -9288933, + "61:84": -9288933, + "62:84": -9288933, + "63:84": -9288933, + "64:84": -9288933, + "65:84": -9288933, + "66:84": -9288933, + "67:84": -9288933, + "68:84": -9288933, + "69:84": -9288933, + "70:84": -9288933, + "71:84": -9288933, + "72:84": -9288933, + "73:84": -9288933, + "74:84": -9288933, + "75:84": -9288933, + "76:84": -16745472, + "77:84": -16745472, + "78:84": -16745472, + "79:84": -9288933, + "80:84": -9288933, + "81:84": -9288933, + "82:84": -9288933, + "83:84": -9288933, + "84:84": 268435456, + "85:84": 402653184, + "86:84": 268435456, + "87:84": 402653184, + "88:84": -65536, + "89:84": -65536, + "90:84": -65536, + "91:84": -65536, + "92:84": -65536, + "93:84": -65536, + "94:84": -65536, + "95:84": -65536, + "96:84": -65536, + "97:84": -65536, + "98:84": -65536, + "99:84": -65536, + "100:84": -65536, + "101:84": -65536, + "102:84": -65536, + "103:84": -65536, + "104:84": -65536, + "105:84": -65536, + "106:84": 268435456, + "107:84": 402653184, + "108:84": 268435456, + "109:84": 402653184, + "110:84": 268435456, + "111:84": 402653184, + "112:84": 268435456, + "113:84": 402653184, + "114:84": 268435456, + "115:84": 402653184, + "116:84": 268435456, + "117:84": 402653184, + "118:84": 268435456, + "119:84": 402653184, + "120:84": 268435456, + "121:84": 402653184, + "122:84": 268435456, + "123:84": 402653184, + "124:84": 268435456, + "125:84": 402653184, + "126:84": 268435456, + "127:84": 402653184, + "0:85": 402653184, + "1:85": 268435456, + "2:85": 402653184, + "3:85": 268435456, + "4:85": 402653184, + "5:85": 268435456, + "6:85": 402653184, + "7:85": 268435456, + "8:85": 402653184, + "9:85": 268435456, + "10:85": 402653184, + "11:85": 268435456, + "12:85": 402653184, + "13:85": 268435456, + "14:85": 402653184, + "15:85": 268435456, + "16:85": 402653184, + "17:85": 268435456, + "18:85": 402653184, + "19:85": 268435456, + "20:85": 402653184, + "21:85": 268435456, + "22:85": -9288933, + "23:85": -9288933, + "24:85": -9288933, + "25:85": -9288933, + "26:85": -9288933, + "27:85": -9288933, + "28:85": -9288933, + "29:85": -9288933, + "30:85": -9288933, + "31:85": -1, + "32:85": -1, + "33:85": -1, + "34:85": -9288933, + "35:85": -9288933, + "36:85": -9288933, + "37:85": -9288933, + "38:85": -9288933, + "39:85": -9288933, + "40:85": -9288933, + "41:85": -9288933, + "42:85": -9288933, + "43:85": -9288933, + "44:85": -9288933, + "45:85": -9288933, + "46:85": -9288933, + "47:85": -9288933, + "48:85": -9288933, + "49:85": -9288933, + "50:85": -9288933, + "51:85": -9288933, + "52:85": -9288933, + "53:85": -9288933, + "54:85": -9288933, + "55:85": -9288933, + "56:85": -9288933, + "57:85": -9288933, + "58:85": -9288933, + "59:85": -9288933, + "60:85": -9288933, + "61:85": -9288933, + "62:85": -9288933, + "63:85": -9288933, + "64:85": -9288933, + "65:85": -9288933, + "66:85": -9288933, + "67:85": -9288933, + "68:85": -9288933, + "69:85": -9288933, + "70:85": -9288933, + "71:85": -9288933, + "72:85": -9288933, + "73:85": -9288933, + "74:85": -9288933, + "75:85": -16745472, + "76:85": -16745472, + "77:85": -16745472, + "78:85": -9288933, + "79:85": -9288933, + "80:85": -9288933, + "81:85": -9288933, + "82:85": -9288933, + "83:85": -9288933, + "84:85": 402653184, + "85:85": 268435456, + "86:85": 402653184, + "87:85": 268435456, + "88:85": -65536, + "89:85": -65536, + "90:85": -65536, + "91:85": -65536, + "92:85": -65536, + "93:85": -65536, + "94:85": -65536, + "95:85": -65536, + "96:85": -65536, + "97:85": -65536, + "98:85": -65536, + "99:85": -65536, + "100:85": -65536, + "101:85": -65536, + "102:85": -65536, + "103:85": -65536, + "104:85": -65536, + "105:85": -65536, + "106:85": 402653184, + "107:85": 268435456, + "108:85": 402653184, + "109:85": 268435456, + "110:85": 402653184, + "111:85": 268435456, + "112:85": 402653184, + "113:85": 268435456, + "114:85": 402653184, + "115:85": 268435456, + "116:85": 402653184, + "117:85": 268435456, + "118:85": 402653184, + "119:85": 268435456, + "120:85": 402653184, + "121:85": 268435456, + "122:85": 402653184, + "123:85": 268435456, + "124:85": 402653184, + "125:85": 268435456, + "126:85": 402653184, + "127:85": 268435456, + "0:86": 268435456, + "1:86": 402653184, + "2:86": 268435456, + "3:86": 402653184, + "4:86": 268435456, + "5:86": 402653184, + "6:86": 268435456, + "7:86": 402653184, + "8:86": 268435456, + "9:86": 402653184, + "10:86": 268435456, + "11:86": 402653184, + "12:86": 268435456, + "13:86": 402653184, + "14:86": 268435456, + "15:86": 402653184, + "16:86": 268435456, + "17:86": 402653184, + "18:86": 268435456, + "19:86": 402653184, + "20:86": 268435456, + "21:86": 402653184, + "22:86": -9288933, + "23:86": -9288933, + "24:86": -9288933, + "25:86": -9288933, + "26:86": -9288933, + "27:86": -9288933, + "28:86": -9288933, + "29:86": -9288933, + "30:86": -9288933, + "31:86": -1, + "32:86": -1, + "33:86": -9288933, + "34:86": -9288933, + "35:86": -9288933, + "36:86": -9288933, + "37:86": -9288933, + "38:86": -9288933, + "39:86": -9288933, + "40:86": -9288933, + "41:86": -9288933, + "42:86": -9288933, + "43:86": -9288933, + "44:86": -9288933, + "45:86": -9288933, + "46:86": -9288933, + "47:86": -9288933, + "48:86": -9288933, + "49:86": -9288933, + "50:86": -9288933, + "51:86": -9288933, + "52:86": -9288933, + "53:86": -9288933, + "54:86": -9288933, + "55:86": -9288933, + "56:86": -9288933, + "57:86": -9288933, + "58:86": -9288933, + "59:86": -9288933, + "60:86": -9288933, + "61:86": -9288933, + "62:86": -9288933, + "63:86": -9288933, + "64:86": -9288933, + "65:86": -9288933, + "66:86": -9288933, + "67:86": -9288933, + "68:86": -9288933, + "69:86": -9288933, + "70:86": -9288933, + "71:86": -9288933, + "72:86": -9288933, + "73:86": -9288933, + "74:86": -9288933, + "75:86": -16745472, + "76:86": -16745472, + "77:86": -9288933, + "78:86": -9288933, + "79:86": -9288933, + "80:86": -9288933, + "81:86": -9288933, + "82:86": -9288933, + "83:86": -9288933, + "84:86": 268435456, + "85:86": 402653184, + "86:86": 268435456, + "87:86": 402653184, + "88:86": -65536, + "89:86": -65536, + "90:86": -65536, + "91:86": -65536, + "92:86": -65536, + "93:86": -65536, + "94:86": -65536, + "95:86": -65536, + "96:86": -65536, + "97:86": -65536, + "98:86": -65536, + "99:86": -65536, + "100:86": -65536, + "101:86": -65536, + "102:86": -65536, + "103:86": -65536, + "104:86": -65536, + "105:86": -65536, + "106:86": 268435456, + "107:86": 402653184, + "108:86": 268435456, + "109:86": 402653184, + "110:86": 268435456, + "111:86": 402653184, + "112:86": 268435456, + "113:86": 402653184, + "114:86": 268435456, + "115:86": 402653184, + "116:86": 268435456, + "117:86": 402653184, + "118:86": 268435456, + "119:86": 402653184, + "120:86": 268435456, + "121:86": 402653184, + "122:86": 268435456, + "123:86": 402653184, + "124:86": 268435456, + "125:86": 402653184, + "126:86": 268435456, + "127:86": 402653184, + "0:87": 402653184, + "1:87": 268435456, + "2:87": 402653184, + "3:87": 268435456, + "4:87": 402653184, + "5:87": 268435456, + "6:87": 402653184, + "7:87": 268435456, + "8:87": 402653184, + "9:87": 268435456, + "10:87": 402653184, + "11:87": 268435456, + "12:87": 402653184, + "13:87": 268435456, + "14:87": 402653184, + "15:87": 268435456, + "16:87": 402653184, + "17:87": 268435456, + "18:87": 402653184, + "19:87": 268435456, + "20:87": 402653184, + "21:87": 268435456, + "22:87": -9288933, + "23:87": -9288933, + "24:87": -9288933, + "25:87": -9288933, + "26:87": -9288933, + "27:87": -9288933, + "28:87": -1, + "29:87": -1, + "30:87": -9288933, + "31:87": -1, + "32:87": -1, + "33:87": -9288933, + "34:87": -9288933, + "35:87": -9288933, + "36:87": -9288933, + "37:87": -9288933, + "38:87": -9288933, + "39:87": -9288933, + "40:87": -9288933, + "41:87": -9288933, + "42:87": -9288933, + "43:87": -9288933, + "44:87": -9288933, + "45:87": -9288933, + "46:87": -9288933, + "47:87": -9288933, + "48:87": -9288933, + "49:87": -9288933, + "50:87": -9288933, + "51:87": -9288933, + "52:87": -9288933, + "53:87": -9288933, + "54:87": -9288933, + "55:87": -9288933, + "56:87": -9288933, + "57:87": -9288933, + "58:87": -9288933, + "59:87": -9288933, + "60:87": -9288933, + "61:87": -9288933, + "62:87": -9288933, + "63:87": -9288933, + "64:87": -9288933, + "65:87": -9288933, + "66:87": -9288933, + "67:87": -9288933, + "68:87": -9288933, + "69:87": -9288933, + "70:87": -9288933, + "71:87": -9288933, + "72:87": -16745472, + "73:87": -16745472, + "74:87": -9288933, + "75:87": -16745472, + "76:87": -16745472, + "77:87": -9288933, + "78:87": -9288933, + "79:87": -9288933, + "80:87": -9288933, + "81:87": -9288933, + "82:87": -9288933, + "83:87": -9288933, + "84:87": 402653184, + "85:87": 268435456, + "86:87": 402653184, + "87:87": 268435456, + "88:87": -65536, + "89:87": -65536, + "90:87": -65536, + "91:87": -65536, + "92:87": -65536, + "93:87": -65536, + "94:87": -65536, + "95:87": -65536, + "96:87": -65536, + "97:87": -65536, + "98:87": -65536, + "99:87": -65536, + "100:87": -65536, + "101:87": -65536, + "102:87": -65536, + "103:87": -65536, + "104:87": -65536, + "105:87": -65536, + "106:87": 402653184, + "107:87": 268435456, + "108:87": 402653184, + "109:87": 268435456, + "110:87": 402653184, + "111:87": 268435456, + "112:87": 402653184, + "113:87": 268435456, + "114:87": 402653184, + "115:87": 268435456, + "116:87": 402653184, + "117:87": 268435456, + "118:87": 402653184, + "119:87": 268435456, + "120:87": 402653184, + "121:87": 268435456, + "122:87": 402653184, + "123:87": 268435456, + "124:87": 402653184, + "125:87": 268435456, + "126:87": 402653184, + "127:87": 268435456, + "0:88": 268435456, + "1:88": 402653184, + "2:88": 268435456, + "3:88": 402653184, + "4:88": 268435456, + "5:88": 402653184, + "6:88": 268435456, + "7:88": 402653184, + "8:88": 268435456, + "9:88": 402653184, + "10:88": 268435456, + "11:88": 402653184, + "12:88": 268435456, + "13:88": 402653184, + "14:88": 268435456, + "15:88": 402653184, + "16:88": 268435456, + "17:88": 402653184, + "18:88": 268435456, + "19:88": 402653184, + "20:88": 268435456, + "21:88": 402653184, + "22:88": -9288933, + "23:88": -9288933, + "24:88": -9288933, + "25:88": -9288933, + "26:88": -9288933, + "27:88": -9288933, + "28:88": -9288933, + "29:88": -1, + "30:88": -1, + "31:88": -1, + "32:88": -9288933, + "33:88": -9288933, + "34:88": -9288933, + "35:88": -9288933, + "36:88": -9288933, + "37:88": -9288933, + "38:88": -9288933, + "39:88": -9288933, + "40:88": -9288933, + "41:88": -9288933, + "42:88": -9288933, + "43:88": -9288933, + "44:88": -9288933, + "45:88": -9288933, + "46:88": -9288933, + "47:88": -9288933, + "48:88": -9288933, + "49:88": -9288933, + "50:88": -9288933, + "51:88": -9288933, + "52:88": -9288933, + "53:88": -9288933, + "54:88": -9288933, + "55:88": -9288933, + "56:88": -9288933, + "57:88": -9288933, + "58:88": -9288933, + "59:88": -9288933, + "60:88": -9288933, + "61:88": -9288933, + "62:88": -9288933, + "63:88": -9288933, + "64:88": -9288933, + "65:88": -9288933, + "66:88": -9288933, + "67:88": -9288933, + "68:88": -9288933, + "69:88": -9288933, + "70:88": -9288933, + "71:88": -9288933, + "72:88": -9288933, + "73:88": -16745472, + "74:88": -16745472, + "75:88": -16745472, + "76:88": -9288933, + "77:88": -9288933, + "78:88": -9288933, + "79:88": -9288933, + "80:88": -9288933, + "81:88": -9288933, + "82:88": -9288933, + "83:88": -9288933, + "84:88": 268435456, + "85:88": 402653184, + "86:88": 268435456, + "87:88": 402653184, + "88:88": -65536, + "89:88": -65536, + "90:88": -65536, + "91:88": -65536, + "92:88": -65536, + "93:88": -65536, + "94:88": -65536, + "95:88": -65536, + "96:88": -65536, + "97:88": -65536, + "98:88": -65536, + "99:88": -65536, + "100:88": -65536, + "101:88": -65536, + "102:88": -65536, + "103:88": -65536, + "104:88": -65536, + "105:88": -65536, + "106:88": 268435456, + "107:88": 402653184, + "108:88": 268435456, + "109:88": 402653184, + "110:88": 268435456, + "111:88": 402653184, + "112:88": 268435456, + "113:88": 402653184, + "114:88": 268435456, + "115:88": 402653184, + "116:88": 268435456, + "117:88": 402653184, + "118:88": 268435456, + "119:88": 402653184, + "120:88": 268435456, + "121:88": 402653184, + "122:88": 268435456, + "123:88": 402653184, + "124:88": 268435456, + "125:88": 402653184, + "126:88": 268435456, + "127:88": 402653184, + "0:89": 402653184, + "1:89": 268435456, + "2:89": 402653184, + "3:89": 268435456, + "4:89": 402653184, + "5:89": 268435456, + "6:89": 402653184, + "7:89": 268435456, + "8:89": 402653184, + "9:89": 268435456, + "10:89": 402653184, + "11:89": 268435456, + "12:89": 402653184, + "13:89": 268435456, + "14:89": 402653184, + "15:89": 268435456, + "16:89": 402653184, + "17:89": 268435456, + "18:89": 402653184, + "19:89": 268435456, + "20:89": 402653184, + "21:89": 268435456, + "22:89": -9288933, + "23:89": -9288933, + "24:89": -9288933, + "25:89": -9288933, + "26:89": -9288933, + "27:89": -9288933, + "28:89": -9288933, + "29:89": -1, + "30:89": -1, + "31:89": -1, + "32:89": -9288933, + "33:89": -9288933, + "34:89": -9288933, + "35:89": -9288933, + "36:89": -9288933, + "37:89": -9288933, + "38:89": -9288933, + "39:89": -9288933, + "40:89": -9288933, + "41:89": -9288933, + "42:89": -9288933, + "43:89": -9288933, + "44:89": -9288933, + "45:89": -9288933, + "46:89": -9288933, + "47:89": -9288933, + "48:89": -9288933, + "49:89": -9288933, + "50:89": -9288933, + "51:89": -9288933, + "52:89": -9288933, + "53:89": -9288933, + "54:89": -9288933, + "55:89": -9288933, + "56:89": -9288933, + "57:89": -9288933, + "58:89": -9288933, + "59:89": -9288933, + "60:89": -9288933, + "61:89": -9288933, + "62:89": -9288933, + "63:89": -9288933, + "64:89": -9288933, + "65:89": -9288933, + "66:89": -9288933, + "67:89": -9288933, + "68:89": -9288933, + "69:89": -9288933, + "70:89": -9288933, + "71:89": -9288933, + "72:89": -9288933, + "73:89": -16745472, + "74:89": -16745472, + "75:89": -16745472, + "76:89": -9288933, + "77:89": -9288933, + "78:89": -9288933, + "79:89": -9288933, + "80:89": -9288933, + "81:89": -9288933, + "82:89": -9288933, + "83:89": -9288933, + "84:89": 402653184, + "85:89": 268435456, + "86:89": 402653184, + "87:89": 268435456, + "88:89": -65536, + "89:89": -65536, + "90:89": -65536, + "91:89": -65536, + "92:89": -65536, + "93:89": -65536, + "94:89": -65536, + "95:89": -65536, + "96:89": -65536, + "97:89": -65536, + "98:89": -65536, + "99:89": -65536, + "100:89": -65536, + "101:89": -65536, + "102:89": -65536, + "103:89": -65536, + "104:89": -65536, + "105:89": -65536, + "106:89": 402653184, + "107:89": 268435456, + "108:89": 402653184, + "109:89": 268435456, + "110:89": 402653184, + "111:89": 268435456, + "112:89": 402653184, + "113:89": 268435456, + "114:89": 402653184, + "115:89": 268435456, + "116:89": 402653184, + "117:89": 268435456, + "118:89": 402653184, + "119:89": 268435456, + "120:89": 402653184, + "121:89": 268435456, + "122:89": 402653184, + "123:89": 268435456, + "124:89": 402653184, + "125:89": 268435456, + "126:89": 402653184, + "127:89": 268435456, + "0:90": 268435456, + "1:90": 402653184, + "2:90": 268435456, + "3:90": 402653184, + "4:90": 268435456, + "5:90": 402653184, + "6:90": 268435456, + "7:90": 402653184, + "8:90": 268435456, + "9:90": 402653184, + "10:90": 268435456, + "11:90": 402653184, + "12:90": 268435456, + "13:90": 402653184, + "14:90": 268435456, + "15:90": 402653184, + "16:90": 268435456, + "17:90": 402653184, + "18:90": 268435456, + "19:90": 402653184, + "20:90": 268435456, + "21:90": 402653184, + "22:90": -9288933, + "23:90": -9288933, + "24:90": -9288933, + "25:90": -9288933, + "26:90": -9288933, + "27:90": -9288933, + "28:90": -9288933, + "29:90": -9288933, + "30:90": -9288933, + "31:90": -9288933, + "32:90": -9288933, + "33:90": -9288933, + "34:90": -9288933, + "35:90": -9288933, + "36:90": -9288933, + "37:90": -9288933, + "38:90": -9288933, + "39:90": -9288933, + "40:90": -9288933, + "41:90": -9288933, + "42:90": -9288933, + "43:90": -9288933, + "44:90": -9288933, + "45:90": -9288933, + "46:90": -9288933, + "47:90": -9288933, + "48:90": -9288933, + "49:90": -9288933, + "50:90": -9288933, + "51:90": -9288933, + "52:90": -9288933, + "53:90": -9288933, + "54:90": -9288933, + "55:90": -9288933, + "56:90": -9288933, + "57:90": -9288933, + "58:90": -9288933, + "59:90": -9288933, + "60:90": -9288933, + "61:90": -9288933, + "62:90": 268435456, + "63:90": 402653184, + "64:90": 268435456, + "65:90": 402653184, + "66:90": -9288933, + "67:90": -9288933, + "68:90": -9288933, + "69:90": -9288933, + "70:90": -9288933, + "71:90": -9288933, + "72:90": -9288933, + "73:90": -9288933, + "74:90": -9288933, + "75:90": -9288933, + "76:90": -9288933, + "77:90": -9288933, + "78:90": -9288933, + "79:90": -9288933, + "80:90": -9288933, + "81:90": -9288933, + "82:90": -9288933, + "83:90": -9288933, + "84:90": 268435456, + "85:90": 402653184, + "86:90": 268435456, + "87:90": 402653184, + "88:90": -65536, + "89:90": -65536, + "90:90": -65536, + "91:90": -65536, + "92:90": -65536, + "93:90": -65536, + "94:90": -65536, + "95:90": -65536, + "96:90": -65536, + "97:90": -65536, + "98:90": -65536, + "99:90": -65536, + "100:90": -65536, + "101:90": -65536, + "102:90": -65536, + "103:90": -65536, + "104:90": -65536, + "105:90": -65536, + "106:90": 268435456, + "107:90": 402653184, + "108:90": 268435456, + "109:90": 402653184, + "110:90": 268435456, + "111:90": 402653184, + "112:90": 268435456, + "113:90": 402653184, + "114:90": 268435456, + "115:90": 402653184, + "116:90": 268435456, + "117:90": 402653184, + "118:90": 268435456, + "119:90": 402653184, + "120:90": 268435456, + "121:90": 402653184, + "122:90": 268435456, + "123:90": 402653184, + "124:90": 268435456, + "125:90": 402653184, + "126:90": 268435456, + "127:90": 402653184, + "0:91": 402653184, + "1:91": 268435456, + "2:91": 402653184, + "3:91": 268435456, + "4:91": 402653184, + "5:91": 268435456, + "6:91": 402653184, + "7:91": 268435456, + "8:91": 402653184, + "9:91": 268435456, + "10:91": 402653184, + "11:91": 268435456, + "12:91": 402653184, + "13:91": 268435456, + "14:91": 402653184, + "15:91": 268435456, + "16:91": 402653184, + "17:91": 268435456, + "18:91": 402653184, + "19:91": 268435456, + "20:91": 402653184, + "21:91": 268435456, + "22:91": -9288933, + "23:91": -9288933, + "24:91": -9288933, + "25:91": -9288933, + "26:91": -9288933, + "27:91": -9288933, + "28:91": -9288933, + "29:91": -9288933, + "30:91": -9288933, + "31:91": -9288933, + "32:91": -9288933, + "33:91": -9288933, + "34:91": -9288933, + "35:91": -9288933, + "36:91": -9288933, + "37:91": -9288933, + "38:91": -9288933, + "39:91": -9288933, + "40:91": -9288933, + "41:91": -9288933, + "42:91": -9288933, + "43:91": -9288933, + "44:91": -9288933, + "45:91": -9288933, + "46:91": -9288933, + "47:91": -9288933, + "48:91": -9288933, + "49:91": -9288933, + "50:91": -9288933, + "51:91": -9288933, + "52:91": -9288933, + "53:91": -9288933, + "54:91": -9288933, + "55:91": -9288933, + "56:91": -9288933, + "57:91": -9288933, + "58:91": -9288933, + "59:91": -9288933, + "60:91": -9288933, + "61:91": -9288933, + "62:91": 402653184, + "63:91": 268435456, + "64:91": 402653184, + "65:91": 268435456, + "66:91": -9288933, + "67:91": -9288933, + "68:91": -9288933, + "69:91": -9288933, + "70:91": -9288933, + "71:91": -9288933, + "72:91": -9288933, + "73:91": -9288933, + "74:91": -9288933, + "75:91": -9288933, + "76:91": -9288933, + "77:91": -9288933, + "78:91": -9288933, + "79:91": -9288933, + "80:91": -9288933, + "81:91": -9288933, + "82:91": -9288933, + "83:91": -9288933, + "84:91": 402653184, + "85:91": 268435456, + "86:91": 402653184, + "87:91": 268435456, + "88:91": -65536, + "89:91": -65536, + "90:91": -65536, + "91:91": -65536, + "92:91": -65536, + "93:91": -65536, + "94:91": -65536, + "95:91": -65536, + "96:91": -65536, + "97:91": -65536, + "98:91": -65536, + "99:91": -65536, + "100:91": -65536, + "101:91": -65536, + "102:91": -65536, + "103:91": -65536, + "104:91": -65536, + "105:91": -65536, + "106:91": 402653184, + "107:91": 268435456, + "108:91": 402653184, + "109:91": 268435456, + "110:91": 402653184, + "111:91": 268435456, + "112:91": 402653184, + "113:91": 268435456, + "114:91": 402653184, + "115:91": 268435456, + "116:91": 402653184, + "117:91": 268435456, + "118:91": 402653184, + "119:91": 268435456, + "120:91": 402653184, + "121:91": 268435456, + "122:91": 402653184, + "123:91": 268435456, + "124:91": 402653184, + "125:91": 268435456, + "126:91": 402653184, + "127:91": 268435456, + "0:92": 268435456, + "1:92": 402653184, + "2:92": 268435456, + "3:92": 402653184, + "4:92": 268435456, + "5:92": 402653184, + "6:92": 268435456, + "7:92": 402653184, + "8:92": 268435456, + "9:92": 402653184, + "10:92": 268435456, + "11:92": 402653184, + "12:92": 268435456, + "13:92": 402653184, + "14:92": 268435456, + "15:92": 402653184, + "16:92": 268435456, + "17:92": 402653184, + "18:92": 268435456, + "19:92": 402653184, + "20:92": 268435456, + "21:92": 402653184, + "22:92": -9288933, + "23:92": -9288933, + "24:92": -9288933, + "25:92": -9288933, + "26:92": -9288933, + "27:92": -9288933, + "28:92": -9288933, + "29:92": -9288933, + "30:92": -9288933, + "31:92": -9288933, + "32:92": -9288933, + "33:92": -9288933, + "34:92": -9288933, + "35:92": -9288933, + "36:92": -9288933, + "37:92": -9288933, + "38:92": -9288933, + "39:92": -9288933, + "40:92": -9288933, + "41:92": -9288933, + "42:92": -9288933, + "43:92": -9288933, + "44:92": -9288933, + "45:92": -9288933, + "46:92": -9288933, + "47:92": -9288933, + "48:92": -9288933, + "49:92": -9288933, + "50:92": -9288933, + "51:92": -9288933, + "52:92": -9288933, + "53:92": -9288933, + "54:92": -9288933, + "55:92": -9288933, + "56:92": -9288933, + "57:92": -9288933, + "58:92": -9288933, + "59:92": -9288933, + "60:92": -9288933, + "61:92": -9288933, + "62:92": 268435456, + "63:92": 402653184, + "64:92": 268435456, + "65:92": 402653184, + "66:92": -9288933, + "67:92": -9288933, + "68:92": -9288933, + "69:92": -9288933, + "70:92": -9288933, + "71:92": -9288933, + "72:92": -9288933, + "73:92": -9288933, + "74:92": -9288933, + "75:92": -9288933, + "76:92": -9288933, + "77:92": -9288933, + "78:92": -9288933, + "79:92": -9288933, + "80:92": -9288933, + "81:92": -9288933, + "82:92": -9288933, + "83:92": -9288933, + "84:92": 268435456, + "85:92": 402653184, + "86:92": 268435456, + "87:92": 402653184, + "88:92": -65536, + "89:92": -65536, + "90:92": -65536, + "91:92": -65536, + "92:92": -65536, + "93:92": -65536, + "94:92": -65536, + "95:92": -65536, + "96:92": -65536, + "97:92": -65536, + "98:92": -65536, + "99:92": -65536, + "100:92": -65536, + "101:92": -65536, + "102:92": -65536, + "103:92": -65536, + "104:92": -65536, + "105:92": -65536, + "106:92": 268435456, + "107:92": 402653184, + "108:92": 268435456, + "109:92": 402653184, + "110:92": 268435456, + "111:92": 402653184, + "112:92": 268435456, + "113:92": 402653184, + "114:92": 268435456, + "115:92": 402653184, + "116:92": 268435456, + "117:92": 402653184, + "118:92": 268435456, + "119:92": 402653184, + "120:92": 268435456, + "121:92": 402653184, + "122:92": 268435456, + "123:92": 402653184, + "124:92": 268435456, + "125:92": 402653184, + "126:92": 268435456, + "127:92": 402653184, + "0:93": 402653184, + "1:93": 268435456, + "2:93": 402653184, + "3:93": 268435456, + "4:93": 402653184, + "5:93": 268435456, + "6:93": 402653184, + "7:93": 268435456, + "8:93": 402653184, + "9:93": 268435456, + "10:93": 402653184, + "11:93": 268435456, + "12:93": 402653184, + "13:93": 268435456, + "14:93": 402653184, + "15:93": 268435456, + "16:93": 402653184, + "17:93": 268435456, + "18:93": 402653184, + "19:93": 268435456, + "20:93": 402653184, + "21:93": 268435456, + "22:93": -9288933, + "23:93": -9288933, + "24:93": -9288933, + "25:93": -9288933, + "26:93": -9288933, + "27:93": -9288933, + "28:93": -9288933, + "29:93": -9288933, + "30:93": -9288933, + "31:93": -9288933, + "32:93": -9288933, + "33:93": -9288933, + "34:93": -9288933, + "35:93": -9288933, + "36:93": -9288933, + "37:93": -9288933, + "38:93": -9288933, + "39:93": -9288933, + "40:93": -9288933, + "41:93": -9288933, + "42:93": -9288933, + "43:93": -9288933, + "44:93": -9288933, + "45:93": -9288933, + "46:93": -9288933, + "47:93": -9288933, + "48:93": -9288933, + "49:93": -9288933, + "50:93": -9288933, + "51:93": -9288933, + "52:93": -9288933, + "53:93": -9288933, + "54:93": -9288933, + "55:93": -9288933, + "56:93": -9288933, + "57:93": -9288933, + "58:93": -9288933, + "59:93": -9288933, + "60:93": -9288933, + "61:93": -9288933, + "62:93": 402653184, + "63:93": 268435456, + "64:93": 402653184, + "65:93": 268435456, + "66:93": -9288933, + "67:93": -9288933, + "68:93": -9288933, + "69:93": -9288933, + "70:93": -9288933, + "71:93": -9288933, + "72:93": -9288933, + "73:93": -9288933, + "74:93": -9288933, + "75:93": -9288933, + "76:93": -9288933, + "77:93": -9288933, + "78:93": -9288933, + "79:93": -9288933, + "80:93": -9288933, + "81:93": -9288933, + "82:93": -9288933, + "83:93": -9288933, + "84:93": 402653184, + "85:93": 268435456, + "86:93": 402653184, + "87:93": 268435456, + "88:93": -65536, + "89:93": -65536, + "90:93": -65536, + "91:93": -65536, + "92:93": -65536, + "93:93": -65536, + "94:93": -65536, + "95:93": -65536, + "96:93": -65536, + "97:93": -65536, + "98:93": -65536, + "99:93": -65536, + "100:93": -65536, + "101:93": -65536, + "102:93": -65536, + "103:93": -65536, + "104:93": -65536, + "105:93": -65536, + "106:93": 402653184, + "107:93": 268435456, + "108:93": 402653184, + "109:93": 268435456, + "110:93": 402653184, + "111:93": 268435456, + "112:93": 402653184, + "113:93": 268435456, + "114:93": 402653184, + "115:93": 268435456, + "116:93": 402653184, + "117:93": 268435456, + "118:93": 402653184, + "119:93": 268435456, + "120:93": 402653184, + "121:93": 268435456, + "122:93": 402653184, + "123:93": 268435456, + "124:93": 402653184, + "125:93": 268435456, + "126:93": 402653184, + "127:93": 268435456, + "0:94": 268435456, + "1:94": 402653184, + "2:94": 268435456, + "3:94": 402653184, + "4:94": 268435456, + "5:94": 402653184, + "6:94": 268435456, + "7:94": 402653184, + "8:94": 268435456, + "9:94": 402653184, + "10:94": 268435456, + "11:94": 402653184, + "12:94": 268435456, + "13:94": 402653184, + "14:94": 268435456, + "15:94": 402653184, + "16:94": 268435456, + "17:94": 402653184, + "18:94": 268435456, + "19:94": 402653184, + "20:94": 268435456, + "21:94": 402653184, + "22:94": -9288933, + "23:94": -9288933, + "24:94": -9288933, + "25:94": -9288933, + "26:94": -9288933, + "27:94": -9288933, + "28:94": -9288933, + "29:94": -9288933, + "30:94": -9288933, + "31:94": -9288933, + "32:94": -9288933, + "33:94": -9288933, + "34:94": -9288933, + "35:94": -9288933, + "36:94": -9288933, + "37:94": -9288933, + "38:94": -9288933, + "39:94": -9288933, + "40:94": -9288933, + "41:94": -9288933, + "42:94": -9288933, + "43:94": -9288933, + "44:94": -9288933, + "45:94": -9288933, + "46:94": -9288933, + "47:94": -9288933, + "48:94": -9288933, + "49:94": -9288933, + "50:94": -9288933, + "51:94": -9288933, + "52:94": -9288933, + "53:94": -9288933, + "54:94": -9288933, + "55:94": -9288933, + "56:94": -9288933, + "57:94": -9288933, + "58:94": -9288933, + "59:94": -9288933, + "60:94": -9288933, + "61:94": -9288933, + "62:94": 268435456, + "63:94": 402653184, + "64:94": 268435456, + "65:94": 402653184, + "66:94": -9288933, + "67:94": -9288933, + "68:94": -9288933, + "69:94": -9288933, + "70:94": -9288933, + "71:94": -9288933, + "72:94": -9288933, + "73:94": -9288933, + "74:94": -9288933, + "75:94": -9288933, + "76:94": -9288933, + "77:94": -9288933, + "78:94": -9288933, + "79:94": -9288933, + "80:94": -9288933, + "81:94": -9288933, + "82:94": -9288933, + "83:94": -9288933, + "84:94": 268435456, + "85:94": 402653184, + "86:94": 268435456, + "87:94": 402653184, + "88:94": -65536, + "89:94": -65536, + "90:94": -65536, + "91:94": -65536, + "92:94": -65536, + "93:94": -65536, + "94:94": -65536, + "95:94": -65536, + "96:94": -65536, + "97:94": -65536, + "98:94": -65536, + "99:94": -65536, + "100:94": -65536, + "101:94": -65536, + "102:94": -65536, + "103:94": -65536, + "104:94": -65536, + "105:94": -65536, + "106:94": 268435456, + "107:94": 402653184, + "108:94": 268435456, + "109:94": 402653184, + "110:94": 268435456, + "111:94": 402653184, + "112:94": 268435456, + "113:94": 402653184, + "114:94": 268435456, + "115:94": 402653184, + "116:94": 268435456, + "117:94": 402653184, + "118:94": 268435456, + "119:94": 402653184, + "120:94": 268435456, + "121:94": 402653184, + "122:94": 268435456, + "123:94": 402653184, + "124:94": 268435456, + "125:94": 402653184, + "126:94": 268435456, + "127:94": 402653184, + "0:95": 402653184, + "1:95": 268435456, + "2:95": 402653184, + "3:95": 268435456, + "4:95": 402653184, + "5:95": 268435456, + "6:95": 402653184, + "7:95": 268435456, + "8:95": 402653184, + "9:95": 268435456, + "10:95": 402653184, + "11:95": 268435456, + "12:95": 402653184, + "13:95": 268435456, + "14:95": 402653184, + "15:95": 268435456, + "16:95": 402653184, + "17:95": 268435456, + "18:95": 402653184, + "19:95": 268435456, + "20:95": 402653184, + "21:95": 268435456, + "22:95": -9288933, + "23:95": -9288933, + "24:95": -9288933, + "25:95": -9288933, + "26:95": -9288933, + "27:95": -9288933, + "28:95": -9288933, + "29:95": -9288933, + "30:95": -9288933, + "31:95": -9288933, + "32:95": -9288933, + "33:95": -9288933, + "34:95": -9288933, + "35:95": -9288933, + "36:95": -9288933, + "37:95": -9288933, + "38:95": -9288933, + "39:95": -9288933, + "40:95": 402653184, + "41:95": 268435456, + "42:95": 402653184, + "43:95": 268435456, + "44:95": 402653184, + "45:95": 268435456, + "46:95": 402653184, + "47:95": 268435456, + "48:95": 402653184, + "49:95": 268435456, + "50:95": -1710797, + "51:95": -1710797, + "52:95": -1710797, + "53:95": -1710797, + "54:95": -1710797, + "55:95": -1710797, + "56:95": -1710797, + "57:95": 268435456, + "58:95": 402653184, + "59:95": 268435456, + "60:95": 402653184, + "61:95": 268435456, + "62:95": 402653184, + "63:95": 268435456, + "64:95": 402653184, + "65:95": 268435456, + "66:95": 402653184, + "67:95": 268435456, + "68:95": 402653184, + "69:95": 268435456, + "70:95": 402653184, + "71:95": 268435456, + "72:95": -9288933, + "73:95": -9288933, + "74:95": -9288933, + "75:95": -9288933, + "76:95": -9288933, + "77:95": -9288933, + "78:95": -9288933, + "79:95": 268435456, + "80:95": 402653184, + "81:95": 268435456, + "82:95": 402653184, + "83:95": 268435456, + "84:95": 402653184, + "85:95": 268435456, + "86:95": 402653184, + "87:95": 268435456, + "88:95": 402653184, + "89:95": 268435456, + "90:95": 402653184, + "91:95": 268435456, + "92:95": 402653184, + "93:95": 268435456, + "94:95": 402653184, + "95:95": 268435456, + "96:95": 402653184, + "97:95": 268435456, + "98:95": 402653184, + "99:95": 268435456, + "100:95": 402653184, + "101:95": 268435456, + "102:95": 402653184, + "103:95": 268435456, + "104:95": 402653184, + "105:95": 268435456, + "106:95": 402653184, + "107:95": 268435456, + "108:95": 402653184, + "109:95": 268435456, + "110:95": 402653184, + "111:95": 268435456, + "112:95": 402653184, + "113:95": 268435456, + "114:95": 402653184, + "115:95": 268435456, + "116:95": 402653184, + "117:95": 268435456, + "118:95": 402653184, + "119:95": 268435456, + "120:95": 402653184, + "121:95": 268435456, + "122:95": 402653184, + "123:95": 268435456, + "124:95": 402653184, + "125:95": 268435456, + "126:95": 402653184, + "127:95": 268435456, + "0:96": 268435456, + "1:96": 402653184, + "2:96": 268435456, + "3:96": 402653184, + "4:96": 268435456, + "5:96": 402653184, + "6:96": 268435456, + "7:96": 402653184, + "8:96": 268435456, + "9:96": 402653184, + "10:96": 268435456, + "11:96": 402653184, + "12:96": 268435456, + "13:96": 402653184, + "14:96": 268435456, + "15:96": 402653184, + "16:96": 268435456, + "17:96": 402653184, + "18:96": 268435456, + "19:96": 402653184, + "20:96": 268435456, + "21:96": 402653184, + "22:96": -9288933, + "23:96": -9288933, + "24:96": -9288933, + "25:96": -9288933, + "26:96": -9288933, + "27:96": -9288933, + "28:96": -9288933, + "29:96": -9288933, + "30:96": -9288933, + "31:96": -9288933, + "32:96": -9288933, + "33:96": -9288933, + "34:96": -9288933, + "35:96": -9288933, + "36:96": -9288933, + "37:96": -9288933, + "38:96": -9288933, + "39:96": -9288933, + "40:96": 268435456, + "41:96": 402653184, + "42:96": 268435456, + "43:96": 402653184, + "44:96": 268435456, + "45:96": 402653184, + "46:96": 268435456, + "47:96": 402653184, + "48:96": 268435456, + "49:96": 402653184, + "50:96": -1710797, + "51:96": -1710797, + "52:96": -1710797, + "53:96": -1710797, + "54:96": -1710797, + "55:96": -1710797, + "56:96": -1710797, + "57:96": 402653184, + "58:96": 268435456, + "59:96": 402653184, + "60:96": 268435456, + "61:96": 402653184, + "62:96": 268435456, + "63:96": 402653184, + "64:96": 268435456, + "65:96": 402653184, + "66:96": 268435456, + "67:96": 402653184, + "68:96": 268435456, + "69:96": 402653184, + "70:96": 268435456, + "71:96": 402653184, + "72:96": -9288933, + "73:96": -9288933, + "74:96": -9288933, + "75:96": -9288933, + "76:96": -9288933, + "77:96": -9288933, + "78:96": -9288933, + "79:96": 402653184, + "80:96": 268435456, + "81:96": 402653184, + "82:96": 268435456, + "83:96": 402653184, + "84:96": 268435456, + "85:96": 402653184, + "86:96": 268435456, + "87:96": 402653184, + "88:96": 268435456, + "89:96": 402653184, + "90:96": 268435456, + "91:96": 402653184, + "92:96": 268435456, + "93:96": 402653184, + "94:96": 268435456, + "95:96": 402653184, + "96:96": 268435456, + "97:96": 402653184, + "98:96": 268435456, + "99:96": 402653184, + "100:96": 268435456, + "101:96": 402653184, + "102:96": 268435456, + "103:96": 402653184, + "104:96": 268435456, + "105:96": 402653184, + "106:96": 268435456, + "107:96": 402653184, + "108:96": 268435456, + "109:96": 402653184, + "110:96": 268435456, + "111:96": 402653184, + "112:96": 268435456, + "113:96": 402653184, + "114:96": 268435456, + "115:96": 402653184, + "116:96": 268435456, + "117:96": 402653184, + "118:96": 268435456, + "119:96": 402653184, + "120:96": 268435456, + "121:96": 402653184, + "122:96": 268435456, + "123:96": 402653184, + "124:96": 268435456, + "125:96": 402653184, + "126:96": 268435456, + "127:96": 402653184, + "0:97": 402653184, + "1:97": 268435456, + "2:97": 402653184, + "3:97": 268435456, + "4:97": 402653184, + "5:97": 268435456, + "6:97": 402653184, + "7:97": 268435456, + "8:97": 402653184, + "9:97": 268435456, + "10:97": 402653184, + "11:97": 268435456, + "12:97": 402653184, + "13:97": 268435456, + "14:97": 402653184, + "15:97": 268435456, + "16:97": 402653184, + "17:97": 268435456, + "18:97": 402653184, + "19:97": 268435456, + "20:97": 402653184, + "21:97": 268435456, + "22:97": -9288933, + "23:97": -9288933, + "24:97": -9288933, + "25:97": -9288933, + "26:97": -9288933, + "27:97": -9288933, + "28:97": -9288933, + "29:97": -9288933, + "30:97": -9288933, + "31:97": -9288933, + "32:97": -9288933, + "33:97": -9288933, + "34:97": -9288933, + "35:97": -9288933, + "36:97": -9288933, + "37:97": -9288933, + "38:97": -9288933, + "39:97": -9288933, + "40:97": 402653184, + "41:97": 268435456, + "42:97": 402653184, + "43:97": 268435456, + "44:97": 402653184, + "45:97": 268435456, + "46:97": 402653184, + "47:97": 268435456, + "48:97": 402653184, + "49:97": 268435456, + "50:97": -1710797, + "51:97": -1710797, + "52:97": -1710797, + "53:97": -1710797, + "54:97": -1710797, + "55:97": -1710797, + "56:97": -1710797, + "57:97": 268435456, + "58:97": 402653184, + "59:97": 268435456, + "60:97": 402653184, + "61:97": 268435456, + "62:97": 402653184, + "63:97": 268435456, + "64:97": 402653184, + "65:97": 268435456, + "66:97": 402653184, + "67:97": 268435456, + "68:97": 402653184, + "69:97": 268435456, + "70:97": 402653184, + "71:97": 268435456, + "72:97": -9288933, + "73:97": -9288933, + "74:97": -9288933, + "75:97": -9288933, + "76:97": -9288933, + "77:97": -9288933, + "78:97": -9288933, + "79:97": 268435456, + "80:97": 402653184, + "81:97": 268435456, + "82:97": 402653184, + "83:97": 268435456, + "84:97": 402653184, + "85:97": 268435456, + "86:97": 402653184, + "87:97": 268435456, + "88:97": 402653184, + "89:97": 268435456, + "90:97": 402653184, + "91:97": 268435456, + "92:97": 402653184, + "93:97": 268435456, + "94:97": 402653184, + "95:97": 268435456, + "96:97": 402653184, + "97:97": 268435456, + "98:97": 402653184, + "99:97": 268435456, + "100:97": 402653184, + "101:97": 268435456, + "102:97": 402653184, + "103:97": 268435456, + "104:97": 402653184, + "105:97": 268435456, + "106:97": 402653184, + "107:97": 268435456, + "108:97": 402653184, + "109:97": 268435456, + "110:97": 402653184, + "111:97": 268435456, + "112:97": 402653184, + "113:97": 268435456, + "114:97": 402653184, + "115:97": 268435456, + "116:97": 402653184, + "117:97": 268435456, + "118:97": 402653184, + "119:97": 268435456, + "120:97": 402653184, + "121:97": 268435456, + "122:97": 402653184, + "123:97": 268435456, + "124:97": 402653184, + "125:97": 268435456, + "126:97": 402653184, + "127:97": 268435456, + "0:98": 268435456, + "1:98": 402653184, + "2:98": 268435456, + "3:98": 402653184, + "4:98": 268435456, + "5:98": 402653184, + "6:98": 268435456, + "7:98": 402653184, + "8:98": 268435456, + "9:98": 402653184, + "10:98": 268435456, + "11:98": 402653184, + "12:98": 268435456, + "13:98": 402653184, + "14:98": 268435456, + "15:98": 402653184, + "16:98": 268435456, + "17:98": 402653184, + "18:98": 268435456, + "19:98": 402653184, + "20:98": 268435456, + "21:98": 402653184, + "22:98": -9288933, + "23:98": -9288933, + "24:98": -9288933, + "25:98": -9288933, + "26:98": -9288933, + "27:98": -9288933, + "28:98": -9288933, + "29:98": -9288933, + "30:98": -9288933, + "31:98": -9288933, + "32:98": -9288933, + "33:98": -9288933, + "34:98": -9288933, + "35:98": -9288933, + "36:98": -9288933, + "37:98": -9288933, + "38:98": -9288933, + "39:98": -9288933, + "40:98": 268435456, + "41:98": 402653184, + "42:98": 268435456, + "43:98": 402653184, + "44:98": 268435456, + "45:98": 402653184, + "46:98": 268435456, + "47:98": 402653184, + "48:98": 268435456, + "49:98": 402653184, + "50:98": -1710797, + "51:98": -1710797, + "52:98": -1710797, + "53:98": -1710797, + "54:98": -1710797, + "55:98": -1710797, + "56:98": -1710797, + "57:98": 402653184, + "58:98": 268435456, + "59:98": 402653184, + "60:98": 268435456, + "61:98": 402653184, + "62:98": 268435456, + "63:98": 402653184, + "64:98": 268435456, + "65:98": 402653184, + "66:98": 268435456, + "67:98": 402653184, + "68:98": 268435456, + "69:98": 402653184, + "70:98": 268435456, + "71:98": 402653184, + "72:98": -9288933, + "73:98": -9288933, + "74:98": -9288933, + "75:98": -9288933, + "76:98": -9288933, + "77:98": -9288933, + "78:98": -9288933, + "79:98": 402653184, + "80:98": 268435456, + "81:98": 402653184, + "82:98": 268435456, + "83:98": 402653184, + "84:98": 268435456, + "85:98": 402653184, + "86:98": 268435456, + "87:98": 402653184, + "88:98": 268435456, + "89:98": 402653184, + "90:98": 268435456, + "91:98": 402653184, + "92:98": 268435456, + "93:98": 402653184, + "94:98": 268435456, + "95:98": 402653184, + "96:98": 268435456, + "97:98": 402653184, + "98:98": 268435456, + "99:98": 402653184, + "100:98": 268435456, + "101:98": 402653184, + "102:98": 268435456, + "103:98": 402653184, + "104:98": 268435456, + "105:98": 402653184, + "106:98": 268435456, + "107:98": 402653184, + "108:98": 268435456, + "109:98": 402653184, + "110:98": 268435456, + "111:98": 402653184, + "112:98": 268435456, + "113:98": 402653184, + "114:98": 268435456, + "115:98": 402653184, + "116:98": 268435456, + "117:98": 402653184, + "118:98": 268435456, + "119:98": 402653184, + "120:98": 268435456, + "121:98": 402653184, + "122:98": 268435456, + "123:98": 402653184, + "124:98": 268435456, + "125:98": 402653184, + "126:98": 268435456, + "127:98": 402653184, + "0:99": 402653184, + "1:99": 268435456, + "2:99": 402653184, + "3:99": 268435456, + "4:99": 402653184, + "5:99": 268435456, + "6:99": 402653184, + "7:99": 268435456, + "8:99": 402653184, + "9:99": 268435456, + "10:99": 402653184, + "11:99": 268435456, + "12:99": 402653184, + "13:99": 268435456, + "14:99": 402653184, + "15:99": 268435456, + "16:99": 402653184, + "17:99": 268435456, + "18:99": 402653184, + "19:99": 268435456, + "20:99": 402653184, + "21:99": 268435456, + "22:99": -9288933, + "23:99": -9288933, + "24:99": -9288933, + "25:99": -9288933, + "26:99": -9288933, + "27:99": -9288933, + "28:99": -9288933, + "29:99": -9288933, + "30:99": -9288933, + "31:99": -9288933, + "32:99": -9288933, + "33:99": -9288933, + "34:99": -9288933, + "35:99": -9288933, + "36:99": -9288933, + "37:99": -9288933, + "38:99": -9288933, + "39:99": -9288933, + "40:99": 402653184, + "41:99": 268435456, + "42:99": 402653184, + "43:99": 268435456, + "44:99": -1710797, + "45:99": -1710797, + "46:99": -1710797, + "47:99": -1710797, + "48:99": -1710797, + "49:99": -1710797, + "50:99": -1710797, + "51:99": -1710797, + "52:99": -1710797, + "53:99": -1710797, + "54:99": -1710797, + "55:99": -1710797, + "56:99": -1710797, + "57:99": -1710797, + "58:99": -1710797, + "59:99": -1710797, + "60:99": -1710797, + "61:99": -1710797, + "62:99": 402653184, + "63:99": 268435456, + "64:99": 402653184, + "65:99": 268435456, + "66:99": -9288933, + "67:99": -9288933, + "68:99": -9288933, + "69:99": -9288933, + "70:99": -9288933, + "71:99": -9288933, + "72:99": -9288933, + "73:99": -9288933, + "74:99": -9288933, + "75:99": -9288933, + "76:99": -9288933, + "77:99": -9288933, + "78:99": -9288933, + "79:99": -9288933, + "80:99": -9288933, + "81:99": -9288933, + "82:99": -9288933, + "83:99": -9288933, + "84:99": 402653184, + "85:99": 268435456, + "86:99": 402653184, + "87:99": 268435456, + "88:99": -5092136, + "89:99": -5092136, + "90:99": -5092136, + "91:99": -5092136, + "92:99": -5092136, + "93:99": -5092136, + "94:99": -5092136, + "95:99": -5092136, + "96:99": -5092136, + "97:99": -5092136, + "98:99": -5092136, + "99:99": -5092136, + "100:99": -5092136, + "101:99": -5092136, + "102:99": -5092136, + "103:99": -5092136, + "104:99": -5092136, + "105:99": -5092136, + "106:99": 402653184, + "107:99": 268435456, + "108:99": 402653184, + "109:99": 268435456, + "110:99": 402653184, + "111:99": 268435456, + "112:99": 402653184, + "113:99": 268435456, + "114:99": 402653184, + "115:99": 268435456, + "116:99": 402653184, + "117:99": 268435456, + "118:99": 402653184, + "119:99": 268435456, + "120:99": 402653184, + "121:99": 268435456, + "122:99": 402653184, + "123:99": 268435456, + "124:99": 402653184, + "125:99": 268435456, + "126:99": 402653184, + "127:99": 268435456, + "0:100": 268435456, + "1:100": 402653184, + "2:100": 268435456, + "3:100": 402653184, + "4:100": 268435456, + "5:100": 402653184, + "6:100": 268435456, + "7:100": 402653184, + "8:100": 268435456, + "9:100": 402653184, + "10:100": 268435456, + "11:100": 402653184, + "12:100": 268435456, + "13:100": 402653184, + "14:100": 268435456, + "15:100": 402653184, + "16:100": 268435456, + "17:100": 402653184, + "18:100": 268435456, + "19:100": 402653184, + "20:100": 268435456, + "21:100": 402653184, + "22:100": -9288933, + "23:100": -9288933, + "24:100": -9288933, + "25:100": -9288933, + "26:100": -9288933, + "27:100": -9288933, + "28:100": -9288933, + "29:100": -9288933, + "30:100": -9288933, + "31:100": -9288933, + "32:100": -9288933, + "33:100": -9288933, + "34:100": -9288933, + "35:100": -9288933, + "36:100": -9288933, + "37:100": -9288933, + "38:100": -9288933, + "39:100": -9288933, + "40:100": 268435456, + "41:100": 402653184, + "42:100": 268435456, + "43:100": 402653184, + "44:100": -1710797, + "45:100": -1710797, + "46:100": -1710797, + "47:100": -1710797, + "48:100": -1710797, + "49:100": -1710797, + "50:100": -1710797, + "51:100": -1710797, + "52:100": -1710797, + "53:100": -1710797, + "54:100": -1710797, + "55:100": -1710797, + "56:100": -1710797, + "57:100": -1710797, + "58:100": -1710797, + "59:100": -1710797, + "60:100": -1710797, + "61:100": -1710797, + "62:100": 268435456, + "63:100": 402653184, + "64:100": 268435456, + "65:100": 402653184, + "66:100": -9288933, + "67:100": -9288933, + "68:100": -9288933, + "69:100": -9288933, + "70:100": -9288933, + "71:100": -9288933, + "72:100": -9288933, + "73:100": -9288933, + "74:100": -9288933, + "75:100": -9288933, + "76:100": -9288933, + "77:100": -9288933, + "78:100": -9288933, + "79:100": -9288933, + "80:100": -9288933, + "81:100": -9288933, + "82:100": -9288933, + "83:100": -9288933, + "84:100": 268435456, + "85:100": 402653184, + "86:100": 268435456, + "87:100": 402653184, + "88:100": -5092136, + "89:100": -5092136, + "90:100": -5092136, + "91:100": -5092136, + "92:100": -5092136, + "93:100": -5092136, + "94:100": -5092136, + "95:100": -5092136, + "96:100": -5092136, + "97:100": -5092136, + "98:100": -5092136, + "99:100": -5092136, + "100:100": -5092136, + "101:100": -5092136, + "102:100": -5092136, + "103:100": -5092136, + "104:100": -5092136, + "105:100": -5092136, + "106:100": 268435456, + "107:100": 402653184, + "108:100": 268435456, + "109:100": 402653184, + "110:100": 268435456, + "111:100": 402653184, + "112:100": 268435456, + "113:100": 402653184, + "114:100": 268435456, + "115:100": 402653184, + "116:100": 268435456, + "117:100": 402653184, + "118:100": 268435456, + "119:100": 402653184, + "120:100": 268435456, + "121:100": 402653184, + "122:100": 268435456, + "123:100": 402653184, + "124:100": 268435456, + "125:100": 402653184, + "126:100": 268435456, + "127:100": 402653184, + "0:101": 402653184, + "1:101": 268435456, + "2:101": 402653184, + "3:101": 268435456, + "4:101": 402653184, + "5:101": 268435456, + "6:101": 402653184, + "7:101": 268435456, + "8:101": 402653184, + "9:101": 268435456, + "10:101": 402653184, + "11:101": 268435456, + "12:101": 402653184, + "13:101": 268435456, + "14:101": 402653184, + "15:101": 268435456, + "16:101": 402653184, + "17:101": 268435456, + "18:101": 402653184, + "19:101": 268435456, + "20:101": 402653184, + "21:101": 268435456, + "22:101": -9288933, + "23:101": -9288933, + "24:101": -9288933, + "25:101": -9288933, + "26:101": -9288933, + "27:101": -9288933, + "28:101": -9288933, + "29:101": -9288933, + "30:101": -9288933, + "31:101": -9288933, + "32:101": -9288933, + "33:101": -9288933, + "34:101": -9288933, + "35:101": -9288933, + "36:101": -9288933, + "37:101": -9288933, + "38:101": -9288933, + "39:101": -9288933, + "40:101": 402653184, + "41:101": 268435456, + "42:101": 402653184, + "43:101": 268435456, + "44:101": -1710797, + "45:101": -1710797, + "46:101": -1710797, + "47:101": -1710797, + "48:101": -1710797, + "49:101": -1710797, + "50:101": -1710797, + "51:101": -1710797, + "52:101": -1710797, + "53:101": -1710797, + "54:101": -1710797, + "55:101": -1710797, + "56:101": -1710797, + "57:101": -1710797, + "58:101": -1710797, + "59:101": -1710797, + "60:101": -1710797, + "61:101": -1710797, + "62:101": 402653184, + "63:101": 268435456, + "64:101": 402653184, + "65:101": 268435456, + "66:101": -9288933, + "67:101": -9288933, + "68:101": -9288933, + "69:101": -9288933, + "70:101": -9288933, + "71:101": -9288933, + "72:101": -9288933, + "73:101": -9288933, + "74:101": -9288933, + "75:101": -9288933, + "76:101": -9288933, + "77:101": -9288933, + "78:101": -9288933, + "79:101": -9288933, + "80:101": -9288933, + "81:101": -9288933, + "82:101": -9288933, + "83:101": -9288933, + "84:101": 402653184, + "85:101": 268435456, + "86:101": 402653184, + "87:101": 268435456, + "88:101": -5092136, + "89:101": -5092136, + "90:101": -5092136, + "91:101": -5092136, + "92:101": -5092136, + "93:101": -5092136, + "94:101": -5092136, + "95:101": -5092136, + "96:101": -5092136, + "97:101": -5092136, + "98:101": -5092136, + "99:101": -5092136, + "100:101": -5092136, + "101:101": -5092136, + "102:101": -5092136, + "103:101": -5092136, + "104:101": -5092136, + "105:101": -5092136, + "106:101": 402653184, + "107:101": 268435456, + "108:101": 402653184, + "109:101": 268435456, + "110:101": 402653184, + "111:101": 268435456, + "112:101": 402653184, + "113:101": 268435456, + "114:101": 402653184, + "115:101": 268435456, + "116:101": 402653184, + "117:101": 268435456, + "118:101": 402653184, + "119:101": 268435456, + "120:101": 402653184, + "121:101": 268435456, + "122:101": 402653184, + "123:101": 268435456, + "124:101": 402653184, + "125:101": 268435456, + "126:101": 402653184, + "127:101": 268435456, + "0:102": 268435456, + "1:102": 402653184, + "2:102": 268435456, + "3:102": 402653184, + "4:102": 268435456, + "5:102": 402653184, + "6:102": 268435456, + "7:102": 402653184, + "8:102": 268435456, + "9:102": 402653184, + "10:102": 268435456, + "11:102": 402653184, + "12:102": 268435456, + "13:102": 402653184, + "14:102": 268435456, + "15:102": 402653184, + "16:102": 268435456, + "17:102": 402653184, + "18:102": 268435456, + "19:102": 402653184, + "20:102": 268435456, + "21:102": 402653184, + "22:102": -9288933, + "23:102": -9288933, + "24:102": -9288933, + "25:102": -9288933, + "26:102": -9288933, + "27:102": -9288933, + "28:102": -9288933, + "29:102": -9288933, + "30:102": -9288933, + "31:102": -9288933, + "32:102": -9288933, + "33:102": -9288933, + "34:102": -9288933, + "35:102": -9288933, + "36:102": -9288933, + "37:102": -9288933, + "38:102": -9288933, + "39:102": -9288933, + "40:102": 268435456, + "41:102": 402653184, + "42:102": 268435456, + "43:102": 402653184, + "44:102": -1710797, + "45:102": -1710797, + "46:102": -1710797, + "47:102": -1710797, + "48:102": -1710797, + "49:102": -1710797, + "50:102": -1710797, + "51:102": -1710797, + "52:102": -1710797, + "53:102": -1710797, + "54:102": -1710797, + "55:102": -1710797, + "56:102": -1710797, + "57:102": -1710797, + "58:102": -1710797, + "59:102": -1710797, + "60:102": -1710797, + "61:102": -1710797, + "62:102": 268435456, + "63:102": 402653184, + "64:102": 268435456, + "65:102": 402653184, + "66:102": -9288933, + "67:102": -9288933, + "68:102": -9288933, + "69:102": -9288933, + "70:102": -9288933, + "71:102": -9288933, + "72:102": -9288933, + "73:102": -9288933, + "74:102": -9288933, + "75:102": -9288933, + "76:102": -9288933, + "77:102": -9288933, + "78:102": -9288933, + "79:102": -9288933, + "80:102": -9288933, + "81:102": -9288933, + "82:102": -9288933, + "83:102": -9288933, + "84:102": 268435456, + "85:102": 402653184, + "86:102": 268435456, + "87:102": 402653184, + "88:102": -5092136, + "89:102": -5092136, + "90:102": -5092136, + "91:102": -5092136, + "92:102": -5092136, + "93:102": -5092136, + "94:102": -5092136, + "95:102": -5092136, + "96:102": -5092136, + "97:102": -5092136, + "98:102": -5092136, + "99:102": -5092136, + "100:102": -5092136, + "101:102": -5092136, + "102:102": -5092136, + "103:102": -5092136, + "104:102": -5092136, + "105:102": -5092136, + "106:102": 268435456, + "107:102": 402653184, + "108:102": 268435456, + "109:102": 402653184, + "110:102": 268435456, + "111:102": 402653184, + "112:102": 268435456, + "113:102": 402653184, + "114:102": 268435456, + "115:102": 402653184, + "116:102": 268435456, + "117:102": 402653184, + "118:102": 268435456, + "119:102": 402653184, + "120:102": 268435456, + "121:102": 402653184, + "122:102": 268435456, + "123:102": 402653184, + "124:102": 268435456, + "125:102": 402653184, + "126:102": 268435456, + "127:102": 402653184, + "0:103": 402653184, + "1:103": 268435456, + "2:103": 402653184, + "3:103": 268435456, + "4:103": 402653184, + "5:103": 268435456, + "6:103": 402653184, + "7:103": 268435456, + "8:103": 402653184, + "9:103": 268435456, + "10:103": 402653184, + "11:103": 268435456, + "12:103": 402653184, + "13:103": 268435456, + "14:103": 402653184, + "15:103": 268435456, + "16:103": 402653184, + "17:103": 268435456, + "18:103": 402653184, + "19:103": 268435456, + "20:103": 402653184, + "21:103": 268435456, + "22:103": -9288933, + "23:103": -9288933, + "24:103": -9288933, + "25:103": -9288933, + "26:103": -9288933, + "27:103": -9288933, + "28:103": -9288933, + "29:103": -9288933, + "30:103": -9288933, + "31:103": -9288933, + "32:103": -9288933, + "33:103": -9288933, + "34:103": -9288933, + "35:103": -9288933, + "36:103": -9288933, + "37:103": -9288933, + "38:103": -9288933, + "39:103": -9288933, + "40:103": 402653184, + "41:103": 268435456, + "42:103": 402653184, + "43:103": 268435456, + "44:103": -1710797, + "45:103": -1710797, + "46:103": -1710797, + "47:103": -1710797, + "48:103": -1710797, + "49:103": -1710797, + "50:103": -1710797, + "51:103": -1710797, + "52:103": -1710797, + "53:103": -1710797, + "54:103": -1710797, + "55:103": -1710797, + "56:103": -1710797, + "57:103": -1710797, + "58:103": -1710797, + "59:103": -1710797, + "60:103": -1710797, + "61:103": -1710797, + "62:103": 402653184, + "63:103": 268435456, + "64:103": 402653184, + "65:103": 268435456, + "66:103": -9288933, + "67:103": -9288933, + "68:103": -9288933, + "69:103": -9288933, + "70:103": -9288933, + "71:103": -9288933, + "72:103": -9288933, + "73:103": -9288933, + "74:103": -9288933, + "75:103": -9288933, + "76:103": -9288933, + "77:103": -9288933, + "78:103": -9288933, + "79:103": -9288933, + "80:103": -9288933, + "81:103": -9288933, + "82:103": -9288933, + "83:103": -9288933, + "84:103": 402653184, + "85:103": 268435456, + "86:103": 402653184, + "87:103": 268435456, + "88:103": -5092136, + "89:103": -5092136, + "90:103": -5092136, + "91:103": -5092136, + "92:103": -5092136, + "93:103": -5092136, + "94:103": -5092136, + "95:103": -5092136, + "96:103": -5092136, + "97:103": -5092136, + "98:103": -5092136, + "99:103": -5092136, + "100:103": -5092136, + "101:103": -5092136, + "102:103": -5092136, + "103:103": -5092136, + "104:103": -5092136, + "105:103": -5092136, + "106:103": 402653184, + "107:103": 268435456, + "108:103": 402653184, + "109:103": 268435456, + "110:103": 402653184, + "111:103": 268435456, + "112:103": 402653184, + "113:103": 268435456, + "114:103": 402653184, + "115:103": 268435456, + "116:103": 402653184, + "117:103": 268435456, + "118:103": 402653184, + "119:103": 268435456, + "120:103": 402653184, + "121:103": 268435456, + "122:103": 402653184, + "123:103": 268435456, + "124:103": 402653184, + "125:103": 268435456, + "126:103": 402653184, + "127:103": 268435456, + "0:104": 268435456, + "1:104": 402653184, + "2:104": 268435456, + "3:104": 402653184, + "4:104": 268435456, + "5:104": 402653184, + "6:104": 268435456, + "7:104": 402653184, + "8:104": 268435456, + "9:104": 402653184, + "10:104": 268435456, + "11:104": 402653184, + "12:104": 268435456, + "13:104": 402653184, + "14:104": 268435456, + "15:104": 402653184, + "16:104": 268435456, + "17:104": 402653184, + "18:104": 268435456, + "19:104": 402653184, + "20:104": 268435456, + "21:104": 402653184, + "22:104": -9288933, + "23:104": -9288933, + "24:104": -9288933, + "25:104": -9288933, + "26:104": -9288933, + "27:104": -9288933, + "28:104": -9288933, + "29:104": -9288933, + "30:104": -9288933, + "31:104": -9288933, + "32:104": -9288933, + "33:104": -9288933, + "34:104": -9288933, + "35:104": -9288933, + "36:104": -9288933, + "37:104": -9288933, + "38:104": -9288933, + "39:104": -9288933, + "40:104": 268435456, + "41:104": 402653184, + "42:104": 268435456, + "43:104": 402653184, + "44:104": -1710797, + "45:104": -1710797, + "46:104": -1710797, + "47:104": -1710797, + "48:104": -1710797, + "49:104": -1710797, + "50:104": -1710797, + "51:104": -1710797, + "52:104": -1710797, + "53:104": -1710797, + "54:104": -1710797, + "55:104": -1710797, + "56:104": -1710797, + "57:104": -1710797, + "58:104": -1710797, + "59:104": -1710797, + "60:104": -1710797, + "61:104": -1710797, + "62:104": 268435456, + "63:104": 402653184, + "64:104": 268435456, + "65:104": 402653184, + "66:104": -9288933, + "67:104": -9288933, + "68:104": -9288933, + "69:104": -9288933, + "70:104": -9288933, + "71:104": -9288933, + "72:104": -9288933, + "73:104": -9288933, + "74:104": -9288933, + "75:104": -9288933, + "76:104": -9288933, + "77:104": -9288933, + "78:104": -9288933, + "79:104": -9288933, + "80:104": -9288933, + "81:104": -9288933, + "82:104": -9288933, + "83:104": -9288933, + "84:104": 268435456, + "85:104": 402653184, + "86:104": 268435456, + "87:104": 402653184, + "88:104": -5092136, + "89:104": -5092136, + "90:104": -5092136, + "91:104": -5092136, + "92:104": -5092136, + "93:104": -5092136, + "94:104": -5092136, + "95:104": -5092136, + "96:104": -5092136, + "97:104": -5092136, + "98:104": -5092136, + "99:104": -5092136, + "100:104": -5092136, + "101:104": -5092136, + "102:104": -5092136, + "103:104": -5092136, + "104:104": -5092136, + "105:104": -5092136, + "106:104": 268435456, + "107:104": 402653184, + "108:104": 268435456, + "109:104": 402653184, + "110:104": 268435456, + "111:104": 402653184, + "112:104": 268435456, + "113:104": 402653184, + "114:104": 268435456, + "115:104": 402653184, + "116:104": 268435456, + "117:104": 402653184, + "118:104": 268435456, + "119:104": 402653184, + "120:104": 268435456, + "121:104": 402653184, + "122:104": 268435456, + "123:104": 402653184, + "124:104": 268435456, + "125:104": 402653184, + "126:104": 268435456, + "127:104": 402653184, + "0:105": 402653184, + "1:105": 268435456, + "2:105": 402653184, + "3:105": 268435456, + "4:105": 402653184, + "5:105": 268435456, + "6:105": 402653184, + "7:105": 268435456, + "8:105": 402653184, + "9:105": 268435456, + "10:105": 402653184, + "11:105": 268435456, + "12:105": 402653184, + "13:105": 268435456, + "14:105": 402653184, + "15:105": 268435456, + "16:105": 402653184, + "17:105": 268435456, + "18:105": 402653184, + "19:105": 268435456, + "20:105": 402653184, + "21:105": 268435456, + "22:105": -9288933, + "23:105": -9288933, + "24:105": -9288933, + "25:105": -9288933, + "26:105": -9288933, + "27:105": -9288933, + "28:105": -9288933, + "29:105": -9288933, + "30:105": -9288933, + "31:105": -9288933, + "32:105": -9288933, + "33:105": -9288933, + "34:105": -9288933, + "35:105": -9288933, + "36:105": -9288933, + "37:105": -9288933, + "38:105": -9288933, + "39:105": -9288933, + "40:105": 402653184, + "41:105": 268435456, + "42:105": 402653184, + "43:105": 268435456, + "44:105": -1710797, + "45:105": -1710797, + "46:105": -1710797, + "47:105": -1710797, + "48:105": -1710797, + "49:105": -1710797, + "50:105": -1710797, + "51:105": -1710797, + "52:105": -1710797, + "53:105": -1710797, + "54:105": -1710797, + "55:105": -1710797, + "56:105": -1710797, + "57:105": -1710797, + "58:105": -1710797, + "59:105": -1710797, + "60:105": -1710797, + "61:105": -1710797, + "62:105": 402653184, + "63:105": 268435456, + "64:105": 402653184, + "65:105": 268435456, + "66:105": -9288933, + "67:105": -9288933, + "68:105": -9288933, + "69:105": -9288933, + "70:105": -9288933, + "71:105": -9288933, + "72:105": -9288933, + "73:105": -9288933, + "74:105": -9288933, + "75:105": -9288933, + "76:105": -9288933, + "77:105": -9288933, + "78:105": -9288933, + "79:105": -9288933, + "80:105": -9288933, + "81:105": -9288933, + "82:105": -9288933, + "83:105": -9288933, + "84:105": -5092136, + "85:105": -5092136, + "86:105": -5092136, + "87:105": -5092136, + "88:105": -5092136, + "89:105": -5092136, + "90:105": -5092136, + "91:105": -5092136, + "92:105": -5092136, + "93:105": -5092136, + "94:105": -5092136, + "95:105": -5092136, + "96:105": -5092136, + "97:105": -5092136, + "98:105": -5092136, + "99:105": -5092136, + "100:105": -5092136, + "101:105": -5092136, + "102:105": -5092136, + "103:105": -5092136, + "104:105": -5092136, + "105:105": -5092136, + "106:105": 402653184, + "107:105": 268435456, + "108:105": 402653184, + "109:105": 268435456, + "110:105": 402653184, + "111:105": 268435456, + "112:105": 402653184, + "113:105": 268435456, + "114:105": 402653184, + "115:105": 268435456, + "116:105": 402653184, + "117:105": 268435456, + "118:105": 402653184, + "119:105": 268435456, + "120:105": 402653184, + "121:105": 268435456, + "122:105": 402653184, + "123:105": 268435456, + "124:105": 402653184, + "125:105": 268435456, + "126:105": 402653184, + "127:105": 268435456, + "0:106": 268435456, + "1:106": 402653184, + "2:106": 268435456, + "3:106": 402653184, + "4:106": 268435456, + "5:106": 402653184, + "6:106": 268435456, + "7:106": 402653184, + "8:106": 268435456, + "9:106": 402653184, + "10:106": 268435456, + "11:106": 402653184, + "12:106": 268435456, + "13:106": 402653184, + "14:106": 268435456, + "15:106": 402653184, + "16:106": 268435456, + "17:106": 402653184, + "18:106": 268435456, + "19:106": 402653184, + "20:106": 268435456, + "21:106": 402653184, + "22:106": -9288933, + "23:106": -9288933, + "24:106": -9288933, + "25:106": -9288933, + "26:106": -9288933, + "27:106": -9288933, + "28:106": -9288933, + "29:106": -9288933, + "30:106": -9288933, + "31:106": -9288933, + "32:106": -9288933, + "33:106": -9288933, + "34:106": -9288933, + "35:106": -9288933, + "36:106": -9288933, + "37:106": -9288933, + "38:106": -9288933, + "39:106": -9288933, + "40:106": 268435456, + "41:106": 402653184, + "42:106": 268435456, + "43:106": 402653184, + "44:106": -1710797, + "45:106": -1710797, + "46:106": -1710797, + "47:106": -1710797, + "48:106": -1710797, + "49:106": -1710797, + "50:106": -1710797, + "51:106": -1710797, + "52:106": -1710797, + "53:106": -1710797, + "54:106": -16745472, + "55:106": -16745472, + "56:106": -16745472, + "57:106": -1710797, + "58:106": -1710797, + "59:106": -1710797, + "60:106": -1710797, + "61:106": -1710797, + "62:106": 268435456, + "63:106": 402653184, + "64:106": 268435456, + "65:106": 402653184, + "66:106": -9288933, + "67:106": -9288933, + "68:106": -9288933, + "69:106": -9288933, + "70:106": -9288933, + "71:106": -9288933, + "72:106": -9288933, + "73:106": -9288933, + "74:106": -9288933, + "75:106": -9288933, + "76:106": -16745472, + "77:106": -16745472, + "78:106": -16745472, + "79:106": -9288933, + "80:106": -9288933, + "81:106": -9288933, + "82:106": -9288933, + "83:106": -9288933, + "84:106": -5092136, + "85:106": -5092136, + "86:106": -5092136, + "87:106": -5092136, + "88:106": -5092136, + "89:106": -5092136, + "90:106": -5092136, + "91:106": -5092136, + "92:106": -5092136, + "93:106": -5092136, + "94:106": -5092136, + "95:106": -5092136, + "96:106": -5092136, + "97:106": -5092136, + "98:106": -16745472, + "99:106": -16745472, + "100:106": -16745472, + "101:106": -5092136, + "102:106": -5092136, + "103:106": -5092136, + "104:106": -5092136, + "105:106": -5092136, + "106:106": 268435456, + "107:106": 402653184, + "108:106": 268435456, + "109:106": 402653184, + "110:106": 268435456, + "111:106": 402653184, + "112:106": 268435456, + "113:106": 402653184, + "114:106": 268435456, + "115:106": 402653184, + "116:106": 268435456, + "117:106": 402653184, + "118:106": 268435456, + "119:106": 402653184, + "120:106": 268435456, + "121:106": 402653184, + "122:106": 268435456, + "123:106": 402653184, + "124:106": 268435456, + "125:106": 402653184, + "126:106": 268435456, + "127:106": 402653184, + "0:107": 402653184, + "1:107": 268435456, + "2:107": 402653184, + "3:107": 268435456, + "4:107": 402653184, + "5:107": 268435456, + "6:107": 402653184, + "7:107": 268435456, + "8:107": 402653184, + "9:107": 268435456, + "10:107": 402653184, + "11:107": 268435456, + "12:107": 402653184, + "13:107": 268435456, + "14:107": 402653184, + "15:107": 268435456, + "16:107": 402653184, + "17:107": 268435456, + "18:107": 402653184, + "19:107": 268435456, + "20:107": 402653184, + "21:107": 268435456, + "22:107": -9288933, + "23:107": -9288933, + "24:107": -9288933, + "25:107": -9288933, + "26:107": -9288933, + "27:107": -9288933, + "28:107": -9288933, + "29:107": -9288933, + "30:107": -9288933, + "31:107": -9288933, + "32:107": -9288933, + "33:107": -9288933, + "34:107": -9288933, + "35:107": -9288933, + "36:107": -9288933, + "37:107": -9288933, + "38:107": -9288933, + "39:107": -9288933, + "40:107": 402653184, + "41:107": 268435456, + "42:107": 402653184, + "43:107": 268435456, + "44:107": -1710797, + "45:107": -1710797, + "46:107": -1710797, + "47:107": -1710797, + "48:107": -1710797, + "49:107": -1710797, + "50:107": -1710797, + "51:107": -1710797, + "52:107": -1710797, + "53:107": -16745472, + "54:107": -16745472, + "55:107": -16745472, + "56:107": -1710797, + "57:107": -1710797, + "58:107": -1710797, + "59:107": -1710797, + "60:107": -1710797, + "61:107": -1710797, + "62:107": 402653184, + "63:107": 268435456, + "64:107": 402653184, + "65:107": 268435456, + "66:107": -9288933, + "67:107": -9288933, + "68:107": -9288933, + "69:107": -9288933, + "70:107": -9288933, + "71:107": -9288933, + "72:107": -9288933, + "73:107": -9288933, + "74:107": -9288933, + "75:107": -16745472, + "76:107": -16745472, + "77:107": -16745472, + "78:107": -9288933, + "79:107": -9288933, + "80:107": -9288933, + "81:107": -9288933, + "82:107": -9288933, + "83:107": -9288933, + "84:107": -5092136, + "85:107": -5092136, + "86:107": -5092136, + "87:107": -5092136, + "88:107": -5092136, + "89:107": -5092136, + "90:107": -5092136, + "91:107": -5092136, + "92:107": -5092136, + "93:107": -5092136, + "94:107": -5092136, + "95:107": -5092136, + "96:107": -5092136, + "97:107": -16745472, + "98:107": -16745472, + "99:107": -16745472, + "100:107": -5092136, + "101:107": -5092136, + "102:107": -5092136, + "103:107": -5092136, + "104:107": -5092136, + "105:107": -5092136, + "106:107": 402653184, + "107:107": 268435456, + "108:107": 402653184, + "109:107": 268435456, + "110:107": 402653184, + "111:107": 268435456, + "112:107": 402653184, + "113:107": 268435456, + "114:107": 402653184, + "115:107": 268435456, + "116:107": 402653184, + "117:107": 268435456, + "118:107": 402653184, + "119:107": 268435456, + "120:107": 402653184, + "121:107": 268435456, + "122:107": 402653184, + "123:107": 268435456, + "124:107": 402653184, + "125:107": 268435456, + "126:107": 402653184, + "127:107": 268435456, + "0:108": 268435456, + "1:108": 402653184, + "2:108": 268435456, + "3:108": 402653184, + "4:108": 268435456, + "5:108": 402653184, + "6:108": 268435456, + "7:108": 402653184, + "8:108": 268435456, + "9:108": 402653184, + "10:108": 268435456, + "11:108": 402653184, + "12:108": 268435456, + "13:108": 402653184, + "14:108": 268435456, + "15:108": 402653184, + "16:108": 268435456, + "17:108": 402653184, + "18:108": 268435456, + "19:108": 402653184, + "20:108": 268435456, + "21:108": 402653184, + "22:108": -9288933, + "23:108": -9288933, + "24:108": -9288933, + "25:108": -9288933, + "26:108": -9288933, + "27:108": -9288933, + "28:108": -9288933, + "29:108": -9288933, + "30:108": -9288933, + "31:108": -9288933, + "32:108": -9288933, + "33:108": -9288933, + "34:108": -9288933, + "35:108": -9288933, + "36:108": -9288933, + "37:108": -9288933, + "38:108": -9288933, + "39:108": -9288933, + "40:108": 268435456, + "41:108": 402653184, + "42:108": 268435456, + "43:108": 402653184, + "44:108": -1710797, + "45:108": -1710797, + "46:108": -1710797, + "47:108": -1710797, + "48:108": -1710797, + "49:108": -1710797, + "50:108": -1710797, + "51:108": -1710797, + "52:108": -1710797, + "53:108": -16745472, + "54:108": -16745472, + "55:108": -1710797, + "56:108": -1710797, + "57:108": -1710797, + "58:108": -1710797, + "59:108": -1710797, + "60:108": -1710797, + "61:108": -1710797, + "62:108": 268435456, + "63:108": 402653184, + "64:108": 268435456, + "65:108": 402653184, + "66:108": -9288933, + "67:108": -9288933, + "68:108": -9288933, + "69:108": -9288933, + "70:108": -9288933, + "71:108": -9288933, + "72:108": -9288933, + "73:108": -9288933, + "74:108": -9288933, + "75:108": -16745472, + "76:108": -16745472, + "77:108": -9288933, + "78:108": -9288933, + "79:108": -9288933, + "80:108": -9288933, + "81:108": -9288933, + "82:108": -9288933, + "83:108": -9288933, + "84:108": -5092136, + "85:108": -5092136, + "86:108": -5092136, + "87:108": -5092136, + "88:108": -5092136, + "89:108": -5092136, + "90:108": -5092136, + "91:108": -5092136, + "92:108": -5092136, + "93:108": -5092136, + "94:108": -5092136, + "95:108": -5092136, + "96:108": -5092136, + "97:108": -16745472, + "98:108": -16745472, + "99:108": -5092136, + "100:108": -5092136, + "101:108": -5092136, + "102:108": -5092136, + "103:108": -5092136, + "104:108": -5092136, + "105:108": -5092136, + "106:108": 268435456, + "107:108": 402653184, + "108:108": 268435456, + "109:108": 402653184, + "110:108": 268435456, + "111:108": 402653184, + "112:108": 268435456, + "113:108": 402653184, + "114:108": 268435456, + "115:108": 402653184, + "116:108": 268435456, + "117:108": 402653184, + "118:108": 268435456, + "119:108": 402653184, + "120:108": 268435456, + "121:108": 402653184, + "122:108": 268435456, + "123:108": 402653184, + "124:108": 268435456, + "125:108": 402653184, + "126:108": 268435456, + "127:108": 402653184, + "0:109": 402653184, + "1:109": 268435456, + "2:109": 402653184, + "3:109": 268435456, + "4:109": 402653184, + "5:109": 268435456, + "6:109": 402653184, + "7:109": 268435456, + "8:109": 402653184, + "9:109": 268435456, + "10:109": 402653184, + "11:109": 268435456, + "12:109": 402653184, + "13:109": 268435456, + "14:109": 402653184, + "15:109": 268435456, + "16:109": 402653184, + "17:109": 268435456, + "18:109": 402653184, + "19:109": 268435456, + "20:109": 402653184, + "21:109": 268435456, + "22:109": -9288933, + "23:109": -9288933, + "24:109": -9288933, + "25:109": -9288933, + "26:109": -9288933, + "27:109": -9288933, + "28:109": -9288933, + "29:109": -9288933, + "30:109": -9288933, + "31:109": -9288933, + "32:109": -9288933, + "33:109": -9288933, + "34:109": -9288933, + "35:109": -9288933, + "36:109": -9288933, + "37:109": -9288933, + "38:109": -9288933, + "39:109": -9288933, + "40:109": 402653184, + "41:109": 268435456, + "42:109": 402653184, + "43:109": 268435456, + "44:109": -1710797, + "45:109": -1710797, + "46:109": -1710797, + "47:109": -1710797, + "48:109": -1710797, + "49:109": -1710797, + "50:109": -16745472, + "51:109": -16745472, + "52:109": -1710797, + "53:109": -16745472, + "54:109": -16745472, + "55:109": -1710797, + "56:109": -1710797, + "57:109": -1710797, + "58:109": -1710797, + "59:109": -1710797, + "60:109": -1710797, + "61:109": -1710797, + "62:109": 402653184, + "63:109": 268435456, + "64:109": 402653184, + "65:109": 268435456, + "66:109": -9288933, + "67:109": -9288933, + "68:109": -9288933, + "69:109": -9288933, + "70:109": -9288933, + "71:109": -9288933, + "72:109": -16745472, + "73:109": -16745472, + "74:109": -9288933, + "75:109": -16745472, + "76:109": -16745472, + "77:109": -9288933, + "78:109": -9288933, + "79:109": -9288933, + "80:109": -9288933, + "81:109": -9288933, + "82:109": -9288933, + "83:109": -9288933, + "84:109": -5092136, + "85:109": -5092136, + "86:109": -5092136, + "87:109": -5092136, + "88:109": -5092136, + "89:109": -5092136, + "90:109": -5092136, + "91:109": -5092136, + "92:109": -5092136, + "93:109": -5092136, + "94:109": -16745472, + "95:109": -16745472, + "96:109": -5092136, + "97:109": -16745472, + "98:109": -16745472, + "99:109": -5092136, + "100:109": -5092136, + "101:109": -5092136, + "102:109": -5092136, + "103:109": -5092136, + "104:109": -5092136, + "105:109": -5092136, + "106:109": 402653184, + "107:109": 268435456, + "108:109": 402653184, + "109:109": 268435456, + "110:109": 402653184, + "111:109": 268435456, + "112:109": 402653184, + "113:109": 268435456, + "114:109": 402653184, + "115:109": 268435456, + "116:109": 402653184, + "117:109": 268435456, + "118:109": 402653184, + "119:109": 268435456, + "120:109": 402653184, + "121:109": 268435456, + "122:109": 402653184, + "123:109": 268435456, + "124:109": 402653184, + "125:109": 268435456, + "126:109": 402653184, + "127:109": 268435456, + "0:110": 268435456, + "1:110": 402653184, + "2:110": 268435456, + "3:110": 402653184, + "4:110": 268435456, + "5:110": 402653184, + "6:110": 268435456, + "7:110": 402653184, + "8:110": 268435456, + "9:110": 402653184, + "10:110": 268435456, + "11:110": 402653184, + "12:110": 268435456, + "13:110": 402653184, + "14:110": 268435456, + "15:110": 402653184, + "16:110": 268435456, + "17:110": 402653184, + "18:110": 268435456, + "19:110": 402653184, + "20:110": 268435456, + "21:110": 402653184, + "22:110": -9288933, + "23:110": -9288933, + "24:110": -9288933, + "25:110": -9288933, + "26:110": -9288933, + "27:110": -9288933, + "28:110": -9288933, + "29:110": -9288933, + "30:110": -9288933, + "31:110": -9288933, + "32:110": -9288933, + "33:110": -9288933, + "34:110": -9288933, + "35:110": -9288933, + "36:110": -9288933, + "37:110": -9288933, + "38:110": -9288933, + "39:110": -9288933, + "40:110": 268435456, + "41:110": 402653184, + "42:110": 268435456, + "43:110": 402653184, + "44:110": -1710797, + "45:110": -1710797, + "46:110": -1710797, + "47:110": -1710797, + "48:110": -1710797, + "49:110": -1710797, + "50:110": -1710797, + "51:110": -16745472, + "52:110": -16745472, + "53:110": -16745472, + "54:110": -1710797, + "55:110": -1710797, + "56:110": -1710797, + "57:110": -1710797, + "58:110": -1710797, + "59:110": -1710797, + "60:110": -1710797, + "61:110": -1710797, + "62:110": 268435456, + "63:110": 402653184, + "64:110": 268435456, + "65:110": 402653184, + "66:110": -9288933, + "67:110": -9288933, + "68:110": -9288933, + "69:110": -9288933, + "70:110": -9288933, + "71:110": -9288933, + "72:110": -9288933, + "73:110": -16745472, + "74:110": -16745472, + "75:110": -16745472, + "76:110": -9288933, + "77:110": -9288933, + "78:110": -9288933, + "79:110": -9288933, + "80:110": -9288933, + "81:110": -9288933, + "82:110": -9288933, + "83:110": -9288933, + "84:110": -5092136, + "85:110": -5092136, + "86:110": -5092136, + "87:110": -5092136, + "88:110": -5092136, + "89:110": -5092136, + "90:110": -5092136, + "91:110": -5092136, + "92:110": -5092136, + "93:110": -5092136, + "94:110": -5092136, + "95:110": -16745472, + "96:110": -16745472, + "97:110": -16745472, + "98:110": -5092136, + "99:110": -5092136, + "100:110": -5092136, + "101:110": -5092136, + "102:110": -5092136, + "103:110": -5092136, + "104:110": -5092136, + "105:110": -5092136, + "106:110": 268435456, + "107:110": 402653184, + "108:110": 268435456, + "109:110": 402653184, + "110:110": 268435456, + "111:110": 402653184, + "112:110": 268435456, + "113:110": 402653184, + "114:110": 268435456, + "115:110": 402653184, + "116:110": 268435456, + "117:110": 402653184, + "118:110": 268435456, + "119:110": 402653184, + "120:110": 268435456, + "121:110": 402653184, + "122:110": 268435456, + "123:110": 402653184, + "124:110": 268435456, + "125:110": 402653184, + "126:110": 268435456, + "127:110": 402653184, + "0:111": 402653184, + "1:111": 268435456, + "2:111": 402653184, + "3:111": 268435456, + "4:111": 402653184, + "5:111": 268435456, + "6:111": 402653184, + "7:111": 268435456, + "8:111": 402653184, + "9:111": 268435456, + "10:111": 402653184, + "11:111": 268435456, + "12:111": 402653184, + "13:111": 268435456, + "14:111": 402653184, + "15:111": 268435456, + "16:111": 402653184, + "17:111": 268435456, + "18:111": 402653184, + "19:111": 268435456, + "20:111": 402653184, + "21:111": 268435456, + "22:111": -9288933, + "23:111": -9288933, + "24:111": -9288933, + "25:111": -9288933, + "26:111": -9288933, + "27:111": -9288933, + "28:111": -9288933, + "29:111": -9288933, + "30:111": -9288933, + "31:111": -9288933, + "32:111": -9288933, + "33:111": -9288933, + "34:111": -9288933, + "35:111": -9288933, + "36:111": -9288933, + "37:111": -9288933, + "38:111": -9288933, + "39:111": -9288933, + "40:111": 402653184, + "41:111": 268435456, + "42:111": 402653184, + "43:111": 268435456, + "44:111": -1710797, + "45:111": -1710797, + "46:111": -1710797, + "47:111": -1710797, + "48:111": -1710797, + "49:111": -1710797, + "50:111": -1710797, + "51:111": -16745472, + "52:111": -16745472, + "53:111": -16745472, + "54:111": -1710797, + "55:111": -1710797, + "56:111": -1710797, + "57:111": -1710797, + "58:111": -1710797, + "59:111": -1710797, + "60:111": -1710797, + "61:111": -1710797, + "62:111": 402653184, + "63:111": 268435456, + "64:111": 402653184, + "65:111": 268435456, + "66:111": -9288933, + "67:111": -9288933, + "68:111": -9288933, + "69:111": -9288933, + "70:111": -9288933, + "71:111": -9288933, + "72:111": -9288933, + "73:111": -16745472, + "74:111": -16745472, + "75:111": -16745472, + "76:111": -9288933, + "77:111": -9288933, + "78:111": -9288933, + "79:111": -9288933, + "80:111": -9288933, + "81:111": -9288933, + "82:111": -9288933, + "83:111": -9288933, + "84:111": -5092136, + "85:111": -5092136, + "86:111": -5092136, + "87:111": -5092136, + "88:111": -5092136, + "89:111": -5092136, + "90:111": -5092136, + "91:111": -5092136, + "92:111": -5092136, + "93:111": -5092136, + "94:111": -5092136, + "95:111": -16745472, + "96:111": -16745472, + "97:111": -16745472, + "98:111": -5092136, + "99:111": -5092136, + "100:111": -5092136, + "101:111": -5092136, + "102:111": -5092136, + "103:111": -5092136, + "104:111": -5092136, + "105:111": -5092136, + "106:111": 402653184, + "107:111": 268435456, + "108:111": 402653184, + "109:111": 268435456, + "110:111": 402653184, + "111:111": 268435456, + "112:111": 402653184, + "113:111": 268435456, + "114:111": 402653184, + "115:111": 268435456, + "116:111": 402653184, + "117:111": 268435456, + "118:111": 402653184, + "119:111": 268435456, + "120:111": 402653184, + "121:111": 268435456, + "122:111": 402653184, + "123:111": 268435456, + "124:111": 402653184, + "125:111": 268435456, + "126:111": 402653184, + "127:111": 268435456, + "0:112": 268435456, + "1:112": 402653184, + "2:112": 268435456, + "3:112": 402653184, + "4:112": 268435456, + "5:112": 402653184, + "6:112": 268435456, + "7:112": 402653184, + "8:112": 268435456, + "9:112": 402653184, + "10:112": 268435456, + "11:112": 402653184, + "12:112": 268435456, + "13:112": 402653184, + "14:112": 268435456, + "15:112": 402653184, + "16:112": 268435456, + "17:112": 402653184, + "18:112": 268435456, + "19:112": 402653184, + "20:112": 268435456, + "21:112": 402653184, + "22:112": -9288933, + "23:112": -9288933, + "24:112": -9288933, + "25:112": -9288933, + "26:112": -9288933, + "27:112": -9288933, + "28:112": -9288933, + "29:112": -9288933, + "30:112": -9288933, + "31:112": -9288933, + "32:112": -9288933, + "33:112": -9288933, + "34:112": -9288933, + "35:112": -9288933, + "36:112": -9288933, + "37:112": -9288933, + "38:112": -9288933, + "39:112": -9288933, + "40:112": 268435456, + "41:112": 402653184, + "42:112": 268435456, + "43:112": 402653184, + "44:112": -1710797, + "45:112": -1710797, + "46:112": -1710797, + "47:112": -1710797, + "48:112": -1710797, + "49:112": -1710797, + "50:112": -1710797, + "51:112": -1710797, + "52:112": -1710797, + "53:112": -1710797, + "54:112": -1710797, + "55:112": -1710797, + "56:112": -1710797, + "57:112": -1710797, + "58:112": -1710797, + "59:112": -1710797, + "60:112": -1710797, + "61:112": -1710797, + "62:112": 268435456, + "63:112": 402653184, + "64:112": 268435456, + "65:112": 402653184, + "66:112": -9288933, + "67:112": -9288933, + "68:112": -9288933, + "69:112": -9288933, + "70:112": -9288933, + "71:112": -9288933, + "72:112": -9288933, + "73:112": -9288933, + "74:112": -9288933, + "75:112": -9288933, + "76:112": -9288933, + "77:112": -9288933, + "78:112": -9288933, + "79:112": -9288933, + "80:112": -9288933, + "81:112": -9288933, + "82:112": -9288933, + "83:112": -9288933, + "84:112": 268435456, + "85:112": 402653184, + "86:112": 268435456, + "87:112": 402653184, + "88:112": -5092136, + "89:112": -5092136, + "90:112": -5092136, + "91:112": -5092136, + "92:112": -5092136, + "93:112": -5092136, + "94:112": -5092136, + "95:112": -5092136, + "96:112": -5092136, + "97:112": -5092136, + "98:112": -5092136, + "99:112": -5092136, + "100:112": -5092136, + "101:112": -5092136, + "102:112": -5092136, + "103:112": -5092136, + "104:112": -5092136, + "105:112": -5092136, + "106:112": 268435456, + "107:112": 402653184, + "108:112": 268435456, + "109:112": 402653184, + "110:112": 268435456, + "111:112": 402653184, + "112:112": 268435456, + "113:112": 402653184, + "114:112": 268435456, + "115:112": 402653184, + "116:112": 268435456, + "117:112": 402653184, + "118:112": 268435456, + "119:112": 402653184, + "120:112": 268435456, + "121:112": 402653184, + "122:112": 268435456, + "123:112": 402653184, + "124:112": 268435456, + "125:112": 402653184, + "126:112": 268435456, + "127:112": 402653184, + "0:113": 402653184, + "1:113": 268435456, + "2:113": 402653184, + "3:113": 268435456, + "4:113": 402653184, + "5:113": 268435456, + "6:113": 402653184, + "7:113": 268435456, + "8:113": 402653184, + "9:113": 268435456, + "10:113": 402653184, + "11:113": 268435456, + "12:113": 402653184, + "13:113": 268435456, + "14:113": 402653184, + "15:113": 268435456, + "16:113": 402653184, + "17:113": 268435456, + "18:113": 402653184, + "19:113": 268435456, + "20:113": 402653184, + "21:113": 268435456, + "22:113": -9288933, + "23:113": -9288933, + "24:113": -9288933, + "25:113": -9288933, + "26:113": -9288933, + "27:113": -9288933, + "28:113": -9288933, + "29:113": -9288933, + "30:113": -9288933, + "31:113": -9288933, + "32:113": -9288933, + "33:113": -9288933, + "34:113": -9288933, + "35:113": -9288933, + "36:113": -9288933, + "37:113": -9288933, + "38:113": -9288933, + "39:113": -9288933, + "40:113": 402653184, + "41:113": 268435456, + "42:113": 402653184, + "43:113": 268435456, + "44:113": -1710797, + "45:113": -1710797, + "46:113": -1710797, + "47:113": -1710797, + "48:113": -1710797, + "49:113": -1710797, + "50:113": -1710797, + "51:113": -1710797, + "52:113": -1710797, + "53:113": -1710797, + "54:113": -1710797, + "55:113": -1710797, + "56:113": -1710797, + "57:113": -1710797, + "58:113": -1710797, + "59:113": -1710797, + "60:113": -1710797, + "61:113": -1710797, + "62:113": 402653184, + "63:113": 268435456, + "64:113": 402653184, + "65:113": 268435456, + "66:113": -9288933, + "67:113": -9288933, + "68:113": -9288933, + "69:113": -9288933, + "70:113": -9288933, + "71:113": -9288933, + "72:113": -9288933, + "73:113": -9288933, + "74:113": -9288933, + "75:113": -9288933, + "76:113": -9288933, + "77:113": -9288933, + "78:113": -9288933, + "79:113": -9288933, + "80:113": -9288933, + "81:113": -9288933, + "82:113": -9288933, + "83:113": -9288933, + "84:113": 402653184, + "85:113": 268435456, + "86:113": 402653184, + "87:113": 268435456, + "88:113": -5092136, + "89:113": -5092136, + "90:113": -5092136, + "91:113": -5092136, + "92:113": -5092136, + "93:113": -5092136, + "94:113": -5092136, + "95:113": -5092136, + "96:113": -5092136, + "97:113": -5092136, + "98:113": -5092136, + "99:113": -5092136, + "100:113": -5092136, + "101:113": -5092136, + "102:113": -5092136, + "103:113": -5092136, + "104:113": -5092136, + "105:113": -5092136, + "106:113": 402653184, + "107:113": 268435456, + "108:113": 402653184, + "109:113": 268435456, + "110:113": 402653184, + "111:113": 268435456, + "112:113": 402653184, + "113:113": 268435456, + "114:113": 402653184, + "115:113": 268435456, + "116:113": 402653184, + "117:113": 268435456, + "118:113": 402653184, + "119:113": 268435456, + "120:113": 402653184, + "121:113": 268435456, + "122:113": 402653184, + "123:113": 268435456, + "124:113": 402653184, + "125:113": 268435456, + "126:113": 402653184, + "127:113": 268435456, + "0:114": 268435456, + "1:114": 402653184, + "2:114": 268435456, + "3:114": 402653184, + "4:114": 268435456, + "5:114": 402653184, + "6:114": 268435456, + "7:114": 402653184, + "8:114": 268435456, + "9:114": 402653184, + "10:114": 268435456, + "11:114": 402653184, + "12:114": 268435456, + "13:114": 402653184, + "14:114": 268435456, + "15:114": 402653184, + "16:114": 268435456, + "17:114": 402653184, + "18:114": 268435456, + "19:114": 402653184, + "20:114": 268435456, + "21:114": 402653184, + "22:114": -9288933, + "23:114": -9288933, + "24:114": -9288933, + "25:114": -9288933, + "26:114": -9288933, + "27:114": -9288933, + "28:114": -9288933, + "29:114": -9288933, + "30:114": -9288933, + "31:114": -9288933, + "32:114": -9288933, + "33:114": -9288933, + "34:114": -9288933, + "35:114": -9288933, + "36:114": -9288933, + "37:114": -9288933, + "38:114": -9288933, + "39:114": -9288933, + "40:114": 268435456, + "41:114": 402653184, + "42:114": 268435456, + "43:114": 402653184, + "44:114": -1710797, + "45:114": -1710797, + "46:114": -1710797, + "47:114": -1710797, + "48:114": -1710797, + "49:114": -1710797, + "50:114": -1710797, + "51:114": -1710797, + "52:114": -1710797, + "53:114": -1710797, + "54:114": -1710797, + "55:114": -1710797, + "56:114": -1710797, + "57:114": -1710797, + "58:114": -1710797, + "59:114": -1710797, + "60:114": -1710797, + "61:114": -1710797, + "62:114": 268435456, + "63:114": 402653184, + "64:114": 268435456, + "65:114": 402653184, + "66:114": -9288933, + "67:114": -9288933, + "68:114": -9288933, + "69:114": -9288933, + "70:114": -9288933, + "71:114": -9288933, + "72:114": -9288933, + "73:114": -9288933, + "74:114": -9288933, + "75:114": -9288933, + "76:114": -9288933, + "77:114": -9288933, + "78:114": -9288933, + "79:114": -9288933, + "80:114": -9288933, + "81:114": -9288933, + "82:114": -9288933, + "83:114": -9288933, + "84:114": 268435456, + "85:114": 402653184, + "86:114": 268435456, + "87:114": 402653184, + "88:114": -5092136, + "89:114": -5092136, + "90:114": -5092136, + "91:114": -5092136, + "92:114": -5092136, + "93:114": -5092136, + "94:114": -5092136, + "95:114": -5092136, + "96:114": -5092136, + "97:114": -5092136, + "98:114": -5092136, + "99:114": -5092136, + "100:114": -5092136, + "101:114": -5092136, + "102:114": -5092136, + "103:114": -5092136, + "104:114": -5092136, + "105:114": -5092136, + "106:114": 268435456, + "107:114": 402653184, + "108:114": 268435456, + "109:114": 402653184, + "110:114": 268435456, + "111:114": 402653184, + "112:114": 268435456, + "113:114": 402653184, + "114:114": 268435456, + "115:114": 402653184, + "116:114": 268435456, + "117:114": 402653184, + "118:114": 268435456, + "119:114": 402653184, + "120:114": 268435456, + "121:114": 402653184, + "122:114": 268435456, + "123:114": 402653184, + "124:114": 268435456, + "125:114": 402653184, + "126:114": 268435456, + "127:114": 402653184, + "0:115": 402653184, + "1:115": 268435456, + "2:115": 402653184, + "3:115": 268435456, + "4:115": 402653184, + "5:115": 268435456, + "6:115": 402653184, + "7:115": 268435456, + "8:115": 402653184, + "9:115": 268435456, + "10:115": 402653184, + "11:115": 268435456, + "12:115": 402653184, + "13:115": 268435456, + "14:115": 402653184, + "15:115": 268435456, + "16:115": 402653184, + "17:115": 268435456, + "18:115": 402653184, + "19:115": 268435456, + "20:115": 402653184, + "21:115": 268435456, + "22:115": -9288933, + "23:115": -9288933, + "24:115": -9288933, + "25:115": -9288933, + "26:115": -9288933, + "27:115": -9288933, + "28:115": -9288933, + "29:115": -9288933, + "30:115": -9288933, + "31:115": -9288933, + "32:115": -9288933, + "33:115": -9288933, + "34:115": -9288933, + "35:115": -9288933, + "36:115": -9288933, + "37:115": -9288933, + "38:115": -9288933, + "39:115": -9288933, + "40:115": 402653184, + "41:115": 268435456, + "42:115": 402653184, + "43:115": 268435456, + "44:115": -1710797, + "45:115": -1710797, + "46:115": -1710797, + "47:115": -1710797, + "48:115": -1710797, + "49:115": -1710797, + "50:115": -1710797, + "51:115": -1710797, + "52:115": -1710797, + "53:115": -1710797, + "54:115": -1710797, + "55:115": -1710797, + "56:115": -1710797, + "57:115": -1710797, + "58:115": -1710797, + "59:115": -1710797, + "60:115": -1710797, + "61:115": -1710797, + "62:115": 402653184, + "63:115": 268435456, + "64:115": 402653184, + "65:115": 268435456, + "66:115": -9288933, + "67:115": -9288933, + "68:115": -9288933, + "69:115": -9288933, + "70:115": -9288933, + "71:115": -9288933, + "72:115": -9288933, + "73:115": -9288933, + "74:115": -9288933, + "75:115": -9288933, + "76:115": -9288933, + "77:115": -9288933, + "78:115": -9288933, + "79:115": -9288933, + "80:115": -9288933, + "81:115": -9288933, + "82:115": -9288933, + "83:115": -9288933, + "84:115": 402653184, + "85:115": 268435456, + "86:115": 402653184, + "87:115": 268435456, + "88:115": -5092136, + "89:115": -5092136, + "90:115": -5092136, + "91:115": -5092136, + "92:115": -5092136, + "93:115": -5092136, + "94:115": -5092136, + "95:115": -5092136, + "96:115": -5092136, + "97:115": -5092136, + "98:115": -5092136, + "99:115": -5092136, + "100:115": -5092136, + "101:115": -5092136, + "102:115": -5092136, + "103:115": -5092136, + "104:115": -5092136, + "105:115": -5092136, + "106:115": 402653184, + "107:115": 268435456, + "108:115": 402653184, + "109:115": 268435456, + "110:115": 402653184, + "111:115": 268435456, + "112:115": 402653184, + "113:115": 268435456, + "114:115": 402653184, + "115:115": 268435456, + "116:115": 402653184, + "117:115": 268435456, + "118:115": 402653184, + "119:115": 268435456, + "120:115": 402653184, + "121:115": 268435456, + "122:115": 402653184, + "123:115": 268435456, + "124:115": 402653184, + "125:115": 268435456, + "126:115": 402653184, + "127:115": 268435456, + "0:116": 268435456, + "1:116": 402653184, + "2:116": 268435456, + "3:116": 402653184, + "4:116": 268435456, + "5:116": 402653184, + "6:116": 268435456, + "7:116": 402653184, + "8:116": 268435456, + "9:116": 402653184, + "10:116": 268435456, + "11:116": 402653184, + "12:116": 268435456, + "13:116": 402653184, + "14:116": 268435456, + "15:116": 402653184, + "16:116": 268435456, + "17:116": 402653184, + "18:116": 268435456, + "19:116": 402653184, + "20:116": 268435456, + "21:116": 402653184, + "22:116": -9288933, + "23:116": -9288933, + "24:116": -9288933, + "25:116": -9288933, + "26:116": -9288933, + "27:116": -9288933, + "28:116": -9288933, + "29:116": -9288933, + "30:116": -9288933, + "31:116": -9288933, + "32:116": -9288933, + "33:116": -9288933, + "34:116": -9288933, + "35:116": -9288933, + "36:116": -9288933, + "37:116": -9288933, + "38:116": -9288933, + "39:116": -9288933, + "40:116": 268435456, + "41:116": 402653184, + "42:116": 268435456, + "43:116": 402653184, + "44:116": -1710797, + "45:116": -1710797, + "46:116": -1710797, + "47:116": -1710797, + "48:116": -1710797, + "49:116": -1710797, + "50:116": -1710797, + "51:116": -1710797, + "52:116": -1710797, + "53:116": -1710797, + "54:116": -1710797, + "55:116": -1710797, + "56:116": -1710797, + "57:116": -1710797, + "58:116": -1710797, + "59:116": -1710797, + "60:116": -1710797, + "61:116": -1710797, + "62:116": 268435456, + "63:116": 402653184, + "64:116": 268435456, + "65:116": 402653184, + "66:116": -9288933, + "67:116": -9288933, + "68:116": -9288933, + "69:116": -9288933, + "70:116": -9288933, + "71:116": -9288933, + "72:116": -9288933, + "73:116": -9288933, + "74:116": -9288933, + "75:116": -9288933, + "76:116": -9288933, + "77:116": -9288933, + "78:116": -9288933, + "79:116": -9288933, + "80:116": -9288933, + "81:116": -9288933, + "82:116": -9288933, + "83:116": -9288933, + "84:116": 268435456, + "85:116": 402653184, + "86:116": 268435456, + "87:116": 402653184, + "88:116": -5092136, + "89:116": -5092136, + "90:116": -5092136, + "91:116": -5092136, + "92:116": -5092136, + "93:116": -5092136, + "94:116": -5092136, + "95:116": -5092136, + "96:116": -5092136, + "97:116": -5092136, + "98:116": -5092136, + "99:116": -5092136, + "100:116": -5092136, + "101:116": -5092136, + "102:116": -5092136, + "103:116": -5092136, + "104:116": -5092136, + "105:116": -5092136, + "106:116": 268435456, + "107:116": 402653184, + "108:116": 268435456, + "109:116": 402653184, + "110:116": 268435456, + "111:116": 402653184, + "112:116": 268435456, + "113:116": 402653184, + "114:116": 268435456, + "115:116": 402653184, + "116:116": 268435456, + "117:116": 402653184, + "118:116": 268435456, + "119:116": 402653184, + "120:116": 268435456, + "121:116": 402653184, + "122:116": 268435456, + "123:116": 402653184, + "124:116": 268435456, + "125:116": 402653184, + "126:116": 268435456, + "127:116": 402653184, + "0:117": 402653184, + "1:117": 268435456, + "2:117": 402653184, + "3:117": 268435456, + "4:117": 402653184, + "5:117": 268435456, + "6:117": 402653184, + "7:117": 268435456, + "8:117": 402653184, + "9:117": 268435456, + "10:117": 402653184, + "11:117": 268435456, + "12:117": 402653184, + "13:117": 268435456, + "14:117": 402653184, + "15:117": 268435456, + "16:117": 402653184, + "17:117": 268435456, + "18:117": 402653184, + "19:117": 268435456, + "20:117": 402653184, + "21:117": 268435456, + "22:117": 402653184, + "23:117": 268435456, + "24:117": 402653184, + "25:117": 268435456, + "26:117": 402653184, + "27:117": 268435456, + "28:117": 402653184, + "29:117": 268435456, + "30:117": 402653184, + "31:117": 268435456, + "32:117": 402653184, + "33:117": 268435456, + "34:117": 402653184, + "35:117": 268435456, + "36:117": 402653184, + "37:117": 268435456, + "38:117": 402653184, + "39:117": 268435456, + "40:117": 402653184, + "41:117": 268435456, + "42:117": 402653184, + "43:117": 268435456, + "44:117": 402653184, + "45:117": 268435456, + "46:117": 402653184, + "47:117": 268435456, + "48:117": 402653184, + "49:117": 268435456, + "50:117": 402653184, + "51:117": 268435456, + "52:117": 402653184, + "53:117": 268435456, + "54:117": 402653184, + "55:117": 268435456, + "56:117": 402653184, + "57:117": 268435456, + "58:117": 402653184, + "59:117": 268435456, + "60:117": 402653184, + "61:117": 268435456, + "62:117": 402653184, + "63:117": 268435456, + "64:117": 402653184, + "65:117": 268435456, + "66:117": 402653184, + "67:117": 268435456, + "68:117": 402653184, + "69:117": 268435456, + "70:117": 402653184, + "71:117": 268435456, + "72:117": 402653184, + "73:117": 268435456, + "74:117": 402653184, + "75:117": 268435456, + "76:117": 402653184, + "77:117": 268435456, + "78:117": 402653184, + "79:117": 268435456, + "80:117": 402653184, + "81:117": 268435456, + "82:117": 402653184, + "83:117": 268435456, + "84:117": 402653184, + "85:117": 268435456, + "86:117": 402653184, + "87:117": 268435456, + "88:117": 402653184, + "89:117": 268435456, + "90:117": 402653184, + "91:117": 268435456, + "92:117": 402653184, + "93:117": 268435456, + "94:117": 402653184, + "95:117": 268435456, + "96:117": 402653184, + "97:117": 268435456, + "98:117": 402653184, + "99:117": 268435456, + "100:117": 402653184, + "101:117": 268435456, + "102:117": 402653184, + "103:117": 268435456, + "104:117": 402653184, + "105:117": 268435456, + "106:117": 402653184, + "107:117": 268435456, + "108:117": 402653184, + "109:117": 268435456, + "110:117": 402653184, + "111:117": 268435456, + "112:117": 402653184, + "113:117": 268435456, + "114:117": 402653184, + "115:117": 268435456, + "116:117": 402653184, + "117:117": 268435456, + "118:117": 402653184, + "119:117": 268435456, + "120:117": 402653184, + "121:117": 268435456, + "122:117": 402653184, + "123:117": 268435456, + "124:117": 402653184, + "125:117": 268435456, + "126:117": 402653184, + "127:117": 268435456, + "0:118": 268435456, + "1:118": 402653184, + "2:118": 268435456, + "3:118": 402653184, + "4:118": 268435456, + "5:118": 402653184, + "6:118": 268435456, + "7:118": 402653184, + "8:118": 268435456, + "9:118": 402653184, + "10:118": 268435456, + "11:118": 402653184, + "12:118": 268435456, + "13:118": 402653184, + "14:118": 268435456, + "15:118": 402653184, + "16:118": 268435456, + "17:118": 402653184, + "18:118": 268435456, + "19:118": 402653184, + "20:118": 268435456, + "21:118": 402653184, + "22:118": 268435456, + "23:118": 402653184, + "24:118": 268435456, + "25:118": 402653184, + "26:118": 268435456, + "27:118": 402653184, + "28:118": 268435456, + "29:118": 402653184, + "30:118": 268435456, + "31:118": 402653184, + "32:118": 268435456, + "33:118": 402653184, + "34:118": 268435456, + "35:118": 402653184, + "36:118": 268435456, + "37:118": 402653184, + "38:118": 268435456, + "39:118": 402653184, + "40:118": 268435456, + "41:118": 402653184, + "42:118": 268435456, + "43:118": 402653184, + "44:118": 268435456, + "45:118": 402653184, + "46:118": 268435456, + "47:118": 402653184, + "48:118": 268435456, + "49:118": 402653184, + "50:118": 268435456, + "51:118": 402653184, + "52:118": 268435456, + "53:118": 402653184, + "54:118": 268435456, + "55:118": 402653184, + "56:118": 268435456, + "57:118": 402653184, + "58:118": 268435456, + "59:118": 402653184, + "60:118": 268435456, + "61:118": 402653184, + "62:118": 268435456, + "63:118": 402653184, + "64:118": 268435456, + "65:118": 402653184, + "66:118": 268435456, + "67:118": 402653184, + "68:118": 268435456, + "69:118": 402653184, + "70:118": 268435456, + "71:118": 402653184, + "72:118": 268435456, + "73:118": 402653184, + "74:118": 268435456, + "75:118": 402653184, + "76:118": 268435456, + "77:118": 402653184, + "78:118": 268435456, + "79:118": 402653184, + "80:118": 268435456, + "81:118": 402653184, + "82:118": 268435456, + "83:118": 402653184, + "84:118": 268435456, + "85:118": 402653184, + "86:118": 268435456, + "87:118": 402653184, + "88:118": 268435456, + "89:118": 402653184, + "90:118": 268435456, + "91:118": 402653184, + "92:118": 268435456, + "93:118": 402653184, + "94:118": 268435456, + "95:118": 402653184, + "96:118": 268435456, + "97:118": 402653184, + "98:118": 268435456, + "99:118": 402653184, + "100:118": 268435456, + "101:118": 402653184, + "102:118": 268435456, + "103:118": 402653184, + "104:118": 268435456, + "105:118": 402653184, + "106:118": 268435456, + "107:118": 402653184, + "108:118": 268435456, + "109:118": 402653184, + "110:118": 268435456, + "111:118": 402653184, + "112:118": 268435456, + "113:118": 402653184, + "114:118": 268435456, + "115:118": 402653184, + "116:118": 268435456, + "117:118": 402653184, + "118:118": 268435456, + "119:118": 402653184, + "120:118": 268435456, + "121:118": 402653184, + "122:118": 268435456, + "123:118": 402653184, + "124:118": 268435456, + "125:118": 402653184, + "126:118": 268435456, + "127:118": 402653184, + "0:119": 402653184, + "1:119": 268435456, + "2:119": 402653184, + "3:119": 268435456, + "4:119": 402653184, + "5:119": 268435456, + "6:119": 402653184, + "7:119": 268435456, + "8:119": 402653184, + "9:119": 268435456, + "10:119": 402653184, + "11:119": 268435456, + "12:119": 402653184, + "13:119": 268435456, + "14:119": 402653184, + "15:119": 268435456, + "16:119": 402653184, + "17:119": 268435456, + "18:119": 402653184, + "19:119": 268435456, + "20:119": 402653184, + "21:119": 268435456, + "22:119": 402653184, + "23:119": 268435456, + "24:119": 402653184, + "25:119": 268435456, + "26:119": 402653184, + "27:119": 268435456, + "28:119": 402653184, + "29:119": 268435456, + "30:119": 402653184, + "31:119": 268435456, + "32:119": 402653184, + "33:119": 268435456, + "34:119": 402653184, + "35:119": 268435456, + "36:119": 402653184, + "37:119": 268435456, + "38:119": 402653184, + "39:119": 268435456, + "40:119": 402653184, + "41:119": 268435456, + "42:119": 402653184, + "43:119": 268435456, + "44:119": 402653184, + "45:119": 268435456, + "46:119": 402653184, + "47:119": 268435456, + "48:119": 402653184, + "49:119": 268435456, + "50:119": 402653184, + "51:119": 268435456, + "52:119": 402653184, + "53:119": 268435456, + "54:119": 402653184, + "55:119": 268435456, + "56:119": 402653184, + "57:119": 268435456, + "58:119": 402653184, + "59:119": 268435456, + "60:119": 402653184, + "61:119": 268435456, + "62:119": 402653184, + "63:119": 268435456, + "64:119": 402653184, + "65:119": 268435456, + "66:119": 402653184, + "67:119": 268435456, + "68:119": 402653184, + "69:119": 268435456, + "70:119": 402653184, + "71:119": 268435456, + "72:119": 402653184, + "73:119": 268435456, + "74:119": 402653184, + "75:119": 268435456, + "76:119": 402653184, + "77:119": 268435456, + "78:119": 402653184, + "79:119": 268435456, + "80:119": 402653184, + "81:119": 268435456, + "82:119": 402653184, + "83:119": 268435456, + "84:119": 402653184, + "85:119": 268435456, + "86:119": 402653184, + "87:119": 268435456, + "88:119": 402653184, + "89:119": 268435456, + "90:119": 402653184, + "91:119": 268435456, + "92:119": 402653184, + "93:119": 268435456, + "94:119": 402653184, + "95:119": 268435456, + "96:119": 402653184, + "97:119": 268435456, + "98:119": 402653184, + "99:119": 268435456, + "100:119": 402653184, + "101:119": 268435456, + "102:119": 402653184, + "103:119": 268435456, + "104:119": 402653184, + "105:119": 268435456, + "106:119": 402653184, + "107:119": 268435456, + "108:119": 402653184, + "109:119": 268435456, + "110:119": 402653184, + "111:119": 268435456, + "112:119": 402653184, + "113:119": 268435456, + "114:119": 402653184, + "115:119": 268435456, + "116:119": 402653184, + "117:119": 268435456, + "118:119": 402653184, + "119:119": 268435456, + "120:119": 402653184, + "121:119": 268435456, + "122:119": 402653184, + "123:119": 268435456, + "124:119": 402653184, + "125:119": 268435456, + "126:119": 402653184, + "127:119": 268435456, + "0:120": 268435456, + "1:120": 402653184, + "2:120": 268435456, + "3:120": 402653184, + "4:120": 268435456, + "5:120": 402653184, + "6:120": 268435456, + "7:120": 402653184, + "8:120": 268435456, + "9:120": 402653184, + "10:120": 268435456, + "11:120": 402653184, + "12:120": 268435456, + "13:120": 402653184, + "14:120": 268435456, + "15:120": 402653184, + "16:120": 268435456, + "17:120": 402653184, + "18:120": 268435456, + "19:120": 402653184, + "20:120": 268435456, + "21:120": 402653184, + "22:120": 268435456, + "23:120": 402653184, + "24:120": 268435456, + "25:120": 402653184, + "26:120": 268435456, + "27:120": 402653184, + "28:120": 268435456, + "29:120": 402653184, + "30:120": 268435456, + "31:120": 402653184, + "32:120": 268435456, + "33:120": 402653184, + "34:120": 268435456, + "35:120": 402653184, + "36:120": 268435456, + "37:120": 402653184, + "38:120": 268435456, + "39:120": 402653184, + "40:120": 268435456, + "41:120": 402653184, + "42:120": 268435456, + "43:120": 402653184, + "44:120": 268435456, + "45:120": 402653184, + "46:120": 268435456, + "47:120": 402653184, + "48:120": 268435456, + "49:120": 402653184, + "50:120": 268435456, + "51:120": 402653184, + "52:120": 268435456, + "53:120": 402653184, + "54:120": 268435456, + "55:120": 402653184, + "56:120": 268435456, + "57:120": 402653184, + "58:120": 268435456, + "59:120": 402653184, + "60:120": 268435456, + "61:120": 402653184, + "62:120": 268435456, + "63:120": 402653184, + "64:120": 268435456, + "65:120": 402653184, + "66:120": 268435456, + "67:120": 402653184, + "68:120": 268435456, + "69:120": 402653184, + "70:120": 268435456, + "71:120": 402653184, + "72:120": 268435456, + "73:120": 402653184, + "74:120": 268435456, + "75:120": 402653184, + "76:120": 268435456, + "77:120": 402653184, + "78:120": 268435456, + "79:120": 402653184, + "80:120": 268435456, + "81:120": 402653184, + "82:120": 268435456, + "83:120": 402653184, + "84:120": 268435456, + "85:120": 402653184, + "86:120": 268435456, + "87:120": 402653184, + "88:120": 268435456, + "89:120": 402653184, + "90:120": 268435456, + "91:120": 402653184, + "92:120": 268435456, + "93:120": 402653184, + "94:120": 268435456, + "95:120": 402653184, + "96:120": 268435456, + "97:120": 402653184, + "98:120": 268435456, + "99:120": 402653184, + "100:120": 268435456, + "101:120": 402653184, + "102:120": 268435456, + "103:120": 402653184, + "104:120": 268435456, + "105:120": 402653184, + "106:120": 268435456, + "107:120": 402653184, + "108:120": 268435456, + "109:120": 402653184, + "110:120": 268435456, + "111:120": 402653184, + "112:120": 268435456, + "113:120": 402653184, + "114:120": 268435456, + "115:120": 402653184, + "116:120": 268435456, + "117:120": 402653184, + "118:120": 268435456, + "119:120": 402653184, + "120:120": 268435456, + "121:120": 402653184, + "122:120": 268435456, + "123:120": 402653184, + "124:120": 268435456, + "125:120": 402653184, + "126:120": 268435456, + "127:120": 402653184, + "0:121": 402653184, + "1:121": 268435456, + "2:121": 402653184, + "3:121": 268435456, + "4:121": 402653184, + "5:121": 268435456, + "6:121": 402653184, + "7:121": 268435456, + "8:121": 402653184, + "9:121": 268435456, + "10:121": 402653184, + "11:121": 268435456, + "12:121": 402653184, + "13:121": 268435456, + "14:121": 402653184, + "15:121": 268435456, + "16:121": 402653184, + "17:121": 268435456, + "18:121": 402653184, + "19:121": 268435456, + "20:121": 402653184, + "21:121": 268435456, + "22:121": 402653184, + "23:121": 268435456, + "24:121": 402653184, + "25:121": 268435456, + "26:121": 402653184, + "27:121": 268435456, + "28:121": 402653184, + "29:121": 268435456, + "30:121": 402653184, + "31:121": 268435456, + "32:121": 402653184, + "33:121": 268435456, + "34:121": 402653184, + "35:121": 268435456, + "36:121": 402653184, + "37:121": 268435456, + "38:121": 402653184, + "39:121": 268435456, + "40:121": 402653184, + "41:121": 268435456, + "42:121": 402653184, + "43:121": 268435456, + "44:121": 402653184, + "45:121": 268435456, + "46:121": 402653184, + "47:121": 268435456, + "48:121": 402653184, + "49:121": 268435456, + "50:121": 402653184, + "51:121": 268435456, + "52:121": 402653184, + "53:121": 268435456, + "54:121": 402653184, + "55:121": 268435456, + "56:121": 402653184, + "57:121": 268435456, + "58:121": 402653184, + "59:121": 268435456, + "60:121": 402653184, + "61:121": 268435456, + "62:121": 402653184, + "63:121": 268435456, + "64:121": 402653184, + "65:121": 268435456, + "66:121": 402653184, + "67:121": 268435456, + "68:121": 402653184, + "69:121": 268435456, + "70:121": 402653184, + "71:121": 268435456, + "72:121": 402653184, + "73:121": 268435456, + "74:121": 402653184, + "75:121": 268435456, + "76:121": 402653184, + "77:121": 268435456, + "78:121": 402653184, + "79:121": 268435456, + "80:121": 402653184, + "81:121": 268435456, + "82:121": 402653184, + "83:121": 268435456, + "84:121": 402653184, + "85:121": 268435456, + "86:121": 402653184, + "87:121": 268435456, + "88:121": 402653184, + "89:121": 268435456, + "90:121": 402653184, + "91:121": 268435456, + "92:121": 402653184, + "93:121": 268435456, + "94:121": 402653184, + "95:121": 268435456, + "96:121": 402653184, + "97:121": 268435456, + "98:121": 402653184, + "99:121": 268435456, + "100:121": 402653184, + "101:121": 268435456, + "102:121": 402653184, + "103:121": 268435456, + "104:121": 402653184, + "105:121": 268435456, + "106:121": 402653184, + "107:121": 268435456, + "108:121": 402653184, + "109:121": 268435456, + "110:121": 402653184, + "111:121": 268435456, + "112:121": 402653184, + "113:121": 268435456, + "114:121": 402653184, + "115:121": 268435456, + "116:121": 402653184, + "117:121": 268435456, + "118:121": 402653184, + "119:121": 268435456, + "120:121": 402653184, + "121:121": 268435456, + "122:121": 402653184, + "123:121": 268435456, + "124:121": 402653184, + "125:121": 268435456, + "126:121": 402653184, + "127:121": 268435456, + "0:122": 268435456, + "1:122": 402653184, + "2:122": 268435456, + "3:122": 402653184, + "4:122": 268435456, + "5:122": 402653184, + "6:122": 268435456, + "7:122": 402653184, + "8:122": 268435456, + "9:122": 402653184, + "10:122": 268435456, + "11:122": 402653184, + "12:122": 268435456, + "13:122": 402653184, + "14:122": 268435456, + "15:122": 402653184, + "16:122": 268435456, + "17:122": 402653184, + "18:122": 268435456, + "19:122": 402653184, + "20:122": 268435456, + "21:122": 402653184, + "22:122": 268435456, + "23:122": 402653184, + "24:122": 268435456, + "25:122": 402653184, + "26:122": 268435456, + "27:122": 402653184, + "28:122": 268435456, + "29:122": 402653184, + "30:122": 268435456, + "31:122": 402653184, + "32:122": 268435456, + "33:122": 402653184, + "34:122": 268435456, + "35:122": 402653184, + "36:122": 268435456, + "37:122": 402653184, + "38:122": 268435456, + "39:122": 402653184, + "40:122": 268435456, + "41:122": 402653184, + "42:122": 268435456, + "43:122": 402653184, + "44:122": 268435456, + "45:122": 402653184, + "46:122": 268435456, + "47:122": 402653184, + "48:122": 268435456, + "49:122": 402653184, + "50:122": 268435456, + "51:122": 402653184, + "52:122": 268435456, + "53:122": 402653184, + "54:122": 268435456, + "55:122": 402653184, + "56:122": 268435456, + "57:122": 402653184, + "58:122": 268435456, + "59:122": 402653184, + "60:122": 268435456, + "61:122": 402653184, + "62:122": 268435456, + "63:122": 402653184, + "64:122": 268435456, + "65:122": 402653184, + "66:122": 268435456, + "67:122": 402653184, + "68:122": 268435456, + "69:122": 402653184, + "70:122": 268435456, + "71:122": 402653184, + "72:122": 268435456, + "73:122": 402653184, + "74:122": 268435456, + "75:122": 402653184, + "76:122": 268435456, + "77:122": 402653184, + "78:122": 268435456, + "79:122": 402653184, + "80:122": 268435456, + "81:122": 402653184, + "82:122": 268435456, + "83:122": 402653184, + "84:122": 268435456, + "85:122": 402653184, + "86:122": 268435456, + "87:122": 402653184, + "88:122": 268435456, + "89:122": 402653184, + "90:122": 268435456, + "91:122": 402653184, + "92:122": 268435456, + "93:122": 402653184, + "94:122": 268435456, + "95:122": 402653184, + "96:122": 268435456, + "97:122": 402653184, + "98:122": 268435456, + "99:122": 402653184, + "100:122": 268435456, + "101:122": 402653184, + "102:122": 268435456, + "103:122": 402653184, + "104:122": 268435456, + "105:122": 402653184, + "106:122": 268435456, + "107:122": 402653184, + "108:122": 268435456, + "109:122": 402653184, + "110:122": 268435456, + "111:122": 402653184, + "112:122": 268435456, + "113:122": 402653184, + "114:122": 268435456, + "115:122": 402653184, + "116:122": 268435456, + "117:122": 402653184, + "118:122": 268435456, + "119:122": 402653184, + "120:122": 268435456, + "121:122": 402653184, + "122:122": 268435456, + "123:122": 402653184, + "124:122": 268435456, + "125:122": 402653184, + "126:122": 268435456, + "127:122": 402653184, + "0:123": 402653184, + "1:123": 268435456, + "2:123": 402653184, + "3:123": 268435456, + "4:123": 402653184, + "5:123": 268435456, + "6:123": 402653184, + "7:123": 268435456, + "8:123": 402653184, + "9:123": 268435456, + "10:123": 402653184, + "11:123": 268435456, + "12:123": 402653184, + "13:123": 268435456, + "14:123": 402653184, + "15:123": 268435456, + "16:123": 402653184, + "17:123": 268435456, + "18:123": 402653184, + "19:123": 268435456, + "20:123": 402653184, + "21:123": 268435456, + "22:123": 402653184, + "23:123": 268435456, + "24:123": 402653184, + "25:123": 268435456, + "26:123": 402653184, + "27:123": 268435456, + "28:123": 402653184, + "29:123": 268435456, + "30:123": 402653184, + "31:123": 268435456, + "32:123": 402653184, + "33:123": 268435456, + "34:123": 402653184, + "35:123": 268435456, + "36:123": 402653184, + "37:123": 268435456, + "38:123": 402653184, + "39:123": 268435456, + "40:123": 402653184, + "41:123": 268435456, + "42:123": 402653184, + "43:123": 268435456, + "44:123": 402653184, + "45:123": 268435456, + "46:123": 402653184, + "47:123": 268435456, + "48:123": 402653184, + "49:123": 268435456, + "50:123": 402653184, + "51:123": 268435456, + "52:123": 402653184, + "53:123": 268435456, + "54:123": 402653184, + "55:123": 268435456, + "56:123": 402653184, + "57:123": 268435456, + "58:123": 402653184, + "59:123": 268435456, + "60:123": 402653184, + "61:123": 268435456, + "62:123": 402653184, + "63:123": 268435456, + "64:123": 402653184, + "65:123": 268435456, + "66:123": 402653184, + "67:123": 268435456, + "68:123": 402653184, + "69:123": 268435456, + "70:123": 402653184, + "71:123": 268435456, + "72:123": 402653184, + "73:123": 268435456, + "74:123": 402653184, + "75:123": 268435456, + "76:123": 402653184, + "77:123": 268435456, + "78:123": 402653184, + "79:123": 268435456, + "80:123": 402653184, + "81:123": 268435456, + "82:123": 402653184, + "83:123": 268435456, + "84:123": 402653184, + "85:123": 268435456, + "86:123": 402653184, + "87:123": 268435456, + "88:123": 402653184, + "89:123": 268435456, + "90:123": 402653184, + "91:123": 268435456, + "92:123": 402653184, + "93:123": 268435456, + "94:123": 402653184, + "95:123": 268435456, + "96:123": 402653184, + "97:123": 268435456, + "98:123": 402653184, + "99:123": 268435456, + "100:123": 402653184, + "101:123": 268435456, + "102:123": 402653184, + "103:123": 268435456, + "104:123": 402653184, + "105:123": 268435456, + "106:123": 402653184, + "107:123": 268435456, + "108:123": 402653184, + "109:123": 268435456, + "110:123": 402653184, + "111:123": 268435456, + "112:123": 402653184, + "113:123": 268435456, + "114:123": 402653184, + "115:123": 268435456, + "116:123": 402653184, + "117:123": 268435456, + "118:123": 402653184, + "119:123": 268435456, + "120:123": 402653184, + "121:123": 268435456, + "122:123": 402653184, + "123:123": 268435456, + "124:123": 402653184, + "125:123": 268435456, + "126:123": 402653184, + "127:123": 268435456, + "0:124": 268435456, + "1:124": 402653184, + "2:124": 268435456, + "3:124": 402653184, + "4:124": 268435456, + "5:124": 402653184, + "6:124": 268435456, + "7:124": 402653184, + "8:124": 268435456, + "9:124": 402653184, + "10:124": 268435456, + "11:124": 402653184, + "12:124": 268435456, + "13:124": 402653184, + "14:124": 268435456, + "15:124": 402653184, + "16:124": 268435456, + "17:124": 402653184, + "18:124": 268435456, + "19:124": 402653184, + "20:124": 268435456, + "21:124": 402653184, + "22:124": 268435456, + "23:124": 402653184, + "24:124": 268435456, + "25:124": 402653184, + "26:124": 268435456, + "27:124": 402653184, + "28:124": 268435456, + "29:124": 402653184, + "30:124": 268435456, + "31:124": 402653184, + "32:124": 268435456, + "33:124": 402653184, + "34:124": 268435456, + "35:124": 402653184, + "36:124": 268435456, + "37:124": 402653184, + "38:124": 268435456, + "39:124": 402653184, + "40:124": 268435456, + "41:124": 402653184, + "42:124": 268435456, + "43:124": 402653184, + "44:124": 268435456, + "45:124": 402653184, + "46:124": 268435456, + "47:124": 402653184, + "48:124": 268435456, + "49:124": 402653184, + "50:124": 268435456, + "51:124": 402653184, + "52:124": 268435456, + "53:124": 402653184, + "54:124": 268435456, + "55:124": 402653184, + "56:124": 268435456, + "57:124": 402653184, + "58:124": 268435456, + "59:124": 402653184, + "60:124": 268435456, + "61:124": 402653184, + "62:124": 268435456, + "63:124": 402653184, + "64:124": 268435456, + "65:124": 402653184, + "66:124": 268435456, + "67:124": 402653184, + "68:124": 268435456, + "69:124": 402653184, + "70:124": 268435456, + "71:124": 402653184, + "72:124": 268435456, + "73:124": 402653184, + "74:124": 268435456, + "75:124": 402653184, + "76:124": 268435456, + "77:124": 402653184, + "78:124": 268435456, + "79:124": 402653184, + "80:124": 268435456, + "81:124": 402653184, + "82:124": 268435456, + "83:124": 402653184, + "84:124": 268435456, + "85:124": 402653184, + "86:124": 268435456, + "87:124": 402653184, + "88:124": 268435456, + "89:124": 402653184, + "90:124": 268435456, + "91:124": 402653184, + "92:124": 268435456, + "93:124": 402653184, + "94:124": 268435456, + "95:124": 402653184, + "96:124": 268435456, + "97:124": 402653184, + "98:124": 268435456, + "99:124": 402653184, + "100:124": 268435456, + "101:124": 402653184, + "102:124": 268435456, + "103:124": 402653184, + "104:124": 268435456, + "105:124": 402653184, + "106:124": 268435456, + "107:124": 402653184, + "108:124": 268435456, + "109:124": 402653184, + "110:124": 268435456, + "111:124": 402653184, + "112:124": 268435456, + "113:124": 402653184, + "114:124": 268435456, + "115:124": 402653184, + "116:124": 268435456, + "117:124": 402653184, + "118:124": 268435456, + "119:124": 402653184, + "120:124": 268435456, + "121:124": 402653184, + "122:124": 268435456, + "123:124": 402653184, + "124:124": 268435456, + "125:124": 402653184, + "126:124": 268435456, + "127:124": 402653184, + "0:125": 402653184, + "1:125": 268435456, + "2:125": 402653184, + "3:125": 268435456, + "4:125": 402653184, + "5:125": 268435456, + "6:125": 402653184, + "7:125": 268435456, + "8:125": 402653184, + "9:125": 268435456, + "10:125": 402653184, + "11:125": 268435456, + "12:125": 402653184, + "13:125": 268435456, + "14:125": 402653184, + "15:125": 268435456, + "16:125": 402653184, + "17:125": 268435456, + "18:125": 402653184, + "19:125": 268435456, + "20:125": 402653184, + "21:125": 268435456, + "22:125": 402653184, + "23:125": 268435456, + "24:125": 402653184, + "25:125": 268435456, + "26:125": 402653184, + "27:125": 268435456, + "28:125": 402653184, + "29:125": 268435456, + "30:125": 402653184, + "31:125": 268435456, + "32:125": 402653184, + "33:125": 268435456, + "34:125": 402653184, + "35:125": 268435456, + "36:125": 402653184, + "37:125": 268435456, + "38:125": 402653184, + "39:125": 268435456, + "40:125": 402653184, + "41:125": 268435456, + "42:125": 402653184, + "43:125": 268435456, + "44:125": 402653184, + "45:125": 268435456, + "46:125": 402653184, + "47:125": 268435456, + "48:125": 402653184, + "49:125": 268435456, + "50:125": 402653184, + "51:125": 268435456, + "52:125": 402653184, + "53:125": 268435456, + "54:125": 402653184, + "55:125": 268435456, + "56:125": 402653184, + "57:125": 268435456, + "58:125": 402653184, + "59:125": 268435456, + "60:125": 402653184, + "61:125": 268435456, + "62:125": 402653184, + "63:125": 268435456, + "64:125": 402653184, + "65:125": 268435456, + "66:125": 402653184, + "67:125": 268435456, + "68:125": 402653184, + "69:125": 268435456, + "70:125": 402653184, + "71:125": 268435456, + "72:125": 402653184, + "73:125": 268435456, + "74:125": 402653184, + "75:125": 268435456, + "76:125": 402653184, + "77:125": 268435456, + "78:125": 402653184, + "79:125": 268435456, + "80:125": 402653184, + "81:125": 268435456, + "82:125": 402653184, + "83:125": 268435456, + "84:125": 402653184, + "85:125": 268435456, + "86:125": 402653184, + "87:125": 268435456, + "88:125": 402653184, + "89:125": 268435456, + "90:125": 402653184, + "91:125": 268435456, + "92:125": 402653184, + "93:125": 268435456, + "94:125": 402653184, + "95:125": 268435456, + "96:125": 402653184, + "97:125": 268435456, + "98:125": 402653184, + "99:125": 268435456, + "100:125": 402653184, + "101:125": 268435456, + "102:125": 402653184, + "103:125": 268435456, + "104:125": 402653184, + "105:125": 268435456, + "106:125": 402653184, + "107:125": 268435456, + "108:125": 402653184, + "109:125": 268435456, + "110:125": 402653184, + "111:125": 268435456, + "112:125": 402653184, + "113:125": 268435456, + "114:125": 402653184, + "115:125": 268435456, + "116:125": 402653184, + "117:125": 268435456, + "118:125": 402653184, + "119:125": 268435456, + "120:125": 402653184, + "121:125": 268435456, + "122:125": 402653184, + "123:125": 268435456, + "124:125": 402653184, + "125:125": 268435456, + "126:125": 402653184, + "127:125": 268435456, + "0:126": 268435456, + "1:126": 402653184, + "2:126": 268435456, + "3:126": 402653184, + "4:126": 268435456, + "5:126": 402653184, + "6:126": 268435456, + "7:126": 402653184, + "8:126": 268435456, + "9:126": 402653184, + "10:126": 268435456, + "11:126": 402653184, + "12:126": 268435456, + "13:126": 402653184, + "14:126": 268435456, + "15:126": 402653184, + "16:126": 268435456, + "17:126": 402653184, + "18:126": 268435456, + "19:126": 402653184, + "20:126": 268435456, + "21:126": 402653184, + "22:126": 268435456, + "23:126": 402653184, + "24:126": 268435456, + "25:126": 402653184, + "26:126": 268435456, + "27:126": 402653184, + "28:126": 268435456, + "29:126": 402653184, + "30:126": 268435456, + "31:126": 402653184, + "32:126": 268435456, + "33:126": 402653184, + "34:126": 268435456, + "35:126": 402653184, + "36:126": 268435456, + "37:126": 402653184, + "38:126": 268435456, + "39:126": 402653184, + "40:126": 268435456, + "41:126": 402653184, + "42:126": 268435456, + "43:126": 402653184, + "44:126": 268435456, + "45:126": 402653184, + "46:126": 268435456, + "47:126": 402653184, + "48:126": 268435456, + "49:126": 402653184, + "50:126": 268435456, + "51:126": 402653184, + "52:126": 268435456, + "53:126": 402653184, + "54:126": 268435456, + "55:126": 402653184, + "56:126": 268435456, + "57:126": 402653184, + "58:126": 268435456, + "59:126": 402653184, + "60:126": 268435456, + "61:126": 402653184, + "62:126": 268435456, + "63:126": 402653184, + "64:126": 268435456, + "65:126": 402653184, + "66:126": 268435456, + "67:126": 402653184, + "68:126": 268435456, + "69:126": 402653184, + "70:126": 268435456, + "71:126": 402653184, + "72:126": 268435456, + "73:126": 402653184, + "74:126": 268435456, + "75:126": 402653184, + "76:126": 268435456, + "77:126": 402653184, + "78:126": 268435456, + "79:126": 402653184, + "80:126": 268435456, + "81:126": 402653184, + "82:126": 268435456, + "83:126": 402653184, + "84:126": 268435456, + "85:126": 402653184, + "86:126": 268435456, + "87:126": 402653184, + "88:126": 268435456, + "89:126": 402653184, + "90:126": 268435456, + "91:126": 402653184, + "92:126": 268435456, + "93:126": 402653184, + "94:126": 268435456, + "95:126": 402653184, + "96:126": 268435456, + "97:126": 402653184, + "98:126": 268435456, + "99:126": 402653184, + "100:126": 268435456, + "101:126": 402653184, + "102:126": 268435456, + "103:126": 402653184, + "104:126": 268435456, + "105:126": 402653184, + "106:126": 268435456, + "107:126": 402653184, + "108:126": 268435456, + "109:126": 402653184, + "110:126": 268435456, + "111:126": 402653184, + "112:126": 268435456, + "113:126": 402653184, + "114:126": 268435456, + "115:126": 402653184, + "116:126": 268435456, + "117:126": 402653184, + "118:126": 268435456, + "119:126": 402653184, + "120:126": 268435456, + "121:126": 402653184, + "122:126": 268435456, + "123:126": 402653184, + "124:126": 268435456, + "125:126": 402653184, + "126:126": 268435456, + "127:126": 402653184, + "0:127": 402653184, + "1:127": 268435456, + "2:127": 402653184, + "3:127": 268435456, + "4:127": 402653184, + "5:127": 268435456, + "6:127": 402653184, + "7:127": 268435456, + "8:127": 402653184, + "9:127": 268435456, + "10:127": 402653184, + "11:127": 268435456, + "12:127": 402653184, + "13:127": 268435456, + "14:127": 402653184, + "15:127": 268435456, + "16:127": 402653184, + "17:127": 268435456, + "18:127": 402653184, + "19:127": 268435456, + "20:127": 402653184, + "21:127": 268435456, + "22:127": 402653184, + "23:127": 268435456, + "24:127": 402653184, + "25:127": 268435456, + "26:127": 402653184, + "27:127": 268435456, + "28:127": 402653184, + "29:127": 268435456, + "30:127": 402653184, + "31:127": 268435456, + "32:127": 402653184, + "33:127": 268435456, + "34:127": 402653184, + "35:127": 268435456, + "36:127": 402653184, + "37:127": 268435456, + "38:127": 402653184, + "39:127": 268435456, + "40:127": 402653184, + "41:127": 268435456, + "42:127": 402653184, + "43:127": 268435456, + "44:127": 402653184, + "45:127": 268435456, + "46:127": 402653184, + "47:127": 268435456, + "48:127": 402653184, + "49:127": 268435456, + "50:127": 402653184, + "51:127": 268435456, + "52:127": 402653184, + "53:127": 268435456, + "54:127": 402653184, + "55:127": 268435456, + "56:127": 402653184, + "57:127": 268435456, + "58:127": 402653184, + "59:127": 268435456, + "60:127": 402653184, + "61:127": 268435456, + "62:127": 402653184, + "63:127": 268435456, + "64:127": 402653184, + "65:127": 268435456, + "66:127": 402653184, + "67:127": 268435456, + "68:127": 402653184, + "69:127": 268435456, + "70:127": 402653184, + "71:127": 268435456, + "72:127": 402653184, + "73:127": 268435456, + "74:127": 402653184, + "75:127": 268435456, + "76:127": 402653184, + "77:127": 268435456, + "78:127": 402653184, + "79:127": 268435456, + "80:127": 402653184, + "81:127": 268435456, + "82:127": 402653184, + "83:127": 268435456, + "84:127": 402653184, + "85:127": 268435456, + "86:127": 402653184, + "87:127": 268435456, + "88:127": 402653184, + "89:127": 268435456, + "90:127": 402653184, + "91:127": 268435456, + "92:127": 402653184, + "93:127": 268435456, + "94:127": 402653184, + "95:127": 268435456, + "96:127": 402653184, + "97:127": 268435456, + "98:127": 402653184, + "99:127": 268435456, + "100:127": 402653184, + "101:127": 268435456, + "102:127": 402653184, + "103:127": 268435456, + "104:127": 402653184, + "105:127": 268435456, + "106:127": 402653184, + "107:127": 268435456, + "108:127": 402653184, + "109:127": 268435456, + "110:127": 402653184, + "111:127": 268435456, + "112:127": 402653184, + "113:127": 268435456, + "114:127": 402653184, + "115:127": 268435456, + "116:127": 402653184, + "117:127": 268435456, + "118:127": 402653184, + "119:127": 268435456, + "120:127": 402653184, + "121:127": 268435456, + "122:127": 402653184, + "123:127": 268435456, + "124:127": 402653184, + "125:127": 268435456, + "126:127": 402653184, + "127:127": 268435456 +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..27531695 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..5586cf8a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..78540079 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..74bc8f23 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..cdf3fdde --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..63ce6702 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_day/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..93ee50d1 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..9f100e8c --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..7c1e9d5d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..133e3d4a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..c049a2fa --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..f9e5ed40 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_1_night/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..0bfb0d2e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..b4890bc5 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..ea7da9aa --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..92013d1a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..2e3da992 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..95398c35 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..837a2928 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..6f988421 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..0c664062 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..278d92f1 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..f9205c52 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..5ca08bf9 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..f1f6a028 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..882e20a2 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..3ec9391f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..0c99863b --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..92b62ab3 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..169c36be --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_day/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..cb60f6d3 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..d538b920 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..27894a8a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..39a3b594 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..b172a40c --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..3edaba89 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/combat_3_night/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..32f9f7bb --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..ece00b29 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..298621e3 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..ed4af05e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..aca79dcf --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..398e21c9 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dark_auction/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..494c5fe0 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..5da4d3e5 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..445c31dc --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..1de0182b --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..75b6cd4e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..c5e99eac --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dungeon/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..494c5fe0 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..5da4d3e5 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..445c31dc --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..1de0182b --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..75b6cd4e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..c5e99eac --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dungeon_hub/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..f6231245 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..286b3a38 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..c6fca879 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..01b2f816 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..a5c810fe --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..30d32a08 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_day/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..b1fb3e84 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..f7642beb --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..3cb3b42f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..a98d7672 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..ad2b8c70 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..f2e93cde --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/dynamic_night/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..c03b849d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..2286407b --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..62127f51 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..fe631d89 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..cf835eea --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..879b5747 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_day/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..265515f6 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..e774ca7a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..1e3c8a98 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..7833eb89 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..63fafd87 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..ae3bdbdf --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_1_night/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..e03657af --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..27db8499 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..c83f2c91 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..9b730712 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..e687ac9d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..a17337b9 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_day/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..26909780 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..d1eb9e1b --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..dafe1dd3 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..0e870f38 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..51a760f5 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..f40c330c --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/farming_2_night/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..9a12896f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..c157ccdd --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..ecee024b --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..0dbef91f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..681aa33e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..6be866d2 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_day/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..050e4f78 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..c3f012a2 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..557d7396 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..3af3638e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..b5f913e6 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..d3c13992 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/foraging_1_night/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..0d5f26dd --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..820b92a4 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..14d01dd1 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..bfc66ec9 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..07f17d24 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..f3df82a5 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/hub_day/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..34bc84db --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..742d158b --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..abf0a253 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..7efc75d6 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..a7f7988b --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..e86e93c4 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/hub_night/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..e0c4288d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..e0cc8139 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..381912e1 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..0beaf628 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..26417482 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..8571b288 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_day/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..e90efd5f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..603f9d04 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..b4d253f6 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..abd201d1 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..4c12b0b9 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..93a5a26d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_1_night/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..7aced4cc --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..852a1af2 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..6710318f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..3d42e658 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..08abb255 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..3d4845d9 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/mining_2/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_0.jpg Binary files differnew file mode 100644 index 00000000..9482df80 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_0.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_1.jpg Binary files differnew file mode 100644 index 00000000..1b4235dd --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_1.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_2.jpg Binary files differnew file mode 100644 index 00000000..2f1fcc06 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_2.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_3.jpg Binary files differnew file mode 100644 index 00000000..ce20d9b5 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_3.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_4.jpg Binary files differnew file mode 100644 index 00000000..3dcdac57 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_4.jpg diff --git a/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_5.jpg Binary files differnew file mode 100644 index 00000000..45f65c7c --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/panoramas/unknown/panorama_5.jpg diff --git a/src/main/resources/assets/notenoughupdates/pv_basic.png b/src/main/resources/assets/notenoughupdates/pv_basic.png Binary files differnew file mode 100644 index 00000000..227bad5a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/pv_basic.png diff --git a/src/main/resources/assets/notenoughupdates/pv_bg.png b/src/main/resources/assets/notenoughupdates/pv_bg.png Binary files differnew file mode 100644 index 00000000..6c09e78d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/pv_bg.png diff --git a/src/main/resources/assets/notenoughupdates/pv_cols.png b/src/main/resources/assets/notenoughupdates/pv_cols.png Binary files differnew file mode 100644 index 00000000..d0f2fa73 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/pv_cols.png diff --git a/src/main/resources/assets/notenoughupdates/pv_dropdown.png b/src/main/resources/assets/notenoughupdates/pv_dropdown.png Binary files differnew file mode 100644 index 00000000..af847f27 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/pv_dropdown.png diff --git a/src/main/resources/assets/notenoughupdates/pv_elements.png b/src/main/resources/assets/notenoughupdates/pv_elements.png Binary files differnew file mode 100644 index 00000000..d742301e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/pv_elements.png diff --git a/src/main/resources/assets/notenoughupdates/pv_extra.png b/src/main/resources/assets/notenoughupdates/pv_extra.png Binary files differnew file mode 100644 index 00000000..3203c85f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/pv_extra.png diff --git a/src/main/resources/assets/notenoughupdates/pv_invs.png b/src/main/resources/assets/notenoughupdates/pv_invs.png Binary files differnew file mode 100644 index 00000000..881078d2 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/pv_invs.png diff --git a/src/main/resources/assets/notenoughupdates/pv_pets.png b/src/main/resources/assets/notenoughupdates/pv_pets.png Binary files differnew file mode 100644 index 00000000..c953c313 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/pv_pets.png diff --git a/src/main/resources/assets/notenoughupdates/quickcommand_background.png b/src/main/resources/assets/notenoughupdates/quickcommand_background.png Binary files differnew file mode 100644 index 00000000..d3c2a3ad --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/quickcommand_background.png diff --git a/src/main/resources/assets/notenoughupdates/radial_circle_off.png b/src/main/resources/assets/notenoughupdates/radial_circle_off.png Binary files differnew file mode 100644 index 00000000..300cbcfb --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/radial_circle_off.png diff --git a/src/main/resources/assets/notenoughupdates/radial_circle_on.png b/src/main/resources/assets/notenoughupdates/radial_circle_on.png Binary files differnew file mode 100644 index 00000000..4d5cc862 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/radial_circle_on.png diff --git a/src/main/resources/assets/notenoughupdates/radial_square_off.png b/src/main/resources/assets/notenoughupdates/radial_square_off.png Binary files differnew file mode 100644 index 00000000..97fbf27e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/radial_square_off.png diff --git a/src/main/resources/assets/notenoughupdates/radial_square_on.png b/src/main/resources/assets/notenoughupdates/radial_square_on.png Binary files differnew file mode 100644 index 00000000..5116df80 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/radial_square_on.png diff --git a/src/main/resources/assets/notenoughupdates/setting_border.png b/src/main/resources/assets/notenoughupdates/setting_border.png Binary files differnew file mode 100644 index 00000000..e5dff747 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/setting_border.png diff --git a/src/main/resources/assets/notenoughupdates/shaders/cape.frag b/src/main/resources/assets/notenoughupdates/shaders/cape.frag index cbe00c70..bfc089bb 100644 --- a/src/main/resources/assets/notenoughupdates/shaders/cape.frag +++ b/src/main/resources/assets/notenoughupdates/shaders/cape.frag @@ -8,9 +8,9 @@ void main() { vec4 texture = texture2D(textureIn, gl_TexCoord[0].st); gl_FragColor = texture * passColour; - vec3 fakeSunNormal = normalize(vec3(0.2f,1f,-0.2f)); + vec3 fakeSunNormal = normalize(vec3(0.2f,1.0f,-0.2f)); vec3 normNormal = normalize(passNormal); float shading = max(0.6f, dot(fakeSunNormal, normNormal)); - gl_FragColor = vec4(gl_FragColor.rgb*shading, gl_FragColor.a);//gl_FragColor.rgb*shading + gl_FragColor = vec4(gl_FragColor.rgb*shading, gl_FragColor.a); }
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/shaders/fade_cape.frag b/src/main/resources/assets/notenoughupdates/shaders/fade_cape.frag index 76738c31..33d6b341 100644 --- a/src/main/resources/assets/notenoughupdates/shaders/fade_cape.frag +++ b/src/main/resources/assets/notenoughupdates/shaders/fade_cape.frag @@ -16,16 +16,16 @@ vec3 hsv2rgb(vec3 c) { void main() { vec4 texture = texture2D(textureIn, gl_TexCoord[0].st); - float hue = mod(millis/10000f+gl_TexCoord[0].t, 1f); + float hue = mod(millis/10000.0f+gl_TexCoord[0].t, 1.0f); float sat = 0.5f; float val = 0.5f; vec3 fade = hsv2rgb(vec3(hue, sat, val)); - gl_FragColor = vec4(texture.rgb*texture.a + fade*(1-texture.a), 1f) * passColour; + gl_FragColor = vec4(texture.rgb*texture.a + fade*(1.0f-texture.a), 1.0f) * passColour; - vec3 fakeSunNormal = normalize(vec3(0.2f,1f,-0.2f)); + vec3 fakeSunNormal = normalize(vec3(0.2f,1.0f,-0.2f)); vec3 normNormal = normalize(passNormal); float shading = max(0.6f, dot(fakeSunNormal, normNormal)); gl_FragColor = vec4(gl_FragColor.rgb*shading, gl_FragColor.a); -}
\ No newline at end of file +} diff --git a/src/main/resources/assets/notenoughupdates/shaders/lava_cape.frag b/src/main/resources/assets/notenoughupdates/shaders/lava_cape.frag new file mode 100644 index 00000000..9fb35990 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/lava_cape.frag @@ -0,0 +1,32 @@ +#version 120 + +varying vec4 passColour; +varying vec3 passNormal; +uniform sampler2D textureIn; + +uniform int millis; + +void main() { + vec4 texture = texture2D(textureIn, gl_TexCoord[0].st); + + float t = gl_TexCoord[0].t; + t = clamp(t, 10.0f/1024.0f, 410.0f/1024.0f); + + float index = mod(millis/30.0f-t*1024.0f, 1024.0f); + float xIndex = mod(index, 1024.0f); + float yIndex = mod(gl_TexCoord[0].s*1024.0f+millis/500.0f, 421.0f)+421.0f; + vec3 lava = texture2D(textureIn, vec2(xIndex/1024.0f, yIndex/1024.0f)).xyz; + + float factor = (lava.r / 0.65f)*(lava.r / 0.65f); + lava.r += sin(mod(millis/2000.0f, 6.28f))*factor*0.15f+sin(mod(millis/500.0f, 6.28f))*factor*0.15f; + lava.g += sin(mod(millis/2000.0f, 6.28f))*factor*0.15f; + lava.b += sin(mod(millis/2000.0f, 6.28f))*factor*0.15f; + + gl_FragColor = vec4(texture.rgb*texture.a + lava*(1.0f-texture.a), 1.0f) * passColour; + + vec3 fakeSunNormal = normalize(vec3(0.2f,1.0f,-0.2f)); + vec3 normNormal = normalize(passNormal); + float shading = max(0.6f, dot(fakeSunNormal, normNormal)); + + gl_FragColor = vec4(gl_FragColor.rgb*shading, gl_FragColor.a); +} diff --git a/src/main/resources/assets/notenoughupdates/shaders/lava_cape.vert b/src/main/resources/assets/notenoughupdates/shaders/lava_cape.vert new file mode 100644 index 00000000..2b5c48f8 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/lava_cape.vert @@ -0,0 +1,12 @@ +#version 120 + +varying vec4 passColour; +varying vec3 passNormal; + +void main() { + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; + + passColour = gl_Color; + passNormal = normalize(gl_Normal); +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/shaders/lightning_cape.frag b/src/main/resources/assets/notenoughupdates/shaders/lightning_cape.frag new file mode 100644 index 00000000..c4472679 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/lightning_cape.frag @@ -0,0 +1,13 @@ +#version 120 + +varying vec4 passColour; +varying vec3 passNormal; +uniform sampler2D textureIn; + +uniform int millis; + +void main() { + vec4 texture = texture2D(textureIn, gl_TexCoord[0].st); + + gl_FragColor = vec4(texture.rgb*shading, gl_FragColor.a); +} diff --git a/src/main/resources/assets/notenoughupdates/shaders/lightning_cape.vert b/src/main/resources/assets/notenoughupdates/shaders/lightning_cape.vert new file mode 100644 index 00000000..2b5c48f8 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/lightning_cape.vert @@ -0,0 +1,12 @@ +#version 120 + +varying vec4 passColour; +varying vec3 passNormal; + +void main() { + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; + + passColour = gl_Color; + passNormal = normalize(gl_Normal); +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/shaders/make_gold.frag b/src/main/resources/assets/notenoughupdates/shaders/make_gold.frag new file mode 100644 index 00000000..e771f2c2 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/make_gold.frag @@ -0,0 +1,38 @@ +#version 120 + +varying vec4 passColour; +varying vec3 passPosition; +uniform sampler2D textureIn; + +uniform float amount; + +//Algorithm by sam hocevar +vec3 rgb2hsv(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +//Algorithm by hughsk +vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +void main() { + vec4 texture = texture2D(textureIn, gl_TexCoord[0].st); + + vec3 hsv = rgb2hsv(texture.rgb); + + float hue = mod(hsv.x + amount + passPosition.x*4.0f, 1.0f); + float sat = hsv.y*0.7f; + float val = hsv.z; + vec3 fade = hsv2rgb(vec3(hue, sat, val)); + + gl_FragColor = vec4(fade.rgb, texture.a); +} diff --git a/src/main/resources/assets/notenoughupdates/shaders/make_gold.vert b/src/main/resources/assets/notenoughupdates/shaders/make_gold.vert new file mode 100644 index 00000000..40a9d08a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/make_gold.vert @@ -0,0 +1,13 @@ +#version 120 + +varying vec4 passColour; +varying vec3 passPosition; + +void main() { + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; + + passPosition = gl_Position.xyz; + + passColour = gl_Color; +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/shaders/mcworld_cape.frag b/src/main/resources/assets/notenoughupdates/shaders/mcworld_cape.frag new file mode 100644 index 00000000..1dc5e1c8 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/mcworld_cape.frag @@ -0,0 +1,129 @@ +#version 120 + +varying vec4 passColour; +varying vec3 passNormal; +uniform sampler2D textureIn; + +uniform int millis; + +//Algorithm by hughsk +vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +vec3 rgb2hsv(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +void main() { + vec4 texture = texture2D(textureIn, gl_TexCoord[0].st); + + float t = gl_TexCoord[0].t; + t = clamp(t, 10.0f/1024.0f, 410.0f/1024.0f); + + float start = 56.0f - 44.0f*t/(420.0f/1024.0f); + float width = 182.0f + 90.0f*t/(420.0f/1024.0f); + float scaleFactor = 1.0f/(width/1024.0f)*112.0f; + + float index = mod(millis/20.0f+t*scaleFactor, 2820.0f); + float yIndex = floor(index/1024.0f)*112.0f-(gl_TexCoord[0].s-start/1024.0f)*scaleFactor+532.0f; + float xIndex = mod(index, 1024.0f); + vec3 world = texture2D(textureIn, vec2(xIndex/1024.0f, yIndex/1024.0f)).xyz; + + float hue = 0.0f; + float saturation = 1.0f; + float value = 1.0f; + if(index < 208) { //sky + float blurFactor = clamp((index-158)/100.0f, 0.0f, 0.5f); + + hue = 200.0f; + saturation = 1.0f - blurFactor; + value = 0.9f - 0.6f*blurFactor; + } else if(index < 800) { //underground + if(index < 400) { + float blurFactor = clamp((258-index)/100.0f, 0.0f, 0.5f); + + hue = 200.0f; + saturation = 0.0f + blurFactor; + value = 0.3f + 0.6f*blurFactor; + } else { + float blurFactor = clamp((index-750)/100.0f, 0.0f, 0.5f); + + hue = 350.0f; + saturation = 0.0f + 0.5f*blurFactor; + value = 0.3f - 0.1f*blurFactor; + } + } else if(index < 1762) { //nether + if(index < 1200) { + float blurFactor = clamp((850-index)/100.0f, 0.0f, 0.5f); + + hue = 350.0f; + saturation = 0.5f - 0.5f*blurFactor; + value = 0.2f + 0.1f*blurFactor; + } else { + float blurFactor = clamp((index-1712)/100.0f, 0.0f, 0.5f); + + hue = 350.0f; + saturation = 0.5f - 0.5f*blurFactor; + value = 0.2f + 0.1f*blurFactor; + } + } else if(index < 2200) { //underground + if(index < 1900) { + float blurFactor = clamp((1812-index)/100.0f, 0.0f, 0.5f); + + hue = 350.0f; + saturation = 0.0f + 0.5f*blurFactor; + value = 0.3f - 0.1f*blurFactor; + } else { + float blurFactor = clamp((index-2150)/100.0f, 0.0f, 0.5f); + + hue = 0.0f; + saturation = 0.0f; + value = 0.3f - 0.3f*blurFactor; + } + } else if(index < 2600) { //end + if(index < 2400) { + float blurFactor = clamp((2250-index)/100.0f, 0.0f, 0.5f); + + hue = 0.0f; + saturation = 0.0f; + value = 0.0f + 0.3f*blurFactor; + } else { + float blurFactor = clamp((index-2550)/100.0f, 0.0f, 0.5f); + + hue = 200.0f; + saturation = 0.0f + blurFactor; + value = 0.0f + 0.9f*blurFactor; + } + } else { //sky + float blurFactor = clamp((2650-index)/100.0f, 0.0f, 0.5f); + + hue = 200.0f; + saturation = 1.0f - blurFactor; + value = 0.9f - 0.9f*blurFactor; + } + hue = mod(hue, 360.0f); + saturation = max(0.0f, min(1.0f, saturation)); + value = max(0.0f, min(1.0f, value)); + + vec3 hsv = rgb2hsv(texture.rgb); + hsv.x = hue/360.0f; + hsv.y *= saturation; + hsv.z *= value; + + gl_FragColor = vec4(hsv2rgb(hsv)*texture.a + world*(1.0f-texture.a), 1.0f) * passColour; + + vec3 fakeSunNormal = normalize(vec3(0.2f,1.0f,-0.2f)); + vec3 normNormal = normalize(passNormal); + float shading = max(0.6f, dot(fakeSunNormal, normNormal)); + + gl_FragColor = vec4(gl_FragColor.rgb*shading, gl_FragColor.a); +} diff --git a/src/main/resources/assets/notenoughupdates/shaders/mcworld_cape.vert b/src/main/resources/assets/notenoughupdates/shaders/mcworld_cape.vert new file mode 100644 index 00000000..2b5c48f8 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/mcworld_cape.vert @@ -0,0 +1,12 @@ +#version 120 + +varying vec4 passColour; +varying vec3 passNormal; + +void main() { + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; + + passColour = gl_Color; + passNormal = normalize(gl_Normal); +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/blur.json b/src/main/resources/assets/notenoughupdates/shaders/program/blur.json new file mode 100644 index 00000000..9da3c2e8 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/program/blur.json @@ -0,0 +1,21 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha" + }, + "vertex": "sobel", + "fragment": "blur2", + "attributes": [ "Position" ], + "samplers": [ + { "name": "DiffuseSampler" } + ], + "uniforms": [ + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "InSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "BlurDir", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "Radius", "type": "float", "count": 1, "values": [ 5.0 ] }, + { "name": "AlphaMult", "type": "float", "count": 1, "values": [ 1.0 ] } + ] +} diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/blur2.fsh b/src/main/resources/assets/notenoughupdates/shaders/program/blur2.fsh new file mode 100644 index 00000000..ca64470a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/program/blur2.fsh @@ -0,0 +1,34 @@ +#version 120 + +uniform sampler2D DiffuseSampler; + +varying vec2 texCoord; +varying vec2 oneTexel; + +uniform vec2 InSize; + +uniform vec2 BlurDir; +uniform float Radius; +uniform float AlphaMult; + +void main() { + vec4 blurred = vec4(0.0); + float totalStrength = 0.0; + float totalAlpha = 0.0; + float totalSamples = 0.0; + for(float r = -Radius; r <= Radius; r += 1.0) { + vec4 sample = texture2D(DiffuseSampler, texCoord + oneTexel * r * BlurDir); + + // Accumulate average alpha + totalAlpha = totalAlpha + sample.a; + totalSamples = totalSamples + 1.0; + + // Accumulate smoothed blur + //float strength = (2.0 - abs(r / Radius))*sample.a; + float strength = sample.a; + totalStrength = totalStrength + strength; + blurred = blurred + sample; + } + float alpha = totalAlpha/totalSamples*AlphaMult; + gl_FragColor = vec4(blurred.rgb / totalStrength, alpha); +} diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.fsh b/src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.fsh new file mode 100644 index 00000000..c7bcfb0f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.fsh @@ -0,0 +1,32 @@ +#version 120 + +uniform sampler2D DiffuseSampler; + +uniform float radiusSq = 0.5f; + +uniform vec2 InSize; +uniform vec2 OutSize; + +varying vec2 texCoord; + +void main() { + if(radiusSq < 0.5 && (texCoord.s-0.5)*(texCoord.s-0.5)+(texCoord.t-0.5)*(texCoord.t-0.5) > radiusSq) { + discard; + } + + /*float totalAlpha = 0.0f; + vec3 accum = vec3(0.0); + + for(int x = -1; x<3; x++) { + for(int y = -1; y<3; y++) { + vec4 pixel = texture2D(DiffuseSampler, texCoord+vec2(x, y)/InSize); + + accum += pixel.rgb * pixel.a; + totalAlpha += pixel.a; + } + } + gl_FragColor.a = totalAlpha/4*4; + gl_FragColor.rgb = accum/4*4;*/ + + gl_FragColor = texture2D(DiffuseSampler, texCoord); +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.json b/src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.json new file mode 100644 index 00000000..bb41ffd5 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.json @@ -0,0 +1,19 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha" + }, + "vertex": "dungeonmap", + "fragment": "dungeonmap", + "attributes": [ "Position" ], + "samplers": [ + { "name": "DiffuseSampler" } + ], + "uniforms": [ + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "InSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "radiusSq", "type": "float", "count": 1, "values": [ 1.0 ] } + ] +} diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.vsh b/src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.vsh new file mode 100644 index 00000000..01a16db5 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.vsh @@ -0,0 +1,16 @@ +#version 120 + +attribute vec4 Position; + +uniform mat4 ProjMat; +uniform vec2 OutSize; + +varying vec2 texCoord; + +void main(){ + vec4 outPos = ProjMat * vec4(Position.xy, 0.0, 1.0); + gl_Position = vec4(outPos.xy, 0.2, 1.0); + + texCoord = Position.xy / OutSize; + texCoord.y = 1.0 - texCoord.y; +} diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/setrgbtoalpha.fsh b/src/main/resources/assets/notenoughupdates/shaders/program/setrgbtoalpha.fsh new file mode 100644 index 00000000..324602fd --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/program/setrgbtoalpha.fsh @@ -0,0 +1,11 @@ +#version 120 + +uniform sampler2D DiffuseSampler; + +varying vec2 texCoord; + +void main(){ + vec4 diffuseColor = texture2D(DiffuseSampler, texCoord); + + gl_FragColor = vec4(diffuseColor.a); +} diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/setrgbtoalpha.json b/src/main/resources/assets/notenoughupdates/shaders/program/setrgbtoalpha.json new file mode 100644 index 00000000..653764fb --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/program/setrgbtoalpha.json @@ -0,0 +1,17 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha" + }, + "vertex": "blit", + "fragment": "setrgbtoalpha", + "attributes": [ "Position" ], + "samplers": [ + { "name": "DiffuseSampler" } + ], + "uniforms": [ + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] } + ] +} diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/sobel.vsh b/src/main/resources/assets/notenoughupdates/shaders/program/sobel.vsh new file mode 100644 index 00000000..21b17369 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/program/sobel.vsh @@ -0,0 +1,20 @@ +#version 120 + +attribute vec4 Position; + +uniform mat4 ProjMat; +uniform vec2 InSize; +uniform vec2 OutSize; + +varying vec2 texCoord; +varying vec2 oneTexel; + +void main(){ + vec4 outPos = ProjMat * vec4(Position.xy, 0.0, 1.0); + gl_Position = vec4(outPos.xy, 0.2, 1.0); + + oneTexel = 1.0 / InSize; + + texCoord = Position.xy / OutSize; + texCoord.y = 1.0 - texCoord.y; +} diff --git a/src/main/resources/assets/notenoughupdates/shaders/space_cape.frag b/src/main/resources/assets/notenoughupdates/shaders/space_cape.frag new file mode 100644 index 00000000..e3e5d56e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/space_cape.frag @@ -0,0 +1,60 @@ +#version 120 + +varying vec4 passColour; +varying vec3 passNormal; +uniform sampler2D textureIn; + +uniform int millis; +uniform int eventMillis; +uniform float eventRand; //0-1 + +void main() { + vec4 texture = texture2D(textureIn, gl_TexCoord[0].st); + + vec2 texCoord = gl_TexCoord[0].st + vec2(mod(millis/100.0f,1024.0f)/1024.0f, 421.0f/1024.0f); + + vec4 extra = vec4(0,0,0,0); + if(eventRand < 0.4f) { + vec2 extraPos = vec2(45.0f+eventRand/0.4f*250.0f, eventMillis/300.0f*550.0f)/1024.0f; + vec2 extraTexCoord = vec2(48.0f/1024.0f-(gl_TexCoord[0].t-extraPos.y), gl_TexCoord[0].s-extraPos.x+894.0f/1024.0f); + if(extraTexCoord.x > 0.0f && extraTexCoord.x < 200.0f/1024.0f) { + if(extraTexCoord.y > 843.0f/1024.0f && extraTexCoord.y < 943.0f/1024.0f) { + extra = texture2D(textureIn, extraTexCoord); + } + } + } else if(eventRand < 0.45f) { + vec2 extraPos = vec2(-30.0f+eventMillis/2000.0f*370.0f, 50.0f+(eventRand-0.4f)/0.05f*300.0f)/1024.0f; + vec2 extraTexCoord = vec2(gl_TexCoord[0].s-extraPos.x+248.0f/1024.0f, gl_TexCoord[0].t-extraPos.y+894.0f/1024.0f); + if(extraTexCoord.x > 200.0f/1024.0f && extraTexCoord.x < 300.0f/1024.0f) { + if(extraTexCoord.y > 843.0f/1024.0f && extraTexCoord.y < 943.0f/1024.0f) { + extra = texture2D(textureIn, extraTexCoord); + } + } + } else if(eventRand < 0.47f) { + vec2 extraPos = vec2(-30.0f+eventMillis/2000.0f*370.0f, 50.0f+(eventRand-0.45f)/0.02f*300.0f)/1024.0f; + vec2 extraTexCoord = vec2(gl_TexCoord[0].s-extraPos.x+348.0f/1024.0f, gl_TexCoord[0].t-extraPos.y+894.0f/1024.0f); + if(extraTexCoord.x > 300.0f/1024.0f && extraTexCoord.x < 400.0f/1024.0f) { + if(extraTexCoord.y > 843.0f/1024.0f && extraTexCoord.y < 943.0f/1024.0f) { + extra = texture2D(textureIn, extraTexCoord); + } + } + } else if(eventRand < 0.48f) { + vec2 extraPos = vec2(-30.0f+eventMillis/2000.0f*370.0f, 50.0f+(eventRand-0.47f)/0.01f*300.0f)/1024.0f; + vec2 extraTexCoord = vec2(gl_TexCoord[0].s-extraPos.x+448.0f/1024.0f, gl_TexCoord[0].t-extraPos.y+894.0f/1024.0f); + if(extraTexCoord.x > 400.0f/1024.0f && extraTexCoord.x < 500.0f/1024.0f) { + if(extraTexCoord.y > 843.0f/1024.0f && extraTexCoord.y < 943.0f/1024.0f) { + extra = texture2D(textureIn, extraTexCoord); + } + } + } + + vec3 space = texture2D(textureIn, texCoord).rgb; + + gl_FragColor = vec4(texture.rgb*texture.a + extra.rgb*extra.a*(1.0f-texture.a) + space*(1.0f-texture.a)*(1.0f-extra.a), 1.0f) * passColour; + + vec3 fakeSunNormal = normalize(vec3(0.2f,1.0f,-0.2f)); + vec3 normNormal = normalize(passNormal); + float shading = max(0.6f, dot(fakeSunNormal, normNormal)); + + gl_FragColor = vec4(gl_FragColor.rgb*shading, gl_FragColor.a); +} diff --git a/src/main/resources/assets/notenoughupdates/shaders/space_cape.vert b/src/main/resources/assets/notenoughupdates/shaders/space_cape.vert new file mode 100644 index 00000000..2b5c48f8 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/shaders/space_cape.vert @@ -0,0 +1,12 @@ +#version 120 + +varying vec4 passColour; +varying vec3 passNormal; + +void main() { + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; + + passColour = gl_Color; + passNormal = normalize(gl_Normal); +}
\ No newline at end of file diff --git a/src/main/resources/assets/notenoughupdates/ss_border.jpg b/src/main/resources/assets/notenoughupdates/ss_border.jpg Binary files differnew file mode 100644 index 00000000..28c1019f --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_border.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss1-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss1-0.jpg Binary files differnew file mode 100644 index 00000000..d05faab2 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss1-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss10-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss10-0.jpg Binary files differnew file mode 100644 index 00000000..a3bbae70 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss10-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss11-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss11-0.jpg Binary files differnew file mode 100644 index 00000000..071a5df1 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss11-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss12-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss12-0.jpg Binary files differnew file mode 100644 index 00000000..447459cc --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss12-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss13-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss13-0.jpg Binary files differnew file mode 100644 index 00000000..88a89ae2 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss13-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss14-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss14-0.jpg Binary files differnew file mode 100644 index 00000000..a83e64fa --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss14-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss15-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss15-0.jpg Binary files differnew file mode 100644 index 00000000..3d34bc43 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss15-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss16-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss16-0.jpg Binary files differnew file mode 100644 index 00000000..9827eec2 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss16-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss17-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss17-0.jpg Binary files differnew file mode 100644 index 00000000..560b1d9a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss17-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss18-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss18-0.jpg Binary files differnew file mode 100644 index 00000000..6322f89d --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss18-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss2-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss2-0.jpg Binary files differnew file mode 100644 index 00000000..ba71a84e --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss2-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss3-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss3-0.jpg Binary files differnew file mode 100644 index 00000000..7b179fcc --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss3-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss4-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss4-0.jpg Binary files differnew file mode 100644 index 00000000..c8ee048c --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss4-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss5-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss5-0.jpg Binary files differnew file mode 100644 index 00000000..4435fd97 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss5-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss6-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss6-0.jpg Binary files differnew file mode 100644 index 00000000..c027edbc --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss6-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss7-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss7-0.jpg Binary files differnew file mode 100644 index 00000000..47dffef2 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss7-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss8-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss8-0.jpg Binary files differnew file mode 100644 index 00000000..fe4ae1bb --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss8-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/ss_small/ss9-0.jpg b/src/main/resources/assets/notenoughupdates/ss_small/ss9-0.jpg Binary files differnew file mode 100644 index 00000000..d06c092a --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/ss_small/ss9-0.jpg diff --git a/src/main/resources/assets/notenoughupdates/supersecretassets/bald.png b/src/main/resources/assets/notenoughupdates/supersecretassets/bald.png Binary files differnew file mode 100644 index 00000000..4f730a44 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/supersecretassets/bald.png diff --git a/src/main/resources/assets/notenoughupdates/wkhtmltox.zip b/src/main/resources/assets/notenoughupdates/wkhtmltox.zip Binary files differindex 5717aeaf..88e17154 100644 --- a/src/main/resources/assets/notenoughupdates/wkhtmltox.zip +++ b/src/main/resources/assets/notenoughupdates/wkhtmltox.zip diff --git a/src/main/resources/mixins.notenoughupdates.json b/src/main/resources/mixins.notenoughupdates.json index 49e37916..a90fbb8d 100644 --- a/src/main/resources/mixins.notenoughupdates.json +++ b/src/main/resources/mixins.notenoughupdates.json @@ -5,6 +5,18 @@ "mixins": [ "MixinItemStack", "MixinInventoryEffectRenderer", - "MixinGuiIngame" + "MixinGuiIngame", + "MixinRenderItem", + "MixinEntityRenderer", + "MixinRenderGlobal", + "MixinNetHandlerPlayClient", + "MixinGuiChest", + "MixinGuiContainer", + "MixinVboRenderList", + "MixinRenderList", + "MixinEntityPlayer", + "MixinTileEntitySpecialRenderer", + "MixinRender", + "MixinRenderFish" ] }
\ No newline at end of file |