diff options
author | Moulberry <james.jenour@student.scotch.wa.edu.au> | 2020-11-08 17:44:27 +1100 |
---|---|---|
committer | Moulberry <james.jenour@student.scotch.wa.edu.au> | 2020-11-08 17:44:27 +1100 |
commit | 07403ec86c53f67b94d988b4c01a0afc2fdb2810 (patch) | |
tree | fba4b3c37b02c42267e03a07453d3941c98fd66d | |
parent | fc4143dd3c892b11ae5f427fcecc22044ff98460 (diff) | |
parent | ec0660e41145d3d9ed479b3e697afddf8ddc8c4c (diff) | |
download | NotEnoughUpdates-07403ec86c53f67b94d988b4c01a0afc2fdb2810.tar.gz NotEnoughUpdates-07403ec86c53f67b94d988b4c01a0afc2fdb2810.tar.bz2 NotEnoughUpdates-07403ec86c53f67b94d988b4c01a0afc2fdb2810.zip |
uh yeah its pretty necessary guys
422 files changed, 38536 insertions, 3178 deletions
@@ -1,21 +1,60 @@ -MIT License - -Copyright (c) 2020 Moulberry - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. + +1. Definitions + + "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. + "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. + "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. + "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. + "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. + "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. + "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. + "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. + "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: + + to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; + to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; + to Distribute and Publicly Perform the Work including as incorporated in Collections; and, + to Distribute and Publicly Perform Adaptations. + +The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights set forth in Section 4(d). + +4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: + + You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested. + You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in connection with the exchange of copyrighted works. + If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. + + For the avoidance of doubt: + Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; + Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and, + Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c). + Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. + Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. + +8. Miscellaneous + + Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. + Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. + If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. + This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. + The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. diff --git a/build.gradle b/build.gradle index 29128fba..cc403b6d 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ apply plugin: 'com.github.johnrengelman.shadow' sourceCompatibility = 1.8 targetCompatibility = 1.8 -version = "1.0" +version = "1.5-REL" group= "io.github.moulberry" archivesBaseName = "NotEnoughUpdates" String modid = "notenoughupdates" @@ -34,13 +34,18 @@ minecraft { repositories { jcenter() maven { url 'https://repo.spongepowered.org/maven/' } + flatDir { + dirs 'deps' + } } dependencies { compile('org.spongepowered:mixin:0.7.11-SNAPSHOT') - compile('org.kohsuke:github-api:1.108') + //compile('org.kohsuke:github-api:1.108') + //compile('org.eclipse.jgit:org.eclipse.jgit:5.7.0.202003110725-r') compile('com.fasterxml.jackson.core:jackson-core:2.10.2') compile('info.bliki.wiki:bliki-core:3.1.0') + implementation name: 'Morus-1.0' } mixin { @@ -49,6 +54,7 @@ mixin { jar { manifest.attributes( + 'Main-Class': 'NotSkyblockAddonsInstallerFrame', 'TweakClass': 'org.spongepowered.asm.launch.MixinTweaker', 'MixinConfigs': "mixins.${modid}.json", 'FMLCorePluginContainsFMLMod': true, @@ -58,7 +64,8 @@ jar { shadowJar { dependencies { - include(dependency('org.kohsuke:github-api:1.108')) + //include(dependency('org.kohsuke:github-api:1.108')) + //include(dependency('org.eclipse.jgit:org.eclipse.jgit:5.7.0.202003110725-r')) include(dependency('org.spongepowered:mixin:0.7.11-SNAPSHOT')) include(dependency('commons-io:commons-io')) @@ -73,6 +80,7 @@ shadowJar { } relocate 'com.fasterxml.jackson', 'neu.com.fasterxml.jackson' + relocate 'org.eclipse', 'neu.org.eclipse' relocate 'org.slf4j', 'neu.org.slf4j' exclude 'module-info.class' 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 |