[
  {
    "path": ".github/workflows/build.yml",
    "content": "# This workflow will build a Java project with Gradle\n# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle\nname: Compile Beta\n\non:\n  push:\n    branches: [ development ]\n  pull_request:\n    branches: [ development ]\n\njobs:\n  build:\n   runs-on: windows-latest\n   steps:\n    - uses: actions/checkout@v2\n    - uses: actions/setup-java@v1\n      with: \n        java-version: 17\n    - name: Cache Gradle packages\n      uses: actions/cache@v2\n      with:\n        path: |\n          ~/.gradle/caches\n          ~/.gradle/wrapper\n        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle', '**/gradle-wrapper.properties') }}\n        restore-keys: ${{ runner.os }}-gradle\n    - run: ./gradlew build --no-daemon\n    - name: Upload\n      uses: actions/upload-artifact@v2\n      with:\n       name: Beta Version (Unstable)\n       path: |\n         versions/1.8.9-forge/build/libs/*.jar\n         !versions/1.8.9-forge/build/libs/*-dev.jar"
  },
  {
    "path": ".gitignore",
    "content": "# eclipse\nbin\n*.launch\n.settings\n.metadata\n.classpath\n.project\n\n# idea\nout\n*.ipr\n*.iws\n*.iml\n.idea\n\n# gradle\nbuild\n.gradle\n\n# other\neclipse\nrun\n*.txt\n*.cfg\n*.gz\n*.log\n*.dat\n*.mca\n*.json\n*.dat_mcr\n*.lock\n*.dat_old\n"
  },
  {
    "path": "COPYING",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\n"
  },
  {
    "path": "COPYING.LESSER",
    "content": "                   GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\n  This version of the GNU Lesser General Public License incorporates\nthe terms and conditions of version 3 of the GNU General Public\nLicense, supplemented by the additional permissions listed below.\n\n  0. Additional Definitions.\n\n  As used herein, \"this License\" refers to version 3 of the GNU Lesser\nGeneral Public License, and the \"GNU GPL\" refers to version 3 of the GNU\nGeneral Public License.\n\n  \"The Library\" refers to a covered work governed by this License,\nother than an Application or a Combined Work as defined below.\n\n  An \"Application\" is any work that makes use of an interface provided\nby the Library, but which is not otherwise based on the Library.\nDefining a subclass of a class defined by the Library is deemed a mode\nof using an interface provided by the Library.\n\n  A \"Combined Work\" is a work produced by combining or linking an\nApplication with the Library.  The particular version of the Library\nwith which the Combined Work was made is also called the \"Linked\nVersion\".\n\n  The \"Minimal Corresponding Source\" for a Combined Work means the\nCorresponding Source for the Combined Work, excluding any source code\nfor portions of the Combined Work that, considered in isolation, are\nbased on the Application, and not on the Linked Version.\n\n  The \"Corresponding Application Code\" for a Combined Work means the\nobject code and/or source code for the Application, including any data\nand utility programs needed for reproducing the Combined Work from the\nApplication, but excluding the System Libraries of the Combined Work.\n\n  1. Exception to Section 3 of the GNU GPL.\n\n  You may convey a covered work under sections 3 and 4 of this License\nwithout being bound by section 3 of the GNU GPL.\n\n  2. Conveying Modified Versions.\n\n  If you modify a copy of the Library, and, in your modifications, a\nfacility refers to a function or data to be supplied by an Application\nthat uses the facility (other than as an argument passed when the\nfacility is invoked), then you may convey a copy of the modified\nversion:\n\n   a) under this License, provided that you make a good faith effort to\n   ensure that, in the event an Application does not supply the\n   function or data, the facility still operates, and performs\n   whatever part of its purpose remains meaningful, or\n\n   b) under the GNU GPL, with none of the additional permissions of\n   this License applicable to that copy.\n\n  3. Object Code Incorporating Material from Library Header Files.\n\n  The object code form of an Application may incorporate material from\na header file that is part of the Library.  You may convey such object\ncode under terms of your choice, provided that, if the incorporated\nmaterial is not limited to numerical parameters, data structure\nlayouts and accessors, or small macros, inline functions and templates\n(ten or fewer lines in length), you do both of the following:\n\n   a) Give prominent notice with each copy of the object code that the\n   Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the object code with a copy of the GNU GPL and this license\n   document.\n\n  4. Combined Works.\n\n  You may convey a Combined Work under terms of your choice that,\ntaken together, effectively do not restrict modification of the\nportions of the Library contained in the Combined Work and reverse\nengineering for debugging such modifications, if you also do each of\nthe following:\n\n   a) Give prominent notice with each copy of the Combined Work that\n   the Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the Combined Work with a copy of the GNU GPL and this license\n   document.\n\n   c) For a Combined Work that displays copyright notices during\n   execution, include the copyright notice for the Library among\n   these notices, as well as a reference directing the user to the\n   copies of the GNU GPL and this license document.\n\n   d) Do one of the following:\n\n       0) Convey the Minimal Corresponding Source under the terms of this\n       License, and the Corresponding Application Code in a form\n       suitable for, and under terms that permit, the user to\n       recombine or relink the Application with a modified version of\n       the Linked Version to produce a modified Combined Work, in the\n       manner specified by section 6 of the GNU GPL for conveying\n       Corresponding Source.\n\n       1) Use a suitable shared library mechanism for linking with the\n       Library.  A suitable mechanism is one that (a) uses at run time\n       a copy of the Library already present on the user's computer\n       system, and (b) will operate properly with a modified version\n       of the Library that is interface-compatible with the Linked\n       Version.\n\n   e) Provide Installation Information, but only if you would otherwise\n   be required to provide such information under section 6 of the\n   GNU GPL, and only to the extent that such information is\n   necessary to install and execute a modified version of the\n   Combined Work produced by recombining or relinking the\n   Application with a modified version of the Linked Version. (If\n   you use option 4d0, the Installation Information must accompany\n   the Minimal Corresponding Source and Corresponding Application\n   Code. If you use option 4d1, you must provide the Installation\n   Information in the manner specified by section 6 of the GNU GPL\n   for conveying Corresponding Source.)\n\n  5. Combined Libraries.\n\n  You may place library facilities that are a work based on the\nLibrary side by side in a single library together with other library\nfacilities that are not Applications and are not covered by this\nLicense, and convey such a combined library under terms of your\nchoice, if you do both of the following:\n\n   a) Accompany the combined library with a copy of the same work based\n   on the Library, uncombined with any other library facilities,\n   conveyed under the terms of this License.\n\n   b) Give prominent notice with the combined library that part of it\n   is a work based on the Library, and explaining where to find the\n   accompanying uncombined form of the same work.\n\n  6. Revised Versions of the GNU Lesser General Public License.\n\n  The Free Software Foundation may publish revised and/or new versions\nof the GNU Lesser General Public License from time to time. Such new\nversions will be similar in spirit to the present version, but may\ndiffer in detail to address new problems or concerns.\n\n  Each version is given a distinguishing version number. If the\nLibrary as you received it specifies that a certain numbered version\nof the GNU Lesser General Public License \"or any later version\"\napplies to it, you have the option of following the terms and\nconditions either of that published version or of any later version\npublished by the Free Software Foundation. If the Library as you\nreceived it does not specify a version number of the GNU Lesser\nGeneral Public License, you may choose any version of the GNU Lesser\nGeneral Public License ever published by the Free Software Foundation.\n\n  If the Library as you received it specifies that a proxy can decide\nwhether future versions of the GNU Lesser General Public License shall\napply, that proxy's public statement of acceptance of any version is\npermanent authorization for you to choose that version for the\nLibrary."
  },
  {
    "path": "README.md",
    "content": "# Danker's Skyblock Mod\nQOL changes that enhances your Hypixel Skyblock experience. Created to add features I couldn't find in a mod, or if the mod was paid (which is against the [Mojang TOS](https://account.mojang.com/documents/commercial_guidelines)).\n\nDiscord Server: https://discord.gg/QsEkNQS\n\nModrinth Link: https://modrinth.com/mod/dankers-skyblock-mod\n\n<details>\n<summary>Incompatibilites</summary>\n\n## Incompatibilities\n- Old Animations <2.6.4 - Frequent crashes\n- Old Animations 2.6.4\n  - Pet colors does not color slots\n  - Catacombs F7 terminal solvers do not color slots\n  - Enchanting solvers do not color slots\n- Old tab display\n  - Many features rely on using the location found in the new tab display\n</details>\n\n<details>\n<summary>Current Features</summary>\n\n## Current Features\n- Guild party desktop notifications\n- Coordinate and angle display\n- Golden T10/T6/T4 enchant display\n- Disable Spirit Sceptre messages\n- Disable Midas Staff messages\n- Disable Implosion messages\n- Disable heal messages\n- Disable ability cooldown messages\n- Disable out of mana messages\n- Disable kill combo messages\n- Slayer item tracker\n- Ghosts item tracker  \n- RNGesus drop alerts\n- Click anywhere on-screen to open Maddox\n- Maddox menu keybind\n- Block starting other slayer quests\n- Slayer slain alert\n- Fishing, jerry fishing, fishing festival, spooky fishing, crystal hollows fishing, lava fishing, trophy fishing trackers\n- Expertise kills in fishing rod lore\n- Gemstones applied in item lore\n- Catacombs trackers\n- Dungeons puzzle solver (Riddle, trivia, blaze, creeper, water, tic tac toe, boulder, silverfish, ice walk)\n- Dungeons timer (similar to LiveSplit)\n- Misc. dungeon info\n- Watcher ready message\n- Catacombs F7 Stage 3 solvers (Starts with letter, select all colour, ignore arrows on sea lanterns)\n- Find correct Livid (with graphic display of HP)\n- Catacombs F6 and F7 Giant HP display\n- Use custom music in supported locations\n- Experimentation solvers (Ultrasequencer, Chronomatron, Superpairs)\n- Hide tooltips in experiment addons\n- Hide tooltips in Melody's Harp\n- Pet background colors based on level\n- Golem spawning alerts + 20 second timer\n- Skill xp/hour tracker\n- Show total skill xp instead of progress to next level\n- Show time until century cakes run out\n- Mythological event (Diana) tracker\n- Low health alert in dungeons\n- API commands\n- Update checker\n- Reparty command\n- Auto accept reparty\n- Highlight Slayer Bosses\n- Highlight Arachne\n- Highlight Skeleton Masters\n- Show teammates in 30 block radius\n- Hide pet candy in pet tooltip\n- Highlighting completed commissions\n- Custom name colors\n- Crystal Hollows waypoints (with SkyblockExtras support)\n- Ability cooldowns display\n- Custom alerts based on chat\n- Predicted dungeon score display\n- Hide player armour\n- Automatically join skyblock\n- Fire pillar display\n- Chat aliases\n- Thunder/Lord Jawbus spawn alerts\n- Show when minion was last collected\n- Show amount of Magmafish if trophy fish are filleted\n- Show estimated time until bazaar order is filled\n- Show timer until Crimson Isle minibosses respawn\n- Automatically announce Vanquishers in chat\n- Kuudra notifications (stun/ballista/cloak)\n- Powder/hour tracker\n- Fix drill animation resetting\n- Highlight filled bazaar orders\n- Dungeon RNG meter info display\n- Optimize mining route\n</details>\n\n<details>\n<summary>Commands</summary>\n\n## Commands\n- /dhelp - Returns this message in-game.\n- /dsm - Opens the GUI for Danker's Skyblock Mod.\n- /loot <zombie/spider/wolf/enderman/blaze/vampire/fishing/catacombs/mythological/> [winter/festival/spooky/ch/lava/trophy/f(1-7)/mm/session] - Returns loot received from slayer quests or fishing stats. /loot fishing winter returns winter sea creatures instead.\n- /display <zombie/spider/wolf/enderman/blaze/vampire/fishing/catacombs/mythological/ghosts/auto/off> [winter/festival/spooky/ch/lava/trophy/f(1-7)/mm/session] - Text display for trackers. /display fishing winter displays winter sea creatures instead. /display auto automatically displays the loot for the slayer quest you have active.\n- /resetloot <zombie/spider/wolf/enderman/blaze/vampire/fishing/catacombs/mythological/confirm/cancel> -  - Resets loot for trackers. /resetloot confirm confirms the reset.\n- /slayer [player] - Uses API to get slayer xp of a person. If no name is provided, it checks yours.\n- /skill [player] - Uses API to get skill levels of a person. If no name is provided, it checks yours.\n- /lobbyskills - Uses API to find the average skills of the lobby, as well the three players with the highest skill average.\n- /guildof [player] - Uses API to get guild name and guild master of a person. If no name is provided, it checks yours.\n- /petsof [player] - Uses API to get pets of a person. If no name is provided, it checks yours.\n- /bank [player] - Uses API to get bank and purse coins of a person. If no name is provided, it checks yours.\n- /armor [player] - Uses API to get armor of a person. If no name is provided, it checks yours.\n- /dungeons [player] - Uses API to get dungeon levels of a person. If no name is provided, it checks yours.\n- /weight [player] [lily/farming] - Uses API to get weight of a person. If no name is provided, it checks yours. Adding lily uses lily's weight. Adding farming uses Kaeso's farming weight.\n- /importfishing - Imports your fishing stats from your latest profile to your fishing tracker using the API.\n- /sbplayers - Uses API to find how many players are on each Skyblock island.\n- /reparty - Disbands and reparties all members in the party\n- /fairysouls - Check the fairysouls of a player\n- /skilltracker <start/stop/reset> - Text display for skill xp/hour.\n- /lobbybank - Uses API to find the average bank total of the lobby, as well the three players with the highest total money in the bank (and purse).\n- /player [player] - Uses API to find skills, slayers, coins and weight of a player.\n- /reloadconfig - Reloads Danker's Skyblock Mod config.\n- /reloaddsmrepo - Reloads Danker's Skyblock Mod repository.\n- /hotmof [player] - Uses API to find total powder and HotM tree of a person. If no name is provided, it checks yours.\n- /trophyfish [player] - Uses API to find trophy fish stats of a person. If no name is provided, it checks yours.\n- /stoplobby - Stops currently running /lobbyskills or /lobbybank command.\n- /powdertracker <start/stop/reset> - Text display for powder/hour.\n</details>\n\n<details>\n<summary>Keybinds</summary>\n\n## Keybinds\n- Open Maddox menu - M by default.\n- Regular Ability - Numpad 4 by default.\n- Start/Stop Skill Tracker - Numpad 5 by default.\n- Create Waypoint - Numpad 6 by default.\n- Start/Stop Powder Tracker - Numpad 8 by default.\n- Disable Mouse Movement - None by default.\n- Disable Moving Forwards/Back - None by default.\n- Disable Moving Left/Right - None by default.\n</details>\n\n<details>\n<summary>Warps</summary>\n\n## Warps\nShortcut commands that save you the time of typing the whole warp command.\n- /deep - Warps you to the Deep Caverns.\n- /nether - Warps you to the Crimson Isle.\n- /isle - Warps you to the Crimson Isle.\n- /crimson - Warps you to the Crimson Isle.\n- /mines - Warps you to the Dwarven Mines.\n- /forge - Warps you to the Dwarven Forge.\n- /crystals - Warps you to the Crystal Hollows.\n- /gold - Warps you to the Gold Mine.\n- /desert - Warps you to the Desert.\n- /spider - Warps you to the Spiders Den.\n- /barn - Warps you to the Barn.\n- /end - Warps you to the End.\n- /park - Warps you to the Park.\n- /castle - Warps you to the Hub Castle.\n- /da - Warps you to the Dark Auction.\n- /crypt - Warps you to the Crypt in the Hub.\n- /nest - Warps you to the top of the Spider's Den.\n- /void - Warps you to the Void Sepulture in the End.\n- /drag - Warps you to the Dragons Nest in the End.\n- /jungle - Warps you to the Jungle.\n- /howl - Warps you to the Howling Cave in the Park.\n- /dun - Warps you to the Dungeon Hub.\n</details>\n\n<details>\n<summary>Custom Music</summary>\n\n## Custom Music\n1. Place a music file with the given name in the `.minecraft/config/dsmmusic` folder:\n  - Dungeon: `dungeon.wav`\n  - Blood room: `bloodroom.wav`\n  - Dungeon boss: `dungeonboss.wav`\n  - Dungeon hub: `dungeonhub.wav`\n  - F7 Phase 2 (Storm): `phasetwo.wav`\n  - F7 Phase 3 (Goldor): `phasethree.wav`\n  - F7 Phase 4 (Necron): `phasefour.wav`\n  - F7 Phase 5 (Wither King): `phasefive.wav`\n  - Hub: `hub.wav`\n  - Private Island: `island.wav`\n  - Farming Islands: `farmingislands.wav`\n  - Garden: `garden.wav`\n  - Gold Mine: `goldmine.wav`\n  - Deep Caverns: `deepcaverns.wav`\n  - Dwarven Mines: `dwarvenmines.wav`\n  - Crystal Hollows: `crystalhollows.wav`\n  - Spider's Den: `spidersden.wav`\n  - Crimson Isle: `crimsonisle.wav`\n  - Kuudra: `kuudra.wav`\n  - The End: `end.wav`\n  - The Park: `park.wav`\n2. Either run `/dsmmusic reload` or restart your game.\n3. Enable the custom music in `/dsm`.\n4. (Optional) Change the volume of the music with `/dsmmusic volume`.\n\n#### Shuffling\nBy adding numbers to the end of the file, you can have multiple music files for the same area. One of them will be randomly selected (the same song could play twice in a row). For example:\n- dungeon.wav\n- dungeon1.wav\n- dungeon2.wav\n- dungeon99.wav\n</details>\n\n<details>\n<summary>Alert Regex</summary>\n\n## Alert Regex\nTo replace alert text with a captured group, add `$$x$$` to the alert text, with `x` being the number of the capture group. `$$0$$` will always be replaced with the entire trigger message.\n\nFor example, with the following alert\n\nRegex: `From (.*) (.*): (.*)`  \nAlert Text: `$$2$$ says $$3$$`  \nTrigger Message: `From [ADMIN] Plancke: Nice autogg`  \n\nthe following alert text would appear\n\n`Plancke says Nice autogg`.\n</details>\n\n<details>\n<summary>Notes</summary>\n\n### Notes\n- Slayer tracker for token drops and 20% chance drops uses a 12x12x12 bounding box centered on the player to detect the drops. If you are out of the range of the item drop, it will not count on the tracker.\n- API commands may take a while depending on your internet connection. The API may also go down.\n- If you use too many API commands too fast, you can and will get rate-limited.\n- Importing fishing uses your sea creature kills, which may not always be exactly correct (e.x. someone else kills your sea creature).\n</details>\n\n### Credits to Open Source Software\nCredit to all the following open source software used in this mod.\n\nSoftware | License\n------------ | -------------\n[SkyblockAddons](https://github.com/BiscuitDevelopment/SkyblockAddons/) | [MIT License](https://github.com/BiscuitDevelopment/SkyblockAddons/blob/master/LICENSE)\n[Zealot Counter](https://github.com/symt/zealot-counter/) | [Apache License](https://github.com/symt/zealot-counter/blob/master/LICENSE.md)\n[NotEnoughUpdates](https://github.com/Moulberry/NotEnoughUpdates/) | [Creative Commons Public License](https://github.com/Moulberry/NotEnoughUpdates/blob/master/LICENSE)\n[HyChat](https://github.com/Moulberry/Hychat) | [Creative Commons Public License](https://github.com/Moulberry/Hychat/blob/master/LICENSE)\n[SkyblockCatia](https://github.com/SteveKunG/SkyBlockcatia) | [MIT License](https://github.com/SteveKunG/SkyBlockcatia/blob/1.8.9/LICENSE.md)\n[MatterOverdrive (Legacy Edition)](https://bitbucket.org/hrznstudio/mo-legacy-edition/) | [GNU General Public License](https://bitbucket.org/hrznstudio/mo-legacy-edition/src/1.12.2/LICENSE.md)\n[Hide Armour](https://github.com/Furgl/Hide-Armor/tree/1.15.2) | No License\n[Elite Discord Bot](https://github.com/ptlthg/EliteDiscordBot) | [MIT License](https://github.com/ptlthg/EliteDiscordBot/blob/master/LICENSE)\n[Baeldung Tutorials](https://github.com/eugenp/tutorials) | [MIT License](https://github.com/eugenp/tutorials/blob/master/LICENSE)\n"
  },
  {
    "path": "build.gradle.kts",
    "content": "import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar\nimport gg.essential.gradle.util.noServerRunConfigs\n\nplugins {\n    id(\"gg.essential.multi-version\")\n    id(\"gg.essential.defaults.repo\")\n    id(\"gg.essential.defaults.java\")\n    id(\"gg.essential.defaults.loom\")\n    id(\"com.github.johnrengelman.shadow\")\n    id(\"net.kyori.blossom\") version \"1.3.0\"\n    id(\"io.github.juuxel.loom-quiltflower-mini\")\n    id(\"signing\")\n    java\n}\n\nval mod_name: String by project\nval mod_version: String by project\nval mod_id: String by project\n\npreprocess {\n    vars.put(\"MODERN\", if (project.platform.mcMinor >= 16) 1 else 0)\n}\n\nblossom {\n    replaceToken(\"@VER@\", mod_version)\n    replaceToken(\"@NAME@\", mod_name)\n    replaceToken(\"@ID@\", mod_id)\n}\n\nversion = mod_version\ngroup = \"me.Danker\"\nbase {\n    archivesName.set(mod_name)\n}\nloom {\n    noServerRunConfigs()\n    if (project.platform.isLegacyForge) {\n        launchConfigs.named(\"client\") {\n            arg(\"--tweakClass\", \"cc.polyfrost.oneconfig.loader.stage0.LaunchWrapperTweaker\")\n            property(\"mixin.debug.export\", \"true\")\n        }\n        runConfigs.named(\"client\") {\n            vmArgs.remove(\"-XstartOnFirstThread\")\n        }\n    }\n}\n\nval shade: Configuration by configurations.creating {\n    configurations.implementation.get().extendsFrom(this)\n}\n\nsourceSets {\n    main {\n        output.setResourcesDir(java.classesDirectory)\n    }\n}\n\nrepositories {\n    maven(\"https://repo.polyfrost.cc/releases\")\n}\n\ndependencies {\n    modCompileOnly(\"cc.polyfrost:oneconfig-$platform:0.2.2-alpha+\")\n\n    if (platform.isLegacyForge) {\n        shade(\"cc.polyfrost:oneconfig-wrapper-launchwrapper:1.0.0-beta17\")\n        runtimeOnly(\"me.djtheredstoner:DevAuth-forge-legacy:1.1.0\")\n    }\n}\n\ntasks.processResources {\n    inputs.property(\"id\", mod_id)\n    inputs.property(\"name\", mod_name)\n    val java = if (project.platform.mcMinor >= 18) {\n        17\n    } else {\n        if (project.platform.mcMinor == 17) 16 else 8\n    }\n    val compatLevel = \"JAVA_${java}\"\n    inputs.property(\"java\", java)\n    inputs.property(\"java_level\", compatLevel)\n    inputs.property(\"version\", mod_version)\n    inputs.property(\"mcVersionStr\", project.platform.mcVersionStr)\n    filesMatching(listOf(\"mcmod.info\", \"mixins.${mod_id}.json\", \"mods.toml\")) {\n        expand(\n                mapOf(\n                        \"id\" to mod_id,\n                        \"name\" to mod_name,\n                        \"java\" to java,\n                        \"java_level\" to compatLevel,\n                        \"version\" to mod_version,\n                        \"mcVersionStr\" to project.platform.mcVersionStr\n                )\n        )\n    }\n    filesMatching(\"fabric.mod.json\") {\n        expand(\n                mapOf(\n                        \"id\" to mod_id,\n                        \"name\" to mod_name,\n                        \"java\" to java,\n                        \"java_level\" to compatLevel,\n                        \"version\" to mod_version,\n                        \"mcVersionStr\" to project.platform.mcVersionStr.substringBeforeLast(\".\") + \".x\"\n                )\n        )\n    }\n}\n\ntasks {\n    withType(Jar::class.java) {\n        if (project.platform.isFabric) {\n            exclude(\"mcmod.info\", \"mods.toml\")\n        } else {\n            exclude(\"fabric.mod.json\")\n            if (project.platform.isLegacyForge) {\n                exclude(\"mods.toml\")\n            } else {\n                exclude(\"mcmod.info\")\n            }\n        }\n    }\n    named<ShadowJar>(\"shadowJar\") {\n        archiveClassifier.set(\"dev\")\n        configurations = listOf(shade)\n        duplicatesStrategy = DuplicatesStrategy.EXCLUDE\n    }\n    remapJar {\n        input.set(shadowJar.get().archiveFile)\n        archiveClassifier.set(\"\")\n    }\n    jar {\n        manifest {\n            attributes(\n                    mapOf(\n                            \"ModSide\" to \"CLIENT\",\n                            \"ForceLoadAsMod\" to true,\n                            \"TweakOrder\" to \"0\",\n                            \"TweakClass\" to \"cc.polyfrost.oneconfig.loader.stage0.LaunchWrapperTweaker\",\n                            \"Main-Class\" to \"DefenitlyNotAJoikedInstallerFrame\"\n                    )\n            )\n        }\n        dependsOn(shadowJar)\n        archiveClassifier.set(\"\")\n        enabled = false\n    }\n}"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-7.5.1-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists"
  },
  {
    "path": "gradle.properties",
    "content": "mod_name = Danker's Skyblock Mod\nmod_id = Danker's Skyblock Mod\nmod_version = 2.3.1\n\nessential.defaults.loom=0\n\norg.gradle.daemon=true\norg.gradle.parallel=true\norg.gradle.configureoncommand=true\norg.gradle.parallel.threads=4\norg.gradle.jvmargs=-Xmx2G"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=`expr $i + 1`\n    done\n    case $i in\n        0) set -- ;;\n        1) set -- \"$args0\" ;;\n        2) set -- \"$args0\" \"$args1\" ;;\n        3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\n@rem you may not use this file except in compliance with the License.\n@rem You may obtain a copy of the License at\n@rem\n@rem      https://www.apache.org/licenses/LICENSE-2.0\n@rem\n@rem Unless required by applicable law or agreed to in writing, software\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@rem See the License for the specific language governing permissions and\n@rem limitations under the License.\n@rem\n\n@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto execute\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto execute\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "root.gradle.kts",
    "content": "plugins {\n    kotlin(\"jvm\") version \"1.6.21\" apply false\n    id(\"gg.essential.multi-version.root\")\n    id(\"com.github.johnrengelman.shadow\") version \"7.1.2\" apply false\n    id(\"io.github.juuxel.loom-quiltflower-mini\") version \"171a6e2e49\" apply false\n}\n\npreprocess {\n    \"1.8.9-forge\"(10809, \"srg\") {}\n}"
  },
  {
    "path": "settings.gradle.kts",
    "content": "pluginManagement {\n    repositories {\n        gradlePluginPortal()\n        mavenCentral()\n        maven(\"https://repo.polyfrost.cc/releases\")\n        maven(\"https://maven.architectury.dev/\")\n    }\n    plugins {\n        val egtVersion = \"0.1.11\"\n        id(\"gg.essential.multi-version.root\") version egtVersion\n    }\n    resolutionStrategy {\n        eachPlugin {\n            if (requested.id.id == \"io.github.juuxel.loom-quiltflower-mini\") {\n                useModule(\"com.github.wyvest:loom-quiltflower-mini:${requested.version}\")\n            }\n        }\n    }\n}\n\nval mod_name: String by settings\n\nrootProject.name = mod_name\nrootProject.buildFileName = \"root.gradle.kts\"\n\nlistOf(\n        \"1.8.9-forge\"\n).forEach { version ->\n    include(\":$version\")\n    project(\":$version\").apply {\n        projectDir = file(\"versions/$version\")\n        buildFileName = \"../../build.gradle.kts\"\n    }\n}"
  },
  {
    "path": "src/main/java/DefenitlyNotAJoikedInstallerFrame.java",
    "content": "import me.Danker.DankersSkyblockMod;\n\nimport javax.imageio.ImageIO;\nimport javax.swing.*;\nimport java.awt.*;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.awt.event.MouseEvent;\nimport java.awt.event.MouseListener;\nimport java.awt.image.BufferedImage;\nimport java.io.*;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.nio.file.Files;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.jar.JarFile;\nimport java.util.regex.Pattern;\nimport java.util.zip.ZipEntry;\n\npublic class DefenitlyNotAJoikedInstallerFrame extends JFrame implements ActionListener, MouseListener {\n\n    private static final Pattern IN_MODS_SUBFOLDER = Pattern.compile(\"1\\\\.8\\\\.9[/\\\\\\\\]?$\");\n\n    private JLabel logo = null;\n    private JLabel versionInfo = null;\n    private JLabel labelFolder = null;\n\n    private JPanel panelCenter = null;\n    private JPanel panelBottom = null;\n    private JPanel totalContentPane = null;\n\n    private JTextArea descriptionText = null;\n    private JTextArea forgeDescriptionText = null;\n\n    private JTextField textFieldFolderLocation = null;\n    private JButton buttonChooseFolder = null;\n\n    private JButton buttonInstall = null;\n    private JButton buttonOpenFolder = null;\n    private JButton buttonClose = null;\n\n    private static final int TOTAL_HEIGHT = 442; //435\n    private static final int TOTAL_WIDTH = 404;\n\n    private int x = 0;\n    private int y = 0; \n\n    private int w = TOTAL_WIDTH;\n    private int h;\n    private int margin;\n\n    public DefenitlyNotAJoikedInstallerFrame() {\n        try {\n            setName(\"DankersSkyblockModInstallerFrame\");\n            setTitle(\"DSM Installer\");\n            setResizable(false);\n            setSize(TOTAL_WIDTH, TOTAL_HEIGHT);\n            setContentPane(getPanelContentPane());\n\n            getButtonFolder().addActionListener(this);\n            getButtonInstall().addActionListener(this);\n            getButtonOpenFolder().addActionListener(this);\n            getButtonClose().addActionListener(this);\n            getForgeTextArea().addMouseListener(this);\n\n            pack();\n            setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);\n\n            getFieldFolder().setText(getModsFolder().getPath());\n            getButtonInstall().setEnabled(true);\n            getButtonInstall().requestFocus();\n        } catch (Exception ex) {\n            showErrorPopup(ex);\n        }\n    }\n\n    public static void main(String[] args) {\n        try {\n            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());\n            DefenitlyNotAJoikedInstallerFrame frame = new DefenitlyNotAJoikedInstallerFrame();\n            frame.centerFrame(frame);\n            frame.setVisible(true);\n\n        } catch (Exception ex) {\n            showErrorPopup(ex);\n        }\n    }\n\n    private JPanel getPanelContentPane() {\n        if (totalContentPane == null) {\n            try {\n                totalContentPane = new JPanel();\n                totalContentPane.setName(\"PanelContentPane\");\n                totalContentPane.setLayout(new BorderLayout(5, 5));\n                totalContentPane.setPreferredSize(new Dimension(TOTAL_WIDTH, TOTAL_HEIGHT));\n                totalContentPane.add(getPanelCenter(), \"Center\");\n                totalContentPane.add(getPanelBottom(), \"South\");\n            } catch (Throwable ivjExc) {\n                showErrorPopup(ivjExc);\n            }\n        }\n        return totalContentPane;\n    }\n\n    private JPanel getPanelCenter() {\n        if (panelCenter == null) {\n            try {\n                (panelCenter = new JPanel()).setName(\"PanelCenter\");\n                panelCenter.setLayout(null);\n                panelCenter.add(getPictureLabel(), getPictureLabel().getName());\n                panelCenter.add(getVersionInfo(), getVersionInfo().getName());\n                panelCenter.add(getTextArea(), getTextArea().getName());\n                panelCenter.add(getForgeTextArea(), getForgeTextArea().getName());\n                panelCenter.add(getLabelFolder(), getLabelFolder().getName());\n                panelCenter.add(getFieldFolder(), getFieldFolder().getName());\n                panelCenter.add(getButtonFolder(), getButtonFolder().getName());\n            } catch (Throwable ivjExc) {\n                showErrorPopup(ivjExc);\n            }\n        }\n        return panelCenter;\n    }\n\n    private JLabel getPictureLabel() {\n        if (logo == null) {\n            try {\n                h = w/2;\n                margin = 5;\n\n                BufferedImage myPicture = ImageIO.read(Objects.requireNonNull(getClass().getClassLoader()\n                        .getResourceAsStream(\"assets/dsm/icons/logo.png\"), \"Logo not found.\"));\n                Image scaled = myPicture.getScaledInstance(w-margin*2, h-margin, Image.SCALE_SMOOTH);\n                logo = new JLabel(new ImageIcon(scaled));\n                logo.setName(\"logo\");\n                logo.setBounds(x+margin, y+margin, w-margin*2, h-margin);\n                logo.setFont(new Font(Font.DIALOG, Font.BOLD, 18));\n                logo.setHorizontalAlignment(SwingConstants.CENTER);\n                logo.setPreferredSize(new Dimension(w, h));\n\n                y += h;\n            } catch (Throwable ivjExc) {\n                showErrorPopup(ivjExc);\n            }\n        }\n        return logo;\n    }\n\n    private JLabel getVersionInfo() {\n        if (versionInfo == null) {\n            try {\n                h = 47; //34\n\n                versionInfo = new JLabel();\n                versionInfo.setName(\"LabelMcVersion\");\n                versionInfo.setBounds(x, y+1, w, h); \n                versionInfo.setFont(new Font(Font.DIALOG, Font.BOLD, 14));\n                versionInfo.setHorizontalAlignment(SwingConstants.CENTER);\n                versionInfo.setPreferredSize(new Dimension(w, h));\n                versionInfo.setText(\"<html><body>Danker's Skyblock Mod - Installer by Biscuit <br><center> for Minecraft 1.8.9</center></body></html>\");\n\n                y += h-5;\n            } catch (Throwable ivjExc) {\n                showErrorPopup(ivjExc);\n            }\n        }\n        return versionInfo;\n    }\n\n\n    private JTextArea getTextArea() {\n        if (descriptionText == null) {\n            try {\n                h = 60;\n                margin = 10;\n\n                descriptionText = new JTextArea();\n                descriptionText.setName(\"TextArea\");\n                setTextAreaProperties(descriptionText);\n                descriptionText.setText(\"This installer will copy Danker's Skyblock Mod into your forge mods folder for you, and replace any old versions that already exist. \" +\n                        \"Close this if you prefer to do this yourself!\");\n                descriptionText.setWrapStyleWord(true);\n\n                y += h;\n            } catch (Throwable ivjExc) {\n                showErrorPopup(ivjExc);\n            }\n        }\n        return descriptionText;\n    }\n\n    private void setTextAreaProperties(JTextArea textArea) {\n        textArea.setBounds(x+margin, y+margin, w-margin*2, h-margin);\n        textArea.setEditable(false);\n        textArea.setHighlighter(null);\n        textArea.setEnabled(true);\n        textArea.setFont(new Font(Font.DIALOG, Font.PLAIN, 12));\n        textArea.setLineWrap(true);\n        textArea.setOpaque(false);\n        textArea.setPreferredSize(new Dimension(w-margin*2, h-margin));\n    }\n\n    private JTextArea getForgeTextArea() {\n        if (forgeDescriptionText == null) {\n            try {\n                h = 55;\n                margin = 10;\n\n                forgeDescriptionText = new JTextArea();\n                forgeDescriptionText.setName(\"TextAreaForge\");\n\n\n                setTextAreaProperties(forgeDescriptionText);\n\n\n\n\n\n                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!\");\n                forgeDescriptionText.setForeground(Color.BLUE.darker());\n                forgeDescriptionText.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));\n                forgeDescriptionText.setWrapStyleWord(true);\n\n                y += h;\n            } catch (Throwable ivjExc) {\n                showErrorPopup(ivjExc);\n            }\n        }\n        return forgeDescriptionText;\n    }\n\n    private JLabel getLabelFolder() {\n        if (labelFolder == null) {\n            h = 16;\n            w = 65;\n\n            x += 10; // Padding\n\n            try {\n                labelFolder = new JLabel();\n                labelFolder.setName(\"LabelFolder\");\n                labelFolder.setBounds(x, y+2, w, h);\n                labelFolder.setPreferredSize(new Dimension(w, h));\n                labelFolder.setText(\"Mods Folder\");\n            } catch (Throwable ivjExc) {\n                showErrorPopup(ivjExc);\n            }\n\n            x += w;\n        }\n        return labelFolder;\n    }\n\n    private JTextField getFieldFolder() {\n        if (textFieldFolderLocation == null) {\n            h = 20;\n            w = 287;\n\n            try {\n                textFieldFolderLocation = new JTextField();\n                textFieldFolderLocation.setName(\"FieldFolder\");\n                textFieldFolderLocation.setBounds(x, y, w, h);\n                textFieldFolderLocation.setEditable(false);\n                textFieldFolderLocation.setPreferredSize(new Dimension(w, h));\n            } catch (Throwable ivjExc) {\n                showErrorPopup(ivjExc);\n            }\n\n            x += w;\n        }\n        return textFieldFolderLocation;\n    }\n\n    private JButton getButtonFolder() {\n        if (buttonChooseFolder == null) {\n            h = 20;\n            w = 25;\n\n            x += 10; // Padding\n\n            try {\n                BufferedImage myPicture = ImageIO.read(Objects.requireNonNull(getClass().getClassLoader()\n                        .getResourceAsStream(\"assets/dsm/icons/folder.png\"), \"Folder icon not found.\"));\n                Image scaled = myPicture.getScaledInstance(w-8, h-6, Image.SCALE_SMOOTH);\n                buttonChooseFolder = new JButton(new ImageIcon(scaled));\n                buttonChooseFolder.setName(\"ButtonFolder\");\n                buttonChooseFolder.setBounds(x, y, w, h);\n                buttonChooseFolder.setPreferredSize(new Dimension(w, h));\n            } catch (Throwable ivjExc) {\n                showErrorPopup(ivjExc);\n            }\n        }\n        return buttonChooseFolder;\n    }\n\n    private JPanel getPanelBottom() {\n        if (panelBottom == null) {\n            try {\n                panelBottom = new JPanel();\n                panelBottom.setName(\"PanelBottom\");\n                panelBottom.setLayout(new FlowLayout(FlowLayout.CENTER, 15, 10));\n                panelBottom.setPreferredSize(new Dimension(390, 55));\n                panelBottom.add(getButtonInstall(), getButtonInstall().getName());\n                panelBottom.add(getButtonOpenFolder(), getButtonOpenFolder().getName());\n                panelBottom.add(getButtonClose(), getButtonClose().getName());\n            } catch (Throwable ivjExc) {\n                showErrorPopup(ivjExc);\n            }\n        }\n        return panelBottom;\n    }\n\n    private JButton getButtonInstall() {\n        if (buttonInstall == null) {\n            w = 100;\n            h = 26;\n\n            try {\n                buttonInstall = new JButton();\n                buttonInstall.setName(\"ButtonInstall\");\n                buttonInstall.setPreferredSize(new Dimension(w, h));\n                buttonInstall.setText(\"Install\");\n            } catch (Throwable ivjExc) {\n                showErrorPopup(ivjExc);\n            }\n        }\n        return buttonInstall;\n    }\n\n    private JButton getButtonOpenFolder() {\n        if (buttonOpenFolder == null) {\n            w = 130;\n            h = 26;\n\n            try {\n                buttonOpenFolder = new JButton();\n                buttonOpenFolder.setName(\"ButtonOpenFolder\");\n                buttonOpenFolder.setPreferredSize(new Dimension(w, h));\n                buttonOpenFolder.setText(\"Open Mods Folder\");\n            } catch (Throwable ivjExc) {\n                showErrorPopup(ivjExc);\n            }\n        }\n        return buttonOpenFolder;\n    }\n\n    private JButton getButtonClose() {\n        if (buttonClose == null) {\n            w = 100;\n            h = 26;\n\n            try {\n                (buttonClose = new JButton()).setName(\"ButtonClose\");\n                buttonClose.setPreferredSize(new Dimension(w, h));\n                buttonClose.setText(\"Cancel\");\n            } catch (Throwable ivjExc) {\n                showErrorPopup(ivjExc);\n            }\n        }\n        return buttonClose;\n    }\n\n    public void onFolderSelect() {\n        File currentDirectory = new File(getFieldFolder().getText());\n\n        JFileChooser jFileChooser = new JFileChooser(currentDirectory);\n        jFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);\n        jFileChooser.setAcceptAllFileFilterUsed(false);\n        if (jFileChooser.showOpenDialog(this) == 0) {\n            File newDirectory = jFileChooser.getSelectedFile();\n            getFieldFolder().setText(newDirectory.getPath());\n        }\n    }\n\n    @Override\n    public void actionPerformed(ActionEvent e) {\n        if (e.getSource() == getButtonClose()) {\n            dispose();\n            System.exit(0);\n        }\n        if (e.getSource() == getButtonFolder()) {\n            onFolderSelect();\n        }\n        if (e.getSource() == getButtonInstall()) {\n            onInstall();\n        }\n        if (e.getSource() == getButtonOpenFolder()) {\n            onOpenFolder();\n        }\n    }\n\n    @Override\n    public void mouseClicked(MouseEvent e) {\n        if (e.getSource() == getForgeTextArea()) {\n            try {\n                Desktop.getDesktop().browse(new URI(\"http://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.8.9.html\"));\n            } catch (IOException | URISyntaxException ex) {\n                showErrorPopup(ex);\n            }\n        }\n    }\n\n    public void onInstall() {\n        try {\n            File modsFolder = new File(getFieldFolder().getText());\n            if (!modsFolder.exists()) {\n                showErrorMessage(\"Folder not found: \" + modsFolder.getPath());\n                return;\n            }\n            if (!modsFolder.isDirectory()) {\n                showErrorMessage(\"Not a folder: \" + modsFolder.getPath());\n                return;\n            }\n            tryInstall(modsFolder);\n        } catch (Exception e) {\n            showErrorPopup(e);\n        }\n    }\n\n    private void tryInstall(File modsFolder) {\n        File thisFile = getThisFile();\n\n        if (thisFile != null) {\n            boolean inSubFolder = IN_MODS_SUBFOLDER.matcher(modsFolder.getPath()).find();\n\n            File newFile = new File(modsFolder, \"Danker's Skyblock Mod - \" + DankersSkyblockMod.VERSION + \".jar\");\n\n            if (thisFile.equals(newFile)) {\n                showErrorMessage(\"You are opening this file from where the file should be installed... there's nothing to be done!\");\n                return;\n            }\n\n            boolean deletingFailure = false;\n            if (modsFolder.isDirectory()) { // Delete in this current folder.\n                boolean failed = findDSMAndDelete(modsFolder.listFiles());\n                if (failed) deletingFailure = true;\n            }\n            if (inSubFolder) { // We are in the 1.8.9 folder, delete in the parent folder as well.\n                if (modsFolder.getParentFile().isDirectory()) {\n                    boolean failed = findDSMAndDelete(modsFolder.getParentFile().listFiles());\n                    if (failed) deletingFailure = true;\n                }\n            } else { // We are in the main mods folder, but the 1.8.9 subfolder exists... delete in there too.\n                File subFolder = new File(modsFolder, \"1.8.9\");\n                if (subFolder.exists() && subFolder.isDirectory()) {\n                    boolean failed = findDSMAndDelete(subFolder.listFiles());\n                    if (failed) deletingFailure = true;\n                }\n            }\n\n            if (deletingFailure) return;\n\n            if (thisFile.isDirectory()) {\n                showErrorMessage(\"This file is a directory... Are we in a development environment?\");\n                return;\n            }\n\n            try {\n                Files.copy(thisFile.toPath(), newFile.toPath());\n            } catch (Exception ex) {\n                showErrorPopup(ex);\n                return;\n            }\n\n            showMessage(\"Danker's Skyblock Mod has been successfully installed into your mods folder.\");\n            dispose();\n            System.exit(0);\n        }\n    }\n\n    private boolean findDSMAndDelete(File[] files) {\n        if (files == null) return false;\n\n        for (File file : files) {\n            if (!file.isDirectory() && file.getPath().endsWith(\".jar\")) {\n                try {\n                    JarFile jarFile = new JarFile(file);\n                    ZipEntry mcModInfo = jarFile.getEntry(\"mcmod.info\");\n                    if (mcModInfo != null) {\n                        InputStream inputStream = jarFile.getInputStream(mcModInfo);\n                        String modID = getModIDFromInputStream(inputStream);\n                        if (modID.equals(\"Danker's Skyblock Mod\")) {\n                            jarFile.close();\n                            try {\n                                boolean deleted = file.delete();\n                                if (!deleted) {\n                                    throw new Exception();\n                                }\n                            } catch (Exception ex) {\n                                ex.printStackTrace();\n                                showErrorMessage(\"Was not able to delete the other DSM files found in your mods folder!\" + System.lineSeparator() +\n                                        \"Please make sure that your minecraft is currently closed and try again, or feel\" + System.lineSeparator() +\n                                        \"free to open your mods folder and delete those files manually.\");\n                                return true;\n                            }\n                            continue;\n                        }\n                    }\n                    jarFile.close();\n                } catch (Exception ex) {\n                    // Just don't check the file I guess, move on to the next...\n                }\n            }\n        }\n        return false;\n    }\n\n    public void onOpenFolder() {\n        try {\n            Desktop.getDesktop().open(getModsFolder());\n        } catch (Exception e) {\n            showErrorPopup(e);\n        }\n    }\n\n    public File getModsFolder() {\n        String userHome = System.getProperty(\"user.home\", \".\");\n\n        File modsFolder = getFile(userHome, \"minecraft/mods/1.8.9\");\n        if (!modsFolder.exists()) {\n            modsFolder = getFile(userHome, \"minecraft/mods\");\n        }\n\n        if (!modsFolder.exists() && !modsFolder.mkdirs()) {\n            throw new RuntimeException(\"The working directory could not be created: \" + modsFolder);\n        }\n        return modsFolder;\n    }\n\n    public File getFile(String userHome, String minecraftPath) {\n        File workingDirectory;\n        switch (getOperatingSystem()) {\n            case LINUX:\n            case SOLARIS: {\n                workingDirectory = new File(userHome, '.' + minecraftPath + '/');\n                break;\n            }\n            case WINDOWS: {\n                String applicationData = System.getenv(\"APPDATA\");\n                if (applicationData != null) {\n                    workingDirectory = new File(applicationData, \".\" + minecraftPath + '/');\n                    break;\n                }\n                workingDirectory = new File(userHome, '.' + minecraftPath + '/');\n                break;\n            }\n            case MACOS: {\n                workingDirectory = new File(userHome, \"Library/Application Support/\" + minecraftPath);\n                break;\n            }\n            default: {\n                workingDirectory = new File(userHome, minecraftPath + '/');\n                break;\n            }\n        }\n        return workingDirectory;\n    }\n\n    public OperatingSystem getOperatingSystem() {\n        String osName = System.getProperty(\"os.name\").toLowerCase(Locale.US);\n        if (osName.contains(\"win\")) {\n            return OperatingSystem.WINDOWS;\n\n        } else if (osName.contains(\"mac\")) {\n            return OperatingSystem.MACOS;\n\n        } else if (osName.contains(\"solaris\") || osName.contains(\"sunos\")) {\n\n            return OperatingSystem.SOLARIS;\n        } else if (osName.contains(\"linux\") || osName.contains(\"unix\")) {\n\n            return OperatingSystem.LINUX;\n        }\n        return OperatingSystem.UNKNOWN;\n    }\n\n    public void centerFrame(JFrame frame) {\n        Rectangle rectangle = frame.getBounds();\n        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();\n        Rectangle screenRectangle = new Rectangle(0, 0, screenSize.width, screenSize.height);\n\n        int newX = screenRectangle.x + (screenRectangle.width - rectangle.width) / 2;\n        int newY = screenRectangle.y + (screenRectangle.height - rectangle.height) / 2;\n\n        if (newX < 0) newX = 0;\n        if (newY < 0) newY = 0;\n\n        frame.setBounds(newX, newY, rectangle.width, rectangle.height);\n    }\n\n    public void showMessage(String message) {\n        JOptionPane.showMessageDialog(null, message, \"Danker's Skyblock Mod\", JOptionPane.INFORMATION_MESSAGE);\n    }\n\n    public void showErrorMessage(String message) {\n        JOptionPane.showMessageDialog(null, message, \"Danker's Skyblock Mod - Error\", JOptionPane.ERROR_MESSAGE);\n    }\n\n    public enum OperatingSystem {\n        LINUX,\n        SOLARIS,\n        WINDOWS,\n        MACOS,\n        UNKNOWN\n    }\n\n    private static String getStacktraceText(Throwable ex) {\n        StringWriter stringWriter = new StringWriter();\n        ex.printStackTrace(new PrintWriter(stringWriter));\n        return stringWriter.toString().replace(\"\\t\", \"  \");\n    }\n\n    private static void showErrorPopup(Throwable ex) {\n        ex.printStackTrace();\n\n        JTextArea textArea = new JTextArea(getStacktraceText(ex));\n        textArea.setEditable(false);\n        Font currentFont = textArea.getFont();\n        Font newFont = new Font(Font.MONOSPACED, currentFont.getStyle(), currentFont.getSize());\n        textArea.setFont(newFont);\n\n        JScrollPane errorScrollPane = new JScrollPane(textArea);\n        errorScrollPane.setPreferredSize(new Dimension(600, 400));\n        JOptionPane.showMessageDialog(null, errorScrollPane, \"Error\", JOptionPane.ERROR_MESSAGE);\n    }\n\n    private String getModIDFromInputStream(InputStream inputStream) {\n        String version = \"\";\n        try {\n            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));\n            while ((version = bufferedReader.readLine()) != null) {\n                if (version.contains(\"\\\"modid\\\": \\\"\")) {\n                    version = version.split(Pattern.quote(\"\\\"modid\\\": \\\"\"))[1];\n                    version = version.substring(0, version.length() - 2);\n                    break;\n                }\n            }\n        } catch (Exception ex) {\n            // RIP, couldn't find the modid...\n        }\n        return version;\n    }\n\n    private File getThisFile() {\n        try {\n            return new File(DefenitlyNotAJoikedInstallerFrame.class.getProtectionDomain().getCodeSource().getLocation().toURI());\n        } catch (URISyntaxException ex) {\n            showErrorPopup(ex);\n        }\n        return null;\n    }\n\n    @Override\n    public void mousePressed(MouseEvent e) {}\n\n    @Override\n    public void mouseReleased(MouseEvent e) {}\n\n    @Override\n    public void mouseEntered(MouseEvent e) {}\n\n    @Override\n    public void mouseExited(MouseEvent e) {}\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/DankersSkyblockMod.java",
    "content": "package me.Danker;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.commands.*;\nimport me.Danker.commands.api.*;\nimport me.Danker.commands.loot.DisplayCommand;\nimport me.Danker.commands.loot.ImportFishingCommand;\nimport me.Danker.commands.loot.LootCommand;\nimport me.Danker.commands.loot.ResetLootCommand;\nimport me.Danker.commands.warp.WarpCommandHandler;\nimport me.Danker.config.CfgConfig;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.*;\nimport me.Danker.features.*;\nimport me.Danker.features.loot.*;\nimport me.Danker.features.puzzlesolvers.*;\nimport me.Danker.gui.WarningGui;\nimport me.Danker.gui.WarningGuiRedirect;\nimport me.Danker.handlers.ConfigHandler;\nimport me.Danker.handlers.PacketHandler;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.GuiMainMenu;\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.command.ICommand;\nimport net.minecraft.event.ClickEvent;\nimport net.minecraft.event.ClickEvent.Action;\nimport net.minecraft.event.HoverEvent;\nimport net.minecraft.inventory.Container;\nimport net.minecraft.inventory.ContainerChest;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.IChatComponent;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.ClientCommandHandler;\nimport net.minecraftforge.client.GuiIngameForge;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.client.event.GuiOpenEvent;\nimport net.minecraftforge.client.event.GuiScreenEvent;\nimport net.minecraftforge.client.event.RenderGameOverlayEvent;\nimport net.minecraftforge.common.MinecraftForge;\nimport net.minecraftforge.event.entity.EntityJoinWorldEvent;\nimport net.minecraftforge.fml.common.Loader;\nimport net.minecraftforge.fml.common.Mod;\nimport net.minecraftforge.fml.common.Mod.EventHandler;\nimport net.minecraftforge.fml.common.event.FMLInitializationEvent;\nimport net.minecraftforge.fml.common.event.FMLPostInitializationEvent;\nimport net.minecraftforge.fml.common.event.FMLPreInitializationEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent.Phase;\nimport net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent;\nimport org.lwjgl.input.Mouse;\n\nimport javax.sound.sampled.LineUnavailableException;\nimport javax.sound.sampled.UnsupportedAudioFileException;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\n@Mod(modid = DankersSkyblockMod.MODID, version = DankersSkyblockMod.VERSION, clientSideOnly = true)\npublic class DankersSkyblockMod {\n    public static final String MODID = \"@ID@\";\n    public static final String VERSION = \"@VER@\";\n    public static ModConfig config;\n\n    public static int titleTimer = -1;\n    public static boolean showTitle = false;\n    public static String titleText = \"\";\n    public static int tickAmount = 1;\n    public static int repoTickAmount = 1;\n    public static boolean usingLabymod = false;\n    public static boolean usingOAM = false;\n    static boolean OAMWarning = false;\n    public static String guiToOpen = null;\n    public static boolean firstLaunch = false;\n    public static String configDirectory;\n    public static JsonObject data = null;\n    public static WarpCommandHandler warpCommandHandler;\n\n    public static int farmingLevel;\n    public static int miningLevel;\n    public static int combatLevel;\n    public static int foragingLevel;\n    public static int fishingLevel;\n    public static int enchantingLevel;\n    public static int alchemyLevel;\n    public static int carpentryLevel;\n\n    @EventHandler\n    public void init(FMLInitializationEvent event) throws UnsupportedAudioFileException, IOException, LineUnavailableException {\n        MinecraftForge.EVENT_BUS.register(this);\n        MinecraftForge.EVENT_BUS.register(new AbilityCooldowns());\n        MinecraftForge.EVENT_BUS.register(new Alerts());\n        MinecraftForge.EVENT_BUS.register(new AnnounceVanquishers());\n        MinecraftForge.EVENT_BUS.register(new ArachneESP());\n        MinecraftForge.EVENT_BUS.register(new ArrowTerminalSolver());\n        MinecraftForge.EVENT_BUS.register(new AutoAcceptReparty());\n        MinecraftForge.EVENT_BUS.register(new AutoDisplay());\n        MinecraftForge.EVENT_BUS.register(new AutoJoinSkyblock());\n        MinecraftForge.EVENT_BUS.register(new AutoSwapToPickBlock());\n        MinecraftForge.EVENT_BUS.register(new BazaarTimeToFill());\n        MinecraftForge.EVENT_BUS.register(new BlazeSolver());\n        MinecraftForge.EVENT_BUS.register(new BlockPlacingFlowers());\n        MinecraftForge.EVENT_BUS.register(new BlockWrongSlayer());\n        MinecraftForge.EVENT_BUS.register(new BlockWrongTerminalClicks());\n        MinecraftForge.EVENT_BUS.register(new BonzoMaskTimer());\n        MinecraftForge.EVENT_BUS.register(new SpiritMaskTimer());\n        MinecraftForge.EVENT_BUS.register(new BoulderSolver());\n        MinecraftForge.EVENT_BUS.register(new CakeTimer());\n        MinecraftForge.EVENT_BUS.register(new ChatAliases());\n        MinecraftForge.EVENT_BUS.register(new ChronomatronSolver());\n        MinecraftForge.EVENT_BUS.register(new ClickInOrderSolver());\n        MinecraftForge.EVENT_BUS.register(new ColouredNames());\n        MinecraftForge.EVENT_BUS.register(new CreeperSolver());\n        MinecraftForge.EVENT_BUS.register(new CrimsonMinibossTimer());\n        MinecraftForge.EVENT_BUS.register(new CrystalHollowWaypoints());\n        MinecraftForge.EVENT_BUS.register(new CustomMusic());\n        MinecraftForge.EVENT_BUS.register(new Debug());\n        MinecraftForge.EVENT_BUS.register(new DisableMovement());\n        MinecraftForge.EVENT_BUS.register(new DrillFix());\n        MinecraftForge.EVENT_BUS.register(new DungeonScore());\n        MinecraftForge.EVENT_BUS.register(new DungeonTimer());\n        MinecraftForge.EVENT_BUS.register(new EndOfFarmAlert());\n        MinecraftForge.EVENT_BUS.register(new ExpertiseLore());\n        MinecraftForge.EVENT_BUS.register(new FasterMaddoxCalling());\n        MinecraftForge.EVENT_BUS.register(new FilletMagmafish());\n        MinecraftForge.EVENT_BUS.register(new FirePillarDisplay());\n        MinecraftForge.EVENT_BUS.register(new FishingSpawnAlerts());\n        MinecraftForge.EVENT_BUS.register(new GemstonesLore());\n        MinecraftForge.EVENT_BUS.register(new GiantHPDisplay());\n        MinecraftForge.EVENT_BUS.register(new GoldenEnchants());\n        MinecraftForge.EVENT_BUS.register(new GolemSpawningAlert());\n        MinecraftForge.EVENT_BUS.register(new GpartyNotifications());\n        MinecraftForge.EVENT_BUS.register(new HidePetCandy());\n        MinecraftForge.EVENT_BUS.register(new HidePlayerArmour());\n        MinecraftForge.EVENT_BUS.register(new HideTooltipsInExperiments());\n        MinecraftForge.EVENT_BUS.register(new HideTooltipsMisc());\n        MinecraftForge.EVENT_BUS.register(new HighlightCommissions());\n        MinecraftForge.EVENT_BUS.register(new HighlightFilledOrders());\n        MinecraftForge.EVENT_BUS.register(new HighlightPests());\n        MinecraftForge.EVENT_BUS.register(new HighlightSkeletonMasters());\n        MinecraftForge.EVENT_BUS.register(new IceWalkSolver());\n        MinecraftForge.EVENT_BUS.register(new KuudraNotifications());\n        MinecraftForge.EVENT_BUS.register(new LividSolver());\n        MinecraftForge.EVENT_BUS.register(new LocrawSpamFix());\n        MinecraftForge.EVENT_BUS.register(new LowHealthNotifications());\n        MinecraftForge.EVENT_BUS.register(new MeterTracker());\n        MinecraftForge.EVENT_BUS.register(new MinionLastCollected());\n        MinecraftForge.EVENT_BUS.register(new NecronNotifications());\n        MinecraftForge.EVENT_BUS.register(new NoF3Coords());\n        MinecraftForge.EVENT_BUS.register(new NotifySlayerSlain());\n        MinecraftForge.EVENT_BUS.register(new PetColours());\n        MinecraftForge.EVENT_BUS.register(new PowderTracker());\n        MinecraftForge.EVENT_BUS.register(new Reparty());\n        MinecraftForge.EVENT_BUS.register(new SameColourSolver());\n        MinecraftForge.EVENT_BUS.register(new SelectAllColourSolver());\n        MinecraftForge.EVENT_BUS.register(new SilverfishSolver());\n        MinecraftForge.EVENT_BUS.register(new Skill50Display());\n        MinecraftForge.EVENT_BUS.register(new SkillTracker());\n        MinecraftForge.EVENT_BUS.register(new SlayerESP());\n        MinecraftForge.EVENT_BUS.register(new SpamHider());\n        MinecraftForge.EVENT_BUS.register(new SpiritBearAlert());\n        MinecraftForge.EVENT_BUS.register(new SpiritBootsFix());\n        MinecraftForge.EVENT_BUS.register(new StartsWithSolver());\n        MinecraftForge.EVENT_BUS.register(new StopSalvagingStarredItems());\n        MinecraftForge.EVENT_BUS.register(new SuperpairsSolver());\n        MinecraftForge.EVENT_BUS.register(new TetherDisplay());\n        MinecraftForge.EVENT_BUS.register(new ThreeManSolver());\n        MinecraftForge.EVENT_BUS.register(new TicTacToeSolver());\n        MinecraftForge.EVENT_BUS.register(new TriviaSolver());\n        MinecraftForge.EVENT_BUS.register(new UltrasequencerSolver());\n        MinecraftForge.EVENT_BUS.register(new UpdateChecker());\n        MinecraftForge.EVENT_BUS.register(new WatcherReadyAlert());\n        MinecraftForge.EVENT_BUS.register(new WaterSolver());\n\n        MinecraftForge.EVENT_BUS.register(new LootDisplay());\n        MinecraftForge.EVENT_BUS.register(new LootTracker());\n        MinecraftForge.EVENT_BUS.register(new BlazeTracker());\n        MinecraftForge.EVENT_BUS.register(new CatacombsTracker());\n        MinecraftForge.EVENT_BUS.register(new EndermanTracker());\n        MinecraftForge.EVENT_BUS.register(new FishingTracker());\n        MinecraftForge.EVENT_BUS.register(new GhostTracker());\n        MinecraftForge.EVENT_BUS.register(new MythologicalTracker());\n        MinecraftForge.EVENT_BUS.register(new SpiderTracker());\n        MinecraftForge.EVENT_BUS.register(new TrophyFishTracker());\n        MinecraftForge.EVENT_BUS.register(new VampireTracker());\n        MinecraftForge.EVENT_BUS.register(new WolfTracker());\n        MinecraftForge.EVENT_BUS.register(new ZombieTracker());\n        \n        MinecraftForge.EVENT_BUS.post(new ModInitEvent(configDirectory));\n        config = new ModConfig();\n        ConfigHandler.reloadConfig();\n        MinecraftForge.EVENT_BUS.post(new PostConfigInitEvent(configDirectory));\n\n        new Thread(Utils::refreshRepo).start();\n    }\n\n    @EventHandler\n    public void preInit(FMLPreInitializationEvent event) {\n        ClientCommandHandler.instance.registerCommand(new ArmourCommand());\n        ClientCommandHandler.instance.registerCommand(new BankCommand());\n        ClientCommandHandler.instance.registerCommand(new CrystalHollowWaypointCommand());\n        ClientCommandHandler.instance.registerCommand(new DankerGuiCommand());\n        ClientCommandHandler.instance.registerCommand(new DHelpCommand());\n        ClientCommandHandler.instance.registerCommand(new DisplayCommand());\n        ClientCommandHandler.instance.registerCommand(new DungeonsCommand());\n        ClientCommandHandler.instance.registerCommand(new FairySoulsCommand());\n        ClientCommandHandler.instance.registerCommand(new GuildOfCommand());\n        ClientCommandHandler.instance.registerCommand(new HOTMCommand());\n        ClientCommandHandler.instance.registerCommand(new HOTMTreeCommand());\n        ClientCommandHandler.instance.registerCommand(new ImportFishingCommand());\n        ClientCommandHandler.instance.registerCommand(new InventoryCommand());\n        ClientCommandHandler.instance.registerCommand(new LobbyBankCommand());\n        ClientCommandHandler.instance.registerCommand(new LobbySkillsCommand());\n        ClientCommandHandler.instance.registerCommand(new LootCommand());\n        ClientCommandHandler.instance.registerCommand(new PetsCommand());\n        ClientCommandHandler.instance.registerCommand(new PlayerCommand());\n        ClientCommandHandler.instance.registerCommand(new PowderTrackerCommand());\n        ClientCommandHandler.instance.registerCommand(new ReloadConfigCommand());\n        ClientCommandHandler.instance.registerCommand(new ReloadRepoCommand());\n        ClientCommandHandler.instance.registerCommand(new ResetLootCommand());\n        ClientCommandHandler.instance.registerCommand(new SkillsCommand());\n        ClientCommandHandler.instance.registerCommand(new SkillTrackerCommand());\n        ClientCommandHandler.instance.registerCommand(new SkyblockPlayersCommand());\n        ClientCommandHandler.instance.registerCommand(new SlayerCommand());\n        ClientCommandHandler.instance.registerCommand(new StopLobbyCommand());\n        ClientCommandHandler.instance.registerCommand(new TrophyFishCommand());\n        ClientCommandHandler.instance.registerCommand(new WeightCommand());\n\n        warpCommandHandler = new WarpCommandHandler();\n\n        configDirectory = event.getModConfigurationDirectory().toString();\n    }\n\n    @EventHandler\n    public void postInit(FMLPostInitializationEvent event) {\n        Package[] packages = Package.getPackages();\n        for (Package p : packages){\n            if (p.getName().startsWith(\"com.spiderfrog.gadgets\") || p.getName().startsWith(\"com.spiderfrog.oldanimations\")){\n                usingOAM = true;\n                break;\n            }\n        }\n        System.out.println(\"OAM detection: \" + usingOAM);\n\n        usingLabymod = Loader.isModLoaded(\"labymod\");\n        System.out.println(\"LabyMod detection: \" + usingLabymod);\n        \n        if (!ClientCommandHandler.instance.getCommands().containsKey(\"reparty\")) {\n            ClientCommandHandler.instance.registerCommand(new RepartyCommand());\n        } else if (CfgConfig.getBoolean(\"commands\", \"reparty\")) {\n            for (Map.Entry<String, ICommand> entry : ClientCommandHandler.instance.getCommands().entrySet()) {\n                if (entry.getKey().equals(\"reparty\") || entry.getKey().equals(\"rp\")) {\n                    entry.setValue(new RepartyCommand());\n                }\n            }\n        }\n\n    }\n\n    @SubscribeEvent\n    public void onGuiOpenEvent(GuiOpenEvent event) {\n        if (event.gui instanceof GuiMainMenu && usingOAM && !OAMWarning) {\n            event.gui = new WarningGuiRedirect(new WarningGui());\n            OAMWarning = true;\n        }\n    }\n\n    @SubscribeEvent\n    public void onJoin(EntityJoinWorldEvent event) {\n        if (firstLaunch) {\n            firstLaunch = false;\n            CfgConfig.writeBooleanConfig(\"misc\", \"firstLaunch\", false);\n\n            IChatComponent chatComponent = new ChatComponentText(\n                    EnumChatFormatting.GOLD + \"Thank you for downloading Danker's Skyblock Mod.\\n\" +\n                         \"To get started, run the command \" + EnumChatFormatting.GOLD + \"/dsm\" + EnumChatFormatting.RESET + \" to view all the mod features.\"\n            );\n            chatComponent.setChatStyle(chatComponent.getChatStyle().setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(\"Click to open the DSM menu.\"))).setChatClickEvent(new ClickEvent(Action.RUN_COMMAND, \"/dsm\")));\n\n            new Thread(() -> {\n                while (true) {\n                    if (Minecraft.getMinecraft().thePlayer == null) {\n                        try {\n                            Thread.sleep(500);\n                        } catch (InterruptedException e) {\n                            e.printStackTrace();\n                        }\n                        continue;\n                    }\n                    try {\n                        Thread.sleep(2000);\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    Minecraft.getMinecraft().thePlayer.addChatMessage(chatComponent);\n                    break;\n                }\n            }).start();\n        }\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (Utils.inSkyblock && !message.contains(\":\") && message.contains(\"  SKILL LEVEL UP \")) {\n            // Handle skill level ups\n            String skill = message.substring(message.indexOf(\"UP\") + 3, message.lastIndexOf(\" \"));\n            int level = Utils.getIntFromString(message.substring(message.indexOf(\"➜\") + 1), true);\n\n            switch (skill) {\n                case \"Farming\":\n                    DankersSkyblockMod.farmingLevel = level;\n                    break;\n                case \"Mining\":\n                    DankersSkyblockMod.miningLevel = level;\n                    break;\n                case \"Combat\":\n                    DankersSkyblockMod.combatLevel = level;\n                    break;\n                case \"Foraging\":\n                    DankersSkyblockMod.foragingLevel = level;\n                    break;\n                case \"Fishing\":\n                    DankersSkyblockMod.fishingLevel = level;\n                    break;\n                case \"Enchanting\":\n                    DankersSkyblockMod.enchantingLevel = level;\n                    break;\n                case \"Alchemy\":\n                    DankersSkyblockMod.alchemyLevel = level;\n                    break;\n                case \"Carpentry\":\n                    DankersSkyblockMod.carpentryLevel = level;\n                    break;\n                default:\n                    System.err.println(\"Unknown skill leveled up.\");\n            }\n\n            CfgConfig.writeIntConfig(\"skills\", skill.toLowerCase(Locale.US), level);\n        }\n    }\n\n    @SubscribeEvent\n    public void renderPlayerInfo(RenderGameOverlayEvent.Post event) {\n        if (usingLabymod && !(Minecraft.getMinecraft().ingameGUI instanceof GuiIngameForge)) return;\n        if (event.type != RenderGameOverlayEvent.ElementType.EXPERIENCE && event.type != RenderGameOverlayEvent.ElementType.JUMPBAR)\n            return;\n        MinecraftForge.EVENT_BUS.post(new RenderOverlayEvent());\n    }\n\n    // LabyMod Support\n    @SubscribeEvent\n    public void renderPlayerInfoLabyMod(RenderGameOverlayEvent event) {\n        if (!usingLabymod) return;\n        if (event.type != null) return;\n        MinecraftForge.EVENT_BUS.post(new RenderOverlayEvent());\n    }\n\n    @SubscribeEvent\n    public void renderPlayerInfo(RenderOverlayEvent event) {\n        if (showTitle) {\n            RenderUtils.drawTitle(titleText);\n        }\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n\n        tickAmount++;\n        if (tickAmount % 20 == 0) {\n            repoTickAmount++;\n            if (player != null) {\n                Utils.checkForSkyblock();\n                Utils.checkTabLocation();\n                Utils.checkForDungeonFloor();\n            }\n\n            tickAmount = 0;\n        }\n\n        if (repoTickAmount % 3601 == 0) {\n            // I didn't want to change everything so I just made a new tick variable\n            new Thread(Utils::refreshRepo).start();\n            repoTickAmount = 1;\n        }\n\n        if (titleTimer >= 0) {\n            if (titleTimer == 0) {\n                showTitle = false;\n            }\n            titleTimer--;\n        }\n\n        // New skill level detection\n        if (mc.currentScreen instanceof GuiChest && tickAmount % 5 == 0 && player != null) {\n            ContainerChest chest = (ContainerChest) player.openContainer;\n            String chestName = chest.getLowerChestInventory().getDisplayName().getUnformattedText().trim();\n\n            if (chestName.equals(\"Your Skills\")) {\n                List<Slot> invSlots = ((GuiChest) mc.currentScreen).inventorySlots.inventorySlots;\n\n                combatLevel = Utils.initializeSkill(invSlots.get(19).getStack(), \"combat\");\n                farmingLevel = Utils.initializeSkill(invSlots.get(20).getStack(), \"farming\");\n                fishingLevel = Utils.initializeSkill(invSlots.get(21).getStack(), \"fishing\");\n                miningLevel = Utils.initializeSkill(invSlots.get(22).getStack(), \"mining\");\n                foragingLevel = Utils.initializeSkill(invSlots.get(23).getStack(), \"foraging\");\n                enchantingLevel = Utils.initializeSkill(invSlots.get(24).getStack(), \"enchanting\");\n                alchemyLevel = Utils.initializeSkill(invSlots.get(25).getStack(), \"alchemy\");\n                carpentryLevel = Utils.initializeSkill(invSlots.get(29).getStack(), \"carpentry\");\n\n                System.out.println(\"Updated skill levels.\");\n            }\n        }\n    }\n\n    // Delay GUI by 1 tick\n    @SubscribeEvent\n    public void onRenderTick(TickEvent.RenderTickEvent event) {\n        if (guiToOpen != null) {\n            Minecraft mc = Minecraft.getMinecraft();\n            switch (guiToOpen) {\n                case \"inventory\":\n                    mc.displayGuiScreen(InventoryCommand.chest);\n                    break;\n                case \"hotminventory\":\n                    mc.displayGuiScreen(HOTMTreeCommand.chest);\n                    break;\n            }\n            guiToOpen = null;\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiMouseInputPre(GuiScreenEvent.MouseInputEvent.Pre event) {\n        if (Mouse.getEventButton() != 0 && Mouse.getEventButton() != 1 && Mouse.getEventButton() != 2)\n            return; // Left click, middle click or right click\n        if (!Mouse.getEventButtonState()) return;\n\n        if (event.gui == InventoryCommand.chest || event.gui == HOTMTreeCommand.chest) {\n            event.setCanceled(true);\n            return;\n        }\n\n        if (!Utils.inSkyblock) return;\n\n        if (event.gui instanceof GuiChest) {\n            Container containerChest = ((GuiChest) event.gui).inventorySlots;\n            if (containerChest instanceof ContainerChest) {\n                // a lot of declarations here, if you get scarred, my bad\n                GuiChest chest = (GuiChest) event.gui;\n                IInventory inventory = ((ContainerChest) containerChest).getLowerChestInventory();\n                Slot slot = chest.getSlotUnderMouse();\n                if (slot == null) return;\n                ItemStack item = slot.getStack();\n                String inventoryName = inventory.getDisplayName().getUnformattedText();\n\n                if (MinecraftForge.EVENT_BUS.post(new ChestSlotClickedEvent(chest, inventory, inventoryName, slot, item))) event.setCanceled(true);\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiRender(GuiScreenEvent.BackgroundDrawnEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.gui instanceof GuiChest) {\n            GuiChest inventory = (GuiChest) event.gui;\n            Container containerChest = inventory.inventorySlots;\n            if (containerChest instanceof ContainerChest) {\n                List<Slot> invSlots = inventory.inventorySlots.inventorySlots;\n                String displayName = ((ContainerChest) containerChest).getLowerChestInventory().getDisplayName().getUnformattedText().trim();\n                int chestSize = inventory.inventorySlots.inventorySlots.size();\n\n                MinecraftForge.EVENT_BUS.post(new GuiChestBackgroundDrawnEvent(inventory, displayName, chestSize, invSlots));\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onServerConnect(ClientConnectedToServerEvent event) {\n        event.manager.channel().pipeline().addBefore(\"packet_handler\", \"danker_packet_handler\", new PacketHandler());\n        System.out.println(\"Added packet handler to channel pipeline.\");\n    }\n\n    // misc feature ig\n\n    public static void onAbilityKey() {\n        if (!Utils.isInDungeons()) return;\n        Minecraft.getMinecraft().thePlayer.dropOneItem(true);\n    }\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/CrystalHollowWaypointCommand.java",
    "content": "package me.Danker.commands;\n\nimport me.Danker.features.CrystalHollowWaypoints;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\n\nimport java.util.Arrays;\n\npublic class CrystalHollowWaypointCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"dsmaddcrystalhollowwaypoints\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" <formatted waypoint>\";\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        if (arg1.length == 0) return;\n\n        if (arg1.length > 4 && arg1[0].equals(\"st\")) {\n            String name = String.join(\" \", Arrays.copyOfRange(arg1, 4, arg1.length));\n            CrystalHollowWaypoints.addWaypoint(name, arg1[1], arg1[2], arg1[3], false);\n        } else {\n            CrystalHollowWaypoints.addDSMWaypoints(String.join(\" \", arg1), false, false);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/DHelpCommand.java",
    "content": "package me.Danker.commands;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.commands.api.*;\nimport me.Danker.commands.loot.DisplayCommand;\nimport me.Danker.commands.loot.ImportFishingCommand;\nimport me.Danker.commands.loot.LootCommand;\nimport me.Danker.commands.loot.ResetLootCommand;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\npublic class DHelpCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"dhelp\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName();\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n    \n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        EntityPlayer player = (EntityPlayer) arg0;\n        \n        player.addChatMessage(new ChatComponentText(\"\\n\" + EnumChatFormatting.GOLD + \" \" + DankersSkyblockMod.MODID + \" Version \" + DankersSkyblockMod.VERSION + \"\\n\" +\n                                                    EnumChatFormatting.AQUA + \" <> = Mandatory parameter. [] = Optional parameter.\\n\" +\n                                                    EnumChatFormatting.GOLD + \" Commands, \" + EnumChatFormatting.GREEN + \" Keybinds.\\n\" +\n                                                    EnumChatFormatting.GOLD + getCommandUsage(arg0) + EnumChatFormatting.AQUA + \" - Returns this message.\\n\" +\n                                                    EnumChatFormatting.GOLD + DankerGuiCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Opens the GUI for Danker's Skyblock Mod.\\n\" +\n                                                    EnumChatFormatting.GOLD + LootCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Returns loot received from slayer quests or fishing stats. /loot fishing winter returns winter sea creatures instead.\\n\" +\n                                                    EnumChatFormatting.GOLD + DisplayCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Text display for trackers. /display fishing winter displays winter sea creatures instead. /display auto automatically displays the loot for the slayer quest you have active.\\n\" +\n                                                    EnumChatFormatting.GOLD + ResetLootCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Resets loot for trackers. /resetloot confirm confirms the reset.\\n\" +\n                                                    EnumChatFormatting.GOLD + SlayerCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to get slayer xp of a person. If no name is provided, it checks yours.\\n\" +\n                                                    EnumChatFormatting.GOLD + SkillsCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to get skill levels of a person. If no name is provided, it checks yours.\\n\" +\n                                                    EnumChatFormatting.GOLD + LobbySkillsCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to find the average skills of the lobby, as well the three players with the highest skill average.\\n\" +\n                                                    EnumChatFormatting.GOLD + GuildOfCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to get guild name and guild master of a person. If no name is provided, it checks yours.\\n\" +\n                                                    EnumChatFormatting.GOLD + PetsCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to get pets of a person. If no name is provided, it checks yours.\\n\" +\n                                                    EnumChatFormatting.GOLD + BankCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to get bank and purse coins of a person. If no name is provided, it checks yours.\\n\" +\n                                                    EnumChatFormatting.GOLD + ArmourCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to get armor of a person. If no name is provided, it checks yours.\\n\" +\n                                                    EnumChatFormatting.GOLD + DungeonsCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to get dungeon levels of a person. If no name is provided, it checks yours.\\n\" +\n                                                    EnumChatFormatting.GOLD + WeightCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to get weight of a person. If no name is provided, it checks yours. Adding lily uses lily's weight instead of Senither's.\\n\" +\n                                                    EnumChatFormatting.GOLD + ImportFishingCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Imports your fishing stats from your latest profile to your fishing tracker using the API.\\n\" +\n                                                    EnumChatFormatting.GOLD + SkyblockPlayersCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to find how many players are on each Skyblock island.\\n\" +\n                                                    EnumChatFormatting.GOLD + SkillTrackerCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Text display for skill xp/hour.\\n\" +\n                                                    EnumChatFormatting.GOLD + LobbyBankCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to find the average bank total of the lobby, as well the three players with the highest total money in the bank(and purse).\\n\" +\n                                                    EnumChatFormatting.GOLD + RepartyCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Disbands and reparties all members in the party.\\n\" +\n                                                    EnumChatFormatting.GOLD + PlayerCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to find skills, slayers, coins and weight of a player.\\n\" +\n                                                    EnumChatFormatting.GOLD + ReloadConfigCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Reloads Danker's Skyblock Mod config.\\n\" +\n                                                    EnumChatFormatting.GOLD + ReloadRepoCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Reloads Danker's Skyblock Mod repository.\\n\" +\n                                                    EnumChatFormatting.GOLD + HOTMCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to find total powder and HotM tree of a person. If no name is provided, it checks yours.\\n\" +\n                                                    EnumChatFormatting.GOLD + TrophyFishCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Uses API to find trophy fish stats of a person. If no name is provided, it checks yours.\\n\" +\n                                                    EnumChatFormatting.GOLD + StopLobbyCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Stops currently running /lobbyskills or /lobbybank command.\\n\" +\n                                                    EnumChatFormatting.GOLD + PowderTrackerCommand.usage(arg0) + EnumChatFormatting.AQUA + \" - Text display for powder/hour.\\n\" +\n                                                    EnumChatFormatting.GREEN + \"Open Maddox Menu\" + EnumChatFormatting.AQUA + \" - M by default.\\n\" +\n                                                    EnumChatFormatting.GREEN + \"Regular Ability\" + EnumChatFormatting.AQUA + \" - Numpad 4 by default.\\n\" +\n                                                    EnumChatFormatting.GREEN + \"Start/Stop Skill Tracker\" + EnumChatFormatting.AQUA + \" - Numpad 5 by default.\\n\" +\n                                                    EnumChatFormatting.GREEN + \"Create Waypoint\" + EnumChatFormatting.AQUA + \" - Numpad 6 by default.\\n\" +\n                                                    EnumChatFormatting.GREEN + \"Start/Stop Powder Tracker\" + EnumChatFormatting.AQUA + \" - Numpad 8 by default.\\n\"));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/DankerGuiCommand.java",
    "content": "package me.Danker.commands;\n\nimport cc.polyfrost.oneconfig.utils.IOUtils;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.features.loot.LootDisplay;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.resources.ResourcePackRepository;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.StringUtils;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class DankerGuiCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"dsm\";\n    }\n\n    @Override\n    public List<String> getCommandAliases() {\n        return Collections.singletonList(\"dankersskyblockmod\");\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName();\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new DankerGuiCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n    \n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        if (arg1.length > 0 && arg1[0].equalsIgnoreCase(\"debug\")) {\n            StringBuilder debug = new StringBuilder();\n            debug.append(\"```md\\n\");\n            debug.append(\"# Other Settings\\n\");\n            debug.append(\"[Current Display][\").append(ModConfig.getDisplay()).append(\"]\\n\");\n            debug.append(\"[Auto Display][\").append(LootDisplay.autoDisplay).append(\"]\\n\");\n            debug.append(\"[Skill Tracker Visible][\").append(ModConfig.skillTrackerHud.isEnabled()).append(\"]\\n\");\n            debug.append(\"[Farm Length X][\").append(ModConfig.farmMinX).append(\" to \").append(ModConfig.farmMaxX).append(\"]\\n\");\n            debug.append(\"[Farm Length Z][\").append(ModConfig.farmMinZ).append(\" to \").append(ModConfig.farmMaxZ).append(\"]\\n\");\n            debug.append(\"# Problematic Mods\\n\");\n            debug.append(\"[LabyMod][\").append(DankersSkyblockMod.usingLabymod).append(\"]\\n\");\n            debug.append(\"[OAM][\").append(DankersSkyblockMod.usingOAM).append(\"]\\n\");\n            debug.append(\"# Resource Packs\\n\");\n            if (Minecraft.getMinecraft().getResourcePackRepository().getRepositoryEntries().size() == 0) {\n                debug.append(\"<None>\\n\");\n            } else {\n                for (ResourcePackRepository.Entry resource : Minecraft.getMinecraft().getResourcePackRepository().getRepositoryEntries()) {\n                    debug.append(\"<\").append(StringUtils.stripControlCodes(resource.getResourcePackName())).append(\">\\n\");\n                }\n            }\n            debug.append(\"```\");\n            IOUtils.copyStringToClipboard(debug.toString());\n            Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Debug stats copied to clipboard.\"));\n            return;\n        }\n\n        DankersSkyblockMod.config.openGui();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/PowderTrackerCommand.java",
    "content": "package me.Danker.commands;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.features.PowderTracker;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\n\nimport java.util.List;\n\npublic class PowderTrackerCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"powdertracker\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" <start/stop/reset>\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new PowderTrackerCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return getListOfStringsMatchingLastWord(args, \"start\", \"resume\", \"pause\", \"stop\", \"reset\");\n        }\n        return null;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        EntityPlayer player = (EntityPlayer) arg0;\n\n        if (arg1.length < 1) {\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: \" + getCommandUsage(arg0)));\n            return;\n        }\n\n        switch (arg1[0].toLowerCase()) {\n            case \"start\":\n            case \"resume\":\n                if (PowderTracker.powderStopwatch.isStarted() && PowderTracker.powderStopwatch.isSuspended()) {\n                    PowderTracker.powderStopwatch.resume();\n                } else if (!PowderTracker.powderStopwatch.isStarted()) {\n                    PowderTracker.powderStopwatch.start();\n                }\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Powder tracker started.\"));\n                break;\n            case \"pause\":\n            case \"stop\":\n                if (PowderTracker.powderStopwatch.isStarted() && !PowderTracker.powderStopwatch.isSuspended()) {\n                    PowderTracker.powderStopwatch.suspend();\n                } else {\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Powder tracker paused.\"));\n                }\n                break;\n            case \"reset\":\n                PowderTracker.reset();\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Powder tracker reset.\"));\n                break;\n            default:\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: \" + getCommandUsage(arg0)));\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/ReloadConfigCommand.java",
    "content": "package me.Danker.commands;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.PostConfigInitEvent;\nimport me.Danker.handlers.ConfigHandler;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraftforge.common.MinecraftForge;\n\npublic class ReloadConfigCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"reloadconfig\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName();\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new ReloadConfigCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n    \n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        EntityPlayer player = (EntityPlayer)arg0;\n        ConfigHandler.reloadConfig();\n        MinecraftForge.EVENT_BUS.post(new PostConfigInitEvent(DankersSkyblockMod.configDirectory));\n        player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Reloaded config.\"));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/ReloadRepoCommand.java",
    "content": "package me.Danker.commands;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.ChatComponentText;\n\npublic class ReloadRepoCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"reloaddsmrepo\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName();\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new ReloadRepoCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n            Utils.refreshRepo();\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Refreshed Danker's Skyblock Mod repo.\"));\n        }).start();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/RepartyCommand.java",
    "content": "package me.Danker.commands;\n\nimport me.Danker.config.ModConfig;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.GuiNewChat;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommand;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n\npublic class RepartyCommand extends CommandBase implements ICommand {\n    public static boolean gettingParty = false;\n    public static int Delimiter = 0;\n    public static boolean disbanding = false;\n    public static boolean inviting = false;\n    public static boolean failInviting = false;\n    public static List<String> party = new ArrayList<>();\n    public static List<String> repartyFailList = new ArrayList<>();\n    public static Thread partyThread = null;\n\n    @Override\n    public String getCommandName() { \n        return \"reparty\"; \n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender sender) { \n        return \"/\" + getCommandName(); \n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new RepartyCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public List<String> getCommandAliases() {\n        return Collections.singletonList(\"rp\");\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() { \n        return 0; \n    }\n\n    @Override\n    public void processCommand(ICommandSender sender, String[] args) throws CommandException {\n        if (args.length > 0 && (args[0].startsWith(\"fail\") || args[0].equals(\"f\"))) {\n            partyThread = new Thread(() -> {\n                EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;\n                GuiNewChat chat = Minecraft.getMinecraft().ingameGUI.getChatGUI();\n\n\n                try {\n                    player.sendChatMessage(\"/p \" + String.join(\" \", repartyFailList));\n                    String members = String.join(EnumChatFormatting.WHITE + \"\\n- \" + EnumChatFormatting.YELLOW, repartyFailList);\n                    player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                            ModConfig.getColour(ModConfig.mainColour) + \"Partying:\" + EnumChatFormatting.WHITE + \"\\n- \" +\n                            EnumChatFormatting.YELLOW + members + \"\\n\" +\n                            ModConfig.getDelimiter()));\n                    failInviting = true;\n                    while (failInviting) {\n                        Thread.sleep(10);\n                    }\n                    if (repartyFailList.size() > 0) {\n                        String repartyFails = String.join(\"\\n- \" + EnumChatFormatting.RED, repartyFailList);\n                        player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                                ModConfig.getColour(ModConfig.mainColour) + \"Failed to invite:\" + EnumChatFormatting.WHITE + \"\\n- \" +\n                                EnumChatFormatting.RED + repartyFails + \"\\n\" +\n                                ModConfig.getDelimiter()));\n                    }\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n            });\n\n            partyThread.start();\n\n            return;\n        }\n\n        party.clear();\n        repartyFailList.clear();\n\n        // MULTI THREAD DRIFTING\n        partyThread = new Thread(() -> {\n            EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;\n\n\n            try {\n                player.sendChatMessage(\"/pl\");\n                gettingParty = true;\n                while (gettingParty) {\n                    Thread.sleep(10);\n                }\n                if (party.size() == 0) return;\n                player.sendChatMessage(\"/p disband\");\n                disbanding = true;\n                while (disbanding) {\n                    Thread.sleep(10);\n                }\n                String members = String.join(EnumChatFormatting.WHITE + \"\\n- \" + EnumChatFormatting.YELLOW, RepartyCommand.party);\n                player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                        ModConfig.getColour(ModConfig.mainColour) + \"Repartying:\" + EnumChatFormatting.WHITE + \"\\n- \" +\n                        EnumChatFormatting.YELLOW + members + \"\\n\" +\n                        ModConfig.getDelimiter()));\n                repartyFailList = new ArrayList<>(party);\n                for (String invitee : party) {\n                    player.sendChatMessage(\"/p \" + invitee);\n                    inviting = true;\n                    while (inviting) {\n                        Thread.sleep(10);\n                    }\n                    Thread.sleep(100);\n                }\n                while (inviting) {\n                    Thread.sleep(10);\n                }\n                if (repartyFailList.size() > 0) {\n                    String repartyFails = String.join(\"\\n- \" + EnumChatFormatting.RED, repartyFailList);\n                    player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                            ModConfig.getColour(ModConfig.mainColour) + \"Failed to invite:\" + EnumChatFormatting.WHITE + \"\\n- \" +\n                            EnumChatFormatting.RED + repartyFails + \"\\n\" +\n                            ModConfig.getDelimiter()));\n                }\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n        });\n\n        partyThread.start();\n    }\n}"
  },
  {
    "path": "src/main/java/me/Danker/commands/SkillTrackerCommand.java",
    "content": "package me.Danker.commands;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.features.SkillTracker;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport org.apache.commons.lang3.time.StopWatch;\n\nimport java.util.List;\n\npublic class SkillTrackerCommand extends CommandBase {\n    public static boolean running = false;\n\n    @Override\n    public String getCommandName() {\n        return \"skilltracker\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" <start/stop/reset/show/hide>\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new SkillTrackerCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n    \n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return getListOfStringsMatchingLastWord(args, \"start\", \"resume\", \"pause\", \"stop\", \"reset\");\n        }\n        return null;\n    }\n    \n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n            \n            if (arg1.length < 1) {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: \" + getCommandUsage(arg0)));\n                return;\n            }\n            \n            try {\n                Thread.sleep(50);\n\n                switch (arg1[0].toLowerCase()) {\n                    case \"start\":\n                    case \"resume\":\n                        if (SkillTracker.skillStopwatch.isStarted() && SkillTracker.skillStopwatch.isSuspended()) {\n                            SkillTracker.skillStopwatch.resume();\n                        } else if (!SkillTracker.skillStopwatch.isStarted()) {\n                            SkillTracker.skillStopwatch.start();\n                        }\n                        player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Skill tracker started.\"));\n                        break;\n                    case \"pause\":\n                    case \"stop\":\n                        if (SkillTracker.skillStopwatch.isStarted() && !SkillTracker.skillStopwatch.isSuspended()) {\n                            SkillTracker.skillStopwatch.suspend();\n                        } else {\n                            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Skill tracker paused.\"));\n                        }\n                        break;\n                    case \"reset\":\n                        SkillTracker.skillStopwatch = new StopWatch();\n                        SkillTracker.farmingXPGained = 0;\n                        SkillTracker.miningXPGained = 0;\n                        SkillTracker.combatXPGained = 0;\n                        SkillTracker.foragingXPGained = 0;\n                        SkillTracker.fishingXPGained = 0;\n                        SkillTracker.enchantingXPGained = 0;\n                        SkillTracker.alchemyXPGained = 0;\n                        player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Skill tracker reset.\"));\n                        break;\n                    default:\n                        player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: \" + getCommandUsage(arg0)));\n                }\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n        }).start();\n    }\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/StopLobbyCommand.java",
    "content": "package me.Danker.commands;\n\nimport me.Danker.commands.api.LobbyBankCommand;\nimport me.Danker.commands.api.LobbySkillsCommand;\nimport me.Danker.config.ModConfig;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.ChatComponentText;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class StopLobbyCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"stoplobby\";\n    }\n\n    @Override\n    public List<String> getCommandAliases() {\n        return Collections.singletonList(\"stoplb\");\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender sender) {\n        return \"/\" + getCommandName();\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new StopLobbyCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public void processCommand(ICommandSender sender, String[] args) throws CommandException {\n        EntityPlayer player = (EntityPlayer) sender;\n        if (LobbySkillsCommand.mainThread != null && LobbySkillsCommand.mainThread.isAlive()) {\n            LobbySkillsCommand.mainThread.interrupt();\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Stopped running /lobbyskills. See logs for progress.\"));\n        }\n        if (LobbyBankCommand.mainThread != null && LobbyBankCommand.mainThread.isAlive()) {\n            LobbyBankCommand.mainThread.interrupt();\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Stopped running /lobbybank. See logs for progress.\"));\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/ArmourCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.nbt.CompressedStreamTools;\nimport net.minecraft.nbt.NBTTagCompound;\nimport net.minecraft.nbt.NBTTagList;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class ArmourCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"armor\";\n    }\n    \n    @Override\n    public List<String> getCommandAliases() {\n        return Collections.singletonList(\"armour\");\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" [name]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new ArmourCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n    \n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return Utils.getMatchingPlayers(args[0]);\n        }\n        return null;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n            \n            // Get UUID for Hypixel API requests\n            String username;\n            String uuid;\n            if (arg1.length == 0) {\n                username = player.getName();\n                uuid = player.getUniqueID().toString().replaceAll(\"[\\\\-]\", \"\");\n            } else {\n                username = arg1[0];\n                uuid = APIHandler.getUUID(username);\n            }\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking armor of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using Polyfrost's API.\"));\n            \n            // Find stats of latest profile\n            JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(uuid);\n            if (profileResponse == null) return;\n\n            String armourBase64 = Utils.getObjectFromPath(profileResponse, \"members.\" + uuid + \".inventory.inv_armor\").get(\"data\").getAsString();\n            InputStream armourStream = new ByteArrayInputStream(Base64.getDecoder().decode(armourBase64));\n            // String armourDecodedGZIP = new String(Base64.getDecoder().decode(armourBase64));\n            \n            try {\n                NBTTagCompound armour = CompressedStreamTools.readCompressed(armourStream);\n                NBTTagList armourList = armour.getTagList(\"i\", 10);\n                \n                String helmet = EnumChatFormatting.RED + \"None\";\n                String chest = EnumChatFormatting.RED + \"None\";\n                String legs = EnumChatFormatting.RED + \"None\";\n                String boots = EnumChatFormatting.RED + \"None\";\n                // Loop through armour\n                for (int i = 0; i < armourList.tagCount(); i++) {\n                    NBTTagCompound armourPiece = armourList.getCompoundTagAt(i);\n                    if (armourPiece.hasNoTags()) continue;\n                    \n                    String armourPieceName = armourPiece.getCompoundTag(\"tag\").getCompoundTag(\"display\").getString(\"Name\");\n                    // NBT is served boots -> helmet\n                    switch (i) {\n                        case 0:\n                            boots = armourPieceName;\n                            break;\n                        case 1:\n                            legs = armourPieceName;\n                            break;\n                        case 2:\n                            chest = armourPieceName;\n                            break;\n                        case 3:\n                            helmet = armourPieceName;\n                            break;\n                        default:\n                            System.err.println(\"An error has occurred.\");\n                            break;\n                    }\n                }\n                armourStream.close();\n                \n                player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + \" \" + username + \"'s Armour:\\n\" +\n                                                            ModConfig.getColour(ModConfig.typeColour) + \" Helmet:      \" + helmet + \"\\n\" +\n                                                            ModConfig.getColour(ModConfig.typeColour) + \" Chestplate: \" + chest + \"\\n\" +\n                                                            ModConfig.getColour(ModConfig.typeColour) + \" Leggings:   \" + legs + \"\\n\" +\n                                                            ModConfig.getColour(ModConfig.typeColour) + \" Boots:       \" + boots + \"\\n\" +\n                                                            ModConfig.getDelimiter()));\n            } catch (IOException ex) {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"An error has occurred while reading inventory data. See logs for more info.\"));\n                ex.printStackTrace();\n            }\n        }).start();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/BankCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.common.collect.ImmutableList;\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.text.NumberFormat;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class BankCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"bankof\";\n    }\n    \n    @Override\n    public List<String> getCommandAliases() {\n        return ImmutableList.of(\"purse\", \"coins\");\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" [name]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new BankCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return Utils.getMatchingPlayers(args[0]);\n        }\n        return null;\n    }\n    \n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n            \n            // Get UUID for Hypixel API requests\n            String username;\n            String uuid;\n            if (arg1.length == 0) {\n                username = player.getName();\n                uuid = player.getUniqueID().toString().replaceAll(\"[\\\\-]\", \"\");\n            } else {\n                username = arg1[0];\n                uuid = APIHandler.getUUID(username);\n            }\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking coins of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using Polyfrost's API.\"));\n            \n            // Find stats of latest profile\n            JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(uuid);\n            if (profileResponse == null) return;\n            \n            System.out.println(\"Fetching bank + purse coins...\");\n            double purseCoins = Utils.getObjectFromPath(profileResponse, \"members.\" + uuid + \".currencies\").get(\"coin_purse\").getAsDouble();\n            purseCoins = Math.floor(purseCoins * 100.0) / 100.0;\n            NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);\n            \n            // Check for bank api\n            if (profileResponse.has(\"banking\")) {\n                double bankCoins = profileResponse.getAsJsonObject(\"banking\").get(\"balance\").getAsDouble();\n                bankCoins = Math.floor(bankCoins * 100.0) / 100.0;\n                \n                player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + \" \" + username + \"'s Coins:\\n\" +\n                                                            ModConfig.getColour(ModConfig.typeColour) + \" Bank: \" + EnumChatFormatting.GOLD + nf.format(bankCoins) + \"\\n\" +\n                                                            ModConfig.getColour(ModConfig.typeColour) + \" Purse: \" + EnumChatFormatting.GOLD + nf.format(purseCoins) + \"\\n\" +\n                                                            ModConfig.getColour(ModConfig.typeColour) + \" Total: \" + EnumChatFormatting.GOLD + nf.format(bankCoins + purseCoins) + \"\\n\" +\n                                                            ModConfig.getDelimiter()));\n            } else {\n                player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + \" \" + username + \"'s Coins:\\n\" +\n                                                            ModConfig.getColour(ModConfig.typeColour) + \" Bank: \" + EnumChatFormatting.RED + \"Bank API disabled.\\n\" +\n                                                            ModConfig.getColour(ModConfig.typeColour) + \" Purse: \" + EnumChatFormatting.GOLD + nf.format(purseCoins) + \"\\n\" +\n                                                            ModConfig.getDelimiter()));\n            }\n        }).start();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/DungeonsCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.event.HoverEvent;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.MathHelper;\n\nimport java.text.NumberFormat;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class DungeonsCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"dungeons\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" [name]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new DungeonsCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n    \n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return Utils.getMatchingPlayers(args[0]);\n        }\n        return null;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n            \n            // Get UUID for Hypixel API requests\n            String username;\n            String uuid;\n            if (arg1.length == 0) {\n                username = player.getName();\n                uuid = player.getUniqueID().toString().replaceAll(\"[\\\\-]\", \"\");\n            } else {\n                username = arg1[0];\n                uuid = APIHandler.getUUID(username);\n            }\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking dungeon stats of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using Polyfrost's API.\"));\n\n            // Find stats of latest profile\n            JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(uuid);\n            if (profileResponse == null) return;\n\n            System.out.println(\"Fetching player data...\");\n            JsonObject playerResponse = HypixelAPIHandler.getJsonObjectAuth(HypixelAPIHandler.URL + \"player/\" + uuid);\n\n            if (playerResponse == null) {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Could not connect to API.\"));\n                return;\n            }\n            if (!playerResponse.get(\"success\").getAsBoolean()) {\n                String reason = playerResponse.get(\"cause\").getAsString();\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Failed with reason: \" + reason));\n                return;\n            }\n            \n            System.out.println(\"Fetching dungeon stats...\");\n            JsonObject dungeonsObject = Utils.getObjectFromPath(profileResponse, \"members.\" + uuid + \".dungeons\");\n            JsonObject catacombsObject = Utils.getObjectFromPath(dungeonsObject, \"dungeon_types.catacombs\");\n            if (!catacombsObject.has(\"experience\")) {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"This player has not played dungeons.\"));\n                return;\n            }\n\n            double catacombs = Utils.xpToDungeonsLevel(catacombsObject.get(\"experience\").getAsDouble());\n            double healer = getClassLevel(dungeonsObject, \"healer\");\n            double mage = getClassLevel(dungeonsObject, \"mage\");\n            double berserk = getClassLevel(dungeonsObject, \"berserk\");\n            double archer = getClassLevel(dungeonsObject, \"archer\");\n            double tank = getClassLevel(dungeonsObject, \"tank\");\n            double classAverage = Math.round((healer + mage + berserk + archer + tank) / 5D * 100D) / 100D;\n            String selectedClass = Utils.capitalizeString(dungeonsObject.get(\"selected_dungeon_class\").getAsString());\n\n            int secrets = 0;\n            JsonObject achievementsObj = Utils.getObjectFromPath(playerResponse, \"player.achievements\");\n            if (achievementsObj.has(\"skyblock_treasure_hunter\")) {\n                secrets = achievementsObj.get(\"skyblock_treasure_hunter\").getAsInt();\n            }\n\n            int highestFloor = 0;\n            if (catacombsObject.has(\"highest_tier_completed\")) {\n                highestFloor = catacombsObject.get(\"highest_tier_completed\").getAsInt();\n            }\n            JsonObject completionObj = catacombsObject.getAsJsonObject(\"tier_completions\");\n\n            JsonObject catacombsMasterObject = Utils.getObjectFromPath(dungeonsObject, \"dungeon_types.master_catacombs\");\n            boolean hasPlayedMaster = catacombsMasterObject.has(\"highest_tier_completed\");\n\n            int highestMasterFloor = 0;\n            JsonObject completionMasterObj = null;\n            if (hasPlayedMaster) {\n                highestMasterFloor = catacombsMasterObject.get(\"highest_tier_completed\").getAsInt();\n                completionMasterObj = catacombsMasterObject.getAsJsonObject(\"tier_completions\");\n            }\n\n            ChatComponentText classLevels = new ChatComponentText(EnumChatFormatting.GOLD + \" Selected Class: \" + selectedClass + \"\\n\\n\" +\n                                                                  EnumChatFormatting.RED + \" Catacombs Level: \" + catacombs + \"\\n\" +\n                                                                  EnumChatFormatting.RED + \" Class Average: \" + classAverage + \"\\n\\n\" +\n                                                                  EnumChatFormatting.YELLOW + \" Healer Level: \" + healer + \"\\n\" +\n                                                                  EnumChatFormatting.LIGHT_PURPLE + \" Mage Level: \" + mage + \"\\n\" +\n                                                                  EnumChatFormatting.RED + \" Berserk Level: \" + berserk + \"\\n\" +\n                                                                  EnumChatFormatting.GREEN + \" Archer Level: \" + archer + \"\\n\" +\n                                                                  EnumChatFormatting.BLUE + \" Tank Level: \" + tank + \"\\n\\n\" +\n                                                                  EnumChatFormatting.WHITE + \" Secrets Found: \" + NumberFormat.getIntegerInstance(Locale.US).format(secrets) + \"\\n\\n\");\n\n            StringBuilder completionsHoverString = new StringBuilder();\n            for (int i = 0; i <= highestFloor; i++) {\n                completionsHoverString\n                    .append(EnumChatFormatting.GOLD)\n                    .append(i == 0 ? \"Entrance: \" : \"Floor \" + i + \": \")\n                    .append(EnumChatFormatting.RESET)\n                    .append(completionObj.get(String.valueOf(i)).getAsInt())\n                    .append(i < highestFloor || hasPlayedMaster ? \"\\n\": \"\");\n            }\n            for (int i = 1; i <= highestMasterFloor; i++) {\n                if (completionMasterObj != null && completionMasterObj.has(String.valueOf(i))) {\n                    completionsHoverString\n                        .append(EnumChatFormatting.GOLD)\n                        .append(\"Master Floor \")\n                        .append(i)\n                        .append(\": \")\n                        .append(EnumChatFormatting.RESET)\n                        .append(completionMasterObj.get(String.valueOf(i)).getAsInt())\n                        .append(i < highestMasterFloor ? \"\\n\": \"\");\n                }\n            }\n\n            ChatComponentText completions;\n            if (hasPlayedMaster) {\n                completions = new ChatComponentText(EnumChatFormatting.GOLD + \" Highest Floor Completed: Master \" + highestMasterFloor);\n            } else {\n                completions = new ChatComponentText(EnumChatFormatting.GOLD + \" Highest Floor Completed: \" + highestFloor);\n            }\n            completions.setChatStyle(completions.getChatStyle().setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(completionsHoverString.toString()))));\n\n            player.addChatMessage(\n                    new ChatComponentText(ModConfig.getDelimiter())\n                    .appendText(\"\\n\")\n                    .appendSibling(classLevels)\n                    .appendSibling(completions)\n                    .appendText(\"\\n\")\n                    .appendSibling(new ChatComponentText(ModConfig.getDelimiter())));\n        }).start();\n    }\n\n    double getClassLevel(JsonObject obj, String dungeonClass) {\n        JsonObject clazz = Utils.getObjectFromPath(obj, \"player_classes.\" + dungeonClass);\n        if (clazz != null) {\n            if (clazz.has(\"experience\")) {\n                double xp = clazz.get(\"experience\").getAsDouble();\n                return MathHelper.clamp_double(Utils.xpToDungeonsLevel(xp), 0D, 50D);\n            }\n        }\n\n        return 0D;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/FairySoulsCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\n\nimport java.util.List;\n\npublic class FairySoulsCommand extends CommandBase {\n    @Override\n    public String getCommandName() {\n        return \"fairysouls\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender sender) {\n        return \"/\" + getCommandName() + \" [name]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new FairySoulsCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return Utils.getMatchingPlayers(args[0]);\n        }\n        return null;\n    }\n\n    @Override\n    public void processCommand(ICommandSender sender, String[] args) throws CommandException {\n        EntityPlayer player = ((EntityPlayer) sender);\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n\n            // Get UUID for Hypixel API requests\n            String username;\n            String uuid;\n            if (args.length == 0) {\n                username = player.getName();\n                uuid = APIHandler.getUUID(username);\n            } else {\n                username = args[0];\n                uuid = APIHandler.getUUID(username);\n            }\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking fairy souls of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using Polyfrost's API.\"));\n\n            // Find fairy souls of latest profile\n            JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(uuid);\n            if (profileResponse == null) return;\n\n            // Extracting the fairy souls from the json data\n            System.out.println(\"Fetching fairy souls\");\n            int fairySouls = Utils.getObjectFromPath(profileResponse, \"members.\" + uuid + \".fairy_soul\").get(\"total_collected\").getAsInt();\n\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" has \" + ModConfig.getColour(ModConfig.valueColour) + fairySouls + ModConfig.getColour(ModConfig.mainColour) + \"/243 collected\"));\n        }).start();\n\n    }\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/GuildOfCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.util.List;\n\npublic class GuildOfCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"guildof\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" [name]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new GuildOfCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n    \n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return Utils.getMatchingPlayers(args[0]);\n        }\n        return null;\n    }\n    \n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n            \n            // Get UUID for Hypixel API requests\n            String username;\n            String uuid;\n            if (arg1.length == 0) {\n                username = player.getName();\n                uuid = player.getUniqueID().toString().replaceAll(\"[\\\\-]\", \"\");\n            } else {\n                username = arg1[0];\n                uuid = APIHandler.getUUID(username);\n            }\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking guild of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using Polyfrost's API.\"));\n            \n            // Find guild ID\n            System.out.println(\"Fetching guild...\");\n            JsonObject guildResponse = HypixelAPIHandler.getJsonObjectAuth(HypixelAPIHandler.URL + \"guild/\" + uuid);\n\n            if (guildResponse == null) {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Could not connect to API.\"));\n                return;\n            }\n            if (!guildResponse.get(\"success\").getAsBoolean()) {\n                String reason = guildResponse.get(\"cause\").getAsString();\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Failed with reason: \" + reason));\n                return;\n            }\n            \n            System.out.println(\"Fetching guild stats and members...\");\n            \n            String guildName = \"N/A\";\n            String guildMaster = \"N/A\";\n            int players = 0;\n            // Check if player is in guild\n            if (!guildResponse.get(\"guild\").isJsonNull()) {\n                guildName = guildResponse.getAsJsonObject(\"guild\").get(\"name\").getAsString();\n                \n                // Loop through members to find guildmaster\n                JsonArray guildMembers = guildResponse.getAsJsonObject(\"guild\").getAsJsonArray(\"members\");\n                players = guildMembers.size();\n                for (JsonElement member : guildMembers) {\n                    JsonObject memberObject = member.getAsJsonObject();\n                    String memberRank = memberObject.get(\"rank\").getAsString();\n                    \n                    if (memberRank.equals(\"GUILDMASTER\") || memberRank.equals(\"Guild Master\")) {\n                        // Get username from UUID\n                        String gmUUID = memberObject.get(\"uuid\").getAsString();\n                        guildMaster = APIHandler.getName(gmUUID);\n                        break;\n                    }\n                }\n            }\n            \n            player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                                                        EnumChatFormatting.AQUA + \" \" + username + \"'s Guild:\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Guild: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + guildName + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Guildmaster: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + guildMaster + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Members: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + players + \"\\n\" +\n                                                        ModConfig.getDelimiter()));\n        }).start();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/HOTMCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.event.ClickEvent;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.text.NumberFormat;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class HOTMCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"hotmof\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" [name]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new HOTMCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return Utils.getMatchingPlayers(args[0]);\n        }\n        return null;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n\n            // Get UUID for Hypixel API requests\n            String username;\n            String uuid;\n            if (arg1.length == 0) {\n                username = player.getName();\n                uuid = player.getUniqueID().toString().replaceAll(\"[\\\\-]\", \"\");\n            } else {\n                username = arg1[0];\n                uuid = APIHandler.getUUID(username);\n            }\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking HotM of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using Polyfrost's API.\"));\n\n            // Find stats of latest profile\n            JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(uuid);\n            if (profileResponse == null) return;\n\n            String latestProfileID = HypixelAPIHandler.getLatestProfileID(uuid);\n            if (latestProfileID == null) return;\n\n            System.out.println(\"Fetching mining stats...\");\n            JsonObject miningCore = Utils.getObjectFromPath(profileResponse, \"members.\" + uuid + \".mining_core\");\n\n            int mithril = 0;\n            if (miningCore.has(\"powder_mithril\")) {\n                mithril = miningCore.get(\"powder_mithril\").getAsInt();\n                if (miningCore.has(\"powder_spent_mithril\")) mithril += miningCore.get(\"powder_spent_mithril\").getAsInt();\n            }\n\n            int gemstone = 0;\n            if (miningCore.has(\"powder_gemstone\")) {\n                gemstone = miningCore.get(\"powder_gemstone\").getAsInt();\n                if (miningCore.has(\"powder_spent_gemstone\")) gemstone += miningCore.get(\"powder_spent_gemstone\").getAsInt();\n            }\n\n            int glacite = 0;\n            if (miningCore.has(\"powder_glacite\")) {\n                glacite = miningCore.get(\"powder_glacite\").getAsInt();\n                if (miningCore.has(\"powder_spent_glacite\")) glacite += miningCore.get(\"powder_spent_glacite\").getAsInt();\n            }\n\n            String ability = EnumChatFormatting.RED + \"None\";\n            if (miningCore.has(\"selected_pickaxe_ability\")) {\n                if (miningCore.get(\"selected_pickaxe_ability\").isJsonNull()) {\n                    ability = EnumChatFormatting.RED + \"None\";\n                } else {\n                    ability = Node.valueOf(miningCore.get(\"selected_pickaxe_ability\").getAsString()).name;\n                }\n            }\n\n            ChatComponentText tree = new ChatComponentText(EnumChatFormatting.GREEN + \"\" + EnumChatFormatting.BOLD + \"[CLICK]\");\n            tree.setChatStyle(tree.getChatStyle().setChatClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, \"/hotmtree \" + username + \" \" + latestProfileID)));\n\n            NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);\n            player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                                                        EnumChatFormatting.AQUA + username + \"'s HotM:\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \"Mithril Powder: \" + EnumChatFormatting.DARK_GREEN + nf.format(mithril) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \"Gemstone Powder: \" + EnumChatFormatting.LIGHT_PURPLE + nf.format(gemstone) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \"Glacite Powder: \" + EnumChatFormatting.AQUA + nf.format(glacite) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \"Pickaxe Ability: \" + ModConfig.getColour(ModConfig.valueColour) + ability + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \"HotM Tree: \").appendSibling(tree)\n                                                        .appendSibling(new ChatComponentText(\"\\n\" + ModConfig.getDelimiter())));\n        }).start();\n    }\n\n    enum Node {\n        mining_speed_boost(\"Mining Speed Boost\"),\n        pickaxe_toss(\"Pickobulus\"),\n        vein_seeker(\"Vein Seeker\"),\n        maniac_miner(\"Maniac Miner\"),\n        gemstone_infusion(\"Gemstone Infusion\"),\n        hazardous_miner(\"Hazardous Miner\");\n\n        public final String name;\n\n        Node(String name) {\n            this.name = name;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/HOTMTreeCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonObject;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.containers.GuiChestDynamic;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.enchantment.Enchantment;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraft.inventory.InventoryBasic;\nimport net.minecraft.item.Item;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.nbt.*;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.ResourceLocation;\nimport net.minecraftforge.common.util.Constants;\n\nimport java.util.ArrayList;\nimport java.util.Base64;\nimport java.util.List;\nimport java.util.UUID;\n\npublic class HOTMTreeCommand extends CommandBase {\n\n    public static GuiChestDynamic chest = null;\n\n    @Override\n    public String getCommandName() {\n        return \"hotmtree\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return null;\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking HotM tree of \" + ModConfig.getColour(ModConfig.secondaryColour) + arg1[0] + ModConfig.getColour(ModConfig.mainColour) + \" using Polyfrost's API.\"));\n\n            System.out.println(\"Fetching profile...\");\n            String profileURL = \"https://sky.shiiyu.moe/api/v2/profile/\" + arg1[0];\n            JsonObject profileResponse = APIHandler.getResponse(profileURL, true);\n            if (profileResponse.has(\"error\")) {\n                String reason = profileResponse.get(\"error\").getAsString();\n                player.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + \"Failed with reason: \" + reason));\n                return;\n            }\n\n            System.out.println(\"Fetching HotM tree...\");\n            JsonArray tree = Utils.getObjectFromPath(profileResponse, \"profiles.\" + arg1[1] + \".items\").getAsJsonArray(\"hotm\");\n\n            IInventory inventory = new InventoryBasic(arg1[0] + \"'s HotM Tree:\", true, 63);\n\n            for (JsonElement e : tree) {\n                JsonObject node = e.getAsJsonObject();\n\n                if (!node.has(\"tag\")) continue;\n\n                ItemStack item = new ItemStack(Item.getItemById(node.get(\"id\").getAsInt()), node.get(\"Count\").getAsInt(), node.get(\"Damage\").getAsInt());\n\n                NBTTagCompound nbt;\n                try {\n                    nbt = JsonToNBT.getTagFromJson(node.get(\"tag\").toString());\n                    removeDoubleQuotes(nbt);\n                    nbt.getCompoundTag(\"display\").getTagList(\"Lore\", Constants.NBT.TAG_STRING).removeTag(0);\n                } catch (NBTException ex) {\n                    ex.printStackTrace();\n                    continue;\n                }\n\n                if (node.get(\"glowing\").getAsBoolean()) {\n                    nbt.setTag(\"HideFlags\", new NBTTagShort((short) 1));\n                }\n\n                if (node.has(\"texture_path\")) {\n                    String path = node.get(\"texture_path\").getAsString();\n                    NBTTagCompound skullOwner = new NBTTagCompound();\n                    NBTTagCompound properties = new NBTTagCompound();\n                    NBTTagList textures = new NBTTagList();\n                    NBTTagCompound value = new NBTTagCompound();\n                    String texture = \"{\\\"textures\\\":{\\\"SKIN\\\":{\\\"url\\\":\\\"http://textures.minecraft.net/texture/\" + path.substring(path.lastIndexOf(\"/\") + 1) + \"\\\"}}}\";\n                    value.setTag(\"Value\", new NBTTagString(Base64.getEncoder().encodeToString(texture.getBytes())));\n                    textures.appendTag(value);\n                    properties.setTag(\"textures\", textures);\n                    skullOwner.setTag(\"Properties\", properties);\n                    skullOwner.setTag(\"Id\", new NBTTagString(UUID.randomUUID().toString()));\n                    nbt.setTag(\"SkullOwner\", skullOwner);\n                }\n\n                item.setTagCompound(nbt);\n\n                if (node.get(\"glowing\").getAsBoolean()) {\n                    item.addEnchantment(Enchantment.protection, 1);\n                }\n                item.setStackDisplayName(Utils.removeBold(item.getDisplayName()));\n\n                inventory.setInventorySlotContents(node.get(\"position\").getAsInt() - 1, item);\n            }\n\n            chest = new GuiChestDynamic(player.inventory, inventory, new ResourceLocation(\"dsm\", \"textures/generic_63.png\"));\n            DankersSkyblockMod.guiToOpen = \"hotminventory\";\n        }).start();\n    }\n\n    // https://bitbucket.org/hrznstudio/mo-legacy-edition/src/4cc47b2a792cc2ef19eb7e5db0169706ea2e48dd/src/main/java/matteroverdrive/util/MOJsonHelper.java#lines-164:179\n    public static void removeDoubleQuotes(NBTTagCompound tagCompound) {\n        List<String> cachedKeyList = new ArrayList<>();\n        cachedKeyList.addAll(tagCompound.getKeySet());\n        for (String key : cachedKeyList) {\n            NBTBase base = tagCompound.getTag(key);\n            tagCompound.removeTag(key);\n\n            key = key.replace(\"\\\"\", \"\");\n            if (base instanceof NBTTagCompound) {\n                removeDoubleQuotes((NBTTagCompound) base);\n            } else if (base instanceof NBTTagList) {\n                removeDoubleQuotes((NBTTagList) base);\n            }\n            tagCompound.setTag(key, base);\n        }\n    }\n\n    // https://bitbucket.org/hrznstudio/mo-legacy-edition/src/4cc47b2a792cc2ef19eb7e5db0169706ea2e48dd/src/main/java/matteroverdrive/util/MOJsonHelper.java#lines-181:189\n    public static void removeDoubleQuotes(NBTTagList tagList) {\n        for (int i = 0; i < tagList.tagCount(); i++) {\n            if (tagList.get(i) instanceof NBTTagCompound) {\n                removeDoubleQuotes((NBTTagCompound) tagList.get(i));\n            } else if (tagList.get(i) instanceof NBTTagList) {\n                removeDoubleQuotes((NBTTagList) tagList.get(i));\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/InventoryCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.containers.GuiChestDynamic;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraft.inventory.InventoryBasic;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.nbt.CompressedStreamTools;\nimport net.minecraft.nbt.NBTTagCompound;\nimport net.minecraft.nbt.NBTTagList;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.ResourceLocation;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class InventoryCommand extends CommandBase {\n\n    public static GuiChestDynamic chest = null;\n\n    @Override\n    public String getCommandName() {\n        return \"inventory\";\n    }\n\n    @Override\n    public List<String> getCommandAliases() {\n        return Collections.singletonList(\"inv\");\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" [name]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new InventoryCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return Utils.getMatchingPlayers(args[0]);\n        }\n        return null;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n\n            // Get UUID for Hypixel API requests\n            String username;\n            String uuid;\n            if (arg1.length == 0) {\n                username = player.getName();\n                uuid = player.getUniqueID().toString().replaceAll(\"[\\\\-]\", \"\");\n            } else {\n                username = arg1[0];\n                uuid = APIHandler.getUUID(username);\n            }\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking inventory of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using Polyfrost's API.\"));\n\n            // Find stats of latest profile\n            JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(uuid);\n            if (profileResponse == null) return;\n\n            System.out.println(\"Fetching inventory...\");\n            JsonObject inventoryObject = Utils.getObjectFromPath(profileResponse, \"members.\" + uuid + \".inventory\");\n\n            IInventory inventory = new InventoryBasic(username + \"'s Inventory:\", true, 63);\n\n            ItemStack notEnabled = new ItemStack(Blocks.barrier, 1, 0);\n            notEnabled.setStackDisplayName(EnumChatFormatting.RED + \"Inventory API not enabled.\");\n\n            try {\n                // Armour\n                String armourBase64 = inventoryObject.getAsJsonObject(\"inv_armor\").get(\"data\").getAsString();\n                InputStream armourStream = new ByteArrayInputStream(Base64.getDecoder().decode(armourBase64));\n                NBTTagCompound armour = CompressedStreamTools.readCompressed(armourStream);\n                NBTTagList armourList = armour.getTagList(\"i\", 10);\n\n                for (int i = 0; i < armourList.tagCount(); i++) {\n                    NBTTagCompound item = armourList.getCompoundTagAt(i);\n                    if (item.hasNoTags()) continue;\n                    inventory.setInventorySlotContents(7 - i * 2, ItemStack.loadItemStackFromNBT(item));\n                }\n\n                // Equipment\n                if (inventoryObject.has(\"equipment_contents\")) {\n                    String equipmentBase64 = inventoryObject.getAsJsonObject(\"equipment_contents\").get(\"data\").getAsString();\n                    InputStream equipmentStream = new ByteArrayInputStream(Base64.getDecoder().decode(equipmentBase64));\n                    NBTTagCompound equipment = CompressedStreamTools.readCompressed(equipmentStream);\n                    NBTTagList equipmentList = equipment.getTagList(\"i\", 10);\n\n                    for (int i = 0; i < equipmentList.tagCount(); i++) {\n                        NBTTagCompound item = equipmentList.getCompoundTagAt(i);\n                        if (item.hasNoTags()) continue;\n                        inventory.setInventorySlotContents(i * 2 + 10, ItemStack.loadItemStackFromNBT(item));\n                    }\n                } else {\n                    for (int i = 10; i <= 16; i += 2) {\n                        inventory.setInventorySlotContents(i, notEnabled);\n                    }\n                }\n\n                // Border\n                ItemStack glass = new ItemStack(Blocks.stained_glass_pane, 1, 15);\n                glass.setStackDisplayName(\"\");\n                for (int i = 0; i < 27; i++) {\n                    if (i < 8 && i % 2 == 1) continue;\n                    if (i > 8 && i < 17 && i % 2 == 0) continue;\n                    inventory.setInventorySlotContents(i, glass);\n                }\n\n                // Inventory\n                if (inventoryObject.has(\"inv_contents\")) {\n                    String invBase64 = inventoryObject.getAsJsonObject(\"inv_contents\").get(\"data\").getAsString();\n                    InputStream invStream = new ByteArrayInputStream(Base64.getDecoder().decode(invBase64));\n\n                    NBTTagCompound inv = CompressedStreamTools.readCompressed(invStream);\n                    NBTTagList invList = inv.getTagList(\"i\", 10);\n\n                    for (int i = 0; i < invList.tagCount(); i++) {\n                        NBTTagCompound item = invList.getCompoundTagAt(i);\n                        if (item.hasNoTags()) continue;\n                        inventory.setInventorySlotContents(i < 9 ? i + 54 : i + 18, ItemStack.loadItemStackFromNBT(item));\n                    }\n                } else {\n                    for (int i = 27; i < 63; i++) {\n                        inventory.setInventorySlotContents(i, notEnabled);\n                    }\n                }\n            } catch (IOException ex) {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"An error has occurred while reading inventory data. See logs for more info.\"));\n                ex.printStackTrace();\n            }\n\n            chest = new GuiChestDynamic(player.inventory, inventory, new ResourceLocation(\"dsm\", \"textures/generic_63.png\"));\n            DankersSkyblockMod.guiToOpen = \"inventory\";\n        }).start();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/LobbyBankCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.network.NetworkPlayerInfo;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.text.NumberFormat;\nimport java.util.*;\nimport java.util.stream.Collectors;\n\npublic class LobbyBankCommand extends CommandBase {\n\n    public static Thread mainThread = null;\n\n    @Override\n    public String getCommandName() {\n        return \"lobbybank\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender sender) {\n        return \"/\" + getCommandName();\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new LobbyBankCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public void processCommand(ICommandSender sender, String[] args) throws CommandException {\n        EntityPlayer playerSP = (EntityPlayer) sender;\n        Map<String, Double> unsortedBankList = new HashMap<>();\n        ArrayList<Double> lobbyBanks = new ArrayList<>();\n\n        mainThread = new Thread(() -> {\n            try {\n                // Create deep copy of players to prevent passing reference and ConcurrentModificationException\n                Collection<NetworkPlayerInfo> players = new ArrayList<>(Minecraft.getMinecraft().getNetHandler().getPlayerInfoMap());\n                playerSP.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking bank of lobby using Polyfrost's API. Estimated time: \" + (int) (Utils.getMatchingPlayers(\"\").size() * 1.2 + 1) + \" seconds.\"));\n                // Send request every .6 seconds, leaving room for another 20 requests per minute\n\n                for (NetworkPlayerInfo player : players) {\n                    if (player.getGameProfile().getName().startsWith(\"!\")) continue;\n\n                    Thread.sleep(600);\n\n                    String UUID = player.getGameProfile().getId().toString().replaceAll(\"-\", \"\");\n                    JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(UUID);\n                    if (profileResponse == null) continue;\n\n                    JsonObject purseObj = Utils.getObjectFromPath(profileResponse, \"members.\" + UUID + \".currencies\");\n                    boolean hasBanking = profileResponse.has(\"banking\");\n\n                    double coin_purse;\n                    // Add bank to lobby banks\n                    // Put bank in HashMap\n\n                    if (purseObj.has(\"coin_purse\")) {\n                        coin_purse = purseObj.get(\"coin_purse\").getAsDouble();\n                        if (hasBanking) {\n                            coin_purse += profileResponse.getAsJsonObject(\"banking\").get(\"balance\").getAsDouble();\n                        }\n\n                        unsortedBankList.put(player.getGameProfile().getName(), coin_purse); // Put bank in HashMap\n                        lobbyBanks.add(coin_purse); // Add bank to lobby banks\n                    }\n                }\n\n                // Sort coins\n                Map<String, Double> sortedBankList = unsortedBankList.entrySet().stream()\n                        .sorted(Map.Entry.<String, Double>comparingByValue().reversed())\n                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,\n                                (e1, e2) -> e1, LinkedHashMap::new));\n\n                String[] sortedBankListKeys = sortedBankList.keySet().toArray(new String[0]);\n                String top3 = \"\";\n                NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);\n                for (int i = 0; i < 3 && i < sortedBankListKeys.length; i++) {\n                    top3 += \"\\n \" + EnumChatFormatting.AQUA + sortedBankListKeys[i] + \": \" + ModConfig.getColour(ModConfig.skillAverageColour) + EnumChatFormatting.BOLD + nf.format(Math.round(sortedBankList.get(sortedBankListKeys[i])));\n                }\n\n                // Get lobby bank\n                double lobbyBank = 0;\n                for (Double playerBanks : lobbyBanks) {\n                    lobbyBank += playerBanks;\n                }\n                lobbyBank = (double) Math.round((lobbyBank / lobbyBanks.size()) * 100) / 100;\n\n                // Finally say bank lobby avg and highest bank users\n                playerSP.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \" Lobby Bank Average: \" + ModConfig.getColour(ModConfig.skillAverageColour) + EnumChatFormatting.BOLD + nf.format(Math.round(lobbyBank)) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \" Highest Bank Averages:\" + top3 + \"\\n\" +\n                        ModConfig.getDelimiter()));\n\n\n            } catch (InterruptedException ex) {\n                System.out.println(\"Current bank average list: \" + unsortedBankList);\n                Thread.currentThread().interrupt();\n                System.out.println(\"Interrupted /lobbybank thread.\");\n            }\n\n        });\n        mainThread.start();\n    }\n}"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/LobbySkillsCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.network.NetworkPlayerInfo;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.util.*;\nimport java.util.Map.Entry;\nimport java.util.stream.Collectors;\n\npublic class LobbySkillsCommand extends CommandBase {\n    \n    public static Thread mainThread = null;\n    \n    @Override\n    public String getCommandName() {\n        return \"lobbyskills\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName();\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new LobbySkillsCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        EntityPlayer playerSP = (EntityPlayer) arg0;\n        Map<String, Double> unsortedSAList = new HashMap<>();\n        ArrayList<Double> lobbySkills = new ArrayList<>();\n\n        mainThread = new Thread(() -> {\n            try {\n                // Create deep copy of players to prevent passing reference and ConcurrentModificationException\n                Collection<NetworkPlayerInfo> players = new ArrayList<>(Minecraft.getMinecraft().getNetHandler().getPlayerInfoMap());\n                playerSP.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking skill average of lobby using Polyfrost's API. Estimated time: \" + (int) (Utils.getMatchingPlayers(\"\").size() * 1.2 + 1) + \" seconds.\"));\n                // Send request every .6 seconds, leaving room for another 20 requests per minute\n                \n                for (NetworkPlayerInfo player : players) {\n                    if (player.getGameProfile().getName().startsWith(\"!\")) continue;\n\n                    Thread.sleep(600);\n\n                    String UUID = player.getGameProfile().getId().toString().replaceAll(\"-\", \"\");\n                    JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(UUID);\n                    if (profileResponse == null) continue;\n\n                    JsonObject experienceObj = Utils.getObjectFromPath(profileResponse, \"members.\" + UUID + \".player_data.experience\");\n                    \n                    // Get SA\n                    double farmingLevel = 0;\n                    double miningLevel = 0;\n                    double combatLevel = 0;\n                    double foragingLevel = 0;\n                    double fishingLevel = 0;\n                    double enchantingLevel = 0;\n                    double alchemyLevel = 0;\n                    double tamingLevel = 0;\n                    double carpentryLevel = 0;\n                    \n                    if (experienceObj.has(\"SKILL_FARMING\") || experienceObj.has(\"SKILL_MINING\") || experienceObj.has(\"SKILL_COMBAT\") || experienceObj.has(\"SKILL_FORAGING\") || experienceObj.has(\"SKILL_FISHING\") || experienceObj.has(\"SKILL_ENCHANTING\") || experienceObj.has(\"SKILL_ALCHEMY\")) {\n                        if (experienceObj.has(\"SKILL_FARMING\")) {\n                            farmingLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_FARMING\").getAsDouble(), Utils.getSkillMaxLevel(\"farming\"));\n                            farmingLevel = (double) Math.round(farmingLevel * 100) / 100;\n                        }\n                        if (experienceObj.has(\"SKILL_MINING\")) {\n                            miningLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_MINING\").getAsDouble(), Utils.getSkillMaxLevel(\"mining\"));\n                            miningLevel = (double) Math.round(miningLevel * 100) / 100;\n                        }\n                        if (experienceObj.has(\"SKILL_COMBAT\")) {\n                            combatLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_COMBAT\").getAsDouble(), Utils.getSkillMaxLevel(\"combat\"));\n                            combatLevel = (double) Math.round(combatLevel * 100) / 100;\n                        }\n                        if (experienceObj.has(\"SKILL_FORAGING\")) {\n                            foragingLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_FORAGING\").getAsDouble(), Utils.getSkillMaxLevel(\"foraging\"));\n                            foragingLevel = (double) Math.round(foragingLevel * 100) / 100;\n                        }\n                        if (experienceObj.has(\"SKILL_FISHING\")) {\n                            fishingLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_FISHING\").getAsDouble(), Utils.getSkillMaxLevel(\"fishing\"));\n                            fishingLevel = (double) Math.round(fishingLevel * 100) / 100;\n                        }\n                        if (experienceObj.has(\"SKILL_ENCHANTING\")) {\n                            enchantingLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_ENCHANTING\").getAsDouble(), Utils.getSkillMaxLevel(\"enchanting\"));\n                            enchantingLevel = (double) Math.round(enchantingLevel * 100) / 100;\n                        }\n                        if (experienceObj.has(\"SKILL_ALCHEMY\")) {\n                            alchemyLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_ALCHEMY\").getAsDouble(), Utils.getSkillMaxLevel(\"alchemy\"));\n                            alchemyLevel = (double) Math.round(alchemyLevel * 100) / 100;\n                        }\n                        if (experienceObj.has(\"SKILL_TAMING\")) {\n                            tamingLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_TAMING\").getAsDouble(), Utils.getSkillMaxLevel(\"taming\"));\n                            tamingLevel = (double) Math.round(tamingLevel * 100) / 100;\n                        }\n                        if (experienceObj.has(\"SKILL_CARPENTRY\")) {\n                            carpentryLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_CARPENTRY\").getAsDouble(), Utils.getSkillMaxLevel(\"carpentry\"));\n                            carpentryLevel = (double) Math.round(carpentryLevel * 100) / 100;\n                        }\n                    } else {\n                        Thread.sleep(600); // Sleep for another request\n                        System.out.println(\"Fetching skills from achievement API\");\n                        JsonObject playerObject = HypixelAPIHandler.getJsonObjectAuth(HypixelAPIHandler.URL + \"player/\" + UUID);\n\n                        if (playerObject == null) {\n                            System.out.println(\"Connection failed for user \" + player.getGameProfile().getName());\n                            return;\n                        }\n                        if (!playerObject.get(\"success\").getAsBoolean()) {\n                            String reason = profileResponse.get(\"cause\").getAsString();\n                            System.out.println(\"User \" + player.getGameProfile().getName() + \" failed with reason: \" + reason);\n                            continue;\n                        }\n                        \n                        JsonObject achievementObject = Utils.getObjectFromPath(playerObject, \"player.achievements\");\n                        if (achievementObject.has(\"skyblock_harvester\")) {\n                            farmingLevel = Math.min(achievementObject.get(\"skyblock_harvester\").getAsInt(), Utils.getSkillMaxLevel(\"farming\"));\n                        }\n                        if (achievementObject.has(\"skyblock_excavator\")) {\n                            miningLevel = Math.min(achievementObject.get(\"skyblock_excavator\").getAsInt(), Utils.getSkillMaxLevel(\"mining\"));\n                        }\n                        if (achievementObject.has(\"skyblock_combat\")) {\n                            combatLevel = Math.min(achievementObject.get(\"skyblock_combat\").getAsInt(), Utils.getSkillMaxLevel(\"combat\"));\n                        }\n                        if (achievementObject.has(\"skyblock_gatherer\")) {\n                            foragingLevel = Math.min(achievementObject.get(\"skyblock_gatherer\").getAsInt(), Utils.getSkillMaxLevel(\"foraging\"));\n                        }\n                        if (achievementObject.has(\"skyblock_angler\")) {\n                            fishingLevel = Math.min(achievementObject.get(\"skyblock_angler\").getAsInt(), Utils.getSkillMaxLevel(\"fishing\"));\n                        }\n                        if (achievementObject.has(\"skyblock_augmentation\")) {\n                            enchantingLevel = Math.min(achievementObject.get(\"skyblock_augmentation\").getAsInt(), Utils.getSkillMaxLevel(\"enchanting\"));\n                        }\n                        if (achievementObject.has(\"skyblock_concoctor\")) {\n                            alchemyLevel = Math.min(achievementObject.get(\"skyblock_concoctor\").getAsInt(), Utils.getSkillMaxLevel(\"alchemy\"));\n                        }\n                        if (achievementObject.has(\"skyblock_domesticator\")) {\n                            tamingLevel = Math.min(achievementObject.get(\"skyblock_domesticator\").getAsInt(), Utils.getSkillMaxLevel(\"taming\"));\n                        }\n                    }\n                    \n                    double skillAvg = (farmingLevel + miningLevel + combatLevel + foragingLevel + fishingLevel + enchantingLevel + alchemyLevel + tamingLevel + carpentryLevel) / 9;\n                    skillAvg = (double) Math.round(skillAvg * 100) / 100;\n                    unsortedSAList.put(player.getGameProfile().getName(), skillAvg); // Put SA in HashMap\n                    lobbySkills.add(skillAvg); // Add SA to lobby skills\n                }\n                \n                // Sort skill average\n                Map<String, Double> sortedSAList = unsortedSAList.entrySet().stream()\n                                                   .sorted(Entry.<String, Double>comparingByValue().reversed())\n                                                   .collect(Collectors.toMap(Entry::getKey, Entry::getValue,\n                                                           (e1, e2) -> e1, LinkedHashMap::new));\n                \n                String[] sortedSAListKeys = sortedSAList.keySet().toArray(new String[0]);\n                String top3 = \"\";\n                for (int i = 0; i < 3 && i < sortedSAListKeys.length; i++) {\n                    top3 += \"\\n \" + EnumChatFormatting.AQUA + sortedSAListKeys[i] + \": \" + ModConfig.getColour(ModConfig.skillAverageColour) + EnumChatFormatting.BOLD + sortedSAList.get(sortedSAListKeys[i]);\n                }\n                \n                // Get lobby sa\n                double lobbySA = 0;\n                for (Double playerSkills : lobbySkills) {\n                    lobbySA += playerSkills;\n                }\n                lobbySA = (double) Math.round((lobbySA / lobbySkills.size()) * 100) / 100;\n                \n                // Finally say skill lobby avg and highest SA users\n                playerSP.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                                                              ModConfig.getColour(ModConfig.typeColour) + \" Lobby Skill Average: \" + ModConfig.getColour(ModConfig.skillAverageColour) + EnumChatFormatting.BOLD + lobbySA + \"\\n\" +\n                                                              ModConfig.getColour(ModConfig.typeColour) + \" Highest Skill Averages:\" + top3 + \"\\n\" +\n                                                              ModConfig.getDelimiter()));\n            } catch (InterruptedException ex) {\n                System.out.println(\"Current skill average list: \" + unsortedSAList);\n                Thread.currentThread().interrupt();\n                System.out.println(\"Interrupted /lobbyskills thread.\");\n            }\n\n        });\n        mainThread.start();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/PetsCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.MathHelper;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class PetsCommand extends CommandBase {\n\n    static int petXpToLevel(double xp, String rarity) {\n        int[] xpPerLevel = {100, 110, 120, 130, 145, 160, 175, 190, 210, 230, 250, 275, 300, 330, 360, 400, 440, 490, 540, 600, 660, 730,\n                800, 880, 960, 1050, 1150, 1260, 1380, 1510, 1650, 1800, 1960, 2130, 2310, 2500, 2700, 2920, 3160, 3420, 3700,\n                4000, 4350, 4750, 5200, 5700, 6300, 7000, 7800, 8700, 9700, 10800, 12000, 13300, 14700, 16200, 17800, 19500,\n                21300, 23200, 25200, 27400, 29800, 32400, 35200, 38200, 41400, 44800, 48400, 52200, 56200, 60400, 64800, 69400,\n                74200, 79200, 84700, 90700, 97200, 104200, 111700, 119700, 128200, 137200, 146700, 156700, 167700, 179700, 192700,\n                206700, 221700, 237700, 254700, 272700, 291700, 311700, 333700, 357700, 383700, 411700, 441700, 476700, 516700,\n                561700, 611700, 666700, 726700, 791700, 861700, 936700, 1016700, 1101700, 1191700, 1286700, 1386700, 1496700,\n                1616700, 1746700, 1886700};\n\n        int levelOffset = 0;\n        switch (rarity) {\n            case \"UNCOMMON\":\n                levelOffset = 6;\n                break;\n            case \"RARE\":\n                levelOffset = 11;\n                break;\n            case \"EPIC\":\n                levelOffset = 16;\n                break;\n            case \"LEGENDARY\":\n                levelOffset = 20;\n                break;\n            case \"MYTHIC\":\n                levelOffset = 20;\n                break;\n        }\n\n        for (int i = levelOffset, xpAdded = 0; i < levelOffset + 99; i++) {\n            xpAdded += xpPerLevel[i];\n            if (xp < xpAdded) {\n                return i + 1 - levelOffset;\n            }\n        }\n        return 100;\n    }\n\n    enum Rarity {\n        COMMON,\n        UNCOMMON,\n        RARE,\n        EPIC,\n        LEGENDARY,\n        MYTHIC;\n\n        public Rarity nextRarity() {\n            if (this.ordinal() == Rarity.values().length) return this;\n            return Rarity.values()[this.ordinal() + 1];\n        }\n\n        public EnumChatFormatting getChatColor() {\n            if (this == Rarity.COMMON) return EnumChatFormatting.WHITE;\n            if (this == Rarity.UNCOMMON) return EnumChatFormatting.GREEN;\n            if (this == Rarity.RARE) return EnumChatFormatting.BLUE;\n            if (this == Rarity.EPIC) return EnumChatFormatting.DARK_PURPLE;\n            if (this == Rarity.LEGENDARY) return EnumChatFormatting.GOLD;\n            if (this == Rarity.MYTHIC) return EnumChatFormatting.LIGHT_PURPLE;\n            return null;\n        }\n    }\n\n    static class Pet {\n\n        public Rarity rarity;\n        public double xp;\n        public boolean active;\n        public boolean rarityBoosted = false;\n        public String name;\n\n        Pet(JsonObject pet) {\n            Rarity rarity = Rarity.valueOf(pet.get(\"tier\").getAsString());\n            if (!pet.get(\"heldItem\").isJsonNull()) {\n                String petItemID = pet.get(\"heldItem\").getAsString();\n                switch (petItemID) {\n                    case \"PET_ITEM_VAMPIRE_FANG\":\n                    case \"PET_ITEM_TOY_JERRY\":\n                    case \"PET_ITEM_TIER_BOOST\":\n                        rarityBoosted = true;\n                        rarity = rarity.nextRarity();\n                }\n            }\n            this.active = pet.get(\"active\").getAsBoolean();\n            this.name = Utils.capitalizeString(pet.get(\"type\").getAsString());\n            this.rarity = rarity;\n            this.xp = pet.get(\"exp\").getAsDouble();\n        }\n\n        public String getStringToAdd() {\n            int level = petXpToLevel(this.xp, this.rarity.name());\n            if (this.name.equals(\"Golden Dragon\") && this.xp > 25353230D) {\n                level = 100 + MathHelper.clamp_int((int) ((this.xp - 25353230) / 1886700) + 2, 0, 100);\n            }\n\n            String messageToAdd = rarity.getChatColor() + \" \" + (this.active ? EnumChatFormatting.BOLD + \">>> \" : \"\") + Utils.capitalizeString(this.rarity.name()) + (this.rarityBoosted ? \" ⇑\" : \"\")  + \" \" + this.name + \" (\" + level + \")\" + (this.active ? \" <<<\" : \"\");\n\n            return messageToAdd + \"\\n\";\n        }\n\n    }\n\n    @Override\n    public String getCommandName() {\n        return \"petsof\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" [name]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new PetsCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return Utils.getMatchingPlayers(args[0]);\n        }\n        return null;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n\n            // Get UUID for Hypixel API requests\n            String username;\n            String uuid;\n            if (arg1.length == 0) {\n                username = player.getName();\n                uuid = player.getUniqueID().toString().replaceAll(\"[\\\\-]\", \"\");\n            } else {\n                username = arg1[0];\n                uuid = APIHandler.getUUID(username);\n            }\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking pets of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using Polyfrost's API.\"));\n\n            // Find stats of latest profile\n            JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(uuid);\n            if (profileResponse == null) return;\n\n            System.out.println(\"Fetching pets...\");\n            JsonArray petsArray = Utils.getObjectFromPath(profileResponse, \"members.\" + uuid + \".pets_data\").getAsJsonArray(\"pets\");\n            if (petsArray.size() == 0) {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + username + \" has no pets.\"));\n                return;\n            }\n\n            System.out.println(\"Looping through pets...\");\n            // Push each pet into list\n            List<Pet> pets = new ArrayList<>();\n            for (JsonElement petElement : petsArray) {\n                pets.add(new Pet(petElement.getAsJsonObject()));\n            }\n\n            // Sort pets by exp and rarity\n            pets.sort((pet1, pet2) -> {\n                int rarity = pet1.rarity.compareTo(pet2.rarity);\n                int xp = Double.compare(pet1.xp, pet2.xp);\n                if (rarity != 0) return -rarity;\n                return -xp;\n            });\n\n            String finalMessage = ModConfig.getDelimiter() + \"\\n\" +\n                    EnumChatFormatting.AQUA + \" \" + username + \"'s Pets (\" + pets.size() + \"):\\n\";\n\n            // Loop through pets\n            for(Pet pet : pets) {\n                finalMessage += pet.getStringToAdd();\n            }\n\n            finalMessage += ModConfig.getDelimiter();\n            player.addChatMessage(new ChatComponentText(finalMessage));\n\n        }).start();\n    }\n\n}"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/PlayerCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.text.NumberFormat;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class PlayerCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"player\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" [name]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new SkillsCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return Utils.getMatchingPlayers(args[0]);\n        }\n        return null;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n\n            // Get UUID for Hypixel API requests\n            String username;\n            String uuid;\n            if (arg1.length == 0) {\n                username = player.getName();\n                uuid = player.getUniqueID().toString().replaceAll(\"[\\\\-]\", \"\");\n            } else {\n                username = arg1[0];\n                uuid = APIHandler.getUUID(username);\n            }\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking stats of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using Polyfrost's API.\"));\n\n            // Find stats of latest profile\n            JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(uuid);\n            if (profileResponse == null) return;\n\n            String latestProfileID = HypixelAPIHandler.getLatestProfileID(uuid);\n            if (latestProfileID == null) return;\n\n            // Skills\n            System.out.println(\"Fetching skills...\");\n            JsonObject userObject = Utils.getObjectFromPath(profileResponse, \"members.\" + uuid);\n            JsonObject experienceObj = Utils.getObjectFromPath(userObject, \"player_data.experience\");\n\n            double farmingLevel = 0;\n            double miningLevel = 0;\n            double combatLevel = 0;\n            double foragingLevel = 0;\n            double fishingLevel = 0;\n            double enchantingLevel = 0;\n            double alchemyLevel = 0;\n            double tamingLevel = 0;\n            double carpentryLevel = 0;\n\n            if (experienceObj.has(\"SKILL_FARMING\") || experienceObj.has(\"SKILL_MINING\") || experienceObj.has(\"SKILL_COMBAT\") || experienceObj.has(\"SKILL_FORAGING\") || experienceObj.has(\"SKILL_FISHING\") || experienceObj.has(\"SKILL_ENCHANTING\") || experienceObj.has(\"SKILL_ALCHEMY\")) {\n                if (experienceObj.has(\"SKILL_FARMING\")) {\n                    farmingLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_FARMING\").getAsDouble(), Utils.getSkillMaxLevel(\"farming\"));\n                    farmingLevel = (double) Math.round(farmingLevel * 100) / 100;\n                }\n                if (experienceObj.has(\"SKILL_MINING\")) {\n                    miningLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_MINING\").getAsDouble(), Utils.getSkillMaxLevel(\"mining\"));\n                    miningLevel = (double) Math.round(miningLevel * 100) / 100;\n                }\n                if (experienceObj.has(\"SKILL_COMBAT\")) {\n                    combatLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_COMBAT\").getAsDouble(), Utils.getSkillMaxLevel(\"combat\"));\n                    combatLevel = (double) Math.round(combatLevel * 100) / 100;\n                }\n                if (experienceObj.has(\"SKILL_FORAGING\")) {\n                    foragingLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_FORAGING\").getAsDouble(), Utils.getSkillMaxLevel(\"foraging\"));\n                    foragingLevel = (double) Math.round(foragingLevel * 100) / 100;\n                }\n                if (experienceObj.has(\"SKILL_FISHING\")) {\n                    fishingLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_FISHING\").getAsDouble(), Utils.getSkillMaxLevel(\"fishing\"));\n                    fishingLevel = (double) Math.round(fishingLevel * 100) / 100;\n                }\n                if (experienceObj.has(\"SKILL_ENCHANTING\")) {\n                    enchantingLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_ENCHANTING\").getAsDouble(), Utils.getSkillMaxLevel(\"enchanting\"));\n                    enchantingLevel = (double) Math.round(enchantingLevel * 100) / 100;\n                }\n                if (experienceObj.has(\"SKILL_ALCHEMY\")) {\n                    alchemyLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_ALCHEMY\").getAsDouble(), Utils.getSkillMaxLevel(\"alchemy\"));\n                    alchemyLevel = (double) Math.round(alchemyLevel * 100) / 100;\n                }\n                if (experienceObj.has(\"SKILL_TAMING\")) {\n                    tamingLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_TAMING\").getAsDouble(), Utils.getSkillMaxLevel(\"taming\"));\n                    tamingLevel = (double) Math.round(tamingLevel * 100) / 100;\n                }\n                if (experienceObj.has(\"SKILL_CARPENTRY\")) {\n                    carpentryLevel = Utils.xpToSkillLevel(experienceObj.get(\"SKILL_CARPENTRY\").getAsDouble(), Utils.getSkillMaxLevel(\"carpentry\"));\n                    carpentryLevel = (double) Math.round(carpentryLevel * 100) / 100;\n                }\n            } else {\n                // Get skills from achievement API, will be floored\n\n                System.out.println(\"Fetching skills from achievement API\");\n                JsonObject playerObject = HypixelAPIHandler.getJsonObjectAuth(HypixelAPIHandler.URL + \"player/\" + uuid);\n\n                if (playerObject == null) {\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Could not connect to API.\"));\n                    return;\n                }\n                if (!playerObject.get(\"success\").getAsBoolean()) {\n                    String reason = profileResponse.get(\"cause\").getAsString();\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Failed with reason: \" + reason));\n                    return;\n                }\n\n                JsonObject achievementObject = Utils.getObjectFromPath(playerObject, \"player.achievements\");\n                if (achievementObject.has(\"skyblock_harvester\")) {\n                    farmingLevel = Math.min(achievementObject.get(\"skyblock_harvester\").getAsInt(), Utils.getSkillMaxLevel(\"farming\"));\n                }\n                if (achievementObject.has(\"skyblock_excavator\")) {\n                    miningLevel = Math.min(achievementObject.get(\"skyblock_excavator\").getAsInt(), Utils.getSkillMaxLevel(\"mining\"));\n                }\n                if (achievementObject.has(\"skyblock_combat\")) {\n                    combatLevel = Math.min(achievementObject.get(\"skyblock_combat\").getAsInt(), Utils.getSkillMaxLevel(\"combat\"));\n                }\n                if (achievementObject.has(\"skyblock_gatherer\")) {\n                    foragingLevel = Math.min(achievementObject.get(\"skyblock_gatherer\").getAsInt(), Utils.getSkillMaxLevel(\"foraging\"));\n                }\n                if (achievementObject.has(\"skyblock_angler\")) {\n                    fishingLevel = Math.min(achievementObject.get(\"skyblock_angler\").getAsInt(), Utils.getSkillMaxLevel(\"fishing\"));\n                }\n                if (achievementObject.has(\"skyblock_augmentation\")) {\n                    enchantingLevel = Math.min(achievementObject.get(\"skyblock_augmentation\").getAsInt(), Utils.getSkillMaxLevel(\"enchanting\"));\n                }\n                if (achievementObject.has(\"skyblock_concoctor\")) {\n                    alchemyLevel = Math.min(achievementObject.get(\"skyblock_concoctor\").getAsInt(), Utils.getSkillMaxLevel(\"alchemy\"));\n                }\n                if (achievementObject.has(\"skyblock_domesticator\")) {\n                    tamingLevel = Math.min(achievementObject.get(\"skyblock_domesticator\").getAsInt(), Utils.getSkillMaxLevel(\"taming\"));\n                }\n            }\n\n            double skillAvg = (farmingLevel + miningLevel + combatLevel + foragingLevel + fishingLevel + enchantingLevel + alchemyLevel + tamingLevel + carpentryLevel) / 9;\n            skillAvg = (double) Math.round(skillAvg * 100) / 100;\n            double trueAvg = (Math.floor(farmingLevel) + Math.floor(miningLevel) + Math.floor(combatLevel) + Math.floor(foragingLevel) + Math.floor(fishingLevel) + Math.floor(enchantingLevel) + Math.floor(alchemyLevel) + Math.floor(tamingLevel) + Math.floor(carpentryLevel)) / 9;\n            trueAvg = (double) Math.round(trueAvg * 100) / 100;\n\n            // Slayers\n            System.out.println(\"Fetching slayer stats...\");\n            JsonObject slayersObject = Utils.getObjectFromPath(userObject, \"slayer.slayer_bosses\");\n            // Zombie\n            int zombieXP = 0;\n            if (slayersObject.getAsJsonObject(\"zombie\").has(\"xp\")) {\n                zombieXP = slayersObject.getAsJsonObject(\"zombie\").get(\"xp\").getAsInt();\n            }\n            // Spider\n            int spiderXP = 0;\n            if (slayersObject.getAsJsonObject(\"spider\").has(\"xp\")) {\n                spiderXP = slayersObject.getAsJsonObject(\"spider\").get(\"xp\").getAsInt();\n            }\n            // Wolf\n            int wolfXP = 0;\n            if (slayersObject.getAsJsonObject(\"wolf\").has(\"xp\")) {\n                wolfXP = slayersObject.getAsJsonObject(\"wolf\").get(\"xp\").getAsInt();\n            }\n            // Enderman\n            int endermanXP = 0;\n            if (slayersObject.getAsJsonObject(\"enderman\").has(\"xp\")) {\n                endermanXP = slayersObject.getAsJsonObject(\"enderman\").get(\"xp\").getAsInt();\n            }\n            // Blaze\n            int blazeXP = 0;\n            if (slayersObject.getAsJsonObject(\"blaze\").has(\"xp\")) {\n                blazeXP = slayersObject.getAsJsonObject(\"blaze\").get(\"xp\").getAsInt();\n            }\n            // Vampire\n            int vampireXP = 0;\n            if (slayersObject.getAsJsonObject(\"vampire\").has(\"xp\")) {\n                vampireXP = slayersObject.getAsJsonObject(\"vampire\").get(\"xp\").getAsInt();\n            }\n\n            int totalXP = zombieXP + spiderXP + wolfXP + endermanXP + blazeXP + vampireXP;\n\n            // Bank\n            System.out.println(\"Fetching bank + purse coins...\");\n            double bankCoins = 0;\n            double purseCoins = userObject.getAsJsonObject(\"currencies\").get(\"coin_purse\").getAsDouble();\n            purseCoins = Math.floor(purseCoins * 100.0) / 100.0;\n\n            // Check for bank api\n            if (profileResponse.has(\"banking\")) {\n                bankCoins = profileResponse.getAsJsonObject(\"banking\").get(\"balance\").getAsDouble();\n                bankCoins = Math.floor(bankCoins * 100.0) / 100.0;\n            }\n\n            // Weight\n            System.out.println(\"Fetching weight from SkyShiiyu API...\");\n            String weightURL = \"https://sky.shiiyu.moe/api/v2/profile/\" + username;\n            JsonObject weightResponse = APIHandler.getResponse(weightURL, true);\n            if (weightResponse.has(\"error\")) {\n                String reason = weightResponse.get(\"error\").getAsString();\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Failed with reason: \" + reason));\n                return;\n            }\n\n            double weight = Utils.getObjectFromPath(weightResponse, \"profiles.\" + latestProfileID + \".data.weight.senither\").get(\"overall\").getAsDouble();\n\n            NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);\n            NumberFormat nfd = NumberFormat.getNumberInstance(Locale.US);\n            player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                                                        EnumChatFormatting.AQUA + \" \" + username + \"'s Skills:\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Farming: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + farmingLevel + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Mining: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + miningLevel + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Combat: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + combatLevel + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Foraging: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + foragingLevel + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Fishing: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + fishingLevel + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Enchanting: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + enchantingLevel + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Alchemy: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + alchemyLevel + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Taming: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + tamingLevel + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Carpentry: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + carpentryLevel + \"\\n\" +\n                                                        EnumChatFormatting.AQUA + \" Average Skill Level: \" + ModConfig.getColour(ModConfig.skillAverageColour) + EnumChatFormatting.BOLD + skillAvg + \"\\n\" +\n                                                        EnumChatFormatting.AQUA + \" True Average Skill Level: \" + ModConfig.getColour(ModConfig.skillAverageColour) + EnumChatFormatting.BOLD + trueAvg + \"\\n\\n\" +\n                                                        EnumChatFormatting.AQUA + \" \" + username + \"'s Total Slayer XP: \" + EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + nf.format(totalXP) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Zombie XP: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + nf.format(zombieXP) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Spider XP: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + nf.format(spiderXP) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Wolf XP: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + nf.format(wolfXP) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Enderman XP: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + nf.format(endermanXP) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Blaze XP: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + nf.format(blazeXP) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Vampire XP: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + nf.format(vampireXP) + \"\\n\\n\" +\n                                                        EnumChatFormatting.AQUA + \" \" + username + \"'s Coins:\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Bank: \" + (bankCoins == 0 ? EnumChatFormatting.RED + \"Bank API disabled.\" : EnumChatFormatting.GOLD + nf.format(bankCoins)) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Purse: \" + EnumChatFormatting.GOLD + nf.format(purseCoins) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Total: \" + EnumChatFormatting.GOLD + nf.format(bankCoins + purseCoins) + \"\\n\\n\" +\n                                                        EnumChatFormatting.AQUA + \" \" + username + \"'s Weight:\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Total Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nfd.format(weight) + \"\\n\" +\n                                                        ModConfig.getDelimiter()));\n        }).start();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/SkillsCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.event.HoverEvent;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.ChatStyle;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.text.NumberFormat;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class SkillsCommand extends CommandBase {\n\n    static NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);\n\n    @Override\n    public String getCommandName() {\n        return \"skill\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" [name]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new SkillsCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n    \n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return Utils.getMatchingPlayers(args[0]);\n        }\n        return null;\n    }\n    \n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n            \n            // Get UUID for Hypixel API requests\n            String username;\n            String uuid;\n            if (arg1.length == 0) {\n                username = player.getName();\n                uuid = player.getUniqueID().toString().replaceAll(\"[\\\\-]\", \"\");\n            } else {\n                username = arg1[0];\n                uuid = APIHandler.getUUID(username);\n            }\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking skills of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using Polyfrost's API.\"));\n            \n            // Find stats of latest profile\n            JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(uuid);\n            if (profileResponse == null) return;\n            \n            System.out.println(\"Fetching skills...\");\n            JsonObject experienceObj = Utils.getObjectFromPath(profileResponse, \"members.\" + uuid + \".player_data.experience\");\n\n            ChatComponentText farmingLevelText = new ChatComponentText(ModConfig.getColour(ModConfig.typeColour) + \" Farming: \");\n            ChatComponentText miningLevelText = new ChatComponentText(ModConfig.getColour(ModConfig.typeColour) + \" Mining: \");\n            ChatComponentText combatLevelText = new ChatComponentText(ModConfig.getColour(ModConfig.typeColour) + \" Combat: \");\n            ChatComponentText foragingLevelText = new ChatComponentText(ModConfig.getColour(ModConfig.typeColour) + \" Foraging: \");\n            ChatComponentText fishingLevelText = new ChatComponentText(ModConfig.getColour(ModConfig.typeColour) + \" Fishing: \");\n            ChatComponentText enchantingLevelText = new ChatComponentText(ModConfig.getColour(ModConfig.typeColour) + \" Enchanting: \");\n            ChatComponentText alchemyLevelText = new ChatComponentText(ModConfig.getColour(ModConfig.typeColour) + \" Alchemy: \");\n            ChatComponentText tamingLevelText = new ChatComponentText(ModConfig.getColour(ModConfig.typeColour) + \" Taming: \");\n            ChatComponentText carpentryLevelText = new ChatComponentText(ModConfig.getColour(ModConfig.typeColour) + \" Carpentry: \");\n            ChatComponentText newLine = new ChatComponentText(\"\\n\");\n\n            double farmingLevel = 0;\n            double miningLevel = 0;\n            double combatLevel = 0;\n            double foragingLevel = 0;\n            double fishingLevel = 0;\n            double enchantingLevel = 0;\n            double alchemyLevel = 0;\n            double tamingLevel = 0;\n            double carpentryLevel = 0;\n\n            if (experienceObj.has(\"SKILL_FARMING\") || experienceObj.has(\"SKILL_MINING\") || experienceObj.has(\"SKILL_COMBAT\") || experienceObj.has(\"SKILL_FORAGING\") || experienceObj.has(\"SKILL_FISHING\") || experienceObj.has(\"SKILL_ENCHANTING\") || experienceObj.has(\"SKILL_ALCHEMY\")) {\n                if (experienceObj.has(\"SKILL_FARMING\")) {\n                    double rawFarmingXP = experienceObj.get(\"SKILL_FARMING\").getAsDouble();\n                    farmingLevel = Utils.xpToSkillLevel(rawFarmingXP, Utils.getSkillMaxLevel(\"farming\"));\n                    farmingLevel = (double) Math.round(farmingLevel * 100) / 100;\n                    farmingLevelText.setChatStyle(appendFormatted(farmingLevelText, \"XP\", rawFarmingXP));\n                    farmingLevelText.setChatStyle(appendFormatted(farmingLevelText, \"Overflow XP\", getOverflowXP(rawFarmingXP, Utils.getSkillMaxLevel(\"farming\"))));\n                }\n                if (experienceObj.has(\"SKILL_MINING\")) {\n                    double rawMiningXP = experienceObj.get(\"SKILL_MINING\").getAsDouble();\n                    miningLevel = Utils.xpToSkillLevel(rawMiningXP, Utils.getSkillMaxLevel(\"mining\"));\n                    miningLevel = (double) Math.round(miningLevel * 100) / 100;\n                    miningLevelText.setChatStyle(appendFormatted(miningLevelText, \"XP\", rawMiningXP));\n                    miningLevelText.setChatStyle(appendFormatted(miningLevelText, \"Overflow XP\", getOverflowXP(rawMiningXP, Utils.getSkillMaxLevel(\"mining\"))));\n                }\n                if (experienceObj.has(\"SKILL_COMBAT\")) {\n                    double rawCombatXP = experienceObj.get(\"SKILL_COMBAT\").getAsDouble();\n                    combatLevel = Utils.xpToSkillLevel(rawCombatXP, Utils.getSkillMaxLevel(\"combat\"));\n                    combatLevel = (double) Math.round(combatLevel * 100) / 100;\n                    combatLevelText.setChatStyle(appendFormatted(combatLevelText, \"XP\", rawCombatXP));\n                    combatLevelText.setChatStyle(appendFormatted(combatLevelText, \"Overflow XP\", getOverflowXP(rawCombatXP, Utils.getSkillMaxLevel(\"combat\"))));\n                }\n                if (experienceObj.has(\"SKILL_FORAGING\")) {\n                    double rawForagingXP = experienceObj.get(\"SKILL_FORAGING\").getAsDouble();\n                    foragingLevel = Utils.xpToSkillLevel(rawForagingXP, Utils.getSkillMaxLevel(\"foraging\"));\n                    foragingLevel = (double) Math.round(foragingLevel * 100) / 100;\n                    foragingLevelText.setChatStyle(appendFormatted(foragingLevelText, \"XP\", rawForagingXP));\n                    foragingLevelText.setChatStyle(appendFormatted(foragingLevelText, \"Overflow XP\", getOverflowXP(rawForagingXP, Utils.getSkillMaxLevel(\"foraging\"))));\n                }\n                if (experienceObj.has(\"SKILL_FISHING\")) {\n                    double rawFishingXP = experienceObj.get(\"SKILL_FISHING\").getAsDouble();\n                    fishingLevel = Utils.xpToSkillLevel(rawFishingXP, Utils.getSkillMaxLevel(\"fishing\"));\n                    fishingLevel = (double) Math.round(fishingLevel * 100) / 100;\n                    fishingLevelText.setChatStyle(appendFormatted(fishingLevelText, \"XP\", rawFishingXP));\n                    fishingLevelText.setChatStyle(appendFormatted(fishingLevelText, \"Overflow XP\", getOverflowXP(rawFishingXP, Utils.getSkillMaxLevel(\"fishing\"))));\n                }\n                if (experienceObj.has(\"SKILL_ENCHANTING\")) {\n                    double rawEnchantingXP = experienceObj.get(\"SKILL_ENCHANTING\").getAsDouble();\n                    enchantingLevel = Utils.xpToSkillLevel(rawEnchantingXP, Utils.getSkillMaxLevel(\"enchanting\"));\n                    enchantingLevel = (double) Math.round(enchantingLevel * 100) / 100;\n                    enchantingLevelText.setChatStyle(appendFormatted(enchantingLevelText, \"XP\", rawEnchantingXP));\n                    enchantingLevelText.setChatStyle(appendFormatted(enchantingLevelText, \"Overflow XP\", getOverflowXP(rawEnchantingXP, Utils.getSkillMaxLevel(\"enchanting\"))));\n                }\n                if (experienceObj.has(\"SKILL_ALCHEMY\")) {\n                    double rawAlchemyXP = experienceObj.get(\"SKILL_ALCHEMY\").getAsDouble();\n                    alchemyLevel = Utils.xpToSkillLevel(rawAlchemyXP, Utils.getSkillMaxLevel(\"alchemy\"));\n                    alchemyLevel = (double) Math.round(alchemyLevel * 100) / 100;\n                    alchemyLevelText.setChatStyle(appendFormatted(alchemyLevelText, \"XP\", rawAlchemyXP));\n                    alchemyLevelText.setChatStyle(appendFormatted(alchemyLevelText, \"Overflow XP\", getOverflowXP(rawAlchemyXP, Utils.getSkillMaxLevel(\"alchemy\"))));\n                }\n                if (experienceObj.has(\"SKILL_TAMING\")) {\n                    double rawTamingXP = experienceObj.get(\"SKILL_TAMING\").getAsDouble();\n                    tamingLevel = Utils.xpToSkillLevel(rawTamingXP, Utils.getSkillMaxLevel(\"taming\"));\n                    tamingLevel = (double) Math.round(tamingLevel * 100) / 100;\n                    tamingLevelText.setChatStyle(appendFormatted(tamingLevelText, \"XP\", rawTamingXP));\n                    tamingLevelText.setChatStyle(appendFormatted(tamingLevelText, \"Overflow XP\", getOverflowXP(rawTamingXP, Utils.getSkillMaxLevel(\"taming\"))));\n                }\n                if (experienceObj.has(\"SKILL_CARPENTRY\")) {\n                    double rawCarpentryXP = experienceObj.get(\"SKILL_CARPENTRY\").getAsDouble();\n                    carpentryLevel = Utils.xpToSkillLevel(rawCarpentryXP, Utils.getSkillMaxLevel(\"carpentry\"));\n                    carpentryLevel = (double) Math.round(carpentryLevel * 100) / 100;\n                    carpentryLevelText.setChatStyle(appendFormatted(carpentryLevelText, \"XP\", rawCarpentryXP));\n                    carpentryLevelText.setChatStyle(appendFormatted(carpentryLevelText, \"Overflow XP\", getOverflowXP(rawCarpentryXP, Utils.getSkillMaxLevel(\"carpentry\"))));\n                }\n            } else {\n                // Get skills from achievement API, will be floored\n\n                System.out.println(\"Fetching skills from achievement API\");\n                JsonObject playerObject = HypixelAPIHandler.getJsonObjectAuth(HypixelAPIHandler.URL + \"player/\" + uuid);\n\n                if (playerObject == null) {\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Could not connect to API.\"));\n                    return;\n                }\n                if (!playerObject.get(\"success\").getAsBoolean()) {\n                    String reason = profileResponse.get(\"cause\").getAsString();\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Failed with reason: \" + reason));\n                    return;\n                }\n\n                JsonObject achievementObject = Utils.getObjectFromPath(playerObject, \"player.achievements\");\n                if (achievementObject.has(\"skyblock_harvester\")) {\n                    farmingLevel = Math.min(achievementObject.get(\"skyblock_harvester\").getAsInt(), Utils.getSkillMaxLevel(\"farming\"));\n                    farmingLevelText.setChatStyle(appendFormatted(farmingLevelText, \"XP\", Utils.skillLevelToXp((int) farmingLevel)));\n                }\n                if (achievementObject.has(\"skyblock_excavator\")) {\n                    miningLevel = Math.min(achievementObject.get(\"skyblock_excavator\").getAsInt(), Utils.getSkillMaxLevel(\"mining\"));\n                    miningLevelText.setChatStyle(appendFormatted(miningLevelText, \"XP\", Utils.skillLevelToXp((int) miningLevel)));\n                }\n                if (achievementObject.has(\"skyblock_combat\")) {\n                    combatLevel = Math.min(achievementObject.get(\"skyblock_combat\").getAsInt(), Utils.getSkillMaxLevel(\"combat\"));\n                    combatLevelText.setChatStyle(appendFormatted(combatLevelText, \"XP\", Utils.skillLevelToXp((int) combatLevel)));\n                }\n                if (achievementObject.has(\"skyblock_gatherer\")) {\n                    foragingLevel = Math.min(achievementObject.get(\"skyblock_gatherer\").getAsInt(), Utils.getSkillMaxLevel(\"foraging\"));\n                    foragingLevelText.setChatStyle(appendFormatted(foragingLevelText, \"XP\", Utils.skillLevelToXp((int) foragingLevel)));\n                }\n                if (achievementObject.has(\"skyblock_angler\")) {\n                    fishingLevel = Math.min(achievementObject.get(\"skyblock_angler\").getAsInt(), Utils.getSkillMaxLevel(\"fishing\"));\n                    fishingLevelText.setChatStyle(appendFormatted(fishingLevelText, \"XP\", Utils.skillLevelToXp((int) fishingLevel)));\n                }\n                if (achievementObject.has(\"skyblock_augmentation\")) {\n                    enchantingLevel = Math.min(achievementObject.get(\"skyblock_augmentation\").getAsInt(), Utils.getSkillMaxLevel(\"enchanting\"));\n                    enchantingLevelText.setChatStyle(appendFormatted(enchantingLevelText, \"XP\", Utils.skillLevelToXp((int) enchantingLevel)));\n                }\n                if (achievementObject.has(\"skyblock_concoctor\")) {\n                    alchemyLevel = Math.min(achievementObject.get(\"skyblock_concoctor\").getAsInt(), Utils.getSkillMaxLevel(\"alchemy\"));\n                    alchemyLevelText.setChatStyle(appendFormatted(alchemyLevelText, \"XP\", Utils.skillLevelToXp((int) alchemyLevel)));\n                }\n                if (achievementObject.has(\"skyblock_domesticator\")) {\n                    tamingLevel = Math.min(achievementObject.get(\"skyblock_domesticator\").getAsInt(), Utils.getSkillMaxLevel(\"taming\"));\n                    tamingLevelText.setChatStyle(appendFormatted(tamingLevelText, \"XP\", Utils.skillLevelToXp((int) tamingLevel)));\n                }\n            }\n\n            farmingLevelText.appendSibling(new ChatComponentText(ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + farmingLevel));\n            miningLevelText.appendSibling(new ChatComponentText(ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + miningLevel));\n            combatLevelText.appendSibling(new ChatComponentText(ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + combatLevel));\n            foragingLevelText.appendSibling(new ChatComponentText(ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + foragingLevel));\n            fishingLevelText.appendSibling(new ChatComponentText(ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + fishingLevel));\n            enchantingLevelText.appendSibling(new ChatComponentText(ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + enchantingLevel));\n            alchemyLevelText.appendSibling(new ChatComponentText(ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + alchemyLevel));\n            tamingLevelText.appendSibling(new ChatComponentText(ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + tamingLevel));\n            carpentryLevelText.appendSibling(new ChatComponentText(ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + carpentryLevel));\n\n            double skillAvg = (farmingLevel + miningLevel + combatLevel + foragingLevel + fishingLevel + enchantingLevel + alchemyLevel + tamingLevel + carpentryLevel) / 9;\n            skillAvg = (double) Math.round(skillAvg * 100) / 100;\n            double trueAvg = (Math.floor(farmingLevel) + Math.floor(miningLevel) + Math.floor(combatLevel) + Math.floor(foragingLevel) + Math.floor(fishingLevel) + Math.floor(enchantingLevel) + Math.floor(alchemyLevel) + Math.floor(tamingLevel) + Math.floor(carpentryLevel)) / 9;\n            trueAvg = (double) Math.round(trueAvg * 100) / 100;\n\n            player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                                                        EnumChatFormatting.AQUA + \" \" + username + \"'s Skills:\\n\")\n                                                        .appendSibling(farmingLevelText).appendSibling(newLine)\n                                                        .appendSibling(miningLevelText).appendSibling(newLine)\n                                                        .appendSibling(combatLevelText).appendSibling(newLine)\n                                                        .appendSibling(foragingLevelText).appendSibling(newLine)\n                                                        .appendSibling(fishingLevelText).appendSibling(newLine)\n                                                        .appendSibling(enchantingLevelText).appendSibling(newLine)\n                                                        .appendSibling(alchemyLevelText).appendSibling(newLine)\n                                                        .appendSibling(tamingLevelText).appendSibling(newLine)\n                                                        .appendSibling(carpentryLevelText).appendSibling(newLine)\n                                                        .appendSibling(new ChatComponentText(\n                                                        EnumChatFormatting.AQUA + \" Average Skill Level: \" + ModConfig.getColour(ModConfig.skillAverageColour) + EnumChatFormatting.BOLD + skillAvg + \"\\n\" +\n                                                        EnumChatFormatting.AQUA + \" True Average Skill Level: \" + ModConfig.getColour(ModConfig.skillAverageColour) + EnumChatFormatting.BOLD + trueAvg + \"\\n\" +\n                                                        ModConfig.getDelimiter())));\n        }).start();\n    }\n\n    static ChatStyle appendHover(ChatComponentText component, String text) {\n        String original = \"\";\n        if (component.getChatStyle().getChatHoverEvent() != null) original = component.getChatStyle().getChatHoverEvent().getValue().getFormattedText();\n        if (original.length() > 0) original += \"\\n\";\n        return component.getChatStyle().setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(original + text)));\n    }\n\n    static ChatStyle appendFormatted(ChatComponentText component, String category, double number) {\n        return appendHover(component, ModConfig.getColour(ModConfig.typeColour) + category + \": \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + nf.format(number));\n    }\n\n    static double getOverflowXP(double xp, int limit) {\n        if (limit == 50) return Math.max(0D, xp - 55172425D);\n        return Math.max(0D, xp - 111672425D);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/SkyblockPlayersCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.ChatComponentText;\n\nimport java.text.NumberFormat;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class SkyblockPlayersCommand extends CommandBase {\n\n    static NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);\n\n    @Override\n    public String getCommandName() {\n        return \"sbplayers\";\n    }\n    \n    @Override\n    public List<String> getCommandAliases() {\n        return Collections.singletonList(\"skyblockplayers\");\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName();\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new SkyblockPlayersCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n            \n            System.out.println(\"Fetching player count...\");\n            JsonObject playersResponse = HypixelAPIHandler.getJsonObjectAuth(HypixelAPIHandler.URL + \"gameCounts\");\n\n            if (playersResponse == null) {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Could not connect to API.\"));\n                return;\n            }\n            if (!playersResponse.get(\"success\").getAsBoolean()) {\n                String reason = playersResponse.get(\"cause\").getAsString();\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Failed with reason: \" + reason));\n                return;\n            }\n            \n            int totalPlayers = playersResponse.get(\"playerCount\").getAsInt();\n            // Skyblock players, comments show JSON key\n            int skyblockTotalPlayers = 0; // players\n            int privateIsland = 0; // dynamic\n            int hub = 0; // hub\n            int farmingIslands = 0; // farming_1\n            int garden = 0; // garden\n            int park = 0; // foraging_1\n            int goldMine = 0; // mining_1\n            int deepCaverns = 0; // mining_2\n            int dwarvenMines = 0; // mining_3\n            int crystalHollows = 0; // crystal_hollows\n            int spidersDen = 0; // combat_1\n            int crimsonIsle = 0; // crimson_isle\n            int kuudra = 0; // kuudra\n            int end = 0; // combat_3\n            int dungeonsHub = 0; // dungeon_hub\n            int dungeons = 0; // dungeon\n            int darkAuction = 0; // dark_auction\n            int jerry = 0; // winter\n            int rift = 0; // rift\n\n            if (Utils.getObjectFromPath(playersResponse, \"games.SKYBLOCK\").has(\"modes\")) {\n                JsonObject skyblockPlayers = Utils.getObjectFromPath(playersResponse, \"games.SKYBLOCK.modes\");\n                skyblockTotalPlayers = Utils.getObjectFromPath(playersResponse, \"games.SKYBLOCK\").get(\"players\").getAsInt();\n\n                privateIsland = getPlayerCount(\"dynamic\", skyblockPlayers);\n                hub = getPlayerCount(\"hub\", skyblockPlayers);\n                farmingIslands = getPlayerCount(\"farming_1\", skyblockPlayers);\n                garden = getPlayerCount(\"garden\", skyblockPlayers);\n                park = getPlayerCount(\"foraging_1\", skyblockPlayers);\n                goldMine = getPlayerCount(\"mining_1\", skyblockPlayers);\n                deepCaverns = getPlayerCount(\"mining_2\", skyblockPlayers);\n                dwarvenMines = getPlayerCount(\"mining_3\", skyblockPlayers);\n                crystalHollows = getPlayerCount(\"crystal_hollows\", skyblockPlayers);\n                spidersDen = getPlayerCount(\"combat_1\", skyblockPlayers);\n                crimsonIsle = getPlayerCount(\"crimson_isle\", skyblockPlayers);\n                kuudra = getPlayerCount(\"kuudra\", skyblockPlayers);\n                end = getPlayerCount(\"combat_3\", skyblockPlayers);\n                dungeonsHub = getPlayerCount(\"dungeon_hub\", skyblockPlayers);\n                dungeons = getPlayerCount(\"dungeon\", skyblockPlayers);\n                darkAuction = getPlayerCount(\"dark_auction\", skyblockPlayers);\n                jerry = getPlayerCount(\"winter\", skyblockPlayers);\n                rift = getPlayerCount(\"rift\", skyblockPlayers);\n            }\n\n            player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Hypixel: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(totalPlayers) + \"\\n\" +\n                                                        getOutput(\"Skyblock\", skyblockTotalPlayers, totalPlayers) +\n                                                        getOutput(\"Private Island\", privateIsland, skyblockTotalPlayers) +\n                                                        getOutput(\"Hub\", hub, skyblockTotalPlayers) +\n                                                        getOutput(\"Dark Auction\", darkAuction, skyblockTotalPlayers) +\n                                                        getOutput(\"The Rift\", rift, skyblockTotalPlayers) +\n                                                        getOutput(\"Farming Islands\", farmingIslands, skyblockTotalPlayers) +\n                                                        getOutput(\"Garden\", garden, skyblockTotalPlayers) +\n                                                        getOutput(\"Park\", park, skyblockTotalPlayers) +\n                                                        getOutput(\"Gold Mine\", goldMine, skyblockTotalPlayers) +\n                                                        getOutput(\"Deep Caverns\", deepCaverns, skyblockTotalPlayers) +\n                                                        getOutput(\"Dwarven Mines\", dwarvenMines, skyblockTotalPlayers) +\n                                                        getOutput(\"Crystal Hollows\", crystalHollows, skyblockTotalPlayers) +\n                                                        getOutput(\"Spider's Den\", spidersDen, skyblockTotalPlayers) +\n                                                        getOutput(\"Crimson Isle\", crimsonIsle, skyblockTotalPlayers) +\n                                                        getOutput(\"Kuudra\", kuudra, skyblockTotalPlayers) +\n                                                        getOutput(\"The End\", end, skyblockTotalPlayers) +\n                                                        getOutput(\"Dungeons Hub\", dungeonsHub, skyblockTotalPlayers) +\n                                                        getOutput(\"Dungeons\", dungeons, skyblockTotalPlayers) +\n                                                        getOutput(\"Jerry's Workshop\", jerry, skyblockTotalPlayers) +\n                                                        ModConfig.getDelimiter()));\n        }).start();\n    }\n\n    static int getPlayerCount(String location, JsonObject obj) {\n        if (obj.has(location)) return obj.get(location).getAsInt();\n        return 0;\n    }\n\n    static String getOutput(String name, int amount, int total) {\n        return ModConfig.getColour(ModConfig.typeColour) + \" \" + name + \": \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(amount) + \" / \" + Utils.getPercentage(amount, total) + \"%\\n\";\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/SlayerCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.text.NumberFormat;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class SlayerCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"slayer\";\n    }\n\n    @Override\n    public List<String> getCommandAliases() {\n        return Collections.singletonList(\"slayers\");\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" [name]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new SlayerCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n    \n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return Utils.getMatchingPlayers(args[0]);\n        }\n        return null;\n    }\n    \n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n            \n            // Get UUID for Hypixel API requests\n            String username;\n            String uuid;\n            if (arg1.length == 0) {\n                username = player.getName();\n                uuid = player.getUniqueID().toString().replaceAll(\"[\\\\-]\", \"\");\n            } else {\n                username = arg1[0];\n                uuid = APIHandler.getUUID(username);\n            }\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking slayer of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using Polyfrost's API.\"));\n            \n            // Find stats of latest profile\n            JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(uuid);\n            if (profileResponse == null) return;\n            \n            System.out.println(\"Fetching slayer stats...\");\n            JsonObject slayersObject = Utils.getObjectFromPath(profileResponse, \"members.\" + uuid + \".slayer.slayer_bosses\");\n\n            // Zombie\n            int zombieXP = 0;\n            if (slayersObject.getAsJsonObject(\"zombie\").has(\"xp\")) {\n                zombieXP = slayersObject.getAsJsonObject(\"zombie\").get(\"xp\").getAsInt();\n            }\n            // Spider\n            int spiderXP = 0;\n            if (slayersObject.getAsJsonObject(\"spider\").has(\"xp\")) {\n                spiderXP = slayersObject.getAsJsonObject(\"spider\").get(\"xp\").getAsInt();\n            }\n            // Wolf\n            int wolfXP = 0;\n            if (slayersObject.getAsJsonObject(\"wolf\").has(\"xp\")) {\n                wolfXP = slayersObject.getAsJsonObject(\"wolf\").get(\"xp\").getAsInt();\n            }\n            // Enderman\n            int endermanXP = 0;\n            if (slayersObject.getAsJsonObject(\"enderman\").has(\"xp\")) {\n                endermanXP = slayersObject.getAsJsonObject(\"enderman\").get(\"xp\").getAsInt();\n            }\n            // Blaze\n            int blazeXP = 0;\n            if (slayersObject.getAsJsonObject(\"blaze\").has(\"xp\")) {\n                blazeXP = slayersObject.getAsJsonObject(\"blaze\").get(\"xp\").getAsInt();\n            }\n            // Vampire\n            int vampireXP = 0;\n            if (slayersObject.getAsJsonObject(\"vampire\").has(\"xp\")) {\n                vampireXP = slayersObject.getAsJsonObject(\"vampire\").get(\"xp\").getAsInt();\n            }\n\n            int totalXP = zombieXP + spiderXP + wolfXP + endermanXP + blazeXP + vampireXP;\n            \n            NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);\n            player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                                                        EnumChatFormatting.AQUA + \" \" + username + \"'s Total XP: \" + EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + nf.format(totalXP) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Zombie XP: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + nf.format(zombieXP) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Spider XP: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + nf.format(spiderXP) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Wolf XP: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + nf.format(wolfXP) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Enderman XP: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + nf.format(endermanXP) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Blaze XP: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + nf.format(blazeXP) + \"\\n\" +\n                                                        ModConfig.getColour(ModConfig.typeColour) + \" Vampire XP: \" + ModConfig.getColour(ModConfig.valueColour) + EnumChatFormatting.BOLD + nf.format(vampireXP) + \"\\n\" +\n                                                        ModConfig.getDelimiter()));\n            \n        }).start();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/TrophyFishCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.features.loot.TrophyFishTracker;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.util.List;\n\npublic class TrophyFishCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"trophyfish\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName();\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new TrophyFishCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return Utils.getMatchingPlayers(args[0]);\n        }\n        return null;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n\n            // Get UUID for Hypixel API requests\n            String username;\n            String uuid;\n            if (arg1.length == 0) {\n                username = player.getName();\n                uuid = player.getUniqueID().toString().replaceAll(\"[\\\\-]\", \"\");\n            } else {\n                username = arg1[0];\n                uuid = APIHandler.getUUID(username);\n            }\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking trophy fish of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using Polyfrost's API.\"));\n\n            // Find stats of latest profile\n            JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(uuid);\n            if (profileResponse == null) return;\n\n            System.out.println(\"Fetching trophy fish...\");\n            JsonObject trophyObject = Utils.getObjectFromPath(profileResponse, \"members.\" + uuid + \".trophy_fish\");\n\n            if (!trophyObject.has(\"total_caught\")) {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"This player has not fished a trophy fish.\"));\n                return;\n            }\n\n            JsonObject fish = new JsonObject();\n            fish.add(\"Sulphur Skitter\", Utils.getTrophyFromAPI(trophyObject, \"sulphur_skitter\"));\n            fish.add(\"Obfuscated 1\", Utils.getTrophyFromAPI(trophyObject, \"obfuscated_fish_1\"));\n            fish.add(\"Steaming-Hot Flounder\", Utils.getTrophyFromAPI(trophyObject, \"steaming_hot_flounder\"));\n            fish.add(\"Obfuscated 2\", Utils.getTrophyFromAPI(trophyObject, \"obfuscated_fish_2\"));\n            fish.add(\"Gusher\", Utils.getTrophyFromAPI(trophyObject, \"gusher\"));\n            fish.add(\"Blobfish\", Utils.getTrophyFromAPI(trophyObject, \"blobfish\"));\n            fish.add(\"Slugfish\", Utils.getTrophyFromAPI(trophyObject, \"slugfish\"));\n            fish.add(\"Obfuscated 3\", Utils.getTrophyFromAPI(trophyObject, \"obfuscated_fish_3\"));\n            fish.add(\"Flyfish\", Utils.getTrophyFromAPI(trophyObject, \"flyfish\"));\n            fish.add(\"Lavahorse\", Utils.getTrophyFromAPI(trophyObject, \"lava_horse\"));\n            fish.add(\"Mana Ray\", Utils.getTrophyFromAPI(trophyObject, \"mana_ray\"));\n            fish.add(\"Volcanic Stonefish\", Utils.getTrophyFromAPI(trophyObject, \"volcanic_stonefish\"));\n            fish.add(\"Vanille\", Utils.getTrophyFromAPI(trophyObject, \"vanille\"));\n            fish.add(\"Skeleton Fish\", Utils.getTrophyFromAPI(trophyObject, \"skeleton_fish\"));\n            fish.add(\"Moldfin\", Utils.getTrophyFromAPI(trophyObject, \"moldfin\"));\n            fish.add(\"Soul Fish\", Utils.getTrophyFromAPI(trophyObject, \"soul_fish\"));\n            fish.add(\"Karate Fish\", Utils.getTrophyFromAPI(trophyObject, \"karate_fish\"));\n            fish.add(\"Golden Fish\", Utils.getTrophyFromAPI(trophyObject, \"golden_fish\"));\n\n            String tier = EnumChatFormatting.RED + \"None\";\n            if (trophyObject.has(\"rewards\")) {\n                switch (trophyObject.getAsJsonArray(\"rewards\").size()) {\n                    case 1:\n                        tier = EnumChatFormatting.DARK_GRAY + \"Novice\";\n                        break;\n                    case 2:\n                        tier = EnumChatFormatting.GRAY + \"Adept\";\n                        break;\n                    case 3:\n                        tier = EnumChatFormatting.GOLD + \"Expert\";\n                        break;\n                    case 4:\n                        tier = EnumChatFormatting.AQUA + \"Master\";\n                        break;\n                }\n            }\n\n            player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                    EnumChatFormatting.GOLD + \" Trophy Fish Rank: \" + tier + \"\\n\" +\n                    EnumChatFormatting.WHITE + \"  Sulphur Skitter \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Sulphur Skitter\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(fish, \"Sulphur Skitter\") + \"\\n\" +\n                    EnumChatFormatting.WHITE + \"  Obfuscated 1 \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Obfuscated 1\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(fish, \"Obfuscated 1\") + \"\\n\" +\n                    EnumChatFormatting.WHITE + \"  Steaminghot Flounder \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Steaming-Hot Flounder\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(fish, \"Steaming-Hot Flounder\") + \"\\n\" +\n                    EnumChatFormatting.WHITE + \"  Gusher \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Gusher\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(fish, \"Gusher\") + \"\\n\" +\n                    EnumChatFormatting.WHITE + \"  Blobfish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Blobfish\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(fish, \"Blobfish\") + \"\\n\" +\n                    EnumChatFormatting.GREEN + \"  Obfuscated 2 \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Obfuscated 2\") + \")\" + EnumChatFormatting.GREEN + \": \" + TrophyFishTracker.getTierCount(fish, \"Obfuscated 2\") + \"\\n\" +\n                    EnumChatFormatting.GREEN + \"  Slugfish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Slugfish\") + \")\" + EnumChatFormatting.GREEN + \": \" + TrophyFishTracker.getTierCount(fish, \"Slugfish\") + \"\\n\" +\n                    EnumChatFormatting.GREEN + \"  Flyfish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Flyfish\") + \")\" + EnumChatFormatting.GREEN + \": \" + TrophyFishTracker.getTierCount(fish, \"Flyfish\") + \"\\n\" +\n                    EnumChatFormatting.BLUE + \"  Obfuscated 3 \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Obfuscated 3\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(fish, \"Obfuscated 3\") + \"\\n\" +\n                    EnumChatFormatting.BLUE + \"  Lavahorse \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Lavahorse\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(fish, \"Lavahorse\") + \"\\n\" +\n                    EnumChatFormatting.BLUE + \"  Mana Ray \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Mana Ray\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(fish, \"Mana Ray\") + \"\\n\" +\n                    EnumChatFormatting.BLUE + \"  Volcanic Stonefish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Volcanic Stonefish\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(fish, \"Volcanic Stonefish\") + \"\\n\" +\n                    EnumChatFormatting.BLUE + \"  Vanille \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Vanille\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(fish, \"Vanille\") + \"\\n\" +\n                    EnumChatFormatting.DARK_PURPLE + \"  Skeleton Fish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Skeleton Fish\") + \")\" + EnumChatFormatting.DARK_PURPLE + \": \" + TrophyFishTracker.getTierCount(fish, \"Skeleton Fish\") + \"\\n\" +\n                    EnumChatFormatting.DARK_PURPLE + \"  Moldfin \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Moldfin\") + \")\" + EnumChatFormatting.DARK_PURPLE + \": \" + TrophyFishTracker.getTierCount(fish, \"Moldfin\") + \"\\n\" +\n                    EnumChatFormatting.DARK_PURPLE + \"  Soul Fish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Soul Fish\") + \")\" + EnumChatFormatting.DARK_PURPLE + \": \" + TrophyFishTracker.getTierCount(fish, \"Soul Fish\") + \"\\n\" +\n                    EnumChatFormatting.DARK_PURPLE + \"  Karate Fish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Karate Fish\") + \")\" + EnumChatFormatting.DARK_PURPLE + \": \" + TrophyFishTracker.getTierCount(fish, \"Karate Fish\") + \"\\n\" +\n                    EnumChatFormatting.GOLD + \"  Golden Fish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(fish, \"Golden Fish\") + \")\" + EnumChatFormatting.GOLD + \": \" + TrophyFishTracker.getTierCount(fish, \"Golden Fish\") + \"\\n\" +\n                    ModConfig.getDelimiter()));\n        }).start();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/api/WeightCommand.java",
    "content": "package me.Danker.commands.api;\n\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonObject;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.text.NumberFormat;\nimport java.util.*;\n\npublic class WeightCommand extends CommandBase {\n\n    ArrayList<String> t12Minions = new ArrayList<>(Arrays.asList(\n            \"WHEAT_12\",\n            \"CARROT_12\",\n            \"POTATO_12\",\n            \"PUMPKIN_12\",\n            \"MELON_12\",\n            \"MUSHROOM_12\",\n            \"COCOA_12\",\n            \"CACTUS_12\",\n            \"SUGAR_CANE_12\",\n            \"NETHER_WARTS_12\"\n    ));\n\n    @Override\n    public String getCommandName() {\n        return \"weight\";\n    }\n\n    @Override\n    public List<String> getCommandAliases() {\n        return Collections.singletonList(\"we\");\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" [name] [lily/farming]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new WeightCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return Utils.getMatchingPlayers(args[0]);\n        } else if (args.length == 2) {\n            return getListOfStringsMatchingLastWord(args, \"lily\", \"farming\");\n        }\n        return null;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n\n            // Get UUID for Hypixel API requests\n            String username;\n            String uuid;\n            if (arg1.length == 0) {\n                username = player.getName();\n                uuid = player.getUniqueID().toString().replaceAll(\"[\\\\-]\", \"\");\n            } else {\n                username = arg1[0];\n                uuid = APIHandler.getUUID(username);\n            }\n\n            NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);\n\n            if (arg1.length < 2) {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking weight of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using SkyCrypt's API.\"));\n                System.out.println(\"Fetching weight from SkyShiiyu API...\");\n                String weightURL = \"https://sky.shiiyu.moe/api/v2/profile/\" + username;\n                JsonObject weightResponse = APIHandler.getResponse(weightURL, true);\n                if (weightResponse.has(\"error\")) {\n                    String reason = weightResponse.get(\"error\").getAsString();\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Failed with reason: \" + reason));\n                    return;\n                }\n\n                String latestProfileID = HypixelAPIHandler.getLatestProfileID(uuid);\n                if (latestProfileID == null) return;\n\n                JsonObject data = Utils.getObjectFromPath(weightResponse, \"profiles.\" + latestProfileID + \".data.weight.senither\");\n                JsonObject skillsObj = Utils.getObjectFromPath(data, \"skill.skills\");\n                JsonObject slayerObj = Utils.getObjectFromPath(data, \"slayer.slayers\");\n                JsonObject classesObj = Utils.getObjectFromPath(data, \"dungeon.classes\");\n\n                double weight = data.get(\"overall\").getAsDouble();\n\n                double skillWeight = data.getAsJsonObject(\"skill\").get(\"total\").getAsDouble();\n                double farmingWeight = skillsObj.get(\"farming\").getAsDouble();\n                double miningWeight = skillsObj.get(\"mining\").getAsDouble();\n                double combatWeight = skillsObj.get(\"combat\").getAsDouble();\n                double foragingWeight = skillsObj.get(\"foraging\").getAsDouble();\n                double fishingWeight = skillsObj.get(\"fishing\").getAsDouble();\n                double enchantingWeight = skillsObj.get(\"enchanting\").getAsDouble();\n                double alchemyWeight = skillsObj.get(\"alchemy\").getAsDouble();\n                double tamingWeight = skillsObj.get(\"taming\").getAsDouble();\n\n                double slayerWeight = data.getAsJsonObject(\"slayer\").get(\"total\").getAsDouble();\n                double zombieWeight = slayerObj.get(\"zombie\").getAsDouble();\n                double spiderWeight = slayerObj.get(\"spider\").getAsDouble();\n                double wolfWeight = slayerObj.get(\"wolf\").getAsDouble();\n                double endermanWeight = slayerObj.get(\"enderman\").getAsDouble();\n                double blazeWeight = slayerObj.get(\"blaze\").getAsDouble();\n                double vampireWeight = slayerObj.get(\"vampire\").getAsDouble();\n\n                double dungeonWeight = data.getAsJsonObject(\"dungeon\").get(\"total\").getAsDouble();\n                double cataWeight = Utils.getObjectFromPath(data, \"dungeon.dungeons.catacombs\").get(\"weight\").getAsDouble();\n                double healerWeight = classesObj.getAsJsonObject(\"healer\").get(\"weight\").getAsDouble();\n                double mageWeight = classesObj.getAsJsonObject(\"mage\").get(\"weight\").getAsDouble();\n                double berserkWeight = classesObj.getAsJsonObject(\"berserk\").get(\"weight\").getAsDouble();\n                double archerWeight = classesObj.getAsJsonObject(\"archer\").get(\"weight\").getAsDouble();\n                double tankWeight = classesObj.getAsJsonObject(\"tank\").get(\"weight\").getAsDouble();\n\n                player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                        EnumChatFormatting.AQUA + \" \" + username + \"'s Weight:\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \" Total Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(weight) + \"\\n\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \" Skill Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(skillWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Farming Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(farmingWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Mining Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(miningWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Combat Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(combatWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Foraging Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(foragingWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Fishing Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(fishingWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Enchanting Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(enchantingWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Alchemy Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(alchemyWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Taming Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(tamingWeight) + \"\\n\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \" Slayers Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(slayerWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Zombie Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(zombieWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Spider Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(spiderWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Wolf Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(wolfWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Enderman Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(endermanWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Blaze Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(blazeWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Vampire Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(vampireWeight) + \"\\n\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \" Dungeons Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(dungeonWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Catacombs XP Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(cataWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Healer Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(healerWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Mage Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(mageWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Berserk Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(berserkWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Archer Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(archerWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"   Tank Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(tankWeight) + \"\\n\" +\n                        ModConfig.getDelimiter()));\n            } else if (arg1[1].equalsIgnoreCase(\"lily\")) {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking weight of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using SkyCrypt's API.\"));\n                System.out.println(\"Fetching weight from SkyShiiyu API...\");\n                String weightURL = \"https://sky.shiiyu.moe/api/v2/profile/\" + username;\n                JsonObject weightResponse = APIHandler.getResponse(weightURL, true);\n                if (weightResponse.has(\"error\")) {\n                    String reason = weightResponse.get(\"error\").getAsString();\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Failed with reason: \" + reason));\n                    return;\n                }\n\n                String latestProfileID = HypixelAPIHandler.getLatestProfileID(uuid);\n                if (latestProfileID == null) return;\n\n                JsonObject data = Utils.getObjectFromPath(weightResponse, \"profiles.\" + latestProfileID + \".data.weight.lily\");\n\n                double weight = data.get(\"total\").getAsDouble();\n                double skillWeight = data.getAsJsonObject(\"skill\").get(\"base\").getAsDouble();\n                double skillOverflow = data.getAsJsonObject(\"skill\").get(\"overflow\").getAsDouble();\n                double slayerWeight = data.get(\"slayer\").getAsDouble();\n                double catacombsXPWeight = data.getAsJsonObject(\"catacombs\").get(\"experience\").getAsDouble();\n                double catacombsBaseWeight = Utils.getObjectFromPath(data, \"catacombs.completion\").get(\"base\").getAsDouble();\n                double catacombsMasterWeight = Utils.getObjectFromPath(data, \"catacombs.completion\").get(\"master\").getAsDouble();\n\n                player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                        EnumChatFormatting.AQUA + \" \" + username + \"'s Weight (Lily):\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \" Total Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(weight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \" Skill Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(skillWeight + skillOverflow) + \" (\" + nf.format(skillWeight) + \" + \" + nf.format(skillOverflow) + \")\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \" Slayers Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(slayerWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \" Catacombs XP Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(catacombsXPWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \" Catacombs Completion Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(catacombsBaseWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \" Catacombs Master Completion Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(catacombsMasterWeight) + \"\\n\" +\n                        ModConfig.getDelimiter()));\n            } else if (arg1[1].equalsIgnoreCase(\"farming\")) {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Checking weight of \" + ModConfig.getColour(ModConfig.secondaryColour) + username + ModConfig.getColour(ModConfig.mainColour) + \" using EliteBot's API.\"));\n                String profileURL = \"https://api.elitebot.dev/weight/\" + uuid;\n                System.out.println(\"Fetching weight from elitebot.dev...\");\n\n                JsonObject weightResponse = APIHandler.getResponse(profileURL, true);\n\n                String selectedProfileId;\n                JsonObject profileWeight = null;\n\n                try {\n                    selectedProfileId = weightResponse.get(\"selectedProfileId\").getAsString();\n                    JsonArray profiles = weightResponse.getAsJsonArray(\"profiles\");\n\n                    for (JsonElement element : profiles) {\n                        if (!element.isJsonObject()) continue;\n\n                        JsonObject profileObj = element.getAsJsonObject();\n                        String profileId = profileObj.get(\"profileId\").getAsString();\n\n                        if (!profileId.equals(selectedProfileId)) continue;\n\n                        profileWeight = profileObj;\n                        break;\n                    }\n                } catch (Exception e) {\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Failed to get farming weight! Try again later.\"));\n                    return;\n                }\n\n                if (profileWeight == null) {\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Failed to get farming weight! Try again later.\"));\n                    return;\n                }\n\n                double mainWeight = profileWeight.get(\"totalWeight\").getAsDouble();\n\n                if (mainWeight == 0) {\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + username + \" does not have collection API on (or has zero farming weight)!\"));\n                    return;\n                }\n\n                JsonObject bonusWeight = profileWeight.getAsJsonObject(\"bonusWeight\");\n\n                StringBuilder bonusSources = new StringBuilder();\n                int bonusWeightTotal = 0;\n\n                for (Map.Entry<String, JsonElement> bonus : bonusWeight.entrySet()) {\n                    if (bonus.getValue().isJsonNull()) continue;\n\n                    String bonusName = bonus.getKey();\n                    int bonusAmount = bonus.getValue().getAsInt();\n\n                    bonusWeightTotal += bonusAmount;\n\n                    bonusSources\n                        .append(ModConfig.getColour(ModConfig.typeColour))\n                        .append(bonusName).append(\": \")\n                        .append(ModConfig.getColour(ModConfig.valueColour))\n                        .append(nf.format(bonusAmount)).append(\"\\n\");\n                }\n\n                player.addChatMessage(new ChatComponentText(ModConfig.getDelimiter() + \"\\n\" +\n                        EnumChatFormatting.AQUA + username + \"'s Weight (Farming):\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"Total Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(mainWeight) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"Collection Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(mainWeight - bonusWeightTotal) + \"\\n\" +\n                        ModConfig.getColour(ModConfig.typeColour) + \"Bonus Weight: \" + ModConfig.getColour(ModConfig.valueColour) + nf.format(bonusWeightTotal) + \"\\n\" +\n                        bonusSources +\n                        ModConfig.getDelimiter()));\n            } else {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: \" + getCommandUsage(arg0)));\n            }\n        }).start();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/loot/DisplayCommand.java",
    "content": "package me.Danker.commands.loot;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.features.loot.LootDisplay;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\n\nimport java.util.List;\n\npublic class DisplayCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"display\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" <zombie/spider/wolf/enderman/blaze/fishing/catacombs/mythological/ghost/auto/off> [winter/festival/spooky/ch/lava/trophy/session/f(1-7)/mm]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new DisplayCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n    \n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return getListOfStringsMatchingLastWord(args, \"wolf\", \"spider\", \"zombie\", \"enderman\", \"blaze\", \"vampire\", \"fishing\", \"catacombs\", \"mythological\", \"ghost\", \"auto\", \"off\");\n        } else if (args.length == 2 && args[0].equalsIgnoreCase(\"fishing\")) {\n            return getListOfStringsMatchingLastWord(args, \"winter\", \"festival\", \"spooky\", \"ch\", \"lava\", \"trophy\", \"session\");\n        } else if (args.length == 2 && args[0].equalsIgnoreCase(\"catacombs\")) {\n            return getListOfStringsMatchingLastWord(args, \"f1\", \"floor1\", \"f2\", \"floor2\", \"f3\", \"floor3\", \"f4\", \"floor4\", \"f5\", \"floor5\", \"f6\", \"floor6\", \"f7\", \"floor7\", \"mm\", \"master\");\n        } else if (args.length > 1) {\n            return getListOfStringsMatchingLastWord(args, \"session\");\n        }\n        return null;\n    }\n    \n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        EntityPlayer player = (EntityPlayer) arg0;\n        \n        if (arg1.length == 0) {\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: \" + getCommandUsage(arg0)));\n            return;\n        }\n\n        String display = \"Off\";\n        switch (arg1[0].toLowerCase()) {\n        case \"wolf\":\n            display = \"Wolf Slayer\";\n            break;\n        case \"spider\":\n            display = \"Spider Slayer\";\n            break;\n        case \"zombie\":\n            display = \"Zombie Slayer\";\n            break;\n        case \"enderman\":\n            display = \"Enderman Slayer\";\n            break;\n        case \"blaze\":\n            display = \"Blaze Slayer\";\n            break;\n        case \"vampire\":\n            display = \"Vampire Slayer\";\n            break;\n        case \"fishing\":\n            if (arg1.length > 1) {\n                switch (arg1[1].toLowerCase()) {\n                    case \"winter\":\n                        display = \"Winter Fishing\";\n                        break;\n                    case \"festival\":\n                        display = \"Fishing Festival\";\n                        break;\n                    case \"spooky\":\n                        display = \"Spooky Fishing\";\n                        break;\n                    case \"ch\":\n                        display = \"Crystal Hollows Fishing\";\n                        break;\n                    case \"lava\":\n                        display = \"Lava Fishing\";\n                        break;\n                    case \"trophy\":\n                        display = \"Trophy Fishing\";\n                        break;\n                    default:\n                        display = \"Fishing\";\n                }\n            } else {\n                display = \"Fishing\";\n            }\n            break;\n        case \"mythological\":\n            display = \"Mythological\";\n            break;\n        case \"catacombs\":\n            if (arg1.length == 1) {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: /display catacombs <f1/f2/f3/f4f5/f6/f7>\"));\n                return;\n            }\n            \n            switch (arg1[1].toLowerCase()) {\n                case \"f1\":\n                case \"floor1\":\n                    display = \"Floor 1\";\n                    break;\n                case \"f2\":\n                case \"floor2\":\n                    display = \"Floor 2\";\n                    break;\n                case \"f3\":\n                case \"floor3\":\n                    display = \"Floor 3\";\n                    break;\n                case \"f4\":\n                case \"floor4\":\n                    display = \"Floor 4\";\n                    break;\n                case \"f5\":\n                case \"floor5\":\n                    display = \"Floor 5\";\n                    break;\n                case \"f6\":\n                case \"floor6\":\n                    display = \"Floor 6\";\n                    break;\n                case \"f7\":\n                case \"floor7\":\n                    display = \"Floor 7\";\n                    break;\n                case \"mm\":\n                case \"master\":\n                    display = \"Master Mode\";\n                    break;\n                default:\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: /display catacombs <f1/f2/f3/f4/f5/f6/f7/mm>\"));\n                    return;\n            }\n            break;\n        case \"ghost\":\n            display = \"Ghost\";\n            break;\n        case \"auto\":\n            LootDisplay.autoDisplay = true;\n            DankersSkyblockMod.config.save();\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Display set to \" + ModConfig.getColour(ModConfig.secondaryColour) + \"auto\" + ModConfig.getColour(ModConfig.mainColour) + \".\"));\n            return;\n        case \"off\":\n            display = \"Off\";\n            break;\n        default:\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: \" + getCommandUsage(arg0)));\n            return;\n        }\n\n        LootDisplay.display = ModConfig.toDisplay(display);\n        LootDisplay.sessionDisplay = arg1[arg1.length - 1].equalsIgnoreCase(\"session\");\n        LootDisplay.autoDisplay = false;\n        DankersSkyblockMod.config.save();\n        player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Display set to \" + ModConfig.getColour(ModConfig.secondaryColour) + display + ModConfig.getColour(ModConfig.mainColour) + \".\"));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/loot/ImportFishingCommand.java",
    "content": "package me.Danker.commands.loot;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.config.CfgConfig;\nimport me.Danker.config.ModConfig;\nimport me.Danker.features.loot.FishingTracker;\nimport me.Danker.features.loot.TrophyFishTracker;\nimport me.Danker.handlers.HypixelAPIHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.ChatComponentText;\n\npublic class ImportFishingCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"importfishing\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName();\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new ImportFishingCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        // MULTI THREAD DRIFTING\n        new Thread(() -> {\n            EntityPlayer player = (EntityPlayer) arg0;\n\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Importing your fishing stats using Polyfrost's API...\"));\n\n            // Get UUID for Hypixel API requests\n            String uuid = player.getUniqueID().toString().replaceAll(\"[\\\\-]\", \"\");\n\n            JsonObject profileResponse = HypixelAPIHandler.getLatestProfile(uuid);\n            if (profileResponse == null) return;\n\n            System.out.println(\"Fetching fishing stats...\");\n            JsonObject memberObject = Utils.getObjectFromPath(profileResponse, \"members.\" + uuid);\n            JsonObject itemsFishedObject = Utils.getObjectFromPath(memberObject, \"player_stats.items_fished\");\n            JsonObject killsObject = Utils.getObjectFromPath(memberObject, \"player_stats.kills\");\n            JsonObject trophyObject = memberObject.getAsJsonObject(\"trophy_fish\");\n\n            FishingTracker.greatCatches = 0;\n            FishingTracker.goodCatches = 0;\n            if (itemsFishedObject.has(\"treasure\")) {\n                if (itemsFishedObject.has(\"large_treasure\")) {\n                    FishingTracker.greatCatches = itemsFishedObject.get(\"large_treasure\").getAsInt();\n                    FishingTracker.goodCatches = itemsFishedObject.get(\"treasure\").getAsInt() - FishingTracker.greatCatches;\n                } else {\n                    FishingTracker.goodCatches = itemsFishedObject.get(\"treasure\").getAsInt();\n                }\n            }\n\n            FishingTracker.seaCreatures = 0;\n            FishingTracker.fishingMilestone = Utils.getObjectFromPath(memberObject, \"player_stats.pets.milestone\").get(\"sea_creatures_killed\").getAsInt();;\n\n            FishingTracker.squids = getSCFromApi(killsObject, \"pond_squid\");\n            FishingTracker.seaWalkers = getSCFromApi(killsObject, \"sea_walker\");\n            FishingTracker.nightSquids = getSCFromApi(killsObject, \"night_squid\");\n            FishingTracker.seaGuardians = getSCFromApi(killsObject, \"sea_guardian\");\n            FishingTracker.seaWitches = getSCFromApi(killsObject, \"sea_witch\");\n            FishingTracker.seaArchers = getSCFromApi(killsObject, \"sea_archer\");\n            FishingTracker.monsterOfTheDeeps = getSCFromApi(killsObject, \"zombie_deep\") + getSCFromApi(killsObject, \"chicken_deep\");\n            FishingTracker.agarimoos = getSCFromApi(killsObject, \"agarimoo\");\n            FishingTracker.catfishes = getSCFromApi(killsObject, \"catfish\");\n            FishingTracker.carrotKings = getSCFromApi(killsObject, \"carrot_king\");\n            FishingTracker.seaLeeches = getSCFromApi(killsObject, \"sea_leech\");\n            FishingTracker.guardianDefenders = getSCFromApi(killsObject, \"guardian_defender\");\n            FishingTracker.deepSeaProtectors = getSCFromApi(killsObject, \"deep_sea_protector\");\n            FishingTracker.hydras = getSCFromApi(killsObject, \"water_hydra\") / 2;\n            FishingTracker.seaEmperors = getSCFromApi(killsObject, \"skeleton_emperor\") + getSCFromApi(killsObject, \"guardian_emperor\");\n            FishingTracker.frozenSteves = getSCFromApi(killsObject, \"frozen_steve\");\n            FishingTracker.frostyTheSnowmans = getSCFromApi(killsObject, \"frosty_the_snowman\");\n            FishingTracker.grinches = getSCFromApi(killsObject, \"grinch\");\n            FishingTracker.nutcrackers = getSCFromApi(killsObject, \"nutcracker\");\n            FishingTracker.yetis = getSCFromApi(killsObject, \"yeti\");\n            FishingTracker.reindrakes = getSCFromApi(killsObject, \"reindrake_100\");\n            FishingTracker.nurseSharks = getSCFromApi(killsObject, \"nurse_shark\");\n            FishingTracker.blueSharks = getSCFromApi(killsObject, \"blue_shark\");\n            FishingTracker.tigerSharks = getSCFromApi(killsObject, \"tiger_shark\");\n            FishingTracker.greatWhiteSharks = getSCFromApi(killsObject, \"great_white_shark\");\n            FishingTracker.scarecrows = getSCFromApi(killsObject, \"scarecrow\");\n            FishingTracker.nightmares = getSCFromApi(killsObject, \"nightmare\");\n            FishingTracker.werewolfs = getSCFromApi(killsObject, \"werewolf\");\n            FishingTracker.phantomFishers = getSCFromApi(killsObject, \"phantom_fisherman\");\n            FishingTracker.grimReapers = getSCFromApi(killsObject, \"grim_reaper\");\n            FishingTracker.waterWorms = getSCFromApi(killsObject, \"water_worm\");\n            FishingTracker.poisonedWaterWorms = getSCFromApi(killsObject, \"poisoned_water_worm\");\n            FishingTracker.flamingWorms = getSCFromApi(killsObject, \"flaming_worm\");\n            FishingTracker.lavaBlazes = getSCFromApi(killsObject, \"lava_blaze\");\n            FishingTracker.lavaPigmen = getSCFromApi(killsObject, \"lava_pigman\");\n            FishingTracker.zombieMiners = getSCFromApi(killsObject, \"zombie_miner\");\n            FishingTracker.plhlegblasts = getSCFromApi(killsObject, \"pond_squid_300\");\n            FishingTracker.magmaSlugs = getSCFromApi(killsObject, \"magma_slug\");\n            FishingTracker.moogmas = getSCFromApi(killsObject, \"moogma\");\n            FishingTracker.lavaLeeches = getSCFromApi(killsObject, \"lava_leech\");\n            FishingTracker.pyroclasticWorms = getSCFromApi(killsObject, \"pyroclastic_worm\");\n            FishingTracker.lavaFlames = getSCFromApi(killsObject, \"lava_flame\");\n            FishingTracker.fireEels = getSCFromApi(killsObject, \"fire_eel\");\n            FishingTracker.tauruses = getSCFromApi(killsObject, \"pig_rider\");\n            FishingTracker.thunders = getSCFromApi(killsObject, \"thunder\");\n            FishingTracker.lordJawbuses = getSCFromApi(killsObject, \"lord_jawbus\");\n\n            System.out.println(\"Writing SC to config...\");\n            CfgConfig.writeIntConfig(\"fishing\", \"goodCatch\", FishingTracker.goodCatches);\n            CfgConfig.writeIntConfig(\"fishing\", \"greatCatch\", FishingTracker.greatCatches);\n            CfgConfig.writeIntConfig(\"fishing\", \"seaCreature\", FishingTracker.seaCreatures);\n            CfgConfig.writeIntConfig(\"fishing\", \"squid\", FishingTracker.squids);\n            CfgConfig.writeIntConfig(\"fishing\", \"seaWalker\", FishingTracker.seaWalkers);\n            CfgConfig.writeIntConfig(\"fishing\", \"nightSquid\", FishingTracker.nightSquids);\n            CfgConfig.writeIntConfig(\"fishing\", \"seaGuardian\", FishingTracker.seaGuardians);\n            CfgConfig.writeIntConfig(\"fishing\", \"seaWitch\", FishingTracker.seaWitches);\n            CfgConfig.writeIntConfig(\"fishing\", \"seaArcher\", FishingTracker.seaArchers);\n            CfgConfig.writeIntConfig(\"fishing\", \"monsterOfDeep\", FishingTracker.monsterOfTheDeeps);\n            CfgConfig.writeIntConfig(\"fishing\", \"agarimoo\", FishingTracker.agarimoos);\n            CfgConfig.writeIntConfig(\"fishing\", \"catfish\", FishingTracker.catfishes);\n            CfgConfig.writeIntConfig(\"fishing\", \"carrotKing\", FishingTracker.carrotKings);\n            CfgConfig.writeIntConfig(\"fishing\", \"seaLeech\", FishingTracker.seaLeeches);\n            CfgConfig.writeIntConfig(\"fishing\", \"guardianDefender\", FishingTracker.guardianDefenders);\n            CfgConfig.writeIntConfig(\"fishing\", \"deepSeaProtector\", FishingTracker.deepSeaProtectors);\n            CfgConfig.writeIntConfig(\"fishing\", \"hydra\", FishingTracker.hydras);\n            CfgConfig.writeIntConfig(\"fishing\", \"seaEmperor\", FishingTracker.seaEmperors);\n            CfgConfig.writeIntConfig(\"fishing\", \"milestone\", FishingTracker.fishingMilestone);\n            CfgConfig.writeIntConfig(\"fishing\", \"frozenSteve\", FishingTracker.frozenSteves);\n            CfgConfig.writeIntConfig(\"fishing\", \"snowman\", FishingTracker.frostyTheSnowmans);\n            CfgConfig.writeIntConfig(\"fishing\", \"grinch\", FishingTracker.grinches);\n            CfgConfig.writeIntConfig(\"fishing\", \"yeti\", FishingTracker.yetis);\n            CfgConfig.writeIntConfig(\"fishing\", \"reindrake\", FishingTracker.reindrakes);\n            CfgConfig.writeIntConfig(\"fishing\", \"nurseShark\", FishingTracker.nurseSharks);\n            CfgConfig.writeIntConfig(\"fishing\", \"blueShark\", FishingTracker.blueSharks);\n            CfgConfig.writeIntConfig(\"fishing\", \"tigerShark\", FishingTracker.tigerSharks);\n            CfgConfig.writeIntConfig(\"fishing\", \"greatWhiteShark\", FishingTracker.greatWhiteSharks);\n            CfgConfig.writeIntConfig(\"fishing\", \"scarecrow\", FishingTracker.scarecrows);\n            CfgConfig.writeIntConfig(\"fishing\", \"nightmare\", FishingTracker.nightmares);\n            CfgConfig.writeIntConfig(\"fishing\", \"werewolf\", FishingTracker.werewolfs);\n            CfgConfig.writeIntConfig(\"fishing\", \"phantomFisher\", FishingTracker.phantomFishers);\n            CfgConfig.writeIntConfig(\"fishing\", \"grimReaper\", FishingTracker.grimReapers);\n            CfgConfig.writeIntConfig(\"fishing\", \"waterWorm\", FishingTracker.waterWorms);\n            CfgConfig.writeIntConfig(\"fishing\", \"poisonedWaterWorm\", FishingTracker.poisonedWaterWorms);\n            CfgConfig.writeIntConfig(\"fishing\", \"flamingWorm\", FishingTracker.flamingWorms);\n            CfgConfig.writeIntConfig(\"fishing\", \"lavaBlaze\", FishingTracker.lavaBlazes);\n            CfgConfig.writeIntConfig(\"fishing\", \"lavaPigman\", FishingTracker.lavaPigmen);\n            CfgConfig.writeIntConfig(\"fishing\", \"zombieMiner\", FishingTracker.zombieMiners);\n            CfgConfig.writeIntConfig(\"fishing\", \"plhlegblast\", FishingTracker.plhlegblasts);\n            CfgConfig.writeIntConfig(\"fishing\", \"magmaSlug\", FishingTracker.magmaSlugs);\n            CfgConfig.writeIntConfig(\"fishing\", \"moogma\", FishingTracker.moogmas);\n            CfgConfig.writeIntConfig(\"fishing\", \"lavaLeech\", FishingTracker.lavaLeeches);\n            CfgConfig.writeIntConfig(\"fishing\", \"pyroclasticWorm\", FishingTracker.pyroclasticWorms);\n            CfgConfig.writeIntConfig(\"fishing\", \"lavaFlame\", FishingTracker.lavaFlames);\n            CfgConfig.writeIntConfig(\"fishing\", \"fireEel\", FishingTracker.fireEels);\n            CfgConfig.writeIntConfig(\"fishing\", \"taurus\", FishingTracker.tauruses);\n            CfgConfig.writeIntConfig(\"fishing\", \"thunder\", FishingTracker.thunders);\n            CfgConfig.writeIntConfig(\"fishing\", \"lordJawbus\", FishingTracker.lordJawbuses);\n\n            TrophyFishTracker.fish = TrophyFishTracker.createEmpty();\n            TrophyFishTracker.fish.add(\"Sulphur Skitter\", Utils.getTrophyFromAPI(trophyObject, \"sulphur_skitter\"));\n            TrophyFishTracker.fish.add(\"Obfuscated 1\", Utils.getTrophyFromAPI(trophyObject, \"obfuscated_fish_1\"));\n            TrophyFishTracker.fish.add(\"Steaming-Hot Flounder\", Utils.getTrophyFromAPI(trophyObject, \"steaming_hot_flounder\"));\n            TrophyFishTracker.fish.add(\"Obfuscated 2\", Utils.getTrophyFromAPI(trophyObject, \"obfuscated_fish_2\"));\n            TrophyFishTracker.fish.add(\"Gusher\", Utils.getTrophyFromAPI(trophyObject, \"gusher\"));\n            TrophyFishTracker.fish.add(\"Blobfish\", Utils.getTrophyFromAPI(trophyObject, \"blobfish\"));\n            TrophyFishTracker.fish.add(\"Slugfish\", Utils.getTrophyFromAPI(trophyObject, \"slugfish\"));\n            TrophyFishTracker.fish.add(\"Obfuscated 3\", Utils.getTrophyFromAPI(trophyObject, \"obfuscated_fish_3\"));\n            TrophyFishTracker.fish.add(\"Flyfish\", Utils.getTrophyFromAPI(trophyObject, \"flyfish\"));\n            TrophyFishTracker.fish.add(\"Lavahorse\", Utils.getTrophyFromAPI(trophyObject, \"lava_horse\"));\n            TrophyFishTracker.fish.add(\"Mana Ray\", Utils.getTrophyFromAPI(trophyObject, \"mana_ray\"));\n            TrophyFishTracker.fish.add(\"Volcanic Stonefish\", Utils.getTrophyFromAPI(trophyObject, \"volcanic_stonefish\"));\n            TrophyFishTracker.fish.add(\"Vanille\", Utils.getTrophyFromAPI(trophyObject, \"vanille\"));\n            TrophyFishTracker.fish.add(\"Skeleton Fish\", Utils.getTrophyFromAPI(trophyObject, \"skeleton_fish\"));\n            TrophyFishTracker.fish.add(\"Moldfin\", Utils.getTrophyFromAPI(trophyObject, \"moldfin\"));\n            TrophyFishTracker.fish.add(\"Soul Fish\", Utils.getTrophyFromAPI(trophyObject, \"soul_fish\"));\n            TrophyFishTracker.fish.add(\"Karate Fish\", Utils.getTrophyFromAPI(trophyObject, \"karate_fish\"));\n            TrophyFishTracker.fish.add(\"Golden Fish\", Utils.getTrophyFromAPI(trophyObject, \"golden_fish\"));\n            TrophyFishTracker.save();\n\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Fishing stats imported.\"));\n        }).start();\n    }\n\n    static int getSCFromApi(JsonObject obj, String key) {\n        int sc = 0;\n        if (obj.has(key)) sc = obj.get(key).getAsInt();\n        FishingTracker.seaCreatures += sc;\n        return sc;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/loot/LootCommand.java",
    "content": "package me.Danker.commands.loot;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.features.loot.*;\nimport me.Danker.utils.Utils;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.text.NumberFormat;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class LootCommand extends CommandBase {\n\n    @Override\n    public String getCommandName() {\n        return \"loot\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \" <zombie/spider/wolf/enderman/blaze/vampire/fishing/catacombs/mythological> [winter/festival/spooky/ch/lava/trophy/f(1-7)/mm/session]\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new LootCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n    \n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length == 1) {\n            return getListOfStringsMatchingLastWord(args, \"wolf\", \"spider\", \"zombie\", \"enderman\", \"blaze\", \"vampire\", \"fishing\", \"catacombs\", \"mythological\");\n        } else if (args.length == 2 && args[0].equalsIgnoreCase(\"fishing\")) {\n            return getListOfStringsMatchingLastWord(args, \"winter\", \"festival\", \"spooky\", \"ch\", \"lava\", \"trophy\", \"session\");\n        } else if (args.length == 2 && args[0].equalsIgnoreCase(\"catacombs\")) {\n            return getListOfStringsMatchingLastWord(args, \"f1\", \"floor1\", \"f2\", \"floor2\", \"f3\", \"floor3\", \"f4\", \"floor4\", \"f5\", \"floor5\", \"f6\", \"floor6\", \"f7\", \"floor7\", \"mm\", \"master\");\n        } else if (args.length > 1) {\n            return getListOfStringsMatchingLastWord(args, \"session\");\n        }\n        return null;\n    }\n\n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        EntityPlayer player = (EntityPlayer) arg0;\n        \n        if (arg1.length == 0) {\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: \" + getCommandUsage(arg0)));\n            return;\n        }\n\n        double timeNow = System.currentTimeMillis() / 1000;\n        String timeBetween;\n        String bossesBetween;\n        String drop20;\n        NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);\n\n        boolean showSession = arg1[arg1.length - 1].equalsIgnoreCase(\"session\");\n\n        switch (arg1[0].toLowerCase()) {\n            case \"wolf\":\n                if (showSession) {\n                    if (WolfTracker.timeSession == -1) {\n                        timeBetween = \"Never\";\n                    } else {\n                        timeBetween = Utils.getTimeBetween(WolfTracker.timeSession, timeNow);\n                    }\n                    if (WolfTracker.bossesSession == -1) {\n                        bossesBetween = \"Never\";\n                    } else {\n                        bossesBetween = nf.format(WolfTracker.bossesSession);\n                    }\n                    if (LootDisplay.slayerCountTotal) {\n                        drop20 = nf.format(WolfTracker.wheelsSession);\n                    } else {\n                        drop20 = nf.format(WolfTracker.wheelsDropsSession) + \" times\";\n                    }\n\n                    player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                                EnumChatFormatting.DARK_AQUA + EnumChatFormatting.BOLD + \"  Sven Loot Summary (Current Session):\\n\" +\n                                                                EnumChatFormatting.GOLD + \"    Svens Killed: \" + nf.format(WolfTracker.svensSession) + \"\\n\" +\n                                                                EnumChatFormatting.GREEN + \"    Wolf Teeth: \" + nf.format(WolfTracker.teethSession) + \"\\n\" +\n                                                                EnumChatFormatting.BLUE + \"    Hamster Wheels: \" + drop20 + \"\\n\" +\n                                                                EnumChatFormatting.AQUA + \"    Spirit Runes: \" + WolfTracker.spiritsSession + \"\\n\" +\n                                                                EnumChatFormatting.WHITE + \"    Critical VI Books: \" + WolfTracker.booksSession + \"\\n\" +\n                                                                EnumChatFormatting.DARK_AQUA + \"    Furballs: \" + WolfTracker.furballsSession + \"\\n\" +\n                                                                EnumChatFormatting.DARK_RED + \"    Red Claw Eggs: \" + WolfTracker.eggsSession + \"\\n\" +\n                                                                EnumChatFormatting.GOLD + \"    Couture Runes: \" + WolfTracker.couturesSession + \"\\n\" +\n                                                                EnumChatFormatting.AQUA + \"    Grizzly Baits: \" + WolfTracker.baitsSession + \"\\n\" +\n                                                                EnumChatFormatting.DARK_PURPLE + \"    Overfluxes: \" + WolfTracker.fluxesSession + \"\\n\" +\n                                                                EnumChatFormatting.AQUA + \"    Time Since RNG: \" + timeBetween + \"\\n\" +\n                                                                EnumChatFormatting.AQUA + \"    Bosses Since RNG: \" + bossesBetween + \"\\n\" +\n                                                                EnumChatFormatting.AQUA + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                    return;\n                }\n\n                if (WolfTracker.time == -1) {\n                    timeBetween = \"Never\";\n                } else {\n                    timeBetween = Utils.getTimeBetween(WolfTracker.time, timeNow);\n                }\n                if (WolfTracker.bosses == -1) {\n                    bossesBetween = \"Never\";\n                } else {\n                    bossesBetween = nf.format(WolfTracker.bosses);\n                }\n                if (LootDisplay.slayerCountTotal) {\n                    drop20 = nf.format(WolfTracker.wheels);\n                } else {\n                    drop20 = nf.format(WolfTracker.wheelsDrops) + \" times\";\n                }\n\n                player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                            EnumChatFormatting.DARK_AQUA + EnumChatFormatting.BOLD + \"  Sven Loot Summary:\\n\" +\n                                                            EnumChatFormatting.GOLD + \"    Svens Killed: \" + nf.format(WolfTracker.svens) + \"\\n\" +\n                                                            EnumChatFormatting.GREEN + \"    Wolf Teeth: \" + nf.format(WolfTracker.teeth) + \"\\n\" +\n                                                            EnumChatFormatting.BLUE + \"    Hamster Wheels: \" + drop20 + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + \"    Spirit Runes: \" + WolfTracker.spirits + \"\\n\" +\n                                                            EnumChatFormatting.WHITE + \"    Critical VI Books: \" + WolfTracker.books + \"\\n\" +\n                                                            EnumChatFormatting.DARK_AQUA + \"    Furballs: \" + WolfTracker.furballs + \"\\n\" +\n                                                            EnumChatFormatting.DARK_RED + \"    Red Claw Eggs: \" + WolfTracker.eggs + \"\\n\" +\n                                                            EnumChatFormatting.GOLD + \"    Couture Runes: \" + WolfTracker.coutures + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + \"    Grizzly Baits: \" + WolfTracker.baits + \"\\n\" +\n                                                            EnumChatFormatting.DARK_PURPLE + \"    Overfluxes: \" + WolfTracker.fluxes + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + \"    Time Since RNG: \" + timeBetween + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + \"    Bosses Since RNG: \" + bossesBetween + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                break;\n            case \"spider\":\n                if (showSession) {\n                    if (SpiderTracker.timeSession == -1) {\n                        timeBetween = \"Never\";\n                    } else {\n                        timeBetween = Utils.getTimeBetween(SpiderTracker.timeSession, timeNow);\n                    }\n                    if (SpiderTracker.bossesSession == -1) {\n                        bossesBetween = \"Never\";\n                    } else {\n                        bossesBetween = nf.format(SpiderTracker.bossesSession);\n                    }\n                    if (LootDisplay.slayerCountTotal) {\n                        drop20 = nf.format(SpiderTracker.TAPSession);\n                    } else {\n                        drop20 = nf.format(SpiderTracker.TAPDropsSession) + \" times\";\n                    }\n\n                    player.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                                EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + \"  Spider Loot Summary (Current Session):\\n\" +\n                                                                EnumChatFormatting.GOLD + \"    Tarantulas Killed: \" + nf.format(SpiderTracker.tarantulasSession) + \"\\n\" +\n                                                                EnumChatFormatting.GREEN + \"    Tarantula Webs: \" + nf.format(SpiderTracker.websSession) + \"\\n\" +\n                                                                EnumChatFormatting.DARK_GREEN + \"    Arrow Poison: \" + drop20 + \"\\n\" +\n                                                                EnumChatFormatting.DARK_GRAY + \"    Bite Runes: \" + SpiderTracker.bitesSession + \"\\n\" +\n                                                                EnumChatFormatting.WHITE + \"    Bane VI Books: \" + SpiderTracker.booksSession + \"\\n\" +\n                                                                EnumChatFormatting.AQUA + \"    Spider Catalysts: \" + SpiderTracker.catalystsSession + \"\\n\" +\n                                                                EnumChatFormatting.DARK_PURPLE + \"    Tarantula Talismans: \" + SpiderTracker.talismansSession + \"\\n\" +\n                                                                EnumChatFormatting.LIGHT_PURPLE + \"    Fly Swatters: \" + SpiderTracker.swattersSession + \"\\n\" +\n                                                                EnumChatFormatting.GOLD + \"    Digested Mosquitos: \" + SpiderTracker.mosquitosSession + \"\\n\" +\n                                                                EnumChatFormatting.AQUA + \"    Time Since RNG: \" + timeBetween + \"\\n\" +\n                                                                EnumChatFormatting.AQUA + \"    Bosses Since RNG: \" + bossesBetween + \"\\n\" +\n                                                                EnumChatFormatting.RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                    return;\n                }\n\n                if (SpiderTracker.time == -1) {\n                    timeBetween = \"Never\";\n                } else {\n                    timeBetween = Utils.getTimeBetween(SpiderTracker.time, timeNow);\n                }\n                if (SpiderTracker.bosses == -1) {\n                    bossesBetween = \"Never\";\n                } else {\n                    bossesBetween = nf.format(SpiderTracker.bosses);\n                }\n                if (LootDisplay.slayerCountTotal) {\n                    drop20 = nf.format(SpiderTracker.TAP);\n                } else {\n                    drop20 = nf.format(SpiderTracker.TAPDrops) + \" times\";\n                }\n\n                player.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                            EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + \"  Spider Loot Summary:\\n\" +\n                                                            EnumChatFormatting.GOLD + \"    Tarantulas Killed: \" + nf.format(SpiderTracker.tarantulas) + \"\\n\" +\n                                                            EnumChatFormatting.GREEN + \"    Tarantula Webs: \" + nf.format(SpiderTracker.webs) + \"\\n\" +\n                                                            EnumChatFormatting.DARK_GREEN + \"    Arrow Poison: \" + drop20 + \"\\n\" +\n                                                            EnumChatFormatting.DARK_GRAY + \"    Bite Runes: \" + SpiderTracker.bites + \"\\n\" +\n                                                            EnumChatFormatting.WHITE + \"    Bane VI Books: \" + SpiderTracker.books + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + \"    Spider Catalysts: \" + SpiderTracker.catalysts + \"\\n\" +\n                                                            EnumChatFormatting.DARK_PURPLE + \"    Tarantula Talismans: \" + SpiderTracker.talismans + \"\\n\" +\n                                                            EnumChatFormatting.LIGHT_PURPLE + \"    Fly Swatters: \" + SpiderTracker.swatters + \"\\n\" +\n                                                            EnumChatFormatting.GOLD + \"    Digested Mosquitos: \" + SpiderTracker.mosquitos + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + \"    Time Since RNG: \" + timeBetween + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + \"    Bosses Since RNG: \" + bossesBetween + \"\\n\" +\n                                                            EnumChatFormatting.RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                break;\n            case \"zombie\":\n                if (showSession) {\n                    if (ZombieTracker.timeSession == -1) {\n                        timeBetween = \"Never\";\n                    } else {\n                        timeBetween = Utils.getTimeBetween(ZombieTracker.timeSession, timeNow);\n                    }\n                    if (ZombieTracker.bossesSession == -1) {\n                        bossesBetween = \"Never\";\n                    } else {\n                        bossesBetween = nf.format(ZombieTracker.bossesSession);\n                    }\n                    if (LootDisplay.slayerCountTotal) {\n                        drop20 = nf.format(ZombieTracker.foulFleshSession);\n                    } else {\n                        drop20 = nf.format(ZombieTracker.foulFleshDropsSession) + \" times\";\n                    }\n\n                    player.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                                EnumChatFormatting.DARK_GREEN + EnumChatFormatting.BOLD + \"  Zombie Loot Summary (Current Session):\\n\" +\n                                                                EnumChatFormatting.GOLD + \"    Revs Killed: \" + nf.format(ZombieTracker.revsSession) + \"\\n\" +\n                                                                EnumChatFormatting.GREEN + \"    Revenant Flesh: \" + nf.format(ZombieTracker.revFleshSession) + \"\\n\" +\n                                                                EnumChatFormatting.GREEN + \"    Revenant Viscera: \" + nf.format(ZombieTracker.revVisceraSession) + \"\\n\" +\n                                                                EnumChatFormatting.BLUE + \"    Foul Flesh: \" + drop20 + \"\\n\" +\n                                                                EnumChatFormatting.DARK_GREEN + \"    Pestilence Runes: \" +ZombieTracker.pestilencesSession + \"\\n\" +\n                                                                EnumChatFormatting.WHITE + \"    Smite VI Books: \" + ZombieTracker.booksSession + \"\\n\" +\n                                                                EnumChatFormatting.WHITE + \"    Smite VII Books: \" + ZombieTracker.booksT7Session + \"\\n\" +\n                                                                EnumChatFormatting.AQUA + \"    Undead Catalysts: \" + ZombieTracker.undeadCatasSession + \"\\n\" +\n                                                                EnumChatFormatting.DARK_PURPLE + \"    Beheaded Horrors: \" + ZombieTracker.beheadedsSession + \"\\n\" +\n                                                                EnumChatFormatting.RED + \"    Revenant Catalysts: \" + ZombieTracker.revCatasSession + \"\\n\" +\n                                                                EnumChatFormatting.DARK_GREEN + \"    Snake Runes: \" + ZombieTracker.snakesSession + \"\\n\" +\n                                                                EnumChatFormatting.GOLD + \"    Scythe Blades: \" + ZombieTracker.scythesSession + \"\\n\" +\n                                                                EnumChatFormatting.RED + \"    Shard of the Shreddeds: \" + ZombieTracker.shardsSession + \"\\n\" +\n                                                                EnumChatFormatting.RED + \"    Warden Hearts: \" + ZombieTracker.wardenHeartsSession + \"\\n\" +\n                                                                EnumChatFormatting.AQUA + \"    Time Since RNG: \" + timeBetween + \"\\n\" +\n                                                                EnumChatFormatting.AQUA + \"    Bosses Since RNG: \" + bossesBetween + \"\\n\" +\n                                                                EnumChatFormatting.GREEN + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                    return;\n                }\n\n                if (ZombieTracker.time == -1) {\n                    timeBetween = \"Never\";\n                } else {\n                    timeBetween = Utils.getTimeBetween(ZombieTracker.time, timeNow);\n                }\n                if (ZombieTracker.bosses == -1) {\n                    bossesBetween = \"Never\";\n                } else {\n                    bossesBetween = nf.format(ZombieTracker.bosses);\n                }\n                if (LootDisplay.slayerCountTotal) {\n                    drop20 = nf.format(ZombieTracker.foulFlesh);\n                } else {\n                    drop20 = nf.format(ZombieTracker.foulFleshDrops) + \" times\";\n                }\n\n                player.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                            EnumChatFormatting.DARK_GREEN + EnumChatFormatting.BOLD + \"  Zombie Loot Summary:\\n\" +\n                                                            EnumChatFormatting.GOLD + \"    Revs Killed: \" + nf.format(ZombieTracker.revs) + \"\\n\" +\n                                                            EnumChatFormatting.GREEN + \"    Revenant Flesh: \" + nf.format(ZombieTracker.revFlesh) + \"\\n\" +\n                                                            EnumChatFormatting.GREEN + \"    Revenant Viscera: \" + nf.format(ZombieTracker.revViscera) + \"\\n\" +\n                                                            EnumChatFormatting.BLUE + \"    Foul Flesh: \" + drop20 + \"\\n\" +\n                                                            EnumChatFormatting.DARK_GREEN + \"    Pestilence Runes: \" + ZombieTracker.pestilences + \"\\n\" +\n                                                            EnumChatFormatting.WHITE + \"    Smite VI Books: \" + ZombieTracker.books + \"\\n\" +\n                                                            EnumChatFormatting.WHITE + \"    Smite VII Books: \" + ZombieTracker.booksT7 + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + \"    Undead Catalysts: \" + ZombieTracker.undeadCatas + \"\\n\" +\n                                                            EnumChatFormatting.DARK_PURPLE + \"    Beheaded Horrors: \" + ZombieTracker.beheadeds + \"\\n\" +\n                                                            EnumChatFormatting.RED + \"    Revenant Catalysts: \" + ZombieTracker.revCatas + \"\\n\" +\n                                                            EnumChatFormatting.DARK_GREEN + \"    Snake Runes: \" + ZombieTracker.snakes + \"\\n\" +\n                                                            EnumChatFormatting.GOLD + \"    Scythe Blades: \" + ZombieTracker.scythes + \"\\n\" +\n                                                            EnumChatFormatting.RED + \"    Shard of the Shreddeds: \" + ZombieTracker.shards + \"\\n\" +\n                                                            EnumChatFormatting.RED + \"    Warden Hearts: \" + ZombieTracker.wardenHearts + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + \"    Time Since RNG: \" + timeBetween + \"\\n\" +\n                                                            EnumChatFormatting.AQUA + \"    Bosses Since RNG: \" + bossesBetween + \"\\n\" +\n                                                            EnumChatFormatting.GREEN + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                break;\n            case \"enderman\":\n                if (showSession) {\n                    if (EndermanTracker.timeSession == -1) {\n                        timeBetween = \"Never\";\n                    } else {\n                        timeBetween = Utils.getTimeBetween(EndermanTracker.timeSession, timeNow);\n                    }\n                    if (EndermanTracker.bossesSession == -1) {\n                        bossesBetween = \"Never\";\n                    } else {\n                        bossesBetween = nf.format(EndermanTracker.bossesSession);\n                    }\n                    if (LootDisplay.slayerCountTotal) {\n                        drop20 = nf.format(EndermanTracker.TAPSession);\n                    } else {\n                        drop20 = nf.format(EndermanTracker.TAPDropsSession) + \" times\";\n                    }\n\n                    player.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_PURPLE + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                            EnumChatFormatting.DARK_GREEN + EnumChatFormatting.BOLD + \"  Enderman Loot Summary (Current Session):\\n\" +\n                            EnumChatFormatting.GOLD + \"    Voidglooms Killed: \" + nf.format(EndermanTracker.voidgloomsSession) + \"\\n\" +\n                            EnumChatFormatting.DARK_GRAY + \"    Null Spheres: \" + nf.format(EndermanTracker.nullSpheresSession) + \"\\n\" +\n                            EnumChatFormatting.DARK_PURPLE + \"    Arrow Poison: \" + drop20 + \"\\n\" +\n                            EnumChatFormatting.LIGHT_PURPLE + \"    Endersnake Runes: \" + EndermanTracker.endersnakesSession + \"\\n\" +\n                            EnumChatFormatting.DARK_GREEN + \"    Summoning Eyes: \" + EndermanTracker.summoningEyesSession + \"\\n\" +\n                            EnumChatFormatting.AQUA + \"    Mana Steal Books: \" + EndermanTracker.manaBooksSession + \"\\n\" +\n                            EnumChatFormatting.BLUE + \"    Transmission Tuners: \" + EndermanTracker.tunersSession + \"\\n\" +\n                            EnumChatFormatting.YELLOW + \"    Null Atoms: \" + EndermanTracker.atomsSession + \"\\n\" +\n                            EnumChatFormatting.YELLOW + \"    Hazmat Endermen: \" + EndermanTracker.hazmatsSession + \"\\n\" +\n                            EnumChatFormatting.AQUA + \"    Espresso Machines: \" + EndermanTracker.espressoMachinesSession + \"\\n\" +\n                            EnumChatFormatting.WHITE + \"    Smarty Pants Books: \" + EndermanTracker.smartyBooksSession + \"\\n\" +\n                            EnumChatFormatting.LIGHT_PURPLE + \"    End Runes: \" + EndermanTracker.endRunesSession + \"\\n\" +\n                            EnumChatFormatting.RED + \"    Blood Chalices: \" + EndermanTracker.chalicesSession + \"\\n\" +\n                            EnumChatFormatting.RED + \"    Sinful Dice: \" + EndermanTracker.diceSession + \"\\n\" +\n                            EnumChatFormatting.DARK_PURPLE + \"    Artifact Upgrader: \" + EndermanTracker.artifactsSession + \"\\n\" +\n                            EnumChatFormatting.DARK_PURPLE + \"    Enderman Skins: \" + EndermanTracker.skinsSession + \"\\n\" +\n                            EnumChatFormatting.GRAY + \"    Enchant Runes: \" + EndermanTracker.enchantRunesSession + \"\\n\" +\n                            EnumChatFormatting.GOLD + \"    Etherwarp Mergers: \" + EndermanTracker.mergersSession + \"\\n\" +\n                            EnumChatFormatting.GOLD + \"    Judgement Cores: \" + EndermanTracker.coresSession + \"\\n\" +\n                            EnumChatFormatting.RED + \"    Ender Slayer VII Books: \" + EndermanTracker.enderBooksSession + \"\\n\" +\n                            EnumChatFormatting.AQUA + \"    Time Since RNG: \" + timeBetween + \"\\n\" +\n                            EnumChatFormatting.AQUA + \"    Bosses Since RNG: \" + bossesBetween + \"\\n\" +\n                            EnumChatFormatting.DARK_PURPLE + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                    return;\n                }\n\n                if (EndermanTracker.time == -1) {\n                    timeBetween = \"Never\";\n                } else {\n                    timeBetween = Utils.getTimeBetween(EndermanTracker.time, timeNow);\n                }\n                if (EndermanTracker.bosses == -1) {\n                    bossesBetween = \"Never\";\n                } else {\n                    bossesBetween = nf.format(EndermanTracker.bosses);\n                }\n                if (LootDisplay.slayerCountTotal) {\n                    drop20 = nf.format(EndermanTracker.TAP);\n                } else {\n                    drop20 = nf.format(EndermanTracker.TAPDrops) + \" times\";\n                }\n\n                player.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_PURPLE + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                        EnumChatFormatting.DARK_GREEN + EnumChatFormatting.BOLD + \"  Enderman Loot Summary:\\n\" +\n                        EnumChatFormatting.GOLD + \"    Voidglooms Killed: \" + nf.format(EndermanTracker.voidglooms) + \"\\n\" +\n                        EnumChatFormatting.DARK_GRAY + \"    Null Spheres: \" + nf.format(EndermanTracker.nullSpheres) + \"\\n\" +\n                        EnumChatFormatting.DARK_PURPLE + \"    Arrow Poison: \" + drop20 + \"\\n\" +\n                        EnumChatFormatting.LIGHT_PURPLE + \"    Endersnake Runes: \" + EndermanTracker.endersnakes + \"\\n\" +\n                        EnumChatFormatting.DARK_GREEN + \"    Summoning Eyes: \" + EndermanTracker.summoningEyes + \"\\n\" +\n                        EnumChatFormatting.AQUA + \"    Mana Steal Books: \" + EndermanTracker.manaBooks + \"\\n\" +\n                        EnumChatFormatting.BLUE + \"    Transmission Tuners: \" + EndermanTracker.tuners + \"\\n\" +\n                        EnumChatFormatting.YELLOW + \"    Null Atoms: \" + EndermanTracker.atoms + \"\\n\" +\n                        EnumChatFormatting.YELLOW + \"    Hazmat Endermen: \" + EndermanTracker.hazmats + \"\\n\" +\n                        EnumChatFormatting.AQUA + \"    Espresso Machines: \" + EndermanTracker.espressoMachines + \"\\n\" +\n                        EnumChatFormatting.WHITE + \"    Smarty Pants Books: \" + EndermanTracker.smartyBooks + \"\\n\" +\n                        EnumChatFormatting.LIGHT_PURPLE + \"    End Runes: \" + EndermanTracker.endRunes + \"\\n\" +\n                        EnumChatFormatting.RED + \"    Blood Chalices: \" + EndermanTracker.chalices + \"\\n\" +\n                        EnumChatFormatting.RED + \"    Sinful Dice: \" + EndermanTracker.dice + \"\\n\" +\n                        EnumChatFormatting.DARK_PURPLE + \"    Artifact Upgrader: \" + EndermanTracker.artifacts + \"\\n\" +\n                        EnumChatFormatting.DARK_PURPLE + \"    Enderman Skins: \" + EndermanTracker.skins + \"\\n\" +\n                        EnumChatFormatting.GRAY + \"    Enchant Runes: \" + EndermanTracker.enchantRunes + \"\\n\" +\n                        EnumChatFormatting.GOLD + \"    Etherwarp Mergers: \" + EndermanTracker.mergers + \"\\n\" +\n                        EnumChatFormatting.GOLD + \"    Judgement Cores: \" + EndermanTracker.cores + \"\\n\" +\n                        EnumChatFormatting.RED + \"    Ender Slayer VII Books: \" + EndermanTracker.enderBooks + \"\\n\" +\n                        EnumChatFormatting.AQUA + \"    Time Since RNG: \" + timeBetween + \"\\n\" +\n                        EnumChatFormatting.AQUA + \"    Bosses Since RNG: \" + bossesBetween + \"\\n\" +\n                        EnumChatFormatting.DARK_PURPLE + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                break;\n            case \"blaze\":\n                if (showSession) {\n                    if (BlazeTracker.timeSession == -1) {\n                        timeBetween = \"Never\";\n                    } else {\n                        timeBetween = Utils.getTimeBetween(BlazeTracker.timeSession, timeNow);\n                    }\n                    if (BlazeTracker.bossesSession == -1) {\n                        bossesBetween = \"Never\";\n                    } else {\n                        bossesBetween = nf.format(BlazeTracker.bossesSession);\n                    }\n\n                    player.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                            EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + \"  Blaze Loot Summary (Current Session):\\n\" +\n                            EnumChatFormatting.GOLD + \"    Demonlords Killed: \" + nf.format(BlazeTracker.demonlordsSession) + \"\\n\" +\n                            EnumChatFormatting.GRAY + \"    Derelict Ashes: \" + nf.format(BlazeTracker.derelictAshesSession) + \"\\n\" +\n                            EnumChatFormatting.YELLOW + \"    Enchanted Blaze Powder: \" + nf.format(BlazeTracker.blazePowderSession) + \"\\n\" +\n                            EnumChatFormatting.RED + \"    Lavatear Runes: \" + nf.format(BlazeTracker.lavatearRunesSession) + \"\\n\" +\n                            EnumChatFormatting.AQUA + \"    Splash Potions: \" + nf.format(BlazeTracker.splashPotionsSession) + \"\\n\" +\n                            EnumChatFormatting.DARK_RED + \"    Magma Arrows: \" + nf.format(BlazeTracker.magmaArrowsSession) + \"\\n\" +\n                            EnumChatFormatting.DARK_AQUA + \"    Mana Disintegrators: \" + nf.format(BlazeTracker.manaDisintegratorsSession) + \"\\n\" +\n                            EnumChatFormatting.LIGHT_PURPLE + \"    Scorched Books: \" + nf.format(BlazeTracker.scorchedBooksSession) + \"\\n\" +\n                            EnumChatFormatting.WHITE + \"    Kelvin Inverters: \" + nf.format(BlazeTracker.kelvinInvertersSession) + \"\\n\" +\n                            EnumChatFormatting.BLUE + \"    Blaze Rod Distillates: \" + nf.format(BlazeTracker.blazeRodDistillatesSession) + \"\\n\" +\n                            EnumChatFormatting.BLUE + \"    Glowstone Distillates: \" + nf.format(BlazeTracker.glowstoneDistillatesSession) + \"\\n\" +\n                            EnumChatFormatting.BLUE + \"    Magma Cream Distillates: \" + nf.format(BlazeTracker.magmaCreamDistillatesSession) + \"\\n\" +\n                            EnumChatFormatting.BLUE + \"    Nether Wart Distillates: \" + nf.format(BlazeTracker.netherWartDistillatesSession) + \"\\n\" +\n                            EnumChatFormatting.BLUE + \"    Gabagool Distillates: \" + nf.format(BlazeTracker.gabagoolDistillatesSession) + \"\\n\" +\n                            EnumChatFormatting.RED + \"    Scorched Power Crystals: \" + nf.format(BlazeTracker.scorchedPowerCrystalsSession) + \"\\n\" +\n                            EnumChatFormatting.RED + \"    Fire Aspect Books: \" + nf.format(BlazeTracker.fireAspectBooksSession) + \"\\n\" +\n                            EnumChatFormatting.GOLD + \"    Fiery Burst Runes: \" + nf.format(BlazeTracker.fieryBurstRunesSession) + \"\\n\" +\n                            EnumChatFormatting.WHITE + \"    Opal Gems: \" + nf.format(BlazeTracker.opalGemsSession) + \"\\n\" +\n                            EnumChatFormatting.RED + \"    Archfiend Dice: \" + nf.format(BlazeTracker.archfiendDiceSession) + \"\\n\" +\n                            EnumChatFormatting.LIGHT_PURPLE + \"    Duplex Books: \" + nf.format(BlazeTracker.duplexBooksSession) + \"\\n\" +\n                            EnumChatFormatting.GOLD + \"    High Class Archfiend Dice: \" + nf.format(BlazeTracker.highClassArchfiendDiceSession) + \"\\n\" +\n                            EnumChatFormatting.GOLD + \"    Engineering Plans: \" + nf.format(BlazeTracker.engineeringPlansSession) + \"\\n\" +\n                            EnumChatFormatting.GOLD + \"    Subzero Inverters: \" + nf.format(BlazeTracker.subzeroInvertersSession) + \"\\n\" +\n                            EnumChatFormatting.AQUA + \"    Time Since RNG: \" + timeBetween + \"\\n\" +\n                            EnumChatFormatting.AQUA + \"    Bosses Since RNG: \" + bossesBetween + \"\\n\" +\n                            EnumChatFormatting.RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                    return;\n                }\n\n                if (BlazeTracker.time == -1) {\n                    timeBetween = \"Never\";\n                } else {\n                    timeBetween = Utils.getTimeBetween(BlazeTracker.time, timeNow);\n                }\n                if (BlazeTracker.bosses == -1) {\n                    bossesBetween = \"Never\";\n                } else {\n                    bossesBetween = nf.format(BlazeTracker.bosses);\n                }\n\n                player.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                        EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + \"  Blaze Loot Summary:\\n\" +\n                        EnumChatFormatting.GOLD + \"    Demonlords Killed: \" + nf.format(BlazeTracker.demonlords) + \"\\n\" +\n                        EnumChatFormatting.GRAY + \"    Derelict Ashes: \" + nf.format(BlazeTracker.derelictAshes) + \"\\n\" +\n                        EnumChatFormatting.YELLOW + \"    Enchanted Blaze Powder: \" + nf.format(BlazeTracker.blazePowder) + \"\\n\" +\n                        EnumChatFormatting.RED + \"    Lavatear Runes: \" + nf.format(BlazeTracker.lavatearRunes) + \"\\n\" +\n                        EnumChatFormatting.AQUA + \"    Splash Potions: \" + nf.format(BlazeTracker.splashPotions) + \"\\n\" +\n                        EnumChatFormatting.DARK_RED + \"    Magma Arrows: \" + nf.format(BlazeTracker.magmaArrows) + \"\\n\" +\n                        EnumChatFormatting.DARK_AQUA + \"    Mana Disintegrators: \" + nf.format(BlazeTracker.manaDisintegrators) + \"\\n\" +\n                        EnumChatFormatting.LIGHT_PURPLE + \"    Scorched Books: \" + nf.format(BlazeTracker.scorchedBooks) + \"\\n\" +\n                        EnumChatFormatting.WHITE + \"    Kelvin Inverters: \" + nf.format(BlazeTracker.kelvinInverters) + \"\\n\" +\n                        EnumChatFormatting.BLUE + \"    Blaze Rod Distillates: \" + nf.format(BlazeTracker.blazeRodDistillates) + \"\\n\" +\n                        EnumChatFormatting.BLUE + \"    Glowstone Distillates: \" + nf.format(BlazeTracker.glowstoneDistillates) + \"\\n\" +\n                        EnumChatFormatting.BLUE + \"    Magma Cream Distillates: \" + nf.format(BlazeTracker.magmaCreamDistillates) + \"\\n\" +\n                        EnumChatFormatting.BLUE + \"    Nether Wart Distillates: \" + nf.format(BlazeTracker.netherWartDistillates) + \"\\n\" +\n                        EnumChatFormatting.BLUE + \"    Gabagool Distillates: \" + nf.format(BlazeTracker.gabagoolDistillates) + \"\\n\" +\n                        EnumChatFormatting.RED + \"    Scorched Power Crystals: \" + nf.format(BlazeTracker.scorchedPowerCrystals) + \"\\n\" +\n                        EnumChatFormatting.RED + \"    Fire Aspect Books: \" + nf.format(BlazeTracker.fireAspectBooks) + \"\\n\" +\n                        EnumChatFormatting.GOLD + \"    Fiery Burst Runes: \" + nf.format(BlazeTracker.fieryBurstRunes) + \"\\n\" +\n                        EnumChatFormatting.WHITE + \"    Opal Gems: \" + nf.format(BlazeTracker.opalGems) + \"\\n\" +\n                        EnumChatFormatting.RED + \"    Archfiend Dice: \" + nf.format(BlazeTracker.archfiendDice) + \"\\n\" +\n                        EnumChatFormatting.LIGHT_PURPLE + \"    Duplex Books: \" + nf.format(BlazeTracker.duplexBooks) + \"\\n\" +\n                        EnumChatFormatting.GOLD + \"    High Class Archfiend Dice: \" + nf.format(BlazeTracker.highClassArchfiendDice) + \"\\n\" +\n                        EnumChatFormatting.GOLD + \"    Engineering Plans: \" + nf.format(BlazeTracker.engineeringPlans) + \"\\n\" +\n                        EnumChatFormatting.GOLD + \"    Subzero Inverters: \" + nf.format(BlazeTracker.subzeroInverters) + \"\\n\" +\n                        EnumChatFormatting.AQUA + \"    Time Since RNG: \" + timeBetween + \"\\n\" +\n                        EnumChatFormatting.AQUA + \"    Bosses Since RNG: \" + bossesBetween + \"\\n\" +\n                        EnumChatFormatting.RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                break;\n            case \"vampire\":\n                if (showSession) {\n                    player.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                            EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + \"  Vampire Loot Summary (Current Session):\\n\" +\n                            EnumChatFormatting.GOLD + \"    Riftstalkers Killed: \" + nf.format(VampireTracker.riftstalkersSession) + \"\\n\" +\n                            EnumChatFormatting.DARK_RED + \"    Coven Seals: \" + nf.format(VampireTracker.covenSealsSession) + \"\\n\" +\n                            EnumChatFormatting.DARK_AQUA + \"    Quantum Bundles: \" + nf.format(VampireTracker.quantumBundlesSession) + \"\\n\" +\n                            EnumChatFormatting.RED + \"    Bubba Blisters: \" + nf.format(VampireTracker.bubbaBlistersSession) + \"\\n\" +\n                            EnumChatFormatting.LIGHT_PURPLE + \"    Soultwist Runes: \" + nf.format(VampireTracker.soultwistRunesSession) + \"\\n\" +\n                            EnumChatFormatting.GRAY + \"    Chocolate Chips: \" + nf.format(VampireTracker.chocolateChipsSession) + \"\\n\" +\n                            EnumChatFormatting.GOLD + \"    Lucky Blocks: \" + nf.format(VampireTracker.luckyBlocksSession) + \"\\n\" +\n                            EnumChatFormatting.RED + \"    The One Bundles: \" + nf.format(VampireTracker.theOneBundlesSession) + \"\\n\" +\n                            EnumChatFormatting.GREEN + \"    McGrubber's Burgers: \" + nf.format(VampireTracker.mcgrubbersBurgersSession) + \"\\n\" +\n                            EnumChatFormatting.WHITE + \"    Vampire Parts: \" + nf.format(VampireTracker.vampirePartsSession) + \"\\n\" +\n                            EnumChatFormatting.RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                    return;\n                }\n\n                player.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                        EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + \"  Vampire Loot Summary:\\n\" +\n                        EnumChatFormatting.GOLD + \"    Riftstalkers Killed: \" + nf.format(VampireTracker.riftstalkers) + \"\\n\" +\n                        EnumChatFormatting.DARK_RED + \"    Coven Seals: \" + nf.format(VampireTracker.covenSeals) + \"\\n\" +\n                        EnumChatFormatting.DARK_AQUA + \"    Quantum Bundles: \" + nf.format(VampireTracker.quantumBundles) + \"\\n\" +\n                        EnumChatFormatting.RED + \"    Bubba Blisters: \" + nf.format(VampireTracker.bubbaBlisters) + \"\\n\" +\n                        EnumChatFormatting.LIGHT_PURPLE + \"    Soultwist Runes: \" + nf.format(VampireTracker.soultwistRunes) + \"\\n\" +\n                        EnumChatFormatting.GRAY + \"    Chocolate Chips: \" + nf.format(VampireTracker.chocolateChips) + \"\\n\" +\n                        EnumChatFormatting.GOLD + \"    Lucky Blocks: \" + nf.format(VampireTracker.luckyBlocks) + \"\\n\" +\n                        EnumChatFormatting.RED + \"    The One Bundles: \" + nf.format(VampireTracker.theOneBundles) + \"\\n\" +\n                        EnumChatFormatting.GREEN + \"    McGrubber's Burgers: \" + nf.format(VampireTracker.mcgrubbersBurgers) + \"\\n\" +\n                        EnumChatFormatting.WHITE + \"    Vampire Parts: \" + nf.format(VampireTracker.vampireParts) + \"\\n\" +\n                        EnumChatFormatting.RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                break;\n            case \"fishing\":\n                if (arg1.length > 1) {\n                    if (arg1[1].equalsIgnoreCase(\"winter\")) {\n                        if (showSession) {\n                            if (FishingTracker.reindrakeTimeSession == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(FishingTracker.reindrakeTimeSession, timeNow);\n                            }\n                            if (FishingTracker.reindrakeSCsSession == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(FishingTracker.reindrakeSCsSession);\n                            }\n\n                            player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                                        EnumChatFormatting.WHITE + EnumChatFormatting.BOLD + \"  Winter Fishing Summary (Current Session):\\n\" +\n                                                                        EnumChatFormatting.AQUA + \"    Frozen Steves: \" + nf.format(FishingTracker.frozenStevesSession) + \"\\n\" +\n                                                                        EnumChatFormatting.WHITE + \"    Snowmans: \" + nf.format(FishingTracker.frostyTheSnowmansSession) + \"\\n\" +\n                                                                        EnumChatFormatting.DARK_GREEN + \"    Grinches: \" + nf.format(FishingTracker.grinchesSession) + \"\\n\" +\n                                                                        EnumChatFormatting.RED + \"    Nutcrackers: \" + nf.format(FishingTracker.nutcrackersSession) + \"\\n\" +\n                                                                        EnumChatFormatting.GOLD + \"    Yetis: \" + nf.format(FishingTracker.yetisSession) + \"\\n\" +\n                                                                        EnumChatFormatting.GOLD + \"    Reindrakes: \" + nf.format(FishingTracker.reindrakesSession) + \"\\n\" +\n                                                                        EnumChatFormatting.AQUA + \"    Time Since Reindrake: \" + timeBetween + \"\\n\" +\n                                                                        EnumChatFormatting.AQUA + \"    Creatures Since Reindrake: \" + bossesBetween + \"\\n\" +\n                                                                        EnumChatFormatting.AQUA + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                            return;\n                        }\n\n                        if (FishingTracker.reindrakeTime == -1) {\n                            timeBetween = \"Never\";\n                        } else {\n                            timeBetween = Utils.getTimeBetween(FishingTracker.reindrakeTime, timeNow);\n                        }\n                        if (FishingTracker.reindrakeSCs == -1) {\n                            bossesBetween = \"Never\";\n                        } else {\n                            bossesBetween = nf.format(FishingTracker.reindrakeSCs);\n                        }\n\n                        player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                                    EnumChatFormatting.WHITE + EnumChatFormatting.BOLD + \"  Winter Fishing Summary:\\n\" +\n                                                                    EnumChatFormatting.AQUA + \"    Frozen Steves: \" + nf.format(FishingTracker.frozenSteves) + \"\\n\" +\n                                                                    EnumChatFormatting.WHITE + \"    Snowmans: \" + nf.format(FishingTracker.frostyTheSnowmans) + \"\\n\" +\n                                                                    EnumChatFormatting.DARK_GREEN + \"    Grinches: \" + nf.format(FishingTracker.grinches) + \"\\n\" +\n                                                                    EnumChatFormatting.RED + \"    Nutcrackers: \" + nf.format(FishingTracker.nutcrackers) + \"\\n\" +\n                                                                    EnumChatFormatting.GOLD + \"    Yetis: \" + nf.format(FishingTracker.yetis) + \"\\n\" +\n                                                                    EnumChatFormatting.GOLD + \"    Reindrakes: \" + nf.format(FishingTracker.reindrakes) + \"\\n\" +\n                                                                    EnumChatFormatting.AQUA + \"    Time Since Reindrake: \" + timeBetween + \"\\n\" +\n                                                                    EnumChatFormatting.AQUA + \"    Creatures Since Reindrake: \" + bossesBetween + \"\\n\" +\n                                                                    EnumChatFormatting.AQUA + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                        return;\n                    } else if (arg1[1].equalsIgnoreCase(\"festival\")) {\n                        if (showSession) {\n                            player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                                        EnumChatFormatting.DARK_BLUE + EnumChatFormatting.BOLD + \" Fishing Festival Summary (Current Session):\\n\" +\n                                                                        EnumChatFormatting.LIGHT_PURPLE + \"    Nurse Sharks: \" + nf.format(FishingTracker.nurseSharksSession) + \"\\n\" +\n                                                                        EnumChatFormatting.BLUE + \"    Blue Sharks: \" + nf.format(FishingTracker.blueSharksSession) + \"\\n\" +\n                                                                        EnumChatFormatting.GOLD + \"    Tiger Sharks: \" + nf.format(FishingTracker.tigerSharksSession) + \"\\n\" +\n                                                                        EnumChatFormatting.WHITE + \"    Great White Sharks: \" + nf.format(FishingTracker.greatWhiteSharksSession) + \"\\n\" +\n                                                                        EnumChatFormatting.AQUA + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                            return;\n                        }\n\n                        player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                                    EnumChatFormatting.DARK_BLUE + EnumChatFormatting.BOLD + \" Fishing Festival Summary:\\n\" +\n                                                                    EnumChatFormatting.LIGHT_PURPLE + \"    Nurse Sharks: \" + nf.format(FishingTracker.nurseSharks) + \"\\n\" +\n                                                                    EnumChatFormatting.BLUE + \"    Blue Sharks: \" + nf.format(FishingTracker.blueSharks) + \"\\n\" +\n                                                                    EnumChatFormatting.GOLD + \"    Tiger Sharks: \" + nf.format(FishingTracker.tigerSharks) + \"\\n\" +\n                                                                    EnumChatFormatting.WHITE + \"    Great White Sharks: \" + nf.format(FishingTracker.greatWhiteSharks) + \"\\n\" +\n                                                                    EnumChatFormatting.AQUA + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                        return;\n                    } else if (arg1[1].equalsIgnoreCase(\"spooky\")) {\n                        if (showSession) {\n                            player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                                        EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + \" Spooky Fishing Summary (Current Session):\\n\" +\n                                                                        EnumChatFormatting.BLUE + \"    Scarecrows: \" + nf.format(FishingTracker.scarecrowsSession) + \"\\n\" +\n                                                                        EnumChatFormatting.GRAY + \"    Nightmares: \" + nf.format(FishingTracker.nightmaresSession) + \"\\n\" +\n                                                                        EnumChatFormatting.DARK_PURPLE + \"    Werewolves: \" + nf.format(FishingTracker.werewolfsSession) + \"\\n\" +\n                                                                        EnumChatFormatting.GOLD + \"    Phantom Fishers: \" + nf.format(FishingTracker.phantomFishersSession) + \"\\n\" +\n                                                                        EnumChatFormatting.GOLD + \"    Grim Reapers: \" + nf.format(FishingTracker.grimReapersSession) + \"\\n\" +\n                                                                        EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                            return;\n                        }\n\n                        player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                                    EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + \" Spooky Fishing Summary:\\n\" +\n                                                                    EnumChatFormatting.BLUE + \"    Scarecrows: \" + nf.format(FishingTracker.scarecrows) + \"\\n\" +\n                                                                    EnumChatFormatting.GRAY + \"    Nightmares: \" + nf.format(FishingTracker.nightmares) + \"\\n\" +\n                                                                    EnumChatFormatting.DARK_PURPLE + \"    Werewolves: \" + nf.format(FishingTracker.werewolfs) + \"\\n\" +\n                                                                    EnumChatFormatting.GOLD + \"    Phantom Fishers: \" + nf.format(FishingTracker.phantomFishers) + \"\\n\" +\n                                                                    EnumChatFormatting.GOLD + \"    Grim Reapers: \" + nf.format(FishingTracker.grimReapers) + \"\\n\" +\n                                                                    EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                        return;\n                    } else if (arg1[1].equalsIgnoreCase(\"ch\")) {\n                        if (showSession) {\n                            player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                                        EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + \" Crystal Hollows Fishing Summary (Current Session):\\n\" +\n                                                                        EnumChatFormatting.BLUE + \"    Water Worms: \" + nf.format(FishingTracker.waterWormsSession) + \"\\n\" +\n                                                                        EnumChatFormatting.GREEN + \"    Poisoned Water Worms: \" + nf.format(FishingTracker.poisonedWaterWormsSession) + \"\\n\" +\n                                                                        EnumChatFormatting.RED + \"    Flaming Worms: \" + nf.format(FishingTracker.flamingWormsSession) + \"\\n\" +\n                                                                        EnumChatFormatting.LIGHT_PURPLE + \"    Lava Blazes: \" + nf.format(FishingTracker.lavaBlazesSession) + \"\\n\" +\n                                                                        EnumChatFormatting.LIGHT_PURPLE + \"    Lava Pigmen: \" + nf.format(FishingTracker.lavaPigmenSession) + \"\\n\" +\n                                                                        EnumChatFormatting.GOLD + \"    Zombie Miners: \" + nf.format(FishingTracker.zombieMinersSession) + \"\\n\" +\n                                                                        EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\n                            return;\n                        }\n\n                        player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                                                    EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + \" Crystal Hollows Fishing Summary:\\n\" +\n                                                                    EnumChatFormatting.BLUE + \"    Water Worms: \" + nf.format(FishingTracker.waterWorms) + \"\\n\" +\n                                                                    EnumChatFormatting.GREEN + \"    Poisoned Water Worms: \" + nf.format(FishingTracker.poisonedWaterWorms) + \"\\n\" +\n                                                                    EnumChatFormatting.RED + \"    Flaming Worms: \" + nf.format(FishingTracker.flamingWorms) + \"\\n\" +\n                                                                    EnumChatFormatting.LIGHT_PURPLE + \"    Lava Blazes: \" + nf.format(FishingTracker.lavaBlazes) + \"\\n\" +\n                                                                    EnumChatFormatting.LIGHT_PURPLE + \"    Lava Pigmen: \" + nf.format(FishingTracker.lavaPigmen) + \"\\n\" +\n                                                                    EnumChatFormatting.GOLD + \"    Zombie Miners: \" + nf.format(FishingTracker.zombieMiners) + \"\\n\" +\n                                                                    EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                        return;\n                    } else if (arg1[1].equalsIgnoreCase(\"lava\")) {\n                        if (showSession) {\n                            if (FishingTracker.jawbusTimeSession == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(FishingTracker.jawbusTimeSession, timeNow);\n                            }\n                            if (FishingTracker.jawbusSCsSession == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(FishingTracker.jawbusSCsSession);\n                            }\n\n                            player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                    EnumChatFormatting.RED + EnumChatFormatting.BOLD + \" Lava Fishing Summary (Current Session):\\n\" +\n                                    EnumChatFormatting.BLUE + \"    Plhlegblasts: \" + nf.format(FishingTracker.plhlegblastsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_RED + \"    Magma Slugs: \" + nf.format(FishingTracker.magmaSlugsSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + \"    Moogmas: \" + nf.format(FishingTracker.moogmasSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + \"    Lava Leeches: \" + nf.format(FishingTracker.lavaLeechesSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + \"    Pyroclastic Worms: \" + nf.format(FishingTracker.pyroclasticWormsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_RED + \"    Lava Flames: \" + nf.format(FishingTracker.lavaFlamesSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + \"    Fire Eels: \" + nf.format(FishingTracker.fireEelsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + \"    Tauruses: \" + nf.format(FishingTracker.taurusesSession) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"    Thunders: \" + nf.format(FishingTracker.thundersSession) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"    Lord Jawbuses: \" + nf.format(FishingTracker.lordJawbusesSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + \"    Time Since Lord Jawbus: \" + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + \"    Creatures Since Lord Jawbus: \" + bossesBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                            return;\n                        }\n\n                        if (FishingTracker.jawbusTime == -1) {\n                            timeBetween = \"Never\";\n                        } else {\n                            timeBetween = Utils.getTimeBetween(FishingTracker.jawbusTime, timeNow);\n                        }\n                        if (FishingTracker.jawbusSCs == -1) {\n                            bossesBetween = \"Never\";\n                        } else {\n                            bossesBetween = nf.format(FishingTracker.jawbusSCs);\n                        }\n\n                        player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                EnumChatFormatting.RED + EnumChatFormatting.BOLD + \" Lava Fishing Summary:\\n\" +\n                                EnumChatFormatting.BLUE + \"    Plhlegblasts: \" + nf.format(FishingTracker.plhlegblasts) + \"\\n\" +\n                                EnumChatFormatting.DARK_RED + \"    Magma Slugs: \" + nf.format(FishingTracker.magmaSlugs) + \"\\n\" +\n                                EnumChatFormatting.RED + \"    Moogmas: \" + nf.format(FishingTracker.moogmas) + \"\\n\" +\n                                EnumChatFormatting.RED + \"    Lava Leeches: \" + nf.format(FishingTracker.lavaLeeches) + \"\\n\" +\n                                EnumChatFormatting.RED + \"    Pyroclastic Worms: \" + nf.format(FishingTracker.pyroclasticWorms) + \"\\n\" +\n                                EnumChatFormatting.DARK_RED + \"    Lava Flames: \" + nf.format(FishingTracker.lavaFlames) + \"\\n\" +\n                                EnumChatFormatting.RED + \"    Fire Eels: \" + nf.format(FishingTracker.fireEels) + \"\\n\" +\n                                EnumChatFormatting.GOLD + \"    Tauruses: \" + nf.format(FishingTracker.tauruses) + \"\\n\" +\n                                EnumChatFormatting.LIGHT_PURPLE + \"    Thunders: \" + nf.format(FishingTracker.thunders) + \"\\n\" +\n                                EnumChatFormatting.LIGHT_PURPLE + \"    Lord Jawbuses: \" + nf.format(FishingTracker.lordJawbuses) + \"\\n\" +\n                                EnumChatFormatting.AQUA + \"    Time Since Lord Jawbus: \" + timeBetween + \"\\n\" +\n                                EnumChatFormatting.AQUA + \"    Creatures Since Lord Jawbus: \" + bossesBetween + \"\\n\" +\n                                EnumChatFormatting.AQUA + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                        return;\n                    } else if (arg1[1].equalsIgnoreCase(\"trophy\")) {\n                        if (showSession) {\n                            player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                    EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + \" Trophy Fishing Summary (Current Session):\\n\" +\n                                    EnumChatFormatting.WHITE + \"    Sulphur Skitter \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Sulphur Skitter\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Sulphur Skitter\") + \"\\n\" +\n                                    EnumChatFormatting.WHITE + \"    Obfuscated 1 \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Obfuscated 1\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Obfuscated 1\") + \"\\n\" +\n                                    EnumChatFormatting.WHITE + \"    Steaminghot Flounder \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Steaming-Hot Flounder\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Steaming-Hot Flounder\") + \"\\n\" +\n                                    EnumChatFormatting.WHITE + \"    Gusher \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Gusher\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Gusher\") + \"\\n\" +\n                                    EnumChatFormatting.WHITE + \"    Blobfish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Blobfish\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Blobfish\") + \"\\n\" +\n                                    EnumChatFormatting.GREEN + \"    Obfuscated 2 \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Obfuscated 2\") + \")\" + EnumChatFormatting.GREEN + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Obfuscated 2\") + \"\\n\" +\n                                    EnumChatFormatting.GREEN + \"    Slugfish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Slugfish\") + \")\" + EnumChatFormatting.GREEN + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Slugfish\") + \"\\n\" +\n                                    EnumChatFormatting.GREEN + \"    Flyfish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Flyfish\") + \")\" + EnumChatFormatting.GREEN + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Flyfish\") + \"\\n\" +\n                                    EnumChatFormatting.BLUE + \"    Obfuscated 3 \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Obfuscated 3\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Obfuscated 3\") + \"\\n\" +\n                                    EnumChatFormatting.BLUE + \"    Lavahorse \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Lavahorse\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Lavahorse\") + \"\\n\" +\n                                    EnumChatFormatting.BLUE + \"    Mana Ray \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Mana Ray\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Mana Ray\") + \"\\n\" +\n                                    EnumChatFormatting.BLUE + \"    Volcanic Stonefish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Volcanic Stonefish\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Volcanic Stonefish\") + \"\\n\" +\n                                    EnumChatFormatting.BLUE + \"    Vanille \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Vanille\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Vanille\") + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"    Skeleton Fish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Skeleton Fish\") + \")\" + EnumChatFormatting.DARK_PURPLE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Skeleton Fish\") + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"    Moldfin \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Moldfin\") + \")\" + EnumChatFormatting.DARK_PURPLE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Moldfin\") + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"    Soul Fish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Soul Fish\") + \")\" + EnumChatFormatting.DARK_PURPLE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Soul Fish\") + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"    Karate Fish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Karate Fish\") + \")\" + EnumChatFormatting.DARK_PURPLE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Karate Fish\") + \"\\n\" +\n                                    EnumChatFormatting.GOLD + \"    Golden Fish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fishSession, \"Golden Fish\") + \")\" + EnumChatFormatting.GOLD + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Golden Fish\") + \"\\n\" +\n                                    EnumChatFormatting.AQUA + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n                            return;\n                        }\n\n                        player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n                                EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + \" Trophy Fishing Summary:\\n\" +\n                                EnumChatFormatting.WHITE + \"    Sulphur Skitter \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Sulphur Skitter\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Sulphur Skitter\") + \"\\n\" +\n                                EnumChatFormatting.WHITE + \"    Obfuscated 1 \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Obfuscated 1\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Obfuscated 1\") + \"\\n\" +\n        \t\t\t\t\t\tEnumChatFormatting.WHITE + \"    Steaminghot Flounder \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Steaming-Hot Flounder\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Steaming-Hot Flounder\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.WHITE + \"    Gusher \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Gusher\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Gusher\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.WHITE + \"    Blobfish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Blobfish\") + \")\" + EnumChatFormatting.WHITE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Blobfish\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.GREEN + \"    Obfuscated 2 \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Obfuscated 2\") + \")\" + EnumChatFormatting.GREEN + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Obfuscated 2\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.GREEN + \"    Slugfish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Slugfish\") + \")\" + EnumChatFormatting.GREEN + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Slugfish\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.GREEN + \"    Flyfish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Flyfish\") + \")\" + EnumChatFormatting.GREEN + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Flyfish\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Obfuscated 3 \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Obfuscated 3\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Obfuscated 3\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Lavahorse \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Lavahorse\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Lavahorse\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Mana Ray \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Mana Ray\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Mana Ray\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Volcanic Stonefish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Volcanic Stonefish\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Volcanic Stonefish\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Vanille \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Vanille\") + \")\" + EnumChatFormatting.BLUE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Vanille\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Skeleton Fish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Skeleton Fish\") + \")\" + EnumChatFormatting.DARK_PURPLE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Skeleton Fish\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Moldfin \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Moldfin\") + \")\" + EnumChatFormatting.DARK_PURPLE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Moldfin\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Soul Fish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Soul Fish\") + \")\" + EnumChatFormatting.DARK_PURPLE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Soul Fish\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Karate Fish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Karate Fish\") + \")\" + EnumChatFormatting.DARK_PURPLE + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Karate Fish\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Golden Fish \" + EnumChatFormatting.DARK_GRAY + \"(\" + TrophyFishTracker.getSum(TrophyFishTracker.fish, \"Golden Fish\") + \")\" + EnumChatFormatting.GOLD + \": \" + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Golden Fish\") + \"\\n\" +\n\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (showSession) {\n\t\t\t\t\tif (FishingTracker.empTimeSession == -1) {\n\t\t\t\t\t\ttimeBetween = \"Never\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttimeBetween = Utils.getTimeBetween(FishingTracker.empTimeSession, timeNow);\n\t\t\t\t\t}\n\t\t\t\t\tif (FishingTracker.empSCsSession == -1) {\n\t\t\t\t\t\tbossesBetween = \"Never\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbossesBetween = nf.format(FishingTracker.empSCsSession);\n\t\t\t\t\t}\n\n\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + EnumChatFormatting.BOLD + \"  Fishing Summary (Current Session):\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Sea Creatures Caught: \" + nf.format(FishingTracker.seaCreaturesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Good Catches: \" + nf.format(FishingTracker.goodCatchesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Great Catches: \" + nf.format(FishingTracker.greatCatchesSession) + \"\\n\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GRAY + \"    Squids: \" + nf.format(FishingTracker.squidsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GREEN + \"    Sea Walkers: \" + nf.format(FishingTracker.seaWalkersSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_GRAY + \"    Night Squids: \" + nf.format(FishingTracker.nightSquidsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_AQUA + \"    Sea Guardians: \" + nf.format(FishingTracker.seaGuardiansSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Sea Witches: \" + nf.format(FishingTracker.seaWitchesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GREEN + \"    Sea Archers: \" + nf.format(FishingTracker.seaArchersSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GREEN + \"    Monster of the Deeps: \" + nf.format(FishingTracker.monsterOfTheDeepsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + \"    Agarimoos: \" + nf.format(FishingTracker.agarimoosSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.YELLOW + \"    Catfishes: \" + nf.format(FishingTracker.catfishesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Carrot Kings: \" + nf.format(FishingTracker.carrotKingsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GRAY + \"    Sea Leeches: \" + nf.format(FishingTracker.seaLeechesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Guardian Defenders: \" + nf.format(FishingTracker.guardianDefendersSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Deep Sea Protectors: \" + nf.format(FishingTracker.deepSeaProtectorsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Hydras: \" + nf.format(FishingTracker.hydrasSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Sea Emperors: \" + nf.format(FishingTracker.seaEmperorsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Since Sea Emperor: \" + timeBetween + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Sea Creatures Since Sea Emperor: \" + bossesBetween + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_AQUA + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (FishingTracker.empTime == -1) {\n\t\t\t\t\ttimeBetween = \"Never\";\n\t\t\t\t} else {\n\t\t\t\t\ttimeBetween = Utils.getTimeBetween(FishingTracker.empTime, timeNow);\n\t\t\t\t}\n\t\t\t\tif (FishingTracker.empSCs == -1) {\n\t\t\t\t\tbossesBetween = \"Never\";\n\t\t\t\t} else {\n\t\t\t\t\tbossesBetween = nf.format(FishingTracker.empSCs);\n\t\t\t\t}\n\n\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_AQUA + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + EnumChatFormatting.BOLD + \"  Fishing Summary:\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Sea Creatures Caught: \" + nf.format(FishingTracker.seaCreatures) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Good Catches: \" + nf.format(FishingTracker.goodCatches) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Great Catches: \" + nf.format(FishingTracker.greatCatches) + \"\\n\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GRAY + \"    Squids: \" + nf.format(FishingTracker.squids) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GREEN + \"    Sea Walkers: \" + nf.format(FishingTracker.seaWalkers) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_GRAY + \"    Night Squids: \" + nf.format(FishingTracker.nightSquids) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_AQUA + \"    Sea Guardians: \" + nf.format(FishingTracker.seaGuardians) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Sea Witches: \" + nf.format(FishingTracker.seaWitches) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GREEN + \"    Sea Archers: \" + nf.format(FishingTracker.seaArchers) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GREEN + \"    Monster of the Deeps: \" + nf.format(FishingTracker.monsterOfTheDeeps) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + \"    Agarimoos: \" + nf.format(FishingTracker.agarimoos) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.YELLOW + \"    Catfishes: \" + nf.format(FishingTracker.catfishes) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Carrot Kings: \" + nf.format(FishingTracker.carrotKings) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GRAY + \"    Sea Leeches: \" + nf.format(FishingTracker.seaLeeches) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Guardian Defenders: \" + nf.format(FishingTracker.guardianDefenders) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Deep Sea Protectors: \" + nf.format(FishingTracker.deepSeaProtectors) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Hydras: \" + nf.format(FishingTracker.hydras) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Sea Emperors: \" + nf.format(FishingTracker.seaEmperors) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Since Sea Emperor: \" + timeBetween + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Sea Creatures Since Sea Emperor: \" + bossesBetween + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_AQUA + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\n\t\t\t\tbreak;\n\t\t\tcase \"mythological\":\n\t\t\t\tif (showSession) {\n\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.GOLD + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.YELLOW + EnumChatFormatting.BOLD + \"  Mythological Event Summary (Current Session):\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.YELLOW + \"    Coins: \" + Utils.getMoneySpent(MythologicalTracker.mythCoinsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.WHITE + \"    Griffin Feathers: \" + nf.format(MythologicalTracker.griffinFeathersSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Crown of Greeds: \" + nf.format(MythologicalTracker.crownOfGreedsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Washed-up Souvenirs: \" + nf.format(MythologicalTracker.washedUpSouvenirsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + \"    Minos Hunters: \" + nf.format(MythologicalTracker.minosHuntersSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GRAY + \"   Siamese Lynxes: \" + nf.format(MythologicalTracker.siameseLynxesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + \"   Minotaurs: \" + nf.format(MythologicalTracker.minotaursSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.WHITE + \"   Gaia Constructs: \" + nf.format(MythologicalTracker.gaiaConstructsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Minos Champions: \" + nf.format(MythologicalTracker.minosChampionsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Minos Inquisitors: \" + nf.format(MythologicalTracker.minosInquisitorsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.GOLD + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.YELLOW + EnumChatFormatting.BOLD + \"  Mythological Event Summary:\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.YELLOW + \"    Coins: \" + Utils.getMoneySpent(MythologicalTracker.mythCoins) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.WHITE + \"    Griffin Feathers: \" + nf.format(MythologicalTracker.griffinFeathers) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Crown of Greeds: \" + nf.format(MythologicalTracker.crownOfGreeds) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Washed-up Souvenirs: \" + nf.format(MythologicalTracker.washedUpSouvenirs) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + \"    Minos Hunters: \" + nf.format(MythologicalTracker.minosHunters) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GRAY + \"   Siamese Lynxes: \" + nf.format(MythologicalTracker.siameseLynxes) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + \"   Minotaurs: \" + nf.format(MythologicalTracker.minotaurs) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.WHITE + \"   Gaia Constructs: \" + nf.format(MythologicalTracker.gaiaConstructs) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Minos Champions: \" + nf.format(MythologicalTracker.minosChampions) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Minos Inquisitors: \" + nf.format(MythologicalTracker.minosInquisitors) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\tbreak;\n\t\t\tcase \"catacombs\":\n\t\t\t\tif (arg1.length == 1) {\n\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: /loot catacombs <f1/f2/f3/f4/f5/f6/f7>\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tswitch (arg1[1].toLowerCase()) {\n\t\t\t\t\tcase \"f1\":\n\t\t\t\t\tcase \"floor1\":\n\t\t\t\t\t\tif (showSession) {\n\t\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F1 Summary (Current Session):\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f1SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GREEN + \"    Balloon Snakes: \" + nf.format(CatacombsTracker.balloonSnakesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Bonzo's Staffs: \" + nf.format(CatacombsTracker.bonzoStaffsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f1CoinsSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f1TimeSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F1 Summary:\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f1SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GREEN + \"    Balloon Snakes: \" + nf.format(CatacombsTracker.balloonSnakes) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Bonzo's Staffs: \" + nf.format(CatacombsTracker.bonzoStaffs) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f1CoinsSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f1TimeSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"f2\":\n\t\t\t\t\tcase \"floor2\":\n\t\t\t\t\t\tif (showSession) {\n\t\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F2 Summary (Current Session):\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f2SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Scarf's Studies: \" + nf.format(CatacombsTracker.scarfStudiesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Adaptive Blades: \" + nf.format(CatacombsTracker.adaptiveSwordsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Adaptive Belts: \" + nf.format(CatacombsTracker.adaptiveBeltsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f2CoinsSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f2TimeSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F2 Summary:\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f2SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Scarf's Studies: \" + nf.format(CatacombsTracker.scarfStudies) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Adaptive Blades: \" + nf.format(CatacombsTracker.adaptiveSwords) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Adaptive Belts: \" + nf.format(CatacombsTracker.adaptiveBelts) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f2CoinsSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f2TimeSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"f3\":\n\t\t\t\t\tcase \"floor3\":\n\t\t\t\t\t\tif (showSession) {\n\t\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F3 Summary (Current Session):\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f3SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Adaptive Helmets: \" + nf.format(CatacombsTracker.adaptiveHelmsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Adaptive Chestplates: \" + nf.format(CatacombsTracker.adaptiveChestsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Adaptive Leggings: \" + nf.format(CatacombsTracker.adaptiveLegsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Adaptive Boots: \" + nf.format(CatacombsTracker.adaptiveBootsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f3CoinsSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f3TimeSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F3 Summary:\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f3SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Adaptive Helmets: \" + nf.format(CatacombsTracker.adaptiveHelms) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Adaptive Chestplates: \" + nf.format(CatacombsTracker.adaptiveChests) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Adaptive Leggings: \" + nf.format(CatacombsTracker.adaptiveLegs) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Adaptive Boots: \" + nf.format(CatacombsTracker.adaptiveBoots) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f3CoinsSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f3TimeSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"f4\":\n\t\t\t\t\tcase \"floor4\":\n\t\t\t\t\t\tif (showSession) {\n\t\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F4 Summary (Current Session):\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f4SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Spirit Wings: \" + nf.format(CatacombsTracker.spiritWingsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Spirit Bones: \" + nf.format(CatacombsTracker.spiritBonesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Spirit Boots: \" + nf.format(CatacombsTracker.spiritBootsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Spirit Swords: \" + nf.format(CatacombsTracker.spiritSwordsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Spirit Bows: \" + nf.format(CatacombsTracker.spiritBowsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Epic Spirit Pets: \" + nf.format(CatacombsTracker.epicSpiritPetsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Leg Spirit Pets: \" + nf.format(CatacombsTracker.legSpiritPetsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f4CoinsSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f4TimeSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F4 Summary:\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f4SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Spirit Wings: \" + nf.format(CatacombsTracker.spiritWings) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Spirit Bones: \" + nf.format(CatacombsTracker.spiritBones) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Spirit Boots: \" + nf.format(CatacombsTracker.spiritBoots) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Spirit Swords: \" + nf.format(CatacombsTracker.spiritSwords) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Spirit Bows: \" + nf.format(CatacombsTracker.spiritBows) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Epic Spirit Pets: \" + nf.format(CatacombsTracker.epicSpiritPets) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Leg Spirit Pets: \" + nf.format(CatacombsTracker.legSpiritPets) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f4CoinsSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f4TimeSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"f5\":\n\t\t\t\t\tcase \"floor5\":\n\t\t\t\t\t\tif (showSession) {\n\t\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F5 Summary (Current Session):\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f5SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Warped Stones: \" + nf.format(CatacombsTracker.warpedStonesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Shadow Assassin Helmets: \" + nf.format(CatacombsTracker.shadowAssHelmsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Shadow Assassin Chests: \" + nf.format(CatacombsTracker.shadowAssChestsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Shadow Assassin Legs: \" + nf.format(CatacombsTracker.shadowAssLegsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Shadow Assassin Boots: \" + nf.format(CatacombsTracker.shadowAssBootsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Shadow Assassin Cloaks: \" + nf.format(CatacombsTracker.shadowAssCloaksSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Last Breaths: \" + nf.format(CatacombsTracker.lastBreathsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Livid Daggers: \" + nf.format(CatacombsTracker.lividDaggersSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Shadow Furys: \" + nf.format(CatacombsTracker.shadowFurysSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f5CoinsSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f5TimeSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F5 Summary:\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f5SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Warped Stones: \" + nf.format(CatacombsTracker.warpedStones) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Shadow Assassin Helmets: \" + nf.format(CatacombsTracker.shadowAssHelms) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Shadow Assassin Chests: \" + nf.format(CatacombsTracker.shadowAssChests) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Shadow Assassin Legs: \" + nf.format(CatacombsTracker.shadowAssLegs) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Shadow Assassin Boots: \" + nf.format(CatacombsTracker.shadowAssBoots) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Shadow Assassin Cloaks: \" + nf.format(CatacombsTracker.shadowAssCloaks) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Last Breaths: \" + nf.format(CatacombsTracker.lastBreaths) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Livid Daggers: \" + nf.format(CatacombsTracker.lividDaggers) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Shadow Furys: \" + nf.format(CatacombsTracker.shadowFurys) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f5CoinsSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f5TimeSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"f6\":\n\t\t\t\t\tcase \"floor6\":\n\t\t\t\t\t\tif (showSession) {\n\t\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F6 Summary (Current Session):\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f6SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Ancient Roses: \" + nf.format(CatacombsTracker.ancientRosesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Precursor Eyes: \" + nf.format(CatacombsTracker.precursorEyesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Giant's Swords: \" + nf.format(CatacombsTracker.giantsSwordsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Necro Lord Helmets: \" + nf.format(CatacombsTracker.necroLordHelmsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Necro Lord Chestplates: \" + nf.format(CatacombsTracker.necroLordChestsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Necro Lord Leggings: \" + nf.format(CatacombsTracker.necroLordLegsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Necro Lord Boots: \" + nf.format(CatacombsTracker.necroLordBootsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Necro Swords: \" + nf.format(CatacombsTracker.necroSwordsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fel Skulls: \" + nf.format(CatacombsTracker.felSkullsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.WHITE + \"    Rerolls: \" + nf.format(CatacombsTracker.f6RerollsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f6CoinsSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f6TimeSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F6 Summary:\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f6SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.BLUE + \"    Ancient Roses: \" + nf.format(CatacombsTracker.ancientRoses) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Precursor Eyes: \" + nf.format(CatacombsTracker.precursorEyes) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Giant's Swords: \" + nf.format(CatacombsTracker.giantsSwords) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Necro Lord Helmets: \" + nf.format(CatacombsTracker.necroLordHelms) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Necro Lord Chestplates: \" + nf.format(CatacombsTracker.necroLordChests) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Necro Lord Leggings: \" + nf.format(CatacombsTracker.necroLordLegs) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Necro Lord Boots: \" + nf.format(CatacombsTracker.necroLordBoots) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Necro Swords: \" + nf.format(CatacombsTracker.necroSwords) + \"\\n\" +\n                                \t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fel Skulls: \" + nf.format(CatacombsTracker.felSkulls) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.WHITE + \"    Rerolls: \" + nf.format(CatacombsTracker.f6Rerolls) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f6CoinsSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f6TimeSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"f7\":\n\t\t\t\t\tcase \"floor7\":\n\t\t\t\t\t\tif (showSession) {\n\t\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F7 Summary (Current Session):\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f7SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Wither Bloods: \" + nf.format(CatacombsTracker.witherBloodsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Wither Cloaks: \" + nf.format(CatacombsTracker.witherCloaksSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Implosions: \" + nf.format(CatacombsTracker.implosionsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Wither Shields: \" + nf.format(CatacombsTracker.witherShieldsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Shadow Warps: \" + nf.format(CatacombsTracker.shadowWarpsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Necron's Handles: \" + nf.format(CatacombsTracker.necronsHandlesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Auto Recombobulator: \" + nf.format(CatacombsTracker.autoRecombsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Wither Helmets: \" + nf.format(CatacombsTracker.witherHelmsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Wither Chesplates: \" + nf.format(CatacombsTracker.witherChestsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Wither Leggings: \" + nf.format(CatacombsTracker.witherLegsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Wither Boots: \" + nf.format(CatacombsTracker.witherBootsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.WHITE + \"    Rerolls: \" + nf.format(CatacombsTracker.f7RerollsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f7CoinsSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f7TimeSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs F7 Summary:\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    S+ Runs: \" + nf.format(CatacombsTracker.f7SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulator 3000s: \" + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Wither Bloods: \" + nf.format(CatacombsTracker.witherBloods) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Wither Cloaks: \" + nf.format(CatacombsTracker.witherCloaks) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Implosions: \" + nf.format(CatacombsTracker.implosions) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Wither Shields: \" + nf.format(CatacombsTracker.witherShields) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Shadow Warps: \" + nf.format(CatacombsTracker.shadowWarps) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Necron's Handles: \" + nf.format(CatacombsTracker.necronsHandles) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Auto Recombobulator: \" + nf.format(CatacombsTracker.autoRecombs) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Wither Helmets: \" + nf.format(CatacombsTracker.witherHelms) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Wither Chesplates: \" + nf.format(CatacombsTracker.witherChests) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Wither Leggings: \" + nf.format(CatacombsTracker.witherLegs) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Wither Boots: \" + nf.format(CatacombsTracker.witherBoots) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.WHITE + \"    Rerolls: \" + nf.format(CatacombsTracker.f7Rerolls) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.f7CoinsSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.f7TimeSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"mm\":\n\t\t\t\t\tcase \"master\":\n\t\t\t\t\t\tif (showSession) {\n\t\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs MM Summary (Current Session):\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master One S Runs: \" + nf.format(CatacombsTracker.m1SSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master One S+ Runs: \" + nf.format(CatacombsTracker.m1SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Two S Runs: \" + nf.format(CatacombsTracker.m2SSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Two S+ Runs: \" + nf.format(CatacombsTracker.m2SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Three S Runs: \" + nf.format(CatacombsTracker.m3SSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Three S+ Runs: \" + nf.format(CatacombsTracker.m3SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Four S Runs: \" + nf.format(CatacombsTracker.m4SSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Four S+ Runs: \" + nf.format(CatacombsTracker.m4SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Five S Runs: \" + nf.format(CatacombsTracker.m5SSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Five S+ Runs: \" + nf.format(CatacombsTracker.m5SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Six S Runs: \" + nf.format(CatacombsTracker.m6SSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Six S+ Runs: \" + nf.format(CatacombsTracker.m6SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Seven S Runs: \" + nf.format(CatacombsTracker.m7SSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Seven S+ Runs: \" + nf.format(CatacombsTracker.m7SPlusSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulators: \" + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    1st Master Stars: \" + nf.format(CatacombsTracker.firstStarsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    2nd Master Stars: \" + nf.format(CatacombsTracker.secondStarsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    3rd Master Stars: \" + nf.format(CatacombsTracker.thirdStarsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    4th Master Stars: \" + nf.format(CatacombsTracker.fourthStarsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    5th Master Stars: \" + nf.format(CatacombsTracker.fifthStarsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Necron Dyes: \" + nf.format(CatacombsTracker.necronDyesSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Dark Claymores: \" + nf.format(CatacombsTracker.darkClaymoresSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.WHITE + \"    Rerolls: \" + nf.format(CatacombsTracker.masterRerollsSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.masterCoinsSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.masterTimeSpentSession) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED + \"\" + EnumChatFormatting.STRIKETHROUGH + \"-------------------\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.RED + EnumChatFormatting.BOLD + \"  Catacombs MM Summary:\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master One S Runs: \" + nf.format(CatacombsTracker.m1S) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master One S+ Runs: \" + nf.format(CatacombsTracker.m1SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Two S Runs: \" + nf.format(CatacombsTracker.m2S) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Two S+ Runs: \" + nf.format(CatacombsTracker.m2SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Three S Runs: \" + nf.format(CatacombsTracker.m3S) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Three S+ Runs: \" + nf.format(CatacombsTracker.m3SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Four S Runs: \" + nf.format(CatacombsTracker.m4S) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Four S+ Runs: \" + nf.format(CatacombsTracker.m4SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Five S Runs: \" + nf.format(CatacombsTracker.m5S) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Five S+ Runs: \" + nf.format(CatacombsTracker.m5SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Six S Runs: \" + nf.format(CatacombsTracker.m6S) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Six S+ Runs: \" + nf.format(CatacombsTracker.m6SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Seven S Runs: \" + nf.format(CatacombsTracker.m7S) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Master Seven S+ Runs: \" + nf.format(CatacombsTracker.m7SPlus) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Recombobulators: \" + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    Fuming Potato Books: \" + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    1st Master Stars: \" + nf.format(CatacombsTracker.firstStars) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    2nd Master Stars: \" + nf.format(CatacombsTracker.secondStars) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    3rd Master Stars: \" + nf.format(CatacombsTracker.thirdStars) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    4th Master Stars: \" + nf.format(CatacombsTracker.fourthStars) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_PURPLE + \"    5th Master Stars: \" + nf.format(CatacombsTracker.fifthStars) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Necron Dyes: \" + nf.format(CatacombsTracker.necronDyes) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.GOLD + \"    Dark Claymores: \" + nf.format(CatacombsTracker.darkClaymores) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.WHITE + \"    Rerolls: \" + nf.format(CatacombsTracker.masterRerolls) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Coins Spent: \" + Utils.getMoneySpent(CatacombsTracker.masterCoinsSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.AQUA + \"    Time Spent: \" + Utils.getTimeBetween(0, CatacombsTracker.masterTimeSpent) + \"\\n\" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEnumChatFormatting.DARK_RED + EnumChatFormatting.STRIKETHROUGH + \"-------------------\"));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tplayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: /loot catacombs <f1/f2/f3/f4/f5/f6/f7/mm>\"));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tplayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: \" + getCommandUsage(arg0)));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/loot/ResetLootCommand.java",
    "content": "package me.Danker.commands.loot;\n\nimport me.Danker.config.CfgConfig;\nimport me.Danker.config.ModConfig;\nimport me.Danker.features.loot.*;\nimport me.Danker.handlers.ConfigHandler;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.util.List;\n\npublic class ResetLootCommand extends CommandBase {\n\n    static String resetOption;\n    static boolean confirmReset = false;\n    \n    @Override\n    public String getCommandName() {\n        return \"resetloot\";\n    }\n\n    @Override\n    public String getCommandUsage(ICommandSender arg0) {\n        return \"/\" + getCommandName() + \"<zombie/spider/wolf/enderman/blaze/vampire/fishing/mythological/catacombs/confirm/cancel>\";\n    }\n\n    public static String usage(ICommandSender arg0) {\n        return new ResetLootCommand().getCommandUsage(arg0);\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n    \n    @Override\n    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {\n        if (args.length != 1) return null;\n        \n        if (confirmReset) {\n            return getListOfStringsMatchingLastWord(args, \"confirm\", \"cancel\");\n        } else {\n            return getListOfStringsMatchingLastWord(args, \"zombie\", \"spider\", \"wolf\", \"enderman\", \"blaze\", \"vampire\", \"fishing\", \"mythological\", \"catacombs\");\n        }\n    }\n    \n    @Override\n    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {\n        EntityPlayer player = (EntityPlayer) arg0;\n        \n        if (arg1.length == 0) {\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: /resetloot <zombie/spider/wolf/enderman/blaze/vampire/fishing/mythological/catacombs>\"));\n            return;\n        }\n        \n        if (confirmReset) {\n            switch (arg1[0].toLowerCase()) {\n                case \"confirm\":\n                    confirmReset = false;\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Resetting \" + resetOption + \" tracker...\"));\n                    switch (resetOption.toLowerCase()) {\n                        case \"zombie\":\n                            resetZombie();\n                            break;\n                        case \"spider\":\n                            resetSpider();\n                            break;\n                        case \"wolf\":\n                            resetWolf();\n                            break;\n                        case \"enderman\":\n                            resetEnderman();\n                            break;\n                        case \"blaze\":\n                            resetBlaze();\n                            break;\n                        case \"vampire\":\n                            resetVampire();\n                            break;\n                        case \"fishing\":\n                            resetFishing();\n                            break;\n                        case \"mythological\":\n                            resetMythological();\n                        case \"catacombs\":\n                            resetCatacombs();\n                        default:\n                            System.err.println(\"Resetting unknown tracker.\");\n                            return;\n                    }\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Reset complete.\"));\n                    break;\n                case \"cancel\":\n                    confirmReset = false;\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Reset cancelled.\"));\n                    break;\n                default:\n                    player.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + \"Please confirm the reset of the \" + resetOption + \" tracker by using /resetloot confirm.\" +\n                                                                EnumChatFormatting.RED + \" Cancel by using /resetloot cancel.\"));\n            }\n        } else {\n            switch (arg1[0].toLowerCase()) {\n                case \"zombie\":\n                case \"spider\":\n                case \"wolf\":\n                case \"enderman\":\n                case \"blaze\":\n                case \"vampire\":\n                case \"fishing\":\n                case \"mythological\":\n                case \"catacombs\":\n                    resetOption = arg1[0];\n                    player.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + \"Are you sure you want to reset the \" + resetOption + \" tracker?\" + \n                                                                \" Confirm with \" + ModConfig.getColour(ModConfig.mainColour) + \"/resetloot confirm\" + EnumChatFormatting.YELLOW + \".\" +\n                                                                \" Cancel by using \" + ModConfig.getColour(ModConfig.mainColour) + \"/resetloot cancel\" + EnumChatFormatting.YELLOW + \".\"));\n                    confirmReset = true;\n                    break;\n                case \"confirm\":\n                case \"cancel\":\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Pick something to reset first.\"));\n                    break;\n                default:\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Usage: \" + getCommandUsage(arg0)));\n            }\n        }\n    }\n    \n    static void resetZombie() {        \n        ZombieTracker.revsSession = 0;\n        ZombieTracker.revFleshSession = 0;\n        ZombieTracker.revVisceraSession = 0;\n        ZombieTracker.foulFleshSession = 0;\n        ZombieTracker.foulFleshDropsSession = 0;\n        ZombieTracker.pestilencesSession = 0;\n        ZombieTracker.undeadCatasSession = 0;\n        ZombieTracker.booksSession = 0;\n        ZombieTracker.booksT7Session = 0;\n        ZombieTracker.beheadedsSession = 0;\n        ZombieTracker.revCatasSession = 0;\n        ZombieTracker.snakesSession = 0;\n        ZombieTracker.scythesSession = 0;\n        ZombieTracker.timeSession = -1;\n        ZombieTracker.bossesSession = -1;\n        CfgConfig.deleteCategory(\"zombie\");\n        ConfigHandler.reloadConfig();\n    }\n    \n    static void resetSpider() {\n        SpiderTracker.tarantulasSession = 0;\n        SpiderTracker.websSession = 0;\n        SpiderTracker.TAPSession = 0;\n        SpiderTracker.TAPDropsSession = 0;\n        SpiderTracker.bitesSession = 0;\n        SpiderTracker.catalystsSession = 0;\n        SpiderTracker.booksSession = 0;\n        SpiderTracker.swattersSession = 0;\n        SpiderTracker.talismansSession = 0;\n        SpiderTracker.mosquitosSession = 0;\n        SpiderTracker.timeSession = -1;\n        SpiderTracker.bossesSession = -1;\n        CfgConfig.deleteCategory(\"spider\");\n        ConfigHandler.reloadConfig();\n    }\n    \n    static void resetWolf() {\n        WolfTracker.svensSession = 0;\n        WolfTracker.teethSession = 0;\n        WolfTracker.wheelsSession = 0;\n        WolfTracker.wheelsDropsSession = 0;\n        WolfTracker.spiritsSession = 0;\n        WolfTracker.booksSession = 0;\n        WolfTracker.furballsSession = 0;\n        WolfTracker.eggsSession = 0;\n        WolfTracker.couturesSession = 0;\n        WolfTracker.baitsSession = 0;\n        WolfTracker.fluxesSession = 0;\n        WolfTracker.timeSession = -1;\n        WolfTracker.bossesSession = -1;\n        CfgConfig.deleteCategory(\"wolf\");\n        ConfigHandler.reloadConfig();\n    }\n\n    static void resetEnderman() {\n        EndermanTracker.voidgloomsSession = 0;\n        EndermanTracker.nullSpheresSession = 0;\n        EndermanTracker.TAPSession = 0;\n        EndermanTracker.TAPDropsSession = 0;\n        EndermanTracker.endersnakesSession = 0;\n        EndermanTracker.summoningEyesSession = 0;\n        EndermanTracker.manaBooksSession = 0;\n        EndermanTracker.tunersSession = 0;\n        EndermanTracker.atomsSession = 0;\n        EndermanTracker.hazmatsSession = 0;\n        EndermanTracker.espressoMachinesSession = 0;\n        EndermanTracker.smartyBooksSession = 0;\n        EndermanTracker.endRunesSession = 0;\n        EndermanTracker.chalicesSession = 0;\n        EndermanTracker.diceSession = 0;\n        EndermanTracker.artifactsSession = 0;\n        EndermanTracker.skinsSession = 0;\n        EndermanTracker.mergersSession = 0;\n        EndermanTracker.coresSession = 0;\n        EndermanTracker.enchantRunesSession = 0;\n        EndermanTracker.enderBooksSession = 0;\n        EndermanTracker.timeSession = -1;\n        EndermanTracker.bossesSession = -1;\n        CfgConfig.deleteCategory(\"enderman\");\n        ConfigHandler.reloadConfig();\n    }\n\n    static void resetBlaze() {\n        BlazeTracker.demonlordsSession = 0;\n        BlazeTracker.derelictAshesSession = 0;\n        BlazeTracker.lavatearRunesSession = 0;\n        BlazeTracker.splashPotionsSession = 0;\n        BlazeTracker.magmaArrowsSession = 0;\n        BlazeTracker.manaDisintegratorsSession = 0;\n        BlazeTracker.scorchedBooksSession = 0;\n        BlazeTracker.kelvinInvertersSession = 0;\n        BlazeTracker.blazeRodDistillatesSession = 0;\n        BlazeTracker.glowstoneDistillatesSession = 0;\n        BlazeTracker.magmaCreamDistillatesSession = 0;\n        BlazeTracker.netherWartDistillatesSession = 0;\n        BlazeTracker.gabagoolDistillatesSession = 0;\n        BlazeTracker.scorchedPowerCrystalsSession = 0;\n        BlazeTracker.fireAspectBooksSession = 0;\n        BlazeTracker.fieryBurstRunesSession = 0;\n        BlazeTracker.opalGemsSession = 0;\n        BlazeTracker.archfiendDiceSession = 0;\n        BlazeTracker.duplexBooksSession = 0;\n        BlazeTracker.highClassArchfiendDiceSession = 0;\n        BlazeTracker.engineeringPlansSession = 0;\n        BlazeTracker.subzeroInvertersSession = 0;\n        BlazeTracker.timeSession = -1;\n        BlazeTracker.bossesSession = -1;\n        CfgConfig.deleteCategory(\"blaze\");\n        ConfigHandler.reloadConfig();\n    }\n\n    static void resetVampire() {\n        VampireTracker.riftstalkersSession = 0;\n        VampireTracker.covenSealsSession = 0;\n        VampireTracker.quantumBundlesSession = 0;\n        VampireTracker.bubbaBlistersSession = 0;\n        VampireTracker.soultwistRunesSession = 0;\n        VampireTracker.chocolateChipsSession = 0;\n        VampireTracker.luckyBlocksSession = 0;\n        VampireTracker.theOneBundlesSession = 0;\n        VampireTracker.mcgrubbersBurgersSession = 0;\n        VampireTracker.vampirePartsSession = 0;\n        CfgConfig.deleteCategory(\"vampire\");\n        ConfigHandler.reloadConfig();\n    }\n\n    static void resetFishing() {\n        FishingTracker.seaCreaturesSession = 0;\n        FishingTracker.goodCatchesSession = 0;\n        FishingTracker.greatCatchesSession = 0;\n        FishingTracker.squidsSession = 0;\n        FishingTracker.seaWalkersSession = 0;\n        FishingTracker.nightSquidsSession = 0;\n        FishingTracker.seaGuardiansSession = 0;\n        FishingTracker.seaWitchesSession = 0;\n        FishingTracker.seaArchersSession = 0;\n        FishingTracker.monsterOfTheDeepsSession = 0;\n        FishingTracker.agarimoosSession = 0;\n        FishingTracker.catfishesSession = 0;\n        FishingTracker.carrotKingsSession = 0;\n        FishingTracker.seaLeechesSession = 0;\n        FishingTracker.guardianDefendersSession = 0;\n        FishingTracker.deepSeaProtectorsSession = 0;\n        FishingTracker.hydrasSession = 0;\n        FishingTracker.seaEmperorsSession = 0;\n        FishingTracker.empTimeSession = -1;\n        FishingTracker.empSCsSession = -1;\n        FishingTracker.fishingMilestoneSession = 0;\n        FishingTracker.frozenStevesSession = 0;\n        FishingTracker.frostyTheSnowmansSession = 0;\n        FishingTracker.grinchesSession = 0;\n        FishingTracker.nutcrackersSession = 0;\n        FishingTracker.yetisSession = 0;\n        FishingTracker.reindrakesSession = 0;\n        FishingTracker.reindrakeTimeSession = -1;\n        FishingTracker.reindrakeSCsSession = -1;\n        FishingTracker.nurseSharksSession = 0;\n        FishingTracker.blueSharksSession = 0;\n        FishingTracker.tigerSharksSession = 0;\n        FishingTracker.greatWhiteSharksSession = 0;\n        FishingTracker.scarecrowsSession = 0;\n        FishingTracker.nightmaresSession = 0;\n        FishingTracker.werewolfsSession = 0;\n        FishingTracker.phantomFishersSession = 0;\n        FishingTracker.grimReapersSession = 0;\n        FishingTracker.waterWormsSession = 0;\n        FishingTracker.poisonedWaterWormsSession = 0;\n        FishingTracker.flamingWormsSession = 0;\n        FishingTracker.lavaBlazesSession = 0;\n        FishingTracker.lavaPigmenSession = 0;\n        FishingTracker.zombieMinersSession = 0;\n        FishingTracker.plhlegblastsSession = 0;\n        FishingTracker.magmaSlugsSession = 0;\n        FishingTracker.moogmasSession = 0;\n        FishingTracker.lavaLeechesSession = 0;\n        FishingTracker.pyroclasticWormsSession = 0;\n        FishingTracker.lavaFlamesSession = 0;\n        FishingTracker.fireEelsSession = 0;\n        FishingTracker.taurusesSession = 0;\n        FishingTracker.thundersSession = 0;\n        FishingTracker.lordJawbusesSession = 0;\n        FishingTracker.jawbusTimeSession = -1;\n        FishingTracker.jawbusSCsSession = -1;\n        CfgConfig.deleteCategory(\"fishing\");\n        ConfigHandler.reloadConfig();\n\n        TrophyFishTracker.fish = TrophyFishTracker.createEmpty();\n        TrophyFishTracker.fishSession = TrophyFishTracker.createEmpty();\n        TrophyFishTracker.save();\n    }\n    \n    static void resetMythological() {\n        MythologicalTracker.mythCoinsSession = 0;\n        MythologicalTracker.griffinFeathersSession = 0;\n        MythologicalTracker.crownOfGreedsSession = 0;\n        MythologicalTracker.washedUpSouvenirsSession = 0;\n        MythologicalTracker.minosHuntersSession = 0;\n        MythologicalTracker.siameseLynxesSession = 0;\n        MythologicalTracker.minotaursSession = 0;\n        MythologicalTracker.gaiaConstructsSession = 0;\n        MythologicalTracker.minosChampionsSession = 0;\n        MythologicalTracker.minosInquisitorsSession = 0;\n        CfgConfig.deleteCategory(\"mythological\");\n        ConfigHandler.reloadConfig();\n    }\n    \n    static void resetCatacombs() {\n        CatacombsTracker.recombobulatorsSession = 0;\n        CatacombsTracker.fumingPotatoBooksSession = 0;\n        CatacombsTracker.f1SPlusSession = 0;\n        CatacombsTracker.bonzoStaffsSession = 0;\n        CatacombsTracker.balloonSnakesSession = 0;\n        CatacombsTracker.f1CoinsSpentSession = 0;\n        CatacombsTracker.f1TimeSpentSession = 0;\n        CatacombsTracker.f2SPlusSession = 0;\n        CatacombsTracker.scarfStudiesSession = 0;\n        CatacombsTracker.adaptiveSwordsSession = 0;\n        CatacombsTracker.adaptiveBeltsSession = 0;\n        CatacombsTracker.f2CoinsSpentSession = 0;\n        CatacombsTracker.f2TimeSpentSession = 0;\n        CatacombsTracker.f3SPlusSession = 0;\n        CatacombsTracker.adaptiveHelmsSession = 0;\n        CatacombsTracker.adaptiveChestsSession = 0;\n        CatacombsTracker.adaptiveLegsSession = 0;\n        CatacombsTracker.adaptiveBootsSession = 0;\n        CatacombsTracker.f3CoinsSpentSession = 0;\n        CatacombsTracker.f3TimeSpentSession = 0;\n        CatacombsTracker.f4SPlusSession = 0;\n        CatacombsTracker.spiritWingsSession = 0;\n        CatacombsTracker.spiritBonesSession = 0;\n        CatacombsTracker.spiritBootsSession = 0;\n        CatacombsTracker.spiritSwordsSession = 0;\n        CatacombsTracker.epicSpiritPetsSession = 0;\n        CatacombsTracker.f4CoinsSpentSession = 0;\n        CatacombsTracker.f4TimeSpentSession = 0;\n        CatacombsTracker.f5SPlusSession = 0;\n        CatacombsTracker.warpedStonesSession = 0;\n        CatacombsTracker.shadowAssHelmsSession = 0;\n        CatacombsTracker.shadowAssChestsSession = 0;\n        CatacombsTracker.shadowAssLegsSession = 0;\n        CatacombsTracker.shadowAssBootsSession = 0;\n        CatacombsTracker.shadowAssCloaksSession = 0;\n        CatacombsTracker.lividDaggersSession = 0;\n        CatacombsTracker.shadowFurysSession = 0;\n        CatacombsTracker.f5CoinsSpentSession = 0;\n        CatacombsTracker.f5TimeSpentSession = 0;\n        CatacombsTracker.f6SPlusSession = 0;\n        CatacombsTracker.ancientRosesSession = 0;\n        CatacombsTracker.precursorEyesSession = 0;\n        CatacombsTracker.giantsSwordsSession = 0;\n        CatacombsTracker.necroLordHelmsSession = 0;\n        CatacombsTracker.necroLordChestsSession = 0;\n        CatacombsTracker.necroLordLegsSession = 0;\n        CatacombsTracker.necroLordBootsSession = 0;\n        CatacombsTracker.necroSwordsSession = 0;\n        CatacombsTracker.felSkullsSession = 0;\n        CatacombsTracker.f6RerollsSession = 0;\n        CatacombsTracker.f6CoinsSpentSession = 0;\n        CatacombsTracker.f6TimeSpentSession = 0;\n        CatacombsTracker.f7SPlusSession = 0;\n        CatacombsTracker.witherBloodsSession = 0;\n        CatacombsTracker.witherCloaksSession = 0;\n        CatacombsTracker.implosionsSession = 0;\n        CatacombsTracker.witherShieldsSession = 0;\n        CatacombsTracker.shadowWarpsSession = 0;\n        CatacombsTracker.necronsHandlesSession = 0;\n        CatacombsTracker.autoRecombsSession = 0;\n        CatacombsTracker.witherHelmsSession = 0;\n        CatacombsTracker.witherChestsSession = 0;\n        CatacombsTracker.witherLegsSession = 0;\n        CatacombsTracker.witherBootsSession = 0;\n        CatacombsTracker.f7RerollsSession = 0;\n        CatacombsTracker.f7CoinsSpentSession = 0;\n        CatacombsTracker.f7TimeSpentSession = 0;\n        CatacombsTracker.m1SSession = 0;\n        CatacombsTracker.m1SPlusSession = 0;\n        CatacombsTracker.m2SSession = 0;\n        CatacombsTracker.m2SPlusSession = 0;\n        CatacombsTracker.m3SSession = 0;\n        CatacombsTracker.m3SPlusSession = 0;\n        CatacombsTracker.m4SSession = 0;\n        CatacombsTracker.m4SPlusSession = 0;\n        CatacombsTracker.m5SSession = 0;\n        CatacombsTracker.m5SPlusSession = 0;\n        CatacombsTracker.m6SSession = 0;\n        CatacombsTracker.m6SPlusSession = 0;\n        CatacombsTracker.m7SSession = 0;\n        CatacombsTracker.m7SPlusSession = 0;\n        CatacombsTracker.firstStarsSession = 0;\n        CatacombsTracker.secondStarsSession = 0;\n        CatacombsTracker.thirdStarsSession = 0;\n        CatacombsTracker.fourthStarsSession = 0;\n        CatacombsTracker.fifthStarsSession = 0;\n        CatacombsTracker.darkClaymoresSession = 0;\n        CatacombsTracker.masterRerollsSession = 0;\n        CatacombsTracker.masterCoinsSpentSession = 0;\n        CatacombsTracker.masterTimeSpentSession = 0;\n        CfgConfig.deleteCategory(\"catacombs\");\n        ConfigHandler.reloadConfig();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/warp/WarpCommand.java",
    "content": "package me.Danker.commands.warp;\n\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.command.CommandBase;\nimport net.minecraft.command.CommandException;\nimport net.minecraft.command.ICommandSender;\n\npublic class WarpCommand extends CommandBase {\n\n\n    private boolean custom_command;\n    public String name;\n    public String destination;\n\n    public WarpCommand(String name) {\n        this(name, name, false);\n    }\n\n    /**\n     * A Command blueprint extending CommandBase that uses the name and sends the destination as \"/warp {@link #destination}\"\n     * @param name the name that the command is called as\n     * @param destination the location name that is sent\n     */\n    public WarpCommand(String name, String destination) {\n        this(name, destination, false);\n    }\n\n    /**\n     * A Command blueprint extending CommandBase that uses the name and sends the destination as \"/warp {@link #destination}\"\n     * @param name the name that the command is called as\n     * @param destination the location name that is sent\n     * @param custom_command is the custom command should use the /warp format or send a custom command.\n     *                       Adds the \"/\" to the destination.\n     */\n    public WarpCommand(String name, String destination, boolean custom_command) {\n        this.name = name;\n        this.destination = destination;\n        this.custom_command = custom_command;\n    }\n\n    /**\n     * Returns the commands name that is set in the constructor\n     */\n    @Override\n    public String getCommandName() {\n        return name;\n    }\n\n    /**\n     * Returns the command usage for the builtin help\n     * @param sender the command sender\n     * @return \"/\" + the command name\n     */\n    @Override\n    public String getCommandUsage(ICommandSender sender) {\n        return \"/\" + getCommandName();\n    }\n\n    @Override\n    public int getRequiredPermissionLevel() {\n        return 0;\n    }\n\n    /**\n     * The logic that is called when the command is executed\n     * Sends a message as the player containing \"/warp {@link #destination}\"\n     * @param sender the command sender\n     * @param args what is written after the command\n     */\n    @Override\n    public void processCommand(ICommandSender sender, String[] args) throws CommandException {\n        if (!Utils.inSkyblock) return;\n        if (custom_command) {\n            Minecraft.getMinecraft().thePlayer.sendChatMessage(\"/\" + this.destination);\n            return;\n        }\n        Minecraft.getMinecraft().thePlayer.sendChatMessage(\"/warp \" + this.destination);\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/commands/warp/WarpCommandHandler.java",
    "content": "package me.Danker.commands.warp;\n\nimport net.minecraftforge.client.ClientCommandHandler;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class WarpCommandHandler {\n\n    private List<WarpCommand> commands;\n\n    /**\n     * Constructor of the WarpCommandHandler, it will register all commands when it is created\n     */\n    public WarpCommandHandler() {\n        this.commands = new ArrayList<WarpCommand>();\n        registerCommands();\n    }\n\n\n    /**\n     * @return List of all registered commands\n     */\n    public List<WarpCommand> getCommands() {\n        return this.commands;\n    }\n\n    /**\n     * Registers a command to the handler\n     * @param warpCommand WarpCommand to register\n     */\n    public void registerCommand(WarpCommand warpCommand) {\n        this.commands.add(warpCommand);\n        ClientCommandHandler.instance.registerCommand(warpCommand);\n    }\n\n    /**\n     * Get a command by its name\n     * @param name Name of the command\n     * @return WarpCommand with the given name\n     */\n    public WarpCommand getCommand(String name) {\n        for (WarpCommand command : this.commands) {\n            if (command.getCommandName().equalsIgnoreCase(name)) {\n                return command;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Get a command by the class it extends from\n     * @param clazz Class to get the command from\n     * @return WarpCommand with the given class\n     */\n    public WarpCommand getCommand(Class<? extends WarpCommand> clazz) {\n        for (WarpCommand command : this.commands) {\n            if (command.getClass() == clazz) {\n                return command;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Register all commands\n     */\n    private void registerCommands() {\n        registerCommand(new WarpCommand(\"deep\"));\n        registerCommand(new WarpCommand(\"nether\"));\n        registerCommand(new WarpCommand(\"isle\"));\n        registerCommand(new WarpCommand(\"crimson\"));\n        registerCommand(new WarpCommand(\"wk\", \"kuudra\"));\n        registerCommand(new WarpCommand(\"mines\"));\n        registerCommand(new WarpCommand(\"forge\"));\n        registerCommand(new WarpCommand(\"crystals\"));\n        registerCommand(new WarpCommand(\"gold\"));\n        registerCommand(new WarpCommand(\"desert\"));\n        registerCommand(new WarpCommand(\"spider\"));\n        registerCommand(new WarpCommand(\"barn\"));\n        registerCommand(new WarpCommand(\"end\"));\n        registerCommand(new WarpCommand(\"park\"));\n        registerCommand(new WarpCommand(\"castle\"));\n        registerCommand(new WarpCommand(\"museum\"));\n        registerCommand(new WarpCommand(\"da\"));\n        registerCommand(new WarpCommand(\"crypt\"));\n        registerCommand(new WarpCommand(\"nest\"));\n        registerCommand(new WarpCommand(\"void\"));\n        registerCommand(new WarpCommand(\"drag\"));\n        registerCommand(new WarpCommand(\"jungle\"));\n        registerCommand(new WarpCommand(\"howl\"));\n        registerCommand(new WarpCommand(\"dun\", \"dungeon_hub\"));\n        registerCommand(new WarpCommand(\"garden\"));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/config/CfgConfig.java",
    "content": "package me.Danker.config;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.features.CakeTimer;\nimport me.Danker.features.loot.*;\nimport net.minecraftforge.common.config.ConfigCategory;\nimport net.minecraftforge.common.config.Configuration;\n\nimport java.io.File;\n\npublic class CfgConfig {\n    public static Configuration config;\n    private final static String file = \"config/Danker's Skyblock Mod.cfg\";\n    \n    public static void init() {\n        config = new Configuration(new File(file));\n        try {\n            config.load();\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        } finally {\n            config.save();\n        }\n    }\n    \n    public static int getInt(String category, String key) {\n        try {\n            if (config.getCategory(category).containsKey(key)) {\n                return config.get(category, key, 0).getInt();\n            }\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        } finally {\n            config.save();\n        }\n        return 0;\n    }\n    \n    public static double getDouble(String category, String key) {\n        try {\n            if (config.getCategory(category).containsKey(key)) {\n                return config.get(category, key, 0D).getDouble();\n            }\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        } finally {\n            config.save();\n        }\n        return 0D;\n    }\n    \n    public static String getString(String category, String key) {\n        try {\n            if (config.getCategory(category).containsKey(key)) {\n                return config.get(category, key, \"\").getString();\n            }\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        } finally {\n            config.save();\n        }\n        return \"\";\n    }\n    \n    public static boolean getBoolean(String category, String key) {\n        try {\n            if (config.getCategory(category).containsKey(key)) {\n                return config.get(category, key, false).getBoolean();\n            }\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        } finally {\n            config.save();\n        }\n        return true;\n    }\n\n    public static void writeIntConfig(String category, String key, int value) {\n        try {\n            int set = config.get(category, key, value).getInt();\n            config.getCategory(category).get(key).set(value);\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        } finally {\n            config.save();\n        }\n    }\n    \n    public static void writeDoubleConfig(String category, String key, double value) {\n        try {\n            double set = config.get(category, key, value).getDouble();\n            config.getCategory(category).get(key).set(value);\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        } finally {\n            config.save();\n        }\n    }\n    \n    public static void writeStringConfig(String category, String key, String value) {\n        try {\n            String set = config.get(category, key, value).getString();\n            config.getCategory(category).get(key).set(value);\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        } finally {\n            config.save();\n        }\n    }\n    \n    public static void writeBooleanConfig(String category, String key, boolean value) {\n        try {\n            boolean set = config.get(category, key, value).getBoolean();\n            config.getCategory(category).get(key).set(value);\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        } finally {\n            config.save();\n        }\n    }\n    \n    public static boolean hasKey(String category, String key) {\n        try {\n            if (!config.hasCategory(category)) return false;\n            return config.getCategory(category).containsKey(key);\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        } finally {\n            config.save();\n        }\n        return false;\n    }\n    \n    public static void deleteCategory(String category) {\n        try {\n            if (config.hasCategory(category)) {\n                config.removeCategory(new ConfigCategory(category));\n            }\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        } finally {\n            config.save();\n        }\n    }\n\n    public static int initInt(String category, String key, int defaultValue) {\n        if (!hasKey(category, key)) {\n            writeIntConfig(category, key, defaultValue);\n            return defaultValue;\n        } else {\n            return getInt(category, key);\n        }\n    }\n\n    public static double initDouble(String category, String key, double defaultValue) {\n        if (!hasKey(category, key)) {\n            writeDoubleConfig(category, key, defaultValue);\n            return defaultValue;\n        } else {\n            return getDouble(category, key);\n        }\n    }\n\n    public static String initString(String category, String key, String defaultValue) {\n        if (!hasKey(category, key)) {\n            writeStringConfig(category, key, defaultValue);\n            return defaultValue;\n        } else {\n            return getString(category, key);\n        }\n    }\n\n    public static boolean initBoolean(String category, String key, boolean defaultValue) {\n        if (!hasKey(category, key)) {\n            writeBooleanConfig(category, key, defaultValue);\n            return defaultValue;\n        } else {\n            return getBoolean(category, key);\n        }\n    }\n    \n    public static void reloadConfig() {\n        init();\n        \n        // Wolf\n        WolfTracker.svens = initInt(\"wolf\", \"svens\", 0);\n        WolfTracker.teeth = initInt(\"wolf\", \"teeth\", 0);\n        WolfTracker.wheels = initInt(\"wolf\", \"wheel\", 0);\n        WolfTracker.wheelsDrops = initInt(\"wolf\", \"wheelDrops\", 0);\n        WolfTracker.spirits = initInt(\"wolf\", \"spirit\", 0);\n        WolfTracker.books = initInt(\"wolf\", \"book\", 0);\n        WolfTracker.furballs = initInt(\"wolf\", \"furball\", 0);\n        WolfTracker.eggs = initInt(\"wolf\", \"egg\", 0);\n        WolfTracker.coutures = initInt(\"wolf\", \"couture\", 0);\n        WolfTracker.baits = initInt(\"wolf\", \"bait\", 0);\n        WolfTracker.fluxes = initInt(\"wolf\", \"flux\", 0);\n        WolfTracker.time = initDouble(\"wolf\", \"timeRNG\", -1);\n        WolfTracker.bosses = initInt(\"wolf\", \"bossRNG\", -1);\n        // Spider\n        SpiderTracker.tarantulas = initInt(\"spider\", \"tarantulas\", 0);\n        SpiderTracker.webs = initInt(\"spider\", \"web\", 0);\n        SpiderTracker.TAP = initInt(\"spider\", \"tap\", 0);\n        SpiderTracker.TAPDrops = initInt(\"spider\", \"tapDrops\", 0);\n        SpiderTracker.bites = initInt(\"spider\", \"bite\", 0);\n        SpiderTracker.catalysts = initInt(\"spider\", \"catalyst\", 0);\n        SpiderTracker.books = initInt(\"spider\", \"book\", 0);\n        SpiderTracker.swatters = initInt(\"spider\", \"swatter\", 0);\n        SpiderTracker.talismans = initInt(\"spider\", \"talisman\", 0);\n        SpiderTracker.mosquitos = initInt(\"spider\", \"mosquito\", 0);\n        SpiderTracker.time = initDouble(\"spider\", \"timeRNG\", -1);\n        SpiderTracker.bosses = initInt(\"spider\", \"bossRNG\", -1);\n        // Zombie\n        ZombieTracker.revs = initInt(\"zombie\", \"revs\", 0);\n        ZombieTracker.revFlesh = initInt(\"zombie\", \"revFlesh\", 0);\n        ZombieTracker.revViscera = initInt(\"zombie\", \"revViscera\", 0);\n        ZombieTracker.foulFlesh = initInt(\"zombie\", \"foulFlesh\", 0);\n        ZombieTracker.foulFleshDrops = initInt(\"zombie\", \"foulFleshDrops\", 0);\n        ZombieTracker.pestilences = initInt(\"zombie\", \"pestilence\", 0);\n        ZombieTracker.undeadCatas = initInt(\"zombie\", \"undeadCatalyst\", 0);\n        ZombieTracker.books = initInt(\"zombie\", \"book\", 0);\n        ZombieTracker.beheadeds = initInt(\"zombie\", \"beheaded\", 0);\n        ZombieTracker.revCatas = initInt(\"zombie\", \"revCatalyst\", 0);\n        ZombieTracker.snakes = initInt(\"zombie\", \"snake\", 0);\n        ZombieTracker.scythes = initInt(\"zombie\", \"scythe\", 0);\n        ZombieTracker.shards = initInt(\"zombie\", \"shard\", 0);\n        ZombieTracker.wardenHearts = initInt(\"zombie\", \"heart\", 0);\n        ZombieTracker.time = initDouble(\"zombie\", \"timeRNG\", -1);\n        ZombieTracker.bosses = initInt(\"zombie\", \"bossRNG\", -1);\n        // Enderman\n        EndermanTracker.voidglooms = initInt(\"enderman\", \"voidglooms\", 0);\n        EndermanTracker.nullSpheres = initInt(\"enderman\", \"nullSpheres\", 0);\n        EndermanTracker.TAP = initInt(\"enderman\", \"tap\", 0);\n        EndermanTracker.TAPDrops = initInt(\"enderman\", \"tapDrops\", 0);\n        EndermanTracker.endersnakes = initInt(\"enderman\", \"endersnakes\", 0);\n        EndermanTracker.summoningEyes = initInt(\"enderman\", \"summoningEyes\", 0);\n        EndermanTracker.manaBooks = initInt(\"enderman\", \"manaBooks\", 0);\n        EndermanTracker.tuners = initInt(\"enderman\", \"tuners\", 0);\n        EndermanTracker.atoms = initInt(\"enderman\", \"atoms\", 0);\n        EndermanTracker.hazmats = initInt(\"enderman\", \"hazmats\", 0);\n        EndermanTracker.espressoMachines = initInt(\"enderman\", \"espressoMachines\", 0);\n        EndermanTracker.smartyBooks = initInt(\"enderman\", \"smartyBooks\", 0);\n        EndermanTracker.endRunes = initInt(\"enderman\", \"endRunes\", 0);\n        EndermanTracker.chalices = initInt(\"enderman\", \"chalices\", 0);\n        EndermanTracker.dice = initInt(\"enderman\", \"dice\", 0);\n        EndermanTracker.artifacts = initInt(\"enderman\", \"artifacts\", 0);\n        EndermanTracker.skins = initInt(\"enderman\", \"skins\", 0);\n        EndermanTracker.mergers = initInt(\"enderman\", \"mergers\", 0);\n        EndermanTracker.cores = initInt(\"enderman\", \"cores\", 0);\n        EndermanTracker.enchantRunes = initInt(\"enderman\", \"enchantRunes\", 0);\n        EndermanTracker.enderBooks = initInt(\"enderman\", \"enderBooks\", 0);\n        EndermanTracker.time = initDouble(\"enderman\", \"timeRNG\", -1);\n        EndermanTracker.bosses = initInt(\"enderman\", \"bossRNG\", -1);\n        // Blaze\n        BlazeTracker.demonlords = initInt(\"blaze\", \"demonlords\", 0);\n        BlazeTracker.derelictAshes = initInt(\"blaze\", \"derelictAshes\", 0);\n        BlazeTracker.blazePowder = initInt(\"blaze\", \"blazePowder\", 0);\n        BlazeTracker.lavatearRunes = initInt(\"blaze\", \"lavatearRunes\", 0);\n        BlazeTracker.splashPotions = initInt(\"blaze\", \"splashPotions\", 0);\n        BlazeTracker.magmaArrows = initInt(\"blaze\", \"magmaArrows\", 0);\n        BlazeTracker.manaDisintegrators = initInt(\"blaze\", \"manaDisintegrators\", 0);\n        BlazeTracker.scorchedBooks = initInt(\"blaze\", \"scorchedBooks\", 0);\n        BlazeTracker.kelvinInverters = initInt(\"blaze\", \"kelvinInverters\", 0);\n        BlazeTracker.blazeRodDistillates = initInt(\"blaze\", \"blazeRodDistillates\", 0);\n        BlazeTracker.glowstoneDistillates = initInt(\"blaze\", \"glowstoneDistillates\", 0);\n        BlazeTracker.magmaCreamDistillates = initInt(\"blaze\", \"magmaCreamDistillates\", 0);\n        BlazeTracker.netherWartDistillates = initInt(\"blaze\", \"netherWartDistillates\", 0);\n        BlazeTracker.gabagoolDistillates = initInt(\"blaze\", \"gabagoolDistillates\", 0);\n        BlazeTracker.scorchedPowerCrystals = initInt(\"blaze\", \"scorchedPowerCrystals\", 0);\n        BlazeTracker.fireAspectBooks = initInt(\"blaze\", \"fireAspectBooks\", 0);\n        BlazeTracker.fieryBurstRunes = initInt(\"blaze\", \"fieryBurstRunes\", 0);\n        BlazeTracker.opalGems = initInt(\"blaze\", \"opalGems\", 0);\n        BlazeTracker.archfiendDice = initInt(\"blaze\", \"archfiendDice\", 0);\n        BlazeTracker.duplexBooks = initInt(\"blaze\", \"duplexBooks\", 0);\n        BlazeTracker.highClassArchfiendDice = initInt(\"blaze\", \"highClassArchfiendDice\", 0);\n        BlazeTracker.engineeringPlans = initInt(\"blaze\", \"engineeringPlans\", 0);\n        BlazeTracker.subzeroInverters = initInt(\"blaze\", \"subzeroInverters\", 0);\n        BlazeTracker.time = initDouble(\"blaze\", \"timeRNG\", -1);\n        BlazeTracker.bosses = initInt(\"blaze\", \"bossRNG\", -1);\n        // Vampire\n        VampireTracker.riftstalkers = initInt(\"vampire\", \"riftstalkers\", 0);\n        VampireTracker.covenSeals = initInt(\"vampire\", \"covenSeals\", 0);\n        VampireTracker.quantumBundles = initInt(\"vampire\", \"quantumBundles\", 0);\n        VampireTracker.bubbaBlisters = initInt(\"vampire\", \"bubbaBlisters\", 0);\n        VampireTracker.soultwistRunes = initInt(\"vampire\", \"soultwistRunes\", 0);\n        VampireTracker.chocolateChips = initInt(\"vampire\", \"chocolateChips\", 0);\n        VampireTracker.luckyBlocks = initInt(\"vampire\", \"luckyBlocks\", 0);\n        VampireTracker.theOneBundles = initInt(\"vampire\", \"theOneBundles\", 0);\n        VampireTracker.mcgrubbersBurgers = initInt(\"vampire\", \"mcgrubbersBurgers\", 0);\n        VampireTracker.vampireParts = initInt(\"vampire\", \"vampireParts\", 0);\n\n        // Fishing\n        FishingTracker.seaCreatures = initInt(\"fishing\", \"seaCreature\", 0);\n        FishingTracker.goodCatches = initInt(\"fishing\", \"goodCatch\", 0);\n        FishingTracker.greatCatches = initInt(\"fishing\", \"greatCatch\", 0);\n        FishingTracker.squids = initInt(\"fishing\", \"squid\", 0);\n        FishingTracker.seaWalkers = initInt(\"fishing\", \"seaWalker\", 0);\n        FishingTracker.nightSquids = initInt(\"fishing\", \"nightSquid\", 0);\n        FishingTracker.seaGuardians = initInt(\"fishing\", \"seaGuardian\", 0);\n        FishingTracker.seaWitches = initInt(\"fishing\", \"seaWitch\", 0);\n        FishingTracker.seaArchers = initInt(\"fishing\", \"seaArcher\", 0);\n        FishingTracker.monsterOfTheDeeps = initInt(\"fishing\", \"monsterOfDeep\", 0);\n        FishingTracker.agarimoos = initInt(\"fishing\", \"agarimoo\", 0);\n        FishingTracker.catfishes = initInt(\"fishing\", \"catfish\", 0);\n        FishingTracker.carrotKings = initInt(\"fishing\", \"carrotKing\", 0);\n        FishingTracker.seaLeeches = initInt(\"fishing\", \"seaLeech\", 0);\n        FishingTracker.guardianDefenders = initInt(\"fishing\", \"guardianDefender\", 0);\n        FishingTracker.deepSeaProtectors = initInt(\"fishing\", \"deepSeaProtector\", 0);\n        FishingTracker.hydras = initInt(\"fishing\", \"hydra\", 0);\n        FishingTracker.seaEmperors = initInt(\"fishing\", \"seaEmperor\", 0);\n        FishingTracker.empTime = initDouble(\"fishing\", \"empTime\", -1);\n        FishingTracker.empSCs = initInt(\"fishing\", \"empSC\", -1);\n        FishingTracker.fishingMilestone = initInt(\"fishing\", \"milestone\", 0);\n        // Fishing Winter\n        FishingTracker.frozenSteves = initInt(\"fishing\", \"frozenSteve\", 0);\n        FishingTracker.frostyTheSnowmans = initInt(\"fishing\", \"snowman\", 0);\n        FishingTracker.grinches = initInt(\"fishing\", \"grinch\", 0);\n        FishingTracker.nutcrackers = initInt(\"fishing\", \"nutcracker\", 0);\n        FishingTracker.reindrakes = initInt(\"fishing\", \"reindrake\", 0);\n        FishingTracker.yetis = initInt(\"fishing\", \"yeti\", 0);\n        FishingTracker.reindrakeTime = initDouble(\"fishing\", \"reindrakeTime\", -1);\n        FishingTracker.reindrakeSCs = initInt(\"fishing\", \"reindrakeSC\", -1);\n        // Fishing Festival\n        FishingTracker.nurseSharks = initInt(\"fishing\", \"nurseShark\", 0);\n        FishingTracker.blueSharks = initInt(\"fishing\", \"blueShark\", 0);\n        FishingTracker.tigerSharks = initInt(\"fishing\", \"tigerShark\", 0);\n        FishingTracker.greatWhiteSharks = initInt(\"fishing\", \"greatWhiteShark\", 0);\n        // Spooky Fishing\n        FishingTracker.scarecrows = initInt(\"fishing\", \"scarecrow\", 0);\n        FishingTracker.nightmares = initInt(\"fishing\", \"nightmare\", 0);\n        FishingTracker.werewolfs = initInt(\"fishing\", \"werewolf\", 0);\n        FishingTracker.phantomFishers = initInt(\"fishing\", \"phantomFisher\", 0);\n        FishingTracker.grimReapers = initInt(\"fishing\", \"grimReaper\", 0);\n        // CH Fishing\n        FishingTracker.waterWorms = initInt(\"fishing\", \"waterWorm\", 0);\n        FishingTracker.poisonedWaterWorms = initInt(\"fishing\", \"poisonedWaterWorm\", 0);\n        FishingTracker.flamingWorms = initInt(\"fishing\", \"flamingWorm\", 0);\n        FishingTracker.lavaBlazes = initInt(\"fishing\", \"lavaBlaze\", 0);\n        FishingTracker.lavaPigmen = initInt(\"fishing\", \"lavaPigman\", 0);\n        FishingTracker.zombieMiners = initInt(\"fishing\", \"zombieMiner\", 0);\n        // Lava Fishing\n        FishingTracker.plhlegblasts = initInt(\"fishing\", \"plhlegblast\", 0);\n        FishingTracker.magmaSlugs = initInt(\"fishing\", \"magmaSlug\", 0);\n        FishingTracker.moogmas = initInt(\"fishing\", \"moogma\", 0);\n        FishingTracker.lavaLeeches = initInt(\"fishing\", \"lavaLeech\", 0);\n        FishingTracker.pyroclasticWorms = initInt(\"fishing\", \"pyroclasticWorm\", 0);\n        FishingTracker.lavaFlames = initInt(\"fishing\", \"lavaFlame\", 0);\n        FishingTracker.fireEels = initInt(\"fishing\", \"fireEel\", 0);\n        FishingTracker.tauruses = initInt(\"fishing\", \"taurus\", 0);\n        FishingTracker.thunders = initInt(\"fishing\", \"thunder\", 0);\n        FishingTracker.lordJawbuses = initInt(\"fishing\", \"lordJawbus\", 0);\n        FishingTracker.jawbusTime = initDouble(\"fishing\", \"jawbusTime\", -1);\n        FishingTracker.jawbusSCs = initInt(\"fishing\", \"jawbusSC\", -1);\n        \n        // Mythological\n        MythologicalTracker.mythCoins = initDouble(\"mythological\", \"coins\", 0);\n        MythologicalTracker.griffinFeathers = initInt(\"mythological\", \"griffinFeather\", 0);\n        MythologicalTracker.crownOfGreeds = initInt(\"mythological\", \"crownOfGreed\", 0);\n        MythologicalTracker.washedUpSouvenirs = initInt(\"mythological\", \"washedUpSouvenir\", 0);\n        MythologicalTracker.minosHunters = initInt(\"mythological\", \"minosHunter\", 0);\n        MythologicalTracker.siameseLynxes = initInt(\"mythological\", \"siameseLynx\", 0);\n        MythologicalTracker.minotaurs = initInt(\"mythological\", \"minotaur\", 0);\n        MythologicalTracker.gaiaConstructs = initInt(\"mythological\", \"gaiaConstruct\", 0);\n        MythologicalTracker.minosChampions = initInt(\"mythological\", \"minosChampion\", 0);\n        MythologicalTracker.minosInquisitors = initInt(\"mythological\", \"minosInquisitor\", 0);\n        \n        // Dungeons\n        CatacombsTracker.recombobulators =  initInt(\"catacombs\", \"recombobulator\", 0);\n        CatacombsTracker.fumingPotatoBooks = initInt(\"catacombs\", \"fumingBooks\", 0);\n        // F1\n        CatacombsTracker.f1SPlus = initInt(\"catacombs\", \"floorOneSPlus\", 0);\n        CatacombsTracker.bonzoStaffs = initInt(\"catacombs\", \"bonzoStaff\", 0);\n        CatacombsTracker.balloonSnakes = initInt(\"catacombs\", \"balloonSnake\", 0);\n        CatacombsTracker.f1CoinsSpent = initDouble(\"catacombs\", \"floorOneCoins\", 0);\n        CatacombsTracker.f1TimeSpent = initDouble(\"catacombs\", \"floorOneTime\", 0);\n        // F2\n        CatacombsTracker.f2SPlus = initInt(\"catacombs\", \"floorTwoSPlus\", 0);\n        CatacombsTracker.scarfStudies = initInt(\"catacombs\", \"scarfStudies\", 0);\n        CatacombsTracker.adaptiveSwords = initInt(\"catacombs\", \"adaptiveSword\", 0);\n        CatacombsTracker.adaptiveBelts = initInt(\"catacombs\", \"adaptiveBelt\", 0);\n        CatacombsTracker.f2CoinsSpent = initDouble(\"catacombs\", \"floorTwoCoins\", 0);\n        CatacombsTracker.f2TimeSpent = initDouble(\"catacombs\", \"floorTwoTime\", 0);\n        // F3\n        CatacombsTracker.f3SPlus = initInt(\"catacombs\", \"floorThreeSPlus\", 0);\n        CatacombsTracker.adaptiveHelms = initInt(\"catacombs\", \"adaptiveHelm\", 0);\n        CatacombsTracker.adaptiveChests = initInt(\"catacombs\", \"adaptiveChest\", 0);\n        CatacombsTracker.adaptiveLegs = initInt(\"catacombs\", \"adaptiveLegging\", 0);\n        CatacombsTracker.adaptiveBoots = initInt(\"catacombs\", \"adaptiveBoot\", 0);\n        CatacombsTracker.f3CoinsSpent = initDouble(\"catacombs\", \"floorThreeCoins\", 0);\n        CatacombsTracker.f3TimeSpent = initDouble(\"catacombs\", \"floorThreeTime\", 0);\n        // F4\n        CatacombsTracker.f4SPlus = initInt(\"catacombs\", \"floorFourSPlus\", 0);\n        CatacombsTracker.spiritWings = initInt(\"catacombs\", \"spiritWing\", 0);\n        CatacombsTracker.spiritBones = initInt(\"catacombs\", \"spiritBone\", 0);\n        CatacombsTracker.spiritBoots = initInt(\"catacombs\", \"spiritBoot\", 0);\n        CatacombsTracker.spiritSwords = initInt(\"catacombs\", \"spiritSword\", 0);\n        CatacombsTracker.spiritBows = initInt(\"catacombs\", \"spiritBow\", 0);\n        CatacombsTracker.epicSpiritPets = initInt(\"catacombs\", \"spiritPetEpic\", 0);\n        CatacombsTracker.legSpiritPets = initInt(\"catacombs\", \"spiritPetLeg\", 0);\n        CatacombsTracker.f4CoinsSpent = initDouble(\"catacombs\", \"floorFourCoins\", 0);\n        CatacombsTracker.f4TimeSpent = initDouble(\"catacombs\", \"floorFourTime\", 0);\n        // F5\n        CatacombsTracker.f5SPlus = initInt(\"catacombs\", \"floorFiveSPlus\", 0);\n        CatacombsTracker.warpedStones = initInt(\"catacombs\", \"warpedStone\", 0);\n        CatacombsTracker.shadowAssHelms = initInt(\"catacombs\", \"shadowAssassinHelm\", 0);\n        CatacombsTracker.shadowAssChests = initInt(\"catacombs\", \"shadowAssassinChest\", 0);\n        CatacombsTracker.shadowAssLegs = initInt(\"catacombs\", \"shadowAssassinLegging\", 0);\n        CatacombsTracker.shadowAssBoots = initInt(\"catacombs\", \"shadowAssassinBoot\", 0);\n        CatacombsTracker.shadowAssCloaks = initInt(\"catacombs\", \"shadowAssassinCloak\", 0);\n        CatacombsTracker.lastBreaths = initInt(\"catacombs\", \"lastBreath\", 0);\n        CatacombsTracker.lividDaggers = initInt(\"catacombs\", \"lividDagger\", 0);\n        CatacombsTracker.shadowFurys = initInt(\"catacombs\", \"shadowFury\", 0);\n        CatacombsTracker.f5CoinsSpent = initDouble(\"catacombs\", \"floorFiveCoins\", 0);\n        CatacombsTracker.f5TimeSpent = initDouble(\"catacombs\", \"floorFiveTime\", 0);\n        // F6\n        CatacombsTracker.f6SPlus = initInt(\"catacombs\", \"floorSixSPlus\", 0);\n        CatacombsTracker.ancientRoses = initInt(\"catacombs\", \"ancientRose\", 0);\n        CatacombsTracker.precursorEyes = initInt(\"catacombs\", \"precursorEye\", 0);\n        CatacombsTracker.giantsSwords = initInt(\"catacombs\", \"giantsSword\", 0);\n        CatacombsTracker.necroLordHelms = initInt(\"catacombs\", \"necroLordHelm\", 0);\n        CatacombsTracker.necroLordChests = initInt(\"catacombs\", \"necroLordChest\", 0);\n        CatacombsTracker.necroLordLegs = initInt(\"catacombs\", \"necroLordLegging\", 0);\n        CatacombsTracker.necroLordBoots = initInt(\"catacombs\", \"necroLordBoot\", 0);\n        CatacombsTracker.necroSwords = initInt(\"catacombs\", \"necroSword\", 0);\n        CatacombsTracker.soulweaverGloves = initInt(\"catacombs\", \"soulweaverGlove\", 0);\n        CatacombsTracker.felSkulls = initInt(\"catacombs\", \"felSkull\", 0);\n        CatacombsTracker.f6Rerolls = initInt(\"catacombs\", \"floorSixRerolls\", 0);\n        CatacombsTracker.f6CoinsSpent = initDouble(\"catacombs\", \"floorSixCoins\", 0);\n        CatacombsTracker.f6TimeSpent = initDouble(\"catacombs\", \"floorSixTime\", 0);\n        // F7\n        CatacombsTracker.f7SPlus = initInt(\"catacombs\", \"floorSevenSPlus\", 0);\n        CatacombsTracker.witherBloods = initInt(\"catacombs\", \"witherBlood\", 0);\n        CatacombsTracker.witherCloaks = initInt(\"catacombs\", \"witherCloak\", 0);\n        CatacombsTracker.implosions = initInt(\"catacombs\", \"implosion\", 0);\n        CatacombsTracker.witherShields = initInt(\"catacombs\", \"witherShield\", 0);\n        CatacombsTracker.shadowWarps = initInt(\"catacombs\", \"shadowWarp\", 0);\n        CatacombsTracker.necronsHandles = initInt(\"catacombs\", \"necronsHandle\", 0);\n        CatacombsTracker.autoRecombs = initInt(\"catacombs\", \"autoRecomb\", 0);\n        CatacombsTracker.witherHelms = initInt(\"catacombs\", \"witherHelm\", 0);\n        CatacombsTracker.witherChests = initInt(\"catacombs\", \"witherChest\", 0);\n        CatacombsTracker.witherLegs = initInt(\"catacombs\", \"witherLegging\", 0);\n        CatacombsTracker.witherBoots = initInt(\"catacombs\", \"witherBoot\", 0);\n        CatacombsTracker.f7Rerolls = initInt(\"catacombs\", \"floorSevenRerolls\", 0);\n        CatacombsTracker.f7CoinsSpent = initDouble(\"catacombs\", \"floorSevenCoins\", 0);\n        CatacombsTracker.f7TimeSpent = initDouble(\"catacombs\", \"floorSevenTime\", 0);\n        // MM\n        CatacombsTracker.m1S = initInt(\"catacombs\", \"masterOneS\", 0);\n        CatacombsTracker.m1SPlus = initInt(\"catacombs\", \"masterOneSPlus\", 0);\n        CatacombsTracker.m2S = initInt(\"catacombs\", \"masterTwoS\", 0);\n        CatacombsTracker.m2SPlus = initInt(\"catacombs\", \"masterTwoSPlus\", 0);\n        CatacombsTracker.m3S = initInt(\"catacombs\", \"masterThreeS\", 0);\n        CatacombsTracker.m3SPlus = initInt(\"catacombs\", \"masterThreeSPlus\", 0);\n        CatacombsTracker.m4S = initInt(\"catacombs\", \"masterFourS\", 0);\n        CatacombsTracker.m4SPlus = initInt(\"catacombs\", \"masterFourSPlus\", 0);\n        CatacombsTracker.m5S = initInt(\"catacombs\", \"masterFiveS\", 0);\n        CatacombsTracker.m5SPlus = initInt(\"catacombs\", \"masterFiveSPlus\", 0);\n        CatacombsTracker.m6S = initInt(\"catacombs\", \"masterSixS\", 0);\n        CatacombsTracker.m6SPlus = initInt(\"catacombs\", \"masterSixSPlus\", 0);\n        CatacombsTracker.m7S = initInt(\"catacombs\", \"masterSevenS\", 0);\n        CatacombsTracker.m7SPlus = initInt(\"catacombs\", \"masterSevenSPlus\", 0);\n        CatacombsTracker.firstStars = initInt(\"catacombs\", \"firstStar\", 0);\n        CatacombsTracker.secondStars = initInt(\"catacombs\", \"secondStar\", 0);\n        CatacombsTracker.thirdStars = initInt(\"catacombs\", \"thirdStar\", 0);\n        CatacombsTracker.fourthStars = initInt(\"catacombs\", \"fourthStar\", 0);\n        CatacombsTracker.fifthStars = initInt(\"catacombs\", \"fifthStar\", 0);\n        CatacombsTracker.necronDyes = initInt(\"catacombs\", \"necronDye\", 0);\n        CatacombsTracker.darkClaymores = initInt(\"catacombs\", \"darkClaymore\", 0);\n        CatacombsTracker.masterRerolls = initInt(\"catacombs\", \"masterRerolls\", 0);\n        CatacombsTracker.masterCoinsSpent = initDouble(\"catacombs\", \"masterCoins\", 0);\n        CatacombsTracker.masterTimeSpent = initDouble(\"catacombs\", \"masterTime\", 0);\n\n        // Ghost\n        GhostTracker.sorrows = initInt(\"ghosts\", \"sorrow\", 0);\n        GhostTracker.voltas = initInt(\"ghosts\", \"volta\", 0);\n        GhostTracker.plasmas = initInt(\"ghosts\", \"plasma\", 0);\n        GhostTracker.ghostlyBoots = initInt(\"ghosts\", \"ghostlyBoots\", 0);\n        GhostTracker.bagOfCashs = initInt(\"ghosts\", \"bagOfCash\", 0);\n\n        // Misc\n        CakeTimer.cakeTime = initDouble(\"misc\", \"cakeTime\", 0);\n        DankersSkyblockMod.firstLaunch = initBoolean(\"misc\", \"firstLaunch\", true);\n\n        // Skills\n        DankersSkyblockMod.farmingLevel = initInt(\"skills\", \"farming\", -1);\n        DankersSkyblockMod.miningLevel = initInt(\"skills\", \"mining\", -1);\n        DankersSkyblockMod.combatLevel = initInt(\"skills\", \"combat\", -1);\n        DankersSkyblockMod.foragingLevel = initInt(\"skills\", \"foraging\", -1);\n        DankersSkyblockMod.fishingLevel = initInt(\"skills\", \"fishing\", -1);\n        DankersSkyblockMod.enchantingLevel = initInt(\"skills\", \"enchanting\", -1);\n        DankersSkyblockMod.alchemyLevel = initInt(\"skills\", \"alchemy\", -1);\n        DankersSkyblockMod.carpentryLevel = initInt(\"skills\", \"carpentry\", -1);\n\n        // Commands\n        if (!hasKey(\"commands\", \"reparty\")) writeBooleanConfig(\"commands\", \"reparty\", false);\n    }\n    \n}\n"
  },
  {
    "path": "src/main/java/me/Danker/config/JsonConfig.java",
    "content": "package me.Danker.config;\n\nimport com.google.gson.*;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.features.*;\nimport me.Danker.features.loot.TrophyFishTracker;\nimport org.apache.commons.io.FileUtils;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\npublic class JsonConfig {\n\n    public static void createNewJsonObject(String file) throws IOException {\n        FileWriter fileWriter = new FileWriter(file);\n        fileWriter.write(new JsonObject().toString());\n        fileWriter.close();\n    }\n\n    public static void createNewJsonArray(String file) throws IOException {\n        FileWriter fileWriter = new FileWriter(file);\n        fileWriter.write(new JsonArray().toString());\n        fileWriter.close();\n    }\n\n    public static JsonObject initJsonObject(String file) throws IOException {\n        if (!(new File(file).exists())) createNewJsonObject(file);\n        try {\n            return new JsonParser().parse(new FileReader(file)).getAsJsonObject();\n        } catch (IllegalStateException | JsonSyntaxException corrupted) {\n            corrupted.printStackTrace();\n            System.out.println(\"Recreating \" + file);\n            createNewJsonObject(file);\n            return new JsonParser().parse(new FileReader(file)).getAsJsonObject();\n        }\n    }\n\n    public static <T> Object[] initJsonArray(String file, Class<T> clazz) throws IOException {\n        if (!(new File(file).exists())) createNewJsonArray(file);\n        Object[] arr = null;\n        try {\n            arr = new Gson().fromJson(new FileReader(file), (Type) clazz);\n        } catch (JsonSyntaxException corrupted) {\n            corrupted.printStackTrace();\n            System.out.println(\"Recreating \" + file);\n            createNewJsonArray(file);\n        }\n        return arr;\n    }\n\n    public static void reloadConfig() {\n        try {\n            File directory = new File(DankersSkyblockMod.configDirectory + \"/dsm\");\n            if (!directory.exists()) directory.mkdir();\n\n            // migrate\n            if (new File(DankersSkyblockMod.configDirectory + \"/dsmalerts.json\").exists()) {\n                transferFile(\"/dsmalerts.json\");\n                transferFile(\"/dsmaliases.json\");\n                transferFile(\"/dsmminions.json\");\n                transferFile(\"/dsmtrophyfish.json\");\n                transferFile(\"/dsmmeter.json\");\n            }\n\n            // Alerts\n            Object[] alerts = initJsonArray(Alerts.configFile, Alerts.Alert[].class);\n            if (alerts != null) Alerts.alerts = new ArrayList<>(Arrays.asList((Alerts.Alert[]) alerts));\n\n            // Aliases\n            Object[] aliases = initJsonArray(ChatAliases.configFile, ChatAliases.Alias[].class);\n            if (aliases != null) ChatAliases.aliases = new ArrayList<>(Arrays.asList((ChatAliases.Alias[]) aliases));\n\n            // Minions\n            Object[] minions = initJsonArray(MinionLastCollected.configFile, MinionLastCollected.Minion[].class);\n            if (minions != null) MinionLastCollected.minions = new ArrayList<>(Arrays.asList((MinionLastCollected.Minion[]) minions));\n\n            // Trophy Fish\n            TrophyFishTracker.fish = initJsonObject(TrophyFishTracker.configFile);\n            MeterTracker.meter = initJsonObject(MeterTracker.configFile);\n            DungeonTimer.timer = initJsonObject(DungeonTimer.configFile);\n        } catch (IOException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    public static void transferFile(String file) throws IOException {\n        File path = new File(DankersSkyblockMod.configDirectory + file);\n        if (path.exists()) {\n            File dest = new File(DankersSkyblockMod.configDirectory + \"/dsm\");\n            FileUtils.moveFileToDirectory(path, dest, true);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/config/ModConfig.java",
    "content": "package me.Danker.config;\n\n\nimport cc.polyfrost.oneconfig.config.Config;\nimport cc.polyfrost.oneconfig.config.annotations.Button;\nimport cc.polyfrost.oneconfig.config.annotations.Color;\nimport cc.polyfrost.oneconfig.config.annotations.Number;\nimport cc.polyfrost.oneconfig.config.annotations.*;\nimport cc.polyfrost.oneconfig.config.core.OneColor;\nimport cc.polyfrost.oneconfig.config.core.OneKeyBind;\nimport cc.polyfrost.oneconfig.config.data.InfoType;\nimport cc.polyfrost.oneconfig.config.data.Mod;\nimport cc.polyfrost.oneconfig.config.data.ModType;\nimport cc.polyfrost.oneconfig.config.data.OptionSize;\nimport cc.polyfrost.oneconfig.config.migration.CfgMigrator;\nimport cc.polyfrost.oneconfig.config.migration.CfgName;\nimport cc.polyfrost.oneconfig.utils.Notifications;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.features.*;\nimport me.Danker.features.loot.LootDisplay;\nimport me.Danker.features.puzzlesolvers.LividSolver;\nimport me.Danker.features.puzzlesolvers.WaterSolver;\nimport me.Danker.gui.alerts.AlertsGui;\nimport me.Danker.gui.aliases.AliasesGui;\nimport me.Danker.gui.crystalhollowwaypoints.CrystalHollowWaypointsGui;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.awt.*;\nimport java.io.IOException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.util.Arrays;\n\npublic class ModConfig extends Config {\n\n    @Exclude Minecraft mc = Minecraft.getMinecraft();\n    @Exclude static String[] displays = {\"Off\", \"Zombie Slayer\", \"Spider Slayer\", \"Wolf Slayer\", \"Enderman Slayer\", \"Blaze Slayer\", \"Vampire Slayer\", \"Fishing\", \"Winter Fishing\", \"Fishing Festival\", \"Spooky Fishing\", \"Crystal Hollows Fishing\", \"Lava Fishing\", \"Trophy Fishing\", \"Floor 1\", \"Floor 2\", \"Floor 3\", \"Floor 4\", \"Floor 5\", \"Floor 6\", \"Floor 7\", \"Master Mode\", \"Mythological\", \"Ghost\"};\n\n    public ModConfig() {\n        super(new Mod(\"Danker's Skyblock Mod\", ModType.SKYBLOCK, \"/assets/dsm/icons/icon.png\", new CfgMigrator(\"./config/Danker's Skyblock Mod.cfg\")), \"dsmconfig.json\");\n        initialize();\n\n        registerKeyBind(maddoxKey, FasterMaddoxCalling::onKey);\n        registerKeyBind(pearlKey, GetPearlFromSack::onKey);\n        registerKeyBind(abilityKey, DankersSkyblockMod::onAbilityKey);\n        registerKeyBind(waypointKey, CrystalHollowWaypoints::onKey);\n        registerKeyBind(skillTrackerKey, SkillTracker::onKey);\n        registerKeyBind(powderTrackerKey, PowderTracker::onKey);\n        registerKeyBind(disableMouse, DisableMovement::onDisableMouse);\n        registerKeyBind(disableWS, DisableMovement::onDisableWS);\n        registerKeyBind(disableAD, DisableMovement::onDisableAD);\n\n        addDependency(\"customNametags\", \"customColouredNames\");\n        addDependency(\"creeperLines\", \"creeper\");\n        addDependency(\"lowestBlazeColour\", \"blaze\");\n        addDependency(\"highestBlazeColour\", \"blaze\");\n        addDependency(\"slayerBoxColour\", \"highlightSlayers\");\n        addDependency(\"arachneBoxColour\", \"highlightArachne\");\n        addDependency(\"skeletonMasterBoxColour\", \"highlightSkeletonMasters\");\n        addDependency(\"slayerName\", \"blockSlayer\");\n        addDependency(\"slayerNumber\", \"blockSlayer\");\n        addDependency(\"ultrasequencerNextColour\", \"ultrasequencer\");\n        addDependency(\"ultrasequencerNextToNextColour\", \"ultrasequencer\");\n        addDependency(\"chronomatronNextColour\", \"chronomatron\");\n        addDependency(\"chronomatronNextToNextColour\", \"chronomatron\");\n        addDependency(\"clickInOrderNextColour\", \"clickInOrder\");\n        addDependency(\"clickInOrderNextToNextColour\", \"clickInOrder\");\n        addDependency(\"farmX\", \"endOfFarmAlert\");\n        addDependency(\"farmMinX\", \"endOfFarmAlert\");\n        addDependency(\"farmMinX\", \"farmX\");\n        addDependency(\"farmMaxX\", \"endOfFarmAlert\");\n        addDependency(\"farmMaxX\", \"farmX\");\n        addDependency(\"farmZ\", \"endOfFarmAlert\");\n        addDependency(\"farmMinZ\", \"endOfFarmAlert\");\n        addDependency(\"farmMinZ\", \"farmZ\");\n        addDependency(\"farmMaxZ\", \"endOfFarmAlert\");\n        addDependency(\"farmMaxZ\", \"farmZ\");\n        addDependency(\"boulderColour\", \"boulder\");\n        addDependency(\"boulderArrowColour\", \"boulder\");\n        addDependency(\"silverfishLineColour\", \"silverfish\");\n        addDependency(\"iceWalkLineColour\", \"iceWalk\");\n        addDependency(\"commissionColour\", \"highlightCommissions\");\n        addDependency(\"lastCollectedColour\", \"minionLastCollected\");\n        addDependency(\"ticTacToeColour\", \"ticTacToe\");\n        addDependency(\"startsWithColour\", \"startsWith\");\n        addDependency(\"selectAllColour\", \"selectAll\");\n        addDependency(\"autoWaypoints\", \"crystalHollowWaypoints\");\n        addDependency(\"autoPlayerWaypoints\", \"crystalHollowWaypoints\");\n        addDependency(\"autoImportWaypoints\", \"crystalHollowWaypoints\");\n        addDependency(\"permaWaypoints\", \"crystalHollowWaypoints\");\n        addDependency(\"permaWaypoints\", \"autoImportWaypoints\");\n        addDependency(\"copyWaypoints\", \"crystalHollowWaypoints\");\n        addDependency(\"importWaypoints\", \"crystalHollowWaypoints\");\n        addDependency(\"triviaWrongAnswerColour\", \"oruo\");\n        addDependency(\"threeManAnswerColour\", \"threeMan\");\n        addDependency(\"highlightOrdersColour\", \"highlightOrders\");\n        addDependency(\"highlightPestsColour\", \"highlightPests\");\n        addDependency(\"hidePlayerArmourOnly\", \"hideArmour\");\n        addDependency(\"autoImportWaypoints\", \"autoWaypoints\");\n        addDependency(\"debugPacketsIn\", \"debug\");\n        addDependency(\"debugPacketsOut\", \"debug\");\n        addDependency(\"debugChat\", \"debug\");\n        addDependency(\"thunderAlert\", \"fishingAlert\");\n        addDependency(\"jawbusAlert\", \"fishingAlert\");\n        addDependency(\"gwAlert\", \"fishingAlert\");\n    }\n\n    public static String getColour(int index) {\n        return \"§\" + Integer.toHexString(index);\n    }\n\n    public static String getDelimiter() {\n        return getColour(delimiterColour) + EnumChatFormatting.STRIKETHROUGH + \"-----------------------------\";\n    }\n\n    public static String getDisplay() {\n        return displays[LootDisplay.display];\n    }\n\n    public static int toDisplay(String value) {\n        return Arrays.asList(displays).indexOf(value);\n    }\n\n    /* categories:\n    general\n        general\n        slayers\n        hide tooltips\n        custom name colors\n    puzzle solvers\n        dungeons\n        terminals\n        experiments\n    display\n        options\n        general\n        dungeons\n        misc.\n    trackers\n        loot tracker\n        skill tracker\n        powder tracker\n    highlights\n        general\n        hitboxes\n    alerts\n        options\n        custom alerts\n        general\n        dungeons\n        farming\n        fishing\n    aliases\n        custom aliases\n    waypoints\n        crystal hollows\n    messages\n        general\n    music\n        options\n        music\n    colors\n        text\n        pet highlight colors\n    keybinds\n        general\n        dungeons\n        waypoints\n        trackers\n        farming\n    debug\n    */\n\n    // General\n\n    @CfgName(\n            name = \"ExpertiseLore\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Expertise Kills In Lore\",\n            description = \"Adds expertise kills to fishing rod tooltip.\",\n            category = \"General\",\n            subcategory = \"General\"\n    )\n    public static boolean expertiseLore = false;\n\n    @CfgName(\n            name = \"HidePetCandy\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Hide Pet Candy\",\n            description = \"Hide pet candy in pet tooltips.\",\n            category = \"General\",\n            subcategory = \"General\"\n    )\n    public static boolean hidePetCandy = false;\n\n    @CfgName(\n            name = \"GemstoneLore\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Applied Gemstones in Lore\",\n            description = \"Adds applied gemstones to item tooltip.\",\n            category = \"General\",\n            subcategory = \"General\"\n    )\n    public static boolean gemstoneLore = false;\n\n    @CfgName(\n            name = \"StopSalvageStarred\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Stop Salvaging Starred Items\",\n            description = \"Blocks salvaging starred items.\",\n            category = \"General\",\n            subcategory = \"General\"\n    )\n    public static boolean stopSalvageStarred = false;\n\n    @CfgName(\n            name = \"PickBlock\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Auto-Swap to Pick Block\",\n            description = \"Automatically changes left clicks to middle clicks.\\nHelpful when lagging.\",\n            category = \"General\",\n            subcategory = \"General\"\n    )\n    public static boolean swapToPickBlock = false;\n\n    @CfgName(\n            name = \"FlowerWeapons\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Prevent Placing Flower Weapons\",\n            description = \"Blocks placing Flower of Truth, Spirit Sceptre, Bouquet of Lies, and Fire Freeze Staff.\",\n            category = \"General\",\n            subcategory = \"General\"\n    )\n    public static boolean flowerWeapons = false;\n\n    @CfgName(\n            name = \"HideArmour\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Hide Player Armor\",\n            description = \"Makes player armour invisible, showing their skin.\",\n            category = \"General\",\n            subcategory = \"General\"\n    )\n    public static boolean hideArmour = false;\n\n    @Switch(\n            name = \"Don't hide NPC armor\",\n            description = \"If you have Hide Player Armor enabled, don't hide the armor of NPCs. 99% accurate\",\n            category = \"General\",\n            subcategory = \"General\"\n    )\n    public static boolean hidePlayerArmourOnly = false;\n\n    @CfgName(\n            name = \"AutoJoinSkyblock\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Automatically Join Skyblock\",\n            description = \"Automatically join Skyblock when you join Hypixel.\\nYou have an addiction.\",\n            category = \"General\",\n            subcategory = \"General\"\n    )\n    public static boolean autoJoinSkyblock = false;\n\n    @CfgName(\n            name = \"AnnounceVanqs\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Announce Vanquishers\",\n            description = \"Announces when and at what coordinates your Vanquisher spawns in your selected chat.\",\n            category = \"General\",\n            subcategory = \"General\"\n    )\n    public static boolean announceVanqs = false;\n\n    @CfgName(\n            name = \"GParty\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Guild Party Notifications\",\n            description = \"Creates desktop notification on guild party.\",\n            category = \"General\",\n            subcategory = \"General\"\n    )\n    public static boolean gparty = false;\n\n    @CfgName(\n            name = \"Golden\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Golden T10/T6/T4 Enchantments\",\n            description = \"Turns expensive enchants golden in tooltips.\",\n            category = \"General\",\n            subcategory = \"General\"\n    )\n    public static boolean golden = false;\n\n    @Switch(\n            name = \"Fix Drill Animation Reset\",\n            description = \"Fixes drill animation resetting when the fuel updates.\",\n            category = \"General\",\n            subcategory = \"General\"\n    )\n    public static boolean drillFix = false;\n\n    @CfgName(\n            name = \"AutoAcceptReparty\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Auto Accept Reparty\",\n            description = \"Automatically rejoins parties when disbanded and invited.\",\n            category = \"General\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean autoAcceptReparty = false;\n\n    @Switch(\n            name = \"RNG Meter Tracker\",\n            description = \"Prints RNG meter info at the end of a dungeon run.\\nOpen your RNG meter menu to sync selected drops.\",\n            category = \"General\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean meterTracker = false;\n\n    @CfgName(\n            name = \"ChatMaddox\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Click On-Screen to Open Maddox\",\n            description = \"Open chat then click anywhere after calling Maddox to open the menu.\",\n            category = \"General\",\n            subcategory = \"Slayers\"\n    )\n    public static boolean chatMaddox = false;\n\n    @Switch(\n            name = \"Only Allow Certain Slayer\",\n            description = \"Blocks clicks on incorrect slayers.\",\n            size = OptionSize.DUAL,\n            category = \"General\",\n            subcategory = \"Slayers\"\n    )\n    public static boolean blockSlayer = false;\n\n    @Dropdown(\n            name = \"Slayer Boss\",\n            options = {\n                    \"Revenant Horror\",\n                    \"Tarantula Broodfather\",\n                    \"Sven Packmaster\",\n                    \"Voidgloom Seraph\",\n                    \"Inferno Demonlord\"\n            },\n            category = \"General\",\n            subcategory = \"Slayers\"\n    )\n    public static int slayerName = 0;\n\n    @Dropdown(\n            name = \"Slayer Tier\",\n            options = {\n                    \"I\",\n                    \"II\",\n                    \"III\",\n                    \"IV\",\n                    \"V\"\n            },\n            category = \"General\",\n            subcategory = \"Slayers\"\n    )\n    public static int slayerNumber = 4;\n\n    @CfgName(\n            name = \"MelodyTooltips\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Hide Tooltips in Melody's Harp\",\n            description = \"Hides tooltips in Melody's Harp.\",\n            category = \"General\",\n            subcategory = \"Hide Tooltips\"\n    )\n    public static boolean melodyTooltips = false;\n\n    @Switch(\n            name = \"Hide Tooltips During Hacking\",\n            description = \"Hides tooltips during hacking in the rift.\",\n            category = \"General\",\n            subcategory = \"Hide Tooltips\"\n    )\n    public static boolean hackingTooltips = false;\n\n    @CfgName(\n            name = \"HideTooltipsInExperimentAddons\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Hide Tooltips in Addons\",\n            description = \"Hides tooltips in experiment addons.\",\n            category = \"General\",\n            subcategory = \"Hide Tooltips\"\n    )\n    public static boolean hideTooltipsInExperimentAddons = false;\n\n    @CfgName(\n            name = \"CustomColouredNames\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Custom Name Colors\",\n            description = \"Replaces some player's usernames with a custom color.\",\n            category = \"General\",\n            subcategory = \"Custom Name Colors\"\n    )\n    public static boolean customColouredNames = false;\n\n    @CfgName(\n            name = \"CustomNametags\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Custom Color on Nametags\",\n            description = \"Displays custom name colors on nametags. Disabling will increase performance with custom colors.\",\n            category = \"General\",\n            subcategory = \"Custom Name Colors\"\n    )\n    public static boolean customNametags = true;\n\n    // Puzzle Solvers\n\n    @HUD(\n            name = \"Find Correct Livid\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static LividSolver.LividSolverHud lividSolverHud = new LividSolver.LividSolverHud();\n\n    @CfgName(\n            name = \"ThreeManPuzzle\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Riddle Solver\",\n            description = \"Solves the three man puzzle in dungeons.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean threeMan = false;\n\n    @Dropdown(\n            name = \"Riddle Puzzle Answer Text Color\",\n            description = \"Color for the solution to the three man dungeon puzzle.\",\n            options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"},\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static int threeManAnswerColour = 2;\n\n    @CfgName(\n            name = \"OruoPuzzle\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Trivia Solver\",\n            description = \"Solves Oruo's trivia in dungeons\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean oruo = false;\n\n    @Dropdown(\n            name = \"Trivia Wrong Answer Text Color\",\n            description = \"Color for the wrong answers in Oruo's trivia dungeon puzzle.\",\n            options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"},\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static int triviaWrongAnswerColour = 12;\n\n    @CfgName(\n            name = \"BlazePuzzle\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Blaze Solver\",\n            description = \"Solves the shoot in order blaze puzzle in dungeons.\",\n            size = OptionSize.DUAL,\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean blaze = false;\n\n    @Color(\n            name = \"Lowest Blaze Color\",\n            description = \"Color for the blaze with the lowest HP in the blaze dungeon puzzle.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static OneColor lowestBlazeColour = new OneColor(255, 0, 0);\n\n    @Color(\n            name = \"Highest Blaze Color\",\n            description = \"Color for the blaze with the highest HP in the blaze dungeon puzzle.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static OneColor highestBlazeColour = new OneColor(64, 255, 64);\n\n    @CfgName(\n            name = \"CreeperPuzzle\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Creeper Solver\",\n            description = \"Solves the creeper beams puzzle in dungeons.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean creeper = false;\n\n    @CfgName(\n            name = \"CreeperLines\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Lines In Creeper Solver\",\n            description = \"Adds lines connecting the matching blocks in the creeper puzzle solver.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean creeperLines = true;\n\n    @CfgName(\n            name = \"TicTacToePuzzle\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Tic Tac Toe Solver\",\n            description = \"Solves the tic tac toe puzzle in dungeons.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean ticTacToe = false;\n\n    @Color(\n            name = \"Correct Location Box Color\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static OneColor ticTacToeColour = new OneColor(64, 255, 64);\n\n    @HUD(\n            name = \"Water Solver\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static WaterSolver.WaterSolverHud waterSolverHud = new WaterSolver.WaterSolverHud();\n\n    @CfgName(\n            name = \"BoulderPuzzle\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Boulder Solver\",\n            description = \"Solves the boulder puzzle in dungeons.\",\n            size = OptionSize.DUAL,\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean boulder = false;\n\n    @Color(\n            name = \"Boulder to Push Color\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static OneColor boulderColour = new OneColor(25, 127, 25);\n\n    @Color(\n            name = \"Boulder Direction Arrow Color\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static OneColor boulderArrowColour = new OneColor(0, 96, 0);\n\n    @CfgName(\n            name = \"SilverfishPuzzle\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Silverfish Solver\",\n            description = \"Solves the silverfish puzzle in dungeons.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean silverfish = false;\n\n    @Color(\n            name = \"Silverfish Line Color\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static OneColor silverfishLineColour = new OneColor(64, 255, 64);\n\n    @CfgName(\n            name = \"IceWalkPuzzle\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Ice Walk Solver\",\n            description = \"Solves the ice walk puzzle in dungeons.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean iceWalk = false;\n\n    @Color(\n            name = \"Ice Walk Line Color\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Dungeons\"\n    )\n    public static OneColor iceWalkLineColour = new OneColor(64, 255, 64);\n\n    @CfgName(\n            name = \"StartsWithTerminal\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Starts With Letter Terminal Solver\",\n            description = \"Solves the starts with letter terminal in F7.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Terminals\"\n    )\n    public static boolean startsWith = false;\n\n    @Color(\n            name = \"Matching Item Color\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Terminals\"\n    )\n    public static OneColor startsWithColour = new OneColor(64, 255, 64, 191);\n\n    @CfgName(\n            name = \"SelectAllTerminal\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Select All Color Terminal Solver\",\n            description = \"Solves the select all matching color termianl in F7.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Terminals\"\n    )\n    public static boolean selectAll = false;\n\n    @Color(\n            name = \"Matching Item Color\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Terminals\"\n    )\n    public static OneColor selectAllColour = new OneColor(64, 255, 64, 191);\n\n    @CfgName(\n            name = \"ClickInOrderTerminal\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Click in Order Terminal Helper\",\n            description = \"Solves the click in order terminal in F7.\",\n            size = OptionSize.DUAL,\n            category = \"Puzzle Solvers\",\n            subcategory = \"Terminals\"\n    )\n    public static boolean clickInOrder = false;\n\n    @Color(\n            name = \"Next Slot to Click\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Terminals\"\n    )\n    public static OneColor clickInOrderNextColour = new OneColor(255, 0, 221);\n\n    @Color(\n            name = \"Next to Next Slot to Click\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Terminals\"\n    )\n    public static OneColor clickInOrderNextToNextColour = new OneColor(11, 239, 231);\n\n    @CfgName(\n            name = \"SameColourTerminal\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Same Colour Terminal Solver\",\n            description = \"Solves the make all same color terminal in F7.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Terminals\"\n    )\n    public static boolean sameColour = false;\n\n    @CfgName(\n            name = \"BlockWrongTerminalClicks\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Block Wrong Clicks on Terminals\",\n            description = \"Blocks incorrect clicks in terminals.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Terminals\"\n    )\n    public static boolean blockWrongTerminalClicks = false;\n\n    @CfgName(\n            name = \"IgnoreItemFrameOnSeaLanterns\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Ignore Arrows On Sea Lanterns\",\n            description = \"Prevents moving correct arrows in the F7 phase 3 arrow device.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Terminals\"\n    )\n    public static boolean itemFrameOnSeaLanterns = false;\n\n    @CfgName(\n            name = \"UltraSequencer\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Ultrasequencer Solver\",\n            description = \"Solves the Ultrasequencer experiment.\",\n            size = OptionSize.DUAL,\n            category = \"Puzzle Solvers\",\n            subcategory = \"Experiments\"\n    )\n    public static boolean ultrasequencer = false;\n\n    @Color(\n            name = \"Next Slot to Click\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Experiments\"\n    )\n    public static OneColor ultrasequencerNextColour = new OneColor(64, 255, 64, 229);\n\n    @Color(\n            name = \"Next to Next Slot to Click\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Experiments\"\n    )\n    public static OneColor ultrasequencerNextToNextColour = new OneColor(64, 218, 230, 215);\n\n    @CfgName(\n            name = \"Chronomatron\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Chronomatron Solver\",\n            description = \"Solves the Chronomatron experiment.\",\n            size = OptionSize.DUAL,\n            category = \"Puzzle Solvers\",\n            subcategory = \"Experiments\"\n    )\n    public static boolean chronomatron = false;\n\n    @Color(\n            name = \"Next Slot to Click\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Experiments\"\n    )\n    public static OneColor chronomatronNextColour = new OneColor(64, 255, 64, 229);\n\n    @Color(\n            name = \"Next to Next Slot to Click\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Experiments\"\n    )\n    public static OneColor chronomatronNextToNextColour = new OneColor(64, 218, 230, 190);\n\n    @CfgName(\n            name = \"Superpairs\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Superpairs Solver\",\n            description = \"Solves the Superpairs experiment.\",\n            category = \"Puzzle Solvers\",\n            subcategory = \"Experiments\"\n    )\n    public static boolean superpairs = false;\n\n    // Display\n\n    @CfgName(\n            name = \"OutlineText\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Outline Displayed Text\",\n            description = \"Adds bold outline to on-screen text.\",\n            category = \"Display\",\n            subcategory = \"Options\"\n    )\n    public static boolean outlineText = false;\n\n    @HUD(\n            name = \"Coordinate/Angle Display\",\n            category = \"Display\",\n            subcategory = \"General\"\n    )\n    public static NoF3Coords coordsHud = new NoF3Coords();\n\n    @HUD(\n            name = \"Display Progress to Max Skill Level\",\n            category = \"Display\",\n            subcategory = \"General\"\n    )\n    public static Skill50Display.MaxSkillHud maxSkillHud = new Skill50Display.MaxSkillHud();\n\n    @HUD(\n            name = \"Cake Timer\",\n            category = \"Display\",\n            subcategory = \"General\"\n    )\n    public static CakeTimer.CakeTimerHud cakeTimerHud = new CakeTimer.CakeTimerHud();\n\n    @HUD(\n            name = \"Ability Cooldowns\",\n            category = \"Display\",\n            subcategory = \"General\"\n    )\n    public static AbilityCooldowns.AbilityCooldownHud abilityCooldownHud = new AbilityCooldowns.AbilityCooldownHud();\n\n    @HUD(\n            name = \"Fire Pillar Display\",\n            category = \"Display\",\n            subcategory = \"General\"\n    )\n    public static FirePillarDisplay.FirePillarHud firePillarHud = new FirePillarDisplay.FirePillarHud();\n\n    @HUD(\n            name = \"Crimson Isle Miniboss Timer\",\n            category = \"Display\",\n            subcategory = \"General\"\n    )\n    public static CrimsonMinibossTimer.MinibossTimerHud minibossTimerHud = new CrimsonMinibossTimer.MinibossTimerHud();\n\n    @HUD(\n            name = \"Golem Spawn Timer\",\n            category = \"Display\",\n            subcategory = \"General\"\n    )\n    public static GolemSpawningAlert.GolemTimerHud golemTimerHud = new GolemSpawningAlert.GolemTimerHud();\n\n    @HUD(\n            name = \"Bonzo's Mask Timer\",\n            category = \"Display\",\n            subcategory = \"Dungeons\"\n    )\n    public static BonzoMaskTimer.BonzoTimerHud bonzoTimerHud = new BonzoMaskTimer.BonzoTimerHud();\n\n    @HUD(\n            name = \"Spirit Mask Timer\",\n            category = \"Display\",\n            subcategory = \"Dungeons\"\n    )\n    public static SpiritMaskTimer.SpiritTimerHud spiritTimerHud = new SpiritMaskTimer.SpiritTimerHud();\n\n    @HUD(\n            name = \"Display Players in 30 Block Radius\",\n            category = \"Display\",\n            subcategory = \"Dungeons\"\n    )\n    public static TetherDisplay.TetherDisplayHud tetherHud = new TetherDisplay.TetherDisplayHud();\n\n    @HUD(\n            name = \"Display Giant HP\",\n            category = \"Display\",\n            subcategory = \"Dungeons\"\n    )\n    public static GiantHPDisplay.GiantHPHud giantHPHud = new GiantHPDisplay.GiantHPHud();\n\n    @HUD(\n            name = \"Display Dungeon Timers\",\n            category = \"Display\",\n            subcategory = \"Dungeons\"\n    )\n    public static DungeonTimer.DungeonTimerHud dungeonTimerHud = new DungeonTimer.DungeonTimerHud();\n\n    @HUD(\n            name = \"Dungeon Score Display\",\n            category = \"Display\",\n            subcategory = \"Dungeons\"\n    )\n    public static DungeonScore.DungeonScoreHud dungeonScoreHud = new DungeonScore.DungeonScoreHud();\n\n    @CfgName(\n            name = \"MinionLastCollected\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Show When Minion Last Collected\",\n            description = \"Displays when a minion was last collected over the minion.\",\n            category = \"Display\",\n            subcategory = \"Misc.\"\n    )\n    public static boolean minionLastCollected = false;\n\n    @Color(\n            name = \"Minion Last Collected Color\",\n            category = \"Display\",\n            subcategory = \"Misc.\"\n    )\n    public static OneColor lastCollectedColour = new OneColor(85, 255, 255);\n\n    @CfgName(\n            name = \"ShowTotalMagmafish\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Show Total Fillet Magmafish\",\n            description = \"Show total Magmafish you would get if you filleted all the trophy fish in your inventory.\",\n            category = \"Display\",\n            subcategory = \"Misc.\"\n    )\n    public static boolean showTotalMagmafish = false;\n\n    @CfgName(\n            name = \"BazaarTimeToFill\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Show Time to Fill Bazaar Order\",\n            description = \"Shows an estimated amount of time it would take for a bazaar order to be filled.\\nAssumes you are not over/undercut.\\nOnly works when moving through menus. Doesn't work when clicking items as shortcut.\",\n            category = \"Display\",\n            subcategory = \"Misc.\"\n    )\n    public static boolean bazaarTimeToFill = false;\n\n    // Trackers\n\n    @HUD(\n            name = \"Loot Display\",\n            category = \"Trackers\"\n    )\n    public static LootDisplay lootDisplayHud = new LootDisplay();\n\n    @HUD(\n            name = \"Skill Tracker\",\n            category = \"Trackers\"\n    )\n    public static SkillTracker.SkillTrackerHud skillTrackerHud = new SkillTracker.SkillTrackerHud();\n\n    @HUD(\n            name = \"Powder Tracker\",\n            category = \"Trackers\"\n    )\n    public static PowderTracker.PowderTrackerHud powderTrackerHud = new PowderTracker.PowderTrackerHud();\n\n    // Highlights\n\n    @CfgName(\n            name = \"PetColors\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Color Pet Backgrounds\",\n            description = \"Colors pets based on their level.\",\n            category = \"Highlights\",\n            subcategory = \"General\"\n    )\n    public static boolean petColours = false;\n\n    @Info(\n            text = \"Pet highlight colors are in the colors category.\",\n            type = InfoType.INFO,\n            category = \"Highlights\",\n            subcategory = \"General\"\n    )\n    public static boolean ignored1;\n\n    @CfgName(\n            name = \"HighlightCommissions\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Highlight Completed Commissions\",\n            description = \"Show which commissions are completed.\",\n            category = \"Highlights\",\n            subcategory = \"General\"\n    )\n    public static boolean highlightCommissions = false;\n\n    @Color(\n            name = \"Commission Highlight Color\",\n            category = \"Highlights\",\n            subcategory = \"General\"\n    )\n    public static OneColor commissionColour = new OneColor(81, 255, 81, 215);\n\n   @Switch(\n            name = \"Highlight Filled Orders\",\n            description = \"Show which bazaar orders have been filled.\",\n            category = \"Highlights\",\n            subcategory = \"General\"\n    )\n    public static boolean highlightOrders = false;\n\n    @Color(\n            name = \"Filled Order Highlight Color\",\n            category = \"Highlights\",\n            subcategory = \"General\"\n    )\n    public static OneColor highlightOrdersColour = new OneColor(81, 255, 81, 215);\n\n    @Switch(\n            name = \"Highlight Plots With Pests\",\n            description = \"Show which plots have pests on them.\",\n            category = \"Highlights\",\n            subcategory = \"General\"\n    )\n    public static boolean highlightPests = false;\n\n    @Color(\n            name = \"Plot Highlight Color\",\n            category = \"Highlights\",\n            subcategory = \"General\"\n    )\n    public static OneColor highlightPestsColour = new OneColor(81, 255, 81, 215);\n\n    @CfgName(\n            name = \"HighlightSlayers\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Highlight Slayer Boss\",\n            description = \"Draws a box around Slayer bosses.\",\n            category = \"Highlights\",\n            subcategory = \"Hitboxes\"\n    )\n    public static boolean highlightSlayers = false;\n\n    @Color(\n            name = \"Slayer Box Color\",\n            category = \"Highlights\",\n            subcategory = \"Hitboxes\"\n    )\n    public static OneColor slayerBoxColour = new OneColor(0, 0, 255);\n\n    @CfgName(\n            name = \"HighlightArachne\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Highlight Arachne\",\n            description = \"Draws a box around Arachne.\",\n            category = \"Highlights\",\n            subcategory = \"Hitboxes\"\n    )\n    public static boolean highlightArachne = false;\n\n    @Color(\n            name = \"Arachne Box Color\",\n            category = \"Highlights\",\n            subcategory = \"Hitboxes\"\n    )\n    public static OneColor arachneBoxColour = new OneColor(0, 255, 0);\n\n    @CfgName(\n            name = \"HighlightSkeletonMasters\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Highlight Skeleton Masters\",\n            description = \"Draws a box around Skeleton Masters.\",\n            category = \"Highlights\",\n            subcategory = \"Hitboxes\"\n    )\n    public static boolean highlightSkeletonMasters = false;\n\n    @Color(\n            name = \"Skeleton Master Box Color\",\n            category = \"Highlights\",\n            subcategory = \"Hitboxes\"\n    )\n    public static OneColor skeletonMasterBoxColour = new OneColor(255, 0, 0);\n\n    // Alerts\n\n    @CfgName(\n            name = \"titleSound\",\n            category = \"misc\"\n    )\n    @Text(\n            name = \"Alert Noise\",\n            description = \"The Minecraft sound that plays when an alert is made.\",\n            category = \"Alerts\",\n            subcategory = \"Options\"\n    )\n    public static String alertNoise = \"random.orb\";\n\n    @CfgName(\n            name = \"Alerts\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Custom Alerts\",\n            description = \"Sends custom alert when a message is recieved\",\n            category = \"Alerts\",\n            subcategory = \"Custom Alerts\"\n    )\n    public static boolean alerts = false;\n\n    @Button(\n            name = \"Custom Alerts\",\n            text = \"Click\",\n            category = \"Alerts\",\n            subcategory = \"Custom Alerts\"\n    )\n    Runnable alertsButton = () -> mc.displayGuiScreen(new AlertsGui(1));\n\n    @CfgName(\n            name = \"GolemAlerts\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Golem Spawn Alert And Timer\",\n            description = \"Creates alert with 20s countdown when golem is spawning.\",\n            category = \"Alerts\",\n            subcategory = \"General\"\n    )\n    public static boolean golemAlerts = false;\n\n    @CfgName(\n            name = \"RNGesusAlerts\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Slayer RNGesus Alerts\",\n            description = \"Alerts when an RNGesus item is dropped.\",\n            category = \"Alerts\",\n            subcategory = \"General\"\n    )\n    public static boolean rngesusAlerts = false;\n\n    @CfgName(\n            name = \"NotifySlayerSlain\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Notify when Slayer Slain\",\n            description = \"Alerts when slayer boss has been slain.\",\n            category = \"Alerts\",\n            subcategory = \"General\"\n    )\n    public static boolean notifySlayerSlain = false;\n\n    @CfgName(\n            name = \"KuudraNotifications\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Kuudra Notifications\",\n            description = \"Alerts when to cloak for dropships, when Kuudra is stunned and when Ballista is fully charged.\",\n            category = \"Alerts\",\n            subcategory = \"General\"\n    )\n    public static boolean kuudraNotifications = false;\n\n    @CfgName(\n            name = \"SpiritBearAlerts\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Spirit Bear Spawn Alerts\",\n            description = \"Alert when Spirit Bear spawns.\",\n            category = \"Alerts\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean spiritBearAlerts = false;\n\n    @CfgName(\n            name = \"LowHealthNotify\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Low Health Notifications\",\n            description = \"Alerts when dungeon teammate has low health.\",\n            category = \"Alerts\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean lowHealthNotify = false;\n\n    @CfgName(\n            name = \"WatcherReadyMessage\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Display Watcher Ready Message\",\n            description = \"Alerts when Watcher finishes spawning mobs.\",\n            category = \"Alerts\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean watcherReady = false;\n\n    @CfgName(\n            name = \"NecronNotifications\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Floor 7 Phase Notifications\",\n            description = \"Creates alert on different phases of the floor 7 fight.\",\n            category = \"Alerts\",\n            subcategory = \"Dungeons\"\n    )\n    public static boolean necronNotifications = false;\n\n    @CfgName(\n            name = \"EndOfFarmAlert\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Alert When Reaching End of Farm\",\n            description = \"Alerts when you go past certain coords.\",\n            size = OptionSize.DUAL,\n            category = \"Alerts\",\n            subcategory = \"Farming\"\n    )\n    public static boolean endOfFarmAlert = false;\n\n    @Switch(\n            name = \"Alert Based on X Coordinates\",\n            description = \"Alerts when you go past X coords.\",\n            size = OptionSize.DUAL,\n            category = \"Alerts\",\n            subcategory = \"Farming\"\n    )\n    public static boolean farmX = true;\n\n    @CfgName(\n            name = \"farmMin\",\n            category = \"misc\"\n    )\n    @Number(\n            name = \"Minimum X Coords\",\n            description = \"When your coords go below this number, the alert will sound.\",\n            min = -300F, max = 300F,\n            category = \"Alerts\",\n            subcategory = \"Farming\"\n    )\n    public static float farmMinX = -220F;\n\n    @CfgName(\n            name = \"farmMax\",\n            category = \"misc\"\n    )\n    @Number(\n            name = \"Maximum X Coords\",\n            description = \"When your coords go above this number, the alert will sound.\",\n            min = -300F, max = 300F,\n            category = \"Alerts\",\n            subcategory = \"Farming\"\n    )\n    public static float farmMaxX = 220F;\n\n    @Switch(\n            name = \"Alert Based on Z Coordinates\",\n            description = \"Alerts when you go past Z coords.\",\n            size = OptionSize.DUAL,\n            category = \"Alerts\",\n            subcategory = \"Farming\"\n    )\n    public static boolean farmZ = true;\n\n    @CfgName(\n            name = \"farmMin\",\n            category = \"misc\"\n    )\n    @Number(\n            name = \"Minimum Z Coords\",\n            description = \"When your coords go below this number, the alert will sound.\",\n            min = -300F, max = 300F,\n            category = \"Alerts\",\n            subcategory = \"Farming\"\n    )\n    public static float farmMinZ = -220F;\n\n    @CfgName(\n            name = \"farmMax\",\n            category = \"misc\"\n    )\n    @Number(\n            name = \"Maximum Z Coords\",\n            description = \"When your coords go above this number, the alert will sound.\",\n            min = -300F, max = 300F,\n            category = \"Alerts\",\n            subcategory = \"Farming\"\n    )\n    public static float farmMaxZ = 220F;\n\n    @CfgName(\n            name = \"FishingAlert\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Fishing Spawn Alerts\",\n            description = \"Alerts when a mob is fished up nearby.\",\n            category = \"Alerts\",\n            subcategory = \"Fishing\"\n    )\n    public static boolean fishingAlert = false;\n\n    @Switch(\n            name = \"Thunder Spawn Alert\",\n            description = \"Alert when a Thunder is fished up nearby.\",\n            category = \"Alerts\",\n            subcategory = \"Fishing\"\n    )\n    public static boolean thunderAlert = true;\n\n    @Switch(\n            name = \"Jawbus Spawn Alert\",\n            description = \"Alert when a Jawbus is fished up nearby.\",\n            category = \"Alerts\",\n            subcategory = \"Fishing\"\n    )\n    public static boolean jawbusAlert = true;\n\n    @Switch(\n            name = \"Great White Shark Spawn Alert\",\n            description = \"Alert when a Great White Shark is fished up nearby.\",\n            category = \"Alerts\",\n            subcategory = \"Fishing\"\n    )\n    public static boolean gwAlert = true;\n\n    // Aliases\n\n    @CfgName(\n            name = \"Aliases\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Custom Aliases\",\n            description = \"Replaces text in chat with an alias.\",\n            category = \"Aliases\",\n            subcategory = \"Custom Aliases\"\n    )\n    public static boolean aliases = false;\n\n    @Button(\n            name = \"Custom Aliases\",\n            text = \"Click\",\n            category = \"Aliases\",\n            subcategory = \"Custom Aliases\"\n    )\n    Runnable aliasesButton = () -> mc.displayGuiScreen(new AliasesGui(1));\n\n    // Waypoints\n\n    @CfgName(\n            name = \"CrystalHollowWaypoints\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Crystal Hollows Waypoints\",\n            description = \"Shows waypoints to various places in the Crystal Hollows.\",\n            category = \"Waypoints\",\n            subcategory = \"Crystal Hollows\"\n    )\n    public static boolean crystalHollowWaypoints = false;\n\n    @Button(\n            name = \"Crystal Hollow Waypoints\",\n            text = \"Click\",\n            category = \"Waypoints\",\n            subcategory = \"Crystal Hollows\"\n    )\n    Runnable crystalHollowWaypointsButton = () -> mc.displayGuiScreen(new CrystalHollowWaypointsGui(1));\n\n    @CfgName(\n            name = \"CrystalAutoWaypoints\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Auto Waypoints\",\n            description = \"Automatically creates waypoints when you visit a special place in the Crystal Hollows.\",\n            category = \"Waypoints\",\n            subcategory = \"Crystal Hollows\"\n    )\n    public static boolean autoWaypoints = true;\n\n    @CfgName(\n            name = \"CrystalAutoPlayerWaypoints\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Auto Add Player Waypoints\",\n            description = \"Automatically adds waypoints sent from players.\",\n            category = \"Waypoints\",\n            subcategory = \"Crystal Hollows\"\n    )\n    public static boolean autoPlayerWaypoints = false;\n\n    @Switch(\n            name = \"Auto Import Waypoints\",\n            description = \"Automatically import DSM formatted waypoints from the text field when you join a Crystal Hollows lobby.\",\n            category = \"Waypoints\",\n            subcategory = \"Crystal Hollows\"\n    )\n    public static boolean autoImportWaypoints = true;\n\n    @Text(\n            name = \"Import These Waypoints\",\n            multiline = true,\n            size = OptionSize.DUAL,\n            category = \"Waypoints\",\n            subcategory = \"Crystal Hollows\"\n    )\n    public static String permaWaypoints = \"Crystal Nucleus@-512,110,512\";\n\n    @Button(\n            name = \"Copy Waypoints to Clipboard\",\n            text = \"Copy\",\n            description = \"Copies current waypoints to your clipboard in a DSM format.\",\n            category = \"Waypoints\",\n            subcategory = \"Crystal Hollows\"\n    )\n    Runnable copyWaypoints = CrystalHollowWaypoints::copyToClipboard;\n\n    @Button(\n            name = \"Import Waypoints from Clipboard\",\n            text = \"Import\",\n            description = \"Imports Skytils, DSM/SBE, or Soopy waypoints from your clipboard.\",\n            category = \"Waypoints\",\n            subcategory = \"Crystal Hollows\"\n    )\n    Runnable importWaypoints = CrystalHollowWaypoints::importWaypoints;\n\n    @Button(\n            name = \"Optimize Waypoints\",\n            text = \"Click\",\n            description = \"Optimizes the waypoint path for the minimum cycle distance.\",\n            category = \"Waypoints\",\n            subcategory = \"Crystal Hollows\"\n    )\n    Runnable optimizeCoords = () -> new Thread(CrystalHollowWaypoints::optimize).start();\n\n    @Info(\n            text = \"Run multiple times for best results.\",\n            type = InfoType.INFO,\n            category = \"Waypoints\",\n            subcategory = \"Crystal Hollows\"\n    )\n    public static boolean ignored2;\n\n    @Number(\n            name = \"Alpha\",\n            description = \"Controls pheromone importance.\",\n            min = 1, max = 100,\n            category = \"Waypoints\",\n            subcategory = \"Crystal Hollows\"\n    )\n    public static int coordAlpha = 10;\n\n    @Number(\n            name = \"Beta\",\n            description = \"Controls distance importance.\",\n            min = 1, max = 500,\n            category = \"Waypoints\",\n            subcategory = \"Crystal Hollows\"\n    )\n    public static int coordBeta = 50;\n\n    // Messages\n\n    @CfgName(\n            name = \"SceptreMessages\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Spirit Sceptre Messages\",\n            description = \"Turn off to hide Spirit Sceptre messages.\",\n            category = \"Messages\",\n            subcategory = \"General\"\n    )\n    public static boolean sceptreMessages = true;\n\n    @CfgName(\n            name = \"MidasStaffMessages\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Midas Staff Messages\",\n            description = \"Turn off to hide Midas Staff messages.\",\n            category = \"Messages\",\n            subcategory = \"General\"\n    )\n    public static boolean midasStaffMessages = true;\n\n    @CfgName(\n            name = \"ImplosionMessages\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Implosion Messages\",\n            description = \"Turn off to hide Implosion messages.\",\n            category = \"Messages\",\n            subcategory = \"General\"\n    )\n    public static boolean implosionMessages = true;\n\n    @CfgName(\n            name = \"HealMessages\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Heal Messages\",\n            description = \"Turn off to hide healing messages.\",\n            category = \"Messages\",\n            subcategory = \"General\"\n    )\n    public static boolean healMessages = true;\n\n    @CfgName(\n            name = \"CooldownMessages\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Cooldown Messages\",\n            description = \"Turn off to hide cooldown messages.\",\n            category = \"Messages\",\n            subcategory = \"General\"\n    )\n    public static boolean cooldownMessages = true;\n\n    @CfgName(\n            name = \"ManaMessages\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Mana Messages\",\n            description = \"Turn off to hide out of mana messages.\",\n            category = \"Messages\",\n            subcategory = \"General\"\n    )\n    public static boolean manaMessages = true;\n\n    @CfgName(\n            name = \"KillComboMessages\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Kill Combo Messages\",\n            description = \"Turn off to hide kill combo messages.\",\n            category = \"Messages\",\n            subcategory = \"General\"\n    )\n    public static boolean killComboMessages = true;\n\n    // Music\n\n    @Button(\n            name = \"Instructions\",\n            description = \"Click to learn how to use custom music.\",\n            text = \"Click\",\n            category = \"Music\"\n    )\n    Runnable musicInstructions = () -> {\n        try {\n            Desktop.getDesktop().browse(new URI(\"https://github.com/bowser0000/SkyblockMod/blob/master/README.md#custom-music\"));\n        } catch (IOException | URISyntaxException ex) {\n            Notifications.INSTANCE.send(\"Error\", \"Error opening web page.\");\n            ex.printStackTrace();\n        }\n    };\n\n    @Button(\n            name = \"Reload Custom Music\",\n            text = \"Click\",\n            category = \"Music\",\n            subcategory = \"Options\"\n    )\n    Runnable reloadMusic = () -> {\n        CustomMusic.init(DankersSkyblockMod.configDirectory);\n        Notifications.INSTANCE.send(\"Success\", \"Reloaded custom music.\");\n    };\n\n    @CfgName(\n            name = \"DisableHypixelMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Disable Hypixel Music\",\n            description = \"Disable the noteblock music Hypixel plays in certain areas when custom music is playing.\\nThis can be turned off manually in Skyblock Menu -> Settings -> Personal -> Sounds -> Play Music\",\n            category = \"Music\",\n            subcategory = \"Options\"\n    )\n    public static boolean disableHypixelMusic = true;\n\n    @CfgName(\n            name = \"DungeonBossMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Dungeon Boss Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean dungeonBossMusic = false;\n\n    @CfgName(\n            name = \"DungeonBossVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Dungeon Boss Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int dungeonBossVolume = 50;\n\n    @CfgName(\n            name = \"Phase2Volume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"F7 Phase 2 Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int phase2Volume = 50;\n\n    @CfgName(\n            name = \"Phase3Volume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"F7 Phase 3 Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int phase3Volume = 50;\n\n    @CfgName(\n            name = \"Phase4Volume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"F7 Phase 4 Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int phase4Volume = 50;\n\n    @CfgName(\n            name = \"Phase5Volume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"F7 Phase 5 Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int phase5Volume = 50;\n\n    @CfgName(\n            name = \"BloodRoomMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Blood Room Open Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean bloodRoomMusic = false;\n\n    @CfgName(\n            name = \"BloodRoomVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Blood Room Open Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int bloodRoomVolume = 50;\n\n    @CfgName(\n            name = \"DungeonMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Dungeon Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean dungeonMusic = false;\n\n    @CfgName(\n            name = \"DungeonVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Dungeon Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int dungeonVolume = 50;\n\n    @CfgName(\n            name = \"HubMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Hub Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean hubMusic = false;\n\n    @CfgName(\n            name = \"HubVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Hub Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int hubVolume = 50;\n\n    @CfgName(\n            name = \"IslandMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Private Island Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean islandMusic = false;\n\n    @CfgName(\n            name = \"IslandVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Private Island Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int islandVolume = 50;\n\n    @CfgName(\n            name = \"DungeonHubMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Dungeon Hub Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean dungeonHubMusic = false;\n\n    @CfgName(\n            name = \"DungeonHubVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Dungeon Hub Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int dungeonHubVolume = 50;\n\n    @CfgName(\n            name = \"FarmingIslandsMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Farming Islands Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean farmingIslandsMusic = false;\n\n    @CfgName(\n            name = \"FarmingIslandsVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Farming Islands Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int farmingIslandsVolume = 50;\n\n    @Switch(\n            name = \"Garden Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean gardenMusic = false;\n\n    @Slider(\n            name = \"Garden Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int gardenVolume = 50;\n\n    @CfgName(\n            name = \"GoldMineMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Gold Mine Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean goldMineMusic = false;\n\n    @CfgName(\n            name = \"GoldMineVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Gold Mine Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int goldMineVolume = 50;\n\n    @CfgName(\n            name = \"DeepCavernsMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Deep Caverns Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean deepCavernsMusic = false;\n\n    @CfgName(\n            name = \"DeepCavernsVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Deep Caverns Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int deepCavernsVolume = 50;\n\n    @CfgName(\n            name = \"DwarvenMinesMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Dwarven Mines Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean dwarvenMinesMusic = false;\n\n    @CfgName(\n            name = \"DwarvenMinesVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Dwarven Mines Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int dwarvenMinesVolume = 50;\n\n    @CfgName(\n            name = \"CrystalHollowsMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Crystal Hollows Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean crystalHollowsMusic = false;\n\n    @CfgName(\n            name = \"CrystalHollowsVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Crystal Hollows Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int crystalHollowsVolume = 50;\n\n    @CfgName(\n            name = \"SpidersDenMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Spider's Den Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean spidersDenMusic = false;\n\n    @CfgName(\n            name = \"SpidersDenVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Spider's Den Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int spidersDenVolume = 50;\n\n    @CfgName(\n            name = \"CrimsonIsleMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Crimson Isle Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean crimsonIsleMusic = false;\n\n    @CfgName(\n            name = \"CrimsonIsleVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Crimson Isle Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int crimsonIsleVolume = 50;\n\n    @Switch(\n            name = \"Kuudra Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean kuudraMusic = false;\n\n    @Slider(\n            name = \"Kuudra Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int kuudraVolume = 50;\n\n    @CfgName(\n            name = \"EndMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"End Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean endMusic = false;\n\n    @CfgName(\n            name = \"EndVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"End Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int endVolume = 50;\n\n    @CfgName(\n            name = \"ParkMusic\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Park Music\",\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static boolean parkMusic = false;\n\n    @CfgName(\n            name = \"ParkVolume\",\n            category = \"music\"\n    )\n    @Slider(\n            name = \"Park Music Volume\",\n            min = 0, max = 100,\n            category = \"Music\",\n            subcategory = \"Music\"\n    )\n    public static int parkVolume = 50;\n\n    // Colors\n    /* List of colours, copy paste\n    {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n    */\n\n    @Dropdown(\n            name = \"Main Text Color\",\n            options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"},\n            category = \"Colors\",\n            subcategory = \"Text\"\n    )\n    public static int mainColour = 10;\n\n    @Dropdown(\n            name = \"Secondary Text Color\",\n            options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"},\n            category = \"Colors\",\n            subcategory = \"Text\"\n    )\n    public static int secondaryColour = 2;\n\n    @Dropdown(\n            name = \"Delimiter Text Color\",\n            description = \"Color of the line shown above and below command outputs. Strike-through is automatically added.\",\n            options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"},\n            category = \"Colors\",\n            subcategory = \"Text\"\n    )\n    public static int delimiterColour = 11;\n\n    @Dropdown(\n            name = \"Error Text Color\",\n            options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"},\n            category = \"Colors\",\n            subcategory = \"Text\"\n    )\n    public static int errorColour = 12;\n\n    @Dropdown(\n            name = \"Type Text Color\",\n            description = \"Used in API commands to color a stat.\",\n            options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"},\n            category = \"Colors\",\n            subcategory = \"Text\"\n    )\n    public static int typeColour = 10;\n\n    @Dropdown(\n            name = \"Value Text Color\",\n            description = \"Used in API commands to color a stat value.\",\n            options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"},\n            category = \"Colors\",\n            subcategory = \"Text\"\n    )\n    public static int valueColour = 2;\n\n    @Dropdown(\n            name = \"Skill Average Text Color\",\n            description = \"Used in API commands to color the skill average number.\",\n            options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"},\n            category = \"Colors\",\n            subcategory = \"Text\"\n    )\n    public static int skillAverageColour = 6;\n\n    @Color(\n            name = \"Pet Levels 1 to 9 Color\",\n            category = \"Colors\",\n            subcategory = \"Pet Highlight Colors\"\n    )\n    public static OneColor pet1To9Colour = new OneColor(153, 153, 153, 191); // Grey\n\n    @Color(\n            name = \"Pet Levels 10 to 19 Color\",\n            category = \"Colors\",\n            subcategory = \"Pet Highlight Colors\"\n    )\n    public static OneColor pet10To19Colour = new OneColor(214, 36, 64, 191); // Red\n\n    @Color(\n            name = \"Pet Levels 20 to 29 Color\",\n            category = \"Colors\",\n            subcategory = \"Pet Highlight Colors\"\n    )\n    public static OneColor pet20To29Colour = new OneColor(239, 82, 48, 191); // Orange\n\n    @Color(\n            name = \"Pet Levels 30 to 39 Color\",\n            category = \"Colors\",\n            subcategory = \"Pet Highlight Colors\"\n    )\n    public static OneColor pet30To39Colour = new OneColor(17, 60, 242, 191); // Dark Blue\n\n    @Color(\n            name = \"Pet Levels 40 to 49 Color\",\n            category = \"Colors\",\n            subcategory = \"Pet Highlight Colors\"\n    )\n    public static OneColor pet40To49Colour = new OneColor(14, 172, 53, 191); // Green\n\n    @Color(\n            name = \"Pet Levels 50 to 59 Color\",\n            category = \"Colors\",\n            subcategory = \"Pet Highlight Colors\"\n    )\n    public static OneColor pet50To59Colour = new OneColor(0, 138, 216, 191); // Light Blue\n\n    @Color(\n            name = \"Pet Levels 60 to 69 Color\",\n            category = \"Colors\",\n            subcategory = \"Pet Highlight Colors\"\n    )\n    public static OneColor pet60To69Colour = new OneColor(126, 79, 198, 191); // Purple\n\n    @Color(\n            name = \"Pet Levels 70 to 79 Color\",\n            category = \"Colors\",\n            subcategory = \"Pet Highlight Colors\"\n    )\n    public static OneColor pet70To79Colour = new OneColor(214, 79, 200, 191); // Pink\n\n    @Color(\n            name = \"Pet Levels 80 to 89 Color\",\n            category = \"Colors\",\n            subcategory = \"Pet Highlight Colors\"\n    )\n    public static OneColor pet80To89Colour = new OneColor(92, 31, 53, 191); // idk weird magenta\n\n    @Color(\n            name = \"Pet Levels 90 to 99 Color\",\n            category = \"Colors\",\n            subcategory = \"Pet Highlight Colors\"\n    )\n    public static OneColor pet90To99Colour = new OneColor(158, 121, 78, 191); // Brown\n\n    @Color(\n            name = \"Pet Level 100 Color\",\n            category = \"Colors\",\n            subcategory = \"Pet Highlight Colors\"\n    )\n    public static OneColor pet100Colour = new OneColor(242, 210, 73, 191); // Gold\n\n    // Keybinds\n\n    @KeyBind(\n            name = \"Get Pearl From Sack\",\n            category = \"Keybinds\",\n            subcategory = \"General\"\n    )\n    public static OneKeyBind pearlKey = new OneKeyBind();\n\n    @Number(\n            name = \"Amount of Pearls\",\n            description = \"Amount of pearls to top up to.\",\n            min = 1, max = 560,\n            category = \"Keybinds\",\n            subcategory = \"General\"\n    )\n    public static int pearlAmount = 16;\n\n    @KeyBind(\n            name = \"Open Maddox Menu\",\n            category = \"Keybinds\",\n            subcategory = \"General\"\n    )\n    public static OneKeyBind maddoxKey = new OneKeyBind();\n\n    @KeyBind(\n            name = \"Regular Ability\",\n            category = \"Keybinds\",\n            subcategory = \"Dungeons\"\n    )\n    public static OneKeyBind abilityKey = new OneKeyBind();\n\n    @KeyBind(\n            name = \"Create Waypoint\",\n            category = \"Keybinds\",\n            subcategory = \"Waypoints\"\n    )\n    public static OneKeyBind waypointKey = new OneKeyBind();\n\n    @KeyBind(\n            name = \"Start/Stop Skill Tracker\",\n            category = \"Keybinds\",\n            subcategory = \"Trackers\"\n    )\n    public static OneKeyBind skillTrackerKey = new OneKeyBind();\n\n    @KeyBind(\n            name = \"Start/Stop Powder Tracker\",\n            category = \"Keybinds\",\n            subcategory = \"Trackers\"\n    )\n    public static OneKeyBind powderTrackerKey = new OneKeyBind();\n\n    @KeyBind(\n            name = \"Disable Mouse Movement\",\n            category = \"Keybinds\",\n            subcategory = \"Farming\"\n    )\n    public static OneKeyBind disableMouse = new OneKeyBind();\n\n    @Info(\n            text = \"If this gets stuck, change your sensitivity in controls.\",\n            type = InfoType.INFO,\n            category = \"Keybinds\",\n            subcategory = \"Farming\"\n    )\n    public static boolean ignored3;\n\n    @KeyBind(\n            name = \"Disable Moving Forwards/Back\",\n            category = \"Keybinds\",\n            subcategory = \"Farming\"\n    )\n    public static OneKeyBind disableWS = new OneKeyBind();\n\n    @KeyBind(\n            name = \"Disable Moving Left/Right\",\n            category = \"Keybinds\",\n            subcategory = \"Farming\"\n    )\n    public static OneKeyBind disableAD = new OneKeyBind();\n\n    @Switch(\n            name = \"Debug Messages\",\n            description = \"Enable debug messages.\",\n            size = OptionSize.DUAL,\n            category = \"Debug\",\n            subcategory = \"Debugging\"\n    )\n    public static boolean debug = false;\n\n    @Switch(\n            name = \"Packets Received\",\n            description = \"Show packets being received.\",\n            category = \"Debug\",\n            subcategory = \"Debugging\"\n    )\n    public static boolean debugPacketsIn = false;\n\n    @Switch(\n            name = \"Packets Sent\",\n            description = \"Show packets being sent.\",\n            category = \"Debug\",\n            subcategory = \"Debugging\"\n    )\n    public static boolean debugPacketsOut = false;\n\n    @Switch(\n            name = \"Messages Sent\",\n            description = \"Show messages/commands being sent.\",\n            category = \"Debug\",\n            subcategory = \"Debugging\"\n    )\n    public static boolean debugChat = false;\n\n    @Switch(\n            name = \"Fix /locraw Spam\",\n            description = \"Prevents /locraw from being sent in succession, fixing commands being sent too fast.\",\n            category = \"Debug\",\n            subcategory = \"Fixes\"\n    )\n    public static boolean fixLocraw = false;\n\n    @Switch(\n            name = \"Fix S04PacketEntityEquipment\",\n            description = \"Fixes S04PacketEntityEquipment packet incorrectly setting armor on Forge clients.\",\n            category = \"Debug\",\n            subcategory = \"Fixes\"\n    )\n    public static boolean spiritBootsFix = true;\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/containers/GuiChestDynamic.java",
    "content": "package me.Danker.containers;\n\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.gui.inventory.GuiContainer;\nimport net.minecraft.client.renderer.GlStateManager;\nimport net.minecraft.inventory.ContainerChest;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraft.util.ResourceLocation;\n\n// Hopefully this is dyanmic, only tested with 63 slots\npublic class GuiChestDynamic extends GuiContainer {\n    private final ResourceLocation CHEST_GUI_TEXTURE;\n    private IInventory upperChestInventory;\n    private IInventory lowerChestInventory;\n    private int inventoryRows;\n\n    public GuiChestDynamic(IInventory upperInv, IInventory lowerInv, ResourceLocation texture)\n    {\n        super(new ContainerChest(upperInv, lowerInv, Minecraft.getMinecraft().thePlayer));\n        this.upperChestInventory = upperInv;\n        this.lowerChestInventory = lowerInv;\n        this.allowUserInput = false;\n        this.inventoryRows = lowerInv.getSizeInventory() / 9;\n        int i = this.inventoryRows * 37;\n        int j = i - this.inventoryRows * 18;\n        this.ySize = j + this.inventoryRows * 18;\n        this.CHEST_GUI_TEXTURE = texture;\n    }\n\n    protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY)\n    {\n        this.fontRendererObj.drawString(this.lowerChestInventory.getDisplayName().getUnformattedText(), 8, 6, 4210752);\n        this.fontRendererObj.drawString(this.upperChestInventory.getDisplayName().getUnformattedText(), 8, this.ySize - this.inventoryRows * 16 - 1, 4210752);\n    }\n\n    protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)\n    {\n        GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);\n        this.mc.getTextureManager().bindTexture(CHEST_GUI_TEXTURE);\n        int i = (this.width - this.xSize) / 2;\n        int j = (this.height - this.ySize) / 2;\n        this.drawTexturedModalRect(i, j, 0, 0, this.xSize, this.inventoryRows * 18 + 17);\n        this.drawTexturedModalRect(i, j + this.inventoryRows * 18 + 17, 0, this.inventoryRows * 18 + 18, this.xSize, this.inventoryRows * 16);\n    }\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/events/ChestSlotClickedEvent.java",
    "content": "package me.Danker.events;\n\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.item.ItemStack;\nimport net.minecraftforge.fml.common.eventhandler.Cancelable;\nimport net.minecraftforge.fml.common.eventhandler.Event;\n\n@Cancelable\npublic class ChestSlotClickedEvent extends Event {\n    public final GuiChest chest;\n    public final IInventory inventory;\n    public final String inventoryName;\n    public final Slot slot;\n    public final ItemStack item;\n\n    public ChestSlotClickedEvent(GuiChest chest, IInventory inventory, String inventoryName, Slot slot, ItemStack item) {\n        this.chest = chest;\n        this.inventory = inventory;\n        this.inventoryName = inventoryName;\n        this.slot = slot;\n        this.item = item;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/events/GuiChestBackgroundDrawnEvent.java",
    "content": "package me.Danker.events;\n\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.inventory.Slot;\nimport net.minecraftforge.fml.common.eventhandler.Event;\n\nimport java.util.List;\n\npublic class GuiChestBackgroundDrawnEvent extends Event {\n    public final GuiChest chest;\n    public final String displayName;\n    public final int chestSize;\n    public final List<Slot> slots;\n\n    public GuiChestBackgroundDrawnEvent(GuiChest chest, String displayName, int chestSize, List<Slot> slots) {\n        this.chest = chest;\n        this.displayName = displayName;\n        this.chestSize = chestSize;\n        this.slots = slots;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/events/ModInitEvent.java",
    "content": "package me.Danker.events;\n\nimport net.minecraftforge.fml.common.eventhandler.Event;\n\npublic class ModInitEvent extends Event {\n\n    public final String configDirectory;\n\n    public ModInitEvent(String configDirectory) {\n        this.configDirectory = configDirectory;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/events/PacketReadEvent.java",
    "content": "package me.Danker.events;\n\nimport net.minecraft.network.Packet;\nimport net.minecraftforge.fml.common.eventhandler.Cancelable;\nimport net.minecraftforge.fml.common.eventhandler.Event;\n\n@Cancelable\npublic class PacketReadEvent extends Event {\n\n    public Packet packet;\n\n    public PacketReadEvent(Packet packet) {\n        this.packet = packet;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/events/PacketWriteEvent.java",
    "content": "package me.Danker.events;\n\nimport net.minecraft.network.Packet;\nimport net.minecraftforge.fml.common.eventhandler.Cancelable;\nimport net.minecraftforge.fml.common.eventhandler.Event;\n\n@Cancelable\npublic class PacketWriteEvent extends Event {\n\n    public Packet packet;\n\n    public PacketWriteEvent(Packet packet) {\n        this.packet = packet;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/events/PostConfigInitEvent.java",
    "content": "package me.Danker.events;\n\nimport net.minecraftforge.fml.common.eventhandler.Event;\n\npublic class PostConfigInitEvent extends Event {\n\n    public final String configDirectory;\n\n    public PostConfigInitEvent(String configDirectory) {\n        this.configDirectory = configDirectory;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/events/RenderOverlayEvent.java",
    "content": "package me.Danker.events;\n\nimport net.minecraftforge.fml.common.eventhandler.Event;\n\npublic class RenderOverlayEvent extends Event {\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/events/SlayerLootDropEvent.java",
    "content": "package me.Danker.events;\n\nimport net.minecraftforge.fml.common.eventhandler.Event;\n\npublic class SlayerLootDropEvent extends Event {\n\n    public final String drop;\n    public final int amount;\n\n    public SlayerLootDropEvent(String drop, int amount) {\n        this.drop = drop;\n        this.amount = amount;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/AbilityCooldowns.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.inventory.ContainerChest;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class AbilityCooldowns {\n\n    public static List<Ability> cooldowns = new ArrayList<>();\n    static double mageReduction = 0D;\n\n    @SubscribeEvent(priority = EventPriority.LOW)\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!Utils.inSkyblock || !ModConfig.abilityCooldownHud.isEnabled()) return;\n\n        if (event.type == 2) {\n            String[] actionBarSections = StringUtils.stripControlCodes(event.message.getUnformattedText()).split(\" {3,}\");\n\n            for (String section : actionBarSections) {\n                if (section.charAt(0) == '-' && section.contains(\"(\") && section.charAt(section.length() - 1) == ')') {\n                    String ability = section.substring(section.indexOf(\"(\") + 1, section.length() - 1);\n\n                    for (Ability cooldown : cooldowns) {\n                        if (cooldown.ability.equals(ability)) return;\n                    }\n\n                    cooldowns.add(new Ability(ability, Utils.getCooldownFromAbility(ability) * (1D - mageReduction)));\n                }\n            }\n        } else {\n            String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n            if (Utils.isInDungeons() && message.startsWith(\"[Mage] Cooldown Reduction \")) {\n                mageReduction = Integer.parseInt(message.substring(message.indexOf(\">\") + 2, message.length() - 1)) / 100D;\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n        if (mc.currentScreen instanceof GuiChest) {\n            if (player == null) return;\n            ContainerChest chest = (ContainerChest) player.openContainer;\n            List<Slot> invSlots = ((GuiChest) mc.currentScreen).inventorySlots.inventorySlots;\n            String chestName = chest.getLowerChestInventory().getDisplayName().getUnformattedText().trim();\n\n            if (ModConfig.abilityCooldownHud.isEnabled() && Utils.isInDungeons() && chestName.startsWith(\"Catacombs - \")) {\n                ItemStack mage = invSlots.get(30).getStack();\n                if (mage == null || mage.getDisplayName() == null) return;\n                if (mage.isItemEnchanted()) {\n                    String display = mage.getDisplayName();\n                    mageReduction = Utils.getCooldownReductionFromLevel(Integer.parseInt(display.substring(display.indexOf(\" \") + 1, display.indexOf(\"]\"))));\n                } else {\n                    mageReduction = 0D;\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        cooldowns.clear();\n        mageReduction = 0D;\n    }\n\n    public static class Ability {\n\n        public final String ability;\n        private final long cooldown;\n\n        public Ability(String ability, double cooldown) {\n            this.ability = ability;\n            this.cooldown = (long) (System.currentTimeMillis() + cooldown * 1000L);\n        }\n\n        public String getTimer() {\n            return EnumChatFormatting.GREEN + ability + \": \" + EnumChatFormatting.YELLOW + String.format(\"%.3f\", getCooldown()) + \"s\";\n        }\n\n        public double getCooldown() {\n            return (cooldown - System.currentTimeMillis()) / 1000D;\n        }\n\n    }\n\n    public static class AbilityCooldownHud extends Hud {\n\n        @Exclude\n        String exampleText = EnumChatFormatting.GREEN + \"Spirit Glide: \" + EnumChatFormatting.YELLOW + \"32.734s\\n\" +\n                EnumChatFormatting.GREEN + \"Parley: \" + EnumChatFormatting.YELLOW + \"2.652s\\n\" +\n                EnumChatFormatting.GREEN + \"Ice Spray: \" + EnumChatFormatting.YELLOW + \"1.429s\";\n\n        @Override\n        protected void preRender(boolean example) {\n            if (enabled && Utils.inSkyblock) {\n                cooldowns.removeIf(ability -> (ability.getCooldown() <= 0));\n            }\n        }\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            if (example) {\n                TextRenderer.drawHUDText(exampleText, x, y, scale);\n                return;\n            }\n\n            if (enabled && Utils.inSkyblock && cooldowns.size() > 0) {\n                TextRenderer.drawHUDText(getText(), x, y, scale);\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return RenderUtils.getWidthFromText(example ? exampleText : getText()) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return RenderUtils.getHeightFromText(example ? exampleText : getText()) * scale;\n        }\n\n        String getText() {\n            StringBuilder sb = new StringBuilder();\n\n            for (Ability ability : cooldowns) {\n                sb.append(ability.getTimer()).append(\"\\n\");\n            }\n\n            return sb.toString();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/Alerts.java",
    "content": "package me.Danker.features;\n\nimport com.google.gson.GsonBuilder;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ModInitEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.awt.*;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class Alerts {\n\n    public static List<Alert> alerts = new ArrayList<>();\n    public static HashMap<Alert, Pattern> patterns = new HashMap<>();\n    public static String configFile;\n\n    @SubscribeEvent\n    public void init(ModInitEvent event) {\n        configFile = event.configDirectory + \"/dsm/dsmalerts.json\";\n    }\n\n    public Pattern getRegexForAlert(Alert alert) {\n        return patterns.computeIfAbsent(alert, it -> Pattern.compile(it.message));\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!ModConfig.alerts || event.type == 2) return;\n\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        for (Alert alert : alerts) {\n            if (!alert.toggled) continue;\n\n            boolean location;\n            switch (alert.location) {\n                case \"Skyblock\":\n                    location = Utils.inSkyblock;\n                    break;\n                case \"Dungeons\":\n                    location = Utils.isInDungeons();\n                    break;\n                default:\n                    location = true;\n            }\n            if (!location) continue;\n\n            if (alert.mode.equals(\"Regex\")) {\n                Matcher matcher = getRegexForAlert(alert).matcher(message);\n                if (matcher.matches()) {\n                    matcher.reset();\n                    String alertText = alert.alert;\n\n                    int i = 0;\n                    while (matcher.find()) {\n                        for (int j = 0; j <= matcher.groupCount(); j++) {\n                            alertText = alertText.replace(\"$$\" + i + \"$$\", matcher.group(j));\n                            i++;\n                        }\n                    }\n\n                    Utils.createTitle(EnumChatFormatting.RED + alertText.replace(\"&\", \"§\"), 2);\n                    if (alert.desktop) Utils.desktopNotification(\"Alert\", alertText, message, TrayIcon.MessageType.INFO);\n\n                    return;\n                }\n            } else {\n                boolean trigger;\n                switch (alert.mode) {\n                    case \"Starts With\":\n                        trigger = message.startsWith(alert.message);\n                        break;\n                    case \"Contains\":\n                        trigger = message.contains(alert.message);\n                        break;\n                    case \"Ends With\":\n                        trigger = message.endsWith(alert.message);\n                        break;\n                    default:\n                        continue;\n                }\n\n                if (trigger) {\n                    Utils.createTitle(EnumChatFormatting.RED + alert.alert.replace(\"&\", \"§\"), 2);\n                    if (alert.desktop) Utils.desktopNotification(\"Alert\", alert.alert, message, TrayIcon.MessageType.INFO);\n\n                    return;\n                }\n            }\n        }\n    }\n\n    public static void save() {\n        for (Alert alert : alerts) {\n            if (alert.mode.equals(\"Regex\")) {\n                Pattern pattern = Pattern.compile(alert.message);\n                patterns.put(alert, pattern);\n            }\n        }\n\n        try (FileWriter writer = new FileWriter(configFile)) {\n            new GsonBuilder().create().toJson(alerts, writer);\n            writer.flush();\n        } catch (IOException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    public static class Alert {\n\n        public String mode;\n        public String location;\n        public String message;\n        public String alert;\n        public boolean desktop;\n        public boolean toggled;\n\n        public Alert(String mode, String location, String message, String alert, boolean desktop, boolean toggled) {\n            this.mode = mode;\n            this.location = location;\n            this.message = message;\n            this.alert = alert;\n            this.desktop = desktop;\n            this.toggled = toggled;\n        }\n\n        public void toggle() {\n            toggled = !toggled;\n        }\n\n        public void toggleDesktop() {\n            desktop = !desktop;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/AnnounceVanquishers.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.GuiNewChat;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class AnnounceVanquishers {\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (message.contains(\":\")) return;\n\n        if (ModConfig.announceVanqs && Utils.currentLocation == Location.CRIMSON_ISLE) {\n            if (message.contains(\"A Vanquisher is spawning nearby!\")) {\n                Minecraft mc = Minecraft.getMinecraft();\n                EntityPlayerSP player = mc.thePlayer;\n                GuiNewChat chat = mc.ingameGUI.getChatGUI();\n\n                String vanq = \"Vanquisher spawned! \" + (int) player.posX + \" \" + (int) player.posY + \" \" + (int) player.posZ;\n                player.sendChatMessage(vanq);\n                chat.addToSentMessages(vanq);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/ArachneESP.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.util.AxisAlignedBB;\nimport net.minecraft.util.StringUtils;\nimport net.minecraft.world.World;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.List;\n\n/**\n * @author RabbitType99\n */\n\npublic class ArachneESP {\n\n    static Entity arachne = null;\n    static boolean arachneActive = true;\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        arachne = null;\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (Utils.currentLocation != Location.SPIDERS_DEN) return;\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n        if (message.contains(\"Something is awakening\")){\n            arachneActive = true;\n            World world = Minecraft.getMinecraft().theWorld;\n            List<Entity> entities = world.getLoadedEntityList();\n            for (Entity e : entities) {\n                if (e.getName().contains(\"Arachne\") && !e.getName().contains(\"Arachne's Brood\")) {\n                    arachne = e;\n                }\n            }\n        }\n        if (message.contains(\"ARACHNE DOWN!\")) {\n            arachneActive = false;\n            arachne = null;\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (arachne != null) {\n            if (arachneActive && ModConfig.highlightArachne) {\n                AxisAlignedBB aabb = new AxisAlignedBB(arachne.posX - 0.75, arachne.posY - 1, arachne.posZ - 0.75, arachne.posX + 0.75, arachne.posY, arachne.posZ + 0.75);\n                RenderUtils.draw3DBox(aabb, ModConfig.arachneBoxColour.getRGB(), event.partialTicks);\n            }\n        }\n    }\n\n}\n\n"
  },
  {
    "path": "src/main/java/me/Danker/features/AutoAcceptReparty.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class AutoAcceptReparty {\n\n    String partyLeader = null;\n    long lastDisband = 0;\n\n    @SubscribeEvent(receiveCanceled = true)\n    public void onChat(ClientChatReceivedEvent event) {\n\n        if (ModConfig.autoAcceptReparty) {\n            String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n            if (message.contains(\":\")) return;\n\n            String[] split = message.split(\"\\\\s\");\n\n            if (message.contains(\"has disbanded the party!\")) {\n                lastDisband = System.currentTimeMillis() / 1000;\n                partyLeader = split[0].contains(\"[\") ? split[1] : split[0];\n            } else if (message.contains(\"has invited you to join their party!\")) {\n                String inviter = split[1].contains(\"[\") ? split[2] : split[1];\n                if (inviter.equals(partyLeader) && System.currentTimeMillis() / 1000 - lastDisband <= 120) {\n                    Minecraft.getMinecraft().thePlayer.sendChatMessage(\"/party accept \" + partyLeader);\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/AutoDisplay.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.features.loot.LootDisplay;\nimport me.Danker.handlers.ScoreboardHandler;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.init.Items;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.world.World;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.List;\n\npublic class AutoDisplay {\n\n    public static String display = \"Off\";\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        World world = mc.theWorld;\n        EntityPlayerSP player = mc.thePlayer;\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            if (LootDisplay.autoDisplay && world != null && player != null) {\n                List<String> scoreboard = ScoreboardHandler.getSidebarLines();\n                boolean found = false;\n                for (String s : scoreboard) {\n                    String sCleaned = ScoreboardHandler.cleanSB(s);\n                    if (sCleaned.contains(\"Sven Packmaster\")) {\n                        display = \"Wolf Slayer\";\n                        found = true;\n                    } else if (sCleaned.contains(\"Tarantula Broodfather\")) {\n                        display = \"Spider Slayer\";\n                        found = true;\n                    } else if (sCleaned.contains(\"Revenant Horror\")) {\n                        display = \"Zombie Slayer\";\n                        found = true;\n                    } else if (sCleaned.contains(\"Voidgloom Seraph\")) {\n                        display = \"Enderman Slayer\";\n                        found = true;\n                    } else if (sCleaned.contains(\"Inferno Demonlord\")) {\n                        display = \"Blaze Slayer\";\n                        found = true;\n                    } else if (sCleaned.contains(\"The Mist\")){\n                        display = \"Ghost\";\n                        found = true;\n                    } else if (Utils.isInDungeons()) {\n                        switch (Utils.currentFloor) {\n                            case F1:\n                                display = \"Floor 1\";\n                                break;\n                            case F2:\n                                display = \"Floor 2\";\n                                break;\n                            case F3:\n                                display = \"Floor 3\";\n                                break;\n                            case F4:\n                                display = \"Floor 4\";\n                                break;\n                            case F5:\n                                display = \"Floor 5\";\n                                break;\n                            case F6:\n                                display = \"Floor 6\";\n                                break;\n                            case F7:\n                                display = \"Floor 7\";\n                                break;\n                            case M1:\n                            case M2:\n                            case M3:\n                            case M4:\n                            case M5:\n                            case M6:\n                            case M7:\n                                display = \"Master Mode\";\n                                break;\n                        }\n                        found = true;\n                    }\n                }\n                for (int i = 0; i < 8; i++) {\n                    ItemStack hotbarItem = player.inventory.getStackInSlot(i);\n                    if (hotbarItem == null) continue;\n                    if (hotbarItem.getDisplayName().contains(\"Ancestral Spade\")) {\n                        display = \"Mythological\";\n                        found = true;\n                        break;\n                    } else if (hotbarItem.getItem() == Items.fishing_rod) {\n                        List<String> lore = hotbarItem.getTooltip(player, mc.gameSettings.advancedItemTooltips);\n                        for (int j = lore.size() - 1; j >= 0; j--) { // reverse\n                            if (lore.get(j).contains(\"FISHING ROD\")) {\n                                if (Utils.currentLocation == Location.CRIMSON_ISLE) {\n                                    display = \"Lava Fishing\";\n                                } else if (Utils.currentLocation == Location.JERRY_WORKSHOP) {\n                                    display = \"Winter Fishing\";\n                                } else {\n                                    display = \"Fishing\";\n                                }\n                                found = true;\n                                break;\n                            }\n                        }\n                    }\n                }\n                if (!found) display = \"Off\";\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/AutoJoinSkyblock.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.network.FMLNetworkEvent;\n\npublic class AutoJoinSkyblock {\n\n    static boolean joinedServer = false;\n\n    @SubscribeEvent\n    public void onConnect(FMLNetworkEvent.ClientConnectedToServerEvent event) {\n        if (ModConfig.autoJoinSkyblock && !joinedServer) {\n            joinedServer = true;\n            new Thread(() -> {\n                EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;\n\n                try {\n                    while (player == null) {\n                        Thread.sleep(100);\n                        player = Minecraft.getMinecraft().thePlayer;\n                    }\n                    Thread.sleep(1000);\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n\n                if (Utils.isOnHypixel()) player.sendChatMessage(\"/play sb\");\n            }).start();\n        }\n    }\n\n    @SubscribeEvent\n    public void onDisconnect(FMLNetworkEvent.ClientDisconnectionFromServerEvent event) {\n        joinedServer = false;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/AutoSwapToPickBlock.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.client.settings.GameSettings;\nimport net.minecraft.inventory.Container;\nimport net.minecraft.inventory.ContainerChest;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraftforge.client.event.GuiOpenEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class AutoSwapToPickBlock {\n\n    static int pickBlockBind;\n    static boolean pickBlockBindSwapped = false;\n\n    @SubscribeEvent\n    public void onGuiOpen(GuiOpenEvent event) {\n        if (!ModConfig.swapToPickBlock || !Utils.inSkyblock) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        GameSettings gameSettings = mc.gameSettings;\n        if (event.gui instanceof GuiChest) {\n            Container containerChest = ((GuiChest) event.gui).inventorySlots;\n            if (containerChest instanceof ContainerChest) {\n                IInventory inventory = ((ContainerChest) containerChest).getLowerChestInventory();\n                String inventoryName = inventory.getDisplayName().getUnformattedText();\n\n                if (inventoryName.startsWith(\"Chronomatron (\") || inventoryName.startsWith(\"Superpairs (\") || inventoryName.startsWith(\"Ultrasequencer (\") || inventoryName.startsWith(\"What starts with:\") || inventoryName.startsWith(\"Select all the\") || inventoryName.startsWith(\"Change all to same color!\") || inventoryName.startsWith(\"Correct all the panes!\") || inventoryName.startsWith(\"Click in order!\") || inventoryName.startsWith(\"Click the button on time!\") || inventoryName.startsWith(\"Harp -\")) {\n                    if (!pickBlockBindSwapped) {\n                        pickBlockBind = gameSettings.keyBindPickBlock.getKeyCode();\n                        gameSettings.keyBindPickBlock.setKeyCode(-100);\n                        pickBlockBindSwapped = true;\n                    }\n                } else {\n                    if (pickBlockBindSwapped) {\n                        gameSettings.keyBindPickBlock.setKeyCode(pickBlockBind);\n                        pickBlockBindSwapped = false;\n                    }\n                }\n            }\n        } else {\n            if (pickBlockBindSwapped) {\n                gameSettings.keyBindPickBlock.setKeyCode(pickBlockBind);\n                pickBlockBindSwapped = false;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/BazaarTimeToFill.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ChestSlotClickedEvent;\nimport me.Danker.events.GuiChestBackgroundDrawnEvent;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.inventory.ContainerChest;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.List;\n\npublic class BazaarTimeToFill {\n\n    static double lastInstaBuys = -1;\n    static double lastInstaSells = -1;\n    String textToDisplay;\n\n    @SubscribeEvent\n    public void onSlotClick(ChestSlotClickedEvent event) {\n        if (!ModConfig.bazaarTimeToFill) return;\n\n        if (event.inventoryName.contains(\" ➜ \") && event.item != null) {\n            if (event.slot.slotNumber - (event.chest.inventorySlots.inventorySlots.size() - 36) >= 0) {\n                // clicked item in inventory\n                lastInstaBuys = -1;\n                lastInstaSells = -1;\n                return;\n            }\n\n            List<String> tooltip = event.item.getTooltip(Minecraft.getMinecraft().thePlayer, false);\n            if (tooltip.size() >= 12) {\n                for (String line : tooltip) {\n                    if (line.endsWith(\"insta-buys in 7d\")) {\n                        lastInstaBuys = getAmountFromLine(line);\n                    } else if (line.endsWith(\"insta-sells in 7d\")) {\n                        lastInstaSells = getAmountFromLine(line);\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (!ModConfig.bazaarTimeToFill || !Utils.inSkyblock) return;\n        if (event.phase != TickEvent.Phase.START) return;\n        if (DankersSkyblockMod.tickAmount % 10 != 0) return;\n\n        textToDisplay = \"\";\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n        if (mc.currentScreen instanceof GuiChest) {\n            if (player == null) return;\n            ContainerChest chest = (ContainerChest) player.openContainer;\n            String chestName = chest.getLowerChestInventory().getDisplayName().getUnformattedText().trim();\n\n            Slot theSlot = ((GuiChest) mc.currentScreen).inventorySlots.inventorySlots.get(10);\n            if (theSlot == null || theSlot.getStack() == null) return;\n            List<String> tooltip = theSlot.getStack().getTooltip(player, false);\n\n            if (chestName.equals(\"How much do you want to pay?\")) {\n                for (String line : tooltip) {\n                    String cleaned = StringUtils.stripControlCodes(line);\n                    if (cleaned.startsWith(\"Ordering: \")) {\n                        double amount = Double.parseDouble(cleaned.replaceAll(\"\\\\D\", \"\"));\n                        textToDisplay = getTextToDisplay(amount, lastInstaSells);\n                        break;\n                    }\n                }\n            } else if (chestName.equals(\"At what price are you selling?\")) {\n                for (String line : tooltip) {\n                    String cleaned = StringUtils.stripControlCodes(line);\n                    if (cleaned.startsWith(\"Selling: \")) {\n                        double amount = Double.parseDouble(cleaned.replaceAll(\"\\\\D\", \"\"));\n                        textToDisplay = getTextToDisplay(amount, lastInstaBuys);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiRender(GuiChestBackgroundDrawnEvent event) {\n        if (!ModConfig.bazaarTimeToFill) return;\n        if (textToDisplay.length() == 0) return;\n\n        int width = UResolution.getScaledWidth();\n        int height = (UResolution.getScaledHeight() - 222) / 2;\n\n        RenderUtils.drawCenteredText(EnumChatFormatting.BLUE + \"Estimated time to fill: \" + textToDisplay, width, height, 1D);\n    }\n\n    static double getAmountFromLine(String line) {\n        try {\n            String amount = StringUtils.stripControlCodes(line.substring(0, line.indexOf(\" \")));\n            double num = Double.parseDouble(amount.replaceAll(\"[^\\\\d.]\", \"\"));\n\n            switch (amount.charAt(amount.length() - 1)) {\n                case 'k':\n                case 'K':\n                    return num * 1000D;\n                case 'm':\n                case 'M':\n                    return num * 1000000D;\n                case 'b':\n                case 'B':\n                    return num * 1000000000D;\n                default:\n                    return num;\n            }\n        } catch (Exception ex) {\n            ex.printStackTrace();\n            return 0;\n        }\n    }\n\n    static String getTextToDisplay(double amount, double volume) {\n        if (volume == -1) return \"Unknown\";\n        if (volume == 0) return \"Never\";\n\n        double volumePerSecond = volume / 604800D;\n        return Utils.getTimeBetween(0, amount / volumePerSecond);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/BlockPlacingFlowers.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.block.Block;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.item.ItemStack;\nimport net.minecraftforge.event.entity.player.PlayerInteractEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\npublic class BlockPlacingFlowers {\n\n    ArrayList<Block> flowerPlaceable = new ArrayList<>(Arrays.asList(\n            Blocks.grass,\n            Blocks.dirt,\n            Blocks.flower_pot,\n            Blocks.tallgrass,\n            Blocks.double_plant\n    ));\n\n    ArrayList<String> flowerWeapons  = new ArrayList<>(Arrays.asList(\n            \"Flower of Truth\",\n            \"Spirit Sceptre\",\n            \"Bouquet of Lies\",\n            \"Fire Freeze Staff\"\n    ));\n\n    @SubscribeEvent\n    public void onInteract(PlayerInteractEvent event) {\n        if (!Utils.inSkyblock || Minecraft.getMinecraft().thePlayer != event.entityPlayer) return;\n        ItemStack item = event.entityPlayer.getHeldItem();\n        if (item == null) return;\n\n        if (ModConfig.flowerWeapons && event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) {\n            Block block = Minecraft.getMinecraft().theWorld.getBlockState(event.pos).getBlock();\n            Block blockUnder = Minecraft.getMinecraft().theWorld.getBlockState(event.pos.down().offset(event.face)).getBlock();\n\n            if (flowerPlaceable.contains(block) || flowerPlaceable.contains(blockUnder)) {\n                for (String weapon : flowerWeapons) {\n                    if(item.getDisplayName().contains(weapon)){\n                        event.setCanceled(true);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/BlockWrongSlayer.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ChestSlotClickedEvent;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class BlockWrongSlayer {\n\n    static String[] names = {\n        \"Revenant Horror\",\n        \"Tarantula Broodfather\",\n        \"Sven Packmaster\",\n        \"Voidgloom Seraph\",\n        \"Inferno Demonlord\"\n    };\n    static String[] tiers = {\n        \"I\",\n        \"II\",\n        \"III\",\n        \"IV\",\n        \"V\"\n    };\n\n    @SubscribeEvent\n    public void onSlotClick(ChestSlotClickedEvent event) {\n        String inventoryName = event.inventoryName;\n        ItemStack item = event.item;\n        if (ModConfig.blockSlayer && item != null) {\n            String name = names[ModConfig.slayerName];\n            String tier = tiers[ModConfig.slayerNumber];\n\n            if (inventoryName.equals(\"Slayer\")) {\n                if (!item.getDisplayName().contains(\"Revenant Horror\") && !item.getDisplayName().contains(\"Tarantula Broodfather\") && !item.getDisplayName().contains(\"Sven Packmaster\"))\n                    return;\n                if (!item.getDisplayName().contains(name)) {\n                    Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Danker's Skyblock Mod has stopped you from starting this quest (Set to \" + name + \" \" + tier + \")\"));\n                    Minecraft.getMinecraft().thePlayer.playSound(\"note.bass\", 1, (float) 0.5);\n                    event.setCanceled(true);\n                }\n            } else if (inventoryName.equals(\"Revenant Horror\") || inventoryName.equals(\"Tarantula Broodfather\") || inventoryName.equals(\"Sven Packmaster\") || inventoryName.equals(\"Voidgloom Seraph\")) {\n                if (item.getDisplayName().contains(\"Revenant Horror\") || item.getDisplayName().contains(\"Tarantula Broodfather\") || item.getDisplayName().contains(\"Sven Packmaster\") || item.getDisplayName().contains(\"Voidgloom Seraph\")) {\n                    // Only check number as they passed the above check\n                    String slayerNumber = item.getDisplayName().substring(item.getDisplayName().lastIndexOf(\" \") + 1);\n                    if (!slayerNumber.equals(tier)) {\n                        Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Danker's Skyblock Mod has stopped you from starting this quest (Set to \" + name + \" \" + tier + \")\"));\n                        Minecraft.getMinecraft().thePlayer.playSound(\"note.bass\", 1, (float) 0.5);\n                        event.setCanceled(true);\n                    }\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/BonzoMaskTimer.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Dropdown;\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.renderer.GlStateManager;\nimport net.minecraft.init.Items;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.ResourceLocation;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport org.lwjgl.opengl.GL11;\n\npublic class BonzoMaskTimer {\n\n    public static double nextBonzoUse = 0;\n    public static final ResourceLocation BONZO_ICON = new ResourceLocation(\"dsm\", \"icons/bonzo.png\");\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        nextBonzoUse = 0;\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!Utils.isInDungeons()) return;\n        if (message.contains(\":\")) return;\n\n        if (ModConfig.bonzoTimerHud.isEnabled() && message.contains(\"Bonzo's Mask\") && message.contains(\"saved your life!\")) {\n            double usedTime = System.currentTimeMillis() / 1000;\n            Minecraft mc = Minecraft.getMinecraft();\n            EntityPlayerSP player = mc.thePlayer;\n            ItemStack bonzoMask = player.getCurrentArmor(3);\n            if (bonzoMask != null && bonzoMask.getItem() == Items.skull) {\n                int cooldownSeconds = 0;\n                for (String line : Utils.getItemLore(bonzoMask)) {\n                    String stripped = StringUtils.stripControlCodes(line);\n                    if (stripped.startsWith(\"Cooldown: \"))\n                        cooldownSeconds = Integer.parseInt(stripped.replaceAll(\"\\\\D\", \"\"));\n                }\n                System.out.println(\"Parsed Bonzo Mask Cooldown: \" + cooldownSeconds);\n                if (cooldownSeconds > 0)\n                    nextBonzoUse = usedTime + cooldownSeconds;\n            }\n        }\n    }\n\n    public static class BonzoTimerHud extends Hud {\n\n        @Exclude\n        String exampleText = ModConfig.getColour(bonzoTimerColour) + \"3m30s\";\n\n        @Dropdown(\n                name = \"Bonzo Timer Text Color\",\n                options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n        )\n        public static int bonzoTimerColour = 12;\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            Minecraft mc = Minecraft.getMinecraft();\n\n            if (example) {\n                double scaleReset = Math.pow(scale, -1);\n                GL11.glScaled(scale, scale, scale);\n                GlStateManager.color(1, 1, 1, 1);\n\n                mc.getTextureManager().bindTexture(BONZO_ICON);\n                RenderUtils.drawModalRectWithCustomSizedTexture(x / scale, y / scale, 0, 0, 16, 16, 16, 16);\n\n                GL11.glScaled(scaleReset, scaleReset, scaleReset);\n\n                TextRenderer.drawHUDText(exampleText, x + 20 * scale, y + 5 * scale, scale);\n                return;\n            }\n\n            if (enabled && Utils.isInDungeons()) {\n                ItemStack helmetSlot = mc.thePlayer.getCurrentArmor(3);\n                if ((helmetSlot != null && helmetSlot.getDisplayName().contains(\"Bonzo's Mask\")) || nextBonzoUse > 0) {\n                    double scaleReset = Math.pow(scale, -1);\n                    GL11.glScaled(scale, scale, scale);\n                    GlStateManager.color(1, 1, 1, 1);\n\n                    mc.getTextureManager().bindTexture(BONZO_ICON);\n                    RenderUtils.drawModalRectWithCustomSizedTexture(x / scale, y / scale, 0, 0, 16, 16, 16, 16);\n\n                    GL11.glScaled(scaleReset, scaleReset, scaleReset);\n\n                    TextRenderer.drawHUDText(getText(), x + 20 * scale, y + 5 * scale, scale);\n                }\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return (RenderUtils.getWidthFromText(example ? exampleText : getText()) + 20 * scale) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return (RenderUtils.getHeightFromText(example ? exampleText : getText()) + 5 * scale) * scale;\n        }\n\n        String getText() {\n            double timeNow = System.currentTimeMillis() / 1000;\n            if (nextBonzoUse - timeNow < 0) {\n                return EnumChatFormatting.GREEN + \"READY\";\n            } else {\n                return ModConfig.getColour(bonzoTimerColour) + Utils.getTimeBetween(timeNow, nextBonzoUse);\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/CakeTimer.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Dropdown;\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.config.CfgConfig;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.renderer.GlStateManager;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.ResourceLocation;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport org.lwjgl.opengl.GL11;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class CakeTimer {\n\n    public static double cakeTime;\n    public static final ResourceLocation CAKE_ICON = new ResourceLocation(\"dsm\", \"icons/cake.png\");\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!Utils.inSkyblock) return;\n        if (message.contains(\":\")) return;\n\n        if (message.contains(\"Yum! You gain +\") && message.contains(\" for 48 hours!\")) {\n            cakeTime = System.currentTimeMillis() / 1000 + 172800; // Add 48 hours\n            CfgConfig.writeDoubleConfig(\"misc\", \"cakeTime\", cakeTime);\n        }else if(message.contains(\"Big Yum! You refresh\") && message.contains(\"for 48 hours!\")){ // Reset timer when refreshing cake\n            cakeTime = System.currentTimeMillis() / 1000 + 172800; // Add 48 hours\n            CfgConfig.writeDoubleConfig(\"misc\", \"cakeTime\", cakeTime);\n        } else if(message.contains(\"You may eat some of it again in \")) { // Keeping this. Maybe Hypixel will revert changes ?\n            Matcher hoursMatcher = Pattern.compile(\"(\\\\d+)h\").matcher(message);\n            Matcher minutesMatcher = Pattern.compile(\"(\\\\d+)m\").matcher(message);\n            Matcher secondsMatcher = Pattern.compile(\"(\\\\d+)s\").matcher(message);\n            int hours = hoursMatcher.find() ? Integer.parseInt(hoursMatcher.group(1)) : 0;\n            int minutes = minutesMatcher.find() ? Integer.parseInt(minutesMatcher.group(1)) : 0;\n            int seconds = secondsMatcher.find() ? Integer.parseInt(secondsMatcher.group(1)) : 0;\n            cakeTime = System.currentTimeMillis() / 1000 + hours * 3600 + minutes * 60 + seconds; // Add left time before cake can be eaten again\n            CfgConfig.writeDoubleConfig(\"misc\", \"cakeTime\", cakeTime);\n        }\n    }\n\n    public static class CakeTimerHud extends Hud {\n\n        @Exclude\n        String exampleText = ModConfig.getColour(cakeColour) + \"11h16m\";\n\n        @Dropdown(\n                name = \"Cake Text Color\",\n                options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n        )\n        public static int cakeColour = 6;\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            if (example) {\n                Minecraft mc = Minecraft.getMinecraft();\n                double scaleReset = Math.pow(scale, -1);\n                GL11.glScaled(scale, scale, scale);\n                GlStateManager.color(1, 1, 1, 1);\n\n                mc.getTextureManager().bindTexture(CAKE_ICON);\n                RenderUtils.drawModalRectWithCustomSizedTexture(x / scale, y / scale, 0, 0, 16, 16, 16, 16);\n\n                GL11.glScaled(scaleReset, scaleReset, scaleReset);\n                TextRenderer.drawHUDText(exampleText, x + 20 * scale, y + 5 * scale, scale);\n                return;\n            }\n\n            if (enabled && Utils.inSkyblock) {\n                Minecraft mc = Minecraft.getMinecraft();\n                double scaleReset = Math.pow(scale, -1);\n                GL11.glScaled(scale, scale, scale);\n                GlStateManager.color(1, 1, 1, 1);\n\n                mc.getTextureManager().bindTexture(CAKE_ICON);\n                RenderUtils.drawModalRectWithCustomSizedTexture(x / scale, y / scale, 0, 0, 16, 16, 16, 16);\n\n                GL11.glScaled(scaleReset, scaleReset, scaleReset);\n                TextRenderer.drawHUDText(getText(), x + 20 * scale, y + 5 * scale, scale);\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return (RenderUtils.getWidthFromText(example ? exampleText : getText()) + 20 * scale) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return (RenderUtils.getHeightFromText(example ? exampleText : getText()) + 5 * scale) * scale;\n        }\n\n        String getText() {\n            double timeNow = System.currentTimeMillis() / 1000;\n            if (cakeTime - timeNow < 0) {\n                return EnumChatFormatting.RED + \"NONE\";\n            } else {\n                return ModConfig.getColour(cakeColour) + Utils.getTimeBetween(timeNow, cakeTime);\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/ChatAliases.java",
    "content": "package me.Danker.features;\n\nimport com.google.gson.GsonBuilder;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ModInitEvent;\nimport me.Danker.events.PacketWriteEvent;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.network.play.client.C01PacketChatMessage;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ChatAliases {\n\n    public static List<Alias> aliases = new ArrayList<>();\n    public static String configFile;\n\n    @SubscribeEvent\n    public void init(ModInitEvent event) {\n        configFile = event.configDirectory + \"/dsm/dsmaliases.json\";\n    }\n\n    @SubscribeEvent\n    public void onPacketWrite(PacketWriteEvent event) {\n        if (ModConfig.aliases) {\n            if (event.packet instanceof C01PacketChatMessage) {\n                C01PacketChatMessage packet = (C01PacketChatMessage) event.packet;\n                String message = packet.getMessage();\n\n                for (Alias alias : aliases) {\n                    if (!alias.toggled) continue;\n                    if (!alias.allowInCommand && message.charAt(0) == '/') continue;\n                    message = message.replace(alias.text, alias.alias);\n                }\n\n                if (!packet.getMessage().equals(message)) {\n                    event.setCanceled(true);\n                    Minecraft.getMinecraft().thePlayer.sendQueue.addToSendQueue(new C01PacketChatMessage(message));\n                }\n            }\n        }\n    }\n\n    public static void save() {\n        try (FileWriter writer = new FileWriter(configFile)) {\n            new GsonBuilder().create().toJson(aliases, writer);\n            writer.flush();\n        } catch (IOException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    public static class Alias {\n\n        public String text;\n        public String alias;\n        public boolean toggled;\n        public boolean allowInCommand;\n\n        public Alias(String text, String alias, boolean toggled, boolean allowInCommand) {\n            this.text = text;\n            this.alias = alias;\n            this.toggled = toggled;\n            this.allowInCommand = allowInCommand;\n        }\n\n        public void toggle() {\n            toggled = !toggled;\n        }\n\n        public void toggleInCommand() {\n            allowInCommand = !allowInCommand;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/ColouredNames.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.PacketReadEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.entity.EntityLivingBase;\nimport net.minecraft.entity.item.EntityArmorStand;\nimport net.minecraft.network.play.server.S45PacketTitle;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.IChatComponent;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.client.event.RenderLivingEvent;\nimport net.minecraftforge.event.entity.player.ItemTooltipEvent;\nimport net.minecraftforge.event.entity.player.PlayerEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.relauncher.ReflectionHelper;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class ColouredNames {\n\n    public static List<String> users = new ArrayList<>();\n    public static Map<String, String> nametags = new HashMap<>();\n    public static final EnumChatFormatting[] RAINBOW_COLOURS = new EnumChatFormatting[]{EnumChatFormatting.RED, EnumChatFormatting.GOLD, EnumChatFormatting.YELLOW, EnumChatFormatting.GREEN, EnumChatFormatting.AQUA, EnumChatFormatting.BLUE, EnumChatFormatting.DARK_PURPLE};\n\n    static Field messageField = ReflectionHelper.findField(S45PacketTitle.class, \"message\", \"field_179810_b\", \"b\");\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!ModConfig.customColouredNames || !Utils.inSkyblock) return;\n        if (event.type == 2) return;\n\n        String text = event.message.getFormattedText();\n        for (String user : users) {\n            if (text.contains(user)) {\n                event.message = replaceChat(event.message, user);\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onTooltip(ItemTooltipEvent event) {\n        if (!ModConfig.customColouredNames || !Utils.inSkyblock) return;\n\n        for (int i = 0; i < event.toolTip.size(); i++) {\n            String line = StringUtils.stripControlCodes(event.toolTip.get(i));\n            for (String user : users) {\n                if (line.contains(user)) {\n                    event.toolTip.set(i, replaceName(event.toolTip.get(i), user, getColourFromName(user)));\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onRenderNametag(PlayerEvent.NameFormat event) {\n        if (!ModConfig.customColouredNames || !Utils.inSkyblock) return;\n\n        if (users.contains(event.username)) {\n            event.displayname = replaceName(event.displayname, event.username, getColourFromName(event.username));\n        }\n    }\n\n    @SubscribeEvent(priority = EventPriority.LOW)\n    public void onRenderLiving(RenderLivingEvent.Specials.Pre<EntityLivingBase> event) {\n        if (!ModConfig.customColouredNames || !ModConfig.customNametags || !Utils.inSkyblock) return;\n\n        Entity entity = event.entity;\n        if (entity instanceof EntityArmorStand && !entity.isDead && entity.hasCustomName()) {\n            String name = entity.getCustomNameTag();\n            if (name.charAt(name.length() - 1) == '❤') return;\n\n            String id = entity.getUniqueID().toString();\n            String nametag = nametags.get(id);\n\n            if (name.equals(nametag)) {\n                entity.setCustomNameTag(nametag);\n            } else {\n                for (String user : users) {\n                    if (name.contains(user)) {\n                        name = replaceName(name, user, getColourFromName(user));\n                    }\n                }\n\n                nametags.put(id, name);\n                entity.setCustomNameTag(name);\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onPacketRead(PacketReadEvent event) {\n        if (!ModConfig.customColouredNames || !Utils.inSkyblock) return;\n\n        if (event.packet instanceof S45PacketTitle) {\n            S45PacketTitle packet = (S45PacketTitle) event.packet;\n\n            if (packet.getMessage() == null) return;\n\n            String message = packet.getMessage().getUnformattedText();\n            for (String user : users) {\n                if (message.contains(user)) {\n                    try {\n                        messageField.setAccessible(true);\n                        messageField.set(packet, replaceChat(packet.getMessage(), user));\n                        event.packet = packet;\n                    } catch (IllegalAccessException ex) {\n                        ex.printStackTrace();\n                    }\n                    break;\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        nametags.clear();\n    }\n\n    // https://github.com/SteveKunG/SkyBlockcatia/blob/1.8.9/src/main/java/com/stevekung/skyblockcatia/utils/SupporterUtils.java#L53\n    public static String replaceName(String text, String name, String colour) {\n        String namePattern = \"(?:(?:\\\\u00a7[0-9a-fbr])\\\\B(?:\" + name + \")\\\\b)|(?:\\\\u00a7[rb]\" + name + \"\\\\u00a7r)|\\\\b\" + name + \"\\\\b\";\n        Matcher prevColourMat = Pattern.compile(\"(?:.*(?:(?<colour>\\\\u00a7[0-9a-fbr])\" + name + \")\\\\b.*)\").matcher(text);\n\n        if (prevColourMat.matches()) {\n            if (colour.equals(\"§z\")) {\n                StringBuilder rainbowName = new StringBuilder();\n                for (int i = 0; i < name.length(); i++) {\n                    rainbowName.append(RAINBOW_COLOURS[i % 7]).append(name.charAt(i));\n                }\n                return text.replaceAll(namePattern, rainbowName + prevColourMat.group(\"colour\"));\n            }\n            return text.replaceAll(namePattern, colour + name + prevColourMat.group(\"colour\"));\n        }\n\n        if (colour.equals(\"§z\")) {\n            StringBuilder rainbowName = new StringBuilder();\n            for (int i = 0; i < name.length(); i++) {\n                rainbowName.append(RAINBOW_COLOURS[i % 7]).append(name.charAt(i));\n            }\n            return text.replaceAll(namePattern, rainbowName.toString() + EnumChatFormatting.WHITE);\n        }\n        return text.replaceAll(namePattern, colour + name + EnumChatFormatting.WHITE);\n    }\n\n    // https://github.com/Moulberry/Hychat/blob/master/src/main/java/io/github/moulberry/hychat/util/TextProcessing.java#L23\n    public static IChatComponent replaceChat(IChatComponent component, String user) {\n        IChatComponent newComponent;\n        ChatComponentText text = (ChatComponentText) component;\n\n        newComponent = new ChatComponentText(replaceName(text.getUnformattedTextForChat(), user, getColourFromName(user)));\n        newComponent.setChatStyle(text.getChatStyle().createShallowCopy());\n\n        for (IChatComponent sibling : text.getSiblings()) {\n            newComponent.appendSibling(replaceChat(sibling, user));\n        }\n\n        return newComponent;\n    }\n\n    public static String getColourFromName(String name) {\n        try {\n            return \"§\" + DankersSkyblockMod.data.getAsJsonObject(\"colourednames\").get(name).getAsString();\n        } catch (NullPointerException ex) {\n            return EnumChatFormatting.WHITE.toString();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/CoordsOptimizer.java",
    "content": "package me.Danker.features;\n\nimport com.google.common.primitives.Ints;\nimport me.Danker.config.ModConfig;\n\nimport java.util.*;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.IntStream;\n\npublic class CoordsOptimizer {\n\n    // https://www.baeldung.com/java-ant-colony-optimization\n\n    private final static Pattern numberedPattern = Pattern.compile(\"\\\\d+\");\n    private final ArrayList<CrystalHollowWaypoints.Waypoint> waypoints;\n\n    private final double c = 1.0;\n    private double alpha;\n    private double beta;\n    private final double evaporation = 0.5;\n    private final double Q = 500;\n    private final double antFactor = 0.8;\n    private final double randomFactor = 0.01;\n\n    private final int maxIterations = 5000;\n\n    private final int numberOfCities;\n    private final int numberOfAnts;\n    private final double[][] graph;\n    private final double[][] trails;\n    private final List<Ant> ants = new ArrayList<>();\n    private final Random random = new Random();\n    private final double[] probabilities;\n\n    private int currentIndex;\n\n    private int[] bestTourOrder;\n    private double bestTourLength;\n\n    public CoordsOptimizer(ArrayList<CrystalHollowWaypoints.Waypoint> waypoints) {\n        this.waypoints = waypoints;\n        graph = getAdjacency();\n        numberOfCities = graph.length;\n        numberOfAnts = (int) (numberOfCities * antFactor);\n        alpha = ModConfig.coordAlpha;\n        beta = ModConfig.coordBeta;\n\n        trails = new double[numberOfCities][numberOfCities];\n        probabilities = new double[numberOfCities];\n        for (int i = 0; i < numberOfAnts; i++) {\n            ants.add(new Ant(numberOfCities));\n        }\n    }\n\n    public static ArrayList<CrystalHollowWaypoints.Waypoint> getNumbered(ArrayList<CrystalHollowWaypoints.Waypoint> waypoints) {\n        ArrayList<CrystalHollowWaypoints.Waypoint> numbered = new ArrayList<>();\n\n        for (CrystalHollowWaypoints.Waypoint waypoint : waypoints) {\n            String location = waypoint.location.replaceAll(\"\\\\D\", \"\");\n            Matcher matcher = numberedPattern.matcher(location);\n            if (matcher.matches()) numbered.add(new CrystalHollowWaypoints.Waypoint(location, waypoint.pos));\n        }\n\n        numbered.sort(Comparator.comparingInt(w -> Integer.parseInt(w.location)));\n        return numbered;\n    }\n\n    public int[] solve() {\n        setupAnts();\n        clearTrails();\n\n        for (int i = 0; i < maxIterations; i++) {\n            moveAnts();\n            updateTrails();\n            updateBest();\n        }\n\n        System.out.println(\"Best path: \" + Arrays.toString(bestTourOrder));\n        return bestTourOrder.clone();\n    }\n\n    private void setupAnts() {\n        for (int i = 0; i < numberOfAnts; i++) {\n            for (Ant ant : ants) {\n                ant.clear();\n                ant.visitCity(-1, random.nextInt(numberOfCities));\n            }\n        }\n        currentIndex = 0;\n    }\n\n    private void moveAnts() {\n        for (int i = currentIndex; i < numberOfCities - 1; i++) {\n            for (Ant ant : ants) {\n                ant.visitCity(currentIndex, selectNextCity(ant));\n            }\n            currentIndex++;\n        }\n    }\n\n    private int selectNextCity(Ant ant) {\n        int t = random.nextInt(numberOfCities - currentIndex);\n        if (random.nextDouble() < randomFactor) {\n            OptionalInt cityIndex = IntStream.range(0, numberOfCities)\n                    .filter(i -> i == t && !ant.visited(i))\n                    .findFirst();\n            if (cityIndex.isPresent()) return cityIndex.getAsInt();\n        }\n        calculateProbabilities(ant);\n\n        double r = random.nextDouble();\n        double total = 0;\n        for (int i = 0; i < numberOfCities; i++) {\n            total += probabilities[i];\n            if (total >= r) return i;\n        }\n\n        throw new RuntimeException(\"There are no other cities\");\n    }\n\n    public void calculateProbabilities(Ant ant) {\n        int i = ant.trail[currentIndex];\n        double pheromone = 0.0;\n        for (int l = 0; l < numberOfCities; l++) {\n            if (!ant.visited(l)) {\n                pheromone += Math.pow(trails[i][l], alpha) * Math.pow(1.0 / graph[i][l], beta);\n            }\n        }\n\n        for (int j = 0; j < numberOfCities; j++) {\n            if (ant.visited(j)) {\n                probabilities[j] = 0.0;\n            } else {\n                double numerator = Math.pow(trails[i][j], alpha) * Math.pow(1.0 / graph[i][j], beta);\n                probabilities[j] = numerator / pheromone;\n            }\n        }\n    }\n\n    private void updateTrails() {\n        for (int i = 0; i < numberOfCities; i++) {\n            for (int j = 0; j < numberOfCities; j++) {\n                trails[i][j] *= evaporation;\n            }\n        }\n\n        for (Ant a : ants) {\n            double contribution = Q / a.trailLength(graph);\n            for (int i = 0; i < numberOfCities - 1; i++) {\n                trails[a.trail[i]][a.trail[i + 1]] += contribution;\n            }\n            trails[a.trail[numberOfCities - 1]][a.trail[0]] += contribution;\n        }\n    }\n\n    private void updateBest() {\n        if (bestTourOrder == null) {\n            bestTourOrder = ants.get(0).trail;\n            bestTourLength = ants.get(0).trailLength(graph);\n        }\n\n        for (Ant a : ants) {\n            if (a.trailLength(graph) < bestTourLength) {\n                bestTourLength = a.trailLength(graph);\n                bestTourOrder = a.trail.clone();\n            }\n        }\n    }\n\n    private void clearTrails() {\n        for (int i = 0; i < numberOfCities; i++) {\n            for (int j = 0; j < numberOfCities; j++) {\n                trails[i][j] = c;\n            }\n        }\n    }\n\n    public ArrayList<CrystalHollowWaypoints.Waypoint> getOptimizedPath() {\n        ArrayList<CrystalHollowWaypoints.Waypoint> sorted = new ArrayList<>();\n        List<Integer> bestPath = Ints.asList(bestTourOrder);\n        Collections.reverse(bestPath);\n\n        int offset = 0;\n        for (int i = 0; i < bestPath.size(); i++) {\n            if (bestPath.get(i) == 0) {\n                offset = i;\n                break;\n            }\n        }\n\n        for (int i = 0; i < bestPath.size(); i++) {\n            int index = (i + offset) % bestPath.size();\n            sorted.add(new CrystalHollowWaypoints.Waypoint(\"\" + (i + 1), waypoints.get(bestPath.get(index)).pos));\n        }\n\n        return sorted;\n    }\n\n    private static double getDistance(CrystalHollowWaypoints.Waypoint waypoint1, CrystalHollowWaypoints.Waypoint waypoint2) {\n        return Math.sqrt(waypoint1.pos.distanceSq(waypoint2.pos));\n    }\n\n    private double[][] getAdjacency() {\n        int length = waypoints.size();\n        double[][] adj = new double[length][length];\n\n        for (int i = 0; i < length; i++) {\n            for (int j = 0; j < length; j++) {\n                double distance = getDistance(waypoints.get(i), waypoints.get(j));\n                adj[i][j] = distance;\n                adj[j][i] = distance;\n            }\n        }\n\n        return adj;\n    }\n\n    public static double getLength(ArrayList<CrystalHollowWaypoints.Waypoint> waypoints) {\n        if (waypoints.size() == 0) return 0;\n\n        double length = 0;\n        for (int i = 0; i < waypoints.size() - 1; i++) {\n            length += getDistance(waypoints.get(i), waypoints.get(i + 1));\n        }\n        length += getDistance(waypoints.get(waypoints.size() - 1), waypoints.get(0));\n\n        return length;\n    }\n\n\n    private static class Ant {\n\n        public int trailSize;\n        public int[] trail;\n        public boolean[] visited;\n\n        public Ant(int tourSize) {\n            this.trailSize = tourSize;\n            this.trail = new int[tourSize];\n            this.visited = new boolean[tourSize];\n        }\n\n        public void visitCity(int currentIndex, int city) {\n            trail[currentIndex + 1] = city;\n            visited[city] = true;\n        }\n\n        public boolean visited(int i) {\n            return visited[i];\n        }\n\n        public double trailLength(double[][] graph) {\n            double length = graph[trail[trailSize - 1]][trail[0]];\n            for (int i = 0; i < trailSize - 1; i++) {\n                length += graph[trail[i]][trail[i + 1]];\n            }\n            return length;\n        }\n\n        public void clear() {\n            for (int i = 0; i < trailSize; i++) {\n                visited[i] = false;\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/CrimsonMinibossTimer.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Dropdown;\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.config.annotations.Switch;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class CrimsonMinibossTimer {\n\n    static double bladesoul;\n    static double duke;\n    static double outlaw;\n    static double magma;\n    static double ashfang;\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        bladesoul = 0;\n        duke = 0;\n        outlaw = 0;\n        magma = 0;\n        ashfang = 0;\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (message.contains(\":\")) return;\n\n        if (ModConfig.minibossTimerHud.isEnabled() && Utils.currentLocation == Location.CRIMSON_ISLE) {\n            if (message.contains(\"BLADESOUL DOWN!\")) {\n                bladesoul = System.currentTimeMillis() / 1000 + 120;\n            } else if (message.contains(\"BARBARIAN DUKE X DOWN!\")) {\n                duke = System.currentTimeMillis() / 1000 + 120;\n            } else if (message.contains(\"MAGE OUTLAW DOWN!\")) {\n                outlaw = System.currentTimeMillis() / 1000 + 120;\n            } else if (message.contains(\"ASHFANG DOWN!\")) {\n                ashfang = System.currentTimeMillis() / 1000 + 120;\n            } else if (message.contains(\"MAGMA BOSS DOWN!\")) {\n                magma = System.currentTimeMillis() / 1000 + 120;\n            }\n        }\n    }\n\n    public static class MinibossTimerHud extends Hud {\n\n        @Switch(\n                name = \"Miniboss Spawn Soon Alert\",\n                description = \"Makes an alert noise when a miniboss is about to spawn soon.\"\n        )\n        public static boolean alert = true;\n\n        @Exclude\n        String exampleText = EnumChatFormatting.GRAY + \"Bladesoul: \" + ModConfig.getColour(minibossTimerColour) + \"0m24s\" + \"\\n\" +\n                             EnumChatFormatting.RED + \"Barbarian Duke: \" + ModConfig.getColour(minibossTimerColour) + \"1m27s\" + \"\\n\" +\n                             EnumChatFormatting.DARK_PURPLE + \"Mage Outlaw: \" + ModConfig.getColour(minibossTimerColour) + \"2m0s\" + \"\\n\" +\n                             EnumChatFormatting.GOLD + \"Ashfang: \" + ModConfig.getColour(minibossTimerUnknownColour) + \"?\" + \"\\n\" +\n                             EnumChatFormatting.DARK_RED + \"Magma Boss: \" + ModConfig.getColour(minibossTimerUnknownColour) + \"?\";\n\n        @Dropdown(\n                name = \"Miniboss Timer Text Color\",\n                options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n        )\n        public static int minibossTimerColour = 6;\n\n        @Dropdown(\n                name = \"Miniboss Unknown Text Color\",\n                options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n        )\n        public static int minibossTimerUnknownColour = 12;\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            if (example) {\n                TextRenderer.drawHUDText(exampleText, x, y, scale);\n                return;\n            }\n\n            if (enabled && Utils.currentLocation == Location.CRIMSON_ISLE) {\n                TextRenderer.drawHUDText(getText(), x, y, scale);\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return RenderUtils.getWidthFromText(example ? exampleText : getText()) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return RenderUtils.getHeightFromText(example ? exampleText : getText()) * scale;\n        }\n\n        String getText() {\n            double timeNow = System.currentTimeMillis() / 1000;\n            return EnumChatFormatting.GRAY + \"Bladesoul: \" + getTime(timeNow, bladesoul) + \"\\n\" +\n                   EnumChatFormatting.RED + \"Barbarian Duke: \" + getTime(timeNow, duke) + \"\\n\" +\n                   EnumChatFormatting.DARK_PURPLE + \"Mage Outlaw: \" + getTime(timeNow, outlaw) + \"\\n\" +\n                   EnumChatFormatting.GOLD + \"Ashfang: \" + getTime(timeNow, ashfang) + \"\\n\" +\n                   EnumChatFormatting.DARK_RED + \"Magma Boss: \" + getTime(timeNow, magma);\n        }\n\n        String getTime(double timeNow, double bossTime) {\n            if (alert && timeNow == bossTime) Minecraft.getMinecraft().thePlayer.playSound(ModConfig.alertNoise, 1, (float) 0.5);\n            if (timeNow < bossTime) {\n                return ModConfig.getColour(minibossTimerColour) + Utils.getTimeBetween(timeNow, bossTime);\n            }\n            return ModConfig.getColour(minibossTimerUnknownColour) + \"?\";\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/CrystalHollowWaypoints.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.utils.IOUtils;\nimport cc.polyfrost.oneconfig.utils.Notifications;\nimport cc.polyfrost.oneconfig.utils.SimpleProfiler;\nimport com.google.gson.*;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.gui.crystalhollowwaypoints.CrystalHollowAddWaypointGui;\nimport me.Danker.handlers.ScoreboardHandler;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.item.EntityArmorStand;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.event.ClickEvent;\nimport net.minecraft.util.*;\nimport net.minecraft.world.World;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\nimport org.apache.commons.codec.binary.Base64;\nimport org.apache.commons.codec.binary.Base64InputStream;\nimport org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class CrystalHollowWaypoints {\n\n    public static ArrayList<Waypoint> waypoints = new ArrayList<>();\n    public static Pattern dsmPattern = Pattern.compile(\"(?<name>.*?) @ (?<x>\\\\d{1,3}) (?<y>\\\\d{1,3}) (?<z>\\\\d{1,3})\");\n    public static Pattern skytilsPattern = Pattern.compile(\"(?<name>.*?): (?<x>\\\\d{1,3}) (?<y>\\\\d{1,3}) (?<z>\\\\d{1,3})\");\n\n    static boolean perma = false;\n    static boolean khazad = false;\n    static boolean fairy = false;\n    static boolean temple = false;\n    static boolean guardian = false;\n    static boolean divan = false;\n    static boolean corleone = false;\n    static boolean king = false;\n    static boolean queen = false;\n    static boolean city = false;\n    static boolean shop = false;\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayer player = mc.thePlayer;\n        World world = mc.theWorld;\n\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            if (ModConfig.autoWaypoints && Utils.currentLocation == Location.CRYSTAL_HOLLOWS && world != null) {\n                boolean found = false;\n                List<String> scoreboard = ScoreboardHandler.getSidebarLines();\n\n                if (!perma) {\n                    perma = true;\n                    try {\n                        if (ModConfig.autoImportWaypoints) addDSMWaypoints(ModConfig.permaWaypoints, false, true);\n                    } catch (ArrayIndexOutOfBoundsException ignored) {}\n                }\n\n                for (String s : scoreboard) {\n                    String sCleaned = ScoreboardHandler.cleanSB(s);\n                    if (!khazad && sCleaned.contains(\"Khazad-d\")) {\n                        khazad = found = true;\n                        waypoints.add(new Waypoint(\"Khazad-dûm\", player.getPosition()));\n                    } else if (!fairy && sCleaned.contains(\"Fairy Grotto\")) {\n                        fairy = found = true;\n                        waypoints.add(new Waypoint(\"Fairy Grotto\", player.getPosition()));\n                    } else if (!temple && sCleaned.contains(\"Jungle Temple\")) {\n                        temple = found = true;\n                        waypoints.add(new Waypoint(\"Jungle Temple\", player.getPosition()));\n                    } else if (!divan && sCleaned.contains(\"Mines of Divan\")) {\n                        divan = found = true;\n                        waypoints.add(new Waypoint(\"Mines of Divan\", player.getPosition()));\n                    } else if (!queen && sCleaned.contains(\"Goblin Queen's Den\")) {\n                        queen = found = true;\n                        waypoints.add(new Waypoint(\"Goblin Queen's Den\", player.getPosition()));\n                    } else if (!city && sCleaned.contains(\"Lost Precursor City\")) {\n                        city = found = true;\n                        waypoints.add(new Waypoint(\"Lost Precursor City\", player.getPosition()));\n                    }\n\n                    if (found) break;\n                }\n\n                if (!found) {\n                    AxisAlignedBB scan = new AxisAlignedBB(player.getPosition().add(-15, -15, -15), player.getPosition().add(15, 15, 15));\n                    List<EntityArmorStand> entities = world.getEntitiesWithinAABB(EntityArmorStand.class, scan);\n\n                    for (EntityArmorStand entity : entities) {\n                        if (entity.hasCustomName()) {\n                            if (!king && entity.getCustomNameTag().endsWith(\"King Yolkar\")) {\n                                king = found = true;\n                                waypoints.add(new Waypoint(\"King Yolkar\", entity.getPosition()));\n                            } else if (!corleone && entity.getCustomNameTag().contains(\"Boss Corleone\")) {\n                                corleone = found = true;\n                                waypoints.add(new Waypoint(\"Boss Corleone\", entity.getPosition()));\n                            } else if (!guardian && entity.getCustomNameTag().contains(\"Key Guardian\")) {\n                                guardian = found = true;\n                                waypoints.add(new Waypoint(\"Key Guardian\", entity.getPosition()));\n                            } else if (!shop && entity.getCustomNameTag().contains(\"Odawa\")) {\n                                shop = found = true;\n                                waypoints.add(new Waypoint(\"Odawa\", entity.getPosition()));\n                            }\n                        }\n                    }\n                }\n\n                if (found && ModConfig.crystalHollowWaypoints) {\n                    Waypoint latest = waypoints.get(waypoints.size() - 1);\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Added \" + latest.location + \" @ \" + latest.getPos()));\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n        EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n\n        if (player == null) return;\n\n        /* examples\n        $SBECHWP:Mines of Divan@-673,117,426\n        $SBECHWP:Khazad-dûm@-292,63,281\\nFairy Grotto@-216,110,400\\njungle temple@-525,110,395\\nJungle Temple@-493,101,425\\nMines of Divan@-673,117,426\n        */\n        if (ModConfig.crystalHollowWaypoints && Utils.currentLocation == Location.CRYSTAL_HOLLOWS) {\n            if (!message.contains(player.getName())) {\n                if (message.contains(\": $DSMCHWP:\") || message.contains(\": $SBECHWP:\")) {\n                    String waypoints = message.substring(message.lastIndexOf(\":\") + 1);\n\n                    if (ModConfig.autoPlayerWaypoints) {\n                        addDSMWaypoints(waypoints, true, false);\n                        return;\n                    }\n\n                    ChatComponentText add = new ChatComponentText(EnumChatFormatting.GREEN + \"\" + EnumChatFormatting.BOLD + \"  [ADD]\\n\");\n                    add.setChatStyle(add.getChatStyle().setChatClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, \"/dsmaddcrystalhollowwaypoints \" + waypoints)));\n\n                    new Thread(() -> {\n                        try {\n                            Thread.sleep(10);\n                        } catch (InterruptedException ex) {\n                            ex.printStackTrace();\n                        }\n                        player.addChatMessage(new ChatComponentText(\"\\n\" + ModConfig.getColour(ModConfig.mainColour) + \"DSM/SBE Crystal Hollows waypoints found. Click to add.\\n\").appendSibling(add));\n                    }).start();\n                } else if (message.indexOf(\":\") != message.lastIndexOf(\":\")) {\n                    String text = message.substring(message.indexOf(\":\") + 2);\n                    Matcher matcher = skytilsPattern.matcher(text);\n\n                    if (matcher.matches()) {\n                        String name = matcher.group(\"name\");\n                        String x = matcher.group(\"x\");\n                        String y = matcher.group(\"y\");\n                        String z = matcher.group(\"z\");\n\n                        if (ModConfig.autoPlayerWaypoints) {\n                            addWaypoint(name, x, y, z, true);\n                            return;\n                        }\n\n                        ChatComponentText add = new ChatComponentText(EnumChatFormatting.GREEN + \"\" + EnumChatFormatting.BOLD + \"  [ADD]\\n\");\n                        add.setChatStyle(add.getChatStyle().setChatClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, \"/dsmaddcrystalhollowwaypoints st \" + x + \" \" + y + \" \" + z + \" \" + name)));\n\n                        new Thread(() -> {\n                            try {\n                                Thread.sleep(10);\n                            } catch (InterruptedException ex) {\n                                ex.printStackTrace();\n                            }\n                            player.addChatMessage(new ChatComponentText(\"\\n\" + ModConfig.getColour(ModConfig.mainColour) + \"Skytils Crystal Hollows waypoints found. Click to add.\\n\").appendSibling(add));\n                        }).start();\n                    }\n                } else if (message.contains(\" @ \")) {\n                    String text = message.substring(message.indexOf(\":\") + 2);\n                    Matcher matcher = dsmPattern.matcher(text);\n\n                    if (matcher.matches()) {\n                        String name = matcher.group(\"name\");\n                        String x = matcher.group(\"x\");\n                        String y = matcher.group(\"y\");\n                        String z = matcher.group(\"z\");\n\n                        if (ModConfig.autoPlayerWaypoints) {\n                            addWaypoint(name, x, y, z, true);\n                            return;\n                        }\n\n                        ChatComponentText add = new ChatComponentText(EnumChatFormatting.GREEN + \"\" + EnumChatFormatting.BOLD + \"  [ADD]\\n\");\n                        add.setChatStyle(add.getChatStyle().setChatClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, \"/dsmaddcrystalhollowwaypoints st \" + x + \" \" + y + \" \" + z + \" \" + name)));\n\n                        new Thread(() -> {\n                            try {\n                                Thread.sleep(10);\n                            } catch (InterruptedException ex) {\n                                ex.printStackTrace();\n                            }\n                            player.addChatMessage(new ChatComponentText(\"\\n\" + ModConfig.getColour(ModConfig.mainColour) + \"DSM Crystal Hollows waypoints found. Click to add.\\n\").appendSibling(add));\n                        }).start();\n                    }\n                }\n            }\n        }\n    }\n\n    public static void onKey() {\n        if (Utils.currentLocation != Location.CRYSTAL_HOLLOWS) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayer player = mc.thePlayer;\n\n        mc.displayGuiScreen(new CrystalHollowAddWaypointGui((int) player.posX, (int) player.posY, (int) player.posZ));\n    }\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n        if (ModConfig.crystalHollowWaypoints && Utils.currentLocation == Location.CRYSTAL_HOLLOWS) {\n            for (Waypoint waypoint : waypoints) {\n                if (waypoint.toggled) RenderUtils.draw3DWaypointString(waypoint, event.partialTicks);\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        waypoints.clear();\n        perma = false;\n        khazad = false;\n        fairy = false;\n        temple = false;\n        guardian = false;\n        divan = false;\n        corleone = false;\n        king = false;\n        queen = false;\n        city = false;\n        shop = false;\n    }\n\n    public static void addWaypoint(String name, String x, String y, String z, boolean auto) {\n        if (auto) {\n            for (Waypoint existing : waypoints) {\n                if (existing.location.equals(name)) {\n                    return;\n                }\n            }\n        }\n\n        BlockPos pos = new BlockPos(Integer.parseInt(x), Integer.parseInt(y), Integer.parseInt(z));\n        Waypoint waypoint = new Waypoint(name, pos);\n        waypoints.add(waypoint);\n        Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Added \" + waypoint.location + \" @ \" + waypoint.getPos()));\n    }\n\n    public static void addDSMWaypoints(String list, boolean auto, boolean silent) {\n        String[] waypointsList = list.split(\"\\\\\\\\n\");\n\n        for (String waypoint : waypointsList) {\n            String[] parts = waypoint.split(\"@-\");\n            String[] coords = parts[1].split(\",\");\n\n            String location = parts[0];\n            BlockPos pos = new BlockPos(Integer.parseInt(coords[0]), Integer.parseInt(coords[1]), Integer.parseInt(coords[2]));\n            Waypoint newWaypoint = new Waypoint(location, pos);\n\n            if (auto) {\n                boolean contains = false;\n                for (Waypoint existing : waypoints) {\n                    if (existing.location.equals(location)) {\n                        contains = true;\n                        break;\n                    }\n                }\n                if (contains) continue;\n            }\n\n            waypoints.add(newWaypoint);\n            if (!silent) Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Added \" + newWaypoint.location + \" @ \" + newWaypoint.getPos()));\n        }\n    }\n\n    public static void addSTWaypoints(String list) {\n        JsonObject obj;\n        try {\n            obj = new Gson().fromJson(list, JsonObject.class);\n        } catch (JsonSyntaxException ex) {\n            ex.printStackTrace();\n            return;\n        }\n\n        JsonArray categories = obj.getAsJsonArray(\"categories\");\n\n        for (JsonElement element : categories) {\n            JsonObject inner = element.getAsJsonObject();\n\n            String island = inner.get(\"island\").getAsString();\n            if (!island.equals(\"crystal_hollows\")) return;\n\n            JsonArray waypoints = inner.getAsJsonArray(\"waypoints\");\n\n            for (JsonElement waypointElement : waypoints) {\n                JsonObject waypoint = waypointElement.getAsJsonObject();\n\n                String name = waypoint.get(\"name\").getAsString();\n                String x = waypoint.get(\"x\").getAsString();\n                String y = waypoint.get(\"y\").getAsString();\n                String z = waypoint.get(\"z\").getAsString();\n\n                addWaypoint(name, x, y, z, false);\n            }\n        }\n    }\n\n    public static void addSoopyWaypoints(String list) {\n        JsonArray arr;\n        try {\n            arr = new Gson().fromJson(list, JsonArray.class);\n        } catch (JsonSyntaxException ex) {\n            ex.printStackTrace();\n            return;\n        }\n\n        for (JsonElement element : arr) {\n            JsonObject waypoint = element.getAsJsonObject();\n\n            String name = waypoint.getAsJsonObject(\"options\").get(\"name\").getAsString();\n            String x = waypoint.get(\"x\").getAsString();\n            String y = waypoint.get(\"y\").getAsString();\n            String z = waypoint.get(\"z\").getAsString();\n\n            addWaypoint(name, x, y, z, false);\n        }\n    }\n\n    public static void copyToClipboard() {\n        StringBuilder sb = new StringBuilder();\n        for (Waypoint waypoint : waypoints) {\n            if (sb.length() > 0) sb.append(\"\\\\n\");\n            sb.append(waypoint.getFormattedWaypoint());\n        }\n        String waypoints = sb.toString();\n        if (waypoints.length() > 0) {\n            IOUtils.copyStringToClipboard(waypoints);\n            Notifications.INSTANCE.send(\"Success\", \"Copied waypoints to clipboard.\");\n        }\n    }\n\n    public static void importWaypoints() {\n        String clipboard = IOUtils.getStringFromClipboard();\n        if (clipboard == null) {\n            Notifications.INSTANCE.send(\"Error\", \"Could not find waypoints in clipboard.\");\n            return;\n        }\n\n        if (clipboard.startsWith(\"<Skytils-Waypoint-Data>(V1):\")) { // ST\n            try {\n                String str = clipboard.substring(clipboard.indexOf(\":\") + 1);\n                GzipCompressorInputStream gcis = new GzipCompressorInputStream(new Base64InputStream(new ByteArrayInputStream(str.getBytes())));\n\n                ByteArrayOutputStream out = new ByteArrayOutputStream();\n                org.apache.commons.compress.utils.IOUtils.copy(gcis, out);\n\n                addSTWaypoints(out.toString());\n            } catch (IOException ex) {\n                ex.printStackTrace();\n                Notifications.INSTANCE.send(\"Error\", \"Error parsing waypoints in clipboard.\");\n            }\n        } else if (Base64.isBase64(clipboard)) { // ST\n            addSTWaypoints(new String(Base64.decodeBase64(clipboard), StandardCharsets.UTF_8));\n        } else if (Utils.isJson(clipboard)) { // Soopy\n            addSoopyWaypoints(clipboard);\n        } else { // DSM\n            try {\n                addDSMWaypoints(clipboard, false, false);\n            } catch (Exception ex) {\n                Notifications.INSTANCE.send(\"Error\", \"Error parsing waypoints in clipboard.\");\n            }\n        }\n    }\n\n    public static void optimize() {\n        SimpleProfiler.push(\"Coords Optimizer\");\n        Notifications.INSTANCE.send(\"Running...\", \"Optimizing waypoints...\");\n\n        Minecraft mc = Minecraft.getMinecraft();\n        ArrayList<Waypoint> numbered = CoordsOptimizer.getNumbered(waypoints);\n        double unoptimizedLength = CoordsOptimizer.getLength(numbered);\n\n        if (numbered.size() < 2) {\n            Notifications.INSTANCE.send(\"Error\", \"Requires at least 2 numbered waypoints.\");\n            SimpleProfiler.pop(\"Coords Optimizer\");\n            return;\n        }\n\n        CoordsOptimizer coordsOptimizer = new CoordsOptimizer(numbered);\n        coordsOptimizer.solve();\n        ArrayList<Waypoint> optimized = coordsOptimizer.getOptimizedPath();\n        double optimizedLength = CoordsOptimizer.getLength(optimized);\n\n        System.out.println(\"Coords optimizer took \" + SimpleProfiler.pop(\"Coords Optimizer\") + \"ms\");\n        Notifications.INSTANCE.send(\"Finished\", \"Finished optimizing waypoints. See logs for more details.\");\n\n        if (optimizedLength < unoptimizedLength) {\n            waypoints = optimized;\n            System.out.println(\"Optimized waypoints from length \" + unoptimizedLength + \" to length \" + optimizedLength);\n            if (mc.thePlayer != null) {\n                mc.thePlayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Optimized waypoints from length \" + String.format(\"%.2f\", unoptimizedLength) + \" to length \" + String.format(\"%.2f\", optimizedLength) + \".\"));\n            }\n        } else {\n            System.out.println(\"Could not find more optimized path. Found length \" + optimizedLength + \" but best length is \" + unoptimizedLength);\n            if (mc.thePlayer != null) {\n                mc.thePlayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Could not find more optimized path. It may have failed to find one, or your route is already perfect.\"));\n            }\n        }\n    }\n    \n\n    public static class Waypoint {\n\n        public String location;\n        public BlockPos pos;\n        public boolean toggled;\n\n        public Waypoint(String location, BlockPos pos) {\n            this.location = location;\n            this.pos = pos;\n            this.toggled = true;\n        }\n\n        public String getFormattedWaypoint() {\n            return location + \"@-\" + pos.getX() + \",\" + pos.getY() + \",\" + pos.getZ();\n        }\n\n        public String getDistance(EntityPlayer player) {\n            return Math.round(player.getDistance(pos.getX(), pos.getY(), pos.getZ())) + \"m\";\n        }\n\n        public String getPos() {\n            return pos.getX() + \", \" + pos.getY() + \", \" + pos.getZ();\n        }\n\n        public void toggle() {\n            toggled = !toggled;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/CustomMusic.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.PostConfigInitEvent;\nimport me.Danker.handlers.ScoreboardHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.StringUtils;\nimport net.minecraft.world.World;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.client.event.sound.PlaySoundEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport javax.sound.sampled.*;\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\n\npublic class CustomMusic {\n\n    static boolean cancelNotes;\n\n    public static Song dungeonboss;\n    public static Song bloodroom;\n    public static Song dungeon;\n    public static Song phase2;\n    public static Song phase3;\n    public static Song phase4;\n    public static Song phase5;\n    public static Song hub;\n    public static Song island;\n    public static Song dungeonHub;\n    public static Song farmingIslands;\n    public static Song garden;\n    public static Song goldMine;\n    public static Song deepCaverns;\n    public static Song dwarvenMines;\n    public static Song crystalHollows;\n    public static Song spidersDen;\n    public static Song crimsonIsle;\n    public static Song kuudra;\n    public static Song end;\n    public static Song park;\n\n    static int curPhase = 0;\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        reset();\n    }\n\n    @SubscribeEvent(priority = EventPriority.LOW)\n    public void onTick(TickEvent.ClientTickEvent event) throws UnsupportedAudioFileException, LineUnavailableException, IOException {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n        World world = mc.theWorld;\n        if (DankersSkyblockMod.tickAmount % 10 == 0) {\n            if (world != null && player != null) {\n                if (Utils.isInDungeons()) {\n                    List<String> scoreboard = ScoreboardHandler.getSidebarLines();\n                    if (scoreboard.size() > 2) {\n                        String firstLine = ScoreboardHandler.cleanSB(scoreboard.get(scoreboard.size() - 1));\n                        String secondLine = ScoreboardHandler.cleanSB(scoreboard.get(scoreboard.size() - 2));\n                        if (firstLine.contains(\"30,30\") || // F1\n                            firstLine.contains(\"30,125\") || // F2\n                            firstLine.contains(\"30,225\") || // F3\n                            secondLine.contains(\"- Healthy\") || // F3\n                            firstLine.contains(\"30,344\") || // F4\n                            firstLine.contains(\"livid\") || // F5\n                            firstLine.contains(\"sadan\") || // F6\n                            firstLine.contains(\"maxor\") || // F7\n                            firstLine.contains(\"f7\")) {\n\n                            if (ModConfig.dungeonBossMusic) {\n                                switch (curPhase) {\n                                    case -1:\n                                        break;\n                                    case 2:\n                                        phase2.start();\n                                        break;\n                                    case 3:\n                                        phase3.start();\n                                        break;\n                                    case 4:\n                                        phase4.start();\n                                        break;\n                                    case 5:\n                                        phase5.start();\n                                        break;\n                                    default:\n                                        dungeonboss.start();\n                                }\n                            }\n                        }\n                    }\n                } else {\n                    switch (Utils.currentLocation) {\n                        case HUB:\n                            if (ModConfig.hubMusic) hub.start();\n                            break;\n                        case PRIVATE_ISLAND:\n                            if (ModConfig.islandMusic) island.start();\n                            break;\n                        case DUNGEON_HUB:\n                            if (ModConfig.dungeonHubMusic) dungeonHub.start();\n                            break;\n                        case FARMING_ISLANDS:\n                            if (ModConfig.farmingIslandsMusic) farmingIslands.start();\n                            break;\n                        case GARDEN:\n                            if (ModConfig.gardenMusic) garden.start();\n                            break;\n                        case GOLD_MINE:\n                            if (ModConfig.goldMineMusic) goldMine.start();\n                            break;\n                        case DEEP_CAVERNS:\n                            if (ModConfig.deepCavernsMusic) deepCaverns.start();\n                            break;\n                        case DWARVEN_MINES:\n                            if (ModConfig.dwarvenMinesMusic) dwarvenMines.start();\n                            break;\n                        case CRYSTAL_HOLLOWS:\n                            if (ModConfig.crystalHollowsMusic) crystalHollows.start();\n                            break;\n                        case SPIDERS_DEN:\n                            if (ModConfig.spidersDenMusic) spidersDen.start();\n                            break;\n                        case CRIMSON_ISLE:\n                            if (ModConfig.crimsonIsleMusic) crimsonIsle.start();\n                            break;\n                        case KUUDRA:\n                            if (ModConfig.kuudraMusic) kuudra.start();\n                            break;\n                        case END:\n                            if (ModConfig.endMusic) end.start();\n                            break;\n                        case PARK:\n                            if (ModConfig.parkMusic) park.start();\n                            break;\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent(receiveCanceled = true)\n    public void onChat(ClientChatReceivedEvent event) throws UnsupportedAudioFileException, LineUnavailableException, IOException {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (ModConfig.dungeonMusic && Utils.isInDungeons()) {\n            if (message.contains(\"[NPC] Mort: Here, I found this map when I first entered the dungeon.\")) {\n                dungeon.start();\n            }\n        }\n\n        if (Utils.isInDungeons()) {\n            if (ModConfig.dungeonBossMusic) {\n                if (phase2.hasSongs() && message.startsWith(\"[BOSS] Storm: Pathetic Maxor\")) {\n                    phase2.start();\n                    curPhase = 2;\n                } else if (phase3.hasSongs() && message.startsWith(\"[BOSS] Goldor: Who dares trespass into my domain?\")) {\n                    phase3.start();\n                    curPhase = 3;\n                } else if (phase4.hasSongs() && message.startsWith(\"[BOSS] Necron: You went further than any human before\")) {\n                    phase4.start();\n                    curPhase = 4;\n                } else if (phase5.hasSongs() && message.startsWith(\"[BOSS] \") && message.endsWith(\"You.. again?\")) {\n                    phase5.start();\n                    curPhase = 5;\n                }\n            }\n\n            if (message.contains(\":\")) return;\n\n            if (message.contains(\"EXTRA STATS \")) {\n                curPhase = -1; // force no play\n                dungeonboss.stop();\n                bloodroom.stop();\n                dungeon.stop();\n                phase2.stop();\n                phase3.stop();\n                phase4.stop();\n                phase5.stop();\n            } else if (message.contains(\"The BLOOD DOOR has been opened!\")) {\n                dungeon.stop();\n                if (ModConfig.bloodRoomMusic) bloodroom.start();\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onSound(PlaySoundEvent event) {\n        if (ModConfig.disableHypixelMusic && cancelNotes && event.name.startsWith(\"note.\")) {\n            event.result = null;\n        }\n    }\n\n    @SubscribeEvent\n    public void postConfigInit(PostConfigInitEvent event) {\n        init(event.configDirectory);\n    }\n\n    public static void init(String configDirectory) {\n        if (configDirectory == null) return;\n        File directory = new File(configDirectory + \"/dsmmusic\");\n        if (!directory.exists()) directory.mkdir();\n\n        reset();\n\n        dungeonboss = new Song(directory, \"dungeonboss\", ModConfig.dungeonBossVolume);\n        bloodroom = new Song(directory, \"bloodroom\", ModConfig.bloodRoomVolume);\n        dungeon = new Song(directory, \"dungeon\", ModConfig.dungeonVolume);\n        phase2 = new Song(directory, \"phasetwo\", ModConfig.phase2Volume);\n        phase3 = new Song(directory, \"phasethree\", ModConfig.phase3Volume);\n        phase4 = new Song(directory, \"phasefour\", ModConfig.phase4Volume);\n        phase5 = new Song(directory, \"phasefive\", ModConfig.phase5Volume);\n        hub = new Song(directory, \"hub\", ModConfig.hubVolume);\n        island = new Song(directory, \"island\", ModConfig.islandVolume);\n        dungeonHub = new Song(directory, \"dungeonhub\", ModConfig.dungeonHubVolume);\n        farmingIslands = new Song(directory, \"farmingislands\", ModConfig.farmingIslandsVolume);\n        garden = new Song(directory, \"garden\", ModConfig.gardenVolume);\n        goldMine = new Song(directory, \"goldmine\", ModConfig.goldMineVolume);\n        deepCaverns = new Song(directory, \"deepcaverns\", ModConfig.deepCavernsVolume);\n        dwarvenMines = new Song(directory, \"dwarvenmines\", ModConfig.dwarvenMinesVolume);\n        crystalHollows = new Song(directory, \"crystalhollows\", ModConfig.crystalHollowsVolume);\n        spidersDen = new Song(directory, \"spidersden\", ModConfig.spidersDenVolume);\n        crimsonIsle = new Song(directory, \"crimsonisle\", ModConfig.crimsonIsleVolume);\n        kuudra = new Song(directory, \"kuudra\", ModConfig.kuudraVolume);\n        end = new Song(directory, \"end\", ModConfig.endVolume);\n        park = new Song(directory, \"park\", ModConfig.parkVolume);\n    }\n\n    public static void reset() {\n        if (dungeonboss != null) dungeonboss.stop();\n        if (bloodroom != null) bloodroom.stop();\n        if (dungeon != null) dungeon.stop();\n        if (phase2 != null) phase2.stop();\n        if (phase3 != null) phase3.stop();\n        if (phase4 != null) phase4.stop();\n        if (phase5 != null) phase5.stop();\n        if (hub != null) hub.stop();\n        if (island != null) island.stop();\n        if (dungeonHub != null) dungeonHub.stop();\n        if (farmingIslands != null) farmingIslands.stop();\n        if (garden != null) garden.stop();\n        if (goldMine != null) goldMine.stop();\n        if (deepCaverns != null) deepCaverns.stop();\n        if (dwarvenMines != null) dwarvenMines.stop();\n        if (crystalHollows != null) crystalHollows.stop();\n        if (spidersDen != null) spidersDen.stop();\n        if (crimsonIsle != null) crimsonIsle.stop();\n        if (kuudra != null) kuudra.stop();\n        if (end != null) end.stop();\n        if (park != null) park.stop();\n        curPhase = 0;\n    }\n\n    public static class Song {\n\n        public Clip music;\n        private final List<File> playlist = new ArrayList<>();\n        private int volume;\n\n        public Song(File directory, String songName, int volume) {\n            File[] files = directory.listFiles();\n            if (files != null) {\n                for (File file : files) {\n                    if (!file.isDirectory() && file.getName().matches(songName + \"\\\\d*(?:\\\\.wav)?\\\\.wav\")) { // .wav.wav moment\n                        playlist.add(file);\n                        System.out.println(\"Added \" + file.getName() + \" to \" + songName + \" playlist.\");\n                    }\n                }\n            }\n\n            this.volume = volume;\n        }\n\n        public void start() throws UnsupportedAudioFileException, LineUnavailableException, IOException {\n\n            try {\n                if (music == null) music = AudioSystem.getClip();\n                if (!music.isRunning()) {\n                    reset();\n                    shuffle();\n                    setVolume(volume);\n                    cancelNotes = true;\n                    music.setMicrosecondPosition(0);\n                    music.start();\n                }\n            } catch (UnsupportedAudioFileException ex) {\n                ex.printStackTrace();\n\n                EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n                if (player != null) {\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Attempted to play non .wav file. Please use a .wav converter instead of renaming the file.\"));\n                }\n            } catch (IllegalArgumentException ex) {\n                ex.printStackTrace();\n\n                EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n                if (player != null) {\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Could not play music. Are your audio drivers up to date?\"));\n                }\n            }\n        }\n\n        public void stop() {\n            cancelNotes = false;\n            if (music != null) {\n                music.stop();\n                if (music.isOpen()) music.close();\n            }\n        }\n\n        public void shuffle() throws LineUnavailableException, UnsupportedAudioFileException, IOException {\n            if (playlist.size() > 0) {\n                File file = playlist.get(new Random().nextInt(playlist.size()));\n                music = AudioSystem.getClip();\n                AudioInputStream ais = AudioSystem.getAudioInputStream(file);\n                music.open(ais);\n            }\n        }\n\n        public boolean setVolume(int volume) {\n            this.volume = volume;\n            if (playlist.size() < 1) return false;\n            if (volume <= 0 || volume > 100) {\n                EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n                if (player != null) player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Volume can only be set between 0% and 100%.\"));\n                return false;\n            }\n\n            if (music != null) {\n                float decibels = (float) (20 * Math.log10(volume / 100.0));\n                FloatControl control = (FloatControl) music.getControl(FloatControl.Type.MASTER_GAIN);\n                if (decibels <= control.getMinimum() || decibels >= control.getMaximum()) return false;\n                control.setValue(decibels);\n            }\n\n            return true;\n        }\n\n        public boolean hasSongs() {\n            return playlist.size() > 0;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/Debug.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.PacketReadEvent;\nimport me.Danker.events.PacketWriteEvent;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.network.play.client.C01PacketChatMessage;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class Debug {\n\n    @SubscribeEvent\n    public void onPacketRead(PacketReadEvent event) {\n        if (!ModConfig.debug) return;\n\n        EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n\n        if (ModConfig.debugPacketsIn) {\n            String name = \"Packet recieved: \" + event.packet.getClass().getSimpleName();\n            if (player != null) player.addChatMessage(new ChatComponentText(name));\n            System.out.println(name);\n        }\n    }\n\n    @SubscribeEvent\n    public void onPacketWrite(PacketWriteEvent event) {\n        if (!ModConfig.debug) return;\n\n        EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n\n        if (ModConfig.debugPacketsOut) {\n            String name = \"Packet sent: \" + event.packet.getClass().getSimpleName();\n            if (player != null) player.addChatMessage(new ChatComponentText(name));\n            System.out.println(name);\n        }\n\n        if (ModConfig.debugChat && event.packet instanceof C01PacketChatMessage) {\n            C01PacketChatMessage packet = (C01PacketChatMessage) event.packet;\n\n            String message = packet.getMessage();\n            if (message.charAt(0) == '/') {\n                message = \"Command sent: \" + message;\n            } else {\n                message = \"Message sent: \" + message;\n            }\n\n            if (player != null) player.addChatMessage(new ChatComponentText(message));\n            System.out.println(message);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/DisableMovement.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.settings.GameSettings;\nimport net.minecraft.client.settings.KeyBinding;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.InputEvent;\n\npublic class DisableMovement {\n\n    static boolean disableMouse = false;\n    static float sens = 0.5F;\n\n    static boolean disableWS = false;\n    static boolean disableAD = false;\n\n    @SubscribeEvent\n    public void onKey(InputEvent.KeyInputEvent event) {\n        Minecraft mc = Minecraft.getMinecraft();\n        GameSettings gs = mc.gameSettings;\n        if (disableWS) {\n            if (gs.keyBindForward.isPressed() || gs.keyBindBack.isPressed()) {\n                KeyBinding.setKeyBindState(gs.keyBindForward.getKeyCode(), false);\n                KeyBinding.setKeyBindState(gs.keyBindBack.getKeyCode(), false);\n                mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + \"Movement blocked. Press \" + ModConfig.disableWS.getDisplay() + \" to re-enable.\"));\n            }\n        }\n        if (disableAD) {\n            if (gs.keyBindLeft.isPressed() || gs.keyBindRight.isPressed()) {\n                KeyBinding.setKeyBindState(gs.keyBindLeft.getKeyCode(), false);\n                KeyBinding.setKeyBindState(gs.keyBindRight.getKeyCode(), false);\n                mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + \"Movement blocked. Press \" + ModConfig.disableAD.getDisplay() + \" to re-enable.\"));\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldUnload(WorldEvent.Unload event) {\n        if (disableMouse) {\n            GameSettings gs = Minecraft.getMinecraft().gameSettings;\n            gs.mouseSensitivity = sens;\n            gs.saveOptions();\n        }\n\n        disableMouse = false;\n        disableWS = false;\n        disableAD = false;\n    }\n\n    public static void onDisableMouse() {\n        disableMouse = !disableMouse;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        GameSettings gs = mc.gameSettings;\n        EntityPlayer player = mc.thePlayer;\n\n        if (disableMouse) {\n            sens = gs.mouseSensitivity;\n            gs.mouseSensitivity = -1/3F;\n            player.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN + \"Disabled moving mouse.\"));\n        } else {\n            gs.mouseSensitivity = sens;\n            gs.saveOptions();\n            player.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN + \"Enabled moving mouse.\"));\n        }\n    }\n\n    public static void onDisableWS() {\n        disableWS = !disableWS;\n\n        EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n        if (disableWS) {\n            player.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN + \"Disabled moving forwards/back.\"));\n        } else {\n            player.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN + \"Enabled moving forwards/back.\"));\n        }\n    }\n\n    public static void onDisableAD() {\n        disableAD = !disableAD;\n\n        EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n        if (disableAD) {\n            player.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN + \"Disabled moving left/right.\"));\n        } else {\n            player.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN + \"Enabled moving left/right.\"));\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/DrillFix.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.PacketReadEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.init.Items;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.network.play.server.S2FPacketSetSlot;\nimport net.minecraft.network.play.server.S30PacketWindowItems;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class DrillFix {\n\n    // https://github.com/BiscuitDevelopment/SkyblockAddons/blob/v1.2.0/src/main/java/codes/biscuit/skyblockaddons/mixins/MixinNetHandlerPlayClient.java\n    @SubscribeEvent\n    public void onPacketRead(PacketReadEvent event) {\n        if (ModConfig.drillFix && Utils.inSkyblock) {\n            Minecraft mc = Minecraft.getMinecraft();\n            EntityPlayer player = mc.thePlayer;\n            boolean isDown = mc.gameSettings.keyBindAttack.isKeyDown();\n\n            if (player == null || player.inventory == null) return;\n\n            if (event.packet instanceof S2FPacketSetSlot) {\n                S2FPacketSetSlot packet = (S2FPacketSetSlot) event.packet;\n                int windowId = packet.func_149175_c();\n                int slot = packet.func_149173_d();\n                ItemStack item = packet.func_149174_e();\n\n                if (item != null && windowId == 0 && slot - 36 == player.inventory.currentItem) {\n                    if (item.getItem().equals(Items.prismarine_shard) && isDown) {\n                        event.setCanceled(true);\n                    }\n                }\n            } else if (event.packet instanceof S30PacketWindowItems) {\n                S30PacketWindowItems packet = (S30PacketWindowItems) event.packet;\n                ItemStack[] items = packet.getItemStacks();\n\n                if (items.length == 45) {\n                    int slot = player.inventory.currentItem + 36;\n                    ItemStack item = items[slot];\n\n                    if (item != null) {\n                        if (item.getItem().equals(Items.prismarine_shard) && isDown) {\n                            items[slot] = player.inventory.getCurrentItem();\n                            event.packet = packet;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/DungeonScore.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.locations.DungeonFloor;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.network.NetworkPlayerInfo;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.MathHelper;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.Collection;\n\npublic class DungeonScore {\n\n    static int failedPuzzles;\n    static int deaths;\n    static int skillScore;\n    static String secrets;\n    static int exploreScore;\n    static int timeScore;\n    static int bonusScore;\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        failedPuzzles = 0;\n        deaths = 0;\n        skillScore = 100;\n        secrets = \"\";\n        exploreScore = 0;\n        timeScore = 100;\n        bonusScore = 0;\n    }\n\n    @SubscribeEvent(receiveCanceled = true)\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!ModConfig.dungeonScoreHud.isEnabled() || !Utils.isInDungeons()) return;\n\n        if (message.contains(\":\")) return;\n\n        if (message.contains(\"PUZZLE FAIL! \") || message.contains(\"chose the wrong answer! I shall never forget this moment\")) {\n            failedPuzzles++;\n        } else if (message.contains(\" and became a ghost.\")) {\n            deaths++;\n        }\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        if (!ModConfig.dungeonScoreHud.isEnabled() || !Utils.isInDungeons()) return;\n\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            int missingPuzzles = 0;\n            double openedRooms = 0;\n            double completedRooms = 0;\n            double roomScore = 0;\n            double secretScore = 0;\n\n            if (Minecraft.getMinecraft().getNetHandler() == null) return;\n            Collection<NetworkPlayerInfo> players = Minecraft.getMinecraft().getNetHandler().getPlayerInfoMap();\n            for (NetworkPlayerInfo player : players) {\n                if (player == null || player.getDisplayName() == null) continue;\n                String display = player.getDisplayName().getUnformattedText();\n\n                if (display.startsWith(\" Opened Rooms: \")) {\n                    openedRooms = Double.parseDouble(display.replaceAll(\"\\\\D\", \"\"));\n                } else if (display.startsWith(\" Completed Rooms: \")) {\n                    completedRooms = Double.parseDouble(display.replaceAll(\"\\\\D\", \"\"));\n                } else if (display.startsWith(\" Secrets Found: \") && display.endsWith(\"%\")) {\n                    secrets = player.getDisplayName().getFormattedText();\n\n                    double secretCount = Double.parseDouble(display.replaceAll(\"[^\\\\d.]\", \"\"));\n\n                    switch (Utils.currentFloor) {\n                        case F1:\n                            secretScore = secretCount / 30D;\n                            break;\n                        case F2:\n                            secretScore = secretCount / 40D;\n                            break;\n                        case F3:\n                            secretScore = secretCount / 50D;\n                            break;\n                        case F4:\n                            secretScore = secretCount / 60D;\n                            break;\n                        case F5:\n                            secretScore = secretCount / 70D;\n                            break;\n                        case F6:\n                            secretScore = secretCount / 85D;\n                            break;\n                        default:\n                            secretScore = secretCount / 100D;\n                    }\n                } else if (display.startsWith(\"Time Elapsed: \")) {\n                    String timeText = display.substring(display.indexOf(\":\") + 2).replaceAll(\"\\\\s\", \"\");\n                    int minutes = Integer.parseInt(timeText.substring(0, timeText.indexOf(\"m\")));\n                    int seconds = Integer.parseInt(timeText.substring(timeText.indexOf(\"m\") + 1, timeText.indexOf(\"s\")));\n                    int time = minutes * 60 + seconds;\n\n                    if (Utils.currentFloor == DungeonFloor.F2) time -= 120;\n\n                    int base;\n                    switch (Utils.currentFloor) {\n                        case F1:\n                        case F2:\n                        case F3:\n                        case F5:\n                            base = 600;\n                            break;\n                        case F4:\n                        case F6:\n                        case F7:\n                            base = 720;\n                            break;\n                        default:\n                            base = 480;\n                    }\n\n                    if (time <= base) {\n                        timeScore = 100;\n                    } else if (time <= base + 100) {\n                        timeScore = (int) Math.ceil(100 - 0.1 * (time - base));\n                    } else if (time <= base + 500) {\n                        timeScore = (int) Math.ceil(90 - 0.05 * (time - base - 100));\n                    } else if (time < base + 2600) {\n                        timeScore = (int) Math.ceil(70 - (1/30D) * (time - base - 1100));\n                    } else {\n                        timeScore = 0;\n                    }\n                } else if (display.startsWith(\" Crypts: \")) {\n                    bonusScore = MathHelper.clamp_int(Integer.parseInt(display.replaceAll(\"\\\\D\", \"\")), 0, 5);\n                } else if (display.contains(\"[✦]\")) {\n                    missingPuzzles++;\n                }\n            }\n\n            if (openedRooms != 0) {\n                roomScore = completedRooms / openedRooms;\n            }\n\n            skillScore = MathHelper.clamp_int(100 - 14 * (failedPuzzles + missingPuzzles) - 2 * deaths, 0, 100);\n            exploreScore = (int) (60 * roomScore + 40 * MathHelper.clamp_double(secretScore, 0, 1));\n        }\n    }\n\n    public static class DungeonScoreHud extends Hud {\n\n        @Exclude\n        String exampleText = \" Secrets Found: \" + EnumChatFormatting.GREEN + \"100.0%\\n\" +\n                             EnumChatFormatting.GOLD + \"Skill:\\n\" +\n                             EnumChatFormatting.GOLD + \"Explore:\\n\" +\n                             EnumChatFormatting.GOLD + \"Speed:\\n\" +\n                             EnumChatFormatting.GOLD + \"Bonus:\\n\" +\n                             EnumChatFormatting.GOLD + \"Total:\";\n\n        @Exclude\n        String exampleNums = \"\\n\" +\n                             EnumChatFormatting.GOLD + \"100\\n\" +\n                             EnumChatFormatting.GOLD + \"100\\n\" +\n                             EnumChatFormatting.GOLD + \"100\\n\" +\n                             EnumChatFormatting.GOLD + \"5\\n\" +\n                             EnumChatFormatting.GOLD + \"305 \" + EnumChatFormatting.GRAY + \"(\" + EnumChatFormatting.GOLD + \"S+\" + EnumChatFormatting.GRAY + \")\";\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            Minecraft mc = Minecraft.getMinecraft();\n\n            if (example) {\n                TextRenderer.drawHUDText(exampleText, x, y, scale);\n                TextRenderer.drawHUDText(exampleNums, (int) (x + (80 * scale)), y, scale);\n                return;\n            }\n\n            if (enabled && Utils.isInDungeons()) {\n                int totalScore = skillScore + exploreScore + timeScore + bonusScore;\n                String total;\n                if (totalScore >= 300) {\n                    total = EnumChatFormatting.GOLD + \"S+\";\n                } else if (totalScore >= 270) {\n                    total = EnumChatFormatting.GOLD + \"S\";\n                } else if (totalScore >= 230) {\n                    total = EnumChatFormatting.DARK_PURPLE + \"A\";\n                } else if (totalScore >= 160) {\n                    total = EnumChatFormatting.GREEN + \"B\";\n                } else if (totalScore >= 100) {\n                    total = EnumChatFormatting.BLUE + \"C\";\n                } else {\n                    total = EnumChatFormatting.RED + \"D\";\n                }\n\n                String scoreText = secrets + \"\\n\" +\n                                   EnumChatFormatting.GOLD + \"Skill:\\n\" +\n                                   EnumChatFormatting.GOLD + \"Explore:\\n\" +\n                                   EnumChatFormatting.GOLD + \"Speed:\\n\" +\n                                   EnumChatFormatting.GOLD + \"Bonus:\\n\" +\n                                   EnumChatFormatting.GOLD + \"Total:\";\n                String score = \"\\n\" +\n                               EnumChatFormatting.GOLD + skillScore + \"\\n\" +\n                               EnumChatFormatting.GOLD + exploreScore + \"\\n\" +\n                               EnumChatFormatting.GOLD + timeScore + \"\\n\" +\n                               EnumChatFormatting.GOLD + bonusScore + \"\\n\" +\n                               EnumChatFormatting.GOLD + totalScore + EnumChatFormatting.GRAY + \" (\" + total + EnumChatFormatting.GRAY + \")\";\n                TextRenderer.drawHUDText(scoreText, x, y, scale);\n                TextRenderer.drawHUDText(score, (int) (x + (80 * scale)), y, scale);\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return (RenderUtils.getWidthFromText(exampleNums) + 80 * scale) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return RenderUtils.getHeightFromText(exampleNums) * scale;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/DungeonTimer.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Dropdown;\nimport cc.polyfrost.oneconfig.config.annotations.DualOption;\nimport cc.polyfrost.oneconfig.config.annotations.Number;\nimport cc.polyfrost.oneconfig.config.annotations.Switch;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport cc.polyfrost.oneconfig.utils.TickDelay;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonObject;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ModInitEvent;\nimport me.Danker.events.PostConfigInitEvent;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class DungeonTimer {\n\n    public static JsonObject timer = new JsonObject();\n    public static String configFile;\n\n    static ActiveTimer activeTimer = null;\n\n    static int witherDoors = 0;\n    static int dungeonDeaths = 0;\n    static int puzzleFails = 0;\n\n    public static JsonObject createEmpty() {\n        JsonObject timer = new JsonObject();\n\n        JsonArray f1 = getBasicSplits(EnumChatFormatting.GOLD + \"Bonzo Entry\", \"Bonzo\");\n        f1.add(createSplit(EnumChatFormatting.GOLD + \"Bonzo Phase 1\", \"\\\\[BOSS\\\\] Bonzo: Oh I'm dead!\"));\n        f1.add(getEndSplit(EnumChatFormatting.GOLD + \"Bonzo Phase 2\"));\n        timer.add(\"F1\", f1);\n        timer.add(\"M1\", Utils.deepCopy(f1));\n\n        JsonArray f2 = getBasicSplits(EnumChatFormatting.WHITE + \"Scarf Entry\", \"Scarf\");\n        f2.add(createSplit(EnumChatFormatting.WHITE + \"Scarf Phase 1\", \"\\\\[BOSS\\\\] Scarf: Those toys are not strong enough I see\\\\.\"));\n        f2.add(getEndSplit(EnumChatFormatting.WHITE + \"Scarf Phase 2\"));\n        timer.add(\"F2\", f2);\n        timer.add(\"M2\", Utils.deepCopy(f2));\n\n        JsonArray f3 = getBasicSplits(EnumChatFormatting.RED + \"Professor Entry\", \"The Professor\");\n        f3.add(createSplit(EnumChatFormatting.WHITE + \"Guardians\", \"\\\\[BOSS\\\\] The Professor: Oh\\\\? You found my Guardians' one weakness\\\\?\"));\n        f3.add(createSplit(EnumChatFormatting.RED + \"Professor\", \"\\\\[BOSS\\\\] The Professor: I see\\\\. You have forced me to use my ultimate technique\\\\.\"));\n        f3.add(getEndSplit(EnumChatFormatting.RED + \"Phase 2\"));\n        timer.add(\"F3\", f3);\n        timer.add(\"M3\", Utils.deepCopy(f3));\n\n        JsonArray f4 = getBasicSplits(EnumChatFormatting.RED + \"Thorn Entry\", \"Thorn\");\n        f4.add(getEndSplit(EnumChatFormatting.RED + \"Thorn\"));\n        timer.add(\"F4\", f4);\n        timer.add(\"M4\", Utils.deepCopy(f4));\n\n        JsonArray f5 = getBasicSplits(EnumChatFormatting.RED + \"Livid Entry\", \"Livid\");\n        f5.add(getEndSplit(EnumChatFormatting.RED + \"Livid\"));\n        timer.add(\"F5\", f5);\n        timer.add(\"M5\", Utils.deepCopy(f5));\n\n        JsonArray f6 = getBasicSplits(EnumChatFormatting.RED + \"Sadan Entry\", \"Sadan\");\n        f6.add(createSplit(EnumChatFormatting.LIGHT_PURPLE + \"Terracottas\", \"\\\\[BOSS\\\\] Sadan: ENOUGH!\"));\n        f6.add(createSplit(EnumChatFormatting.GREEN + \"Giants\", \"\\\\[BOSS\\\\] Sadan: You did it\\\\. I understand now, you have earned my respect\\\\.\"));\n        f6.add(getEndSplit(EnumChatFormatting.RED + \"Sadan\"));\n        timer.add(\"F6\", f6);\n        timer.add(\"M6\", Utils.deepCopy(f6));\n\n        JsonArray f7 = getBasicSplits(EnumChatFormatting.RED + \"Boss Entry\", \"Maxor\");\n        f7.add(createSplit(EnumChatFormatting.AQUA + \"Maxor\", \"\\\\[BOSS\\\\] Storm: Pathetic Maxor, just like expected\\\\.\"));\n        f7.add(createSplit(EnumChatFormatting.RED + \"Storm\", \"\\\\[BOSS\\\\] Storm: At least my son died by your hands\\\\.\"));\n        f7.add(createSplit(EnumChatFormatting.GOLD + \"Terminals\", \"The Core entrance is opening!\"));\n        f7.add(createSplit(EnumChatFormatting.GOLD + \"Goldor\", \"\\\\[BOSS\\\\] Goldor: \\\\.\\\\.\\\\.\\\\.\"));\n        f7.add(createSplit(EnumChatFormatting.DARK_RED + \"Necron\", \"\\\\[BOSS\\\\] Necron: All this, for nothing\\\\.\\\\.\\\\.\"));\n        timer.add(\"F7\", f7);\n        JsonArray m7 = Utils.deepCopy(f7);\n        m7.add(getEndSplit(EnumChatFormatting.GRAY + \"Wither King\"));\n        timer.add(\"M7\", m7);\n\n        return timer;\n    }\n\n    public static JsonObject createSplit(String name, String triggerRegex) {\n        JsonObject split = new JsonObject();\n\n        split.addProperty(\"name\", name);\n        split.addProperty(\"trigger\", triggerRegex);\n        split.addProperty(\"pb\", -1);\n        split.addProperty(\"gold\", -1);\n\n        return split;\n    }\n\n    public static JsonArray getBasicSplits(String entryName, String bossName) {\n        JsonArray splits = new JsonArray();\n\n        splits.add(createSplit(EnumChatFormatting.DARK_RED + \"Blood Open\", \"\\\\[BOSS\\\\] The Watcher: .*\"));\n        splits.add(createSplit(EnumChatFormatting.RED + \"Blood Clear\", \"\\\\[BOSS\\\\] The Watcher: You have proven yourself. You may pass.\"));\n        splits.add(createSplit(entryName, \"\\\\[BOSS\\\\] \" + bossName + \":.*\"));\n\n        return splits;\n    }\n\n    public static JsonObject getEndSplit(String name) {\n        return createSplit(name, \".* {3}Team Score:.*\");\n    }\n\n    @SubscribeEvent\n    public void init(ModInitEvent event) {\n        configFile = event.configDirectory + \"/dsm/dsmdungeonsplits.json\";\n    }\n\n    @SubscribeEvent\n    public void postConfigInit(PostConfigInitEvent event) {\n        if (timer.entrySet().isEmpty()) timer = createEmpty();\n        save();\n    }\n\n    @SubscribeEvent(receiveCanceled = true)\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!Utils.isInDungeons()) return;\n        if (event.type == 2) return;\n\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (activeTimer != null && !activeTimer.isTimerDone()) {\n            Matcher matcher = activeTimer.getCurrentSplit().trigger.matcher(message);\n            if (matcher.matches()) {\n                activeTimer.split();\n            }\n        }\n\n        if (message.contains(\":\")) return;\n\n        if (activeTimer != null && message.contains(\"Starting in 1 second\")) {\n            activeTimer.getFirstSplit().startTime = System.currentTimeMillis() + 1000D;\n        } else if (message.contains(\"PUZZLE FAIL! \") || message.contains(\"chose the wrong answer! I shall never forget this moment\")) {\n            puzzleFails++;\n        } else if (message.contains(\" opened a WITHER door!\")) {\n            witherDoors++;\n        } else if (message.contains(\" and became a ghost.\")) {\n            dungeonDeaths++;\n        }\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        if (!ModConfig.dungeonTimerHud.isEnabled()) return;\n        if (activeTimer != null) return;\n\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            String currentFloor = Utils.currentFloor.toString();\n\n            if (timer.has(currentFloor)) {\n                activeTimer = new ActiveTimer(timer.getAsJsonArray(currentFloor));\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        activeTimer = null;\n        witherDoors = 0;\n        dungeonDeaths = 0;\n        puzzleFails = 0;\n    }\n\n    public static void save() {\n        try (FileWriter writer = new FileWriter(configFile)) {\n            new GsonBuilder().create().toJson(timer, writer);\n            writer.flush();\n        } catch (IOException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    static class ActiveTimer {\n\n        ArrayList<Split> splits = new ArrayList<>();\n        int currentIndex = 0;\n\n        public double sumOfBest = 0;\n\n        public ActiveTimer(JsonArray floor) {\n            boolean fullRun = true;\n\n            for (JsonElement element : floor) {\n                Split split = new Split(element.getAsJsonObject());\n                splits.add(split);\n\n                if (split.goldTime < 0D) {\n                    sumOfBest = -1;\n                    fullRun = false;\n                } else if (fullRun && split.goldTime > 0D) {\n                    sumOfBest += split.goldTime;\n                }\n            }\n        }\n\n        public boolean isTimerDone() {\n            return currentIndex >= splits.size();\n        }\n\n        public Split getCurrentSplit() {\n            return splits.get(currentIndex);\n        }\n\n        public Split getFirstSplit() {\n            return splits.get(0);\n        }\n\n        public void split() {\n            EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n            double time = System.currentTimeMillis();\n\n            Split curSplit = getCurrentSplit();\n            curSplit.endTime = time;\n            if (curSplit.goldTime < 0D || curSplit.getTime() < curSplit.goldTime) {\n                curSplit.splitObj.addProperty(\"gold\", curSplit.getTime()); // set gold\n                sumOfBest -= curSplit.goldTime - curSplit.getTime();\n            }\n\n            currentIndex++;\n\n            if (currentIndex < splits.size()) {\n                getCurrentSplit().startTime = time;\n\n                if (DungeonTimerHud.inChat) {\n                    player.addChatMessage(new ChatComponentText(curSplit.getFullText()));\n                }\n            } else {\n                double sum = 0D;\n                double pbSum = 0D;\n\n                for (Split split : splits) {\n                    sum += split.getTime();\n                    pbSum += split.pbTime;\n                }\n\n                if (pbSum < 0D || sum < pbSum) {\n                    for (Split split : splits) {\n                        split.splitObj.addProperty(\"pb\", split.getTime()); // replace times with pb\n                    }\n                }\n\n                if (DungeonTimerHud.inChat) {\n                    new TickDelay(() -> {\n                        for (Split split : activeTimer.splits) {\n                            player.addChatMessage(new ChatComponentText(split.getFullText()));\n                        }\n                    }, 1);\n                }\n            }\n            save();\n        }\n\n        public String getSumOfBest() {\n            if (sumOfBest < 0D) return \"\";\n\n            int minutes = (int) (sumOfBest / 60);\n            double seconds = sumOfBest % 60;\n\n            if (minutes == 0) {\n                return String.format(\"%.\" + DungeonTimerHud.decimals + \"f\", seconds) + \"s\";\n            } else {\n                return minutes + \"m\" + String.format(\"%.\" + DungeonTimerHud.decimals + \"f\", seconds) + \"s\";\n            }\n        }\n\n        public String getBestPossibleTime() {\n            if (sumOfBest < 0D) return \"\"; // requires all splits to have golds\n\n            double sum = 0D;\n            for (Split split : splits) {\n                if (split.startTime < 0D || (split.endTime < 0D && split.getTime() < split.goldTime)) {\n                    // hasnt started or split hasnt reached gold split\n                    sum += split.goldTime;\n                } else {\n                    sum += split.getTime();\n                }\n            }\n\n            int minutes = (int) (sum / 60);\n            double seconds = sum % 60;\n\n            if (minutes == 0) {\n                return String.format(\"%.\" + DungeonTimerHud.decimals + \"f\", seconds) + \"s\";\n            } else {\n                return minutes + \"m\" + String.format(\"%.\" + DungeonTimerHud.decimals + \"f\", seconds) + \"s\";\n            }\n        }\n\n    }\n\n    static class Split {\n\n        public JsonObject splitObj;\n        public String name;\n        public Pattern trigger;\n        public double startTime = -1;\n        public double endTime = -1;\n        public double pbTime;\n        public double goldTime;\n\n        public Split(JsonObject split) {\n            this.splitObj = split;\n            this.name = split.get(\"name\").getAsString();\n            this.trigger = Pattern.compile(split.get(\"trigger\").getAsString());\n            this.pbTime = split.get(\"pb\").getAsDouble();\n            this.goldTime = split.get(\"gold\").getAsDouble();\n        }\n\n        public double getTime() {\n            if (startTime < 0D) return 0D;\n            if (endTime < 0D) return (System.currentTimeMillis() - startTime) / 1000D;\n            return (endTime - startTime) / 1000D;\n        }\n\n        public String getColouredTime() {\n            String time = String.format(\"%.\" + DungeonTimerHud.decimals + \"f\", getTime()) + \"s\";\n\n            if (startTime < 0D) return ModConfig.getColour(DungeonTimerHud.timerColour) + time;\n            if (endTime > 0D && (goldTime < 0D || getTime() < goldTime)) return ModConfig.getColour(DungeonTimerHud.goldColour) + time;\n            if (!DungeonTimerHud.compareGold && (pbTime < 0D || getTime() < pbTime)) return ModConfig.getColour(DungeonTimerHud.greenColour) + time;\n            if (DungeonTimerHud.compareGold && (goldTime < 0D || getTime() < goldTime)) return ModConfig.getColour(DungeonTimerHud.greenColour) + time;\n            return ModConfig.getColour(DungeonTimerHud.redColour) + time;\n        }\n\n        public String getPBDiff() {\n            if (goldTime < 0D || pbTime < 0D) return \"\";\n            if (getTime() < goldTime && endTime < 0D) return \"\";\n            if (DungeonTimerHud.compareGold) {\n                return \" (\" + String.format(\"%+.\" + DungeonTimerHud.decimals + \"f\", getTime() - goldTime) + \"s)\";\n            }\n            return \" (\" + String.format(\"%+.\" + DungeonTimerHud.decimals + \"f\", getTime() - pbTime) + \"s)\";\n        }\n\n        public String getFullText() {\n            String text = name + \": \" + getColouredTime();\n            if (DungeonTimerHud.showDiff) text += getPBDiff();\n            return text;\n        }\n\n    }\n\n    public static class DungeonTimerHud extends Hud {\n\n        @Dropdown(\n                name = \"Timer Color\",\n                options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n        )\n        public static int timerColour = 7;\n\n        @Dropdown(\n                name = \"Green Split Color\",\n                options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n        )\n        public static int greenColour = 10;\n\n        @Dropdown(\n                name = \"Red Split Color\",\n                options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n        )\n        public static int redColour = 12;\n\n        @Dropdown(\n                name = \"Gold Split Color\",\n                options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n        )\n        public static int goldColour = 6;\n\n        @Number(\n                name = \"Timer Decimal Places\",\n                min = 0, max = 5\n        )\n        public static int decimals = 2;\n\n        @Switch(\n                name = \"Show Difference\",\n                description = \"Show the time difference from your personal best run.\"\n        )\n        public static boolean showDiff = false;\n\n        @DualOption(\n                name = \"Compare Difference Against\",\n                left = \"PB\",\n                right = \"Gold\"\n        )\n        public static boolean compareGold = false;\n\n        @Switch(\n                name = \"Show Current Pace\",\n                description = \"Shows your current pace, using your gold splits as a best possible time.\"\n        )\n        public static boolean bestPossibleTime = false;\n\n        @Switch(\n                name = \"Show Sum of Best\",\n                description = \"Show sum of gold splits in the timer.\"\n        )\n        public static boolean sumOfBest = false;\n\n        @Switch(\n                name = \"Show Misc. Info\",\n                description = \"Show miscellaneous info about the dungeon run.\"\n        )\n        public static boolean extraInfo = false;\n\n        @Switch(\n                name = \"Show Split Info in Chat\",\n                description = \"Shows split information in chat after a split and after a dungeon run.\"\n        )\n        public static boolean inChat = false;\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            if (example) {\n                TextRenderer.drawHUDText(getExampleText(), x, y, scale);\n                TextRenderer.drawHUDText(getExampleNums(), (int) (x + (90 * scale)), y, scale);\n                return;\n            }\n\n            if (enabled && Utils.isInDungeons()) {\n                if (activeTimer != null) {\n                    StringBuilder dungeonTimerText = new StringBuilder();\n                    StringBuilder dungeonTimers = new StringBuilder();\n\n                    for (Split split : activeTimer.splits) {\n                        dungeonTimerText.append(split.name).append(\":\\n\");\n                        dungeonTimers.append(split.getColouredTime());\n                        if (showDiff) dungeonTimers.append(split.getPBDiff());\n                        dungeonTimers.append(\"\\n\");\n                    }\n\n                    if (bestPossibleTime) {\n                        dungeonTimerText.append(EnumChatFormatting.GOLD).append(\"Current Pace:\\n\");\n                        dungeonTimers.append(EnumChatFormatting.GOLD).append(activeTimer.getBestPossibleTime()).append(\"\\n\");\n                    }\n\n                    if (sumOfBest) {\n                        dungeonTimerText.append(EnumChatFormatting.GOLD).append(\"Sum of Best:\\n\");\n                        dungeonTimers.append(EnumChatFormatting.GOLD).append(activeTimer.getSumOfBest()).append(\"\\n\");\n                    }\n\n                    if (extraInfo) {\n                        dungeonTimerText.append(EnumChatFormatting.GRAY).append(\"Wither Doors:\\n\")\n                                        .append(EnumChatFormatting.YELLOW).append(\"Deaths:\\n\")\n                                        .append(EnumChatFormatting.YELLOW).append(\"Puzzle Fails:\");\n                        dungeonTimers.append(EnumChatFormatting.GRAY).append(witherDoors).append(\"\\n\")\n                                     .append(EnumChatFormatting.YELLOW).append(dungeonDeaths).append(\"\\n\")\n                                     .append(EnumChatFormatting.YELLOW).append(puzzleFails);\n                    }\n\n                    TextRenderer.drawHUDText(dungeonTimerText.toString(), x, y, scale);\n                    TextRenderer.drawHUDText(dungeonTimers.toString(), (int) (x + (90 * scale)), y, scale);\n                }\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return (RenderUtils.getWidthFromText(getExampleNums()) + 90 * scale) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return RenderUtils.getHeightFromText(getExampleNums()) * scale;\n        }\n        \n        String getExampleText() {\n            String exampleText = EnumChatFormatting.DARK_RED + \"Blood Open:\\n\" +\n                                 EnumChatFormatting.RED + \"Blood Clear:\\n\" +\n                                 EnumChatFormatting.RED + \"Boss Entry:\\n\" +\n                                 EnumChatFormatting.AQUA + \"Maxor:\\n\" +\n                                 EnumChatFormatting.RED + \"Storm:\\n\" +\n                                 EnumChatFormatting.GOLD + \"Terminals:\\n\" +\n                                 EnumChatFormatting.GOLD + \"Goldor:\\n\" +\n                                 EnumChatFormatting.DARK_RED + \"Necron:\\n\" +\n                                 EnumChatFormatting.GRAY + \"Wither King:\";\n\n            if (bestPossibleTime) {\n                exampleText += \"\\n\" + EnumChatFormatting.GOLD + \"Current Pace:\";\n            }\n\n            if (sumOfBest) {\n                exampleText += \"\\n\" + EnumChatFormatting.GOLD + \"Sum of Best:\";\n            }\n\n            if (extraInfo) {\n                exampleText += EnumChatFormatting.GRAY + \"\\nWither Doors:\\n\" +\n                               EnumChatFormatting.YELLOW + \"Deaths:\\n\" +\n                               EnumChatFormatting.YELLOW + \"Puzzle Fails:\";\n            }\n\n            return exampleText;\n        }\n\n        String getExampleNums() {\n            String exampleNums = ModConfig.getColour(goldColour) + \"175.56s\\n\" +\n                                 ModConfig.getColour(greenColour) + \"130.63s\\n\" +\n                                 ModConfig.getColour(greenColour) + \"458.94s\\n\" +\n                                 ModConfig.getColour(redColour) + \"49.93s\\n\" +\n                                 ModConfig.getColour(goldColour) + \"73.75s\\n\" +\n                                 ModConfig.getColour(greenColour) + \"227.65s\\n\" +\n                                 ModConfig.getColour(redColour) + \"17.56s\\n\" +\n                                 ModConfig.getColour(timerColour) + \"32.19s\\n\" +\n                                 ModConfig.getColour(timerColour) + \"0.00s\";\n\n            if (showDiff) {\n                exampleNums = ModConfig.getColour(goldColour) + \"175.56s (-12.78s)\\n\" +\n                              ModConfig.getColour(greenColour) + \"130.63s (-2.76s)\\n\" +\n                              ModConfig.getColour(greenColour) + \"458.94s (-5.62s)\\n\" +\n                              ModConfig.getColour(redColour) + \"49.93s (+1.21s)\\n\" +\n                              ModConfig.getColour(goldColour) + \"73.75s (-1.69s)\\n\" +\n                              ModConfig.getColour(greenColour) + \"227.65s (-13.52s)\\n\" +\n                              ModConfig.getColour(redColour) + \"17.56s (+0.56s)\\n\" +\n                              ModConfig.getColour(greenColour) + \"32.19s\\n\" +\n                              ModConfig.getColour(timerColour) + \"0.00s\";\n            }\n\n            if (bestPossibleTime) {\n                exampleNums += \"\\n\" + EnumChatFormatting.GOLD + \"21m54.01s\";\n            }\n\n            if (sumOfBest) {\n                exampleNums += \"\\n\" + EnumChatFormatting.GOLD + \"6m2s.20s\";\n            }\n\n            if (extraInfo) {\n                exampleNums += \"\\n\" + EnumChatFormatting.GRAY+ 5 + \"\\n\" +\n                               EnumChatFormatting.YELLOW + 2 + \"\\n\" +\n                               EnumChatFormatting.YELLOW + 1;\n            }\n\n            return exampleNums;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/EndOfFarmAlert.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\npublic class EndOfFarmAlert {\n\n    static boolean alertedX = false;\n    static boolean alertedZ = false;\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        if (DankersSkyblockMod.tickAmount % 10 == 0) {\n            if (ModConfig.endOfFarmAlert && Utils.currentLocation == Location.GARDEN) {\n                EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n                if (player == null) return;\n\n                double x = player.posX;\n                double z = player.posZ;\n\n                if (ModConfig.farmX && (x <= ModConfig.farmMinX || x >= ModConfig.farmMaxX)) {\n                    if (!alertedX) {\n                        alertedX = true;\n                        Utils.createTitle(EnumChatFormatting.RED + \"END OF FARM\", 1);\n                    }\n                } else {\n                    alertedX = false;\n                }\n\n                if (ModConfig.farmZ && (z <= ModConfig.farmMinZ || z >= ModConfig.farmMaxZ)) {\n                    if (!alertedZ) {\n                        alertedZ = true;\n                        Utils.createTitle(EnumChatFormatting.RED + \"END OF FARM\", 1);\n                    }\n                } else {\n                    alertedZ = false;\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/ExpertiseLore.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.nbt.NBTTagCompound;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraftforge.event.entity.player.ItemTooltipEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class ExpertiseLore {\n\n    @SubscribeEvent(priority = EventPriority.HIGHEST)\n    public void onTooltip(ItemTooltipEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.toolTip == null) return;\n\n        ItemStack item = event.itemStack;\n        if (ModConfig.expertiseLore) {\n            if (item.hasTagCompound()) {\n                NBTTagCompound tags = item.getSubCompound(\"ExtraAttributes\", false);\n                if (tags != null) {\n                    if (tags.hasKey(\"expertise_kills\")) {\n                        int index = 4;\n                        if (!Minecraft.getMinecraft().gameSettings.advancedItemTooltips) index -= 2;\n\n                        event.toolTip.add(event.toolTip.size() - index, \"\");\n                        event.toolTip.add(event.toolTip.size() - index, \"Expertise Kills: \" + EnumChatFormatting.RED + tags.getInteger(\"expertise_kills\"));\n                        if (Utils.expertiseKillsLeft(tags.getInteger(\"expertise_kills\")) != -1) {\n                            event.toolTip.add(event.toolTip.size() - index, Utils.expertiseKillsLeft(tags.getInteger(\"expertise_kills\")) + \" kills to tier up!\");\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/FasterMaddoxCalling.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.GuiChat;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.IChatComponent;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.client.event.GuiScreenEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport org.lwjgl.input.Mouse;\n\nimport java.util.List;\n\npublic class FasterMaddoxCalling {\n\n    static String lastMaddoxCommand = \"/cb placeholder\";\n    static double lastMaddoxTime = 0;\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!Utils.inSkyblock) return;\n        if (message.contains(\":\")) return;\n\n        if (message.contains(\"[OPEN MENU]\")) {\n            List<IChatComponent> listOfSiblings = event.message.getSiblings();\n            for (IChatComponent sibling : listOfSiblings) {\n                if (sibling.getUnformattedText().contains(\"[OPEN MENU]\")) {\n                    lastMaddoxCommand = sibling.getChatStyle().getChatClickEvent().getValue();\n                    lastMaddoxTime = System.currentTimeMillis() / 1000;\n                }\n            }\n            if (ModConfig.chatMaddox) Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Open chat then click anywhere on-screen to open Maddox\"));\n        }\n    }\n\n    @SubscribeEvent\n    public void onMouseInputPost(GuiScreenEvent.MouseInputEvent.Post event) {\n        if (!Utils.inSkyblock) return;\n        if (Mouse.getEventButton() == 0 && event.gui instanceof GuiChat) {\n            if (ModConfig.chatMaddox && System.currentTimeMillis() / 1000 - lastMaddoxTime < 10) {\n                Minecraft.getMinecraft().thePlayer.sendChatMessage(lastMaddoxCommand);\n            }\n        }\n    }\n\n    public static void onKey() {\n        if (!Utils.inSkyblock) return;\n\n        EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;\n        player.sendChatMessage(lastMaddoxCommand);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/FilletMagmafish.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ModInitEvent;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.gui.inventory.GuiInventory;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraftforge.client.event.GuiOpenEvent;\nimport net.minecraftforge.client.event.GuiScreenEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.text.NumberFormat;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Optional;\n\npublic class FilletMagmafish {\n\n    static Map<String, Integer> fillet = new HashMap<>();\n    static int total = 0;\n\n    @SubscribeEvent\n    public void init(ModInitEvent event) {\n        fillet.put(\"SULPHUR_SKITTER_BRONZE\", 40);\n        fillet.put(\"SULPHUR_SKITTER_SILVER\", 60);\n        fillet.put(\"SULPHUR_SKITTER_GOLD\", 80);\n        fillet.put(\"SULPHUR_SKITTER_DIAMOND\", 120);\n        fillet.put(\"OBFUSCATED_FISH_1_BRONZE\", 16);\n        fillet.put(\"OBFUSCATED_FISH_1_SILVER\", 24);\n        fillet.put(\"OBFUSCATED_FISH_1_GOLD\", 32);\n        fillet.put(\"OBFUSCATED_FISH_1_DIAMOND\", 48);\n        fillet.put(\"STEAMING_HOT_FLOUNDER_BRONZE\", 20);\n        fillet.put(\"STEAMING_HOT_FLOUNDER_SILVER\", 28);\n        fillet.put(\"STEAMING_HOT_FLOUNDER_GOLD\", 40);\n        fillet.put(\"STEAMING_HOT_FLOUNDER_DIAMOND\", 60);\n        fillet.put(\"GUSHER_BRONZE\", 32);\n        fillet.put(\"GUSHER_SILVER\", 48);\n        fillet.put(\"GUSHER_GOLD\", 64);\n        fillet.put(\"GUSHER_DIAMOND\", 96);\n        fillet.put(\"BLOBFISH_BRONZE\", 4);\n        fillet.put(\"BLOBFISH_SILVER\", 8);\n        fillet.put(\"BLOBFISH_GOLD\", 12);\n        fillet.put(\"BLOBFISH_DIAMOND\", 16);\n        fillet.put(\"OBFUSCATED_FISH_2_BRONZE\", 40);\n        fillet.put(\"OBFUSCATED_FISH_2_SILVER\", 60);\n        fillet.put(\"OBFUSCATED_FISH_2_GOLD\", 80);\n        fillet.put(\"OBFUSCATED_FISH_2_DIAMOND\", 120);\n        fillet.put(\"SLUGFISH_BRONZE\", 40);\n        fillet.put(\"SLUGFISH_SILVER\", 60);\n        fillet.put(\"SLUGFISH_GOLD\", 80);\n        fillet.put(\"SLUGFISH_DIAMOND\", 120);\n        fillet.put(\"FLYFISH_BRONZE\", 32);\n        fillet.put(\"FLYFISH_SILVER\", 48);\n        fillet.put(\"FLYFISH_GOLD\", 64);\n        fillet.put(\"FLYFISH_DIAMOND\", 96);\n        fillet.put(\"OBFUSCATED_FISH_3_BRONZE\", 400);\n        fillet.put(\"OBFUSCATED_FISH_3_SILVER\", 700);\n        fillet.put(\"OBFUSCATED_FISH_3_GOLD\", 1000);\n        fillet.put(\"OBFUSCATED_FISH_3_DIAMOND\", 1300);\n        fillet.put(\"LAVA_HORSE_BRONZE\", 12);\n        fillet.put(\"LAVA_HORSE_SILVER\", 16);\n        fillet.put(\"LAVA_HORSE_GOLD\", 20);\n        fillet.put(\"LAVA_HORSE_DIAMOND\", 24);\n        fillet.put(\"MANA_RAY_BRONZE\", 40);\n        fillet.put(\"MANA_RAY_SILVER\", 60);\n        fillet.put(\"MANA_RAY_GOLD\", 80);\n        fillet.put(\"MANA_RAY_DIAMOND\", 120);\n        fillet.put(\"VOLCANIC_STONEFISH_BRONZE\", 20);\n        fillet.put(\"VOLCANIC_STONEFISH_SILVER\", 28);\n        fillet.put(\"VOLCANIC_STONEFISH_GOLD\", 40);\n        fillet.put(\"VOLCANIC_STONEFISH_DIAMOND\", 60);\n        fillet.put(\"VANILLE_BRONZE\", 80);\n        fillet.put(\"VANILLE_SILVER\", 120);\n        fillet.put(\"VANILLE_GOLD\", 160);\n        fillet.put(\"VANILLE_DIAMOND\", 240);\n        fillet.put(\"SKELETON_FISH_BRONZE\", 32);\n        fillet.put(\"SKELETON_FISH_SILVER\", 48);\n        fillet.put(\"SKELETON_FISH_GOLD\", 64);\n        fillet.put(\"SKELETON_FISH_DIAMOND\", 96);\n        fillet.put(\"MOLDFIN_BRONZE\", 32);\n        fillet.put(\"MOLDFIN_SILVER\", 48);\n        fillet.put(\"MOLDFIN_GOLD\", 64);\n        fillet.put(\"MOLDFIN_DIAMOND\", 96);\n        fillet.put(\"SOUL_FISH_BRONZE\", 32);\n        fillet.put(\"SOUL_FISH_SILVER\", 48);\n        fillet.put(\"SOUL_FISH_GOLD\", 64);\n        fillet.put(\"SOUL_FISH_DIAMOND\", 96);\n        fillet.put(\"KARATE_FISH_BRONZE\", 40);\n        fillet.put(\"KARATE_FISH_SILVER\", 60);\n        fillet.put(\"KARATE_FISH_GOLD\", 80);\n        fillet.put(\"KARATE_FISH_DIAMOND\", 120);\n        fillet.put(\"GOLDEN_FISH_BRONZE\", 400);\n        fillet.put(\"GOLDEN_FISH_SILVER\", 700);\n        fillet.put(\"GOLDEN_FISH_GOLD\", 1000);\n        fillet.put(\"GOLDEN_FISH_DIAMOND\", 1300);\n    }\n\n    @SubscribeEvent\n    public void onGuiOpen(GuiOpenEvent event) {\n        if (!ModConfig.showTotalMagmafish || !Utils.inSkyblock) return;\n\n        if (event.gui instanceof GuiInventory) {\n            ItemStack[] inv = Minecraft.getMinecraft().thePlayer.inventory.mainInventory;\n\n            for (ItemStack stack : inv) {\n                if (stack == null) continue;\n\n                String id = Utils.getSkyblockItemID(stack);\n                if (id == null) continue;\n\n                total += Optional.ofNullable(fillet.get(id)).orElse(0) * stack.stackSize;\n            }\n        } else {\n            total = 0;\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiScreenRender(GuiScreenEvent.BackgroundDrawnEvent event) {\n        if (!ModConfig.showTotalMagmafish || !Utils.inSkyblock) return;\n\n        if (event.gui instanceof GuiInventory) {\n            if (total == 0) return;\n\n            NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);\n            String display = EnumChatFormatting.BLUE + \"Magmafish: \" + nf.format(total);\n\n            int width = UResolution.getScaledWidth();\n            int height = (UResolution.getScaledHeight() - 222) / 2 + 10;\n\n            RenderUtils.drawCenteredText(display, width, height, 1D);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/FirePillarDisplay.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraft.world.World;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.List;\n\npublic class FirePillarDisplay {\n\n    static Entity pillar = null;\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        World world = Minecraft.getMinecraft().theWorld;\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            pillar = null;\n            if (ModConfig.firePillarHud.isEnabled() && world != null && Utils.currentLocation == Location.CRIMSON_ISLE && Utils.isInScoreboard(\"Slay the boss!\")) {\n                List<Entity> entities = world.getLoadedEntityList();\n\n                for (Entity entity : entities) {\n                    String name = StringUtils.stripControlCodes(entity.getName());\n                    if (name.endsWith(\" hits\") && name.charAt(1) == 's') {\n                        pillar = entity;\n                        break;\n                    }\n                }\n            }\n        }\n    }\n\n    public static class FirePillarHud extends Hud {\n\n        @Exclude\n        String exampleText = EnumChatFormatting.GOLD + \"3s \" + EnumChatFormatting.RED + \"8 hits\";\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            if (example) {\n                TextRenderer.drawHUDText(exampleText, x, y, scale);\n                return;\n            }\n\n            if (enabled && pillar != null) {\n                TextRenderer.drawHUDText(getText(), x, y, scale);\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return RenderUtils.getWidthFromText(example ? exampleText : getText()) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return RenderUtils.getHeightFromText(example ? exampleText : getText()) * scale;\n        }\n\n        String getText() {\n            if (pillar != null) return Utils.removeBold(pillar.getName());\n            return \"\";\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/FishingSpawnAlerts.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.entity.item.EntityArmorStand;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraft.world.World;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.List;\n\npublic class FishingSpawnAlerts {\n\n    static boolean lastThunder = false;\n    static boolean lastJawbus = false;\n    static boolean lastGW = false;\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        World world = Minecraft.getMinecraft().theWorld;\n        if (DankersSkyblockMod.tickAmount % 10 == 0) {\n            if (ModConfig.fishingAlert && world != null) {\n                boolean thunder = false;\n                boolean jawbus = false;\n                boolean gw = false;\n                List<Entity> entities = world.getLoadedEntityList();\n\n                for (Entity entity : entities) {\n                    if (entity instanceof EntityArmorStand) {\n                        String name = StringUtils.stripControlCodes(entity.getName());\n                        if (ModConfig.thunderAlert && name.contains(\"Thunder\")) {\n                            thunder = true;\n                        } else if (ModConfig.jawbusAlert && name.contains(\"Lord Jawbus\")) {\n                            jawbus = true;\n                        } else if (ModConfig.gwAlert && name.contains(\"Great White Shark\")) {\n                            gw = true;\n                        }\n                    }\n                }\n\n                if (thunder && !lastThunder) Utils.createTitle(EnumChatFormatting.AQUA + \"THUNDER\", 2);\n                if (jawbus && !lastJawbus) Utils.createTitle(EnumChatFormatting.AQUA + \"JAWBUS\", 2);\n                if (gw && !lastGW) Utils.createTitle(EnumChatFormatting.AQUA + \"GREAT WHITE\", 2);\n\n                lastThunder = thunder;\n                lastJawbus = jawbus;\n                lastGW = gw;\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        lastThunder = false;\n        lastJawbus = false;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/GemstonesLore.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ModInitEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.nbt.NBTTagCompound;\nimport net.minecraft.nbt.NBTTagString;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraftforge.event.entity.player.ItemTooltipEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class GemstonesLore {\n\n    static Map<String, EnumChatFormatting> gemstoneColours = new HashMap<>();\n\n    @SubscribeEvent\n    public void init(ModInitEvent event) {\n        gemstoneColours.put(\"Amber\", EnumChatFormatting.GOLD);\n        gemstoneColours.put(\"Sapphire\", EnumChatFormatting.AQUA);\n        gemstoneColours.put(\"Jasper\", EnumChatFormatting.LIGHT_PURPLE);\n        gemstoneColours.put(\"Amethyst\", EnumChatFormatting.DARK_PURPLE);\n        gemstoneColours.put(\"Topaz\", EnumChatFormatting.YELLOW);\n        gemstoneColours.put(\"Jade\", EnumChatFormatting.GREEN);\n        gemstoneColours.put(\"Ruby\", EnumChatFormatting.RED);\n        gemstoneColours.put(\"Opal\", EnumChatFormatting.WHITE);\n        gemstoneColours.put(\"Aquamarine\", EnumChatFormatting.DARK_AQUA);\n        gemstoneColours.put(\"Peridot\", EnumChatFormatting.DARK_GREEN);\n        gemstoneColours.put(\"Citrine\", EnumChatFormatting.DARK_RED);\n        gemstoneColours.put(\"Onyx\", EnumChatFormatting.DARK_GRAY);\n    }\n\n    @SubscribeEvent(priority = EventPriority.HIGHEST)\n    public void onTooltip(ItemTooltipEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.toolTip == null) return;\n\n        ItemStack item = event.itemStack;\n        if (ModConfig.gemstoneLore) {\n            if (item.hasTagCompound()) {\n                NBTTagCompound tags = item.getSubCompound(\"ExtraAttributes\", false);\n                if (tags != null) {\n                    if (tags.hasKey(\"gems\")) {\n                        NBTTagCompound gems = tags.getCompoundTag(\"gems\");\n                        Set<String> set = gems.getKeySet();\n\n                        if (set.isEmpty()) return;\n\n                        int index = Minecraft.getMinecraft().gameSettings.advancedItemTooltips ? 4 : 2;\n\n                        event.toolTip.add(event.toolTip.size() - index, \"\");\n                        event.toolTip.add(event.toolTip.size() - index, \"Gemstones Applied:\");\n\n                        for (String gem : set) {\n                            char last = gem.charAt(gem.length() - 1);\n                            if (!Character.isDigit(last)) continue;\n\n                            String gemstone = \"  \";\n\n                            if (gems.getTag(gem) instanceof NBTTagString) {\n                                gemstone += Utils.capitalizeString(gems.getString(gem)) + \" \";\n                                if (gem.startsWith(\"UNIVERSAL_\") || gem.startsWith(\"MINING_\") || gem.startsWith(\"COMBAT_\") || gem.startsWith(\"DEFENSIVE_\") || gem.startsWith(\"CHISEL_\")) {\n                                    gemstone += Utils.capitalizeString(gems.getString(gem + \"_gem\"));\n                                } else {\n                                    gemstone += Utils.capitalizeString(gem.substring(0, gem.indexOf(\"_\")));\n                                }\n                            } else if (gems.getTag(gem) instanceof NBTTagCompound) {\n                                String gemQuality = gems.getCompoundTag(gem).getString(\"quality\");\n                                gemstone += Utils.capitalizeString(gemQuality) + \" \";\n                                if (gem.startsWith(\"UNIVERSAL_\") || gem.startsWith(\"MINING_\") || gem.startsWith(\"COMBAT_\") || gem.startsWith(\"DEFENSIVE_\") || gem.startsWith(\"CHISEL_\")) {\n                                    gemstone += Utils.capitalizeString(gems.getString(gem + \"_gem\"));\n                                } else {\n                                    gemstone += Utils.capitalizeString(gem.substring(0, gem.indexOf(\"_\")));\n                                }\n                            }\n\n                            for (String colour : gemstoneColours.keySet()) {\n                                if (gemstone.contains(colour)) {\n                                    gemstone = gemstoneColours.get(colour) + gemstone;\n                                }\n                            }\n\n                            event.toolTip.add(event.toolTip.size() - index, gemstone);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/GetPearlFromSack.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.item.ItemStack;\n\npublic class GetPearlFromSack {\n\n    public static void onKey() {\n        if (!Utils.inSkyblock) return;\n\n        EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;\n        ItemStack[] inv = player.inventory.mainInventory;\n        int amountOfPearls = 0;\n\n        for (ItemStack stack : inv) {\n            if (stack == null) continue;\n\n            String id = Utils.getSkyblockItemID(stack);\n            if (id == null) continue;\n\n            if (id.equals(\"ENDER_PEARL\")) amountOfPearls += stack.stackSize;\n        }\n\n        if (amountOfPearls >= ModConfig.pearlAmount) return;\n        player.sendChatMessage(\"/gfs Ender Pearl \" + (ModConfig.pearlAmount - amountOfPearls));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/GiantHPDisplay.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.ScoreboardHandler;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraft.world.World;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Pattern;\n\npublic class GiantHPDisplay {\n\n    static Pattern f6GiantPattern = Pattern.compile(\"(Jolly Pink Giant|L\\\\.A\\\\.S\\\\.R\\\\.|The Diamond Giant|Bigfoot).*\");\n    static List<Entity> giants = new ArrayList<>();\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        World world = Minecraft.getMinecraft().theWorld;\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            if (ModConfig.giantHPHud.isEnabled() && Utils.isInDungeons() && world != null) {\n                giants.clear();\n                List<String> scoreboard = ScoreboardHandler.getSidebarLines();\n                if (scoreboard.size() == 0) return;\n                String firstLine = ScoreboardHandler.cleanSB(scoreboard.get(scoreboard.size() - 1));\n\n                if (firstLine.contains(\"sadan\")) {\n                    List<Entity> entities = world.getLoadedEntityList();\n\n                    for (Entity entity : entities) {\n                        String name = StringUtils.stripControlCodes(entity.getName());\n                        if (f6GiantPattern.matcher(name).find()) {\n                            giants.add(entity);\n                        }\n                    }\n                } else if (firstLine.contains(\"138,30\") || firstLine.contains(\"354,66\") || firstLine.contains(\"138,66\")) {\n                    List<Entity> entities = world.getLoadedEntityList();\n\n                    for (Entity entity : entities) {\n                        if (entity.getName().contains(\"Giant \")) {\n                            giants.add(entity);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public static class GiantHPHud extends Hud {\n\n        @Exclude\n        String exampleText = EnumChatFormatting.DARK_RED + \"L.A.S.R. \" + EnumChatFormatting.GREEN + \"25M\" + EnumChatFormatting.RED + \"❤\\n\" +\n                             EnumChatFormatting.RED + \"Bigfoot \" + EnumChatFormatting.GREEN + \"25M\" + EnumChatFormatting.RED + \"❤\\n\" +\n                             EnumChatFormatting.LIGHT_PURPLE + \"Jolly Pink Giant \" + EnumChatFormatting.GREEN + \"25M\" + EnumChatFormatting.RED + \"❤\\n\" +\n                             EnumChatFormatting.DARK_AQUA + \"The Diamond Giant \" + EnumChatFormatting.GREEN + \"25M\" + EnumChatFormatting.RED + \"❤\";\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            if (example) {\n                TextRenderer.drawHUDText(exampleText, x, y, scale);\n                return;\n            }\n\n            if (enabled && Utils.isInDungeons() && giants.size() > 0) {\n                TextRenderer.drawHUDText(getText(), x, y, scale);\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return RenderUtils.getWidthFromText(example ? exampleText : getText()) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return RenderUtils.getHeightFromText(example ? exampleText : getText()) * scale;\n        }\n\n        String getText() {\n            StringBuilder sb = new StringBuilder();\n\n            for (Entity giant : giants) {\n                if (!giant.isDead) sb.append(Utils.removeBold(giant.getDisplayName().getFormattedText())).append(\"\\n\");\n            }\n\n            return sb.toString();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/GoldenEnchants.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ModInitEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraftforge.event.entity.player.ItemTooltipEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.regex.Pattern;\n\npublic class GoldenEnchants {\n\n    public static Map<String, String> t6Enchants = new HashMap<>();\n    public static Pattern t6EnchantPattern = Pattern.compile(\"\");\n\n    @SubscribeEvent\n    public void init(ModInitEvent event) {\n        t6Enchants.put(\"9Angler VI\", \"6Angler VI\");\n        t6Enchants.put(\"9Bane of Arthropods VI\", \"6Bane of Arthropods VI\");\n        t6Enchants.put(\"9Caster VI\", \"6Caster VI\");\n        t6Enchants.put(\"9Compact X\", \"6Compact X\");\n        t6Enchants.put(\"9Critical VI\", \"6Critical VI\");\n        t6Enchants.put(\"9Dragon Hunter V\", \"6Dragon Hunter V\");\n        t6Enchants.put(\"9Efficiency VI\", \"6Efficiency VI\");\n        t6Enchants.put(\"9Ender Slayer VI\", \"6Ender Slayer VI\");\n        t6Enchants.put(\"9Experience IV\", \"6Experience IV\");\n        t6Enchants.put(\"9Expertise X\", \"6Expertise X\");\n        t6Enchants.put(\"9Feather Falling X\", \"6Feather Falling X\");\n        t6Enchants.put(\"9Frail VI\", \"6Frail VI\");\n        t6Enchants.put(\"9Giant Killer VI\", \"6Giant Killer VI\");\n        t6Enchants.put(\"9Growth VI\", \"6Growth VI\");\n        t6Enchants.put(\"9Infinite Quiver X\", \"6Infinite Quiver X\");\n        t6Enchants.put(\"9Lethality VI\", \"6Lethality VI\");\n        t6Enchants.put(\"9Life Steal IV\", \"6Life Steal IV\");\n        t6Enchants.put(\"9Looting IV\", \"6Looting IV\");\n        t6Enchants.put(\"9Luck VI\", \"6Luck VI\");\n        t6Enchants.put(\"9Luck of the Sea VI\", \"6Luck of the Sea VI\");\n        t6Enchants.put(\"9Lure VI\", \"6Lure VI\");\n        t6Enchants.put(\"9Magnet VI\", \"6Magnet VI\");\n        t6Enchants.put(\"9Overload V\", \"6Overload V\");\n        t6Enchants.put(\"9Power VI\", \"6Power VI\");\n        t6Enchants.put(\"9Protection VI\", \"6Protection VI\");\n        t6Enchants.put(\"9Scavenger IV\", \"6Scavenger IV\");\n        t6Enchants.put(\"9Scavenger V\", \"6Scavenger V\");\n        t6Enchants.put(\"9Sharpness VI\", \"6Sharpness VI\");\n        t6Enchants.put(\"9Smite VI\", \"6Smite VI\");\n        t6Enchants.put(\"9Spiked Hook VI\", \"6Spiked Hook VI\");\n        t6Enchants.put(\"9Thunderlord VI\", \"6Thunderlord VI\");\n        t6Enchants.put(\"9Vampirism VI\", \"6Vampirism VI\");\n\n        String patternString = \"(\" + String.join(\"|\", t6Enchants.keySet()) + \")\";\n        t6EnchantPattern = Pattern.compile(patternString);\n    }\n\n    @SubscribeEvent(priority = EventPriority.HIGHEST)\n    public void onTooltip(ItemTooltipEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.toolTip == null) return;\n\n        if (ModConfig.golden) {\n            for (int i = 0; i < event.toolTip.size(); i++) {\n                event.toolTip.set(i, Utils.returnGoldenEnchants(event.toolTip.get(i)));\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/GolemSpawningAlert.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Dropdown;\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.renderer.GlStateManager;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.ResourceLocation;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport org.lwjgl.opengl.GL11;\n\npublic class GolemSpawningAlert {\n\n    static double golemTime = 0;\n    public static final ResourceLocation GOLEM_ICON = new ResourceLocation(\"dsm\", \"icons/golem.png\");\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!Utils.inSkyblock) return;\n        if (message.contains(\":\")) return;\n\n        if (ModConfig.golemAlerts) {\n            if (message.contains(\"The ground begins to shake as an Endstone Protector rises from below!\")) {\n                golemTime = System.currentTimeMillis() / 1000 + 20;\n                Utils.createTitle(EnumChatFormatting.RED + \"GOLEM SPAWNING!\", 3);\n            }\n        }\n    }\n\n    public static class GolemTimerHud extends Hud {\n\n        @Exclude\n        String exampleText = ModConfig.getColour(golemAlertColour) + \"20s\";\n\n        @Dropdown(\n                name = \"Golem Timer Text Color\",\n                options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n        )\n        public static int golemAlertColour = 6;\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            Minecraft mc = Minecraft.getMinecraft();\n\n            if (example) {\n                double scaleReset = Math.pow(scale, -1);\n                GL11.glScaled(scale, scale, scale);\n                GlStateManager.color(1, 1, 1, 1);\n\n                mc.getTextureManager().bindTexture(GOLEM_ICON);\n                RenderUtils.drawModalRectWithCustomSizedTexture(x / scale, y / scale, 0, 0, 16, 16, 16, 16);\n\n                GL11.glScaled(scaleReset, scaleReset, scaleReset);\n\n                TextRenderer.drawHUDText(exampleText, x + 20 * scale, y + 5 * scale, scale);\n                return;\n            }\n\n            if (enabled && Utils.inSkyblock && golemTime > System.currentTimeMillis() / 1000) {\n                double scaleReset = Math.pow(scale, -1);\n                GL11.glScaled(scale, scale, scale);\n                GlStateManager.color(1, 1, 1, 1);\n\n                mc.getTextureManager().bindTexture(GOLEM_ICON);\n                RenderUtils.drawModalRectWithCustomSizedTexture(x / scale, y / scale, 0, 0, 16, 16, 16, 16);\n\n                GL11.glScaled(scaleReset, scaleReset, scaleReset);\n\n                TextRenderer.drawHUDText(getText(), x + 20 * scale, y + 5 * scale, scale);\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return (RenderUtils.getWidthFromText(example ? exampleText : getText()) + 20 * scale) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return (RenderUtils.getHeightFromText(example ? exampleText : getText()) + 5 * scale) * scale;\n        }\n\n        String getText() {\n            double timeNow = System.currentTimeMillis() / 1000;\n            return ModConfig.getColour(golemAlertColour) + Utils.getTimeBetween(timeNow, golemTime);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/GpartyNotifications.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.awt.*;\n\npublic class GpartyNotifications {\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!Utils.inSkyblock) return;\n        if (message.contains(\":\")) return;\n\n        if (ModConfig.gparty) {\n            if (message.contains(\" has invited all members of \")) {\n                Utils.desktopNotification(\"Guild Party Notifier\", \"Guild Party\", message, TrayIcon.MessageType.INFO);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/HidePetCandy.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraftforge.event.entity.player.ItemTooltipEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class HidePetCandy {\n\n    @SubscribeEvent\n    public void onTooltip(ItemTooltipEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.toolTip == null) return;\n\n        if (ModConfig.hidePetCandy) {\n            for (int i = 0; i < event.toolTip.size(); i++) {\n                if (event.toolTip.get(i).endsWith(\"Pet Candy Used\")) {\n                    event.toolTip.remove(i);\n                    event.toolTip.remove(i);\n                    break;\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/HidePlayerArmour.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.entity.EntityLivingBase;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.potion.Potion;\nimport net.minecraftforge.client.event.RenderLivingEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class HidePlayerArmour {\n\n    List<ItemStack> armour = new ArrayList<>();\n\n    @SubscribeEvent\n    public void onRenderLivingPre(RenderLivingEvent.Pre<EntityLivingBase> event) {\n        if (shouldHideArmor(event)) {\n            EntityPlayer player = (EntityPlayer) event.entity;\n            for (int i = 0; i < player.inventory.armorInventory.length; i++) {\n                if (player.inventory.armorInventory[i] != null) {\n                    armour.add(player.inventory.armorInventory[i].copy());\n                    player.inventory.armorInventory[i] = null;\n                } else {\n                    armour.add(null);\n                }\n            }\n        }\n    }\n\n    public boolean isNPC(EntityPlayer player) {\n        return player.getUniqueID() == null || player.getUniqueID().version() != 4;\n    }\n\n    public boolean shouldHideArmor(RenderLivingEvent<EntityLivingBase> event) {\n        return ModConfig.hideArmour\n                && Utils.inSkyblock && event.entity instanceof EntityPlayer\n                && (!ModConfig.hidePlayerArmourOnly || !isNPC(((EntityPlayer) event.entity)))\n                && event.entity.getActivePotionEffect(Potion.invisibility) == null;\n    }\n\n    @SubscribeEvent\n    public void onRenderLivingPost(RenderLivingEvent.Post<EntityLivingBase> event) {\n        if (shouldHideArmor(event)) {\n            EntityPlayer player = (EntityPlayer) event.entity;\n\n            for (int i = 0; i < player.inventory.armorInventory.length; i++) {\n                player.inventory.armorInventory[i] = armour.get(i);\n            }\n            armour.clear();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/HideTooltipsInExperiments.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.inventory.ContainerChest;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraftforge.event.entity.player.ItemTooltipEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class HideTooltipsInExperiments {\n\n    @SubscribeEvent(priority = EventPriority.LOW)\n    public void onTooltipLow(ItemTooltipEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.toolTip == null) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n\n        if (mc.currentScreen instanceof GuiChest) {\n            ContainerChest chest = (ContainerChest) player.openContainer;\n            IInventory inv = chest.getLowerChestInventory();\n            String chestName = inv.getDisplayName().getUnformattedText();\n\n            if (ModConfig.hideTooltipsInExperimentAddons && (chestName.startsWith(\"Ultrasequencer (\") || chestName.startsWith(\"Chronomatron (\"))) {\n                event.toolTip.clear();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/HideTooltipsMisc.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.inventory.ContainerChest;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraftforge.event.entity.player.ItemTooltipEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class HideTooltipsMisc {\n\n    @SubscribeEvent\n    public void onTooltipLow(ItemTooltipEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.toolTip == null) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n\n        if (mc.currentScreen instanceof GuiChest) {\n            ContainerChest chest = (ContainerChest) player.openContainer;\n            IInventory inv = chest.getLowerChestInventory();\n            String chestName = inv.getDisplayName().getUnformattedText();\n\n            if ((ModConfig.melodyTooltips && chestName.startsWith(\"Harp\")) ||\n                (ModConfig.hackingTooltips && Utils.currentLocation == Location.RIFT && chestName.equals(\"Hacking\"))) {\n                event.toolTip.clear();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/HighlightCommissions.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.GuiChestBackgroundDrawnEvent;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.item.ItemWritableBook;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.List;\n\npublic class HighlightCommissions {\n\n    @SubscribeEvent\n    public void onGuiRender(GuiChestBackgroundDrawnEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (!ModConfig.highlightCommissions) return;\n        List<Slot> slots = event.slots;\n        if (!event.displayName.equals(\"Commissions\")) return;\n\n        for (Slot slot : slots) {\n            if (slot == null || slot.getStack() == null) continue;\n            if (slot.getStack().getItem() instanceof ItemWritableBook) {\n                for (String line : Utils.getItemLore(slot.getStack())) {\n                    if (line.contains(\"COMPLETED\")) {\n                        RenderUtils.drawOnSlot(event.chestSize, slot.xDisplayPosition, slot.yDisplayPosition, ModConfig.commissionColour.getRGB());\n                        break;\n                    }\n                }\n\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/HighlightFilledOrders.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.GuiChestBackgroundDrawnEvent;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.inventory.Slot;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.List;\n\npublic class HighlightFilledOrders {\n\n    @SubscribeEvent\n    public void onGuiRender(GuiChestBackgroundDrawnEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (!ModConfig.highlightOrders) return;\n        if (!event.displayName.equals(\"Your Bazaar Orders\")) return;\n\n        List<Slot> slots = event.slots;\n        for (Slot slot : slots) {\n            if (slot == null || slot.getStack() == null) continue;\n            for (String line : Utils.getItemLore(slot.getStack())) {\n                if (line.endsWith(\"100%!\")) {\n                    RenderUtils.drawOnSlot(event.chestSize, slot.xDisplayPosition, slot.yDisplayPosition, ModConfig.highlightOrdersColour.getRGB());\n                    break;\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/HighlightPests.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.GuiChestBackgroundDrawnEvent;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.inventory.Slot;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.List;\n\npublic class HighlightPests {\n\n    @SubscribeEvent\n    public void onGuiRender(GuiChestBackgroundDrawnEvent event) {\n        if (!ModConfig.highlightPests) return;\n        if (Utils.currentLocation != Location.GARDEN) return;\n        if (!event.displayName.equals(\"Configure Plots\")) return;\n\n        List<Slot> slots = event.slots;\n        for (Slot slot : slots) {\n            if (slot == null || slot.getStack() == null) continue;\n            for (String line : Utils.getItemLore(slot.getStack())) {\n                if (line.length() <= 30) continue;\n\n                if (line.charAt(4) == 'ൠ') {\n                    RenderUtils.drawOnSlot(event.chestSize, slot.xDisplayPosition, slot.yDisplayPosition, ModConfig.highlightPestsColour.getRGB());\n                    break;\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/HighlightSkeletonMasters.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.entity.EntityLivingBase;\nimport net.minecraft.entity.monster.EntitySkeleton;\nimport net.minecraft.item.ItemStack;\nimport net.minecraftforge.client.event.RenderLivingEvent;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class HighlightSkeletonMasters {\n\n    static List<Entity> skeletonMasters = new ArrayList<>();\n\n    @SubscribeEvent\n    public void onRenderEntity(RenderLivingEvent.Pre<EntityLivingBase> event) {\n        if (ModConfig.highlightSkeletonMasters && event.entity instanceof EntitySkeleton && Utils.isInDungeons()) {\n            ItemStack helmet = event.entity.getCurrentArmor(3);\n            if (helmet != null && helmet.getDisplayName().endsWith(\"Skeleton Master Helmet\")) {\n                skeletonMasters.add(event.entity);\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n        if (ModConfig.highlightSkeletonMasters) {\n            for (Entity skeletonMaster : skeletonMasters) {\n                if (!skeletonMaster.isDead)\n                    RenderUtils.draw3DBox(skeletonMaster.getEntityBoundingBox(), ModConfig.skeletonMasterBoxColour.getRGB(), event.partialTicks);\n            }\n            skeletonMasters.clear();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/KuudraNotifications.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.PacketReadEvent;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.Utils;\nimport net.minecraft.network.play.server.S45PacketTitle;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class KuudraNotifications {\n\n    @SubscribeEvent(receiveCanceled = true)\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!ModConfig.kuudraNotifications) return;\n        if (Utils.currentLocation != Location.KUUDRA) return;\n\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n        \n        if (message.startsWith(\"[NPC] Elle: That looks like it hurt!\")) {\n            Utils.createTitle(EnumChatFormatting.RED + \"KUUDRA STUNNED!\", 2);\n        } else if (message.equals(\"[NPC] Elle: Phew! The Ballista is finally ready! It should be strong enough to tank Kuudra's blows now!\")) {\n            Utils.createTitle(EnumChatFormatting.GREEN + \"BALLISTA BUILT!\", 2);\n        }\n\n        if (message.contains(\":\")) return;\n\n        if (message.contains(\"recovered a Fuel Cell and charged the Ballista! (100%)\")) {\n            Utils.createTitle(EnumChatFormatting.GREEN + \"BALLISTA CHARGED!\", 2);\n        }\n    }\n\n    @SubscribeEvent\n    public void onPacketRead(PacketReadEvent event) {\n        if (!ModConfig.kuudraNotifications || Utils.currentLocation != Location.KUUDRA) return;\n\n        if (event.packet instanceof S45PacketTitle) {\n            S45PacketTitle packet = (S45PacketTitle) event.packet;\n\n            if (packet.getMessage() == null) return;\n\n            String message = packet.getMessage().getUnformattedText();\n            if (message.endsWith(\" INCOMING\")) {\n                new Thread(() -> {\n                    try {\n                        Thread.sleep(45000);\n                        if (Utils.currentLocation == Location.KUUDRA) Utils.createTitle(EnumChatFormatting.AQUA + \"CLOAK!\", 3);\n                    } catch (InterruptedException ex) {\n                        ex.printStackTrace();\n                    }\n                }).start();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/LocrawSpamFix.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.PacketWriteEvent;\nimport net.minecraft.network.play.client.C01PacketChatMessage;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class LocrawSpamFix {\n\n    static long lastLocraw = 0;\n\n    @SubscribeEvent\n    public void onPacketWrite(PacketWriteEvent event) {\n        if (!ModConfig.fixLocraw) return;\n\n        if (event.packet instanceof C01PacketChatMessage) {\n            C01PacketChatMessage packet = (C01PacketChatMessage) event.packet;\n\n            if (packet.getMessage().equals(\"/locraw\")) {\n                long time = System.currentTimeMillis();\n                if (time - lastLocraw <= 5000) event.setCanceled(true);\n                lastLocraw = time;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/LowHealthNotifications.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.ScoreboardHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.world.World;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.List;\n\npublic class LowHealthNotifications {\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        World world = Minecraft.getMinecraft().theWorld;\n        if (DankersSkyblockMod.tickAmount % 2 == 0) {\n            if (ModConfig.lowHealthNotify && Utils.isInDungeons() && world != null) {\n                List<String> scoreboard = ScoreboardHandler.getSidebarLines();\n                for (String score : scoreboard) {\n                    if (score.endsWith(\"❤\") && score.matches(\".* §c\\\\d.*\")) {\n                        String name = score.substring(score.indexOf(\" \") + 1);\n                        Utils.createTitle(EnumChatFormatting.RED + \"LOW HEALTH!\\n\" + name, 1);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/MeterTracker.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.utils.TickDelay;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonObject;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ChestSlotClickedEvent;\nimport me.Danker.events.ModInitEvent;\nimport me.Danker.events.PostConfigInitEvent;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.init.Items;\nimport net.minecraft.inventory.ContainerChest;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.MathHelper;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.text.NumberFormat;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class MeterTracker {\n\n    public static JsonObject meter = new JsonObject();\n    public static String configFile;\n\n    public static JsonObject createEmpty() {\n        JsonObject meter = new JsonObject();\n\n        JsonObject floor = new JsonObject();\n        floor.addProperty(\"drop\", EnumChatFormatting.RED + \"None\");\n        floor.addProperty(\"progress\", 0);\n        floor.addProperty(\"goal\", 0);\n\n        meter.add(\"F1\", Utils.deepCopy(floor));\n        meter.add(\"F2\", Utils.deepCopy(floor));\n        meter.add(\"F3\", Utils.deepCopy(floor));\n        meter.add(\"F4\", Utils.deepCopy(floor));\n        meter.add(\"F5\", Utils.deepCopy(floor));\n        meter.add(\"F6\", Utils.deepCopy(floor));\n        meter.add(\"F7\", Utils.deepCopy(floor));\n        meter.add(\"M1\", Utils.deepCopy(floor));\n        meter.add(\"M2\", Utils.deepCopy(floor));\n        meter.add(\"M3\", Utils.deepCopy(floor));\n        meter.add(\"M4\", Utils.deepCopy(floor));\n        meter.add(\"M5\", Utils.deepCopy(floor));\n        meter.add(\"M6\", Utils.deepCopy(floor));\n        meter.add(\"M7\", Utils.deepCopy(floor));\n\n        return meter;\n    }\n\n    @SubscribeEvent\n    public void init(ModInitEvent event) {\n        configFile = event.configDirectory + \"/dsm/dsmmeter.json\";\n    }\n\n    @SubscribeEvent\n    public void postConfigInit(PostConfigInitEvent event) {\n        if (meter.entrySet().isEmpty()) meter = createEmpty();\n        save();\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (Utils.currentLocation != Location.CATACOMBS) return;\n        if (event.type == 2) return;\n\n        if (message.contains(\"    Team Score: \")) {\n            String currentFloor = Utils.currentFloor.toString();\n\n            if (meter.has(currentFloor)) {\n                EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n                int score = Integer.parseInt(message.replaceAll(\"\\\\D\", \"\"));\n                if (score < 270) return;\n                if (score < 300) score *= 0.7;\n\n                JsonObject floor = meter.getAsJsonObject(currentFloor);\n                NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);\n\n                String drop = floor.get(\"drop\").getAsString();\n                int progress = floor.get(\"progress\").getAsInt();\n                int goal = floor.get(\"goal\").getAsInt();\n\n                progress += score;\n                if (goal == 0) return;\n\n                double percent = (double) progress / goal * 100D;\n                percent = MathHelper.clamp_double(percent, 0D, 100D);\n\n                String info = EnumChatFormatting.GOLD + \"Selected Drop: \" + drop + \"\\n\" +\n                              EnumChatFormatting.GOLD + \"Progress: \" + EnumChatFormatting.LIGHT_PURPLE + nf.format(progress) + EnumChatFormatting.DARK_PURPLE + \"/\" + EnumChatFormatting.LIGHT_PURPLE + nf.format(goal) +\n                              EnumChatFormatting.DARK_GRAY + \" (\" + EnumChatFormatting.LIGHT_PURPLE + String.format(\"%.2f\", percent) + EnumChatFormatting.DARK_PURPLE + \"%\" + EnumChatFormatting.DARK_GRAY + \")\" + \"\\n\";\n                int runsLeft = 0;\n\n                if (progress >= goal) {\n                    progress -= goal;\n                    info += EnumChatFormatting.GREEN + \"\" + EnumChatFormatting.BOLD + \"Item dropped!\";\n                    floor.addProperty(\"drop\", EnumChatFormatting.RED + \"None\");\n                    goal = 0;\n                } else {\n                    runsLeft = (int) Math.ceil((goal - progress) / (currentFloor.charAt(1) == '6' || currentFloor.charAt(1) == '7' ? 307D : 305D));\n                    info += EnumChatFormatting.GOLD + \"Minimum Runs Left: \" + EnumChatFormatting.AQUA + runsLeft;\n                }\n\n                floor.addProperty(\"progress\", progress);\n                floor.addProperty(\"goal\", goal);\n\n                save();\n\n                if (ModConfig.meterTracker) {\n                    String finalInfo = info;\n                    int finalRunsLeft = runsLeft;\n                    new TickDelay(() -> {\n                        player.addChatMessage(new ChatComponentText(finalInfo));\n                        if (finalRunsLeft == 1) {\n                            player.addChatMessage(new ChatComponentText(\"\" + EnumChatFormatting.RED + EnumChatFormatting.BOLD + \"Reset meter if you want to maintain high chances!\"));\n                        }\n                    }, 1);\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n        if (!Utils.inSkyblock) return;\n\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            Minecraft mc = Minecraft.getMinecraft();\n            EntityPlayerSP player = mc.thePlayer;\n            if (mc.currentScreen instanceof GuiChest) {\n                if (player == null) return;\n                ContainerChest chest = (ContainerChest) player.openContainer;\n                List<Slot> invSlots = ((GuiChest) mc.currentScreen).inventorySlots.inventorySlots;\n                String chestName = chest.getLowerChestInventory().getDisplayName().getUnformattedText().trim();\n\n                if (chestName.equals(\"Catacombs RNG Meter\")) {\n                    for (int i = 19; i <= 34; i++) {\n                        ItemStack stack = invSlots.get(i).getStack();\n                        if (stack == null || stack.getItem() != Items.skull) continue;\n\n                        List<String> lore = Utils.getItemLore(stack);\n                        String floor = lore.get(0);\n                        floor = floor.substring(floor.indexOf(\"(\") + 1, floor.indexOf(\")\"));\n\n                        if (meter.has(floor)) {\n                            String drop = EnumChatFormatting.RED + \"None\";\n                            int progress;\n                            int goal = 0;\n\n                            if (StringUtils.stripControlCodes(lore.get(13)).equals(\"Selected Drop\")) {\n                                drop = lore.get(14);\n                                String line = StringUtils.stripControlCodes(lore.get(17));\n                                progress = getProgressFromLine(line);\n                                goal = getGoalFromLine(line);\n                            } else {\n                                try {\n                                    progress = Integer.parseInt(StringUtils.stripControlCodes(lore.get(17)).replaceAll(\"\\\\D\", \"\"));\n                                } catch (NumberFormatException ex) {\n                                    progress = 0;\n                                }\n                            }\n\n                            JsonObject floorMeter = meter.getAsJsonObject(floor);\n                            floorMeter.addProperty(\"drop\", drop);\n                            floorMeter.addProperty(\"progress\", progress);\n                            floorMeter.addProperty(\"goal\", goal);\n                            save();\n\n                            System.out.println(\"Updated \" + floor + \" meter.\");\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onSlotClick(ChestSlotClickedEvent event) {\n        if (event.item == null) return;\n\n        String inventoryName = event.inventoryName;\n        if (inventoryName.startsWith(\"Catacombs (\") && inventoryName.endsWith(\") RNG Meter\")) {\n            String floor = inventoryName.substring(inventoryName.indexOf(\"(\") + 1, inventoryName.indexOf(\")\"));\n\n            if (meter.has(floor)) {\n                JsonObject floorMeter = meter.getAsJsonObject(floor);\n                String drop = event.item.getDisplayName();\n                String currentDrop = floorMeter.get(\"drop\").getAsString();\n                if (drop.equals(currentDrop)) return;\n\n                List<String> lore = Utils.getItemLore(event.item);\n                for (String line : lore) {\n                    String cleaned = StringUtils.stripControlCodes(line);\n                    if (cleaned.startsWith(\"Dungeon Score: \")) {\n                        int progress = getProgressFromLine(cleaned);\n                        int goal = getGoalFromLine(cleaned);\n\n                        floorMeter.addProperty(\"drop\", drop);\n                        floorMeter.addProperty(\"progress\", progress);\n                        floorMeter.addProperty(\"goal\", goal);\n                        save();\n\n                        System.out.println(\"Switched \" + floor + \" meter to \" + drop);\n                        return;\n                    }\n                }\n            }\n        }\n    }\n\n    public static void save() {\n        try (FileWriter writer = new FileWriter(configFile)) {\n            new GsonBuilder().create().toJson(meter, writer);\n            writer.flush();\n        } catch (IOException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    static int getProgressFromLine(String line) {\n        try {\n            return Integer.parseInt(line.substring(0, line.indexOf(\"/\")).replaceAll(\"\\\\D\", \"\"));\n        } catch (NumberFormatException ex) {\n            return 0;\n        }\n    }\n\n    static int getGoalFromLine(String line) {\n        String goalString = line.substring(line.indexOf(\"/\") + 1);\n\n        try {\n            if (goalString.endsWith(\"k\")) {\n                return Integer.parseInt(goalString.replaceAll(\"\\\\D\", \"\")) * 1000;\n            } else {\n                return Integer.parseInt(goalString.replaceAll(\"\\\\D\", \"\"));\n            }\n        } catch (NumberFormatException ex) {\n            return 1;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/MinionLastCollected.java",
    "content": "package me.Danker.features;\n\nimport com.google.gson.GsonBuilder;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ChestSlotClickedEvent;\nimport me.Danker.events.ModInitEvent;\nimport me.Danker.events.PacketWriteEvent;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.entity.item.EntityArmorStand;\nimport net.minecraft.item.Item;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.network.play.client.C02PacketUseEntity;\nimport net.minecraft.util.AxisAlignedBB;\nimport net.minecraft.util.BlockPos;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class MinionLastCollected {\n\n    public static List<Minion> minions = new ArrayList<>();\n    public static String configFile;\n    static BlockPos lastMinion = null;\n\n    @SubscribeEvent\n    public void init(ModInitEvent event) {\n        configFile = event.configDirectory + \"/dsm/dsmminions.json\";\n    }\n\n    @SubscribeEvent\n    public void onPacketWrite(PacketWriteEvent event) {\n        if (ModConfig.minionLastCollected && Utils.inSkyblock && Utils.isInScoreboard(\"Your Island\")) {\n            if (event.packet instanceof C02PacketUseEntity) {\n                C02PacketUseEntity packet = (C02PacketUseEntity) event.packet;\n                Entity entity = packet.getEntityFromWorld(Minecraft.getMinecraft().theWorld);\n                if (isAMinion(entity)) {\n                    lastMinion = entity.getPosition();\n                    if (getMinionFromPos(lastMinion) == null) {\n                        minions.add(new Minion(lastMinion));\n                        save();\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onSlotClick(ChestSlotClickedEvent event) {\n        if (ModConfig.minionLastCollected && Utils.currentLocation == Location.PRIVATE_ISLAND) {\n            String inventoryName = event.inventoryName;\n            ItemStack item = event.item;\n            if (inventoryName.contains(\" Minion \") && item != null && lastMinion != null) {\n                if (item.getDisplayName().contains(\"Collect All\") || item.getDisplayName().contains(\"Hopper\")) {\n                    getMinionFromPos(lastMinion).collectNow();\n                    save();\n                } else if (item.getDisplayName().contains(\"Pickup Minion\")) {\n                    minions.remove(getMinionFromPos(lastMinion));\n                    save();\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n        if (ModConfig.minionLastCollected && Utils.inSkyblock && Utils.currentLocation == Location.PRIVATE_ISLAND) {\n            for (Minion minion : minions) {\n                if (!minionExistsAtPos(minion.pos)) continue;\n                RenderUtils.draw3DString(minion.pos.getX() + 0.5, minion.pos.getY() + 2.2, minion.pos.getZ() + 0.5, minion.getTimeCollected(), ModConfig.lastCollectedColour.getRGB(), event.partialTicks);\n            }\n        }\n    }\n\n    public boolean isAMinion(Entity entity) {\n        if (!(entity instanceof EntityArmorStand)) return false;\n        EntityArmorStand armourStand = (EntityArmorStand) entity;\n\n        for (int i = 0; i <= 3; i++) {\n            if (armourStand.getCurrentArmor(i) == null) return false;\n        }\n\n        return (Item.getIdFromItem(armourStand.getCurrentArmor(0).getItem()) == 301 && // leather boots\n                Item.getIdFromItem(armourStand.getCurrentArmor(1).getItem()) == 300 && // leather leggings\n                (Item.getIdFromItem(armourStand.getCurrentArmor(2).getItem()) == 299 || // leather chestplate\n                Item.getIdFromItem(armourStand.getCurrentArmor(2).getItem()) == 304) && // chainmail leggings?\n                Item.getIdFromItem(armourStand.getCurrentArmor(3).getItem()) == 397); // :skull:\n    }\n\n    // maybe use in the future\n    public boolean isArmour(Item item) {\n        int id = Item.getIdFromItem(item);\n        return id >= 298 && id <= 317;\n    }\n\n    public Minion getMinionFromPos(BlockPos pos) {\n        for (Minion minion : minions) {\n            if (minion.pos.equals(pos)) return minion;\n        }\n        return null;\n    }\n\n    public boolean minionExistsAtPos(BlockPos pos) {\n        AxisAlignedBB aabb = new AxisAlignedBB(pos, pos.add(1, 1, 1));\n        List<EntityArmorStand> entities = Minecraft.getMinecraft().theWorld.getEntitiesWithinAABB(EntityArmorStand.class, aabb);\n        return entities.size() > 0; // just assume theres a minion there\n    }\n\n    public static void save() {\n        try (FileWriter writer = new FileWriter(configFile)) {\n            new GsonBuilder().create().toJson(minions, writer);\n            writer.flush();\n        } catch (IOException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    public static class Minion {\n\n        public BlockPos pos;\n        public double lastCollect;\n\n        public Minion(BlockPos pos) {\n            this.pos = pos;\n            this.lastCollect = -1;\n        }\n\n        public String getTimeCollected() {\n            String lastCollected = \"Last Collected: \";\n            if (lastCollect == -1) {\n                return lastCollected + \"Never\";\n            }\n            return lastCollected + Utils.getTimeBetween(lastCollect, System.currentTimeMillis() / 1000) + \" ago\";\n        }\n\n        public void collectNow() {\n            lastCollect = System.currentTimeMillis() / 1000;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/NecronNotifications.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.block.Block;\nimport net.minecraft.block.state.IBlockState;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.item.EntityArmorStand;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraft.world.World;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.List;\n\npublic class NecronNotifications {\n\n    @SubscribeEvent(receiveCanceled = true)\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!Utils.isInDungeons()) return;\n\n        if (ModConfig.necronNotifications) {\n            Minecraft mc = Minecraft.getMinecraft();\n            World world = mc.theWorld;\n\n            if (message.startsWith(\"[BOSS] Maxor:\")) {\n                if (message.contains(\"THAT BEAM! IT HURTS! IT HURTS!!\") || message.contains(\"YOU TRICKED ME!\")) {\n                    Utils.createTitle(EnumChatFormatting.RED + \"MAXOR STUCK!\", 2);\n                }\n            } else if (message.startsWith(\"[BOSS] Storm:\")) {\n                if (message.contains(\"Ouch, that hurt!\") || message.contains(\"Oof\")) {\n                    List<EntityArmorStand> stormLabels = world.getEntities(EntityArmorStand.class, (entity -> {\n                        if (!entity.hasCustomName()) return false;\n                        return entity.getCustomNameTag().contains(\"Storm\");\n                    }));\n                    if (stormLabels.size() == 0) {\n                        Utils.createTitle(EnumChatFormatting.WHITE + \"STORM STUNNED!\", 2);\n                    } else {\n                        EntityArmorStand storm = stormLabels.get(0);\n                        double x = storm.posX;\n                        double z = storm.posZ;\n\n                        BlockPos blockPos = new BlockPos(x, 168, z);\n\n                        IBlockState blockState = world.getBlockState(blockPos);\n                        Block block = blockState.getBlock();\n\n                        if (block != Blocks.stained_hardened_clay) {\n                            Utils.createTitle(EnumChatFormatting.WHITE + \"STORM STUNNED!\", 2);\n                        } else {\n                            switch (block.getDamageValue(world, blockPos)) {\n                                case 4:\n                                    Utils.createTitle(EnumChatFormatting.YELLOW + \"YELLOW PILLAR!\", 2);\n                                    break;\n                                case 5:\n                                    Utils.createTitle(EnumChatFormatting.DARK_GREEN + \"GREEN PILLAR!\", 2);\n                                    break;\n                                case 11:\n                                    Utils.createTitle(EnumChatFormatting.DARK_PURPLE + \"PURPLE PILLAR!\", 2);\n                                    break;\n                                default:\n                                    Utils.createTitle(EnumChatFormatting.WHITE + \"STORM STUNNED!\", 2);\n                            }\n                        }\n\n                    }\n                } else if (message.contains(\"I should have known that I stood no chance.\")) {\n                    Utils.createTitle(EnumChatFormatting.RED + \"RED PILLAR!\", 2);\n                }\n            } else if (message.startsWith(\"[BOSS] Necron:\") && message.contains(\"ARGH!\")) {\n                Utils.createTitle(EnumChatFormatting.RED + \"EXPLOSION OVER!\", 2);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/NoF3Coords.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Dropdown;\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.player.EntityPlayer;\n\npublic class NoF3Coords extends Hud {\n\n    @Exclude\n    String exampleText = ModConfig.getColour(coordsColour) + \"74 / 14 / -26 (141.1 / 6.7)\";\n\n    @Dropdown(\n            name = \"Coordinate/Angle Color\",\n            options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n    )\n    public static int coordsColour = 15;\n\n    @Override\n    protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n        if (example) {\n            TextRenderer.drawHUDText(exampleText, x, y, scale);\n            return;\n        }\n\n        if (enabled) {\n            TextRenderer.drawHUDText(getText(), x, y, scale);\n        }\n    }\n\n    @Override\n    protected float getWidth(float scale, boolean example) {\n        return RenderUtils.getWidthFromText(example ? exampleText : getText()) * scale;\n    }\n\n    @Override\n    protected float getHeight(float scale, boolean example) {\n        return RenderUtils.getHeightFromText(example ? exampleText : getText()) * scale;\n    }\n\n    String getText() {\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayer player = mc.thePlayer;\n\n        double xDir = (player.rotationYaw % 360 + 360) % 360;\n        if (xDir > 180) xDir -= 360;\n        xDir = (double) Math.round(xDir * 10d) / 10d;\n        double yDir = (double) Math.round(player.rotationPitch * 10d) / 10d;\n\n        return ModConfig.getColour(coordsColour) + (int) player.posX + \" / \" + (int) player.posY + \" / \" + (int) player.posZ + \" (\" + xDir + \" / \" + yDir + \")\";\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/NotifySlayerSlain.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.ScoreboardHandler;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.monster.EntitySpider;\nimport net.minecraft.entity.monster.EntityZombie;\nimport net.minecraft.entity.passive.EntityWolf;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.event.entity.player.ArrowNockEvent;\nimport net.minecraftforge.event.entity.player.AttackEntityEvent;\nimport net.minecraftforge.event.entity.player.PlayerInteractEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class NotifySlayerSlain {\n\n    @SubscribeEvent\n    public void onInteract(PlayerInteractEvent event) {\n        if (!Utils.inSkyblock || Minecraft.getMinecraft().thePlayer != event.entityPlayer) return;\n        ItemStack item = event.entityPlayer.getHeldItem();\n        if (item == null) return;\n\n        if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_AIR) {\n            if (ModConfig.notifySlayerSlain) {\n                if (ScoreboardHandler.getSidebarLines().stream().anyMatch(x -> ScoreboardHandler.cleanSB(x).contains(\"Boss slain!\"))) {\n                    if (ScoreboardHandler.getSidebarLines().stream().anyMatch(x -> {\n                        String line = ScoreboardHandler.cleanSB(x);\n                        return Arrays.stream(new String[]{\"Howling Cave\", \"Ruins\", \"Graveyard\", \"Coal Mine\", \"Spider's Den\"}).anyMatch(line::contains);\n                    })) {\n                        if (Utils.hasRightClickAbility(item)) {\n                            List<String> lore = Utils.getItemLore(item);\n\n                            int abilityLine = -1;\n                            for (int i = 0; i < lore.size(); i++) {\n                                String line = StringUtils.stripControlCodes(lore.get(i));\n                                if (line.startsWith(\"Item Ability:\")) abilityLine = i;\n                                if (abilityLine != -1 && i > abilityLine) {\n                                    if (line.toLowerCase().contains(\"damage\")) {\n                                        Utils.createTitle(EnumChatFormatting.RED + \"Boss slain!\", 2);\n                                        break;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onArrowNock(ArrowNockEvent event) {\n        if (!Utils.inSkyblock || Minecraft.getMinecraft().thePlayer != event.entityPlayer) return;\n\n        if (ModConfig.notifySlayerSlain) {\n            if (ScoreboardHandler.getSidebarLines().stream().anyMatch(x -> ScoreboardHandler.cleanSB(x).contains(\"Boss slain!\"))) {\n                if (ScoreboardHandler.getSidebarLines().stream().anyMatch(x -> {\n                    String line = ScoreboardHandler.cleanSB(x);\n                    return Arrays.stream(new String[]{\"Howling Cave\", \"Ruins\", \"Graveyard\", \"Coal Mine\", \"Spider's Den\"}).anyMatch(line::contains);\n                })) {\n                    Utils.createTitle(EnumChatFormatting.RED + \"Boss slain!\", 2);\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onAttackingEntity(AttackEntityEvent event) {\n        if (ModConfig.notifySlayerSlain && (event.target instanceof EntityZombie || event.target instanceof EntitySpider || event.target instanceof EntityWolf)) {\n            List<String> scoreboard = ScoreboardHandler.getSidebarLines();\n\n            for (String line : scoreboard) {\n                String cleanedLine = ScoreboardHandler.cleanSB(line);\n                if (cleanedLine.contains(\"Boss slain!\")) {\n                    Utils.createTitle(EnumChatFormatting.RED + \"Boss slain!\", 2);\n                    break;\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/PetColours.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.GuiChestBackgroundDrawnEvent;\nimport me.Danker.utils.RenderUtils;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.regex.Pattern;\n\npublic class PetColours {\n\n    static Pattern petPattern = Pattern.compile(\"\\\\[Lvl [\\\\d]{1,3}]\");\n\n    @SubscribeEvent\n    public void onGuiRender(GuiChestBackgroundDrawnEvent event) {\n        if (ModConfig.petColours) {\n            for (Slot slot : event.slots) {\n                ItemStack item = slot.getStack();\n                if (item == null) continue;\n                String name = item.getDisplayName();\n                if (petPattern.matcher(StringUtils.stripControlCodes(name)).find()) {\n                    if (name.endsWith(\"aHealer\") || name.endsWith(\"aMage\") || name.endsWith(\"aBerserk\") || name.endsWith(\"aArcher\") || name.endsWith(\"aTank\"))\n                        continue;\n                    int colour;\n                    int petLevel;\n\n                    try {\n                        String level = name.substring(name.indexOf(\"Lvl\") + 4, name.indexOf(\"]\"));\n                        petLevel = Integer.parseInt(level);\n                    } catch (NumberFormatException ex) {\n                        ex.printStackTrace();\n                        continue;\n                    }\n\n                    if (petLevel == 100 || petLevel == 200) {\n                        colour = ModConfig.pet100Colour.getRGB();\n                    } else if ((petLevel < 100 && petLevel >= 90) || petLevel >= 190) {\n                        colour = ModConfig.pet90To99Colour.getRGB();\n                    } else if ((petLevel < 100 && petLevel >= 80) || petLevel >= 180) {\n                        colour = ModConfig.pet80To89Colour.getRGB();\n                    } else if ((petLevel < 100 && petLevel >= 70) || petLevel >= 170) {\n                        colour = ModConfig.pet70To79Colour.getRGB();\n                    } else if ((petLevel < 100 && petLevel >= 60) || petLevel >= 160) {\n                        colour = ModConfig.pet60To69Colour.getRGB();\n                    } else if ((petLevel < 100 && petLevel >= 50) || petLevel >= 150) {\n                        colour = ModConfig.pet50To59Colour.getRGB();\n                    } else if ((petLevel < 100 && petLevel >= 40) || petLevel >= 140) {\n                        colour = ModConfig.pet40To49Colour.getRGB();\n                    } else if ((petLevel < 100 && petLevel >= 30) || petLevel >= 130) {\n                        colour = ModConfig.pet30To39Colour.getRGB();\n                    } else if ((petLevel < 100 && petLevel >= 20) || petLevel >= 120) {\n                        colour = ModConfig.pet20To29Colour.getRGB();\n                    } else if ((petLevel < 100 && petLevel >= 10) || petLevel >= 110) {\n                        colour = ModConfig.pet10To19Colour.getRGB();\n                    } else {\n                        colour = ModConfig.pet1To9Colour.getRGB();\n                    }\n                    RenderUtils.drawOnSlot(event.chestSize, slot.xDisplayPosition, slot.yDisplayPosition, colour);\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/PowderTracker.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Button;\nimport cc.polyfrost.oneconfig.config.annotations.Dropdown;\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.config.annotations.Switch;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.network.NetworkPlayerInfo;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\nimport org.apache.commons.lang3.time.StopWatch;\n\nimport java.text.NumberFormat;\nimport java.util.Collection;\nimport java.util.Locale;\n\npublic class PowderTracker {\n\n    public static StopWatch powderStopwatch = new StopWatch();\n    private static int lastMithril = -1;\n    private static int mithrilGained = 0;\n    private static int lastGemstone = -1;\n    private static int gemstoneGained = 0;\n    private static int lastGlacite = -1;\n    private static int glaciteGained = 0;\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            if (Utils.currentLocation == Location.DWARVEN_MINES || Utils.currentLocation == Location.CRYSTAL_HOLLOWS || Utils.currentLocation == Location.MINESHAFT) {\n                if (Minecraft.getMinecraft().getNetHandler() == null) return;\n                Collection<NetworkPlayerInfo> players = Minecraft.getMinecraft().getNetHandler().getPlayerInfoMap();\n                for (NetworkPlayerInfo player : players) {\n                    if (player == null || player.getDisplayName() == null) continue;\n                    String text = player.getDisplayName().getUnformattedText();\n                    if (text.startsWith(\" Mithril: \")) {\n                        int mithril = Integer.parseInt(text.replaceAll(\"\\\\D\", \"\"));\n                        if (powderStopwatch.isStarted() && !powderStopwatch.isSuspended() && lastMithril != -1 && mithril > lastMithril) mithrilGained += mithril - lastMithril;\n                        lastMithril = mithril;\n                    } else if (text.startsWith(\" Gemstone: \")) {\n                        int gemstone = Integer.parseInt(text.replaceAll(\"\\\\D\", \"\"));\n                        if (powderStopwatch.isStarted() && !powderStopwatch.isSuspended() && lastGemstone != -1 && gemstone > lastGemstone) gemstoneGained += gemstone - lastGemstone;\n                        lastGemstone = gemstone;\n                    } else if (text.startsWith(\" Glacite: \")) {\n                        int glacite = Integer.parseInt(text.replaceAll(\"\\\\D\", \"\"));\n                        if (powderStopwatch.isStarted() && !powderStopwatch.isSuspended() && lastGlacite != -1 && glacite > lastGlacite) glaciteGained += glacite - lastGlacite;\n                        lastGlacite = glacite;\n                    }\n                }\n            }\n        }\n    }\n\n    public static void onKey() {\n        if (!Utils.inSkyblock) return;\n\n        EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;\n        if (powderStopwatch.isStarted() && powderStopwatch.isSuspended()) {\n            powderStopwatch.resume();\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Powder tracker started.\"));\n        } else if (!powderStopwatch.isStarted()) {\n            powderStopwatch.start();\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Powder tracker started.\"));\n        } else if (powderStopwatch.isStarted() && !powderStopwatch.isSuspended()) {\n            powderStopwatch.suspend();\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Powder tracker paused.\"));\n        }\n    }\n\n    public static void reset() {\n        powderStopwatch = new StopWatch();\n        lastMithril = -1;\n        mithrilGained = 0;\n        lastGemstone = -1;\n        gemstoneGained = 0;\n        lastGlacite = -1;\n        glaciteGained = 0;\n    }\n\n    public static class PowderTrackerHud extends Hud {\n\n        @Exclude\n        String exampleText = EnumChatFormatting.DARK_GREEN + \"Mithril Gained: 74,264\\n\" +\n                             EnumChatFormatting.DARK_GREEN + \"Mithril Per Hour: 107,326\\n\" +\n                             EnumChatFormatting.LIGHT_PURPLE + \"Gemstone Gained: 101,299\\n\" +\n                             EnumChatFormatting.LIGHT_PURPLE + \"Gemstone Per Hour: 146,397\\n\" +\n                             EnumChatFormatting.AQUA + \"Glacite Gained: 123,456\\n\" +\n                             EnumChatFormatting.AQUA + \"Glacite Per Hour: 178,418\\n\" +\n                             ModConfig.getColour(powderTrackerColour) + \"Time Elapsed: \" + Utils.getTimeBetween(0, 2491);\n\n        @Button(\n                name = \"Start Powder Tracker\",\n                text = \"Start\",\n                category = \"Trackers\",\n                subcategory = \"Powder Tracker\"\n        )\n        Runnable startPowderTracker = () -> {\n            if (PowderTracker.powderStopwatch.isStarted() && PowderTracker.powderStopwatch.isSuspended()) {\n                PowderTracker.powderStopwatch.resume();\n            } else if (!PowderTracker.powderStopwatch.isStarted()) {\n                PowderTracker.powderStopwatch.start();\n            }\n        };\n\n        @Button(\n                name = \"Stop Powder Tracker\",\n                text = \"Stop\",\n                category = \"Trackers\",\n                subcategory = \"Powder Tracker\"\n        )\n        Runnable stopPowderTracker = () -> {\n            if (PowderTracker.powderStopwatch.isStarted() && !PowderTracker.powderStopwatch.isSuspended()) {\n                PowderTracker.powderStopwatch.suspend();\n            }\n        };\n\n        @Dropdown(\n                name = \"Powder Tracker Text Color\",\n                options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"},\n                category = \"Trackers\",\n                subcategory = \"Powder Tracker\"\n        )\n        public static int powderTrackerColour = 11;\n\n        @Button(\n                name = \"Reset Powder Tracker\",\n                text = \"Reset\",\n                category = \"Trackers\",\n                subcategory = \"Powder Tracker\"\n        )\n        Runnable resetPowderTracker = PowderTracker::reset;\n\n        @Switch(\n                name = \"Only show in CH and DM\",\n                description = \"Only display if you're in the Crystal Hollows or Dwarven Mines.\",\n                category = \"Trackers\",\n                subcategory = \"Powder Tracker\"\n        )\n        public static boolean onlyInArea = true;\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            if (example) {\n                TextRenderer.drawHUDText(exampleText, x, y, scale);\n                return;\n            }\n\n            if (enabled && Utils.inSkyblock) {\n                if (!onlyInArea || (Utils.currentLocation == Location.DWARVEN_MINES || Utils.currentLocation == Location.CRYSTAL_HOLLOWS || Utils.currentLocation == Location.MINESHAFT)) {\n                    TextRenderer.drawHUDText(getText(), x, y, scale);\n                }\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return RenderUtils.getWidthFromText(example ? exampleText : getText()) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return RenderUtils.getHeightFromText(example ? exampleText : getText()) * scale;\n        }\n\n        String getText() {\n            int mithrilPerHour = (int) Math.round(mithrilGained / ((powderStopwatch.getTime() + 1) / 3600000d));\n            int gemstonePerHour = (int) Math.round(gemstoneGained / ((powderStopwatch.getTime() + 1) / 3600000d));\n            int glacitePerHour = (int) Math.round(glaciteGained / ((powderStopwatch.getTime() + 1) / 3600000d));\n\n            NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);\n            String powderTrackerText = EnumChatFormatting.DARK_GREEN + \"Mithril Gained: \" + nf.format(mithrilGained) + \"\\n\" +\n                                       EnumChatFormatting.DARK_GREEN + \"Mithril Per Hour: \" + nf.format(mithrilPerHour) + \"\\n\" +\n                                       EnumChatFormatting.LIGHT_PURPLE + \"Gemstone Gained: \" + nf.format(gemstoneGained) + \"\\n\" +\n                                       EnumChatFormatting.LIGHT_PURPLE + \"Gemstone Per Hour: \" + nf.format(gemstonePerHour) + \"\\n\" +\n                                       EnumChatFormatting.AQUA + \"Glacite Gained: \" + nf.format(glaciteGained) + \"\\n\" +\n                                       EnumChatFormatting.AQUA + \"Glacite Per Hour: \" + nf.format(glacitePerHour) + \"\\n\" +\n                                       ModConfig.getColour(powderTrackerColour) + \"Time Elapsed: \" + Utils.getTimeBetween(0, powderStopwatch.getTime() / 1000d);\n            if (!powderStopwatch.isStarted() || powderStopwatch.isSuspended()) {\n                powderTrackerText += \"\\n\" + EnumChatFormatting.RED + \"PAUSED\";\n            }\n\n            return powderTrackerText;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/Reparty.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.commands.RepartyCommand;\nimport me.Danker.config.ModConfig;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class Reparty {\n\n    @SubscribeEvent(priority = EventPriority.HIGHEST)\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        // Getting party\n        if (RepartyCommand.gettingParty) {\n            if (message.contains(\"-----\")) {\n                switch(RepartyCommand.Delimiter) {\n                    case 0:\n                        System.out.println(\"Get Party Delimiter Cancelled\");\n                        RepartyCommand.Delimiter++;\n                        event.setCanceled(true);\n                        return;\n                    case 1:\n                        System.out.println(\"Done querying party\");\n                        RepartyCommand.gettingParty = false;\n                        RepartyCommand.Delimiter = 0;\n                        event.setCanceled(true);\n                        return;\n                }\n            }else if (message.startsWith(\"Party M\") || message.startsWith(\"Party Leader\")){\n                EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;\n\n                Pattern party_start_pattern = Pattern.compile(\"^Party Members \\\\((\\\\d+)\\\\)$\");\n                Pattern leader_pattern = Pattern.compile(\"^Party Leader: (?:\\\\[.+?] )?(\\\\w+) ●$\");\n                Pattern members_pattern = Pattern.compile(\" (?:\\\\[.+?] )?(\\\\w+) ●\");\n                Matcher party_start = party_start_pattern.matcher(message);\n                Matcher leader = leader_pattern.matcher(message);\n                Matcher members = members_pattern.matcher(message);\n\n                if (party_start.matches() && Integer.parseInt(party_start.group(1)) == 1) {\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"You cannot reparty yourself.\"));\n                    RepartyCommand.partyThread.interrupt();\n                } else if (leader.matches() && !(leader.group(1).equals(player.getName()))) {\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"You are not party leader.\"));\n                    RepartyCommand.partyThread.interrupt();\n                } else {\n                    while (members.find()) {\n                        String partyMember = members.group(1);\n                        if (!partyMember.equals(player.getName())) {\n                            RepartyCommand.party.add(partyMember);\n                            System.out.println(partyMember);\n                        }\n                    }\n                }\n                event.setCanceled(true);\n                return;\n            }\n        }\n        // Disbanding party\n        if (RepartyCommand.disbanding) {\n            if (message.contains(\"-----\")) {\n                switch (RepartyCommand.Delimiter) {\n                    case 0:\n                        System.out.println(\"Disband Delimiter Cancelled\");\n                        RepartyCommand.Delimiter++;\n                        event.setCanceled(true);\n                        return;\n                    case 1:\n                        System.out.println(\"Done disbanding\");\n                        RepartyCommand.disbanding = false;\n                        RepartyCommand.Delimiter = 0;\n                        event.setCanceled(true);\n                        return;\n                }\n            } else if (message.endsWith(\"has disbanded the party!\")) {\n                event.setCanceled(true);\n                return;\n            }\n        }\n        // Inviting\n        if (RepartyCommand.inviting) {\n            if (message.contains(\"-----\")) {\n                switch (RepartyCommand.Delimiter) {\n                    case 1:\n                        event.setCanceled(true);\n                        RepartyCommand.Delimiter = 0;\n                        System.out.println(\"Player Invited!\");\n                        RepartyCommand.inviting = false;\n                        return;\n                    case 0:\n                        RepartyCommand.Delimiter++;\n                        event.setCanceled(true);\n                        return;\n                }\n            } else if (message.endsWith(\" to the party! They have 60 seconds to accept.\")) {\n                Pattern invitePattern = Pattern.compile(\"(?:(?:\\\\[.+?] )?(?:\\\\w+) invited )(?:\\\\[.+?] )?(\\\\w+)\");\n                Matcher invitee = invitePattern.matcher(message);\n                if (invitee.find()) {\n                    System.out.println(\"\" + invitee.group(1) + \": \" + RepartyCommand.repartyFailList.remove(invitee.group(1)));\n                }\n                event.setCanceled(true);\n                return;\n            } else if (message.contains(\"Couldn't find a player\") || message.contains(\"You cannot invite that player\")) {\n                event.setCanceled(true);\n                return;\n            }\n        }\n        // Fail Inviting\n        if (RepartyCommand.failInviting) {\n            if (message.contains(\"-----\")) {\n                switch (RepartyCommand.Delimiter) {\n                    case 1:\n                        event.setCanceled(true);\n                        RepartyCommand.Delimiter = 0;\n                        System.out.println(\"Player Invited!\");\n                        RepartyCommand.inviting = false;\n                        return;\n                    case 0:\n                        RepartyCommand.Delimiter++;\n                        event.setCanceled(true);\n                }\n            } else if (message.endsWith(\" to the party! They have 60 seconds to accept.\")) {\n                Pattern invitePattern = Pattern.compile(\"(?:(?:\\\\[.+?] )?(?:\\\\w+) invited )(?:\\\\[.+?] )?(\\\\w+)\");\n                Matcher invitee = invitePattern.matcher(message);\n                if (invitee.find()) {\n                    System.out.println(\"\" + invitee.group(1) + \": \" + RepartyCommand.repartyFailList.remove(invitee.group(1)));\n                }\n                event.setCanceled(true);\n            } else if (message.contains(\"Couldn't find a player\") || message.contains(\"You cannot invite that player\")) {\n                event.setCanceled(true);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/Skill50Display.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Dropdown;\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.config.annotations.Number;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.text.NumberFormat;\nimport java.util.Locale;\n\npublic class Skill50Display {\n\n    public static int skillTimer = -1;\n    public static boolean showSkill = false;\n    public static String skillText = \"\";\n\n    @SubscribeEvent(priority = EventPriority.HIGHEST)\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!Utils.inSkyblock || event.type != 2) return;\n\n        String[] actionBarSections = event.message.getUnformattedText().split(\" {3,}\");\n\n        for (String section : actionBarSections) {\n            if (ModConfig.maxSkillHud.isEnabled() && section.contains(\"+\") && section.contains(\"(\") && section.contains(\")\") && !section.contains(\"Runecrafting\")) {\n                if (section.contains(\"/\")) {\n                    String xpGained = section.substring(section.indexOf(\"+\"), section.indexOf(\"(\") - 1);\n\n                    double currentXp;\n                    try {\n                        currentXp = Double.parseDouble(section.substring(section.indexOf(\"(\") + 1, section.indexOf(\"/\")).replace(\",\", \"\"));\n                    } catch (NumberFormatException ex) {\n                        ex.printStackTrace();\n                        return;\n                    }\n\n                    int limit;\n                    int totalXp;\n                    if (section.contains(\"Farming\") || section.contains(\"Enchanting\") || section.contains(\"Mining\") || section.contains(\"Combat\")) {\n                        limit = 60;\n                        totalXp = 111672425;\n                    } else {\n                        limit = 50;\n                        totalXp = 55172425;\n                    }\n\n                    int nextLevelXp;\n                    String nextLevelXpString = section.substring(section.indexOf(\"/\") + 1, section.indexOf(\")\")).replaceAll(\",\", \"\");\n                    if (nextLevelXpString.contains(\"k\")) {\n                        nextLevelXp = (int) (Double.parseDouble(nextLevelXpString.substring(0, nextLevelXpString.indexOf(\"k\"))) * 1000);\n                    } else {\n                        nextLevelXp = Integer.parseInt(nextLevelXpString);\n                    }\n\n                    int previousXp = Utils.getPastXpEarned(nextLevelXp, limit);\n                    double percentage = Math.floor(((currentXp + previousXp) / totalXp) * 10000D) / 100D;\n\n                    NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);\n                    skillTimer = MaxSkillHud.maxSkillTime * 20;\n                    showSkill = true;\n                    skillText = ModConfig.getColour(MaxSkillHud.maxSkillDisplayColour) + xpGained + \" (\" + nf.format(currentXp + previousXp) + \"/\" + nf.format(totalXp) + \") \" + percentage + \"%\";\n                } else {\n                    if (!Utils.skillsInitialized()) {\n                        return;\n                    }\n\n                    String xpGained = section.substring(section.indexOf(\"+\"), section.indexOf(\"(\") - 1);\n                    double percentage = Double.parseDouble(section.substring(section.indexOf(\"(\") + 1, section.indexOf(\"%\")));\n                    int level = 1;\n                    if (section.contains(\"Farming\")) {\n                        level = DankersSkyblockMod.farmingLevel;\n                    } else if (section.contains(\"Mining\")) {\n                        level = DankersSkyblockMod.miningLevel;\n                    } else if (section.contains(\"Combat\")) {\n                        level = DankersSkyblockMod.combatLevel;\n                    } else if (section.contains(\"Foraging\")) {\n                        level = DankersSkyblockMod.foragingLevel;\n                    } else if (section.contains(\"Fishing\")) {\n                        level = DankersSkyblockMod.fishingLevel;\n                    } else if (section.contains(\"Enchanting\")) {\n                        level = DankersSkyblockMod.enchantingLevel;\n                    } else if (section.contains(\"Alchemy\")) {\n                        level = DankersSkyblockMod.alchemyLevel;\n                    } else if (section.contains(\"Carpentry\")) {\n                        level = DankersSkyblockMod.carpentryLevel;\n                    }\n\n                    double currentXp = Utils.getTotalXpEarned(level, percentage);\n                    int totalXp = section.contains(\"Farming\") || section.contains(\"Enchanting\") || section.contains(\"Mining\") || section.contains(\"Combat\") ? 111672425 : 55172425;\n                    double percentageTo50 = Math.floor((currentXp / totalXp) * 10000D) / 100D;\n\n                    NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);\n                    skillTimer = MaxSkillHud.maxSkillTime * 20;\n                    showSkill = true;\n                    skillText = ModConfig.getColour(MaxSkillHud.maxSkillDisplayColour) + xpGained + \" (\" + nf.format(currentXp) + \"/\" + nf.format(totalXp) + \") \" + percentageTo50 + \"%\";\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        if (skillTimer >= 0) {\n            if (skillTimer == 0) {\n                showSkill = false;\n            }\n            skillTimer--;\n        }\n    }\n\n    public static class MaxSkillHud extends Hud {\n\n        @Exclude\n        String exampleText = ModConfig.getColour(maxSkillDisplayColour) + \"+3.5 Farming (28,882,117.7/55,172,425) 52.34%\";\n\n        @Dropdown(\n                name = \"Progress to Max Skill Text Color\",\n                options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n        )\n        public static int maxSkillDisplayColour = 11;\n\n        @Number(\n                name = \"Length to Display Progress (seconds)\",\n                description = \"The amount of time to display progress to max skill level in seconds.\",\n                min = 1, max = 3600\n        )\n        public static int maxSkillTime = 3;\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            if (example) {\n                TextRenderer.drawHUDText(exampleText, x, y, scale);\n                return;\n            }\n\n            if (enabled) {\n                if (!Utils.skillsInitialized() && Utils.inSkyblock) {\n                    TextRenderer.drawHUDText(EnumChatFormatting.RED + \"Please open the skill menu to use skill features. (/skills)\", x, y, scale);\n                    return;\n                }\n\n                if (showSkill) {\n                    TextRenderer.drawHUDText(skillText, x, y, scale);\n                }\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return RenderUtils.getWidthFromText(example ? exampleText : skillText) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return RenderUtils.getHeightFromText(example ? exampleText : skillText) * scale;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/SkillTracker.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Button;\nimport cc.polyfrost.oneconfig.config.annotations.Dropdown;\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.config.annotations.Switch;\nimport cc.polyfrost.oneconfig.config.migration.CfgName;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.client.event.GuiOpenEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport org.apache.commons.lang3.time.StopWatch;\n\nimport java.text.NumberFormat;\nimport java.text.ParseException;\nimport java.util.Locale;\n\npublic class SkillTracker {\n\n    static String lastSkill = \"Farming\";\n    public static StopWatch skillStopwatch = new StopWatch();\n    static double farmingXP = 0;\n    public static double farmingXPGained = 0;\n    static boolean ignoreFarming = false;\n    static double miningXP = 0;\n    public static double miningXPGained = 0;\n    static boolean ignoreMining = false;\n    static double combatXP = 0;\n    public static double combatXPGained = 0;\n    static boolean ignoreCombat = false;\n    static double foragingXP = 0;\n    public static double foragingXPGained = 0;\n    static boolean ignoreForaging = false;\n    static double fishingXP = 0;\n    public static double fishingXPGained = 0;\n    static boolean ignoreFishing = false;\n    static double enchantingXP = 0;\n    public static double enchantingXPGained = 0;\n    static boolean ignoreEnchanting = false;\n    static double alchemyXP = 0;\n    public static double alchemyXPGained = 0;\n    static boolean ignoreAlchemy = false;\n    static double xpLeft = 0;\n    static double timeSinceGained = 0;\n    static final NumberFormat nf = NumberFormat.getInstance(Locale.US);\n\n    @SubscribeEvent(priority = EventPriority.HIGHEST)\n    public void onChat(ClientChatReceivedEvent event) throws ParseException {\n        if (!Utils.inSkyblock || event.type != 2) return;\n\n        String[] actionBarSections = event.message.getUnformattedText().split(\" {3,}\");\n\n        for (String section : actionBarSections) {\n            if (section.contains(\"+\") && section.contains(\"(\") && section.contains(\")\") && !section.contains(\"Runecrafting\") && !section.contains(\"Carpentry\") && !section.contains(\"SkyBlock XP\")) {\n                if (SkillTrackerHud.autoSkillTracker && System.currentTimeMillis() / 1000 - timeSinceGained <= 2) {\n                    if (skillStopwatch.isStarted() && skillStopwatch.isSuspended()) {\n                        skillStopwatch.resume();\n                    } else if (!skillStopwatch.isStarted()) {\n                        skillStopwatch.start();\n                    }\n                }\n                timeSinceGained = System.currentTimeMillis() / 1000;\n\n                String skill = section.substring(section.indexOf(\" \") + 1, section.lastIndexOf(\" \"));\n                double totalXP;\n\n                if (section.contains(\"/\")) {\n                    int limit = section.contains(\"Farming\") || section.contains(\"Enchanting\") || section.contains(\"Mining\") || section.contains(\"Combat\") ? 60 : 50;\n                    double currentXP;\n                    try {\n                        currentXP = nf.parse(section.substring(section.indexOf(\"(\") + 1, section.indexOf(\"/\")).replace(\",\", \"\")).doubleValue();\n                    } catch (NumberFormatException ex) {\n                        ex.printStackTrace();\n                        return;\n                    }\n\n                    int xpToLevelUp;\n                    String nextLevelXpString = section.substring(section.indexOf(\"/\") + 1, section.indexOf(\")\")).replaceAll(\",\", \"\");\n                    if (nextLevelXpString.contains(\"k\")) {\n                        xpToLevelUp = (int) (nf.parse(nextLevelXpString.substring(0, nextLevelXpString.indexOf(\"k\"))).doubleValue() * 1000);\n                    } else {\n                        xpToLevelUp = nf.parse(nextLevelXpString).intValue();\n                    }\n\n                    xpLeft = xpToLevelUp - currentXP;\n                    int previousXP = Utils.getPastXpEarned(xpToLevelUp, limit);\n                    totalXP = currentXP + previousXP;\n                } else {\n                    if (!Utils.skillsInitialized()) {\n                        return;\n                    }\n\n                    int level = 1;\n                    if (section.contains(\"Farming\")) {\n                        level = DankersSkyblockMod.farmingLevel;\n                    } else if (section.contains(\"Mining\")) {\n                        level = DankersSkyblockMod.miningLevel;\n                    } else if (section.contains(\"Combat\")) {\n                        level = DankersSkyblockMod.combatLevel;\n                    } else if (section.contains(\"Foraging\")) {\n                        level = DankersSkyblockMod.foragingLevel;\n                    } else if (section.contains(\"Fishing\")) {\n                        level = DankersSkyblockMod.fishingLevel;\n                    } else if (section.contains(\"Enchanting\")) {\n                        level = DankersSkyblockMod.enchantingLevel;\n                    } else if (section.contains(\"Alchemy\")) {\n                        level = DankersSkyblockMod.alchemyLevel;\n                    } else if (section.contains(\"Carpentry\")) {\n                        level = DankersSkyblockMod.carpentryLevel;\n                    }\n\n                    totalXP = Utils.getTotalXpEarned(level, nf.parse(section.substring(section.indexOf(\"(\") + 1, section.indexOf(\"%\"))).doubleValue());\n                    xpLeft = Utils.getTotalXpEarned(level + 1, 0) - totalXP;\n                }\n\n                double add;\n                switch (skill) {\n                    case \"Farming\":\n                        lastSkill = \"Farming\";\n                        if (ignoreFarming) {\n                            ignoreFarming = false;\n                            return;\n                        }\n                        add = addXP(totalXP, farmingXP);\n                        if (add < 0) {\n                            ignoreFarming = true;\n                            return;\n                        }\n                        farmingXPGained += add;\n                        farmingXP = totalXP;\n                        break;\n                    case \"Mining\":\n                        lastSkill = \"Mining\";\n                        if (ignoreMining) {\n                            ignoreMining = false;\n                            return;\n                        }\n                        add = addXP(totalXP, miningXP);\n                        if (add < 0) {\n                            ignoreMining = true;\n                            return;\n                        }\n                        miningXPGained += add;\n                        miningXP = totalXP;\n                        break;\n                    case \"Combat\":\n                        lastSkill = \"Combat\";\n                        if (ignoreCombat) {\n                            ignoreCombat = false;\n                            return;\n                        }\n                        add = addXP(totalXP, combatXP);\n                        if (add < 0) {\n                            ignoreCombat = true;\n                            return;\n                        }\n                        combatXPGained += add;\n                        combatXP = totalXP;\n                        break;\n                    case \"Foraging\":\n                        lastSkill = \"Foraging\";\n                        if (ignoreForaging) {\n                            ignoreForaging = false;\n                            return;\n                        }\n                        add = addXP(totalXP, foragingXP);\n                        if (add < 0) {\n                            ignoreForaging = true;\n                            return;\n                        }\n                        foragingXPGained += add;\n                        foragingXP = totalXP;\n                        break;\n                    case \"Fishing\":\n                        lastSkill = \"Fishing\";\n                        if (ignoreFishing) {\n                            ignoreFishing = false;\n                            return;\n                        }\n                        add = addXP(totalXP, fishingXP);\n                        if (add < 0) {\n                            ignoreFishing = true;\n                            return;\n                        }\n                        fishingXPGained += add;\n                        fishingXP = totalXP;\n                        break;\n                    case \"Enchanting\":\n                        lastSkill = \"Enchanting\";\n                        if (ignoreEnchanting) {\n                            ignoreEnchanting = false;\n                            return;\n                        }\n                        add = addXP(totalXP, enchantingXP);\n                        if (add < 0) {\n                            ignoreEnchanting = true;\n                            return;\n                        }\n                        enchantingXPGained += add;\n                        enchantingXP = totalXP;\n                        break;\n                    case \"Alchemy\":\n                        lastSkill = \"Alchemy\";\n                        if (ignoreAlchemy) {\n                            ignoreAlchemy = false;\n                            return;\n                        }\n                        add = addXP(totalXP, alchemyXP);\n                        if (add < 0) {\n                            ignoreAlchemy = true;\n                            return;\n                        }\n                        alchemyXPGained += add;\n                        alchemyXP = totalXP;\n                        break;\n                    default:\n                        System.err.println(\"Unknown skill.\");\n                }\n            }\n        }\n    }\n\n    public static void onKey() {\n        if (!Utils.inSkyblock) return;\n\n        EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;\n        if (skillStopwatch.isStarted() && skillStopwatch.isSuspended()) {\n            skillStopwatch.resume();\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Skill tracker started.\"));\n        } else if (!skillStopwatch.isStarted()) {\n            skillStopwatch.start();\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Skill tracker started.\"));\n        } else if (skillStopwatch.isStarted() && !skillStopwatch.isSuspended()) {\n            skillStopwatch.suspend();\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Skill tracker paused.\"));\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiOpen(GuiOpenEvent event) {\n        if (event.gui instanceof GuiChest && SkillTrackerHud.autoSkillTracker && skillStopwatch.isStarted() && !skillStopwatch.isSuspended()) {\n            skillStopwatch.suspend();\n        }\n    }\n\n    static double addXP(double totalXP, double skillXP) {\n        if (skillXP != 0) {\n            if (skillStopwatch.isStarted() && !skillStopwatch.isSuspended()) {\n                if (totalXP > skillXP) {\n                    return totalXP - skillXP;\n                } else {\n                    return -1;\n                }\n            }\n        }\n        return 0;\n    }\n\n    public static class SkillTrackerHud extends Hud {\n\n        @Exclude\n        String exampleText = ModConfig.getColour(skillTrackerColour) + \"Farming XP Earned: 462,425.3\\n\" +\n                             ModConfig.getColour(skillTrackerColour) + \"Time Elapsed: \" + Utils.getTimeBetween(0, 3602) + \"\\n\" +\n                             ModConfig.getColour(skillTrackerColour) + \"XP Per Hour: 462,168\";\n\n        @Button(\n                name = \"Start Skill Tracker\",\n                text = \"Start\"\n        )\n        Runnable startSkillTracker = () -> {\n            if (SkillTracker.skillStopwatch.isStarted() && SkillTracker.skillStopwatch.isSuspended()) {\n                SkillTracker.skillStopwatch.resume();\n            } else if (!SkillTracker.skillStopwatch.isStarted()) {\n                SkillTracker.skillStopwatch.start();\n            }\n        };\n\n        @Button(\n                name = \"Stop Skill Tracker\",\n                text = \"Stop\"\n        )\n        Runnable stopSkillTracker = () -> {\n            if (SkillTracker.skillStopwatch.isStarted() && !SkillTracker.skillStopwatch.isSuspended()) {\n                SkillTracker.skillStopwatch.suspend();\n            }\n        };\n\n        @CfgName(\n                name = \"AutoSkillTracker\",\n                category = \"toggles\"\n        )\n        @Switch(\n                name = \"Auto Start/Stop Skill Tracker\",\n                description = \"Automatically pauses skill tracker when opening a gui.\"\n        )\n        public static boolean autoSkillTracker = false;\n\n        @Dropdown(\n                name = \"Skill Tracker Text Color\",\n                options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n        )\n        public static int skillTrackerColour = 11;\n\n        @Button(\n                name = \"Reset Skill Tracker\",\n                text = \"Reset\"\n        )\n        Runnable resetSkillTracker = () -> {\n            SkillTracker.skillStopwatch = new StopWatch();\n            SkillTracker.farmingXPGained = 0;\n            SkillTracker.miningXPGained = 0;\n            SkillTracker.combatXPGained = 0;\n            SkillTracker.foragingXPGained = 0;\n            SkillTracker.fishingXPGained = 0;\n            SkillTracker.enchantingXPGained = 0;\n            SkillTracker.alchemyXPGained = 0;\n        };\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            Minecraft mc = Minecraft.getMinecraft();\n\n            if (example) {\n                TextRenderer.drawHUDText(exampleText, x, y, scale);\n                return;\n            }\n\n            if (enabled && Utils.inSkyblock) {\n                if (!Utils.skillsInitialized()) {\n                    TextRenderer.drawHUDText(EnumChatFormatting.RED + \"Please open the skill menu to use skill features. (/skills)\", x, y, scale);\n                    return;\n                }\n\n                TextRenderer.drawHUDText(getText(), x, y, scale);\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return RenderUtils.getWidthFromText(example ? exampleText : getText()) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return RenderUtils.getHeightFromText(example ? exampleText : getText()) * scale;\n        }\n\n        String getText() {\n            int xpPerHour;\n            double xpToShow = 0;\n            switch (lastSkill) {\n                case \"Farming\":\n                    xpToShow = farmingXPGained;\n                    break;\n                case \"Mining\":\n                    xpToShow = miningXPGained;\n                    break;\n                case \"Combat\":\n                    xpToShow = combatXPGained;\n                    break;\n                case \"Foraging\":\n                    xpToShow = foragingXPGained;\n                    break;\n                case \"Fishing\":\n                    xpToShow = fishingXPGained;\n                    break;\n                case \"Enchanting\":\n                    xpToShow = enchantingXPGained;\n                    break;\n                case \"Alchemy\":\n                    xpToShow = alchemyXPGained;\n                    break;\n                default:\n                    System.err.println(\"Unknown skill in rendering.\");\n            }\n            xpPerHour = (int) Math.round(xpToShow / ((skillStopwatch.getTime() + 1) / 3600000d));\n            String skillTrackerText = ModConfig.getColour(skillTrackerColour) + lastSkill + \" XP Earned: \" + NumberFormat.getNumberInstance(Locale.US).format(xpToShow) + \"\\n\" +\n                                      ModConfig.getColour(skillTrackerColour) + \"Time Elapsed: \" + Utils.getTimeBetween(0, skillStopwatch.getTime() / 1000d) + \"\\n\" +\n                                      ModConfig.getColour(skillTrackerColour) + \"XP Per Hour: \" + NumberFormat.getIntegerInstance(Locale.US).format(xpPerHour);\n            if (xpLeft >= 0) {\n                String time = xpPerHour == 0 ? \"Never\" : Utils.getTimeBetween(0, xpLeft / (xpPerHour / 3600D));\n                skillTrackerText += \"\\n\" + ModConfig.getColour(skillTrackerColour) + \"Time Until Next Level: \" + time;\n            }\n            if (!skillStopwatch.isStarted() || skillStopwatch.isSuspended()) {\n                skillTrackerText += \"\\n\" + EnumChatFormatting.RED + \"PAUSED\";\n            }\n\n            return skillTrackerText;\n        }\n\n    }\n\n}"
  },
  {
    "path": "src/main/java/me/Danker/features/SlayerESP.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.util.AxisAlignedBB;\nimport net.minecraft.util.StringUtils;\nimport net.minecraft.world.World;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.List;\n\n/**\n * @author CuzImClicks\n */\n\npublic class SlayerESP {\n\n    static Entity zombie = null;\n    static Entity spider = null;\n    static Entity wolf = null;\n    static Entity enderman = null;\n    static Entity blaze = null;\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        zombie = null;\n        spider = null;\n        wolf = null;\n        enderman = null;\n        blaze = null;\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.phase != TickEvent.Phase.START) return;\n\n        World world = Minecraft.getMinecraft().theWorld;\n        if (world == null) return;\n        if (zombie != null || spider != null || wolf != null || enderman != null) return;\n        // keep checking if blaze is active because it switches entities\n\n        if (DankersSkyblockMod.tickAmount % 10 == 0 && ModConfig.highlightSlayers) {\n            if (Utils.isInScoreboard(\"Slay the boss!\")) {\n                List<Entity> entities = world.getLoadedEntityList();\n                for (Entity e : entities) {\n                    String name = e.getName();\n                    if (name.contains(\"Revenant Horror\")) {\n                        zombie = e;\n                        return;\n                    } else if (name.contains(\"Tarantula Broodfather\")) {\n                        spider = e;\n                        return;\n                    } else if (name.contains(\"Sven Packmaster\")) {\n                        wolf = e;\n                        return;\n                    } else if (name.contains(\"Voidgloom Seraph\")) {\n                        enderman = e;\n                        return;\n                    } else if (name.contains(\"Inferno Demonlord\")) {\n                        blaze = e;\n                        return;\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!Utils.inSkyblock) return;\n\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n        if (message.contains(\":\")) return;\n\n        if (message.contains(\"NICE! SLAYER BOSS SLAIN!\") || message.contains(\"SLAYER QUEST COMPLETE!\") || message.contains(\"SLAYER QUEST FAILED!\")) {\n            zombie = null;\n            spider = null;\n            wolf = null;\n            enderman = null;\n            blaze = null;\n        }\n\n    }\n\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (ModConfig.highlightSlayers) {\n            if (zombie != null) {\n                AxisAlignedBB aabb = new AxisAlignedBB(zombie.posX - 0.5, zombie.posY - 2, zombie.posZ - 0.5, zombie.posX + 0.5, zombie.posY, zombie.posZ + 0.5);\n                RenderUtils.draw3DBox(aabb, ModConfig.slayerBoxColour.getRGB(), event.partialTicks);\n            } else if (spider != null) {\n                AxisAlignedBB aabb = new AxisAlignedBB(spider.posX - 0.75, spider.posY - 1, spider.posZ - 0.75, spider.posX + 0.75, spider.posY, spider.posZ + 0.75);\n                RenderUtils.draw3DBox(aabb, ModConfig.slayerBoxColour.getRGB(), event.partialTicks);\n            } else if (wolf != null) {\n                AxisAlignedBB aabb = new AxisAlignedBB(wolf.posX - 0.5, wolf.posY - 1, wolf.posZ - 0.5, wolf.posX + 0.5, wolf.posY, wolf.posZ + 0.5);\n                RenderUtils.draw3DBox(aabb, ModConfig.slayerBoxColour.getRGB(), event.partialTicks);\n            } else if (enderman != null) {\n                AxisAlignedBB aabb = new AxisAlignedBB(enderman.posX - 0.5, enderman.posY - 3, enderman.posZ - 0.5, enderman.posX + 0.5, enderman.posY, enderman.posZ + 0.5);\n                RenderUtils.draw3DBox(aabb, ModConfig.slayerBoxColour.getRGB(), event.partialTicks);\n            } else if (blaze != null) {\n                AxisAlignedBB aabb = new AxisAlignedBB(blaze.posX - 0.5, blaze.posY - 2, blaze.posZ - 0.5, blaze.posX + 0.5, blaze.posY, blaze.posZ + 0.5);\n                RenderUtils.draw3DBox(aabb, ModConfig.slayerBoxColour.getRGB(), event.partialTicks);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/SpamHider.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class SpamHider {\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!Utils.inSkyblock) return;\n        if (message.contains(\":\")) return;\n\n        // Spirit Sceptre\n        if (!ModConfig.sceptreMessages && message.contains(\"Your Spirit Sceptre hit \")) {\n            event.setCanceled(true);\n            return;\n        }\n        // Midas Staff\n        if (!ModConfig.midasStaffMessages && message.contains(\"Your Molten Wave hit \")) {\n            event.setCanceled(true);\n            return;\n        }\n        // Heals\n        if (!ModConfig.healMessages && message.contains(\" health!\") && (message.contains(\"You healed \") || message.contains(\" healed you for \"))) {\n            event.setCanceled(true);\n            return;\n        }\n        // Ability Cooldown\n        if (!ModConfig.cooldownMessages && message.contains(\"This ability is on cooldown for \")) {\n            event.setCanceled(true);\n            return;\n        }\n        // Out of mana messages\n        if (!ModConfig.manaMessages && message.contains(\"You do not have enough mana to do this!\")) {\n            event.setCanceled(true);\n            return;\n        }\n        // Implosion\n        if (!ModConfig.implosionMessages) {\n            if (message.contains(\"Your Implosion hit \") || message.contains(\"There are blocks in the way\")) {\n                event.setCanceled(true);\n                return;\n            }\n        }\n        // Kill Combo\n        if (!ModConfig.killComboMessages) {\n            if ((message.contains(\"+\") && message.contains(\" Kill Combo\")) || message.contains(\"Your Kill Combo has expired!\")) {\n                event.setCanceled(true);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/SpiritBearAlert.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class SpiritBearAlert {\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!Utils.inSkyblock) return;\n        if (message.contains(\":\")) return;\n\n        if (ModConfig.spiritBearAlerts && message.contains(\"The Spirit Bear has appeared!\")) {\n            Utils.createTitle(EnumChatFormatting.DARK_PURPLE + \"SPIRIT BEAR\", 2);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/SpiritBootsFix.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.PacketReadEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.network.play.server.S04PacketEntityEquipment;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.relauncher.ReflectionHelper;\n\nimport java.lang.reflect.Field;\n\npublic class SpiritBootsFix {\n\n    static Field slot = ReflectionHelper.findField(S04PacketEntityEquipment.class, \"equipmentSlot\", \"field_149392_b\", \"b\");\n\n    @SubscribeEvent\n    public void onPacketRead(PacketReadEvent event) {\n        if (!ModConfig.spiritBootsFix) return;\n\n        if (Utils.inSkyblock && event.packet instanceof S04PacketEntityEquipment) {\n            EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n            S04PacketEntityEquipment packet = (S04PacketEntityEquipment) event.packet;\n\n            if (player == null) return;\n            if (packet.getEntityID() == player.getEntityId()) {\n                try {\n                    slot.setAccessible(true);\n                    slot.setInt(packet, slot.getInt(packet) + 1);\n                    event.packet = packet;\n                } catch (IllegalAccessException ex) {\n                    ex.printStackTrace();\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/SpiritMaskTimer.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Dropdown;\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.renderer.GlStateManager;\nimport net.minecraft.init.Items;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.ResourceLocation;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport org.lwjgl.opengl.GL11;\n\npublic class SpiritMaskTimer {\n\n    public static double nextspiritUse = 0;\n    public static final ResourceLocation SPIRIT_ICON = new ResourceLocation(\"dsm\", \"icons/spiritmask.png\");\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        nextspiritUse = 0;\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (message.contains(\":\")) return;\n\n        if (ModConfig.spiritTimerHud.isEnabled() && message.contains(\"Spirit Mask\") && message.contains(\"Second Wind Activated! Your Spirit Mask saved your life!\")) {\n            double usedTime = System.currentTimeMillis() / 1000;\n            Minecraft mc = Minecraft.getMinecraft();\n            EntityPlayerSP player = mc.thePlayer;\n            ItemStack spiritMask = player.getCurrentArmor(3);\n            if (spiritMask != null && spiritMask.getItem() == Items.skull) {\n                int cooldownSeconds = 0;\n                for (String line : Utils.getItemLore(spiritMask)) {\n                    String stripped = StringUtils.stripControlCodes(line);\n                    if (stripped.startsWith(\"Cooldown: \"))\n                        cooldownSeconds = Integer.parseInt(stripped.replaceAll(\"\\\\D\", \"\"));\n                }\n                System.out.println(\"Parsed Spirit Mask Cooldown: \" + cooldownSeconds);\n                if (cooldownSeconds > 0)\n                    nextspiritUse = usedTime + cooldownSeconds;\n            }\n        }\n    }\n\n    public static class SpiritTimerHud extends Hud {\n\n        @Exclude\n        String exampleText = ModConfig.getColour(spiritTimerColour) + \"30s\";\n\n        @Dropdown(\n                name = \"Spirit Timer Text Color\",\n                options = {\"Black\", \"Dark Blue\", \"Dark Green\", \"Dark Aqua\", \"Dark Red\", \"Dark Purple\", \"Gold\", \"Gray\", \"Dark Gray\", \"Blue\", \"Green\", \"Aqua\", \"Red\", \"Light Purple\", \"Yellow\", \"White\"}\n        )\n        public static int spiritTimerColour = 12;\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            Minecraft mc = Minecraft.getMinecraft();\n\n            if (example) {\n                double scaleReset = Math.pow(scale, -1);\n                GL11.glScaled(scale, scale, scale);\n                GlStateManager.color(1, 1, 1, 1);\n\n                mc.getTextureManager().bindTexture(SPIRIT_ICON);\n                RenderUtils.drawModalRectWithCustomSizedTexture(x / scale, y / scale, 0, 0, 16, 16, 16, 16);\n\n                GL11.glScaled(scaleReset, scaleReset, scaleReset);\n\n                TextRenderer.drawHUDText(exampleText, x + 20 * scale, y + 5 * scale, scale);\n                return;\n            }\n\n            if (enabled) {\n                ItemStack helmetSlot = mc.thePlayer.getCurrentArmor(3);\n                if ((helmetSlot != null && helmetSlot.getDisplayName().contains(\"Spirit Mask\")) || nextspiritUse > 0) {\n                    double scaleReset = Math.pow(scale, -1);\n                    GL11.glScaled(scale, scale, scale);\n                    GlStateManager.color(1, 1, 1, 1);\n                    \n                    mc.getTextureManager().bindTexture(SPIRIT_ICON);\n                    RenderUtils.drawModalRectWithCustomSizedTexture(x / scale, y / scale, 0, 0, 16, 16, 16, 16);\n\n                    GL11.glScaled(scaleReset, scaleReset, scaleReset);\n\n                    TextRenderer.drawHUDText(getText(), x + 20 * scale, y + 5 * scale, scale);\n                }\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return (RenderUtils.getWidthFromText(example ? exampleText : getText()) + 20 * scale) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return (RenderUtils.getHeightFromText(example ? exampleText : getText()) + 5 * scale) * scale;\n        }\n\n        String getText() {\n            double timeNow = System.currentTimeMillis() / 1000;\n            if (nextspiritUse - timeNow < 0) {\n                return EnumChatFormatting.GREEN + \"READY\";\n            } else {\n                return ModConfig.getColour(spiritTimerColour) + Utils.getTimeBetween(timeNow, nextspiritUse);\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/StopSalvagingStarredItems.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ChestSlotClickedEvent;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class StopSalvagingStarredItems {\n\n    @SubscribeEvent\n    public void onSlotClick(ChestSlotClickedEvent event) {\n        ItemStack item = event.item;\n        if (ModConfig.stopSalvageStarred && event.inventoryName.startsWith(\"Salvage\")) {\n            if (item == null) return;\n            boolean inSalvageGui = false;\n            if (item.getDisplayName().contains(\"Salvage\") || item.getDisplayName().contains(\"Essence\")) {\n                ItemStack salvageItem = event.inventory.getStackInSlot(13);\n                if (salvageItem == null) return;\n                item = salvageItem;\n                inSalvageGui = true;\n            }\n            if (item.getDisplayName().contains(\"✪\") && (event.slot.slotNumber > 53 || inSalvageGui)) {\n                Minecraft.getMinecraft().thePlayer.playSound(\"note.bass\", 1, 0.5f);\n                Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Danker's Skyblock Mod has stopped you from salvaging that item!\"));\n                event.setCanceled(true);\n                return;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/TetherDisplay.java",
    "content": "package me.Danker.features;\n\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityOtherPlayerMP;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.AxisAlignedBB;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.world.World;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class TetherDisplay {\n\n    static List<String> playersInRadius = new ArrayList<>();\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayer player = mc.thePlayer;\n        World world = mc.theWorld;\n        if (DankersSkyblockMod.tickAmount % 10 == 0) {\n            if (ModConfig.tetherHud.isEnabled() && Utils.isInDungeons() && player != null && world != null) {\n                playersInRadius.clear();\n                List<EntityPlayer> teammates = world.getEntitiesWithinAABB(EntityOtherPlayerMP.class, new AxisAlignedBB(player.posX - 30, player.posY - 30, player.posZ - 30, player.posX + 30, player.posY + 30, player.posZ + 30));\n\n                for (EntityPlayer teammate : teammates) {\n                    if (Utils.isRealPlayer(teammate) && !teammate.isInvisible() && player.getDistanceToEntity(teammate) <= 30F) {\n                        playersInRadius.add(teammate.getDisplayName().getSiblings().get(0).getFormattedText());\n                    }\n                }\n            }\n        }\n    }\n\n    public static class TetherDisplayHud extends Hud {\n\n        @Exclude\n        String exampleText = EnumChatFormatting.AQUA + \"Teammates In Radius:\\n\" +\n                             EnumChatFormatting.GREEN + \"NoticeMehSenpai\\n\" +\n                             EnumChatFormatting.GREEN + \"DeathStreeks\\n\" +\n                             EnumChatFormatting.GREEN + \"Not_A_Neko\\n\" +\n                             EnumChatFormatting.GREEN + \"Minikloon\";\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            if (example) {\n                TextRenderer.drawHUDText(exampleText, x, y, scale);\n                return;\n            }\n\n            if (enabled && Utils.isInDungeons()) {\n                TextRenderer.drawHUDText(getText(), x, y, scale);\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return RenderUtils.getWidthFromText(example ? exampleText : getText()) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return RenderUtils.getHeightFromText(example ? exampleText : getText()) * scale;\n        }\n\n        String getText() {\n            String teammates;\n            if (playersInRadius.size() > 0) {\n                teammates = String.join(\"\\n\", playersInRadius);\n            } else {\n                teammates = EnumChatFormatting.RED + \"NONE\";\n            }\n\n            return EnumChatFormatting.AQUA + \"Teammates In Radius:\\n\" + teammates;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/UpdateChecker.java",
    "content": "package me.Danker.features;\n\nimport com.google.gson.JsonObject;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.APIHandler;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.event.ClickEvent;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraftforge.event.entity.EntityJoinWorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.versioning.DefaultArtifactVersion;\n\npublic class UpdateChecker {\n\n    static boolean updateChecked = false;\n\n    @SubscribeEvent\n    public void onJoin(EntityJoinWorldEvent event) {\n        if (!updateChecked) {\n            updateChecked = true;\n\n            // MULTI THREAD DRIFTING\n            new Thread(() -> {\n                EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n\n                System.out.println(\"Checking for updates...\");\n                JsonObject latestRelease = APIHandler.getResponse(\"https://api.github.com/repos/bowser0000/SkyblockMod/releases/latest\", false);\n\n                String latestTag = latestRelease.get(\"tag_name\").getAsString();\n                DefaultArtifactVersion currentVersion = new DefaultArtifactVersion(DankersSkyblockMod.VERSION);\n                DefaultArtifactVersion latestVersion = new DefaultArtifactVersion(latestTag.substring(1));\n\n                if (currentVersion.compareTo(latestVersion) < 0) {\n                    String releaseURL = latestRelease.get(\"html_url\").getAsString();\n\n                    ChatComponentText update = new ChatComponentText(EnumChatFormatting.GREEN + \"\" + EnumChatFormatting.BOLD + \"  [UPDATE]  \");\n                    update.setChatStyle(update.getChatStyle().setChatClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, releaseURL)));\n\n                    try {\n                        Thread.sleep(2000);\n                    } catch (InterruptedException ex) {\n                        ex.printStackTrace();\n                    }\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + DankersSkyblockMod.MODID + \" is outdated. Please update to \" + latestTag + \".\\n\").appendSibling(update));\n                }\n            }).start();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/WatcherReadyAlert.java",
    "content": "package me.Danker.features;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class WatcherReadyAlert {\n\n    @SubscribeEvent(receiveCanceled = true)\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!ModConfig.watcherReady) return;\n        if (!Utils.isInDungeons()) return;\n\n        if (message.contains(\"[BOSS] The Watcher: That will be enough for now.\")) {\n            Utils.createTitle(EnumChatFormatting.RED + \"WATCHER READY\", 2);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/loot/BlazeTracker.java",
    "content": "package me.Danker.features.loot;\n\nimport me.Danker.config.CfgConfig;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.SlayerLootDropEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class BlazeTracker {\n\n    public static int demonlords;\n    public static int derelictAshes;\n    public static int blazePowder;\n    public static int lavatearRunes;\n    public static int splashPotions;\n    public static int magmaArrows;\n    public static int manaDisintegrators;\n    public static int scorchedBooks;\n    public static int kelvinInverters;\n    public static int blazeRodDistillates;\n    public static int glowstoneDistillates;\n    public static int magmaCreamDistillates;\n    public static int netherWartDistillates;\n    public static int gabagoolDistillates;\n    public static int scorchedPowerCrystals;\n    public static int fireAspectBooks;\n    public static int fieryBurstRunes;\n    public static int opalGems;\n    public static int archfiendDice;\n    public static int duplexBooks;\n    public static int highClassArchfiendDice;\n    public static int engineeringPlans;\n    public static int subzeroInverters;\n    public static double time;\n    public static int bosses;\n\n    public static int demonlordsSession = 0;\n    public static int derelictAshesSession = 0;\n    public static int blazePowderSession = 0;\n    public static int lavatearRunesSession = 0;\n    public static int splashPotionsSession = 0;\n    public static int magmaArrowsSession = 0;\n    public static int manaDisintegratorsSession = 0;\n    public static int scorchedBooksSession = 0;\n    public static int kelvinInvertersSession = 0;\n    public static int blazeRodDistillatesSession = 0;\n    public static int glowstoneDistillatesSession = 0;\n    public static int magmaCreamDistillatesSession = 0;\n    public static int netherWartDistillatesSession = 0;\n    public static int gabagoolDistillatesSession = 0;\n    public static int scorchedPowerCrystalsSession = 0;\n    public static int fireAspectBooksSession = 0;\n    public static int fieryBurstRunesSession = 0;\n    public static int opalGemsSession = 0;\n    public static int archfiendDiceSession = 0;\n    public static int duplexBooksSession = 0;\n    public static int highClassArchfiendDiceSession = 0;\n    public static int engineeringPlansSession = 0;\n    public static int subzeroInvertersSession = 0;\n    public static double timeSession = -1;\n    public static int bossesSession = -1;\n\n    @SubscribeEvent\n    public void onLootDrop(SlayerLootDropEvent event) {\n        boolean rng = false;\n\n        switch (event.drop) {\n            case \"Enchanted Blaze Powder\":\n                blazePowder += event.amount;\n                blazePowderSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"blazePowder\", blazePowder);\n                break;\n            case \"◆ Lavatears Rune I\":\n                lavatearRunes += event.amount;\n                lavatearRunesSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"lavatearRunes\", lavatearRunes);\n                break;\n            case \"Wisp's Ice-Flavored Water I Splash Potion\":\n                splashPotions += 5;\n                splashPotionsSession += 5;\n                CfgConfig.writeIntConfig(\"blaze\", \"splashPotions\", splashPotions);\n                break;\n            case \"Bundle of Magma Arrows\":\n                magmaArrows += event.amount;\n                magmaArrowsSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"magmaArrows\", magmaArrows);\n                break;\n            case \"Mana Disintegrator\":\n                manaDisintegrators += event.amount;\n                manaDisintegratorsSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"manaDisintegrators\", manaDisintegrators);\n                break;\n            case \"Scorched Books\":\n                scorchedBooks += event.amount;\n                scorchedBooksSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"scorchedBooks\", scorchedBooks);\n                break;\n            case \"Kelvin Inverter\":\n                kelvinInverters += event.amount;\n                kelvinInvertersSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"kelvinInverters\", kelvinInverters);\n                break;\n            case \"Blaze Rod Distillate\":\n                blazeRodDistillates += event.amount;\n                blazeRodDistillatesSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"blazeRodDistillates\", blazeRodDistillates);\n                break;\n            case \"Glowstone Distillate\":\n                glowstoneDistillates += event.amount;\n                glowstoneDistillatesSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"glowstoneDistillates\", glowstoneDistillates);\n                break;\n            case \"Magma Cream Distillate\":\n                magmaCreamDistillates += event.amount;\n                magmaCreamDistillatesSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"magmaCreamDistillates\", magmaCreamDistillates);\n                break;\n            case \"Nether Wart Distillate\":\n                netherWartDistillates += event.amount;\n                netherWartDistillatesSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"netherWartDistillates\", netherWartDistillates);\n                break;\n            case \"Gabagool Distillate\":\n                gabagoolDistillates += event.amount;\n                gabagoolDistillatesSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"gabagoolDistillates\", gabagoolDistillates);\n                break;\n            case \"Scorched Power Crystal\":\n                scorchedPowerCrystals += event.amount;\n                scorchedPowerCrystalsSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"scorchedPowerCrystals\", scorchedPowerCrystals);\n                break;\n            case \"Fire Aspect III\":\n                fireAspectBooks += event.amount;\n                fireAspectBooksSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"fireAspectBooks\", fireAspectBooks);\n                break;\n            case \"◆ Fiery Burst Rune I\":\n                rng = true;\n                fieryBurstRunes += event.amount;\n                fieryBurstRunesSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"fieryBurstRunes\", fieryBurstRunes);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.RED + \"FIERY BURST RUNE!\", 3);\n                break;\n            case \"❂ Flawed Opal Gemstone\":\n                opalGems += event.amount;\n                opalGemsSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"opalGems\", opalGems);\n                break;\n            case \"Archfiend Dice\":\n                archfiendDice += event.amount;\n                archfiendDiceSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"archfiendDice\", archfiendDice);\n                break;\n            case \"Duplex I\":\n                duplexBooks += event.amount;\n                duplexBooksSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"duplexBooks\", duplexBooks);\n                break;\n            case \"High Class Archfiend Dice\":\n                rng = true;\n                highClassArchfiendDice += event.amount;\n                highClassArchfiendDiceSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"highClassArchfiendDice\", highClassArchfiendDice);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.GOLD + \"HIGH CLASS ARCHFIEND DICE!\", 5);\n                break;\n            case \"Wilson's Engineering Plans\":\n                rng = true;\n                engineeringPlans += event.amount;\n                engineeringPlansSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"engineeringPlans\", engineeringPlans);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.GOLD + \"ENGINEERING PLANS!\", 3);\n                break;\n            case \"Subzero Inverter\":\n                rng = true;\n                subzeroInverters += event.amount;\n                subzeroInvertersSession += event.amount;\n                CfgConfig.writeIntConfig(\"blaze\", \"subzeroInverters\", subzeroInverters);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.GOLD + \"SUBZERO INVERTER!\", 3);\n                break;\n        }\n\n        if (rng) {\n            time = System.currentTimeMillis() / 1000;\n            bosses = 0;\n            timeSession = System.currentTimeMillis() / 1000;\n            bossesSession = 0;\n            CfgConfig.writeDoubleConfig(\"blaze\", \"timeRNG\", time);\n            CfgConfig.writeIntConfig(\"blaze\", \"bossRNG\", 0);\n        }\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.type == 2) return;\n\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (message.contains(\":\")) return;\n\n        if (message.contains(\"   Blaze Slayer LVL \")) {\n            demonlords++;\n            demonlordsSession++;\n            if (bosses != -1) {\n                bosses++;\n            }\n            if (bossesSession != -1) {\n                bossesSession++;\n            }\n            CfgConfig.writeIntConfig(\"blaze\", \"demonlords\", demonlords);\n            CfgConfig.writeIntConfig(\"blaze\", \"bossRNG\", bosses);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/loot/CatacombsTracker.java",
    "content": "package me.Danker.features.loot;\n\nimport me.Danker.config.CfgConfig;\nimport me.Danker.events.ChestSlotClickedEvent;\nimport me.Danker.handlers.ScoreboardHandler;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.List;\n\npublic class CatacombsTracker {\n\n    // Catacombs Dungeons\n    public static int recombobulators;\n    public static int fumingPotatoBooks;\n    // F1\n    public static int f1SPlus;\n    public static int bonzoStaffs;\n    public static int balloonSnakes;\n    public static double f1CoinsSpent;\n    public static double f1TimeSpent;\n    // F2\n    public static int f2SPlus;\n    public static int scarfStudies;\n    public static int adaptiveSwords;\n    public static int adaptiveBelts;\n    public static double f2CoinsSpent;\n    public static double f2TimeSpent;\n    // F3\n    public static int f3SPlus;\n    public static int adaptiveHelms;\n    public static int adaptiveChests;\n    public static int adaptiveLegs;\n    public static int adaptiveBoots;\n    public static double f3CoinsSpent;\n    public static double f3TimeSpent;\n    // F4\n    public static int f4SPlus;\n    public static int spiritWings;\n    public static int spiritBones;\n    public static int spiritBoots;\n    public static int spiritSwords;\n    public static int spiritBows;\n    public static int epicSpiritPets;\n    public static int legSpiritPets;\n    public static double f4CoinsSpent;\n    public static double f4TimeSpent;\n    // F5\n    public static int f5SPlus;\n    public static int warpedStones;\n    public static int shadowAssHelms;\n    public static int shadowAssChests;\n    public static int shadowAssLegs;\n    public static int shadowAssBoots;\n    public static int shadowAssCloaks;\n    public static int lastBreaths;\n    public static int lividDaggers;\n    public static int shadowFurys;\n    public static double f5CoinsSpent;\n    public static double f5TimeSpent;\n    // F6\n    public static int f6SPlus;\n    public static int ancientRoses;\n    public static int precursorEyes;\n    public static int giantsSwords;\n    public static int necroLordHelms;\n    public static int necroLordChests;\n    public static int necroLordLegs;\n    public static int necroLordBoots;\n    public static int necroSwords;\n    public static int soulweaverGloves;\n    public static int felSkulls;\n    public static int f6Rerolls;\n    public static double f6CoinsSpent;\n    public static double f6TimeSpent;\n    // F7\n    public static int f7SPlus;\n    public static int witherBloods;\n    public static int witherCloaks;\n    public static int implosions;\n    public static int witherShields;\n    public static int shadowWarps;\n    public static int necronsHandles;\n    public static int autoRecombs;\n    public static int witherHelms;\n    public static int witherChests;\n    public static int witherLegs;\n    public static int witherBoots;\n    public static int f7Rerolls;\n    public static double f7CoinsSpent;\n    public static double f7TimeSpent;\n    // MM\n    public static int m1S;\n    public static int m1SPlus;\n    public static int m2S;\n    public static int m2SPlus;\n    public static int m3S;\n    public static int m3SPlus;\n    public static int m4S;\n    public static int m4SPlus;\n    public static int m5S;\n    public static int m5SPlus;\n    public static int m6S;\n    public static int m6SPlus;\n    public static int m7S;\n    public static int m7SPlus;\n    public static int firstStars;\n    public static int secondStars;\n    public static int thirdStars;\n    public static int fourthStars;\n    public static int fifthStars;\n    public static int necronDyes;\n    public static int darkClaymores;\n    public static int masterRerolls;\n    public static double masterCoinsSpent;\n    public static double masterTimeSpent;\n\n    // Catacombs Dungeons\n    public static int recombobulatorsSession = 0;\n    public static int fumingPotatoBooksSession = 0;\n    // F1\n    public static int f1SPlusSession = 0;\n    public static int bonzoStaffsSession = 0;\n    public static int balloonSnakesSession = 0;\n    public static double f1CoinsSpentSession = 0;\n    public static double f1TimeSpentSession = 0;\n    // F2\n    public static int f2SPlusSession = 0;\n    public static int scarfStudiesSession = 0;\n    public static int adaptiveSwordsSession = 0;\n    public static int adaptiveBeltsSession = 0;\n    public static double f2CoinsSpentSession = 0;\n    public static double f2TimeSpentSession = 0;\n    // F3\n    public static int f3SPlusSession = 0;\n    public static int adaptiveHelmsSession = 0;\n    public static int adaptiveChestsSession = 0;\n    public static int adaptiveLegsSession = 0;\n    public static int adaptiveBootsSession = 0;\n    public static double f3CoinsSpentSession = 0;\n    public static double f3TimeSpentSession = 0;\n    // F4\n    public static int f4SPlusSession = 0;\n    public static int spiritWingsSession = 0;\n    public static int spiritBonesSession = 0;\n    public static int spiritBootsSession = 0;\n    public static int spiritSwordsSession = 0;\n    public static int spiritBowsSession = 0;\n    public static int epicSpiritPetsSession = 0;\n    public static int legSpiritPetsSession = 0;\n    public static double f4CoinsSpentSession = 0;\n    public static double f4TimeSpentSession = 0;\n    // F5\n    public static int f5SPlusSession = 0;\n    public static int warpedStonesSession = 0;\n    public static int shadowAssHelmsSession = 0;\n    public static int shadowAssChestsSession = 0;\n    public static int shadowAssLegsSession = 0;\n    public static int shadowAssBootsSession = 0;\n    public static int shadowAssCloaksSession = 0;\n    public static int lastBreathsSession = 0;\n    public static int lividDaggersSession = 0;\n    public static int shadowFurysSession = 0;\n    public static double f5CoinsSpentSession = 0;\n    public static double f5TimeSpentSession = 0;\n    // F6\n    public static int f6SPlusSession = 0;\n    public static int ancientRosesSession = 0;\n    public static int precursorEyesSession = 0;\n    public static int giantsSwordsSession = 0;\n    public static int necroLordHelmsSession = 0;\n    public static int necroLordChestsSession = 0;\n    public static int necroLordLegsSession = 0;\n    public static int necroLordBootsSession = 0;\n    public static int necroSwordsSession = 0;\n    public static int soulweaverGlovesSession = 0;\n    public static int felSkullsSession = 0;\n    public static int f6RerollsSession = 0;\n    public static double f6CoinsSpentSession = 0;\n    public static double f6TimeSpentSession = 0;\n    // F7\n    public static int f7SPlusSession = 0;\n    public static int witherBloodsSession = 0;\n    public static int witherCloaksSession = 0;\n    public static int implosionsSession = 0;\n    public static int witherShieldsSession = 0;\n    public static int shadowWarpsSession = 0;\n    public static int necronsHandlesSession = 0;\n    public static int autoRecombsSession = 0;\n    public static int witherHelmsSession = 0;\n    public static int witherChestsSession = 0;\n    public static int witherLegsSession = 0;\n    public static int witherBootsSession = 0;\n    public static int f7RerollsSession = 0;\n    public static double f7CoinsSpentSession = 0;\n    public static double f7TimeSpentSession = 0;\n    // MM\n    public static int m1SSession = 0;\n    public static int m1SPlusSession = 0;\n    public static int m2SSession = 0;\n    public static int m2SPlusSession = 0;\n    public static int m3SSession = 0;\n    public static int m3SPlusSession = 0;\n    public static int m4SSession = 0;\n    public static int m4SPlusSession = 0;\n    public static int m5SSession = 0;\n    public static int m5SPlusSession = 0;\n    public static int m6SSession = 0;\n    public static int m6SPlusSession = 0;\n    public static int m7SSession = 0;\n    public static int m7SPlusSession = 0;\n    public static int firstStarsSession = 0;\n    public static int secondStarsSession = 0;\n    public static int thirdStarsSession = 0;\n    public static int fourthStarsSession = 0;\n    public static int fifthStarsSession = 0;\n    public static int necronDyesSession = 0;\n    public static int darkClaymoresSession = 0;\n    public static int masterRerollsSession = 0;\n    public static double masterCoinsSpentSession = 0;\n    public static double masterTimeSpentSession = 0;\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (Utils.currentLocation != Location.CATACOMBS && Utils.currentLocation != Location.DUNGEON_HUB) return;\n        if (event.type == 2) return;\n\n        if (message.contains(\"    Team Score: \")) {\n            if (message.contains(\"(S+)\")) {\n                switch (Utils.currentFloor) {\n                    case F1:\n                        f1SPlus++;\n                        f1SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"floorOneSPlus\", f1SPlus);\n                        break;\n                    case F2:\n                        f2SPlus++;\n                        f2SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"floorTwoSPlus\", f2SPlus);\n                        break;\n                    case F3:\n                        f3SPlus++;\n                        f3SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"floorThreeSPlus\", f3SPlus);\n                        break;\n                    case F4:\n                        f4SPlus++;\n                        f4SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"floorFourSPlus\", f4SPlus);\n                        break;\n                    case F5:\n                        f5SPlus++;\n                        f5SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"floorFiveSPlus\", f5SPlus);\n                        break;\n                    case F6:\n                        f6SPlus++;\n                        f6SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"floorSixSPlus\", f6SPlus);\n                        break;\n                    case F7:\n                        f7SPlus++;\n                        f7SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"floorSevenSPlus\", f7SPlus);\n                        break;\n                    case M1:\n                        m1S++;\n                        m1SPlus++;\n                        m1SSession++;\n                        m1SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterOneS\", m1S);\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterOneSPlus\", m1SPlus);\n                        break;\n                    case M2:\n                        m2S++;\n                        m2SPlus++;\n                        m2SSession++;\n                        m2SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterTwoS\", m2S);\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterTwoSPlus\", m2SPlus);\n                        break;\n                    case M3:\n                        m3S++;\n                        m3SPlus++;\n                        m3SSession++;\n                        m3SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterThreeS\", m3S);\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterThreeSPlus\", m3SPlus);\n                        break;\n                    case M4:\n                        m4S++;\n                        m4SPlus++;\n                        m4SSession++;\n                        m4SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterFourS\", m4S);\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterFourSPlus\", m4SPlus);\n                        break;\n                    case M5:\n                        m5S++;\n                        m5SPlus++;\n                        m5SSession++;\n                        m5SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterFiveS\", m5S);\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterFiveSPlus\", m5SPlus);\n                        break;\n                    case M6:\n                        m6S++;\n                        m6SPlus++;\n                        m6SSession++;\n                        m6SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterSixS\", m6S);\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterSixSPlus\", m6SPlus);\n                        break;\n                    case M7:\n                        m7S++;\n                        m7SPlus++;\n                        m7SSession++;\n                        m7SPlusSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterSevenS\", m7S);\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterSevenSPlus\", m7SPlus);\n                        break;\n                }\n            } else if (message.contains(\"(S)\")) {\n                switch (Utils.currentFloor) {\n                    case M1:\n                        m1S++;\n                        m1SSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterOneS\", m1S);\n                        break;\n                    case M2:\n                        m2S++;\n                        m2SSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterTwoS\", m2S);\n                        break;\n                    case M3:\n                        m3S++;\n                        m3SSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterThreeS\", m3S);\n                        break;\n                    case M4:\n                        m4S++;\n                        m4SSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterFourS\", m4S);\n                        break;\n                    case M5:\n                        m5S++;\n                        m5SSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterFiveS\", m5S);\n                        break;\n                    case M6:\n                        m6S++;\n                        m6SSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterSixS\", m6S);\n                        break;\n                    case M7:\n                        m7S++;\n                        m7SSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterSevenS\", m7S);\n                        break;\n                }\n            }\n        }\n\n        if (message.contains(\":\")) return;\n\n        if (message.startsWith(\"    \")) {\n            if (message.contains(\"Recombobulator 3000\")) {\n                recombobulators++;\n                recombobulatorsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"recombobulator\", recombobulators);\n            } else if (message.contains(\"Fuming Potato Book\")) {\n                fumingPotatoBooks++;\n                fumingPotatoBooksSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"fumingBooks\", fumingPotatoBooks);\n            } else if (message.contains(\"Bonzo's Staff\")) { // F1\n                bonzoStaffs++;\n                bonzoStaffsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"bonzoStaff\", bonzoStaffs);\n            } else if (message.contains(\"Balloon Snake\")) {\n                balloonSnakes++;\n                balloonSnakesSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"balloonSnake\", balloonSnakes);\n            } else if (message.contains(\"Scarf's Studies\")) { // F2\n                scarfStudies++;\n                scarfStudiesSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"scarfStudies\", scarfStudies);\n            } else if (message.contains(\"Adaptive Blade\")) {\n                adaptiveSwords++;\n                adaptiveSwordsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"adaptiveSword\", adaptiveSwords);\n            } else if (message.contains(\"Adaptive Belt\")) {\n                adaptiveBelts++;\n                adaptiveBeltsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"adaptiveBelt\", adaptiveBelts);\n            } else if (message.contains(\"Adaptive Helmet\")) { // F3\n                adaptiveHelms++;\n                adaptiveHelmsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"adaptiveHelm\", adaptiveHelms);\n            } else if (message.contains(\"Adaptive Chestplate\")) {\n                adaptiveChests++;\n                adaptiveChestsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"adaptiveChest\", adaptiveChests);\n            } else if (message.contains(\"Adaptive Leggings\")) {\n                adaptiveLegs++;\n                adaptiveLegsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"adaptiveLegging\", adaptiveLegs);\n            } else if (message.contains(\"Adaptive Boots\")) {\n                adaptiveBoots++;\n                adaptiveBootsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"adaptiveBoot\", adaptiveBoots);\n            } else if (message.contains(\"Spirit Wing\")) { // F4\n                spiritWings++;\n                spiritWingsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"spiritWing\", spiritWings);\n            } else if (message.contains(\"Spirit Bone\")) {\n                spiritBones++;\n                spiritBonesSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"spiritBone\", spiritBones);\n            } else if (message.contains(\"Spirit Boots\")) {\n                spiritBoots++;\n                spiritBootsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"spiritBoot\", spiritBoots);\n            } else if (message.contains(\"[Lvl 1] Spirit\")) {\n                String formattedMessage = event.message.getFormattedText();\n                // Unicode colour code messes up here, just gonna remove the symbols\n                if (formattedMessage.contains(\"5Spirit\")) {\n                    epicSpiritPets++;\n                    epicSpiritPetsSession++;\n                    CfgConfig.writeIntConfig(\"catacombs\", \"spiritPetEpic\", epicSpiritPets);\n                } else if (formattedMessage.contains(\"6Spirit\")) {\n                    legSpiritPets++;\n                    legSpiritPetsSession++;\n                    CfgConfig.writeIntConfig(\"catacombs\", \"spiritPetLeg\", legSpiritPets);\n                }\n            } else if (message.contains(\"Spirit Sword\")) {\n                spiritSwords++;\n                spiritSwordsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"spiritSword\", spiritSwords);\n            } else if (message.contains(\"Spirit Bow\")) {\n                spiritBows++;\n                spiritBowsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"spiritBow\", spiritBows);\n            } else if (message.contains(\"Warped Stone\")) { // F5\n                warpedStones++;\n                warpedStonesSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"warpedStone\", warpedStones);\n            } else if (message.contains(\"Shadow Assassin Helmet\")) {\n                shadowAssHelms++;\n                shadowAssHelmsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"shadowAssassinHelm\", shadowAssHelms);\n            } else if (message.contains(\"Shadow Assassin Chestplate\")) {\n                shadowAssChests++;\n                shadowAssChestsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"shadowAssassinChest\", shadowAssChests);\n            } else if (message.contains(\"Shadow Assassin Leggings\")) {\n                shadowAssLegs++;\n                shadowAssLegsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"shadowAssassinLegging\", shadowAssLegs);\n            } else if (message.contains(\"Shadow Assassin Boots\")) {\n                shadowAssBoots++;\n                shadowAssBootsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"shadowAssassinBoot\", shadowAssBoots);\n            } else if (message.contains(\"Shadow Assassin Cloak\")) {\n                shadowAssCloaks++;\n                shadowAssCloaksSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"shadowAssassinCloak\", shadowAssCloaks);\n            } else if (message.contains(\"Livid Dagger\")) {\n                lividDaggers++;\n                lividDaggersSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"lividDagger\", lividDaggers);\n            } else if (message.contains(\"Shadow Fury\")) {\n                shadowFurys++;\n                shadowFurysSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"shadowFury\", shadowFurys);\n            } else if (message.contains(\"Ancient Rose\")) { // F6\n                ancientRoses++;\n                ancientRosesSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"ancientRose\", ancientRoses);\n            } else if (message.contains(\"Precursor Eye\")) {\n                precursorEyes++;\n                precursorEyesSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"precursorEye\", precursorEyes);\n            } else if (message.contains(\"Giant's Sword\")) {\n                giantsSwords++;\n                giantsSwordsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"giantsSword\", giantsSwords);\n            } else if (message.contains(\"Necromancer Lord Helmet\")) {\n                necroLordHelms++;\n                necroLordHelmsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"necroLordHelm\", necroLordHelms);\n            } else if (message.contains(\"Necromancer Lord Chestplate\")) {\n                necroLordChests++;\n                necroLordChestsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"necroLordChest\", necroLordChests);\n            } else if (message.contains(\"Necromancer Lord Leggings\")) {\n                necroLordLegs++;\n                necroLordLegsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"necroLordLegging\", necroLordLegs);\n            } else if (message.contains(\"Necromancer Lord Boots\")) {\n                necroLordBoots++;\n                necroLordBootsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"necroLordBoot\", necroLordBoots);\n            } else if (message.contains(\"Necromancer Sword\")) {\n                necroSwords++;\n                necroSwordsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"necroSword\", necroSwords);\n            } else if (message.contains(\"Soulweaver Gloves\")) {\n                soulweaverGloves++;\n                soulweaverGlovesSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"soulweaverGlove\", soulweaverGloves);\n            } else if (message.contains(\"Fel Skull\")) {\n                felSkulls++;\n                felSkullsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"felSkull\", felSkulls);\n            } else if (message.contains(\"Wither Blood\")) { // F7\n                witherBloods++;\n                witherBloodsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"witherBlood\", witherBloods);\n            } else if (message.contains(\"Wither Cloak\")) {\n                witherCloaks++;\n                witherCloaksSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"witherCloak\", witherCloaks);\n            } else if (message.contains(\"Implosion\")) {\n                implosions++;\n                implosionsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"implosion\", implosions);\n            } else if (message.contains(\"Wither Shield\")) {\n                witherShields++;\n                witherShieldsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"witherShield\", witherShields);\n            } else if (message.contains(\"Shadow Warp\")) {\n                shadowWarps++;\n                shadowWarpsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"shadowWarp\", shadowWarps);\n            } else if (message.contains(\"Necron's Handle\")) {\n                necronsHandles++;\n                necronsHandlesSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"necronsHandle\", necronsHandles);\n            } else if (message.contains(\"Auto Recombobulator\")) {\n                autoRecombs++;\n                autoRecombsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"autoRecomb\", autoRecombs);\n            } else if (message.contains(\"Wither Helmet\")) {\n                witherHelms++;\n                witherHelmsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"witherHelm\", witherHelms);\n            } else if (message.contains(\"Wither Chestplate\")) {\n                witherChests++;\n                witherChestsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"witherChest\", witherChests);\n            } else if (message.contains(\"Wither Leggings\")) {\n                witherLegs++;\n                witherLegsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"witherLegging\", witherLegs);\n            } else if (message.contains(\"Wither Boots\")) {\n                witherBoots++;\n                witherBootsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"witherBoot\", witherBoots);\n            } else if (message.contains(\"First Master Star\")) {\n                firstStars++;\n                firstStarsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"firstStar\", firstStars);\n            } else if (message.contains(\"Second Master Star\")) {\n                secondStars++;\n                secondStarsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"secondStar\", secondStars);\n            } else if (message.contains(\"Third Master Star\")) {\n                thirdStars++;\n                thirdStarsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"thirdStar\", thirdStars);\n            } else if (message.contains(\"Fourth Master Star\")) {\n                fourthStars++;\n                fourthStarsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"fourthStar\", fourthStars);\n            } else if (message.contains(\"Fifth Master Star\")) {\n                fifthStars++;\n                fifthStarsSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"fifthStar\", fifthStars);\n            } else if (message.contains(\"Dark Claymore\")) {\n                darkClaymores++;\n                darkClaymoresSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"darkClaymore\", darkClaymores);\n            } else if (message.contains(\"Necron Dye\")) {\n                necronDyes++;\n                necronDyesSession++;\n                CfgConfig.writeIntConfig(\"catacombs\", \"necronDye\", necronDyes);\n            }\n        }\n\n        if (message.contains(\"EXTRA STATS \")) {\n            List<String> scoreboard = ScoreboardHandler.getSidebarLines();\n            for (String s : scoreboard) {\n                String sCleaned = ScoreboardHandler.cleanSB(s);\n                if (sCleaned.contains(\"Time Elapsed:\")) {\n                    // Get floor time\n                    String time = sCleaned.substring(sCleaned.indexOf(\":\") + 2);\n                    time = time.replaceAll(\"\\\\s\", \"\");\n                    int minutes = Integer.parseInt(time.substring(0, time.indexOf(\"m\")));\n                    int seconds = Integer.parseInt(time.substring(time.indexOf(\"m\") + 1, time.indexOf(\"s\")));\n                    int timeToAdd = (minutes * 60) + seconds;\n\n                    // Add time to floor\n                    switch (Utils.currentFloor) {\n                        case F1:\n                            f1TimeSpent = Math.floor(f1TimeSpent + timeToAdd);\n                            f1TimeSpentSession = Math.floor(f1TimeSpentSession + timeToAdd);\n                            CfgConfig.writeDoubleConfig(\"catacombs\", \"floorOneTime\", f1TimeSpent);\n                            break;\n                        case F2:\n                            f2TimeSpent = Math.floor(f2TimeSpent + timeToAdd);\n                            f2TimeSpentSession = Math.floor(f2TimeSpentSession + timeToAdd);\n                            CfgConfig.writeDoubleConfig(\"catacombs\", \"floorTwoTime\", f2TimeSpent);\n                            break;\n                        case F3:\n                            f3TimeSpent = Math.floor(f3TimeSpent + timeToAdd);\n                            f3TimeSpentSession = Math.floor(f3TimeSpentSession + timeToAdd);\n                            CfgConfig.writeDoubleConfig(\"catacombs\", \"floorThreeTime\", f3TimeSpent);\n                            break;\n                        case F4:\n                            f4TimeSpent = Math.floor(f4TimeSpent + timeToAdd);\n                            f4TimeSpentSession = Math.floor(f4TimeSpentSession + timeToAdd);\n                            CfgConfig.writeDoubleConfig(\"catacombs\", \"floorFourTime\", f4TimeSpent);\n                            break;\n                        case F5:\n                            f5TimeSpent = Math.floor(f5TimeSpent + timeToAdd);\n                            f5TimeSpentSession = Math.floor(f5TimeSpentSession + timeToAdd);\n                            CfgConfig.writeDoubleConfig(\"catacombs\", \"floorFiveTime\", f5TimeSpent);\n                            break;\n                        case F6:\n                            f6TimeSpent = Math.floor(f6TimeSpent + timeToAdd);\n                            f6TimeSpentSession = Math.floor(f6TimeSpentSession + timeToAdd);\n                            CfgConfig.writeDoubleConfig(\"catacombs\", \"floorSixTime\", f6TimeSpent);\n                            break;\n                        case F7:\n                            f7TimeSpent = Math.floor(f7TimeSpent + timeToAdd);\n                            f7TimeSpentSession = Math.floor(f7TimeSpentSession + timeToAdd);\n                            CfgConfig.writeDoubleConfig(\"catacombs\", \"floorSevenTime\", f7TimeSpent);\n                            break;\n                        case M1:\n                        case M2:\n                        case M3:\n                        case M4:\n                        case M5:\n                        case M6:\n                        case M7:\n                            masterTimeSpent = Math.floor(masterTimeSpent + timeToAdd);\n                            masterTimeSpentSession = Math.floor(masterTimeSpentSession + timeToAdd);\n                            CfgConfig.writeDoubleConfig(\"catacombs\", \"masterTime\", masterTimeSpent);\n                            break;\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onSlotClick(ChestSlotClickedEvent event) {\n        if (!Utils.isInDungeons()) return;\n\n        ItemStack item = event.item;\n\n        if (event.inventoryName.endsWith(\" Chest\") && item != null) {\n            if (item.getDisplayName().contains(\"Open Reward Chest\")) {\n                List<String> tooltip = item.getTooltip(Minecraft.getMinecraft().thePlayer, false);\n                for (String lineUnclean : tooltip) {\n                    String line = StringUtils.stripControlCodes(lineUnclean);\n                    if (line.contains(\" Coins\") && !line.contains(\"NOTE:\")) {\n                        int coinsSpent = Integer.parseInt(line.replaceAll(\"\\\\D\", \"\"));\n\n                        switch (Utils.currentFloor) {\n                            case F1:\n                                f1CoinsSpent += coinsSpent;\n                                f1CoinsSpentSession += coinsSpent;\n                                CfgConfig.writeDoubleConfig(\"catacombs\", \"floorOneCoins\", f1CoinsSpent);\n                                break;\n                            case F2:\n                                f2CoinsSpent += coinsSpent;\n                                f2CoinsSpentSession += coinsSpent;\n                                CfgConfig.writeDoubleConfig(\"catacombs\", \"floorTwoCoins\", f2CoinsSpent);\n                                break;\n                            case F3:\n                                f3CoinsSpent += coinsSpent;\n                                f3CoinsSpentSession += coinsSpent;\n                                CfgConfig.writeDoubleConfig(\"catacombs\", \"floorThreeCoins\", f3CoinsSpent);\n                                break;\n                            case F4:\n                                f4CoinsSpent += coinsSpent;\n                                f4CoinsSpentSession += coinsSpent;\n                                CfgConfig.writeDoubleConfig(\"catacombs\", \"floorFourCoins\", f4CoinsSpent);\n                                break;\n                            case F5:\n                                f5CoinsSpent += coinsSpent;\n                                f5CoinsSpentSession += coinsSpent;\n                                CfgConfig.writeDoubleConfig(\"catacombs\", \"floorFiveCoins\", f5CoinsSpent);\n                                break;\n                            case F6:\n                                f6CoinsSpent += coinsSpent;\n                                f6CoinsSpentSession += coinsSpent;\n                                CfgConfig.writeDoubleConfig(\"catacombs\", \"floorSixCoins\", f6CoinsSpent);\n                                break;\n                            case F7:\n                                f7CoinsSpent += coinsSpent;\n                                f7CoinsSpentSession += coinsSpent;\n                                CfgConfig.writeDoubleConfig(\"catacombs\", \"floorSevenCoins\", f7CoinsSpent);\n                                break;\n                            case M1:\n                            case M2:\n                            case M3:\n                            case M4:\n                            case M5:\n                            case M6:\n                            case M7:\n                                masterCoinsSpent += coinsSpent;\n                                masterCoinsSpentSession += coinsSpent;\n                                CfgConfig.writeDoubleConfig(\"catacombs\", \"masterCoins\", masterCoinsSpent);\n                                break;\n                        }\n                        break;\n                    }\n                }\n            } else if (item.getDisplayName().contains(\"Reroll Chest\")) {\n                switch (Utils.currentFloor) {\n                    case F6:\n                        f6Rerolls++;\n                        f6RerollsSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"floorSixRerolls\", f6Rerolls);\n                        break;\n                    case F7:\n                        f7Rerolls++;\n                        f7RerollsSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"floorSevenRerolls\", f7Rerolls);\n                        break;\n                    case M1:\n                    case M2:\n                    case M3:\n                    case M4:\n                    case M5:\n                    case M6:\n                    case M7:\n                        masterRerolls++;\n                        masterRerollsSession++;\n                        CfgConfig.writeIntConfig(\"catacombs\", \"masterRerolls\", masterRerolls);\n                        break;\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/loot/EndermanTracker.java",
    "content": "package me.Danker.features.loot;\n\nimport me.Danker.config.CfgConfig;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.SlayerLootDropEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class EndermanTracker {\n\n    public static int voidglooms;\n    public static int nullSpheres;\n    public static int TAP;\n    public static int TAPDrops;\n    public static int endersnakes;\n    public static int summoningEyes;\n    public static int manaBooks;\n    public static int tuners;\n    public static int atoms;\n    public static int hazmats;\n    public static int espressoMachines;\n    public static int smartyBooks;\n    public static int endRunes;\n    public static int chalices;\n    public static int dice;\n    public static int artifacts;\n    public static int skins;\n    public static int mergers;\n    public static int cores;\n    public static int enchantRunes;\n    public static int enderBooks;\n    public static double time;\n    public static int bosses;\n\n    public static int voidgloomsSession = 0;\n    public static int nullSpheresSession = 0;\n    public static int TAPSession = 0;\n    public static int TAPDropsSession = 0;\n    public static int endersnakesSession = 0;\n    public static int summoningEyesSession = 0;\n    public static int manaBooksSession = 0;\n    public static int tunersSession = 0;\n    public static int atomsSession = 0;\n    public static int hazmatsSession = 0;\n    public static int espressoMachinesSession = 0;\n    public static int smartyBooksSession = 0;\n    public static int endRunesSession = 0;\n    public static int chalicesSession = 0;\n    public static int diceSession = 0;\n    public static int artifactsSession = 0;\n    public static int skinsSession = 0;\n    public static int mergersSession = 0;\n    public static int coresSession = 0;\n    public static int enchantRunesSession = 0;\n    public static int enderBooksSession = 0;\n    public static double timeSession = -1;\n    public static int bossesSession = -1;\n\n    @SubscribeEvent\n    public void onLootDrop(SlayerLootDropEvent event) {\n        boolean rng = false;\n\n        switch (event.drop) {\n            case \"Twilight Arrow Poison\":\n                TAP += event.amount;\n                TAPSession += event.amount;\n                TAPDrops++;\n                TAPDropsSession++;\n                CfgConfig.writeIntConfig(\"enderman\", \"tap\", TAP);\n                CfgConfig.writeIntConfig(\"enderman\", \"tapDrops\", TAPDrops);\n                break;\n            case \"◆ Endersnake Rune I\":\n                endersnakes += event.amount;\n                endersnakesSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"endersnakes\", endersnakes);\n                break;\n            case \"Summoning Eye\":\n                summoningEyes += event.amount;\n                summoningEyesSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"summoningEyes\", summoningEyes);\n                break;\n            case \"Mana Steal I\":\n                manaBooks += event.amount;\n                manaBooksSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"manaBooks\", manaBooks);\n                break;\n            case \"Transmission Tuner\":\n                tuners += event.amount;\n                tunersSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"tuners\", tuners);\n                break;\n            case \"Null Atom\":\n                atoms += event.amount;\n                atomsSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"atoms\", atoms);\n                break;\n            case \"Hazmat Enderman\":\n                hazmats += event.amount;\n                hazmatsSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"hazmats\", hazmats);\n                break;\n            case \"Pocket Espresso Machine\":\n                rng = true;\n                espressoMachines += event.amount;\n                espressoMachinesSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"espressoMachines\", espressoMachines);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.AQUA + \"POCKET ESPRESSO MACHINE!\", 3);\n                break;\n            case \"Smarty Pants I\":\n                smartyBooks += event.amount;\n                smartyBooksSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"smartyBooks\", smartyBooks);\n                break;\n            case \"◆ End Rune I\":\n                endRunes += event.amount;\n                endRunesSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"endRunes\", endRunes);\n                break;\n            case \"Handy Blood Chalice\":\n                rng = true;\n                chalices += event.amount;\n                chalicesSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"chalices\", chalices);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.RED + \"HANDY BLOOD CHALICE!\", 3);\n                break;\n            case \"Sinful Dice\":\n                dice += event.amount;\n                diceSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"dice\", dice);\n                break;\n            case \"Exceedingly Rare Ender Artifact Upgrader\":\n                rng = true;\n                artifacts += event.amount;\n                artifactsSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"artifacts\", artifacts);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.DARK_PURPLE + \"ENDER ARTIFACT UPGRADER!\", 3);\n                break;\n            case \"Void Conqueror Enderman Skin\":\n                rng = true;\n                skins += event.amount;\n                skinsSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"skins\", skins);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.DARK_PURPLE + \"ENDERMAN SKIN!\", 3);\n                break;\n            case \"Etherwarp Merger\":\n                mergers += event.amount;\n                mergersSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"mergers\", mergers);\n                break;\n            case \"Judgement Core\":\n                rng = true;\n                cores += event.amount;\n                coresSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"cores\", cores);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.GOLD + \"JUDGEMENT CORE!\", 5);\n                break;\n            case \"◆ Enchant Rune I\":\n                rng = true;\n                enchantRunes += event.amount;\n                enchantRunesSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"enchantRunes\", enchantRunes);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.GRAY + \"ENCHANT RUNE!\", 3);\n                break;\n            case \"Ender Slayer VII\":\n                rng = true;\n                enderBooks += event.amount;\n                enderBooksSession += event.amount;\n                CfgConfig.writeIntConfig(\"enderman\", \"enderBooks\", enderBooks);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.RED + \"ENDER SLAYER VII!\", 3);\n                break;\n        }\n\n        if (rng) {\n            time = System.currentTimeMillis() / 1000;\n            bosses = 0;\n            timeSession = System.currentTimeMillis() / 1000;\n            bossesSession = 0;\n            CfgConfig.writeDoubleConfig(\"enderman\", \"timeRNG\", time);\n            CfgConfig.writeIntConfig(\"enderman\", \"bossRNG\", 0);\n        }\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.type == 2) return;\n\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (message.contains(\":\")) return;\n\n        if (message.contains(\"   Enderman Slayer LVL \")) {\n            voidglooms++;\n            voidgloomsSession++;\n            if (bosses != -1) {\n                bosses++;\n            }\n            if (bossesSession != -1) {\n                bossesSession++;\n            }\n            CfgConfig.writeIntConfig(\"enderman\", \"voidglooms\", voidglooms);\n            CfgConfig.writeIntConfig(\"enderman\", \"bossRNG\", bosses);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/loot/FishingTracker.java",
    "content": "package me.Danker.features.loot;\n\nimport me.Danker.config.CfgConfig;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class FishingTracker {\n\n    // Fishing\n    public static int seaCreatures;\n    public static int goodCatches;\n    public static int greatCatches;\n    public static int squids;\n    public static int seaWalkers;\n    public static int nightSquids;\n    public static int seaGuardians;\n    public static int seaWitches;\n    public static int seaArchers;\n    public static int monsterOfTheDeeps;\n    public static int agarimoos;\n    public static int catfishes;\n    public static int carrotKings;\n    public static int seaLeeches;\n    public static int guardianDefenders;\n    public static int deepSeaProtectors;\n    public static int hydras;\n    public static int seaEmperors;\n    public static double empTime;\n    public static int empSCs;\n    public static int fishingMilestone;\n    // Fishing Winter\n    public static int frozenSteves;\n    public static int frostyTheSnowmans;\n    public static int grinches;\n    public static int nutcrackers;\n    public static int yetis;\n    public static int reindrakes;\n    public static double reindrakeTime;\n    public static int reindrakeSCs;\n    // Fishing Festival\n    public static int nurseSharks;\n    public static int blueSharks;\n    public static int tigerSharks;\n    public static int greatWhiteSharks;\n    // Spooky Fishing\n    public static int scarecrows;\n    public static int nightmares;\n    public static int werewolfs;\n    public static int phantomFishers;\n    public static int grimReapers;\n    // CH Fishing\n    public static int waterWorms;\n    public static int poisonedWaterWorms;\n    public static int flamingWorms;\n    public static int lavaBlazes;\n    public static int lavaPigmen;\n    public static int zombieMiners;\n    // Lava fishing\n    public static int plhlegblasts;\n    public static int magmaSlugs;\n    public static int moogmas;\n    public static int lavaLeeches;\n    public static int pyroclasticWorms;\n    public static int lavaFlames;\n    public static int fireEels;\n    public static int tauruses;\n    public static int thunders;\n    public static int lordJawbuses;\n    public static double jawbusTime;\n    public static int jawbusSCs;\n\n    // Fishing\n    public static int seaCreaturesSession = 0;\n    public static int goodCatchesSession = 0;\n    public static int greatCatchesSession = 0;\n    public static int squidsSession = 0;\n    public static int seaWalkersSession = 0;\n    public static int nightSquidsSession = 0;\n    public static int seaGuardiansSession = 0;\n    public static int seaWitchesSession = 0;\n    public static int seaArchersSession = 0;\n    public static int monsterOfTheDeepsSession = 0;\n    public static int agarimoosSession = 0;\n    public static int catfishesSession = 0;\n    public static int carrotKingsSession = 0;\n    public static int seaLeechesSession = 0;\n    public static int guardianDefendersSession = 0;\n    public static int deepSeaProtectorsSession = 0;\n    public static int hydrasSession = 0;\n    public static int seaEmperorsSession = 0;\n    public static double empTimeSession = -1;\n    public static int empSCsSession = -1;\n    public static int fishingMilestoneSession = 0;\n    // Fishing Winter\n    public static int frozenStevesSession = 0;\n    public static int frostyTheSnowmansSession = 0;\n    public static int grinchesSession = 0;\n    public static int nutcrackersSession = 0;\n    public static int yetisSession = 0;\n    public static int reindrakesSession = 0;\n    public static double reindrakeTimeSession = -1;\n    public static int reindrakeSCsSession = -1;\n    // Fishing Festival\n    public static int nurseSharksSession = 0;\n    public static int blueSharksSession = 0;\n    public static int tigerSharksSession = 0;\n    public static int greatWhiteSharksSession = 0;\n    // Spooky Fishing\n    public static int scarecrowsSession = 0;\n    public static int nightmaresSession = 0;\n    public static int werewolfsSession = 0;\n    public static int phantomFishersSession = 0;\n    public static int grimReapersSession = 0;\n    // CH Fishing\n    public static int waterWormsSession = 0;\n    public static int poisonedWaterWormsSession = 0;\n    public static int flamingWormsSession = 0;\n    public static int lavaBlazesSession = 0;\n    public static int lavaPigmenSession = 0;\n    public static int zombieMinersSession = 0;\n    // Lava fishing\n    public static int plhlegblastsSession = 0;\n    public static int magmaSlugsSession = 0;\n    public static int moogmasSession = 0;\n    public static int lavaLeechesSession = 0;\n    public static int pyroclasticWormsSession = 0;\n    public static int lavaFlamesSession = 0;\n    public static int fireEelsSession = 0;\n    public static int taurusesSession = 0;\n    public static int thundersSession = 0;\n    public static int lordJawbusesSession = 0;\n    public static double jawbusTimeSession = -1;\n    public static int jawbusSCsSession = -1;\n\n    boolean doubleHook = false;\n    boolean hasIncreased = false;\n\n    @SubscribeEvent(receiveCanceled = true)\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!Utils.inSkyblock) return;\n\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (event.type == 2) return;\n        if (message.contains(\":\")) return;\n\n        if (message.startsWith(\"It's a Double Hook!\")) {\n            doubleHook = true;\n        } else if (message.startsWith(\"GOOD CATCH!\")) {\n            goodCatches++;\n            goodCatchesSession++;\n            CfgConfig.writeIntConfig(\"fishing\", \"goodCatch\", goodCatches);\n        } else if (message.startsWith(\"GREAT CATCH!\")) {\n            greatCatches++;\n            greatCatchesSession++;\n            CfgConfig.writeIntConfig(\"fishing\", \"greatCatch\", greatCatches);\n        } else if (message.equals(\"A Squid appeared.\")) {\n            squids += getAmount();\n            squidsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"squid\", squids);\n            increaseSeaCreatures();\n        } else if (message.equals(\"You caught a Sea Walker.\")) {\n            seaWalkers += getAmount();\n            seaWalkersSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"seaWalker\", seaWalkers);\n            increaseSeaCreatures();\n        } else if (message.equals(\"Pitch darkness reveals a Night Squid.\")) {\n            nightSquids += getAmount();\n            nightSquidsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"nightSquid\", nightSquids);\n            increaseSeaCreatures();\n        } else if (message.equals(\"You stumbled upon a Sea Guardian.\")) {\n            seaGuardians += getAmount();\n            seaGuardiansSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"seaGuardian\", seaGuardians);\n            increaseSeaCreatures();\n        } else if (message.equals(\"It looks like you've disrupted the Sea Witch's brewing session. Watch out, she's furious!\")) {\n            seaWitches += getAmount();\n            seaWitchesSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"seaWitch\", seaWitches);\n            increaseSeaCreatures();\n        } else if (message.equals(\"You reeled in a Sea Archer.\")) {\n            seaArchers += getAmount();\n            seaArchersSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"seaArcher\", seaArchers);\n            increaseSeaCreatures();\n        } else if (message.equals(\"The Rider of the Deep has emerged.\")) {\n            monsterOfTheDeeps += getAmount();\n            monsterOfTheDeepsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"monsterOfDeep\", monsterOfTheDeeps);\n            increaseSeaCreatures();\n        } else if (message.equals(\"Your Chumcap Bucket trembles, it's an Agarimoo.\")) {\n            agarimoos += getAmount();\n            agarimoosSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"agarimoo\", agarimoos);\n            increaseSeaCreatures();\n        } else if (message.equals(\"Huh? A Catfish!\")) {\n            catfishes += getAmount();\n            catfishesSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"catfish\", catfishes);\n            increaseSeaCreatures();\n        } else if (message.equals(\"Is this even a fish? It's the Carrot King!\")) {\n            carrotKings += getAmount();\n            carrotKingsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"carrotKing\", carrotKings);\n            increaseSeaCreatures();\n        } else if (message.equals(\"Gross! A Sea Leech!\")) {\n            seaLeeches += getAmount();\n            seaLeechesSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"seaLeech\", seaLeeches);\n            increaseSeaCreatures();\n        } else if (message.equals(\"You've discovered a Guardian Defender of the sea.\")) {\n            guardianDefenders += getAmount();\n            guardianDefendersSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"guardianDefender\", guardianDefenders);\n            increaseSeaCreatures();\n        } else if (message.equals(\"You have awoken the Deep Sea Protector, prepare for a battle!\")) {\n            deepSeaProtectors += getAmount();\n            deepSeaProtectorsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"deepSeaProtector\", deepSeaProtectors);\n            increaseSeaCreatures();\n        } else if (message.equals(\"The Water Hydra has come to test your strength.\")) {\n            hydras += getAmount();\n            hydrasSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"hydra\", hydras);\n            increaseSeaCreatures();\n        } else if (message.equals(\"The Sea Emperor arises from the depths.\")) {\n            increaseSeaCreatures();\n\n            seaEmperors += getAmount();\n            empTime = System.currentTimeMillis() / 1000;\n            empSCs = 0;\n            seaEmperorsSession += getAmount();\n            empTimeSession = System.currentTimeMillis() / 1000;\n            empSCsSession = 0;\n            CfgConfig.writeIntConfig(\"fishing\", \"seaEmperor\", seaEmperors);\n            CfgConfig.writeDoubleConfig(\"fishing\", \"empTime\", empTime);\n            CfgConfig.writeIntConfig(\"fishing\", \"empSC\", empSCs);\n        } else if (message.equals(\"Frozen Steve fell into the pond long ago, never to resurface...until now!\")) { // Fishing Winter\n            frozenSteves += getAmount();\n            frozenStevesSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"frozenSteve\", frozenSteves);\n            increaseSeaCreatures();\n        } else if (message.equals(\"It's a snowman! He looks harmless.\")) {\n            frostyTheSnowmans += getAmount();\n            frostyTheSnowmansSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"snowman\", frostyTheSnowmans);\n            increaseSeaCreatures();\n        } else if (message.equals(\"The Grinch stole Jerry's Gifts...get them back!\")) {\n            grinches += getAmount();\n            grinchesSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"grinch\", grinches);\n            increaseSeaCreatures();\n        } else if (message.equals(\"You found a forgotten Nutcracker laying beneath the ice.\")) {\n            nutcrackers += getAmount();\n            nutcrackersSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"nutcracker\", nutcrackers);\n            increaseSeaCreatures();\n        } else if (message.equals(\"What is this creature!?\")) {\n            yetis += getAmount();\n            yetisSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"yeti\", yetis);\n            increaseSeaCreatures();\n        } else if (message.equals(\"A Reindrake forms from the depths.\")) {\n            reindrakes += getAmount();\n            reindrakeTime = System.currentTimeMillis() / 1000;\n            reindrakeSCs = 0;\n            reindrakesSession += getAmount();\n            reindrakeTimeSession = System.currentTimeMillis() / 1000;\n            reindrakeSCsSession = 0;\n            CfgConfig.writeIntConfig(\"fishing\", \"reindrake\", reindrakes);\n            CfgConfig.writeDoubleConfig(\"fishing\", \"reindrakeTime\", reindrakeTime);\n            CfgConfig.writeIntConfig(\"fishing\", \"reindrakeSC\", reindrakeSCs);\n            increaseSeaCreatures();\n        } else if (message.equals(\"A tiny fin emerges from the water, you've caught a Nurse Shark.\")) { // Fishing Festival\n            nurseSharks += getAmount();\n            nurseSharksSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"nurseShark\", nurseSharks);\n            increaseSeaCreatures();\n        } else if (message.equals(\"You spot a fin as blue as the water it came from, it's a Blue Shark.\")) {\n            blueSharks += getAmount();\n            blueSharksSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"blueShark\", blueSharks);\n            increaseSeaCreatures();\n        } else if (message.equals(\"A striped beast bounds from the depths, the wild Tiger Shark!\")) {\n            tigerSharks += getAmount();\n            tigerSharksSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"tigerShark\", tigerSharks);\n            increaseSeaCreatures();\n        } else if (message.equals(\"Hide no longer, a Great White Shark has tracked your scent and thirsts for your blood!\")) {\n            greatWhiteSharks += getAmount();\n            greatWhiteSharksSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"greatWhiteShark\", greatWhiteSharks);\n            increaseSeaCreatures();\n        } else if (message.equals(\"Phew! It's only a Scarecrow.\")) {\n            scarecrows += getAmount();\n            scarecrowsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"scarecrow\", scarecrows);\n            increaseSeaCreatures();\n        } else if (message.equals(\"You hear trotting from beneath the waves, you caught a Nightmare.\")) {\n            nightmares += getAmount();\n            nightmaresSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"nightmare\", nightmares);\n            increaseSeaCreatures();\n        } else if (message.equals(\"It must be a full moon, a Werewolf appears.\")) {\n            werewolfs += getAmount();\n            werewolfsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"werewolf\", werewolfs);\n            increaseSeaCreatures();\n        } else if (message.equals(\"The spirit of a long lost Phantom Fisher has come to haunt you.\")) {\n            phantomFishers += getAmount();\n            phantomFishersSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"phantomFisher\", phantomFishers);\n            increaseSeaCreatures();\n        } else if (message.equals(\"This can't be! The manifestation of death himself!\")) {\n            grimReapers += getAmount();\n            grimReapersSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"grimReaper\", grimReapers);\n            increaseSeaCreatures();\n        } else if (message.equals(\"A Water Worm surfaces!\")) {\n            waterWorms += getAmount();\n            waterWormsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"waterWorm\", waterWorms);\n            increaseSeaCreatures();\n        } else if (message.equals(\"A Poisoned Water Worm surfaces!\")) {\n            poisonedWaterWorms += getAmount();\n            poisonedWaterWormsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"poisonedWaterWorm\", poisonedWaterWorms);\n            increaseSeaCreatures();\n        } else if (message.equals(\"A Flaming Worm surfaces from the depths!\")) {\n            flamingWorms += getAmount();\n            flamingWormsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"flamingWorm\", flamingWorms);\n            increaseSeaCreatures();\n        } else if (message.equals(\"A Lava Blaze has surfaced from the depths!\")) {\n            lavaBlazes += getAmount();\n            lavaBlazesSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"lavaBlaze\", lavaBlazes);\n            increaseSeaCreatures();\n        } else if (message.equals(\"A Lava Pigman arose from the depths!\")) {\n            lavaPigmen += getAmount();\n            lavaPigmenSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"lavaPigman\", lavaPigmen);\n            increaseSeaCreatures();\n        } else if (message.equals(\"An Abyssal Miner breaks out of the water!\")) {\n            zombieMiners += getAmount();\n            zombieMinersSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"zombieMiner\", zombieMiners);\n            increaseSeaCreatures();\n        } else if (message.equals(\"WOAH! A Plhlegblast appeared.\")) {\n            plhlegblasts += getAmount();\n            plhlegblastsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"plhlegblast\", plhlegblasts);\n            increaseSeaCreatures();\n        } else if (message.equals(\"From beneath the lava appears a Magma Slug.\")) {\n            magmaSlugs += getAmount();\n            magmaSlugsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"magmaSlug\", magmaSlugs);\n            increaseSeaCreatures();\n        } else if (message.equals(\"You hear a faint Moo from the lava... A Moogma appears.\")) {\n            moogmas += getAmount();\n            moogmasSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"moogma\", moogmas);\n            increaseSeaCreatures();\n        } else if (message.equals(\"A small but fearsome Lava Leech emerges.\")) {\n            lavaLeeches += getAmount();\n            lavaLeechesSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"lavaLeech\", lavaLeeches);\n            increaseSeaCreatures();\n        } else if (message.equals(\"You feel the heat radiating as a Pyroclastic Worm surfaces.\")) {\n            pyroclasticWorms += getAmount();\n            pyroclasticWormsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"pyroclasticWorm\", pyroclasticWorms);\n            increaseSeaCreatures();\n        } else if (message.equals(\"A Lava Flame flies out from beneath the lava.\")) {\n            lavaFlames += getAmount();\n            lavaFlamesSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"lavaFlame\", lavaFlames);\n            increaseSeaCreatures();\n        } else if (message.equals(\"A Fire Eel slithers out from the depths.\")) {\n            fireEels += getAmount();\n            fireEelsSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"fireEel\", fireEels);\n            increaseSeaCreatures();\n        } else if (message.equals(\"Taurus and his steed emerge.\")) {\n            tauruses += getAmount();\n            taurusesSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"taurus\", tauruses);\n            increaseSeaCreatures();\n        } else if (message.equals(\"You hear a massive rumble as Thunder emerges.\")) {\n            thunders += getAmount();\n            thundersSession += getAmount();\n            CfgConfig.writeIntConfig(\"fishing\", \"thunder\", thunders);\n            increaseSeaCreatures();\n        } else if (message.equals(\"You have angered a legendary creature... Lord Jawbus has arrived.\")) {\n            lordJawbuses += getAmount();\n            jawbusTime = System.currentTimeMillis() / 1000;\n            jawbusSCs = 0;\n            lordJawbusesSession += getAmount();\n            jawbusTimeSession = System.currentTimeMillis() / 1000;\n            jawbusSCsSession = 0;\n            CfgConfig.writeIntConfig(\"fishing\", \"lordJawbus\", lordJawbuses);\n            CfgConfig.writeDoubleConfig(\"fishing\", \"jawbusTime\", jawbusTime);\n            CfgConfig.writeIntConfig(\"fishing\", \"jawbusSC\", jawbusSCs);\n            increaseSeaCreatures();\n        }\n\n        if (hasIncreased) {\n            doubleHook = false;\n            hasIncreased = false;\n        }\n    }\n\n    public void increaseSeaCreatures() {\n        // Only increment Yetis when in Jerry's Workshop\n        if (Utils.currentLocation == Location.JERRY_WORKSHOP) {\n            if (reindrakeSCs != -1) {\n                reindrakeSCs += getAmount();\n            }\n            if (reindrakeSCsSession != -1) {\n                reindrakeSCsSession += getAmount();\n            }\n        } else if (Utils.currentLocation == Location.CRIMSON_ISLE) {\n            if (jawbusSCs != -1) {\n                jawbusSCs += getAmount();\n            }\n            if (jawbusSCsSession != -1) {\n                jawbusSCsSession += getAmount();\n            }\n        } else {\n            if (empSCs != -1) {\n                empSCs += getAmount();\n            }\n            if (empSCsSession != -1) {\n                empSCsSession += getAmount();\n            }\n        }\n\n        seaCreatures += getAmount();\n        fishingMilestone += getAmount();\n        seaCreaturesSession += getAmount();\n        fishingMilestoneSession += getAmount();\n        CfgConfig.writeIntConfig(\"fishing\", \"seaCreature\", seaCreatures);\n        CfgConfig.writeIntConfig(\"fishing\", \"milestone\", fishingMilestone);\n        CfgConfig.writeIntConfig(\"fishing\", \"empSC\", empSCs);\n        CfgConfig.writeIntConfig(\"fishing\", \"reindrakeSC\", reindrakeSCs);\n        CfgConfig.writeIntConfig(\"fishing\", \"jawbusSC\", jawbusSCs);\n    }\n\n    public int getAmount() {\n        hasIncreased = true;\n        return doubleHook ? 2 : 1;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/loot/GhostTracker.java",
    "content": "package me.Danker.features.loot;\n\nimport me.Danker.config.CfgConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class GhostTracker {\n\n    public static int sorrows  = 0;\n    public static int bagOfCashs  = 0;\n    public static int voltas  = 0;\n    public static int plasmas  = 0;\n    public static int ghostlyBoots = 0;\n\n    public static int sorrowSession = 0;\n    public static int bagOfCashSession = 0;\n    public static int voltaSession = 0;\n    public static int plasmaSession = 0;\n    public static int ghostlyBootsSession = 0;\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!Utils.inSkyblock) return;\n        if (event.type == 2) return;\n        if (message.contains(\":\")) return;\n\n        if (message.contains(\"RARE DROP!\")) {\n            if (message.contains(\"Sorrow\")) {\n                sorrows++;\n                sorrowSession++;\n                CfgConfig.writeIntConfig(\"ghosts\", \"sorrow\", sorrows);\n            }\n            if (message.contains(\"Volta\")) {\n                voltas++;\n                voltaSession++;\n                CfgConfig.writeIntConfig(\"ghosts\", \"volta\", voltas);\n            }\n            if (message.contains(\"Plasma\")) {\n                plasmas++;\n                plasmaSession++;\n                CfgConfig.writeIntConfig(\"ghosts\", \"plasma\", plasmas);\n            }\n            if (message.contains(\"Ghostly Boots\")) {\n                ghostlyBoots++;\n                ghostlyBootsSession++;\n                CfgConfig.writeIntConfig(\"ghosts\", \"ghostlyBoots\", ghostlyBoots);\n            }\n            if (message.contains(\"The ghost's death materialized \")) {\n                bagOfCashs++;\n                bagOfCashSession++;\n                CfgConfig.writeIntConfig(\"ghosts\", \"bagOfCash\", bagOfCashs);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/loot/LootDisplay.java",
    "content": "package me.Danker.features.loot;\n\nimport cc.polyfrost.oneconfig.config.annotations.Dropdown;\nimport cc.polyfrost.oneconfig.config.annotations.DualOption;\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.config.annotations.Switch;\nimport cc.polyfrost.oneconfig.config.migration.CfgName;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.config.ModConfig;\nimport me.Danker.features.AutoDisplay;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.util.EnumChatFormatting;\n\nimport java.text.NumberFormat;\nimport java.util.Locale;\n\npublic class LootDisplay extends Hud {\n\n    @Exclude\n    String exampleText = EnumChatFormatting.GOLD + \"Svens Killed:\\n\" +\n                         EnumChatFormatting.GREEN + \"Wolf Teeth:\\n\" +\n                         EnumChatFormatting.BLUE + \"Hamster Wheels:\\n\" +\n                         EnumChatFormatting.AQUA + \"Spirit Runes:\\n\" +\n                         EnumChatFormatting.WHITE + \"Critical VI Books:\\n\" +\n                         EnumChatFormatting.DARK_RED + \"Red Claw Eggs:\\n\" +\n                         EnumChatFormatting.GOLD + \"Couture Runes:\\n\" +\n                         EnumChatFormatting.AQUA + \"Grizzly Baits:\\n\" +\n                         EnumChatFormatting.DARK_PURPLE + \"Overfluxes:\\n\" +\n                         EnumChatFormatting.AQUA + \"Time Since RNG:\\n\" +\n                         EnumChatFormatting.AQUA + \"Bosses Since RNG:\";\n    @Exclude\n    String exampleNums = EnumChatFormatting.GOLD + \"1,024\" + \"\\n\" +\n                         EnumChatFormatting.GREEN + \"59,719\" + \"\\n\" +\n                         EnumChatFormatting.BLUE + \"36\" + \"\\n\" +\n                         EnumChatFormatting.AQUA + \"64\" + \"\\n\" +\n                         EnumChatFormatting.WHITE + \"17\" + \"\\n\" +\n                         EnumChatFormatting.DARK_RED + \"3\" + \"\\n\" +\n                         EnumChatFormatting.GOLD + \"4\" + \"\\n\" +\n                         EnumChatFormatting.AQUA + \"0\" + \"\\n\" +\n                         EnumChatFormatting.DARK_PURPLE + \"5\" + \"\\n\" +\n                         EnumChatFormatting.AQUA + Utils.getTimeBetween(0, 2678400) + \"\\n\" +\n                         EnumChatFormatting.AQUA + \"5,000\";\n\n    @Dropdown(\n            name = \"Loot Display\",\n            options = {\n                    \"Off\",\n                    \"Zombie Slayer\",\n                    \"Spider Slayer\",\n                    \"Wolf Slayer\",\n                    \"Enderman Slayer\",\n                    \"Blaze Slayer\",\n                    \"Vampire Slayer\",\n                    \"Fishing\",\n                    \"Winter Fishing\",\n                    \"Fishing Festival\",\n                    \"Spooky Fishing\",\n                    \"Crystal Hollows Fishing\",\n                    \"Lava Fishing\",\n                    \"Trophy Fishing\",\n                    \"Floor 1\",\n                    \"Floor 2\",\n                    \"Floor 3\",\n                    \"Floor 4\",\n                    \"Floor 5\",\n                    \"Floor 6\",\n                    \"Floor 7\",\n                    \"Master Mode\",\n                    \"Mythological\",\n                    \"Ghost\"\n            } // update ModConfig.displays as well\n    )\n    public static int display = 0;\n\n    @CfgName(\n            name = \"autoDisplay\",\n            category = \"misc\"\n    )\n    @Switch(\n            name = \"Auto Display\",\n            description = \"Automatically switches display depending on what you're doing.\"\n    )\n    public static boolean autoDisplay = false;\n\n    @Switch(\n            name = \"Current Session Only\",\n            description = \"Only shows loot earned in the current Minecraft session.\"\n    )\n    public static boolean sessionDisplay = false;\n\n    @CfgName(\n            name = \"SlayerCount\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Count Total 20% Drops\",\n            description = \"Counts times dropped instead of amount dropped.\\nE.x. Hamster Wheels: 40 -> Hamster Wheels: 10 times.\"\n    )\n    public static boolean slayerCountTotal = false;\n\n    @CfgName(\n            name = \"MasterSPlusDisplay\",\n            category = \"toggles\"\n    )\n    @DualOption(\n            name = \"Master Mode Runs Shown\",\n            left = \"S Runs\",\n            right = \"S+ Runs\"\n    )\n    public static boolean masterSRunsDisplay = false;\n\n    @CfgName(\n            name = \"SplitFishing\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Split Fishing Display\",\n            description = \"Splits fishing display in half to save vertical space.\"\n    )\n    public static boolean splitFishing = true;\n\n    @CfgName(\n            name = \"ShowTrophyCompletion\",\n            category = \"toggles\"\n    )\n    @Switch(\n            name = \"Show Trophy Fish Completion\",\n            description = \"Show completion instead of count in trophy fish tracker display.\"\n    )\n    public static boolean showTrophyCompletion = false;\n\n    @Override\n    protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n        Minecraft mc = Minecraft.getMinecraft();\n\n        if (example) {\n            TextRenderer.drawHUDText(exampleText, x, y, scale);\n            TextRenderer.drawHUDText(exampleNums, (int) (x + (110 * scale)), y, scale);\n            return;\n        }\n\n        if (enabled) {\n            String display = autoDisplay ? AutoDisplay.display : ModConfig.getDisplay();\n\n            if (!display.equals(\"Off\")) {\n                String dropsText = \"\";\n                String countText = \"\";\n                String dropsTextTwo;\n                String countTextTwo;\n                String timeBetween;\n                String bossesBetween;\n                String drop20;\n                String runs;\n                String runsCount;\n                double timeNow = System.currentTimeMillis() / 1000;\n                NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);\n\n                switch (display) {\n                    case \"Wolf Slayer\":\n                        if (!sessionDisplay) {\n                            if (WolfTracker.time == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(WolfTracker.time, timeNow);\n                            }\n                            if (WolfTracker.bosses == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(WolfTracker.bosses);\n                            }\n                            if (slayerCountTotal) {\n                                drop20 = nf.format(WolfTracker.wheels);\n                            } else {\n                                drop20 = nf.format(WolfTracker.wheelsDrops) + \" times\";\n                            }\n\n                            dropsText = EnumChatFormatting.GOLD + \"Svens Killed:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Wolf Teeth:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Hamster Wheels:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Spirit Runes:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Critical VI Books:\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + \"Furballs:\\n\" +\n                                    EnumChatFormatting.DARK_RED + \"Red Claw Eggs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Couture Runes:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Grizzly Baits:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Overfluxes:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since RNG:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Bosses Since RNG:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(WolfTracker.svens) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(WolfTracker.teeth) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + drop20 + \"\\n\" +\n                                    EnumChatFormatting.AQUA + WolfTracker.spirits + \"\\n\" +\n                                    EnumChatFormatting.WHITE + WolfTracker.books + \"\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + WolfTracker.furballs + \"\\n\" +\n                                    EnumChatFormatting.DARK_RED + WolfTracker.eggs + \"\\n\" +\n                                    EnumChatFormatting.GOLD + WolfTracker.coutures + \"\\n\" +\n                                    EnumChatFormatting.AQUA + WolfTracker.baits + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + WolfTracker.fluxes + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        } else {\n                            if (WolfTracker.timeSession == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(WolfTracker.timeSession, timeNow);\n                            }\n                            if (WolfTracker.bossesSession == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(WolfTracker.bossesSession);\n                            }\n                            if (slayerCountTotal) {\n                                drop20 = nf.format(WolfTracker.wheelsSession);\n                            } else {\n                                drop20 = nf.format(WolfTracker.wheelsDropsSession) + \" times\";\n                            }\n\n                            dropsText = EnumChatFormatting.GOLD + \"Svens Killed:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Wolf Teeth:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Hamster Wheels:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Spirit Runes:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Critical VI Books:\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + \"Furballs:\\n\" +\n                                    EnumChatFormatting.DARK_RED + \"Red Claw Eggs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Couture Runes:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Grizzly Baits:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Overfluxes:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since RNG:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Bosses Since RNG:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(WolfTracker.svensSession) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(WolfTracker.teethSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + drop20 + \"\\n\" +\n                                    EnumChatFormatting.AQUA + WolfTracker.spiritsSession + \"\\n\" +\n                                    EnumChatFormatting.WHITE + WolfTracker.booksSession + \"\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + WolfTracker.furballsSession + \"\\n\" +\n                                    EnumChatFormatting.DARK_RED + WolfTracker.eggsSession + \"\\n\" +\n                                    EnumChatFormatting.GOLD + WolfTracker.couturesSession + \"\\n\" +\n                                    EnumChatFormatting.AQUA + WolfTracker.baitsSession + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + WolfTracker.fluxesSession + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        }\n                        break;\n                    case \"Spider Slayer\":\n                        if (!sessionDisplay) {\n                            if (SpiderTracker.time == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(SpiderTracker.time, timeNow);\n                            }\n                            if (SpiderTracker.bosses == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(SpiderTracker.bosses);\n                            }\n                            if (slayerCountTotal) {\n                                drop20 = nf.format(SpiderTracker.TAP);\n                            } else {\n                                drop20 = nf.format(SpiderTracker.TAPDrops) + \" times\";\n                            }\n\n                            dropsText = EnumChatFormatting.GOLD + \"Tarantulas Killed:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Tarantula Webs:\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + \"Arrow Poison:\\n\" +\n                                    EnumChatFormatting.DARK_GRAY + \"Bite Runes:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Bane VI Books:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Spider Catalysts:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Tarantula Talismans:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Fly Swatters:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Digested Mosquitos:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since RNG:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Bosses Since RNG:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(SpiderTracker.tarantulas) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(SpiderTracker.webs) + \"\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + drop20 + \"\\n\" +\n                                    EnumChatFormatting.DARK_GRAY + SpiderTracker.bites + \"\\n\" +\n                                    EnumChatFormatting.WHITE + SpiderTracker.books + \"\\n\" +\n                                    EnumChatFormatting.AQUA + SpiderTracker.catalysts + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + SpiderTracker.talismans + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + SpiderTracker.swatters + \"\\n\" +\n                                    EnumChatFormatting.GOLD + SpiderTracker.mosquitos + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        } else {\n                            if (SpiderTracker.timeSession == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(SpiderTracker.timeSession, timeNow);\n                            }\n                            if (SpiderTracker.bossesSession == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(SpiderTracker.bossesSession);\n                            }\n                            if (slayerCountTotal) {\n                                drop20 = nf.format(SpiderTracker.TAPSession);\n                            } else {\n                                drop20 = nf.format(SpiderTracker.TAPDropsSession) + \" times\";\n                            }\n\n                            dropsText = EnumChatFormatting.GOLD + \"Tarantulas Killed:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Tarantula Webs:\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + \"Arrow Poison:\\n\" +\n                                    EnumChatFormatting.DARK_GRAY + \"Bite Runes:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Bane VI Books:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Spider Catalysts:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Tarantula Talismans:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Fly Swatters:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Digested Mosquitos:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since RNG:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Bosses Since RNG:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(SpiderTracker.tarantulasSession) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(SpiderTracker.websSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + drop20 + \"\\n\" +\n                                    EnumChatFormatting.DARK_GRAY + SpiderTracker.bitesSession + \"\\n\" +\n                                    EnumChatFormatting.WHITE + SpiderTracker.booksSession + \"\\n\" +\n                                    EnumChatFormatting.AQUA + SpiderTracker.catalystsSession + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + SpiderTracker.talismansSession + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + SpiderTracker.swattersSession + \"\\n\" +\n                                    EnumChatFormatting.GOLD + SpiderTracker.mosquitosSession + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        }\n                        break;\n                    case \"Zombie Slayer\":\n                        if (!sessionDisplay) {\n                            if (ZombieTracker.time == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(ZombieTracker.time, timeNow);\n                            }\n                            if (ZombieTracker.bosses == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(ZombieTracker.bosses);\n                            }\n                            if (slayerCountTotal) {\n                                drop20 = nf.format(ZombieTracker.foulFlesh);\n                            } else {\n                                drop20 = nf.format(ZombieTracker.foulFleshDrops) + \" times\";\n                            }\n\n                            dropsText = EnumChatFormatting.GOLD + \"Revs Killed:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Revenant Flesh:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Revenant Viscera:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Foul Flesh:\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + \"Pestilence Runes:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Smite VI Books:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Smite VII Books:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Undead Catalysts:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Beheaded Horrors:\\n\" +\n                                    EnumChatFormatting.RED + \"Revenant Catalysts:\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + \"Snake Runes:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Scythe Blades:\\n\" +\n                                    EnumChatFormatting.RED + \"Shard of Shreddeds:\\n\" +\n                                    EnumChatFormatting.RED + \"Warden Hearts:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since RNG:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Bosses Since RNG:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(ZombieTracker.revs) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(ZombieTracker.revFlesh) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(ZombieTracker.revViscera) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + drop20 + \"\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + ZombieTracker.pestilences + \"\\n\" +\n                                    EnumChatFormatting.WHITE + ZombieTracker.books + \"\\n\" +\n                                    EnumChatFormatting.WHITE + ZombieTracker.booksT7 + \"\\n\" +\n                                    EnumChatFormatting.AQUA + ZombieTracker.undeadCatas + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + ZombieTracker.beheadeds + \"\\n\" +\n                                    EnumChatFormatting.RED + ZombieTracker.revCatas + \"\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + ZombieTracker.snakes + \"\\n\" +\n                                    EnumChatFormatting.GOLD + ZombieTracker.scythes + \"\\n\" +\n                                    EnumChatFormatting.RED + ZombieTracker.shards + \"\\n\" +\n                                    EnumChatFormatting.RED + ZombieTracker.wardenHearts + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        } else {\n                            if (ZombieTracker.timeSession == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(ZombieTracker.timeSession, timeNow);\n                            }\n                            if (ZombieTracker.bossesSession == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(ZombieTracker.bossesSession);\n                            }\n                            if (slayerCountTotal) {\n                                drop20 = nf.format(ZombieTracker.foulFleshSession);\n                            } else {\n                                drop20 = nf.format(ZombieTracker.foulFleshDropsSession) + \" times\";\n                            }\n\n                            dropsText = EnumChatFormatting.GOLD + \"Revs Killed:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Revenant Flesh:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Revenant Viscera:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Foul Flesh:\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + \"Pestilence Runes:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Smite VI Books:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Smite VII Books:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Undead Catalysts:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Beheaded Horrors:\\n\" +\n                                    EnumChatFormatting.RED + \"Revenant Catalysts:\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + \"Snake Runes:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Scythe Blades:\\n\" +\n                                    EnumChatFormatting.RED + \"Shard of Shreddeds:\\n\" +\n                                    EnumChatFormatting.RED + \"Warden Hearts:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since RNG:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Bosses Since RNG:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(ZombieTracker.revsSession) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(ZombieTracker.revFleshSession) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(ZombieTracker.revVisceraSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + drop20 + \"\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + ZombieTracker.pestilencesSession + \"\\n\" +\n                                    EnumChatFormatting.WHITE + ZombieTracker.booksSession + \"\\n\" +\n                                    EnumChatFormatting.WHITE + ZombieTracker.booksT7Session + \"\\n\" +\n                                    EnumChatFormatting.AQUA + ZombieTracker.undeadCatasSession + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + ZombieTracker.beheadedsSession + \"\\n\" +\n                                    EnumChatFormatting.RED + ZombieTracker.revCatasSession + \"\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + ZombieTracker.snakesSession + \"\\n\" +\n                                    EnumChatFormatting.GOLD + ZombieTracker.scythesSession + \"\\n\" +\n                                    EnumChatFormatting.RED + ZombieTracker.shardsSession + \"\\n\" +\n                                    EnumChatFormatting.RED + ZombieTracker.wardenHeartsSession + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        }\n                        break;\n                    case \"Enderman Slayer\":\n                        if (!sessionDisplay) {\n                            if (EndermanTracker.time == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(EndermanTracker.time, timeNow);\n                            }\n                            if (EndermanTracker.bosses == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(EndermanTracker.bosses);\n                            }\n                            if (slayerCountTotal) {\n                                drop20 = nf.format(EndermanTracker.TAP);\n                            } else {\n                                drop20 = nf.format(EndermanTracker.TAPDrops) + \" times\";\n                            }\n\n                            dropsText = EnumChatFormatting.GOLD + \"Voidglooms Killed:\\n\" +\n                                    EnumChatFormatting.DARK_GRAY + \"Null Spheres:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Arrow Poison:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Endersnake Runes:\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + \"Summoning Eyes:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Mana Steal Books:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Transmission Tuners:\\n\" +\n                                    EnumChatFormatting.YELLOW + \"Null Atoms:\\n\" +\n                                    EnumChatFormatting.YELLOW + \"Hazmat Endermen:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Espresso Machines:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Smarty Pants Books:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"End Runes:\\n\" +\n                                    EnumChatFormatting.RED + \"Blood Chalices:\\n\" +\n                                    EnumChatFormatting.RED + \"Sinful Dice:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Artifact Upgrader:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Enderman Skins:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Enchant Runes:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Etherwarp Mergers:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Judgement Cores:\\n\" +\n                                    EnumChatFormatting.RED + \"Ender Slayer Books:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since RNG:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Bosses Since RNG:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(EndermanTracker.voidglooms) + \"\\n\" +\n                                    EnumChatFormatting.DARK_GRAY + nf.format(EndermanTracker.nullSpheres) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + drop20 + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + EndermanTracker.endersnakes + \"\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + EndermanTracker.summoningEyes + \"\\n\" +\n                                    EnumChatFormatting.AQUA + EndermanTracker.manaBooks + \"\\n\" +\n                                    EnumChatFormatting.BLUE + EndermanTracker.tuners + \"\\n\" +\n                                    EnumChatFormatting.YELLOW + EndermanTracker.atoms + \"\\n\" +\n                                    EnumChatFormatting.YELLOW + EndermanTracker.hazmats + \"\\n\" +\n                                    EnumChatFormatting.AQUA + EndermanTracker.espressoMachines + \"\\n\" +\n                                    EnumChatFormatting.WHITE + EndermanTracker.smartyBooks + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + EndermanTracker.endRunes + \"\\n\" +\n                                    EnumChatFormatting.RED + EndermanTracker.chalices + \"\\n\" +\n                                    EnumChatFormatting.RED + EndermanTracker.dice + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + EndermanTracker.artifacts + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + EndermanTracker.skins + \"\\n\" +\n                                    EnumChatFormatting.GRAY + EndermanTracker.enchantRunes + \"\\n\" +\n                                    EnumChatFormatting.GOLD + EndermanTracker.mergers + \"\\n\" +\n                                    EnumChatFormatting.GOLD + EndermanTracker.cores + \"\\n\" +\n                                    EnumChatFormatting.RED + EndermanTracker.enderBooks + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        } else {\n                            if (EndermanTracker.timeSession == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(EndermanTracker.timeSession, timeNow);\n                            }\n                            if (EndermanTracker.bossesSession == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(EndermanTracker.bossesSession);\n                            }\n                            if (slayerCountTotal) {\n                                drop20 = nf.format(EndermanTracker.TAPSession);\n                            } else {\n                                drop20 = nf.format(EndermanTracker.TAPDropsSession) + \" times\";\n                            }\n\n                            dropsText = EnumChatFormatting.GOLD + \"Voidglooms Killed:\\n\" +\n                                    EnumChatFormatting.DARK_GRAY + \"Null Spheres:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Arrow Poison:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Endersnake Runes:\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + \"Summoning Eyes:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Mana Steal Books:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Transmission Tuners:\\n\" +\n                                    EnumChatFormatting.YELLOW + \"Null Atoms:\\n\" +\n                                    EnumChatFormatting.YELLOW + \"Hazmat Endermen:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Espresso Machines:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Smarty Pants Books:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"End Runes:\\n\" +\n                                    EnumChatFormatting.RED + \"Blood Chalices:\\n\" +\n                                    EnumChatFormatting.RED + \"Sinful Dice:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Artifact Upgrader:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Enderman Skins:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Enchant Runes:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Etherwarp Mergers:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Judgement Cores:\\n\" +\n                                    EnumChatFormatting.RED + \"Ender Slayer Books:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since RNG:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Bosses Since RNG:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(EndermanTracker.voidgloomsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_GRAY + nf.format(EndermanTracker.nullSpheresSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + drop20 + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + EndermanTracker.endersnakesSession + \"\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + EndermanTracker.summoningEyesSession + \"\\n\" +\n                                    EnumChatFormatting.AQUA + EndermanTracker.manaBooksSession + \"\\n\" +\n                                    EnumChatFormatting.BLUE + EndermanTracker.tunersSession + \"\\n\" +\n                                    EnumChatFormatting.YELLOW + EndermanTracker.atomsSession + \"\\n\" +\n                                    EnumChatFormatting.YELLOW + EndermanTracker.hazmatsSession + \"\\n\" +\n                                    EnumChatFormatting.AQUA + EndermanTracker.espressoMachinesSession + \"\\n\" +\n                                    EnumChatFormatting.WHITE + EndermanTracker.smartyBooksSession + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + EndermanTracker.endRunesSession + \"\\n\" +\n                                    EnumChatFormatting.RED + EndermanTracker.chalicesSession + \"\\n\" +\n                                    EnumChatFormatting.RED + EndermanTracker.diceSession + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + EndermanTracker.artifactsSession + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + EndermanTracker.skinsSession + \"\\n\" +\n                                    EnumChatFormatting.GRAY + EndermanTracker.enchantRunesSession + \"\\n\" +\n                                    EnumChatFormatting.GOLD + EndermanTracker.mergersSession + \"\\n\" +\n                                    EnumChatFormatting.GOLD + EndermanTracker.coresSession + \"\\n\" +\n                                    EnumChatFormatting.RED + EndermanTracker.enderBooksSession + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        }\n                        break;\n                    case \"Blaze Slayer\":\n                        if (!sessionDisplay) {\n                            if (BlazeTracker.time == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(BlazeTracker.time, timeNow);\n                            }\n                            if (BlazeTracker.bosses == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(BlazeTracker.bosses);\n                            }\n\n                            dropsText = EnumChatFormatting.GOLD + \"Demonlords Killed:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Derelict Ashes:\\n\" +\n                                    EnumChatFormatting.YELLOW + \"Blaze Powder:\\n\" +\n                                    EnumChatFormatting.RED + \"Lavatear Runes:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Splash Potions:\\n\" +\n                                    EnumChatFormatting.DARK_RED + \"Magma Arrows:\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + \"Mana Disintegrators:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Scorched Books:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Kelvin Inverters:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Blaze Rod Distillates:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Glowstone Distillates:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Magma Distillates:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Wart Distillates:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Gabagool Distillates:\\n\" +\n                                    EnumChatFormatting.RED + \"Power Crystals:\\n\" +\n                                    EnumChatFormatting.RED + \"Fire Aspect Books:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Fiery Burst Runes:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Opal Gems:\\n\" +\n                                    EnumChatFormatting.RED + \"Archfiend Dice:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Duplex Books:\\n\" +\n                                    EnumChatFormatting.GOLD + \"High Class Dice:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Engineering Plans:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Subzero Inverters:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since RNG:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Bosses Since RNG:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(BlazeTracker.demonlords) + \"\\n\" +\n                                    EnumChatFormatting.GRAY + nf.format(BlazeTracker.derelictAshes) + \"\\n\" +\n                                    EnumChatFormatting.YELLOW + nf.format(BlazeTracker.blazePowder) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(BlazeTracker.lavatearRunes) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(BlazeTracker.splashPotions) + \"\\n\" +\n                                    EnumChatFormatting.DARK_RED + nf.format(BlazeTracker.magmaArrows) + \"\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + nf.format(BlazeTracker.manaDisintegrators) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + nf.format(BlazeTracker.scorchedBooks) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(BlazeTracker.kelvinInverters) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(BlazeTracker.blazeRodDistillates) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(BlazeTracker.glowstoneDistillates) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(BlazeTracker.magmaCreamDistillates) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(BlazeTracker.netherWartDistillates) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(BlazeTracker.gabagoolDistillates) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(BlazeTracker.scorchedPowerCrystals) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(BlazeTracker.fireAspectBooks) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(BlazeTracker.fieryBurstRunes) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(BlazeTracker.opalGems) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(BlazeTracker.archfiendDice) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + nf.format(BlazeTracker.duplexBooks) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(BlazeTracker.highClassArchfiendDice) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(BlazeTracker.engineeringPlans) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(BlazeTracker.subzeroInverters) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        } else {\n                            if (BlazeTracker.timeSession == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(BlazeTracker.timeSession, timeNow);\n                            }\n                            if (BlazeTracker.bossesSession == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(BlazeTracker.bossesSession);\n                            }\n\n                            dropsText = EnumChatFormatting.GOLD + \"Demonlords Killed:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Derelict Ashes:\\n\" +\n                                    EnumChatFormatting.YELLOW + \"Blaze Powder:\\n\" +\n                                    EnumChatFormatting.RED + \"Lavatear Runes:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Splash Potions:\\n\" +\n                                    EnumChatFormatting.DARK_RED + \"Magma Arrows:\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + \"Mana Disintegrators:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Scorched Books:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Kelvin Inverters:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Blaze Rod Distillates:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Glowstone Distillates:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Magma Distillates:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Wart Distillates:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Gabagool Distillates:\\n\" +\n                                    EnumChatFormatting.RED + \"Power Crystals:\\n\" +\n                                    EnumChatFormatting.RED + \"Fire Aspect Books:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Fiery Burst Runes:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Opal Gems:\\n\" +\n                                    EnumChatFormatting.RED + \"Archfiend Dice:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Duplex Books:\\n\" +\n                                    EnumChatFormatting.GOLD + \"High Class Dice:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Engineering Plans:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Subzero Inverters:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since RNG:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Bosses Since RNG:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(BlazeTracker.demonlordsSession) + \"\\n\" +\n                                    EnumChatFormatting.GRAY + nf.format(BlazeTracker.derelictAshesSession) + \"\\n\" +\n                                    EnumChatFormatting.YELLOW + nf.format(BlazeTracker.blazePowderSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(BlazeTracker.lavatearRunesSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(BlazeTracker.splashPotionsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_RED + nf.format(BlazeTracker.magmaArrowsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + nf.format(BlazeTracker.manaDisintegratorsSession) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + nf.format(BlazeTracker.scorchedBooksSession) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(BlazeTracker.kelvinInvertersSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(BlazeTracker.blazeRodDistillatesSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(BlazeTracker.glowstoneDistillatesSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(BlazeTracker.magmaCreamDistillatesSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(BlazeTracker.netherWartDistillatesSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(BlazeTracker.gabagoolDistillatesSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(BlazeTracker.scorchedPowerCrystalsSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(BlazeTracker.fireAspectBooksSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(BlazeTracker.fieryBurstRunesSession) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(BlazeTracker.opalGemsSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(BlazeTracker.archfiendDiceSession) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + nf.format(BlazeTracker.duplexBooksSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(BlazeTracker.highClassArchfiendDiceSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(BlazeTracker.engineeringPlansSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(BlazeTracker.subzeroInvertersSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        }\n                        break;\n                    case \"Vampire Slayer\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.GOLD + \"Riftstalkers Killed:\\n\" +\n                                    EnumChatFormatting.DARK_RED + \"Coven Seals:\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + \"Quantum Bundles:\\n\" +\n                                    EnumChatFormatting.RED + \"Bubba Blisters:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Soultwist Runes:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Chocolate Chips:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Lucky Blocks:\\n\" +\n                                    EnumChatFormatting.RED + \"The One Bundles:\\n\" +\n                                    EnumChatFormatting.GREEN + \"McGrubbers Burgers:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Vampire Parts:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(VampireTracker.riftstalkers) + \"\\n\" +\n                                    EnumChatFormatting.DARK_RED + nf.format(VampireTracker.covenSeals) + \"\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + nf.format(VampireTracker.quantumBundles) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(VampireTracker.bubbaBlisters) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + nf.format(VampireTracker.soultwistRunes) + \"\\n\" +\n                                    EnumChatFormatting.GRAY + nf.format(VampireTracker.chocolateChips) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(VampireTracker.luckyBlocks) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(VampireTracker.theOneBundles) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(VampireTracker.mcgrubbersBurgers) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(VampireTracker.vampireParts);\n                        } else {\n                            dropsText = EnumChatFormatting.GOLD + \"Riftstalkers Killed:\\n\" +\n                                    EnumChatFormatting.DARK_RED + \"Coven Seals:\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + \"Quantum Bundles:\\n\" +\n                                    EnumChatFormatting.RED + \"Bubba Blisters:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Soultwist Runes:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Chocolate Chips:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Lucky Blocks:\\n\" +\n                                    EnumChatFormatting.RED + \"The One Bundles:\\n\" +\n                                    EnumChatFormatting.GREEN + \"McGrubbers Burgers:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Vampire Parts:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(VampireTracker.riftstalkersSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_RED + nf.format(VampireTracker.covenSealsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + nf.format(VampireTracker.quantumBundlesSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(VampireTracker.bubbaBlistersSession) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + nf.format(VampireTracker.soultwistRunesSession) + \"\\n\" +\n                                    EnumChatFormatting.GRAY + nf.format(VampireTracker.chocolateChipsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(VampireTracker.luckyBlocksSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(VampireTracker.theOneBundlesSession) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(VampireTracker.mcgrubbersBurgersSession) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(VampireTracker.vampirePartsSession);\n                        }\n                        break;\n                    case \"Fishing\":\n                        if (!sessionDisplay) {\n                            if (FishingTracker.empTime == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(FishingTracker.empTime, timeNow);\n                            }\n                            if (FishingTracker.empSCs == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(FishingTracker.empSCs);\n                            }\n\n                            dropsText = EnumChatFormatting.AQUA + \"Creatures Caught:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Fishing Milestone:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Good Catches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Great Catches:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Squids:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Sea Walkers:\\n\" +\n                                    EnumChatFormatting.DARK_GRAY + \"Night Squids:\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + \"Sea Guardians:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Sea Witches:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Sea Archers:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Monster of Deeps:\";\n                            countText = EnumChatFormatting.AQUA + nf.format(FishingTracker.seaCreatures) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.fishingMilestone) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.goodCatches) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.greatCatches) + \"\\n\" +\n                                    EnumChatFormatting.GRAY + nf.format(FishingTracker.squids) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(FishingTracker.seaWalkers) + \"\\n\" +\n                                    EnumChatFormatting.DARK_GRAY + nf.format(FishingTracker.nightSquids) + \"\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + nf.format(FishingTracker.seaGuardians) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(FishingTracker.seaWitches) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(FishingTracker.seaArchers) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(FishingTracker.monsterOfTheDeeps);\n                            // Seperated to save vertical space\n                            dropsTextTwo = EnumChatFormatting.RED + \"Agarimoos:\\n\" +\n                                    EnumChatFormatting.YELLOW + \"Catfishes:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Carrot Kings:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Sea Leeches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Guardian Defenders:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Deep Sea Protectors:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Hydras:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Sea Emperors:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since Emp:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Creatures Since Emp:\";\n                            countTextTwo = EnumChatFormatting.RED + nf.format(FishingTracker.agarimoos) + \"\\n\" +\n                                    EnumChatFormatting.YELLOW + nf.format(FishingTracker.catfishes) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.carrotKings) + \"\\n\" +\n                                    EnumChatFormatting.GRAY + nf.format(FishingTracker.seaLeeches) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.guardianDefenders) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.deepSeaProtectors) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.hydras) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.seaEmperors) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n\n                            if (splitFishing) {\n                                TextRenderer.drawHUDText(dropsTextTwo, (int) (x + (160 * scale)), y, scale);\n                                TextRenderer.drawHUDText(countTextTwo, (int) (x + (270 * scale)), y, scale);\n                            } else {\n                                dropsText += \"\\n\" + dropsTextTwo;\n                                countText += \"\\n\" + countTextTwo;\n                            }\n                        } else {\n                            if (FishingTracker.empTimeSession == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(FishingTracker.empTimeSession, timeNow);\n                            }\n                            if (FishingTracker.empSCsSession == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(FishingTracker.empSCsSession);\n                            }\n\n                            dropsText = EnumChatFormatting.AQUA + \"Creatures Caught:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Fishing Milestone:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Good Catches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Great Catches:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Squids:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Sea Walkers:\\n\" +\n                                    EnumChatFormatting.DARK_GRAY + \"Night Squids:\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + \"Sea Guardians:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Sea Witches:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Sea Archers:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Monster of Deeps:\";\n                            countText = EnumChatFormatting.AQUA + nf.format(FishingTracker.seaCreaturesSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.fishingMilestoneSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.goodCatchesSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.greatCatchesSession) + \"\\n\" +\n                                    EnumChatFormatting.GRAY + nf.format(FishingTracker.squidsSession) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(FishingTracker.seaWalkersSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_GRAY + nf.format(FishingTracker.nightSquidsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_AQUA + nf.format(FishingTracker.seaGuardiansSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(FishingTracker.seaWitchesSession) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(FishingTracker.seaArchersSession) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(FishingTracker.monsterOfTheDeepsSession);\n                            // Seperated to save vertical space\n                            dropsTextTwo = EnumChatFormatting.RED + \"Agarimoos:\\n\" +\n                                    EnumChatFormatting.YELLOW + \"Catfishes:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Carrot Kings:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Sea Leeches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Guardian Defenders:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Deep Sea Protectors:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Hydras:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Sea Emperors:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since Emp:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Creatures Since Emp:\";\n                            countTextTwo = EnumChatFormatting.RED + nf.format(FishingTracker.agarimoosSession) + \"\\n\" +\n                                    EnumChatFormatting.YELLOW + nf.format(FishingTracker.catfishesSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.carrotKingsSession) + \"\\n\" +\n                                    EnumChatFormatting.GRAY + nf.format(FishingTracker.seaLeechesSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.guardianDefendersSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.deepSeaProtectorsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.hydrasSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.seaEmperorsSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n\n                            if (splitFishing) {\n                                TextRenderer.drawHUDText(dropsTextTwo, (int) (x + (160 * scale)), y, scale);\n                                TextRenderer.drawHUDText(countTextTwo, (int) (x + (270 * scale)), y, scale);\n                            } else {\n                                dropsText += \"\\n\" + dropsTextTwo;\n                                countText += \"\\n\" + countTextTwo;\n                            }\n                        }\n                        break;\n                    case \"Winter Fishing\":\n                        if (!sessionDisplay) {\n                            if (FishingTracker.reindrakeTime == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(FishingTracker.reindrakeTime, timeNow);\n                            }\n                            if (FishingTracker.reindrakeSCs == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(FishingTracker.reindrakeSCs);\n                            }\n\n                            dropsText = EnumChatFormatting.AQUA + \"Creatures Caught:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Fishing Milestone:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Good Catches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Great Catches:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Frozen Steves:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Snowmans:\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + \"Grinches:\\n\" +\n                                    EnumChatFormatting.RED + \"Nutcrackers:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Yetis:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Reindrakes:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since Reindrake:\\n\" +\n                                    EnumChatFormatting.AQUA + \"SC Since Reindrake:\";\n                            countText = EnumChatFormatting.AQUA + nf.format(FishingTracker.seaCreatures) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.fishingMilestone) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.goodCatches) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.greatCatches) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.frozenSteves) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(FishingTracker.frostyTheSnowmans) + \"\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + nf.format(FishingTracker.grinches) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(FishingTracker.nutcrackers) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.yetis) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.reindrakes) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        } else {\n                            if (FishingTracker.reindrakeTimeSession == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(FishingTracker.reindrakeTimeSession, timeNow);\n                            }\n                            if (FishingTracker.reindrakeSCsSession == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(FishingTracker.reindrakeSCsSession);\n                            }\n\n                            dropsText = EnumChatFormatting.AQUA + \"Creatures Caught:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Fishing Milestone:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Good Catches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Great Catches:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Frozen Steves:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Snowmans:\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + \"Grinches:\\n\" +\n                                    EnumChatFormatting.RED + \"Nutcrackers:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Yetis:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Reindrakes:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since Reindrake:\\n\" +\n                                    EnumChatFormatting.AQUA + \"SC Since Reindrake:\";\n                            countText = EnumChatFormatting.AQUA + nf.format(FishingTracker.seaCreaturesSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.fishingMilestoneSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.goodCatchesSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.greatCatchesSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.frozenStevesSession) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(FishingTracker.frostyTheSnowmansSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_GREEN + nf.format(FishingTracker.grinchesSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(FishingTracker.nutcrackersSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.yetisSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.reindrakesSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        }\n                        break;\n                    case \"Fishing Festival\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.AQUA + \"Creatures Caught:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Fishing Milestone:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Good Catches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Great Catches:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Nurse Sharks:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Blue Sharks:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Tiger Sharks:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Great White Sharks:\";\n                            countText = EnumChatFormatting.AQUA + nf.format(FishingTracker.seaCreatures) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.fishingMilestone) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.goodCatches) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.greatCatches) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + nf.format(FishingTracker.nurseSharks) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(FishingTracker.blueSharks) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.tigerSharks) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(FishingTracker.greatWhiteSharks);\n                        } else {\n                            dropsText = EnumChatFormatting.AQUA + \"Creatures Caught:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Fishing Milestone:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Good Catches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Great Catches:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Nurse Sharks:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Blue Sharks:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Tiger Sharks:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Great White Sharks:\";\n                            countText = EnumChatFormatting.AQUA + nf.format(FishingTracker.seaCreaturesSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.fishingMilestoneSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.goodCatchesSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.greatCatchesSession) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + nf.format(FishingTracker.nurseSharksSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(FishingTracker.blueSharksSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.tigerSharksSession) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(FishingTracker.greatWhiteSharksSession);\n                        }\n                        break;\n                    case \"Spooky Fishing\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.AQUA + \"Creatures Caught:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Fishing Milestone:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Good Catches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Great Catches:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Scarecrows:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Nightmares:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Werewolves:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Phantom Fishers:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Grim Reapers:\";\n                            countText = EnumChatFormatting.AQUA + nf.format(FishingTracker.seaCreatures) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.fishingMilestone) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.goodCatches) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.greatCatches) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(FishingTracker.scarecrows) + \"\\n\" +\n                                    EnumChatFormatting.GRAY + nf.format(FishingTracker.nightmares) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.werewolfs) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.phantomFishers) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.grimReapers);\n                        } else {\n                            dropsText = EnumChatFormatting.AQUA + \"Creatures Caught:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Fishing Milestone:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Good Catches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Great Catches:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Scarecrows:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Nightmares:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Werewolves:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Phantom Fishers:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Grim Reapers:\";\n                            countText = EnumChatFormatting.AQUA + nf.format(FishingTracker.seaCreaturesSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.fishingMilestoneSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.goodCatchesSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.greatCatchesSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(FishingTracker.scarecrowsSession) + \"\\n\" +\n                                    EnumChatFormatting.GRAY + nf.format(FishingTracker.nightmaresSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.werewolfsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.phantomFishersSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.grimReapersSession);\n                        }\n                        break;\n                    case \"Crystal Hollows Fishing\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.AQUA + \"Creatures Caught:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Fishing Milestone:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Good Catches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Great Catches:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Water Worms:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Poison Water Worms:\\n\" +\n                                    EnumChatFormatting.RED + \"Flaming Worms:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Lava Blazes:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Lava Pigmen:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Zombie Miners:\";\n                            countText = EnumChatFormatting.AQUA + nf.format(FishingTracker.seaCreatures) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.fishingMilestone) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.goodCatches) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.greatCatches) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(FishingTracker.waterWorms) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(FishingTracker.poisonedWaterWorms) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(FishingTracker.flamingWorms) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.lavaBlazes) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.lavaPigmen) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.zombieMiners);\n                        } else {\n                            dropsText = EnumChatFormatting.AQUA + \"Creatures Caught:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Fishing Milestone:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Good Catches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Great Catches:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Water Worms:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Poison Water Worms:\\n\" +\n                                    EnumChatFormatting.RED + \"Flaming Worms:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Lava Blazes:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Lava Pigmen:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Zombie Miners:\";\n                            countText = EnumChatFormatting.AQUA + nf.format(FishingTracker.seaCreaturesSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.fishingMilestoneSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.goodCatchesSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.greatCatchesSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(FishingTracker.waterWormsSession) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(FishingTracker.poisonedWaterWormsSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(FishingTracker.flamingWormsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.lavaBlazesSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.lavaPigmenSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.zombieMinersSession);\n                        }\n                        break;\n                    case \"Lava Fishing\":\n                        if (!sessionDisplay) {\n                            if (FishingTracker.jawbusTime == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(FishingTracker.jawbusTime, timeNow);\n                            }\n                            if (FishingTracker.jawbusSCs == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(FishingTracker.jawbusSCs);\n                            }\n\n                            dropsText = EnumChatFormatting.AQUA + \"Creatures Caught:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Fishing Milestone:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Good Catches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Great Catches:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Plhlegblasts:\\n\" +\n                                    EnumChatFormatting.DARK_RED + \"Magma Slugs:\\n\" +\n                                    EnumChatFormatting.RED + \"Moogmas:\\n\" +\n                                    EnumChatFormatting.RED + \"Lava Leeches:\\n\" +\n                                    EnumChatFormatting.RED + \"Pyroclastic Worms:\\n\" +\n                                    EnumChatFormatting.DARK_RED + \"Lava Flames:\\n\" +\n                                    EnumChatFormatting.RED + \"Fire Eels:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Tauruses:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Thunders:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Lord Jawbuses:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since Jawbus:\\n\" +\n                                    EnumChatFormatting.AQUA + \"SC Since Jawbus:\";\n                            countText = EnumChatFormatting.AQUA + nf.format(FishingTracker.seaCreatures) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.fishingMilestone) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.goodCatches) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.greatCatches) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(FishingTracker.plhlegblasts) + \"\\n\" +\n                                    EnumChatFormatting.DARK_RED + nf.format(FishingTracker.magmaSlugs) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(FishingTracker.moogmas) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(FishingTracker.lavaLeeches) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(FishingTracker.pyroclasticWorms) + \"\\n\" +\n                                    EnumChatFormatting.DARK_RED + nf.format(FishingTracker.lavaFlames) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(FishingTracker.fireEels) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.tauruses) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + nf.format(FishingTracker.thunders) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + nf.format(FishingTracker.lordJawbuses) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        } else {\n                            if (FishingTracker.jawbusTimeSession == -1) {\n                                timeBetween = \"Never\";\n                            } else {\n                                timeBetween = Utils.getTimeBetween(FishingTracker.jawbusTimeSession, timeNow);\n                            }\n                            if (FishingTracker.jawbusSCsSession == -1) {\n                                bossesBetween = \"Never\";\n                            } else {\n                                bossesBetween = nf.format(FishingTracker.jawbusSCsSession);\n                            }\n\n                            dropsText = EnumChatFormatting.AQUA + \"Creatures Caught:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Fishing Milestone:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Good Catches:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Great Catches:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Plhlegblasts:\\n\" +\n                                    EnumChatFormatting.DARK_RED + \"Magma Slugs:\\n\" +\n                                    EnumChatFormatting.RED + \"Moogmas:\\n\" +\n                                    EnumChatFormatting.RED + \"Lava Leeches:\\n\" +\n                                    EnumChatFormatting.RED + \"Pyroclastic Worms:\\n\" +\n                                    EnumChatFormatting.DARK_RED + \"Lava Flames:\\n\" +\n                                    EnumChatFormatting.RED + \"Fire Eels:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Tauruses:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Thunders:\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + \"Lord Jawbuses:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Since Jawbus:\\n\" +\n                                    EnumChatFormatting.AQUA + \"SC Since Jawbus:\";\n                            countText = EnumChatFormatting.AQUA + nf.format(FishingTracker.seaCreaturesSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(FishingTracker.fishingMilestoneSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.goodCatchesSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(FishingTracker.greatCatchesSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(FishingTracker.plhlegblastsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_RED + nf.format(FishingTracker.magmaSlugsSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(FishingTracker.moogmasSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(FishingTracker.lavaLeechesSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(FishingTracker.pyroclasticWormsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_RED + nf.format(FishingTracker.lavaFlamesSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(FishingTracker.fireEelsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(FishingTracker.taurusesSession) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + nf.format(FishingTracker.thundersSession) + \"\\n\" +\n                                    EnumChatFormatting.LIGHT_PURPLE + nf.format(FishingTracker.lordJawbusesSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + timeBetween + \"\\n\" +\n                                    EnumChatFormatting.AQUA + bossesBetween;\n                        }\n                        break;\n                    case \"Trophy Fishing\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.WHITE + \"Sulphur Skitter:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Obfuscated 1:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Steaminghot Flounder:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Gusher:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Blobfish:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Obfuscated 2:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Slugfish:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Flyfish:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Obfuscated 3:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Lavahorse:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Mana Ray:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Volcanic Stonefish:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Vanille:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Skeleton Fish:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Moldfin:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Soul Fish:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Karate Fish:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Golden Fish:\";\n                            if (!showTrophyCompletion)\n                                countText = EnumChatFormatting.WHITE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Sulphur Skitter\") + \"\\n\" +\n                                        EnumChatFormatting.WHITE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Obfuscated 1\") + \"\\n\" +\n                                        EnumChatFormatting.WHITE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Steaming-Hot Flounder\") + \"\\n\" +\n                                        EnumChatFormatting.WHITE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Gusher\") + \"\\n\" +\n                                        EnumChatFormatting.WHITE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Blobfish\") + \"\\n\" +\n                                        EnumChatFormatting.GREEN + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Obfuscated 2\") + \"\\n\" +\n                                        EnumChatFormatting.GREEN + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Slugfish\") + \"\\n\" +\n                                        EnumChatFormatting.GREEN + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Flyfish\") + \"\\n\" +\n                                        EnumChatFormatting.BLUE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Obfuscated 3\") + \"\\n\" +\n                                        EnumChatFormatting.BLUE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Lavahorse\") + \"\\n\" +\n                                        EnumChatFormatting.BLUE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Mana Ray\") + \"\\n\" +\n                                        EnumChatFormatting.BLUE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Volcanic Stonefish\") + \"\\n\" +\n                                        EnumChatFormatting.BLUE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Vanille\") + \"\\n\" +\n                                        EnumChatFormatting.DARK_PURPLE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Skeleton Fish\") + \"\\n\" +\n                                        EnumChatFormatting.DARK_PURPLE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Moldfin\") + \"\\n\" +\n                                        EnumChatFormatting.DARK_PURPLE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Soul Fish\") + \"\\n\" +\n                                        EnumChatFormatting.DARK_PURPLE + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Karate Fish\") + \"\\n\" +\n                                        EnumChatFormatting.GOLD + TrophyFishTracker.getTierCount(TrophyFishTracker.fish, \"Golden Fish\");\n\n                            if (showTrophyCompletion) {\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Sulphur Skitter\", (int) (x + (110 * scale)), (int) y, scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Obfuscated 1\", (int) (x + (110 * scale)), (int) (y + (mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Steaming-Hot Flounder\", (int) (x + (110 * scale)), (int) (y + (2 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Gusher\", (int) (x + (110 * scale)), (int) (y + (3 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Blobfish\", (int) (x + (110 * scale)), (int) (y + (4 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Obfuscated 2\", (int) (x + (110 * scale)), (int) (y + (5 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Slugfish\", (int) (x + (110 * scale)), (int) (y + (6 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Flyfish\", (int) (x + (110 * scale)), (int) (y + (7 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Obfuscated 3\", (int) (x + (110 * scale)), (int) (y + (8 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Lavahorse\", (int) (x + (110 * scale)), (int) (y + (9 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Mana Ray\", (int) (x + (110 * scale)), (int) (y + (10 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Volcanic Stonefish\", (int) (x + (110 * scale)), (int) (y + (11 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Vanille\", (int) (x + (110 * scale)), (int) (y + (12 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Skeleton Fish\", (int) (x + (110 * scale)), (int) (y + (13 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Moldfin\", (int) (x + (110 * scale)), (int) (y + (14 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Soul Fish\", (int) (x + (110 * scale)), (int) (y + (15 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Karate Fish\", (int) (x + (110 * scale)), (int) (y + (16 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fish, \"Golden Fish\", (int) (x + (110 * scale)), (int) (y + (17 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                            }\n                        } else {\n                            dropsText = EnumChatFormatting.WHITE + \"Sulphur Skitter:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Obfuscated 1:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Steaminghot Flounder:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Gusher:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Blobfish:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Obfuscated 2:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Slugfish:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Flyfish:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Obfuscated 3:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Lavahorse:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Mana Ray:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Volcanic Stonefish:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Vanille:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Skeleton Fish:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Moldfin:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Soul Fish:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Karate Fish:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Golden Fish:\";\n                            if (!showTrophyCompletion) countText = EnumChatFormatting.WHITE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Sulphur Skitter\") + \"\\n\" +\n                                    EnumChatFormatting.WHITE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Obfuscated 1\") + \"\\n\" +\n                                    EnumChatFormatting.WHITE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Steaming-Hot Flounder\") + \"\\n\" +\n                                    EnumChatFormatting.WHITE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Gusher\") + \"\\n\" +\n                                    EnumChatFormatting.WHITE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Blobfish\") + \"\\n\" +\n                                    EnumChatFormatting.GREEN + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Obfuscated 2\") + \"\\n\" +\n                                    EnumChatFormatting.GREEN + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Slugfish\") + \"\\n\" +\n                                    EnumChatFormatting.GREEN + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Flyfish\") + \"\\n\" +\n                                    EnumChatFormatting.BLUE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Obfuscated 3\") + \"\\n\" +\n                                    EnumChatFormatting.BLUE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Lavahorse\") + \"\\n\" +\n                                    EnumChatFormatting.BLUE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Mana Ray\") + \"\\n\" +\n                                    EnumChatFormatting.BLUE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Volcanic Stonefish\") + \"\\n\" +\n                                    EnumChatFormatting.BLUE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Vanille\") + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Skeleton Fish\") + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Moldfin\") + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Soul Fish\") + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Karate Fish\") + \"\\n\" +\n                                    EnumChatFormatting.GOLD + TrophyFishTracker.getTierCount(TrophyFishTracker.fishSession, \"Golden Fish\");\n\n                            if (showTrophyCompletion) {\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Sulphur Skitter\", (int) (x + (110 * scale)), (int) y, scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Obfuscated 1\", (int) (x + (110 * scale)), (int) (y + (mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Steaming-Hot Flounder\", (int) (x + (110 * scale)), (int) (y + (2 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Gusher\", (int) (x + (110 * scale)), (int) (y + (3 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Blobfish\", (int) (x + (110 * scale)), (int) (y + (4 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Obfuscated 2\", (int) (x + (110 * scale)), (int) (y + (5 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Slugfish\", (int) (x + (110 * scale)), (int) (y + (6 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Flyfish\", (int) (x + (110 * scale)), (int) (y + (7 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Obfuscated 3\", (int) (x + (110 * scale)), (int) (y + (8 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Lavahorse\", (int) (x + (110 * scale)), (int) (y + (9 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Mana Ray\", (int) (x + (110 * scale)), (int) (y + (10 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Volcanic Stonefish\", (int) (x + (110 * scale)), (int) (y + (11 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Vanille\", (int) (x + (110 * scale)), (int) (y + (12 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Skeleton Fish\", (int) (x + (110 * scale)), (int) (y + (13 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Moldfin\", (int) (x + (110 * scale)), (int) (y + (14 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Soul Fish\", (int) (x + (110 * scale)), (int) (y + (15 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Karate Fish\", (int) (x + (110 * scale)), (int) (y + (16 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                                TrophyFishTracker.drawCompletion(TrophyFishTracker.fishSession, \"Golden Fish\", (int) (x + (110 * scale)), (int) (y + (17 * mc.fontRendererObj.FONT_HEIGHT * scale)), scale);\n                            }\n                        }\n                        break;\n                    case \"Mythological\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.GOLD + \"Coins:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Griffin Feathers:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Crown of Greeds:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Washed up Souvenirs:\\n\" +\n                                    EnumChatFormatting.RED + \"Minos Hunters:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Siamese Lynxes:\\n\" +\n                                    EnumChatFormatting.RED + \"Minotaurs:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Gaia Constructs:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Minos Champions:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Minos Inquisitors:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(MythologicalTracker.mythCoins) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(MythologicalTracker.griffinFeathers) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(MythologicalTracker.crownOfGreeds) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(MythologicalTracker.washedUpSouvenirs) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(MythologicalTracker.minosHunters) + \"\\n\" +\n                                    EnumChatFormatting.GRAY + nf.format(MythologicalTracker.siameseLynxes) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(MythologicalTracker.minotaurs) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(MythologicalTracker.gaiaConstructs) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(MythologicalTracker.minosChampions) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(MythologicalTracker.minosInquisitors);\n                        } else {\n                            dropsText = EnumChatFormatting.GOLD + \"Coins:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Griffin Feathers:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Crown of Greeds:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Washed up Souvenirs:\\n\" +\n                                    EnumChatFormatting.RED + \"Minos Hunters:\\n\" +\n                                    EnumChatFormatting.GRAY + \"Siamese Lynxes:\\n\" +\n                                    EnumChatFormatting.RED + \"Minotaurs:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Gaia Constructs:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Minos Champions:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Minos Inquisitors:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(MythologicalTracker.mythCoinsSession) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(MythologicalTracker.griffinFeathersSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(MythologicalTracker.crownOfGreedsSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + nf.format(MythologicalTracker.washedUpSouvenirsSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(MythologicalTracker.minosHuntersSession) + \"\\n\" +\n                                    EnumChatFormatting.GRAY + nf.format(MythologicalTracker.siameseLynxesSession) + \"\\n\" +\n                                    EnumChatFormatting.RED + nf.format(MythologicalTracker.minotaursSession) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(MythologicalTracker.gaiaConstructsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(MythologicalTracker.minosChampionsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(MythologicalTracker.minosInquisitorsSession);\n                        }\n                        break;\n                    case \"Floor 1\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Balloon Snakes:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Bonzo's Staffs:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f1SPlus) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(CatacombsTracker.balloonSnakes) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(CatacombsTracker.bonzoStaffs) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f1CoinsSpent) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f1TimeSpent);\n                        } else {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.GREEN + \"Balloon Snakes:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Bonzo's Staffs:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f1SPlusSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n                                    EnumChatFormatting.GREEN + nf.format(CatacombsTracker.balloonSnakesSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(CatacombsTracker.bonzoStaffsSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f1CoinsSpentSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f1TimeSpentSession);\n                        }\n                        break;\n                    case \"Floor 2\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Scarf's Studies:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Adaptive Blades:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Adaptive Belts:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f2SPlus) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(CatacombsTracker.scarfStudies) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.adaptiveSwords) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.adaptiveBelts) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f2CoinsSpent) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f2TimeSpent);\n                        } else {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Scarf's Studies:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Adaptive Blades:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Adaptive Belts:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f2SPlusSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(CatacombsTracker.scarfStudiesSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.adaptiveSwordsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.adaptiveBeltsSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f2CoinsSpentSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f2TimeSpentSession);\n                        }\n                        break;\n                    case \"Floor 3\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Adaptive Helmets:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Adaptive Chestplates:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Adaptive Leggings:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Adaptive Boots:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f3SPlus) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.adaptiveHelms) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.adaptiveChests) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.adaptiveLegs) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.adaptiveBoots) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f3CoinsSpent) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f3TimeSpent);\n                        } else {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Adaptive Helmets:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Adaptive Chestplates:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Adaptive Leggings:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Adaptive Boots:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f3SPlusSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.adaptiveHelmsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.adaptiveChestsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.adaptiveLegsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.adaptiveBootsSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f3CoinsSpentSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f3TimeSpentSession);\n                        }\n                        break;\n                    case \"Floor 4\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Spirit Wings:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Spirit Bones:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Spirit Boots:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Spirit Swords:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Spirit Bows:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Epic Spirit Pets:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Leg Spirit Pets:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f4SPlus) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.spiritWings) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.spiritBones) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.spiritBoots) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.spiritSwords) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.spiritBows) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.epicSpiritPets) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.legSpiritPets) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f4CoinsSpent) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f4TimeSpent);\n                        } else {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Spirit Wings:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Spirit Bones:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Spirit Boots:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Spirit Swords:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Spirit Bows:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Epic Spirit Pets:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Leg Spirit Pets:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f4SPlusSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.spiritWingsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.spiritBonesSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.spiritBootsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.spiritSwordsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.spiritBowsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.epicSpiritPetsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.legSpiritPetsSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f4CoinsSpentSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f4TimeSpentSession);\n                        }\n                        break;\n                    case \"Floor 5\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Warped Stones:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Shadow Helmets:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Shadow Chestplates:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Shadow Leggings:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Shadow Boots:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Shadow Cloaks:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Last Breaths:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Livid Daggers:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Shadow Furys:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f5SPlus) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(CatacombsTracker.warpedStones) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.shadowAssHelms) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.shadowAssChests) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.shadowAssLegs) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.shadowAssBoots) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.shadowAssCloaks) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.lastBreaths) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.lividDaggers) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.shadowFurys) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f5CoinsSpent) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f5TimeSpent);\n                        } else {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Warped Stones:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Shadow Helmets:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Shadow Chestplates:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Shadow Leggings:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Shadow Boots:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Shadow Cloaks:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Last Breaths:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Livid Daggers:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Shadow Furys:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f5SPlusSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(CatacombsTracker.warpedStonesSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.shadowAssHelmsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.shadowAssChestsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.shadowAssLegsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.shadowAssBootsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.shadowAssCloaksSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.lastBreathsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.lividDaggersSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.shadowFurysSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f5CoinsSpentSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f5TimeSpentSession);\n                        }\n                        break;\n                    case \"Floor 6\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Ancient Roses:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Precursor Eyes:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Giant's Swords:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Necro Lord Helmets:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Necro Lord Chests:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Necro Lord Leggings:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Necro Lord Boots:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Necro Swords:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fel Skulls:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Rerolls:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f6SPlus) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(CatacombsTracker.ancientRoses) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.precursorEyes) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.giantsSwords) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.necroLordHelms) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.necroLordChests) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.necroLordLegs) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.necroLordBoots) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.necroSwords) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.felSkulls) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(CatacombsTracker.f6Rerolls) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f6CoinsSpent) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f6TimeSpent);\n                        } else {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Ancient Roses:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Precursor Eyes:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Giant's Swords:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Necro Lord Helmets:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Necro Lord Chests:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Necro Lord Leggings:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Necro Lord Boots:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Necro Swords:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fel Skulls:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Rerolls:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f6SPlusSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(CatacombsTracker.ancientRosesSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.precursorEyesSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.giantsSwordsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.necroLordHelmsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.necroLordChestsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.necroLordLegsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.necroLordBootsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.necroSwordsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.felSkullsSession) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(CatacombsTracker.f6RerollsSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f6CoinsSpentSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f6TimeSpentSession);\n                        }\n                        break;\n                    case \"Floor 7\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Wither Bloods:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Wither Cloaks:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Implosions:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Wither Shields:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Shadow Warps:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Necron's Handles:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Auto Recombobs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Wither Helmets:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Wither Chests:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Wither Leggings:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Wither Boots:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Rerolls:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f7SPlus) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.witherBloods) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.witherCloaks) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.implosions) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.witherShields) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.shadowWarps) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.necronsHandles) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.autoRecombs) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.witherHelms) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.witherChests) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.witherLegs) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.witherBoots) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(CatacombsTracker.f7Rerolls) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f7CoinsSpent) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f7TimeSpent);\n                        } else {\n                            dropsText = EnumChatFormatting.GOLD + \"S+ Runs:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Wither Bloods:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Wither Cloaks:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Implosions:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Wither Shields:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Shadow Warps:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Necron's Handles:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Auto Recombobulators:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Wither Helmets:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Wither Chests:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Wither Leggings:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Wither Boots:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Rerolls:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.f7SPlusSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.witherBloodsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.witherCloaksSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.implosionsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.witherShieldsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.shadowWarpsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.necronsHandlesSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.autoRecombsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.witherHelmsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.witherChestsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.witherLegsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.witherBootsSession) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(CatacombsTracker.f7RerollsSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.f7CoinsSpentSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.f7TimeSpentSession);\n                        }\n                        break;\n                    case \"Master Mode\":\n                        if (!sessionDisplay) {\n                            if (masterSRunsDisplay) {\n                                runs = EnumChatFormatting.GOLD + \"Master One S+:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Two S+:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Three S+:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Four S+:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Five S+:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Six S+:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Seven S+:\\n\";\n                                runsCount = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m1SPlus) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m2SPlus) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m3SPlus) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m4SPlus) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m5SPlus) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m6SPlus) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m7SPlus) + \"\\n\";\n                            } else {\n                                runs = EnumChatFormatting.GOLD + \"Master One S:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Two S:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Three S:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Four S:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Five S:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Six S:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Seven S:\\n\";\n                                runsCount = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m1S) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m2S) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m3S) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m4S) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m5S) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m6S) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m7S) + \"\\n\";\n                            }\n\n                            dropsText = runs +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"1st Master Stars:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"2nd Master Stars:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"3rd Master Stars:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"4th Master Stars:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"5th Master Stars:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Necron Dyes:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Dark Claymores:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Rerolls:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = runsCount +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulators) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooks) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.firstStars) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.secondStars) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.thirdStars) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fourthStars) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fifthStars) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.necronDyes) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.darkClaymores) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(CatacombsTracker.masterRerolls) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.masterCoinsSpent) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.masterTimeSpent);\n                        } else {\n                            if (masterSRunsDisplay) {\n                                runs = EnumChatFormatting.GOLD + \"Master One S+:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Two S+:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Three S+:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Four S+:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Five S+:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Six S+:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Seven S+:\\n\";\n                                runsCount = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m1SPlusSession) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m2SPlusSession) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m3SPlusSession) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m4SPlusSession) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m5SPlusSession) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m6SPlusSession) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m7SPlusSession) + \"\\n\";\n                            } else {\n                                runs = EnumChatFormatting.GOLD + \"Master One S:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Two S:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Three S:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Four S:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Five S:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Six S:\\n\" +\n                                        EnumChatFormatting.GOLD + \"Master Seven S:\\n\";\n                                runsCount = EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m1SSession) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m2SSession) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m3SSession) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m4SSession) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m5SSession) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m6SSession) + \"\\n\" +\n                                        EnumChatFormatting.GOLD + nf.format(CatacombsTracker.m7SSession) + \"\\n\";\n                            }\n\n                            dropsText = runs +\n                                    EnumChatFormatting.GOLD + \"Recombobulators:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Fuming Potato Books:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"1st Master Stars:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"2nd Master Stars:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"3rd Master Stars:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"4th Master Stars:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"5th Master Stars:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Necron Dyes:\\n\" +\n                                    EnumChatFormatting.GOLD + \"Dark Claymores:\\n\" +\n                                    EnumChatFormatting.WHITE + \"Rerolls:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Coins Spent:\\n\" +\n                                    EnumChatFormatting.AQUA + \"Time Spent:\";\n                            countText = runsCount +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.recombobulatorsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fumingPotatoBooksSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.firstStarsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.secondStarsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.thirdStarsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fourthStarsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(CatacombsTracker.fifthStarsSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.necronDyesSession) + \"\\n\" +\n                                    EnumChatFormatting.GOLD + nf.format(CatacombsTracker.darkClaymoresSession) + \"\\n\" +\n                                    EnumChatFormatting.WHITE + nf.format(CatacombsTracker.masterRerollsSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getMoneySpent(CatacombsTracker.masterCoinsSpentSession) + \"\\n\" +\n                                    EnumChatFormatting.AQUA + Utils.getTimeBetween(0, CatacombsTracker.masterTimeSpentSession);\n                        }\n                        break;\n                    case \"Ghost\":\n                        if (!sessionDisplay) {\n                            dropsText = EnumChatFormatting.GOLD + \"Bags of Cash:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Sorrows:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Ghosty Boots:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Voltas:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Plasmas:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(GhostTracker.bagOfCashSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(GhostTracker.sorrowSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(GhostTracker.ghostlyBootsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(GhostTracker.voltaSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(GhostTracker.plasmaSession);\n                        } else {\n                            dropsText = EnumChatFormatting.GOLD + \"Bags of Cash:\\n\" +\n                                    EnumChatFormatting.BLUE + \"Sorrows:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Ghosty Boots:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Voltas:\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + \"Plasmas:\";\n                            countText = EnumChatFormatting.GOLD + nf.format(GhostTracker.bagOfCashSession) + \"\\n\" +\n                                    EnumChatFormatting.BLUE + nf.format(GhostTracker.sorrowSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(GhostTracker.ghostlyBootsSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(GhostTracker.voltaSession) + \"\\n\" +\n                                    EnumChatFormatting.DARK_PURPLE + nf.format(GhostTracker.plasmaSession);\n                        }\n                        break;\n                }\n                TextRenderer.drawHUDText(dropsText, x, y, scale);\n                TextRenderer.drawHUDText(countText, (int) (x + (110 * scale)), y, scale);\n            }\n        }\n    }\n\n    // just use example dimensions itll be fine\n    @Override\n    protected float getWidth(float scale, boolean example) {\n        return (RenderUtils.getWidthFromText(exampleNums) + 110 * scale) * scale;\n    }\n\n    @Override\n    protected float getHeight(float scale, boolean example) {\n        return RenderUtils.getHeightFromText(exampleNums) * scale;\n    }\n\n}"
  },
  {
    "path": "src/main/java/me/Danker/features/loot/LootTracker.java",
    "content": "package me.Danker.features.loot;\n\nimport me.Danker.config.CfgConfig;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.PacketReadEvent;\nimport me.Danker.events.SlayerLootDropEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.network.play.server.S29PacketSoundEffect;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.common.MinecraftForge;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.ConcurrentModificationException;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class LootTracker {\n\n    public static long itemsChecked = 0;\n    // RARE DROP! (61x Twilight Arrow Poison) (+140% Magic Find!)\n    // VERY RARE DROP!  (19x Nether Wart Distillate) (+160% Magic Find!)\n    static Pattern twentyPattern = Pattern.compile(\"(VERY )?RARE DROP!  ?\\\\((?<amount>\\\\d+)x (?<drop>.+?)\\\\).*\");\n    // CRAZY RARE DROP!  (Judgement Core) (+203% Magic Find!)\n    static Pattern dropPattern = Pattern.compile(\"(((VERY|CRAZY) )?RARE|INSANE) DROP!  ?\\\\((?<drop>.+?)\\\\).*\");\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.type == 2) return;\n\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (message.contains(\":\")) return;\n\n        Matcher twentyMatcher = twentyPattern.matcher(message);\n        if (twentyMatcher.matches()) {\n            MinecraftForge.EVENT_BUS.post(new SlayerLootDropEvent(twentyMatcher.group(\"drop\"), Integer.parseInt(twentyMatcher.group(\"amount\"))));\n        } else {\n            Matcher dropMatcher = dropPattern.matcher(message);\n            if (dropMatcher.matches()) {\n                MinecraftForge.EVENT_BUS.post(new SlayerLootDropEvent(dropMatcher.group(\"drop\"), 1));\n            }\n        }\n    }\n\n    // slayer token drops\n    @SubscribeEvent\n    public void onPacketRead(PacketReadEvent event) {\n        if (!Utils.inSkyblock) return;\n\n        if (event.packet instanceof S29PacketSoundEffect) {\n            S29PacketSoundEffect packet = (S29PacketSoundEffect) event.packet;\n\n            if (packet.getSoundName().equals(\"note.pling\")) {\n                if (System.currentTimeMillis() / 1000 - itemsChecked < 3) return;\n\n                if (Utils.isInScoreboard(\"Boss slain!\") || Utils.isInScoreboard(\"Slay the boss!\")) {\n                    try {\n                        int itemTeeth = Utils.getItems(\"Wolf Tooth\");\n                        int itemWebs = Utils.getItems(\"Tarantula Web\");\n                        int itemRev = Utils.getItems(\"Revenant Flesh\");\n                        int itemNullSphere = Utils.getItems(\"Null Sphere\");\n                        int itemDerelictAshe = Utils.getItems(\"Derelict Ashe\");\n                        int itemCovenSeal = Utils.getItems(\"Coven Seal\");\n\n                        // If no items, are detected, allow check again. Should fix items not being found\n                        if (itemTeeth + itemWebs + itemRev + itemNullSphere + itemDerelictAshe + itemCovenSeal > 0) {\n                            itemsChecked = System.currentTimeMillis() / 1000;\n                            WolfTracker.teeth += itemTeeth;\n                            SpiderTracker.webs += itemWebs;\n                            ZombieTracker.revFlesh += itemRev;\n                            EndermanTracker.nullSpheres += itemNullSphere;\n                            BlazeTracker.derelictAshes += itemDerelictAshe;\n                            VampireTracker.covenSeals += itemCovenSeal;\n\n                            WolfTracker.teethSession += itemTeeth;\n                            SpiderTracker.websSession += itemWebs;\n                            ZombieTracker.revFleshSession += itemRev;\n                            EndermanTracker.nullSpheresSession += itemNullSphere;\n                            BlazeTracker.derelictAshesSession += itemDerelictAshe;\n                            VampireTracker.covenSealsSession += itemCovenSeal;\n\n                            CfgConfig.writeIntConfig(\"wolf\", \"teeth\", WolfTracker.teeth);\n                            CfgConfig.writeIntConfig(\"spider\", \"web\", SpiderTracker.webs);\n                            CfgConfig.writeIntConfig(\"zombie\", \"revFlesh\", ZombieTracker.revFlesh);\n                            CfgConfig.writeIntConfig(\"enderman\", \"nullSpheres\", EndermanTracker.nullSpheres);\n                            CfgConfig.writeIntConfig(\"blaze\", \"derelictAshes\", BlazeTracker.derelictAshes);\n                            CfgConfig.writeIntConfig(\"vampire\", \"covenSeals\", VampireTracker.covenSeals);\n                        }\n                    } catch (ConcurrentModificationException ex) {\n                        Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Error tracking slayer drops.\"));\n                        ex.printStackTrace();\n                    }\n                }\n            }\n        }\n    }\n\n    public static int getAmountfromMessage(String message) {\n        Matcher matcher = dropPattern.matcher(message);\n        if (matcher.find()) {\n            return Integer.parseInt(matcher.group(\"amount\"));\n        }\n        return 1;\n    }\n    \n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/loot/MythologicalTracker.java",
    "content": "package me.Danker.features.loot;\n\nimport me.Danker.config.CfgConfig;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.List;\n\npublic class MythologicalTracker {\n\n    public static double mythCoins;\n    public static int griffinFeathers;\n    public static int crownOfGreeds;\n    public static int washedUpSouvenirs;\n    public static int minosHunters;\n    public static int siameseLynxes;\n    public static int minotaurs;\n    public static int gaiaConstructs;\n    public static int minosChampions;\n    public static int minosInquisitors;\n\n    public static double mythCoinsSession = 0;\n    public static int griffinFeathersSession = 0;\n    public static int crownOfGreedsSession = 0;\n    public static int washedUpSouvenirsSession = 0;\n    public static int minosHuntersSession = 0;\n    public static int siameseLynxesSession = 0;\n    public static int minotaursSession = 0;\n    public static int gaiaConstructsSession = 0;\n    public static int minosChampionsSession = 0;\n    public static int minosInquisitorsSession = 0;\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!Utils.inSkyblock) return;\n        if (event.type == 2) return;\n        if (message.contains(\":\")) return;\n\n        if (message.contains(\"You dug out\")) {\n            if (message.contains(\" coins!\")) {\n                double coinsEarned = Double.parseDouble(message.replaceAll(\"\\\\D\", \"\"));\n                mythCoins += coinsEarned;\n                mythCoinsSession += coinsEarned;\n                CfgConfig.writeDoubleConfig(\"mythological\", \"coins\", mythCoins);\n            } else if (message.contains(\"a Griffin Feather!\")) {\n                griffinFeathers++;\n                griffinFeathersSession++;\n                CfgConfig.writeIntConfig(\"mythological\", \"griffinFeather\", griffinFeathers);\n            } else if (message.contains(\"a Crown of Greed!\")) {\n                crownOfGreeds++;\n                crownOfGreedsSession++;\n                CfgConfig.writeIntConfig(\"mythological\", \"crownOfGreed\", crownOfGreeds);\n            } else if (message.contains(\"a Washed-up Souvenir!\")) {\n                washedUpSouvenirs++;\n                washedUpSouvenirsSession++;\n                CfgConfig.writeIntConfig(\"mythological\", \"washedUpSouvenir\", washedUpSouvenirs);\n            } else if (message.contains(\"a Minos Hunter!\")) {\n                minosHunters++;\n                minosHuntersSession++;\n                CfgConfig.writeIntConfig(\"mythological\", \"minosHunter\", minosHunters);\n            } else if (message.contains(\"Siamese Lynxes!\")) {\n                siameseLynxes++;\n                siameseLynxesSession++;\n                CfgConfig.writeIntConfig(\"mythological\", \"siameseLynx\", siameseLynxes);\n            } else if (message.contains(\"a Minotaur!\")) {\n                minotaurs++;\n                minotaursSession++;\n                CfgConfig.writeIntConfig(\"mythological\", \"minotaur\", minotaurs);\n            } else if (message.contains(\"a Gaia Construct!\")) {\n                gaiaConstructs++;\n                gaiaConstructsSession++;\n                CfgConfig.writeIntConfig(\"mythological\", \"gaiaConstruct\", gaiaConstructs);\n            } else if (message.contains(\"a Minos Champion!\")) {\n                minosChampions++;\n                minosChampionsSession++;\n                CfgConfig.writeIntConfig(\"mythological\", \"minosChampion\", minosChampions);\n            } else if (message.contains(\"a Minos Inquisitor!\")) {\n                minosInquisitors++;\n                minosInquisitorsSession++;\n                CfgConfig.writeIntConfig(\"mythological\", \"minosInquisitor\", minosInquisitors);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/loot/SpiderTracker.java",
    "content": "package me.Danker.features.loot;\n\nimport me.Danker.config.CfgConfig;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.SlayerLootDropEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class SpiderTracker {\n\n    public static int tarantulas;\n    public static int webs;\n    public static int TAP;\n    public static int TAPDrops;\n    public static int bites;\n    public static int catalysts;\n    public static int books;\n    public static int swatters;\n    public static int talismans;\n    public static int mosquitos;\n    public static double time;\n    public static int bosses;\n\n    public static int tarantulasSession = 0;\n    public static int websSession = 0;\n    public static int TAPSession = 0;\n    public static int TAPDropsSession = 0;\n    public static int bitesSession = 0;\n    public static int catalystsSession = 0;\n    public static int booksSession = 0;\n    public static int swattersSession = 0;\n    public static int talismansSession = 0;\n    public static int mosquitosSession = 0;\n    public static double timeSession = -1;\n    public static int bossesSession = -1;\n\n    @SubscribeEvent\n    public void onLootDrop(SlayerLootDropEvent event) {\n        boolean rng = false;\n\n        switch (event.drop) {\n            case \"Toxic Arrow Poison\":\n                TAP += event.amount;\n                TAPSession += event.amount;\n                TAPDrops++;\n                TAPDropsSession++;\n                CfgConfig.writeIntConfig(\"spider\", \"tap\", TAP);\n                CfgConfig.writeIntConfig(\"spider\", \"tapDrops\", TAPDrops);\n                break;\n            case \"◆ Bite Rune I\":\n                bites += event.amount;\n                bitesSession += event.amount;\n                CfgConfig.writeIntConfig(\"spider\", \"bite\", bites);\n                break;\n            case \"Bane of Arthropods VI\":\n                books += event.amount;\n                booksSession += event.amount;\n                CfgConfig.writeIntConfig(\"spider\", \"book\", books);\n                break;\n            case \"Spider Catalyst\":\n                catalysts += event.amount;\n                catalystsSession += event.amount;\n                CfgConfig.writeIntConfig(\"spider\", \"catalyst\", catalysts);\n                break;\n            case \"Fly Swatter\":\n                rng = true;\n                swatters += event.amount;\n                swattersSession += event.amount;\n                CfgConfig.writeIntConfig(\"spider\", \"swatter\", swatters);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.LIGHT_PURPLE + \"FLY SWATTER!\", 3);\n                break;\n            case \"Tarantula Talisman\":\n                rng = true;\n                talismans += event.amount;\n                talismansSession += event.amount;\n                CfgConfig.writeIntConfig(\"spider\", \"talisman\", talismans);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.DARK_PURPLE + \"TARANTULA TALISMAN!\", 3);\n                break;\n            case \"Digested Mosquito\":\n                rng = true;\n                mosquitos += event.amount;\n                mosquitosSession += event.amount;\n                CfgConfig.writeIntConfig(\"spider\", \"mosquito\", mosquitos);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.GOLD + \"DIGESTED MOSQUITO!\", 5);\n                break;\n        }\n\n        if (rng) {\n            time = System.currentTimeMillis() / 1000;\n            bosses = 0;\n            timeSession = System.currentTimeMillis() / 1000;\n            bossesSession = 0;\n            CfgConfig.writeDoubleConfig(\"spider\", \"timeRNG\", time);\n            CfgConfig.writeIntConfig(\"spider\", \"bossRNG\", 0);\n        }\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.type == 2) return;\n\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (message.contains(\":\")) return;\n\n        if (message.contains(\"   Spider Slayer LVL \")) {\n            tarantulas++;\n            tarantulasSession++;\n            if (bosses != -1) {\n                bosses++;\n            }\n            if (bossesSession != -1) {\n                bossesSession++;\n            }\n            CfgConfig.writeIntConfig(\"spider\", \"tarantulas\", tarantulas);\n            CfgConfig.writeIntConfig(\"spider\", \"bossRNG\", bosses);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/loot/TrophyFishTracker.java",
    "content": "package me.Danker.features.loot;\n\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonObject;\nimport me.Danker.events.ModInitEvent;\nimport me.Danker.events.PostConfigInitEvent;\nimport me.Danker.locations.Location;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.init.Items;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class TrophyFishTracker {\n\n    public static JsonObject fish = new JsonObject();\n    public static JsonObject fishSession = new JsonObject();\n    public static Pattern fishPattern = Pattern.compile(\"TROPHY FISH! You caught an? (?<fish>.*) (?<tier>.*).\");\n    public static String configFile;\n\n    public static JsonObject createEmpty() {\n        JsonObject fish = new JsonObject();\n\n        JsonObject tiers = new JsonObject();\n        tiers.addProperty(\"BRONZE\", 0);\n        tiers.addProperty(\"SILVER\", 0);\n        tiers.addProperty(\"GOLD\", 0);\n        tiers.addProperty(\"DIAMOND\", 0);\n\n        fish.add(\"Sulphur Skitter\", Utils.deepCopy(tiers));\n        fish.add(\"Obfuscated 1\", Utils.deepCopy(tiers));\n        fish.add(\"Steaming-Hot Flounder\", Utils.deepCopy(tiers));\n        fish.add(\"Obfuscated 2\", Utils.deepCopy(tiers));\n        fish.add(\"Gusher\", Utils.deepCopy(tiers));\n        fish.add(\"Blobfish\", Utils.deepCopy(tiers));\n        fish.add(\"Slugfish\", Utils.deepCopy(tiers));\n        fish.add(\"Obfuscated 3\", Utils.deepCopy(tiers));\n        fish.add(\"Flyfish\", Utils.deepCopy(tiers));\n        fish.add(\"Lavahorse\", Utils.deepCopy(tiers));\n        fish.add(\"Mana Ray\", Utils.deepCopy(tiers));\n        fish.add(\"Volcanic Stonefish\", Utils.deepCopy(tiers));\n        fish.add(\"Vanille\", Utils.deepCopy(tiers));\n        fish.add(\"Skeleton Fish\", Utils.deepCopy(tiers));\n        fish.add(\"Moldfin\", Utils.deepCopy(tiers));\n        fish.add(\"Soul Fish\", Utils.deepCopy(tiers));\n        fish.add(\"Karate Fish\", Utils.deepCopy(tiers));\n        fish.add(\"Golden Fish\", Utils.deepCopy(tiers));\n\n        return fish;\n    }\n\n    @SubscribeEvent\n    public void init(ModInitEvent event) {\n        configFile = event.configDirectory + \"/dsm/dsmtrophyfish.json\";\n    }\n\n    @SubscribeEvent\n    public void postConfigInit(PostConfigInitEvent event) {\n        if (fish.entrySet().isEmpty() || fish.has(\"Sulpher Skitter\")) fish = createEmpty();\n        if (fishSession.entrySet().isEmpty()) fishSession = createEmpty();\n        save();\n    }\n\n    @SubscribeEvent(receiveCanceled = true)\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!Utils.inSkyblock) return;\n        if (Utils.currentLocation != Location.CRIMSON_ISLE) return;\n        if (event.type == 2) return;\n        if (message.contains(\":\")) return;\n\n        Matcher matcher = fishPattern.matcher(message);\n\n        if (matcher.matches()) {\n            String fishName = matcher.group(\"fish\");\n            String tier = matcher.group(\"tier\");\n\n            JsonObject fishObj = fish.getAsJsonObject(fishName);\n            int amount = fishObj.get(tier).getAsInt();\n            fishObj.addProperty(tier, amount + 1);\n\n            JsonObject fishSessionObj = fishSession.getAsJsonObject(fishName);\n            int amountSession = fishSessionObj.get(tier).getAsInt();\n            fishSessionObj.addProperty(tier, amountSession + 1);\n\n            save();\n        }\n    }\n\n    public static void save() {\n        try (FileWriter writer = new FileWriter(configFile)) {\n            new GsonBuilder().create().toJson(fish, writer);\n            writer.flush();\n        } catch (IOException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    public static String getTierCount(JsonObject obj, String name) {\n        JsonObject type = obj.getAsJsonObject(name);\n\n        int bronze = type.get(\"BRONZE\").getAsInt();\n        int silver = type.get(\"SILVER\").getAsInt();\n        int gold = type.get(\"GOLD\").getAsInt();\n        int diamond = type.get(\"DIAMOND\").getAsInt();\n\n        return EnumChatFormatting.DARK_GRAY + \"\" + bronze + EnumChatFormatting.WHITE + \"-\" +\n               EnumChatFormatting.GRAY + silver + EnumChatFormatting.WHITE + \"-\" +\n               EnumChatFormatting.GOLD + gold + EnumChatFormatting.WHITE + \"-\" +\n               EnumChatFormatting.AQUA + diamond;\n    }\n\n    public static int getSum(JsonObject obj, String name) {\n        JsonObject type = obj.getAsJsonObject(name);\n        return type.get(\"BRONZE\").getAsInt() +\n               type.get(\"SILVER\").getAsInt() +\n               type.get(\"GOLD\").getAsInt() +\n               type.get(\"DIAMOND\").getAsInt();\n    }\n\n    public static void drawCompletion(JsonObject obj, String name, int x, int y, double scale) {\n        JsonObject type = obj.getAsJsonObject(name);\n\n        boolean bronze = type.get(\"BRONZE\").getAsInt() > 0;\n        boolean silver = type.get(\"SILVER\").getAsInt() > 0;\n        boolean gold = type.get(\"GOLD\").getAsInt() > 0;\n        boolean diamond = type.get(\"DIAMOND\").getAsInt() > 0;\n\n        ItemStack incomplete = new ItemStack(Items.dye, 1, 8);\n        ItemStack bronzeComplete = new ItemStack(Items.brick);\n        ItemStack silverComplete = new ItemStack(Items.iron_ingot);\n        ItemStack goldComplete = new ItemStack(Items.gold_ingot);\n        ItemStack diamondComplete = new ItemStack(Items.diamond);\n\n        // -116 hides behind chat + tab\n        RenderUtils.renderItem(bronze ? bronzeComplete : incomplete, x, y - 2, -116, scale / 1.3D);\n        RenderUtils.renderItem(silver ? silverComplete : incomplete, x + 15, y - 2, -116, scale / 1.3D);\n        RenderUtils.renderItem(gold ? goldComplete : incomplete, x + 30, y - 2, -116, scale / 1.3D);\n        RenderUtils.renderItem(diamond ? diamondComplete : incomplete, x + 45, y - 2, -116, scale / 1.3D);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/loot/VampireTracker.java",
    "content": "package me.Danker.features.loot;\n\nimport me.Danker.config.CfgConfig;\nimport me.Danker.events.SlayerLootDropEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class VampireTracker {\n\n    public static int riftstalkers;\n    public static int covenSeals;\n    public static int quantumBundles;\n    public static int bubbaBlisters;\n    public static int soultwistRunes;\n    public static int chocolateChips;\n    public static int luckyBlocks;\n    public static int theOneBundles;\n    public static int mcgrubbersBurgers;\n    public static int vampireParts;\n\n    public static int riftstalkersSession = 0;\n    public static int covenSealsSession = 0;\n    public static int quantumBundlesSession = 0;\n    public static int bubbaBlistersSession = 0;\n    public static int soultwistRunesSession = 0;\n    public static int chocolateChipsSession = 0;\n    public static int luckyBlocksSession = 0;\n    public static int theOneBundlesSession = 0;\n    public static int mcgrubbersBurgersSession = 0;\n    public static int vampirePartsSession = 0;\n\n    @SubscribeEvent\n    public void onLootDrop(SlayerLootDropEvent event) {\n        // no rngs\n        switch (event.drop) {\n            case \"Bubba Blister\":\n                bubbaBlisters += event.amount;\n                bubbaBlistersSession += event.amount;\n                CfgConfig.writeIntConfig(\"vampire\", \"bubbaBlisters\", bubbaBlisters);\n                break;\n            case \"◆ Soultwist Rune I\":\n                soultwistRunes += event.amount;\n                soultwistRunesSession += event.amount;\n                CfgConfig.writeIntConfig(\"vampire\", \"soultwistRunes\", soultwistRunes);\n                break;\n            case \"Fang-tastic Chocolate Chip\":\n                chocolateChips += event.amount;\n                chocolateChipsSession += event.amount;\n                CfgConfig.writeIntConfig(\"vampire\", \"chocolateChips\", chocolateChips);\n                break;\n            case \"Guardian Lucky Block\":\n                luckyBlocks += event.amount;\n                luckyBlocksSession += event.amount;\n                CfgConfig.writeIntConfig(\"vampire\", \"luckyBlocks\", luckyBlocks);\n                break;\n            case \"McGrubber's Burger\":\n                mcgrubbersBurgers += event.amount;\n                mcgrubbersBurgersSession += event.amount;\n                CfgConfig.writeIntConfig(\"vampire\", \"mcgrubbersBurgers\", mcgrubbersBurgers);\n                break;\n            case \"Unfanged Vampire Part\":\n                vampireParts += event.amount;\n                vampirePartsSession += event.amount;\n                CfgConfig.writeIntConfig(\"vampire\", \"vampireParts\", vampireParts);\n                break;\n        }\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.type == 2) return;\n\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (message.contains(\":\")) return;\n\n        if (message.contains(\"   Vampire Slayer LVL \")) {\n            riftstalkers++;\n            riftstalkersSession++;\n            CfgConfig.writeIntConfig(\"vampire\", \"riftstalkers\", riftstalkers);\n        } else if (message.contains(\"(Enchanted Book Bundle)\")) { // special case\n            String formatted = event.message.getFormattedText();\n            if (formatted.contains(EnumChatFormatting.GREEN + \"Enchanted\")) { // quantum\n                quantumBundles++;\n                quantumBundlesSession++;\n                CfgConfig.writeIntConfig(\"vampire\", \"quantumBundles\", quantumBundles);\n            } else if (formatted.contains(EnumChatFormatting.GOLD + \"Enchanted\")) { // the one\n                theOneBundles++;\n                theOneBundlesSession++;\n                CfgConfig.writeIntConfig(\"vampire\", \"theOneBundles\", theOneBundles);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/loot/WolfTracker.java",
    "content": "package me.Danker.features.loot;\n\nimport me.Danker.config.CfgConfig;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.SlayerLootDropEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class WolfTracker {\n\n    public static int svens;\n    public static int teeth;\n    public static int wheels;\n    public static int wheelsDrops;\n    public static int spirits;\n    public static int books;\n    public static int furballs;\n    public static int eggs;\n    public static int coutures;\n    public static int baits;\n    public static int fluxes;\n    public static double time;\n    public static int bosses;\n\n    public static int svensSession = 0;\n    public static int teethSession = 0;\n    public static int wheelsSession = 0;\n    public static int wheelsDropsSession = 0;\n    public static int spiritsSession = 0;\n    public static int booksSession = 0;\n    public static int furballsSession = 0;\n    public static int eggsSession = 0;\n    public static int couturesSession = 0;\n    public static int baitsSession = 0;\n    public static int fluxesSession = 0;\n    public static double timeSession = -1;\n    public static int bossesSession = -1;\n\n\n    @SubscribeEvent\n    public void onLootDrop(SlayerLootDropEvent event) {\n        boolean rng = false;\n\n        switch (event.drop) {\n            case \"Hamster Wheel\":\n                wheels += event.amount;\n                wheelsSession += event.amount;\n                wheelsDrops++;\n                wheelsDropsSession++;\n                CfgConfig.writeIntConfig(\"wolf\", \"wheel\", wheels);\n                CfgConfig.writeIntConfig(\"wolf\", \"wheelDrops\", wheelsDrops);\n                break;\n            case \"◆ Spirit Rune I\":\n                spirits += event.amount;\n                spiritsSession += event.amount;\n                CfgConfig.writeIntConfig(\"wolf\", \"spirit\", spirits);\n                break;\n            case \"Critical VI\":\n                books += event.amount;\n                booksSession += event.amount;\n                CfgConfig.writeIntConfig(\"wolf\", \"book\", books);\n                break;\n            case \"Furball\":\n                furballs += event.amount;\n                furballsSession += event.amount;\n                CfgConfig.writeIntConfig(\"wolf\", \"furball\", furballs);\n                break;\n            case \"Red Claw Egg\":\n                rng = true;\n                eggs += event.amount;\n                eggsSession += event.amount;\n                CfgConfig.writeIntConfig(\"wolf\", \"egg\", eggs);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.DARK_RED + \"RED CLAW EGG!\", 3);\n                break;\n            case \"◆ Couture Rune I\":\n                rng = true;\n                coutures += event.amount;\n                couturesSession += event.amount;\n                CfgConfig.writeIntConfig(\"wolf\", \"couture\", coutures);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.GOLD + \"COUTURE RUNE!\", 3);\n                break;\n            case \"Grizzly Bait\":\n            case \"Rename Me\":\n            case \"Grizzly Salmon\":\n                rng = true;\n                baits += event.amount;\n                baitsSession += event.amount;\n                CfgConfig.writeIntConfig(\"wolf\", \"bait\", baits);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.AQUA + \"GRIZZLY BAIT!\", 3);\n                break;\n            case \"Overflux Capacitor\":\n                rng = true;\n                fluxes += event.amount;\n                fluxesSession += event.amount;\n                CfgConfig.writeIntConfig(\"wolf\", \"flux\", fluxes);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.DARK_PURPLE + \"OVERFLUX CAPACITOR!\", 5);\n                break;\n        }\n\n        if (rng) {\n            time = System.currentTimeMillis() / 1000;\n            bosses = 0;\n            timeSession = System.currentTimeMillis() / 1000;\n            bossesSession = 0;\n            CfgConfig.writeDoubleConfig(\"wolf\", \"timeRNG\", time);\n            CfgConfig.writeIntConfig(\"wolf\", \"bossRNG\", 0);\n        }\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.type == 2) return;\n\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (message.contains(\":\")) return;\n\n        if (message.contains(\"   Wolf Slayer LVL \")) {\n            svens++;\n            svensSession++;\n            if (bosses != -1) {\n                bosses++;\n            }\n            if (bossesSession != -1) {\n                bossesSession++;\n            }\n            CfgConfig.writeIntConfig(\"wolf\", \"svens\", svens);\n            CfgConfig.writeIntConfig(\"wolf\", \"bossRNG\", bosses);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/loot/ZombieTracker.java",
    "content": "package me.Danker.features.loot;\n\nimport me.Danker.config.CfgConfig;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.SlayerLootDropEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class ZombieTracker {\n\n    public static int revs;\n    public static int revFlesh;\n    public static int revViscera;\n    public static int foulFlesh;\n    public static int foulFleshDrops;\n    public static int pestilences;\n    public static int undeadCatas;\n    public static int books;\n    public static int booksT7;\n    public static int beheadeds;\n    public static int revCatas;\n    public static int snakes;\n    public static int scythes;\n    public static int shards;\n    public static int wardenHearts;\n    public static double time;\n    public static int bosses;\n\n    public static int revsSession = 0;\n    public static int revFleshSession = 0;\n    public static int revVisceraSession = 0;\n    public static int foulFleshSession = 0;\n    public static int foulFleshDropsSession = 0;\n    public static int pestilencesSession = 0;\n    public static int undeadCatasSession = 0;\n    public static int booksSession = 0;\n    public static int booksT7Session = 0;\n    public static int beheadedsSession = 0;\n    public static int revCatasSession = 0;\n    public static int snakesSession = 0;\n    public static int scythesSession = 0;\n    public static int shardsSession = 0;\n    public static int wardenHeartsSession = 0;\n    public static double timeSession = -1;\n    public static int bossesSession = -1;\n\n    @SubscribeEvent\n    public void onLootDrop(SlayerLootDropEvent event) {\n        boolean rng = false;\n\n        switch (event.drop) {\n            case \"Revenant Viscera\":\n                revViscera += event.amount;\n                revVisceraSession += event.amount;\n                CfgConfig.writeIntConfig(\"zombie\", \"revViscera\", revViscera);\n                break;\n            case \"Foul Flesh\":\n                foulFlesh += event.amount;\n                foulFleshSession += event.amount;\n                foulFleshDrops++;\n                foulFleshDropsSession++;\n                CfgConfig.writeIntConfig(\"zombie\", \"foulFlesh\", foulFlesh);\n                CfgConfig.writeIntConfig(\"zombie\", \"foulFleshDrops\", foulFleshDrops);\n                break;\n            case \"Revenant Catalyst\":\n                revCatas += event.amount;\n                revCatasSession += event.amount;\n                CfgConfig.writeIntConfig(\"zombie\", \"revCatalyst\", revCatas);\n                break;\n            case \"◆ Pestilence Rune I\":\n                pestilences += event.amount;\n                pestilencesSession += event.amount;\n                CfgConfig.writeIntConfig(\"zombie\", \"pestilence\", pestilences);\n                break;\n            case \"Smite VI\":\n                books += event.amount;\n                booksSession += event.amount;\n                CfgConfig.writeIntConfig(\"zombie\", \"book\", books);\n                break;\n            case \"Smite VII\":\n                booksT7 += event.amount;\n                booksT7Session += event.amount;\n                CfgConfig.writeIntConfig(\"zombie\", \"bookT7\", booksT7);\n                break;\n            case \"Undead Catalyst\":\n                undeadCatas += event.amount;\n                undeadCatasSession += event.amount;\n                CfgConfig.writeIntConfig(\"zombie\", \"undeadCatalyst\", undeadCatas);\n                break;\n            case \"Beheaded Horror\":\n                rng = true;\n                beheadeds += event.amount;\n                beheadedsSession += event.amount;\n                CfgConfig.writeIntConfig(\"zombie\", \"beheaded\", beheadeds);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.DARK_PURPLE + \"BEHEADED HORROR!\", 3);\n                break;\n            case \"◆ Snake Rune I\":\n                rng = true;\n                snakes += event.amount;\n                snakesSession += event.amount;\n                CfgConfig.writeIntConfig(\"zombie\", \"snake\", snakes);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.DARK_GREEN + \"SNAKE RUNE!\", 3);\n                break;\n            case \"Scythe Blade\":\n                rng = true;\n                scythes += event.amount;\n                scythesSession += event.amount;\n                CfgConfig.writeIntConfig(\"zombie\", \"scythe\", scythes);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.GOLD + \"SCYTHE BLADE!\", 5);\n                break;\n            case \"Shard of the Shredded\":\n                rng = true;\n                shards += event.amount;\n                shardsSession += event.amount;\n                CfgConfig.writeIntConfig(\"zombie\", \"shard\", shards);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.RED + \"SHARD OF THE SHREDDED!\", 5);\n                break;\n            case \"WARDEN HEART\":\n                rng = true;\n                wardenHearts += event.amount;\n                wardenHeartsSession += event.amount;\n                CfgConfig.writeIntConfig(\"zombie\", \"heart\", wardenHearts);\n                if (ModConfig.rngesusAlerts) Utils.createTitle(EnumChatFormatting.RED + \"WARDEN HEART!\", 5);\n                break;\n        }\n\n        if (rng) {\n            time = System.currentTimeMillis() / 1000;\n            bosses = 0;\n            timeSession = System.currentTimeMillis() / 1000;\n            bossesSession = 0;\n            CfgConfig.writeDoubleConfig(\"zombie\", \"timeRNG\", time);\n            CfgConfig.writeIntConfig(\"zombie\", \"bossRNG\", 0);\n        }\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.type == 2) return;\n\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (message.contains(\":\")) return;\n\n        if (message.contains(\"   Zombie Slayer LVL \")) {\n            revs++;\n            revsSession++;\n            if (bosses != -1) {\n                bosses++;\n            }\n            if (bossesSession != 1) {\n                bossesSession++;\n            }\n            CfgConfig.writeIntConfig(\"zombie\", \"revs\", revs);\n            CfgConfig.writeIntConfig(\"zombie\", \"bossRNG\", bosses);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/ArrowTerminalSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.PacketWriteEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.entity.item.EntityItemFrame;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.init.Items;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.network.play.client.C02PacketUseEntity;\nimport net.minecraft.util.BlockPos;\nimport net.minecraftforge.event.entity.player.EntityInteractEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class ArrowTerminalSolver {\n\n    @SubscribeEvent\n    public void onEntityInteract(EntityInteractEvent event) {\n        Minecraft mc = Minecraft.getMinecraft();\n        if (mc.thePlayer != event.entityPlayer) return;\n\n        if (ModConfig.itemFrameOnSeaLanterns && Utils.isInDungeons() && event.target instanceof EntityItemFrame) {\n            EntityItemFrame itemFrame = (EntityItemFrame) event.target;\n            ItemStack item = itemFrame.getDisplayedItem();\n            if (item == null || item.getItem() != Items.arrow) return;\n            BlockPos blockPos = Utils.getBlockUnderItemFrame(itemFrame);\n            if (mc.theWorld.getBlockState(blockPos).getBlock() == Blocks.sea_lantern) {\n                event.setCanceled(true);\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onPacket(PacketWriteEvent event) {\n        if (ModConfig.itemFrameOnSeaLanterns && Utils.isInDungeons() && event.packet instanceof C02PacketUseEntity) {\n            Minecraft mc = Minecraft.getMinecraft();\n            C02PacketUseEntity packet = (C02PacketUseEntity) event.packet;\n            Entity entityHit = packet.getEntityFromWorld(mc.theWorld);\n            if (entityHit instanceof EntityItemFrame) {\n                EntityItemFrame itemFrame = (EntityItemFrame) entityHit;\n                ItemStack item = itemFrame.getDisplayedItem();\n                if (item != null && item.getItem() == Items.arrow) {\n                    BlockPos blockPos = Utils.getBlockUnderItemFrame(itemFrame);\n                    if (mc.theWorld.getBlockState(blockPos).getBlock() == Blocks.sea_lantern) {\n                        event.setCanceled(true);\n                    }\n                }\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/BlazeSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.block.Block;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.util.*;\nimport net.minecraft.world.World;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.List;\n\npublic class BlazeSolver {\n\n    static Entity highestBlaze = null;\n    static Entity lowestBlaze = null;\n    static boolean higherToLower = false;\n    static boolean foundChest = false;\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        higherToLower = false;\n        foundChest = false;\n        lowestBlaze = null;\n        highestBlaze = null;\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n        World world = mc.theWorld;\n\n        if (DankersSkyblockMod.tickAmount % 4 == 0) {\n            if (ModConfig.blaze && Utils.isInDungeons() && world != null && player != null) {\n\n                List<Entity> entities = world.getLoadedEntityList();\n                int highestHealth = 0;\n                highestBlaze = null;\n                int lowestHealth = 99999999;\n                lowestBlaze = null;\n\n                for (Entity entity : entities) {\n                    if (entity.getName().contains(\"Blaze\") && entity.getName().contains(\"/\")) {\n                        String blazeName = StringUtils.stripControlCodes(entity.getName());\n                        try {\n                            int health = Utils.parseInt(blazeName.substring(blazeName.indexOf(\"/\") + 1, blazeName.length() - 1));\n                            if (health > highestHealth) {\n                                highestHealth = health;\n                                highestBlaze = entity;\n                            }\n                            if (health < lowestHealth) {\n                                lowestHealth = health;\n                                lowestBlaze = entity;\n                            }\n                        } catch (NumberFormatException ex) {\n                            ex.printStackTrace();\n                        }\n                    }\n                }\n\n                if (!foundChest) {\n                    new Thread(() -> {\n                        Iterable<BlockPos> blocks = BlockPos.getAllInBox(new BlockPos(player.posX - 27, 69, player.posZ - 27), new BlockPos(player.posX + 27, 70, player.posZ + 27));\n                        for (BlockPos blockPos : blocks) {\n                            Block block = world.getBlockState(blockPos).getBlock();\n                            if (block == Blocks.chest && world.getBlockState(blockPos.add(0, 1, 0)).getBlock() == Blocks.iron_bars) {\n                                Block blockbelow = world.getBlockState(blockPos.add(0, -1, 0)).getBlock();\n                                if (blockbelow == Blocks.stone) {\n                                    higherToLower = false;\n                                    foundChest = true;\n                                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Chest located. Sorting from lowest to highest.\"));\n                                } else if (blockbelow == Blocks.air) {\n                                    higherToLower = true;\n                                    foundChest = true;\n                                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.mainColour) + \"Chest located. Sorting from highest to lowest.\"));\n                                } else {\n                                    return;\n                                }\n                            }\n                        }\n                    }).start();\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n        if (ModConfig.blaze && Utils.isInDungeons()) {\n            if (foundChest) {\n                if (lowestBlaze != null && !higherToLower) {\n                    BlockPos stringPos = new BlockPos(lowestBlaze.posX, lowestBlaze.posY + 1, lowestBlaze.posZ);\n                    RenderUtils.draw3DString(stringPos, EnumChatFormatting.BOLD + \"Shoot me!\", ModConfig.lowestBlazeColour.getRGB(), event.partialTicks);\n                    AxisAlignedBB aabb = new AxisAlignedBB(lowestBlaze.posX - 0.5, lowestBlaze.posY - 2, lowestBlaze.posZ - 0.5, lowestBlaze.posX + 0.5, lowestBlaze.posY, lowestBlaze.posZ + 0.5);\n                    RenderUtils.draw3DBox(aabb, ModConfig.lowestBlazeColour.getRGB(), event.partialTicks);\n                }\n                if (highestBlaze != null && higherToLower) {\n                    BlockPos stringPos = new BlockPos(highestBlaze.posX, highestBlaze.posY + 1, highestBlaze.posZ);\n                    RenderUtils.draw3DString(stringPos, EnumChatFormatting.BOLD + \"Shoot me!\", ModConfig.lowestBlazeColour.getRGB(), event.partialTicks);\n                    AxisAlignedBB aabb = new AxisAlignedBB(highestBlaze.posX - 0.5, highestBlaze.posY - 2, highestBlaze.posZ - 0.5, highestBlaze.posX + 0.5, highestBlaze.posY, highestBlaze.posZ + 0.5);\n                    RenderUtils.draw3DBox(aabb, ModConfig.lowestBlazeColour.getRGB(), event.partialTicks);\n                }\n            } else {\n                if (lowestBlaze != null) {\n                    BlockPos stringPos = new BlockPos(lowestBlaze.posX, lowestBlaze.posY + 1, lowestBlaze.posZ);\n                    RenderUtils.draw3DString(stringPos, EnumChatFormatting.BOLD + \"Smallest\", ModConfig.lowestBlazeColour.getRGB(), event.partialTicks);\n                    AxisAlignedBB aabb = new AxisAlignedBB(lowestBlaze.posX - 0.5, lowestBlaze.posY - 2, lowestBlaze.posZ - 0.5, lowestBlaze.posX + 0.5, lowestBlaze.posY, lowestBlaze.posZ + 0.5);\n                    RenderUtils.draw3DBox(aabb, ModConfig.lowestBlazeColour.getRGB(), event.partialTicks);\n                }\n                if (highestBlaze != null) {\n                    BlockPos stringPos = new BlockPos(highestBlaze.posX, highestBlaze.posY + 1, highestBlaze.posZ);\n                    RenderUtils.draw3DString(stringPos, EnumChatFormatting.BOLD + \"Biggest\", ModConfig.highestBlazeColour.getRGB(), event.partialTicks);\n                    AxisAlignedBB aabb = new AxisAlignedBB(highestBlaze.posX - 0.5, highestBlaze.posY - 2, highestBlaze.posZ - 0.5, highestBlaze.posX + 0.5, highestBlaze.posY, highestBlaze.posZ + 0.5);\n                    RenderUtils.draw3DBox(aabb, ModConfig.highestBlazeColour.getRGB(), event.partialTicks);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/BlockWrongTerminalClicks.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ChestSlotClickedEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.item.Item;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport org.lwjgl.input.Keyboard;\n\npublic class BlockWrongTerminalClicks {\n\n    @SubscribeEvent\n    public void onSlotClick(ChestSlotClickedEvent event) {\n        if (ModConfig.blockWrongTerminalClicks && Utils.isInDungeons()) {\n            IInventory inventory = event.inventory;\n            String inventoryName = event.inventoryName;\n            Slot slot = event.slot;\n            ItemStack item = event.item;\n            boolean shouldCancel = false;\n\n            if (item == null) return;\n\n            //most of these are extra but who cares\n\n            switch (inventoryName) {\n                case \"Correct all the panes!\":\n                    shouldCancel = !StringUtils.stripControlCodes(item.getDisplayName()).startsWith(\"Off\");\n                    break;\n                case \"Click in order!\":\n\n                    if (slot.getSlotIndex() > 35) {\n                        break;\n                    }\n\n                    if ((item.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane))) {\n                        shouldCancel = true;\n                        break;\n                    }\n                    if (item.getItemDamage() != 14) {\n                        shouldCancel = true;\n                        break;\n                    }\n                    int needed = ClickInOrderSolver.terminalNumberNeeded[0];\n                    if (needed == 0) break;\n                    shouldCancel = needed != -1 && item.stackSize != needed;\n                    break;\n                case \"Change all to same color!\":\n                    if (SameColourSolver.foundColour) {\n                        shouldCancel = SameColourSolver.getDistance(item.getItemDamage(), SameColourSolver.correctColour) == 0;\n                    }\n                    break;\n                case \"Click the button on time!\":\n                    int correctPos = -1;\n                    for (int i = 0; i <= 50; i++) {\n                        ItemStack stack = inventory.getStackInSlot(i);\n                        if (stack == null || stack.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane)) continue;\n\n                        if (stack.getItemDamage() == 10) {\n                            correctPos = i % 9;\n                        } else if (stack.getItemDamage() == 5 && correctPos != -1) {\n                            shouldCancel = i % 9 != correctPos;\n                            break;\n                        }\n                    }\n                    break;\n            }\n\n            if (!shouldCancel) {\n                if (inventoryName.startsWith(\"What starts with:\")) {\n                    char letter = inventoryName.charAt(inventoryName.indexOf(\"'\") + 1);\n                    shouldCancel = !(StringUtils.stripControlCodes(item.getDisplayName()).charAt(0) == letter);\n                } else if (inventoryName.startsWith(\"Select all the\")) {\n                    if (SelectAllColourSolver.terminalColorNeeded == null) return;\n                    String itemName = StringUtils.stripControlCodes(item.getDisplayName()).toUpperCase();\n                    shouldCancel = !(itemName.contains(SelectAllColourSolver.terminalColorNeeded) ||\n                            (SelectAllColourSolver.terminalColorNeeded.equals(\"SILVER\") && itemName.contains(\"LIGHT GRAY\")) ||\n                            (SelectAllColourSolver.terminalColorNeeded.equals(\"WHITE\") && (itemName.equals(\"WOOL\") || itemName.equals(\"BONE MEAL\"))) ||\n                            (SelectAllColourSolver.terminalColorNeeded.equals(\"BLACK\") && itemName.equals(\"INK SACK\")) ||\n                            (SelectAllColourSolver.terminalColorNeeded.equals(\"BLUE\") && itemName.equals(\"LAPIS LAZULI\")) ||\n                            (SelectAllColourSolver.terminalColorNeeded.equals(\"BROWN\") && itemName.equals(\"COCOA BEAN\")));\n                }\n            }\n\n            event.setCanceled(shouldCancel && !Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) && !Keyboard.isKeyDown(Keyboard.KEY_RCONTROL));\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/BoulderSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.BoulderUtils;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.block.Block;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.util.AxisAlignedBB;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.world.World;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.event.entity.player.PlayerInteractEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class BoulderSolver {\n\n    static boolean prevInBoulderRoom = false;\n    static boolean inBoulderRoom = false;\n    static BlockPos chest = null;\n    static String boulderRoomDirection = null;\n    public static List<int[]> route = new ArrayList<>();\n    static int currentStep = 0;\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        reset();\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n        World world = mc.theWorld;\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            if (ModConfig.boulder && Utils.isInDungeons() && world != null && player != null) {\n                // multi thread block checking\n                new Thread(() -> {\n                    prevInBoulderRoom = inBoulderRoom;\n                    int quartzBlocksFound = 0;\n                    int barriersFound = 0;\n                    BlockPos plusPlusQuartz = null;\n                    BlockPos minusMinusQuartz = null;\n                    Iterable<BlockPos> blocks = BlockPos.getAllInBox(new BlockPos(player.posX - 25, 68, player.posZ - 25), new BlockPos(player.posX + 25, 68, player.posZ + 25));\n                    // Detect boulder room\n                    for (BlockPos blockPos : blocks) {\n                        if (world.getBlockState(blockPos).getBlock() == Blocks.quartz_block) {\n                            quartzBlocksFound++;\n                            if (plusPlusQuartz == null || (blockPos.getX() >= plusPlusQuartz.getX() && blockPos.getZ() >= plusPlusQuartz.getZ())) {\n                                plusPlusQuartz = blockPos;\n                            }\n                            if (minusMinusQuartz == null || (blockPos.getX() <= minusMinusQuartz.getX() && blockPos.getZ() <= minusMinusQuartz.getZ())) {\n                                minusMinusQuartz = blockPos;\n                            }\n                            if (quartzBlocksFound == 8) {\n                                break;\n                            }\n                        } else if (world.getBlockState(blockPos).getBlock() == Blocks.barrier) {\n                            barriersFound++;\n                        }\n                    }\n\n                    if (quartzBlocksFound == 8 && barriersFound >= 350) {\n                        inBoulderRoom = true;\n                        if (!prevInBoulderRoom) {\n                            // Get boulder locations\n                            char[][] board = new char[7][7];\n                            for (int x = plusPlusQuartz.getX() - 1, iterationX = 0; iterationX < 7; x -= 3, iterationX++) {\n                                for (int z = plusPlusQuartz.getZ() - 1, iterationZ = 0; iterationZ < 7; z -= 3, iterationZ++) {\n                                    BlockPos boulderPos = new BlockPos(x, 66, z);\n                                    if (world.getBlockState(boulderPos).getBlock() == Blocks.planks) {\n                                        board[iterationX][iterationZ] = 'X';\n                                    }\n                                }\n                            }\n\n                            // Detect rotation of room\n                            BlockPos northChest = minusMinusQuartz.add(11, -2, -2);\n                            BlockPos eastChest = plusPlusQuartz.add(2, -2, -11);\n                            BlockPos southChest = plusPlusQuartz.add(-11, -2, 2);\n                            BlockPos westChest = minusMinusQuartz.add(-2, -2, 11);\n                            if (world.getBlockState(northChest).getBlock() == Blocks.chest) {\n                                boulderRoomDirection = \"north\";\n                                chest = northChest;\n                                board = BoulderUtils.flipVertically(BoulderUtils.rotateClockwise(board));\n                            } else if (world.getBlockState(eastChest).getBlock() == Blocks.chest) {\n                                boulderRoomDirection = \"east\";\n                                chest = eastChest;\n                                board = BoulderUtils.flipHorizontally(board);\n                            } else if (world.getBlockState(southChest).getBlock() == Blocks.chest) {\n                                boulderRoomDirection = \"south\";\n                                chest = southChest;\n                                board = BoulderUtils.flipHorizontally(BoulderUtils.rotateClockwise(board));\n                            } else if (world.getBlockState(westChest).getBlock() == Blocks.chest) {\n                                boulderRoomDirection = \"west\";\n                                chest = westChest;\n                                board = BoulderUtils.flipVertically(board);\n                            } else {\n                                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Could not determine orientation of boulder room.\"));\n                                return;\n                            }\n                            board = BoulderUtils.removeFirstRow(board);\n                            if (BoulderUtils.hasOpenPath(board)) return;\n\n                            long startTime = System.currentTimeMillis();\n                            reset();\n                            int length = BoulderUtils.findSolution(board, 0, route);\n                            long endTime = System.currentTimeMillis();\n                            System.out.println(\"Time elapsed: \" + (endTime - startTime) + \"ms, \" + BoulderUtils.iterations + \" iterations.\");\n                            if (length == 10) {\n                                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"No solution to puzzle found, most likely puzzle failed.\"));\n                            } else {\n                                System.out.println(\"Solved \" + boulderRoomDirection + \" facing boulder room in \" + length + \" steps. Path:\");\n                                for (int[] block : route) {\n                                    System.out.println(Arrays.toString(block));\n                                }\n                            }\n                        }\n                    } else {\n                        chest = null;\n                        boulderRoomDirection = null;\n                        inBoulderRoom = false;\n                    }\n                }).start();\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n        if (ModConfig.boulder && Utils.isInDungeons() && route.size() > 0 && currentStep < route.size() && chest != null) {\n            int[] currentBlockArray = route.get(currentStep);\n            AxisAlignedBB currentBoulder = BoulderUtils.getBoulder(currentBlockArray[0], currentBlockArray[1], chest, boulderRoomDirection);\n            if (currentBoulder == null) return;\n            RenderUtils.drawFilled3DBox(currentBoulder, ModConfig.boulderColour.getRGB(), true, false, event.partialTicks);\n            char direction;\n            switch (currentBlockArray[2]) {\n                case 1:\n                    direction = 'u';\n                    break;\n                case 2:\n                    direction = 'd';\n                    break;\n                case 3:\n                    direction = 'l';\n                    break;\n                case 4:\n                    direction = 'r';\n                    break;\n                default:\n                    return;\n            }\n            BoulderUtils.drawArrow(currentBoulder, boulderRoomDirection, direction, ModConfig.boulderArrowColour.getRGB(), event.partialTicks);\n        }\n    }\n\n    @SubscribeEvent\n    public void onInteract(PlayerInteractEvent event) {\n        if (Minecraft.getMinecraft().thePlayer != event.entityPlayer || !inBoulderRoom || !ModConfig.boulder) return;\n\n        if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) {\n            Block block = Minecraft.getMinecraft().theWorld.getBlockState(event.pos).getBlock();\n            if (block == Blocks.stone_button) currentStep++;\n        }\n    }\n\n    static void reset() {\n        route.clear();\n        currentStep = 0;\n        BoulderUtils.seenBoardStates.clear();\n        BoulderUtils.iterations = 0;\n        BoulderUtils.fastestSolution = 10;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/ChronomatronSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ChestSlotClickedEvent;\nimport me.Danker.events.GuiChestBackgroundDrawnEvent;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.item.Item;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.GuiOpenEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport org.lwjgl.input.Keyboard;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ChronomatronSolver {\n\n    static int lastChronomatronRound = 0;\n    static List<String> chronomatronPattern = new ArrayList<>();\n    static int chronomatronMouseClicks = 0;\n\n    @SubscribeEvent\n    public void onSlotClick(ChestSlotClickedEvent event) {\n        if (ModConfig.chronomatron && event.inventoryName.startsWith(\"Chronomatron (\")) {\n            IInventory inventory = event.inventory;\n            ItemStack item = event.item;\n\n            if (item == null) {\n                if (event.isCancelable() && !Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) && !Keyboard.isKeyDown(Keyboard.KEY_RCONTROL)) {\n                    event.setCanceled(true);\n                }\n                return;\n            }\n\n            if (inventory.getStackInSlot(49).getDisplayName().startsWith(\"§7Timer: §a\") && (item.getItem() == Item.getItemFromBlock(Blocks.stained_glass) || item.getItem() == Item.getItemFromBlock(Blocks.stained_hardened_clay))) {\n                if (chronomatronPattern.size() > chronomatronMouseClicks && !item.getDisplayName().equals(chronomatronPattern.get(chronomatronMouseClicks))) {\n                    if (event.isCancelable() && !Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) && !Keyboard.isKeyDown(Keyboard.KEY_RCONTROL)) {\n                        event.setCanceled(true);\n                        return;\n                    }\n                }\n                chronomatronMouseClicks++;\n            } else if (inventory.getStackInSlot(49).getDisplayName().startsWith(\"§aRemember the pattern!\")) {\n                if (event.isCancelable()) event.setCanceled(true);\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiRender(GuiChestBackgroundDrawnEvent event) {\n        if (ModConfig.chronomatron && event.displayName.startsWith(\"Chronomatron (\")) {\n            int chestSize = event.chestSize;\n            List<Slot> invSlots = event.slots;\n            if (invSlots.size() > 48 && invSlots.get(49).getStack() != null) {\n                if (invSlots.get(49).getStack().getDisplayName().startsWith(\"§7Timer: §a\") && invSlots.get(4).getStack() != null) {\n                    int round = invSlots.get(4).getStack().stackSize;\n                    int timerSeconds = Integer.parseInt(StringUtils.stripControlCodes(invSlots.get(49).getStack().getDisplayName()).replaceAll(\"\\\\D\", \"\"));\n                    if (round != lastChronomatronRound && timerSeconds == round + 2) {\n                        lastChronomatronRound = round;\n                        for (int i = 10; i <= 43; i++) {\n                            ItemStack stack = invSlots.get(i).getStack();\n                            if (stack == null) continue;\n                            if (stack.getItem() == Item.getItemFromBlock(Blocks.stained_hardened_clay)) {\n                                chronomatronPattern.add(stack.getDisplayName());\n                                break;\n                            }\n                        }\n                    }\n                    if (chronomatronMouseClicks < chronomatronPattern.size()) {\n                        for (int i = 10; i <= 43; i++) {\n                            ItemStack glass = invSlots.get(i).getStack();\n                            if (glass == null) continue;\n\n                            Slot glassSlot = invSlots.get(i);\n\n                                \n                            if (glass.getDisplayName().equals(chronomatronPattern.get(chronomatronMouseClicks))) {\n                                RenderUtils.drawOnSlot(chestSize, glassSlot.xDisplayPosition, glassSlot.yDisplayPosition, ModConfig.chronomatronNextColour.getRGB());\n                            } else if (chronomatronMouseClicks + 1 < chronomatronPattern.size() && glass.getDisplayName().equals(chronomatronPattern.get(chronomatronMouseClicks + 1))) {\n                                RenderUtils.drawOnSlot(chestSize, glassSlot.xDisplayPosition, glassSlot.yDisplayPosition, ModConfig.chronomatronNextToNextColour.getRGB());\n                            }\n                            \n                        }\n                    }\n                } else if (invSlots.get(49).getStack().getDisplayName().equals(\"§aRemember the pattern!\")) {\n                    chronomatronMouseClicks = 0;\n                }\n            }\n            Minecraft mc = Minecraft.getMinecraft();\n            int guiLeft = (UResolution.getScaledWidth() - 176) / 2;\n            TextRenderer.drawText(String.join(\"\\n\", chronomatronPattern), (int) (guiLeft * 0.8), 10, 1);\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiOpen(GuiOpenEvent event) {\n        lastChronomatronRound = 0;\n        chronomatronPattern.clear();\n        chronomatronMouseClicks = 0;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/ClickInOrderSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.GuiChestBackgroundDrawnEvent;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.inventory.ContainerChest;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.item.Item;\nimport net.minecraft.item.ItemStack;\nimport net.minecraftforge.client.event.GuiOpenEvent;\nimport net.minecraftforge.event.entity.player.ItemTooltipEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.List;\n\npublic class ClickInOrderSolver {\n\n    static Slot[] clickInOrderSlots = new Slot[36];\n    static int[] terminalNumberNeeded = new int[4];\n\n    @SubscribeEvent(priority = EventPriority.LOW)\n    public void onTooltipLow(ItemTooltipEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.toolTip == null) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n\n        if (mc.currentScreen instanceof GuiChest) {\n            ContainerChest chest = (ContainerChest) player.openContainer;\n            IInventory inv = chest.getLowerChestInventory();\n            String chestName = inv.getDisplayName().getUnformattedText();\n\n            if (ModConfig.clickInOrder && chestName.equals(\"Click in order!\")) {\n                event.toolTip.clear();\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n        if (mc.currentScreen instanceof GuiChest) {\n            if (player == null) return;\n            ContainerChest chest = (ContainerChest) player.openContainer;\n            List<Slot> invSlots = ((GuiChest) mc.currentScreen).inventorySlots.inventorySlots;\n            String chestName = chest.getLowerChestInventory().getDisplayName().getUnformattedText().trim();\n\n            if (ModConfig.clickInOrder && chestName.equals(\"Click in order!\")) {\n                if (terminalNumberNeeded[0] == 0) terminalNumberNeeded[0] = 15;\n                if (terminalNumberNeeded[2] == 0) terminalNumberNeeded[2] = 15;\n                for (int i = 10; i <= 25; i++) {\n                    if (i == 17 || i == 18) continue;\n                    ItemStack prevStack = invSlots.get(terminalNumberNeeded[1]).getStack();\n                    if (prevStack == null) terminalNumberNeeded[0] = 15;\n                    else if (prevStack.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane))\n                        terminalNumberNeeded[0] = 15;\n                    else if (prevStack.getItemDamage() == 5) terminalNumberNeeded[0] = 15;\n\n                    ItemStack itemStack = invSlots.get(i).getStack();\n                    if (itemStack == null) continue;\n                    if (itemStack.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane)) continue;\n                    if (itemStack.getItemDamage() != 14) continue;\n                    if (itemStack.stackSize < terminalNumberNeeded[0]) {\n                        terminalNumberNeeded[0] = itemStack.stackSize;\n                        terminalNumberNeeded[1] = i;\n                    } else if (itemStack.stackSize == terminalNumberNeeded[0] + 1) {\n                        terminalNumberNeeded[2] = itemStack.stackSize;\n                        terminalNumberNeeded[3] = i;\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiRender(GuiChestBackgroundDrawnEvent event) {\n        if (ModConfig.clickInOrder && event.displayName.equals(\"Click in order!\")) {\n            int chestSize = event.chestSize;\n            List<Slot> invSlots = event.slots;\n            Slot slot = invSlots.get(terminalNumberNeeded[1]);\n            RenderUtils.drawOnSlot(chestSize, slot.xDisplayPosition, slot.yDisplayPosition, ModConfig.clickInOrderNextColour.getRGB());\n            Slot nextSlot = invSlots.get(terminalNumberNeeded[3]);\n            if (nextSlot != slot && nextSlot.getSlotIndex() != 0) {\n                RenderUtils.drawOnSlot(chestSize, nextSlot.xDisplayPosition, nextSlot.yDisplayPosition, ModConfig.clickInOrderNextToNextColour.getRGB());\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiOpen(GuiOpenEvent event) {\n        terminalNumberNeeded = new int[4];\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/CreeperSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.block.Block;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.entity.monster.EntityCreeper;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.util.AxisAlignedBB;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.Vec3;\nimport net.minecraft.world.World;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class CreeperSolver {\n\n    // Among Us colours\n    static final int[] CREEPER_COLOURS = {0x50EF39, 0xC51111, 0x132ED1, 0x117F2D, 0xED54BA, 0xEF7D0D, 0xF5F557, 0xD6E0F0, 0x6B2FBB, 0x39FEDC};\n    static boolean drawCreeperLines = false;\n    static Vec3 creeperLocation = new Vec3(0, 0, 0);\n    static List<Vec3[]> creeperLines = new ArrayList<>();\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        World world = mc.theWorld;\n        EntityPlayerSP player = mc.thePlayer;\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            if (ModConfig.creeper && Utils.isInDungeons() && world != null && player != null) {\n                double x = player.posX;\n                double y = player.posY;\n                double z = player.posZ;\n                // Find creepers nearby\n                AxisAlignedBB creeperScan = new AxisAlignedBB(x - 14, y - 8, z - 13, x + 14, y + 8, z + 13); // 28x16x26 cube\n                List<EntityCreeper> creepers = world.getEntitiesWithinAABB(EntityCreeper.class, creeperScan);\n                // Check if creeper is nearby\n                if (creepers.size() > 0 && !creepers.get(0).isInvisible()) { // Don't show Wither Cloak creepers\n                    EntityCreeper creeper = creepers.get(0);\n                    // Start creeper line drawings\n                    creeperLines.clear();\n                    if (!drawCreeperLines) creeperLocation = new Vec3(creeper.posX, creeper.posY + 1, creeper.posZ);\n                    drawCreeperLines = true;\n                    // Search for nearby sea lanterns and prismarine blocks\n                    BlockPos point1 = new BlockPos(creeper.posX - 14, creeper.posY - 7, creeper.posZ - 13);\n                    BlockPos point2 = new BlockPos(creeper.posX + 14, creeper.posY + 10, creeper.posZ + 13);\n                    Iterable<BlockPos> blocks = BlockPos.getAllInBox(point1, point2);\n                    for (BlockPos blockPos : blocks) {\n                        Block block = world.getBlockState(blockPos).getBlock();\n                        if (block == Blocks.sea_lantern || block == Blocks.prismarine) {\n                            // Connect block to nearest block on opposite side\n                            Vec3 startBlock = new Vec3(blockPos.getX() + 0.5, blockPos.getY() + 0.5, blockPos.getZ() + 0.5);\n                            BlockPos oppositeBlock = Utils.getFirstBlockPosAfterVectors(mc, startBlock, creeperLocation, 10, 20);\n                            BlockPos endBlock = Utils.getNearbyBlock(mc, oppositeBlock, Blocks.sea_lantern, Blocks.prismarine);\n                            if (endBlock != null && startBlock.yCoord > 68 && endBlock.getY() > 68) { // Don't create line underground\n                                // Add to list for drawing\n                                Vec3[] insertArray = {startBlock, new Vec3(endBlock.getX() + 0.5, endBlock.getY() + 0.5, endBlock.getZ() + 0.5)};\n                                creeperLines.add(insertArray);\n                            }\n                        }\n                    }\n                } else {\n                    drawCreeperLines = false;\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n        if (ModConfig.creeper && drawCreeperLines && !creeperLines.isEmpty()) {\n            for (int i = 0; i < creeperLines.size(); i++) {\n                Vec3 pos1 = creeperLines.get(i)[0];\n                Vec3 pos2 = creeperLines.get(i)[1];\n                int colour = CREEPER_COLOURS[i % 10];\n\n                if (ModConfig.creeperLines) RenderUtils.draw3DLine(pos1, pos2, colour, 2, true, event.partialTicks);\n                RenderUtils.drawFilled3DBox(new AxisAlignedBB(pos1.xCoord - 0.51, pos1.yCoord - 0.51, pos1.zCoord - 0.51, pos1.xCoord + 0.51, pos1.yCoord + 0.51, pos1.zCoord + 0.51), colour, true, true, event.partialTicks);\n                RenderUtils.drawFilled3DBox(new AxisAlignedBB(pos2.xCoord - 0.51, pos2.yCoord - 0.51, pos2.zCoord - 0.51, pos2.xCoord + 0.51, pos2.yCoord + 0.51, pos2.zCoord + 0.51), colour, true, true, event.partialTicks);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/IceWalkSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.IceWalkUtils;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.block.Block;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.EnumFacing;\nimport net.minecraft.util.Vec3;\nimport net.minecraft.world.World;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class IceWalkSolver {\n\n    static boolean prevInIceWalkRoom = false;\n    static boolean inIceWalkRoom = false;\n    static BlockPos chest = null;\n    static EnumFacing silverfishRoomDirection = null;\n    static List<IceWalkUtils.Point> threeByThreeRoute = new ArrayList<>();\n    static List<IceWalkUtils.Point> fiveByFiveRoute = new ArrayList<>();\n    static List<IceWalkUtils.Point> sevenBySevenRoute = new ArrayList<>();\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        reset();\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n        World world = mc.theWorld;\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            if (ModConfig.iceWalk && Utils.isInDungeons() && world != null && player != null) {\n                // multi thread block checking\n                new Thread(() -> {\n                    boolean foundRoom = false;\n                    prevInIceWalkRoom = inIceWalkRoom;\n                    Iterable<BlockPos> blocks = BlockPos.getAllInBox(new BlockPos(player.posX - 27, 75, player.posZ - 27), new BlockPos(player.posX + 27, 75, player.posZ + 27));\n                    for (BlockPos blockPos : blocks) {\n                        Block block = world.getBlockState(blockPos).getBlock();\n                        if (block == Blocks.chest) {\n                            char[][] threeByThreeBoard = new char[4][3];\n                            char[][] fiveByFiveBoard = new char[6][5];\n                            char[][] sevenBySevenBoard = new char[8][7];\n\n                            if (world.getBlockState(blockPos.add(0, 7, 2)).getBlock() == Blocks.iron_bars && world.getBlockState(blockPos.add(0, -3, 2)).getBlock() == Blocks.stone_brick_stairs) {\n                                silverfishRoomDirection = EnumFacing.NORTH;\n                            } else if (world.getBlockState(blockPos.add(-2, 7, 0)).getBlock() == Blocks.iron_bars && world.getBlockState(blockPos.add(-2, -3, 0)).getBlock() == Blocks.stone_brick_stairs) {\n                                silverfishRoomDirection = EnumFacing.EAST;\n                            } else if (world.getBlockState(blockPos.add(0, 7, -2)).getBlock() == Blocks.iron_bars && world.getBlockState(blockPos.add(0, -3, -2)).getBlock() == Blocks.stone_brick_stairs) {\n                                silverfishRoomDirection = EnumFacing.SOUTH;\n                            } else if (world.getBlockState(blockPos.add(2, 7, 0)).getBlock() == Blocks.iron_bars && world.getBlockState(blockPos.add(2, -3, 0)).getBlock() == Blocks.stone_brick_stairs) {\n                                silverfishRoomDirection = EnumFacing.WEST;\n                            } else {\n                                return;\n                            }\n\n                            foundRoom = true;\n                            inIceWalkRoom = true;\n                            if (!prevInIceWalkRoom) {\n                                chest = blockPos;\n                                switch (silverfishRoomDirection) {\n                                    case NORTH:\n                                        for (int row = chest.getZ() + 3, xIteration = 0; xIteration < 8; row++, xIteration++) {\n                                            for (int column = chest.getX() - 3, yIteration = 0; yIteration < 7; column++, yIteration++) {\n                                                if (world.getBlockState(new BlockPos(column, 72, row)).getBlock() != Blocks.air) {\n                                                    sevenBySevenBoard[xIteration][yIteration] = 'X';\n                                                }\n                                            }\n                                        }\n                                        for (int row = chest.getZ() + 12, xIteration = 0; xIteration < 6; row++, xIteration++) {\n                                            for (int column = chest.getX() - 2, yIteration = 0; yIteration < 5; column++, yIteration++) {\n                                                if (world.getBlockState(new BlockPos(column, 71, row)).getBlock() != Blocks.air) {\n                                                    fiveByFiveBoard[xIteration][yIteration] = 'X';\n                                                }\n                                            }\n                                        }\n                                        for (int row = chest.getZ() + 19, xIteration = 0; xIteration < 4; row++, xIteration++) {\n                                            for (int column = chest.getX() - 1, yIteration = 0; yIteration < 3; column++, yIteration++) {\n                                                if (world.getBlockState(new BlockPos(column, 70, row)).getBlock() != Blocks.air) {\n                                                    threeByThreeBoard[xIteration][yIteration] = 'X';\n                                                }\n                                            }\n                                        }\n                                        break;\n                                    case EAST:\n                                        for (int row = chest.getX() - 3, xIteration = 0; xIteration < 8; row--, xIteration++) {\n                                            for (int column = chest.getZ() - 3, yIteration = 0; yIteration < 7; column++, yIteration++) {\n                                                if (world.getBlockState(new BlockPos(row, 72, column)).getBlock() != Blocks.air) {\n                                                    sevenBySevenBoard[xIteration][yIteration] = 'X';\n                                                }\n                                            }\n                                        }\n                                        for (int row = chest.getX() - 12, xIteration = 0; xIteration < 6; row--, xIteration++) {\n                                            for (int column = chest.getZ() - 2, yIteration = 0; yIteration < 5; column++, yIteration++) {\n                                                if (world.getBlockState(new BlockPos(row, 71, column)).getBlock() != Blocks.air) {\n                                                    fiveByFiveBoard[xIteration][yIteration] = 'X';\n                                                }\n                                            }\n                                        }\n                                        for (int row = chest.getX() - 19, xIteration = 0; xIteration < 4; row--, xIteration++) {\n                                            for (int column = chest.getZ() - 1, yIteration = 0; yIteration < 3; column++, yIteration++) {\n                                                if (world.getBlockState(new BlockPos(row, 70, column)).getBlock() != Blocks.air) {\n                                                    threeByThreeBoard[xIteration][yIteration] = 'X';\n                                                }\n                                            }\n                                        }\n                                        break;\n                                    case SOUTH:\n                                        for (int row = chest.getZ() - 3, xIteration = 0; xIteration < 8; row--, xIteration++) {\n                                            for (int column = chest.getX() + 3, yIteration = 0; yIteration < 7; column--, yIteration++) {\n                                                if (world.getBlockState(new BlockPos(column, 72, row)).getBlock() != Blocks.air) {\n                                                    sevenBySevenBoard[xIteration][yIteration] = 'X';\n                                                }\n                                            }\n                                        }\n                                        for (int row = chest.getZ() - 12, xIteration = 0; xIteration < 6; row--, xIteration++) {\n                                            for (int column = chest.getX() + 2, yIteration = 0; yIteration < 5; column--, yIteration++) {\n                                                if (world.getBlockState(new BlockPos(column, 71, row)).getBlock() != Blocks.air) {\n                                                    fiveByFiveBoard[xIteration][yIteration] = 'X';\n                                                }\n                                            }\n                                        }\n                                        for (int row = chest.getZ() - 19, xIteration = 0; xIteration < 4; row--, xIteration++) {\n                                            for (int column = chest.getX() + 1, yIteration = 0; yIteration < 3; column--, yIteration++) {\n                                                if (world.getBlockState(new BlockPos(column, 70, row)).getBlock() != Blocks.air) {\n                                                    threeByThreeBoard[xIteration][yIteration] = 'X';\n                                                }\n                                            }\n                                        }\n                                        break;\n                                    case WEST:\n                                        for (int row = chest.getX() + 3, xIteration = 0; xIteration < 8; row++, xIteration++) {\n                                            for (int column = chest.getZ() + 3, yIteration = 0; yIteration < 7; column--, yIteration++) {\n                                                if (world.getBlockState(new BlockPos(row, 72, column)).getBlock() != Blocks.air) {\n                                                    sevenBySevenBoard[xIteration][yIteration] = 'X';\n                                                }\n                                            }\n                                        }\n                                        for (int row = chest.getX() + 12, xIteration = 0; xIteration < 6; row++, xIteration++) {\n                                            for (int column = chest.getZ() + 2, yIteration = 0; yIteration < 5; column--, yIteration++) {\n                                                if (world.getBlockState(new BlockPos(row, 71, column)).getBlock() != Blocks.air) {\n                                                    fiveByFiveBoard[xIteration][yIteration] = 'X';\n                                                }\n                                            }\n                                        }\n                                        for (int row = chest.getX() + 19, xIteration = 0; xIteration < 4; row++, xIteration++) {\n                                            for (int column = chest.getZ() + 1, yIteration = 0; yIteration < 3; column--, yIteration++) {\n                                                if (world.getBlockState(new BlockPos(row, 70, column)).getBlock() != Blocks.air) {\n                                                    threeByThreeBoard[xIteration][yIteration] = 'X';\n                                                }\n                                            }\n                                        }\n                                        break;\n                                }\n                                System.out.println(Arrays.deepToString(threeByThreeBoard));\n                                System.out.println(Arrays.deepToString(fiveByFiveBoard));\n                                System.out.println(Arrays.deepToString(sevenBySevenBoard));\n\n                                threeByThreeRoute = IceWalkUtils.solve(threeByThreeBoard);\n                                fiveByFiveRoute = IceWalkUtils.solve(fiveByFiveBoard);\n                                sevenBySevenRoute = IceWalkUtils.solve(sevenBySevenBoard);\n                            }\n                        }\n                    }\n                    if (!foundRoom) {\n                        inIceWalkRoom = false;\n                        reset();\n                    }\n                }).start();\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n        if (ModConfig.iceWalk && Utils.isInDungeons() && chest != null) {\n            if (threeByThreeRoute != null && threeByThreeRoute.size() > 1) {\n                for (int i = 0; i < threeByThreeRoute.size() - 1; i++) {\n                    Vec3 pos1;\n                    Vec3 pos2;\n                    switch (silverfishRoomDirection) {\n                        case NORTH:\n                            pos1 = new Vec3(chest.getX() - 0.5 + threeByThreeRoute.get(i).column, 70.5, chest.getZ() + 19.5 + threeByThreeRoute.get(i).row);\n                            pos2 = new Vec3(chest.getX() - 0.5 + threeByThreeRoute.get(i + 1).column, 70.5, chest.getZ() + 19.5 + threeByThreeRoute.get(i + 1).row);\n                            break;\n                        case EAST:\n                            pos1 = new Vec3(chest.getX() - 18.5 - threeByThreeRoute.get(i).row, 70.5, chest.getZ() - 0.5 + threeByThreeRoute.get(i).column);\n                            pos2 = new Vec3(chest.getX() - 18.5 - threeByThreeRoute.get(i + 1).row, 70.5, chest.getZ() - 0.5 + threeByThreeRoute.get(i + 1).column);\n                            break;\n                        case SOUTH:\n                            pos1 = new Vec3(chest.getX() + 1.5 - threeByThreeRoute.get(i).column, 70.5, chest.getZ() - 18.5 - threeByThreeRoute.get(i).row);\n                            pos2 = new Vec3(chest.getX() + 1.5 - threeByThreeRoute.get(i + 1).column, 70.5, chest.getZ() - 18.5 - threeByThreeRoute.get(i + 1).row);\n                            break;\n                        case WEST:\n                            pos1 = new Vec3(chest.getX() + 19.5 + threeByThreeRoute.get(i).row, 70.5, chest.getZ() + 1.5 - threeByThreeRoute.get(i).column);\n                            pos2 = new Vec3(chest.getX() + 19.5 + threeByThreeRoute.get(i + 1).row, 70.5, chest.getZ() + 1.5 - threeByThreeRoute.get(i + 1).column);\n                            break;\n                        default:\n                            return;\n                    }\n                    RenderUtils.draw3DLine(pos1, pos2, ModConfig.iceWalkLineColour.getRGB(), 5, true, event.partialTicks);\n                }\n            }\n\n            if (fiveByFiveRoute != null && fiveByFiveRoute.size() > 1) {\n                for (int i = 0; i < fiveByFiveRoute.size() - 1; i++) {\n                    Vec3 pos1;\n                    Vec3 pos2;\n                    switch (silverfishRoomDirection) {\n                        case NORTH:\n                            pos1 = new Vec3(chest.getX() - 1.5 + fiveByFiveRoute.get(i).column, 71.5, chest.getZ() + 12.5 + fiveByFiveRoute.get(i).row);\n                            pos2 = new Vec3(chest.getX() - 1.5 + fiveByFiveRoute.get(i + 1).column, 71.5, chest.getZ() + 12.5 + fiveByFiveRoute.get(i + 1).row);\n                            break;\n                        case EAST:\n                            pos1 = new Vec3(chest.getX() - 11.5 - fiveByFiveRoute.get(i).row, 71.5, chest.getZ() - 1.5 + fiveByFiveRoute.get(i).column);\n                            pos2 = new Vec3(chest.getX() - 11.5 - fiveByFiveRoute.get(i + 1).row, 71.5, chest.getZ() - 1.5 + fiveByFiveRoute.get(i + 1).column);\n                            break;\n                        case SOUTH:\n                            pos1 = new Vec3(chest.getX() + 2.5 - fiveByFiveRoute.get(i).column, 71.5, chest.getZ() - 11.5 - fiveByFiveRoute.get(i).row);\n                            pos2 = new Vec3(chest.getX() + 2.5 - fiveByFiveRoute.get(i + 1).column, 71.5, chest.getZ() - 11.5 - fiveByFiveRoute.get(i + 1).row);\n                            break;\n                        case WEST:\n                            pos1 = new Vec3(chest.getX() + 12.5 + fiveByFiveRoute.get(i).row, 71.5, chest.getZ() + 2.5 - fiveByFiveRoute.get(i).column);\n                            pos2 = new Vec3(chest.getX() + 12.5 + fiveByFiveRoute.get(i + 1).row, 71.5, chest.getZ() + 2.5 - fiveByFiveRoute.get(i + 1).column);\n                            break;\n                        default:\n                            return;\n                    }\n                    RenderUtils.draw3DLine(pos1, pos2, ModConfig.iceWalkLineColour.getRGB(), 5, true, event.partialTicks);\n                }\n            }\n\n            if (sevenBySevenRoute != null && sevenBySevenRoute.size() > 1) {\n                for (int i = 0; i < sevenBySevenRoute.size() - 1; i++) {\n                    Vec3 pos1;\n                    Vec3 pos2;\n                    switch (silverfishRoomDirection) {\n                        case NORTH:\n                            pos1 = new Vec3(chest.getX() - 2.5 + sevenBySevenRoute.get(i).column, 72.5, chest.getZ() + 3.5 + sevenBySevenRoute.get(i).row);\n                            pos2 = new Vec3(chest.getX() - 2.5 + sevenBySevenRoute.get(i + 1).column, 72.5, chest.getZ() + 3.5 + sevenBySevenRoute.get(i + 1).row);\n                            break;\n                        case EAST:\n                            pos1 = new Vec3(chest.getX() - 2.5 - sevenBySevenRoute.get(i).row, 72.5, chest.getZ() - 2.5 + sevenBySevenRoute.get(i).column);\n                            pos2 = new Vec3(chest.getX() - 2.5 - sevenBySevenRoute.get(i + 1).row, 72.5, chest.getZ() - 2.5 + sevenBySevenRoute.get(i + 1).column);\n                            break;\n                        case SOUTH:\n                            pos1 = new Vec3(chest.getX() + 3.5 - sevenBySevenRoute.get(i).column, 72.5, chest.getZ() - 2.5 - sevenBySevenRoute.get(i).row);\n                            pos2 = new Vec3(chest.getX() + 3.5 - sevenBySevenRoute.get(i + 1).column, 72.5, chest.getZ() - 2.5 - sevenBySevenRoute.get(i + 1).row);\n                            break;\n                        case WEST:\n                            pos1 = new Vec3(chest.getX() + 3.5 + sevenBySevenRoute.get(i).row, 72.5, chest.getZ() + 3.5 - sevenBySevenRoute.get(i).column);\n                            pos2 = new Vec3(chest.getX() + 3.5 + sevenBySevenRoute.get(i + 1).row, 72.5, chest.getZ() + 3.5 - sevenBySevenRoute.get(i + 1).column);\n                            break;\n                        default:\n                            return;\n                    }\n                    RenderUtils.draw3DLine(pos1, pos2, ModConfig.iceWalkLineColour.getRGB(), 5, true, event.partialTicks);\n                }\n            }\n        }\n    }\n\n    static void reset() {\n        silverfishRoomDirection = null;\n        chest = null;\n        if (threeByThreeRoute != null) threeByThreeRoute.clear();\n        if (fiveByFiveRoute != null) fiveByFiveRoute.clear();\n        if (sevenBySevenRoute != null) sevenBySevenRoute.clear();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/LividSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport cc.polyfrost.oneconfig.config.annotations.Color;\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.config.core.OneColor;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.ScoreboardHandler;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.locations.DungeonFloor;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.entity.EntityLivingBase;\nimport net.minecraft.entity.item.EntityArmorStand;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.util.AxisAlignedBB;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.world.World;\nimport net.minecraftforge.client.event.RenderLivingEvent;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.List;\n\npublic class LividSolver {\n\n    static BlockPos pos = new BlockPos(5, 108, 25);\n    static Entity livid = null;\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        livid = null;\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n        if (!ModConfig.lividSolverHud.isEnabled()) return;\n\n        if (DankersSkyblockMod.tickAmount % 10 == 0) {\n            World world = Minecraft.getMinecraft().theWorld;\n            if (world == null) return;\n            if (Utils.currentFloor == DungeonFloor.F5 || Utils.currentFloor == DungeonFloor.M5) {\n                List<String> scoreboard = ScoreboardHandler.getSidebarLines();\n                if (scoreboard.size() == 0) return;\n                String firstLine = ScoreboardHandler.cleanSB(scoreboard.get(scoreboard.size() - 1));\n\n                if (firstLine.contains(\"livid\")) {\n                    if (world.getBlockState(pos).getBlock() == Blocks.wool) {\n                        List<Entity> entities = world.getLoadedEntityList();\n                        int colour = world.getBlockState(pos).getBlock().getDamageValue(world, pos);\n                        String find = getTextFromValue(colour);\n\n                        for (Entity entity : entities) {\n                            if (!(entity instanceof EntityArmorStand) || !entity.hasCustomName()) continue;\n                            String name = entity.getCustomNameTag();\n\n                            if (name.contains(find)) {\n                                livid = entity;\n                                return;\n                            }\n                        }\n                        livid = null;\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onRenderEntity(RenderLivingEvent.Pre<EntityLivingBase> event) {\n        if (!ModConfig.lividSolverHud.isEnabled() || livid == null) return;\n\n        Entity entity = event.entity;\n        if (entity instanceof EntityArmorStand && entity.hasCustomName()) {\n            String name = entity.getCustomNameTag();\n            if (!entity.isEntityEqual(livid) && name.contains(\"Livid\")) {\n                event.setCanceled(true);\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n        if (ModConfig.lividSolverHud.isEnabled() && livid != null) {\n            AxisAlignedBB aabb = new AxisAlignedBB(livid.posX - 0.5, livid.posY - 2, livid.posZ - 0.5, livid.posX + 0.5, livid.posY, livid.posZ + 0.5);\n            RenderUtils.draw3DBox(aabb, LividSolverHud.lividColour.getRGB(), event.partialTicks);\n        }\n    }\n\n    static String getTextFromValue(int value) {\n        String colour = \"Failed\";\n        switch (value) {\n            case 0:\n                colour = EnumChatFormatting.WHITE.toString();\n                break;\n            case 2:\n                colour = EnumChatFormatting.LIGHT_PURPLE.toString();\n                break;\n            case 4:\n                colour = EnumChatFormatting.YELLOW.toString();\n                break;\n            case 5:\n                colour = EnumChatFormatting.GREEN.toString();\n                break;\n            case 7:\n                colour = EnumChatFormatting.GRAY.toString();\n                break;\n            case 10:\n                colour = EnumChatFormatting.DARK_PURPLE.toString();\n                break;\n            case 11:\n                colour = EnumChatFormatting.BLUE.toString();\n                break;\n            case 13:\n                colour = EnumChatFormatting.DARK_GREEN.toString();\n                break;\n            case 14:\n                colour = EnumChatFormatting.RED.toString();\n                break;\n        }\n        return colour + EnumChatFormatting.BOLD + \"Livid\";\n    }\n\n    public static class LividSolverHud extends Hud {\n\n        @Exclude\n        String exampleText = EnumChatFormatting.WHITE + \"﴾ Livid \" + EnumChatFormatting.YELLOW + \"6.9M\" + EnumChatFormatting.RED + \"❤ \" + EnumChatFormatting.WHITE + \"﴿\";\n\n        @Color(\n                name = \"Correct Livid Box Color\",\n                category = \"Puzzle Solvers\",\n                subcategory = \"Dungeons\"\n        )\n        public static OneColor lividColour = new OneColor(0, 0, 255);\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            if (example) {\n                TextRenderer.drawHUDText(exampleText, x, y, scale);\n                return;\n            }\n\n            if (ModConfig.lividSolverHud.isEnabled() && livid != null) {\n                TextRenderer.drawHUDText(getText(), x, y, scale);\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return RenderUtils.getWidthFromText(example ? exampleText : getText()) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return RenderUtils.getHeightFromText(example ? exampleText : getText()) * scale;\n        }\n\n        String getText() {\n            if (livid != null) return livid.getName().replace(EnumChatFormatting.BOLD.toString(), \"\");\n            return \"\";\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/SameColourSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.GuiChestBackgroundDrawnEvent;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.inventory.ContainerChest;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.item.Item;\nimport net.minecraft.item.ItemStack;\nimport net.minecraftforge.client.event.GuiOpenEvent;\nimport net.minecraftforge.event.entity.player.ItemTooltipEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\nimport org.apache.commons.lang3.math.NumberUtils;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class SameColourSolver {\n\n    public static boolean foundColour = false;\n    public static int correctColour = 0;\n    static List<Integer> colourLoop = Arrays.asList(14, 1, 4, 13, 11);\n\n    @SubscribeEvent(priority = EventPriority.LOW)\n    public void onTooltipLow(ItemTooltipEvent event) {\n        if (!ModConfig.sameColour || !Utils.isInDungeons()) return;\n        if (event.toolTip == null) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n\n        if (mc.currentScreen instanceof GuiChest) {\n            ContainerChest chest = (ContainerChest) player.openContainer;\n            IInventory inv = chest.getLowerChestInventory();\n            String chestName = inv.getDisplayName().getUnformattedText();\n\n            if (chestName.equals(\"Change all to same color!\")) {\n                event.toolTip.clear();\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n        if (!ModConfig.sameColour || foundColour || !Utils.isInDungeons()) return;\n\n        if (DankersSkyblockMod.tickAmount % 5 == 0) {\n            Minecraft mc = Minecraft.getMinecraft();\n            EntityPlayerSP player = mc.thePlayer;\n            if (mc.currentScreen instanceof GuiChest) {\n                if (player == null) return;\n                ContainerChest chest = (ContainerChest) player.openContainer;\n                List<Slot> invSlots = ((GuiChest) mc.currentScreen).inventorySlots.inventorySlots;\n                String chestName = chest.getLowerChestInventory().getDisplayName().getUnformattedText().trim();\n\n                if (chestName.equals(\"Change all to same color!\")) {\n                    int red = 0;\n                    int orange = 0;\n                    int yellow = 0;\n                    int green = 0;\n                    int blue = 0;\n\n                    for (int i = 12; i <= 32; i++) {\n                        ItemStack stack = invSlots.get(i).getStack();\n                        if (stack == null || stack.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane))\n                            continue;\n                        if (stack.getItemDamage() == 7) continue;\n\n                        switch (stack.getItemDamage()) {\n                            case 1:\n                                orange++;\n                                break;\n                            case 4:\n                                yellow++;\n                                break;\n                            case 11:\n                                blue++;\n                                break;\n                            case 13:\n                                green++;\n                                break;\n                            case 14:\n                                red++;\n                                break;\n                        }\n                    }\n\n                    int max = NumberUtils.max(new int[]{red, orange, yellow, green, blue});\n                    if (max == red) {\n                        correctColour = 14;\n                    } else if (max == orange) {\n                        correctColour = 1;\n                    } else if (max == yellow) {\n                        correctColour = 4;\n                    } else if (max == green) {\n                        correctColour = 13;\n                    } else {\n                        correctColour = 11;\n                    }\n                    foundColour = true;\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiRender(GuiChestBackgroundDrawnEvent event) {\n        if (!ModConfig.sameColour || !foundColour || !Utils.isInDungeons()) return;\n\n        if (event.displayName.equals(\"Change all to same color!\")) {\n            int chestSize = event.chestSize;\n            List<Slot> invSlots = event.slots;\n\n            for (int i = 12; i <= 32; i++) {\n                Slot slot = invSlots.get(i);\n                ItemStack stack = slot.getStack();\n                if (stack == null || stack.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane)) continue;\n                if (stack.getItemDamage() == 7) continue;\n\n                int distance = getDistance(stack.getItemDamage(), correctColour);\n                if (distance == 0) continue;\n\n                RenderUtils.drawTextOnSlot(chestSize, slot.xDisplayPosition, slot.yDisplayPosition, \"\" + distance);\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiOpen(GuiOpenEvent event) {\n        if (!(event.gui instanceof GuiChest)) {\n            foundColour = false;\n            correctColour = 0;\n        }\n    }\n\n    public static int getDistance(int colour, int endColour) {\n        int index = colourLoop.indexOf(colour);\n        int finalIndex = colourLoop.indexOf(endColour);\n        if (index == -1 || finalIndex == -1) return 0;\n\n        if (finalIndex < index) {\n            return finalIndex - index + 5;\n        }\n        return finalIndex - index;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/SelectAllColourSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.GuiChestBackgroundDrawnEvent;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.GuiOpenEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class SelectAllColourSolver {\n\n    static Pattern selectAllTerminalPattern = Pattern.compile(\"[A-Z]{2,}\");\n    static String terminalColorNeeded;\n\n    @SubscribeEvent\n    public void onGuiRender(GuiChestBackgroundDrawnEvent event) {\n        String displayName = event.displayName;\n        if (ModConfig.selectAll && Utils.isInDungeons() && displayName.startsWith(\"Select all the\")) {\n            String colour;\n            List<String> colourParts = new ArrayList<>();\n            Matcher colourMatcher = selectAllTerminalPattern.matcher(displayName);\n            while (colourMatcher.find()) {\n                colourParts.add(colourMatcher.group());\n            }\n            colour = String.join(\" \", colourParts);\n            terminalColorNeeded = colour;\n\n            for (Slot slot : event.slots) {\n                if (slot.inventory == Minecraft.getMinecraft().thePlayer.inventory) continue;\n                ItemStack item = slot.getStack();\n                if (item == null) continue;\n                if (item.isItemEnchanted()) continue;\n                String itemName = StringUtils.stripControlCodes(item.getDisplayName()).toUpperCase();\n                if (itemName.contains(terminalColorNeeded) ||\n                        (terminalColorNeeded.equals(\"SILVER\") && itemName.contains(\"LIGHT GRAY\")) ||\n                        (terminalColorNeeded.equals(\"WHITE\") && (itemName.equals(\"WOOL\") || itemName.equals(\"BONE MEAL\"))) ||\n                        (terminalColorNeeded.equals(\"BLACK\") && itemName.equals(\"INK SACK\")) ||\n                        (terminalColorNeeded.equals(\"BLUE\") && itemName.equals(\"LAPIS LAZULI\")) ||\n                        (terminalColorNeeded.equals(\"BROWN\") && itemName.equals(\"COCOA BEAN\"))) {\n                    RenderUtils.drawOnSlot(event.chestSize, slot.xDisplayPosition, slot.yDisplayPosition, ModConfig.selectAllColour.getRGB());\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiOpen(GuiOpenEvent event) {\n        terminalColorNeeded = null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/SilverfishSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.SilverfishUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.block.BlockHopper;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.entity.item.EntityItem;\nimport net.minecraft.entity.monster.EntitySilverfish;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.item.Item;\nimport net.minecraft.tileentity.TileEntity;\nimport net.minecraft.util.AxisAlignedBB;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.EnumFacing;\nimport net.minecraft.util.Vec3;\nimport net.minecraft.world.World;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class SilverfishSolver {\n\n    static boolean prevInSilverfishRoom = false;\n    static boolean inSilverfishRoom = false;\n    static BlockPos chest = null;\n    static EnumFacing silverfishRoomDirection = null;\n    static List<SilverfishUtils.Point> route = new ArrayList<>();\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        reset();\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        World world = mc.theWorld;\n        EntityPlayerSP player = mc.thePlayer;\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            if (ModConfig.silverfish && Utils.isInDungeons() && world != null && player != null) {\n                new Thread(() -> {\n                    boolean foundRoom = false;\n                    prevInSilverfishRoom = inSilverfishRoom;\n                    double x = player.posX;\n                    double z = player.posZ;\n                    // Find creepers nearby\n                    AxisAlignedBB entityScan = new AxisAlignedBB(x - 25, 67, z - 25, x + 25, 68, z + 25); // 50x1x50\n                    List<EntitySilverfish> silverfishes = world.getEntitiesWithinAABB(EntitySilverfish.class, entityScan);\n                    List<EntityItem> items = world.getEntitiesWithinAABB(EntityItem.class, entityScan);\n                    if (silverfishes.size() > 0 && items.size() > 0) {\n                        double silverfishX = silverfishes.get(0).posX;\n                        double silverfishZ = silverfishes.get(0).posZ;\n                        for (EntityItem item : items) {\n                            if (Item.getIdFromItem(item.getEntityItem().getItem()) == 46 && Math.abs(item.posX - silverfishX) < 1 && Math.abs(item.posZ - silverfishZ) < 1) {\n                                Iterable<BlockPos> blocks = BlockPos.getAllInBox(new BlockPos(player.posX - 27, 67, player.posZ - 27), new BlockPos(player.posX + 27, 67, player.posZ + 27));\n                                for (BlockPos blockPos : blocks) {\n                                    if (world.getBlockState(blockPos).getBlock() == Blocks.chest && world.getBlockState(blockPos.add(0, 2, 0)).getBlock() == Blocks.hopper) {\n                                        foundRoom = true;\n                                        inSilverfishRoom = true;\n                                        if (!prevInSilverfishRoom) {\n                                            chest = blockPos;\n                                            BlockPos silverfishBlock = new BlockPos(silverfishX, 67, silverfishZ);\n                                            TileEntity hopper = world.getTileEntity(blockPos.add(0, 2, 0));\n                                            silverfishRoomDirection = BlockHopper.getFacing(hopper.getBlockMetadata());\n                                            char[][] board = new char[19][19];\n                                            SilverfishUtils.Point silverfishPoint = null;\n\n                                            switch (silverfishRoomDirection) {\n                                                case NORTH:\n                                                    for (int row = chest.getZ() + 3, xIteration = 0; xIteration < 19; row++, xIteration++) {\n                                                        for (int column = chest.getX() - 9, yIteration = 0; yIteration < 19; column++, yIteration++) {\n                                                            if (world.getBlockState(new BlockPos(column, 67, row)).getBlock() != Blocks.air) {\n                                                                board[xIteration][yIteration] = 'X';\n                                                            } else if (silverfishBlock.equals(new BlockPos(column, 67, row))) {\n                                                                silverfishPoint = new SilverfishUtils.Point(xIteration, yIteration);\n                                                            }\n                                                        }\n                                                    }\n                                                    break;\n                                                case EAST:\n                                                    for (int row = chest.getX() - 3, xIteration = 0; xIteration < 19; row--, xIteration++) {\n                                                        for (int column = chest.getZ() - 9, yIteration = 0; yIteration < 19; column++, yIteration++) {\n                                                            if (world.getBlockState(new BlockPos(row, 67, column)).getBlock() != Blocks.air) {\n                                                                board[xIteration][yIteration] = 'X';\n                                                            } else if (silverfishBlock.equals(new BlockPos(row, 67, column))) {\n                                                                silverfishPoint = new SilverfishUtils.Point(xIteration, yIteration);\n                                                            }\n                                                        }\n                                                    }\n                                                    break;\n                                                case SOUTH:\n                                                    for (int row = chest.getZ() - 3, xIteration = 0; xIteration < 19; row--, xIteration++) {\n                                                        for (int column = chest.getX() + 9, yIteration = 0; yIteration < 19; column--, yIteration++) {\n                                                            if (world.getBlockState(new BlockPos(column, 67, row)).getBlock() != Blocks.air) {\n                                                                board[xIteration][yIteration] = 'X';\n                                                            } else if (silverfishBlock.equals(new BlockPos(column, 67, row))) {\n                                                                silverfishPoint = new SilverfishUtils.Point(xIteration, yIteration);\n                                                            }\n                                                        }\n                                                    }\n                                                    break;\n                                                case WEST:\n                                                    for (int row = chest.getX() + 3, xIteration = 0; xIteration < 19; row++, xIteration++) {\n                                                        for (int column = chest.getZ() + 9, yIteration = 0; yIteration < 19; column--, yIteration++) {\n                                                            if (world.getBlockState(new BlockPos(row, 67, column)).getBlock() != Blocks.air) {\n                                                                board[xIteration][yIteration] = 'X';\n                                                            } else if (silverfishBlock.equals(new BlockPos(row, 67, column))) {\n                                                                board[xIteration][yIteration] = 'S';\n                                                                silverfishPoint = new SilverfishUtils.Point(xIteration, yIteration);\n                                                            }\n                                                        }\n                                                    }\n                                                    break;\n                                                default:\n                                                    return;\n                                            }\n                                            System.out.println(Arrays.deepToString(board));\n\n                                            List<SilverfishUtils.Point> endPoints = new ArrayList<>();\n                                            for (int column = 0; column < 19; column++) {\n                                                if (board[0][column] != 'X') endPoints.add(new SilverfishUtils.Point(0, column));\n                                            }\n\n                                            route = SilverfishUtils.solve(board, silverfishPoint, endPoints);\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                    }\n                    if (!foundRoom) reset();\n                }).start();\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n        if (ModConfig.silverfish && Utils.isInDungeons() && route != null && route.size() > 0 && chest != null) {\n            for (int i = 0; i < route.size() - 1; i++) {\n                Vec3 pos1 = null;\n                Vec3 pos2 = null;\n                switch (silverfishRoomDirection) {\n                    case NORTH:\n                        pos1 = new Vec3(chest.getX() - 8.5 + route.get(i).column, 67.5, chest.getZ() + 3.5 + route.get(i).row);\n                        pos2 = new Vec3(chest.getX() - 8.5 + route.get(i + 1).column, 67.5, chest.getZ() + 3.5 + route.get(i + 1).row);\n                        break;\n                    case EAST:\n                        pos1 = new Vec3(chest.getX() - 2.5 - route.get(i).row, 67.5, chest.getZ() - 8.5 + route.get(i).column);\n                        pos2 = new Vec3(chest.getX() - 2.5 - route.get(i + 1).row, 67.5, chest.getZ() - 8.5 + route.get(i + 1).column);\n                        break;\n                    case SOUTH:\n                        pos1 = new Vec3(chest.getX() + 9.5 - route.get(i).column, 67.5, chest.getZ() - 2.5 - route.get(i).row);\n                        pos2 = new Vec3(chest.getX() + 9.5 - route.get(i + 1).column, 67.5, chest.getZ() - 2.5 - route.get(i + 1).row);\n                        break;\n                    case WEST:\n                        pos1 = new Vec3(chest.getX() + 3.5 + route.get(i).row, 67.5, chest.getZ() + 9.5 - route.get(i).column);\n                        pos2 = new Vec3(chest.getX() + 3.5 + route.get(i + 1).row, 67.5, chest.getZ() + 9.5 - route.get(i + 1).column);\n                        break;\n                    default:\n                        return;\n                }\n                RenderUtils.draw3DLine(pos1, pos2, ModConfig.silverfishLineColour.getRGB(), 5, true, event.partialTicks);\n            }\n        }\n    }\n\n    static void reset() {\n        inSilverfishRoom = false;\n        chest = null;\n        silverfishRoomDirection = null;\n        route.clear();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/StartsWithSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.GuiChestBackgroundDrawnEvent;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\npublic class StartsWithSolver {\n\n    @SubscribeEvent\n    public void onGuiRender(GuiChestBackgroundDrawnEvent event) {\n        String displayName = event.displayName;\n        if (ModConfig.startsWith && Utils.isInDungeons() && displayName.startsWith(\"What starts with:\")) {\n            char letter = displayName.charAt(displayName.indexOf(\"'\") + 1);\n            for (Slot slot : event.slots) {\n                if (slot.inventory == Minecraft.getMinecraft().thePlayer.inventory) continue;\n                ItemStack item = slot.getStack();\n                if (item == null) continue;\n                if (item.isItemEnchanted()) continue;\n                if (StringUtils.stripControlCodes(item.getDisplayName()).charAt(0) == letter) {\n                    RenderUtils.drawOnSlot(event.chestSize, slot.xDisplayPosition, slot.yDisplayPosition, ModConfig.startsWithColour.getRGB());\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/SuperpairsSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.GuiChestBackgroundDrawnEvent;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.inventory.ContainerChest;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.item.Item;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.GuiOpenEvent;\nimport net.minecraftforge.event.entity.player.ItemTooltipEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.awt.*;\nimport java.util.List;\nimport java.util.*;\n\npublic class SuperpairsSolver {\n\n    static ItemStack[] experimentTableSlots = new ItemStack[54];\n\n    @SubscribeEvent(priority = EventPriority.HIGHEST)\n    public void onTooltip(ItemTooltipEvent event) {\n        if (!Utils.inSkyblock) return;\n        if (event.toolTip == null) return;\n\n        ItemStack item = event.itemStack;\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n\n        if (mc.currentScreen instanceof GuiChest) {\n            ContainerChest chest = (ContainerChest) player.openContainer;\n            IInventory inv = chest.getLowerChestInventory();\n            String chestName = inv.getDisplayName().getUnformattedText();\n\n            if (ModConfig.superpairs && chestName.contains(\"Superpairs (\")) {\n                if (Item.getIdFromItem(item.getItem()) != 95) return;\n                if (item.getDisplayName().contains(\"Click any button\") || item.getDisplayName().contains(\"Click a second button\") || item.getDisplayName().contains(\"Next button is instantly rewarded\") || item.getDisplayName().contains(\"Stained Glass\")) {\n                    Slot slot = ((GuiChest) mc.currentScreen).getSlotUnderMouse();\n                    if (slot == null) return;\n                    ItemStack itemStack = experimentTableSlots[slot.getSlotIndex()];\n                    if (itemStack == null) return;\n                    String itemName = itemStack.getDisplayName();\n\n                    if (event.toolTip.stream().anyMatch(x -> StringUtils.stripControlCodes(x).equals(StringUtils.stripControlCodes(itemName))))\n                        return;\n                    event.toolTip.removeIf(x -> {\n                        x = StringUtils.stripControlCodes(x);\n                        if (x.equals(\"minecraft:stained_glass\")) return true;\n                        return x.startsWith(\"NBT: \");\n                    });\n                    event.toolTip.add(itemName);\n                    event.toolTip.add(itemStack.getItem().getRegistryName());\n                }\n\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n        if (mc.currentScreen instanceof GuiChest) {\n            if (player == null) return;\n            ContainerChest chest = (ContainerChest) player.openContainer;\n            List<Slot> invSlots = ((GuiChest) mc.currentScreen).inventorySlots.inventorySlots;\n            String chestName = chest.getLowerChestInventory().getDisplayName().getUnformattedText().trim();\n\n            if (ModConfig.superpairs && chestName.startsWith(\"Superpairs (\")) {\n                for (int i = 0; i < 53; i++) {\n                    ItemStack itemStack = invSlots.get(i).getStack();\n                    if (itemStack == null) continue;\n                    String itemName = itemStack.getDisplayName();\n                    if (Item.getIdFromItem(itemStack.getItem()) == 95 || Item.getIdFromItem(itemStack.getItem()) == 160) continue;\n                    if (itemName.contains(\"Instant Find\") || itemName.contains(\"Gained +\")) continue;\n                    if (itemName.contains(\"Enchanted Book\")) {\n                        itemName = itemStack.getTooltip(mc.thePlayer, false).get(3);\n                    }\n                    if (itemStack.stackSize > 1) {\n                        itemName = itemStack.stackSize + \" \" + itemName;\n                    }\n                    if (experimentTableSlots[i] != null) continue;\n                    experimentTableSlots[i] = itemStack.copy().setStackDisplayName(itemName);\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiRender(GuiChestBackgroundDrawnEvent event) {\n        if (ModConfig.superpairs && event.displayName.contains(\"Superpairs (\")) {\n            HashMap<String, HashSet<Integer>> matches = new HashMap<>();\n            for (int i = 0; i < 53; i++) {\n                ItemStack itemStack = experimentTableSlots[i];\n                if (itemStack == null) continue;\n\n                //Utils.renderItem(itemStack, x, y, -100);\n\n                String itemName = itemStack.getDisplayName();\n                String keyName = itemName + itemStack.getUnlocalizedName();\n                matches.computeIfAbsent(keyName, k -> new HashSet<>());\n                matches.get(keyName).add(i);\n            }\n\n            Color[] colors = {\n                    new Color(255, 0, 0, 100),\n                    new Color(0, 0, 255, 100),\n                    new Color(100, 179, 113, 100),\n                    new Color(255, 114, 255, 100),\n                    new Color(255, 199, 87, 100),\n                    new Color(119, 105, 198, 100),\n                    new Color(135, 199, 112, 100),\n                    new Color(240, 37, 240, 100),\n                    new Color(178, 132, 190, 100),\n                    new Color(63, 135, 163, 100),\n                    new Color(146, 74, 10, 100),\n                    new Color(255, 255, 255, 100),\n                    new Color(217, 252, 140, 100),\n                    new Color(255, 82, 82, 100)\n            };\n\n            Iterator<Color> colorIterator = Arrays.stream(colors).iterator();\n\n            matches.forEach((itemName, slotSet) -> {\n                if (slotSet.size() < 2) return;\n                ArrayList<Slot> slots = new ArrayList<>();\n                slotSet.forEach(slotNum -> slots.add(event.slots.get(slotNum)));\n                Color color = colorIterator.next();\n                slots.forEach(slot -> RenderUtils.drawOnSlot(event.chestSize, slot.xDisplayPosition, slot.yDisplayPosition, color.getRGB()));\n            });\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiOpen(GuiOpenEvent event) {\n        experimentTableSlots = new ItemStack[54];\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/TeleportPadSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.DankersSkyblockMod;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.world.World;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class TeleportPadSolver {\n\n    static List<BlockPos> usedPads = new ArrayList<>();\n    static BlockPos finalPad = null;\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        usedPads.clear();\n        finalPad = null;\n    }\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n        World world = mc.theWorld;\n\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/ThreeManSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport com.google.gson.JsonArray;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.util.*;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.event.world.WorldEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.List;\n\npublic class ThreeManSolver {\n\n    // Hard coded solutions if api call fails\n    static String[] riddleSolutions = {\"The reward is not in my chest!\", \"At least one of them is lying, and the reward is not in\",\n            \"My chest doesn't have the reward. We are all telling the truth\", \"My chest has the reward and I'm telling the truth\",\n            \"The reward isn't in any of our chests\", \"Both of them are telling the truth.\"};\n    static BlockPos riddleChest = null;\n\n    @SubscribeEvent\n    public void onWorldChange(WorldEvent.Load event) {\n        riddleChest = null;\n    }\n\n    @SubscribeEvent\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!Utils.isInDungeons()) return;\n\n        if (ModConfig.threeMan && message.startsWith(\"[NPC]\")) {\n            if (DankersSkyblockMod.data != null && DankersSkyblockMod.data.has(\"threeman\")) {\n                JsonArray riddleSolutions = DankersSkyblockMod.data.getAsJsonArray(\"threeman\");\n\n                for (int i = 0; i < riddleSolutions.size(); i++) {\n                    String solution = riddleSolutions.get(i).getAsString();\n                    if (message.contains(solution)) {\n                        answer(message);\n                        break;\n                    }\n                }\n            } else {\n                for (String solution : riddleSolutions) {\n                    if (message.contains(solution)) {\n                        answer(message);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n        if (ModConfig.threeMan && riddleChest != null) {\n            RenderUtils.drawFilled3DBox(new AxisAlignedBB(riddleChest.getX() - 0.05, riddleChest.getY(), riddleChest.getZ() - 0.05, riddleChest.getX() + 1.05, riddleChest.getY() + 1, riddleChest.getZ() + 1.05), 0x197F19, true, true, event.partialTicks);\n        }\n    }\n\n    public static void answer(String message) {\n        Minecraft mc = Minecraft.getMinecraft();\n        String npcName = message.substring(message.indexOf(\"]\") + 2, message.indexOf(\":\"));\n        mc.thePlayer.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.threeManAnswerColour) + EnumChatFormatting.BOLD + StringUtils.stripControlCodes(npcName) + ModConfig.getColour(ModConfig.mainColour) + \" has the blessing.\"));\n\n        if (riddleChest == null) {\n            List<Entity> entities = mc.theWorld.getLoadedEntityList();\n            for (Entity entity : entities) {\n                if (entity == null || !entity.hasCustomName()) continue;\n                if (entity.getCustomNameTag().contains(npcName)) {\n                    BlockPos npcLocation = new BlockPos(entity.posX, 69, entity.posZ);\n                    if (mc.theWorld.getBlockState(npcLocation.north()).getBlock() == Blocks.chest) {\n                        riddleChest = npcLocation.north();\n                    } else if (mc.theWorld.getBlockState(npcLocation.east()).getBlock() == Blocks.chest) {\n                        riddleChest = npcLocation.east();\n                    } else if (mc.theWorld.getBlockState(npcLocation.south()).getBlock() == Blocks.chest) {\n                        riddleChest = npcLocation.south();\n                    } else if (mc.theWorld.getBlockState(npcLocation.west()).getBlock() == Blocks.chest) {\n                        riddleChest = npcLocation.west();\n                    } else {\n                        System.out.print(\"Could not find correct riddle chest.\");\n                    }\n                    break;\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/TicTacToeSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.TicTacToeUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.block.Block;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.entity.item.EntityItemFrame;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.item.ItemMap;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.AxisAlignedBB;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.EnumFacing;\nimport net.minecraft.world.World;\nimport net.minecraft.world.storage.MapData;\nimport net.minecraftforge.client.event.RenderWorldLastEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class TicTacToeSolver {\n\n    static AxisAlignedBB correctTicTacToeButton = null;\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        World world = mc.theWorld;\n        EntityPlayerSP player = mc.thePlayer;\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            if (ModConfig.ticTacToe && Utils.isInDungeons() && world != null && player != null) {\n                correctTicTacToeButton = null;\n                AxisAlignedBB aabb = new AxisAlignedBB(player.posX - 6, player.posY - 6, player.posZ - 6, player.posX + 6, player.posY + 6, player.posZ + 6);\n                List<EntityItemFrame> itemFrames = world.getEntitiesWithinAABB(EntityItemFrame.class, aabb);\n                List<EntityItemFrame> itemFramesWithMaps = new ArrayList<>();\n                // Find how many item frames have maps already placed\n                for (EntityItemFrame itemFrame : itemFrames) {\n                    ItemStack item = itemFrame.getDisplayedItem();\n                    if (item == null || !(item.getItem() instanceof ItemMap)) continue;\n                    MapData mapData = ((ItemMap) item.getItem()).getMapData(item, world);\n                    if (mapData == null) continue;\n\n                    itemFramesWithMaps.add(itemFrame);\n                }\n\n                // Only run when it's your turn\n                if (itemFramesWithMaps.size() != 9 && itemFramesWithMaps.size() % 2 == 1) {\n                    char[][] board = new char[3][3];\n                    BlockPos leftmostRow = null;\n                    int sign = 1;\n                    char facing = 'X';\n                    for (EntityItemFrame itemFrame : itemFramesWithMaps) {\n                        ItemStack map = itemFrame.getDisplayedItem();\n                        MapData mapData = ((ItemMap) map.getItem()).getMapData(map, world);\n\n                        // Find position on board\n                        // I mixed up row and column here and I'm too lazy to fix it\n                        int row = 0;\n                        int column;\n                        sign = 1;\n\n                        if (itemFrame.facingDirection == EnumFacing.SOUTH || itemFrame.facingDirection == EnumFacing.WEST) {\n                            sign = -1;\n                        }\n\n                        BlockPos itemFramePos = new BlockPos(itemFrame.posX, Math.floor(itemFrame.posY), itemFrame.posZ);\n                        for (int i = 2; i >= 0; i--) {\n                            int realI = i * sign;\n                            BlockPos blockPos = itemFramePos;\n                            if (itemFrame.posX % 0.5 == 0) {\n                                blockPos = itemFramePos.add(realI, 0, 0);\n                            } else if (itemFrame.posZ % 0.5 == 0) {\n                                blockPos = itemFramePos.add(0, 0, realI);\n                                facing = 'Z';\n                            }\n                            Block block = world.getBlockState(blockPos).getBlock();\n                            if (block == Blocks.air || block == Blocks.stone_button) {\n                                leftmostRow = blockPos;\n                                row = i;\n                                break;\n                            }\n                        }\n\n                        if (itemFrame.posY == 72.5) {\n                            column = 0;\n                        } else if (itemFrame.posY == 71.5) {\n                            column = 1;\n                        } else if (itemFrame.posY == 70.5) {\n                            column = 2;\n                        } else {\n                            continue;\n                        }\n\n                        // Get colour\n                        // Middle pixel = 64*128 + 64 = 8256\n                        int colourInt = mapData.colors[8256] & 255;\n                        if (colourInt == 114) {\n                            board[column][row] = 'X';\n                        } else if (colourInt == 33) {\n                            board[column][row] = 'O';\n                        }\n                    }\n                    System.out.println(\"Board: \" + Arrays.deepToString(board));\n\n                    // Draw best move\n                    int bestMove = TicTacToeUtils.getBestMove(board) - 1;\n                    System.out.println(\"Best move slot: \" + bestMove);\n                    if (leftmostRow != null) {\n                        double drawX = facing == 'X' ? leftmostRow.getX() - sign * (bestMove % 3) : leftmostRow.getX();\n                        double drawY = 72 - Math.floor(bestMove / 3);\n                        double drawZ = facing == 'Z' ? leftmostRow.getZ() - sign * (bestMove % 3) : leftmostRow.getZ();\n\n                        correctTicTacToeButton = new AxisAlignedBB(drawX, drawY, drawZ, drawX + 1, drawY + 1, drawZ + 1);\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onWorldRender(RenderWorldLastEvent event) {\n        if (ModConfig.ticTacToe && correctTicTacToeButton != null) {\n            RenderUtils.draw3DBox(correctTicTacToeButton, ModConfig.ticTacToeColour.getRGB(), event.partialTicks);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonObject;\nimport com.google.gson.JsonPrimitive;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ModInitEvent;\nimport me.Danker.utils.Utils;\nimport net.minecraft.util.ChatComponentText;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.ClientChatReceivedEvent;\nimport net.minecraftforge.fml.common.eventhandler.EventPriority;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\npublic class TriviaSolver {\n\n    static Map<String, String[]> triviaSolutions = new HashMap<>();\n    static String[] triviaAnswers = null;\n    static JsonArray triviaAnswersJson = null;\n\n    @SubscribeEvent\n    public void init(ModInitEvent event) {\n        // Hard coded solutions if api call fails\n        triviaSolutions.put(\"What is the status of The Watcher?\", new String[]{\"Stalker\"});\n        triviaSolutions.put(\"What is the status of Bonzo?\", new String[]{\"New Necromancer\"});\n        triviaSolutions.put(\"What is the status of Scarf?\", new String[]{\"Apprentice Necromancer\"});\n        triviaSolutions.put(\"What is the status of The Professor?\", new String[]{\"Professor\"});\n        triviaSolutions.put(\"What is the status of Thorn?\", new String[]{\"Shaman Necromancer\"});\n        triviaSolutions.put(\"What is the status of Livid?\", new String[]{\"Master Necromancer\"});\n        triviaSolutions.put(\"What is the status of Sadan?\", new String[]{\"Necromancer Lord\"});\n        triviaSolutions.put(\"What is the status of Maxor, Storm, Goldor, and Necron?\", new String[]{\"The Wither Lords\"});\n        triviaSolutions.put(\"How many total Fairy Souls are there?\", new String[]{\"247 Fairy Souls\"});\n        triviaSolutions.put(\"How many Fairy Souls are there in Spider's Den?\", new String[]{\"19 Fairy Souls\"});\n        triviaSolutions.put(\"How many Fairy Souls are there in The End?\", new String[]{\"12 Fairy Souls\"});\n        triviaSolutions.put(\"How many Fairy Souls are there in The Farming Islands?\", new String[]{\"20 Fairy Souls\"});\n        triviaSolutions.put(\"How many Fairy Souls are there in Crimson Isle?\", new String[]{\"29 Fairy Souls\"});\n        triviaSolutions.put(\"How many Fairy Souls are there in The Park?\", new String[]{\"11 Fairy Souls\"});\n        triviaSolutions.put(\"How many Fairy Souls are there in Jerry's Workshop?\", new String[]{\"5 Fairy Souls\"});\n        triviaSolutions.put(\"How many Fairy Souls are there in Hub?\", new String[]{\"79 Fairy Souls\"});\n        triviaSolutions.put(\"How many Fairy Souls are there in The Hub?\", new String[]{\"79 Fairy Souls\"});\n        triviaSolutions.put(\"How many Fairy Souls are there in Deep Caverns?\", new String[]{\"21 Fairy Souls\"});\n        triviaSolutions.put(\"How many Fairy Souls are there in Gold Mine?\", new String[]{\"12 Fairy Souls\"});\n        triviaSolutions.put(\"How many Fairy Souls are there in Dungeon Hub?\", new String[]{\"7 Fairy Souls\"});\n        triviaSolutions.put(\"Which brother is on the Spider's Den?\", new String[]{\"Rick\"});\n        triviaSolutions.put(\"Which brother is on the Spiders Den?\", new String[]{\"Rick\"});\n        triviaSolutions.put(\"What is the name of Rick's brother?\", new String[]{\"Pat\"});\n        triviaSolutions.put(\"What is the name of the Painter in the Hub?\", new String[]{\"Marco\"});\n        triviaSolutions.put(\"What is the name of the person that upgrades pets?\", new String[]{\"Kat\"});\n        triviaSolutions.put(\"What is the name of the lady of the Nether?\", new String[]{\"Elle\"});\n        triviaSolutions.put(\"Which villager in the Village gives you a Rogue Sword?\", new String[]{\"Jamie\"});\n        triviaSolutions.put(\"How many unique minions are there?\", new String[]{\"59 Minions\"});\n        triviaSolutions.put(\"Which of these enemies does not spawn in the Spider's Den?\", new String[]{\"Zombie Spider\", \"Cave Spider\", \"Wither Skeleton\",\n                \"Dashing Spooder\", \"Broodfather\", \"Night Spider\"});\n        triviaSolutions.put(\"Which of these enemies does not spawn in the Spiders Den?\", new String[]{\"Zombie Spider\", \"Cave Spider\", \"Wither Skeleton\",\n                \"Dashing Spooder\", \"Broodfather\", \"Night Spider\"});\n        triviaSolutions.put(\"Which of these monsters only spawns at night?\", new String[]{\"Zombie Villager\", \"Ghast\"});\n        triviaSolutions.put(\"Which of these is not a dragon in The End?\", new String[]{\"Zoomer Dragon\", \"Weak Dragon\", \"Stonk Dragon\", \"Holy Dragon\", \"Boomer Dragon\",\n                \"Booger Dragon\", \"Older Dragon\", \"Elder Dragon\", \"Stable Dragon\", \"Professor Dragon\"});\n    }\n\n    @SubscribeEvent(priority = EventPriority.HIGHEST)\n    public void onChat(ClientChatReceivedEvent event) {\n        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());\n\n        if (!Utils.isInDungeons()) return;\n        if (event.type == 2) return;\n\n        if (ModConfig.oruo) {\n            if (DankersSkyblockMod.data != null && DankersSkyblockMod.data.has(\"trivia\")) {\n                if (message.contains(\"What SkyBlock year is it?\")) {\n                    double currentTime = System.currentTimeMillis() / 1000L;\n\n                    double diff = Math.floor(currentTime - 1560276000);\n\n                    int year = (int) (diff / 446400 + 1);\n                    triviaAnswersJson = new JsonArray();\n                    triviaAnswersJson.add(new JsonPrimitive(\"Year \" + year));\n                } else {\n                    JsonObject triviaSolutions = DankersSkyblockMod.data.getAsJsonObject(\"trivia\");\n\n                    List<String> triviaSolutionsList = triviaSolutions.entrySet().stream()\n                                                       .map(Map.Entry::getKey)\n                                                       .collect(Collectors.toCollection(ArrayList::new));\n                    for (String question : triviaSolutionsList) {\n                        if (message.contains(question)) {\n                            triviaAnswersJson = triviaSolutions.getAsJsonArray(question);\n                            break;\n                        }\n                    }\n                }\n\n                // Set wrong answers to red and remove click events\n                if (triviaAnswersJson != null && (message.contains(\"ⓐ\") || message.contains(\"ⓑ\") || message.contains(\"ⓒ\"))) {\n                    boolean isSolution = false;\n                    for (int i = 0; i < triviaAnswersJson.size(); i++) {\n                        String solution = triviaAnswersJson.get(i).getAsString();\n                        if (message.contains(solution)) {\n                            isSolution = true;\n                            break;\n                        }\n                    }\n                    if (!isSolution) {\n                        char letter = message.charAt(5);\n                        String option = message.substring(6);\n                        event.message = new ChatComponentText(\"     \" + EnumChatFormatting.GOLD + letter + ModConfig.getColour(ModConfig.triviaWrongAnswerColour) + option);\n                    }\n                }\n            } else {\n                if (message.contains(\"What SkyBlock year is it?\")) {\n                    double currentTime = System.currentTimeMillis() / 1000L;\n\n                    double diff = Math.floor(currentTime - 1560276000);\n\n                    int year = (int) (diff / 446400 + 1);\n                    triviaAnswers = new String[]{\"Year \" + year};\n                } else {\n                    for (String question : triviaSolutions.keySet()) {\n                        if (message.contains(question)) {\n                            triviaAnswers = triviaSolutions.get(question);\n                            break;\n                        }\n                    }\n                }\n\n                // Set wrong answers to red and remove click events\n                if (triviaAnswers != null && (message.contains(\"ⓐ\") || message.contains(\"ⓑ\") || message.contains(\"ⓒ\"))) {\n                    boolean isSolution = false;\n                    for (String solution : triviaAnswers) {\n                        if (message.contains(solution)) {\n                            isSolution = true;\n                            break;\n                        }\n                    }\n                    if (!isSolution) {\n                        char letter = message.charAt(5);\n                        String option = message.substring(6);\n                        event.message = new ChatComponentText(\"     \" + EnumChatFormatting.GOLD + letter + ModConfig.getColour(ModConfig.triviaWrongAnswerColour) + option);\n                    }\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/UltrasequencerSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport me.Danker.config.ModConfig;\nimport me.Danker.events.ChestSlotClickedEvent;\nimport me.Danker.events.GuiChestBackgroundDrawnEvent;\nimport me.Danker.utils.RenderUtils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.inventory.GuiChest;\nimport net.minecraft.inventory.ContainerChest;\nimport net.minecraft.inventory.IInventory;\nimport net.minecraft.inventory.Slot;\nimport net.minecraft.util.StringUtils;\nimport net.minecraftforge.client.event.GuiOpenEvent;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\nimport org.lwjgl.input.Keyboard;\n\nimport java.util.List;\n\npublic class UltrasequencerSolver {\n\n    static Slot[] clickInOrderSlots = new Slot[36];\n    static int lastUltraSequencerClicked = 0;\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n        if (mc.currentScreen instanceof GuiChest) {\n            if (player == null) return;\n            ContainerChest chest = (ContainerChest) player.openContainer;\n            List<Slot> invSlots = ((GuiChest) mc.currentScreen).inventorySlots.inventorySlots;\n            String chestName = chest.getLowerChestInventory().getDisplayName().getUnformattedText().trim();\n\n            if (ModConfig.ultrasequencer && chestName.startsWith(\"Ultrasequencer (\")) {\n                if (invSlots.get(49).getStack() != null && invSlots.get(49).getStack().getDisplayName().equals(\"§aRemember the pattern!\")) {\n                    for (int i = 9; i <= 44; i++) {\n                        if (invSlots.get(i) == null || invSlots.get(i).getStack() == null) continue;\n                        String itemName = StringUtils.stripControlCodes(invSlots.get(i).getStack().getDisplayName());\n                        if (itemName.matches(\"\\\\d+\")) {\n                            int number = Integer.parseInt(itemName);\n                            clickInOrderSlots[number - 1] = invSlots.get(i);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onSlotClick(ChestSlotClickedEvent event) {\n        if (ModConfig.ultrasequencer && event.inventoryName.startsWith(\"Ultrasequencer (\")) {\n            IInventory inventory = event.inventory;\n            if (event.item == null) {\n                if (event.isCancelable() && !Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) && !Keyboard.isKeyDown(Keyboard.KEY_RCONTROL))\n                    event.setCanceled(true);\n                return;\n            }\n            if (inventory.getStackInSlot(49).getDisplayName().equals(\"§aRemember the pattern!\")) {\n                if (event.isCancelable()) event.setCanceled(true);\n            } else if (inventory.getStackInSlot(49).getDisplayName().startsWith(\"§7Timer: §a\")) {\n                if (clickInOrderSlots[lastUltraSequencerClicked] != null && event.slot.getSlotIndex() != clickInOrderSlots[lastUltraSequencerClicked].getSlotIndex()) {\n                    if (event.isCancelable() && !Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) && !Keyboard.isKeyDown(Keyboard.KEY_RCONTROL)) {\n                        event.setCanceled(true);\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiRender(GuiChestBackgroundDrawnEvent event) {\n        if (ModConfig.ultrasequencer && event.displayName.startsWith(\"Ultrasequencer (\")) {\n            List<Slot> invSlots = event.slots;\n            if (invSlots.size() > 48 && invSlots.get(49).getStack() != null) {\n                if (invSlots.get(49).getStack().getDisplayName().startsWith(\"§7Timer: §a\")) {\n                    lastUltraSequencerClicked = 0;\n                    for (Slot slot : clickInOrderSlots) {\n                        if (slot != null && slot.getStack() != null && StringUtils.stripControlCodes(slot.getStack().getDisplayName()).matches(\"\\\\d+\")) {\n                            int number = Integer.parseInt(StringUtils.stripControlCodes(slot.getStack().getDisplayName()));\n                            if (number > lastUltraSequencerClicked) {\n                                lastUltraSequencerClicked = number;\n                            }\n                        }\n                    }\n                    if (lastUltraSequencerClicked < clickInOrderSlots.length) {\n                        if (clickInOrderSlots[lastUltraSequencerClicked] != null) {\n                            Slot nextSlot = clickInOrderSlots[lastUltraSequencerClicked];\n                            RenderUtils.drawOnSlot(event.chestSize, nextSlot.xDisplayPosition, nextSlot.yDisplayPosition, ModConfig.ultrasequencerNextColour.getRGB());\n                        }\n                    }\n                    if (lastUltraSequencerClicked + 1 < clickInOrderSlots.length) {\n                        if (clickInOrderSlots[lastUltraSequencerClicked + 1] != null) {\n                            Slot nextSlot = clickInOrderSlots[lastUltraSequencerClicked + 1];\n                            RenderUtils.drawOnSlot(event.chestSize, nextSlot.xDisplayPosition, nextSlot.yDisplayPosition, ModConfig.ultrasequencerNextToNextColour.getRGB());\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    @SubscribeEvent\n    public void onGuiOpen(GuiOpenEvent event) {\n        clickInOrderSlots = new Slot[36];\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/features/puzzlesolvers/WaterSolver.java",
    "content": "package me.Danker.features.puzzlesolvers;\n\nimport cc.polyfrost.oneconfig.config.annotations.Exclude;\nimport cc.polyfrost.oneconfig.hud.Hud;\nimport cc.polyfrost.oneconfig.libs.universal.UMatrixStack;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.block.Block;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.world.World;\nimport net.minecraftforge.fml.common.eventhandler.SubscribeEvent;\nimport net.minecraftforge.fml.common.gameevent.TickEvent;\n\npublic class WaterSolver {\n\n    static boolean prevInWaterRoom = false;\n    static boolean inWaterRoom = false;\n    static String waterAnswers = null;\n\n    @SubscribeEvent\n    public void onTick(TickEvent.ClientTickEvent event) {\n        if (event.phase != TickEvent.Phase.START) return;\n\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayerSP player = mc.thePlayer;\n        World world = mc.theWorld;\n        if (DankersSkyblockMod.tickAmount % 20 == 0) {\n            if (ModConfig.waterSolverHud.isEnabled() && Utils.isInDungeons() && world != null && player != null) {\n                // multi thread block checking\n                new Thread(() -> {\n                    prevInWaterRoom = inWaterRoom;\n                    inWaterRoom = false;\n                    boolean foundPiston = false;\n                    boolean done = false;\n                    for (int x = (int) (player.posX - 13); x <= player.posX + 13; x++) {\n                        for (int z = (int) (player.posZ - 13); z <= player.posZ + 13; z++) {\n                            BlockPos blockPos = new BlockPos(x, 54, z);\n                            if (world.getBlockState(blockPos).getBlock() == Blocks.sticky_piston) {\n                                foundPiston = true;\n                                break;\n                            }\n                        }\n                        if (foundPiston) break;\n                    }\n\n                    if (foundPiston) {\n                        for (int x = (int) (player.posX - 25); x <= player.posX + 25; x++) {\n                            for (int z = (int) (player.posZ - 25); z <= player.posZ + 25; z++) {\n                                BlockPos blockPos = new BlockPos(x, 82, z);\n                                if (world.getBlockState(blockPos).getBlock() == Blocks.piston_head) {\n                                    inWaterRoom = true;\n                                    if (!prevInWaterRoom) {\n                                        boolean foundGold = false;\n                                        boolean foundClay = false;\n                                        boolean foundEmerald = false;\n                                        boolean foundQuartz = false;\n                                        boolean foundDiamond = false;\n\n                                        // Detect first blocks near water stream\n                                        BlockPos scan1 = new BlockPos(x + 1, 78, z + 1);\n                                        BlockPos scan2 = new BlockPos(x - 1, 77, z - 1);\n                                        Iterable<BlockPos> blocks = BlockPos.getAllInBox(scan1, scan2);\n                                        for (BlockPos puzzleBlockPos : blocks) {\n                                            Block block = world.getBlockState(puzzleBlockPos).getBlock();\n                                            if (block == Blocks.gold_block) {\n                                                foundGold = true;\n                                            } else if (block == Blocks.hardened_clay) {\n                                                foundClay = true;\n                                            } else if (block == Blocks.emerald_block) {\n                                                foundEmerald = true;\n                                            } else if (block == Blocks.quartz_block) {\n                                                foundQuartz = true;\n                                            } else if (block == Blocks.diamond_block) {\n                                                foundDiamond = true;\n                                            }\n                                        }\n\n                                        int variant = 0;\n                                        if (foundGold && foundClay) {\n                                            variant = 1;\n                                        } else if (foundEmerald && foundQuartz) {\n                                            variant = 2;\n                                        } else if (foundQuartz && foundDiamond) {\n                                            variant = 3;\n                                        } else if (foundGold && foundQuartz) {\n                                            variant = 4;\n                                        }\n\n                                        // Return solution\n                                        String purple;\n                                        String orange;\n                                        String blue;\n                                        String green;\n                                        String red;\n                                        switch (variant) {\n                                            case 1:\n                                                purple = EnumChatFormatting.WHITE + \"Quartz, \" + EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.AQUA + \"Diamond, \" + EnumChatFormatting.RED + \"Clay\";\n                                                orange = EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.DARK_GRAY + \"Coal, \" + EnumChatFormatting.GREEN + \"Emerald\";\n                                                blue = EnumChatFormatting.WHITE + \"Quartz, \" + EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.GREEN + \"Emerald, \" + EnumChatFormatting.RED + \"Clay\";\n                                                green = EnumChatFormatting.GREEN + \"Emerald\";\n                                                red = EnumChatFormatting.GRAY + \"None\";\n                                                break;\n                                            case 2:\n                                                purple = EnumChatFormatting.DARK_GRAY + \"Coal\";\n                                                orange = EnumChatFormatting.WHITE + \"Quartz, \" + EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.GREEN + \"Emerald, \" + EnumChatFormatting.RED + \"Clay\";\n                                                blue = EnumChatFormatting.WHITE + \"Quartz, \" + EnumChatFormatting.AQUA + \"Diamond, \" + EnumChatFormatting.GREEN + \"Emerald\";\n                                                green = EnumChatFormatting.WHITE + \"Quartz, \" + EnumChatFormatting.GREEN + \"Emerald\";\n                                                red = EnumChatFormatting.WHITE + \"Quartz, \" + EnumChatFormatting.DARK_GRAY + \"Coal, \" + EnumChatFormatting.GREEN + \"Emerald\";\n                                                break;\n                                            case 3:\n                                                purple = EnumChatFormatting.WHITE + \"Quartz, \" + EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.AQUA + \"Diamond\";\n                                                orange = EnumChatFormatting.GREEN + \"Emerald\";\n                                                blue = EnumChatFormatting.WHITE + \"Quartz, \" + EnumChatFormatting.AQUA + \"Diamond\";\n                                                green = EnumChatFormatting.GRAY + \"None\";\n                                                red = EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.GREEN + \"Emerald\";\n                                                break;\n                                            case 4:\n                                                purple = EnumChatFormatting.WHITE + \"Quartz, \" + EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.GREEN + \"Emerald, \" + EnumChatFormatting.RED + \"Clay\";\n                                                orange = EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.DARK_GRAY + \"Coal\";\n                                                blue = EnumChatFormatting.WHITE + \"Quartz, \" + EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.DARK_GRAY + \"Coal, \" + EnumChatFormatting.GREEN + \"Emerald, \" + EnumChatFormatting.RED + \"Clay\";\n                                                green = EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.GREEN + \"Emerald\";\n                                                red = EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.AQUA + \"Diamond, \" + EnumChatFormatting.GREEN + \"Emerald, \" + EnumChatFormatting.RED + \"Clay\";\n                                                break;\n                                            default:\n                                                purple = orange = blue = green = red = ModConfig.getColour(ModConfig.errorColour) + \"Error detecting water puzzle variant.\";\n                                                break;\n                                        }\n                                        waterAnswers = ModConfig.getColour(ModConfig.mainColour) + \"The following levers must be down:\\n\" +\n                                                EnumChatFormatting.DARK_PURPLE + \"Purple: \" + purple + \"\\n\" +\n                                                EnumChatFormatting.GOLD + \"Orange: \" + orange + \"\\n\" +\n                                                EnumChatFormatting.BLUE + \"Blue: \" + blue + \"\\n\" +\n                                                EnumChatFormatting.GREEN + \"Green: \" + green + \"\\n\" +\n                                                EnumChatFormatting.RED + \"Red: \" + red;\n                                        done = true;\n                                        break;\n                                    }\n                                }\n                            }\n                            if (done) break;\n                        }\n                    } else {\n                        waterAnswers = null;\n                    }\n                }).start();\n            }\n        }\n    }\n\n    public static class WaterSolverHud extends Hud {\n\n        @Exclude\n        String exampleText = ModConfig.getColour(ModConfig.mainColour) + \"The following levers must be down:\\n\" +\n                             EnumChatFormatting.DARK_PURPLE + \"Purple: \" + EnumChatFormatting.WHITE + \"Quartz, \" + EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.GREEN + \"Emerald, \" + EnumChatFormatting.RED + \"Clay\\n\" +\n                             EnumChatFormatting.GOLD + \"Orange: \" + EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.DARK_GRAY + \"Coal\\n\" +\n                             EnumChatFormatting.BLUE + \"Blue: \" + EnumChatFormatting.WHITE + \"Quartz, \" + EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.DARK_GRAY + \"Coal, \" + EnumChatFormatting.GREEN + \"Emerald, \" + EnumChatFormatting.RED + \"Clay\\n\" +\n                             EnumChatFormatting.GREEN + \"Green: \" + EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.GREEN + \"Emerald\\n\" +\n                             EnumChatFormatting.RED + \"Red: \" + EnumChatFormatting.YELLOW + \"Gold, \" + EnumChatFormatting.AQUA + \"Diamond, \" + EnumChatFormatting.GREEN + \"Emerald, \" + EnumChatFormatting.RED + \"Clay\";\n\n        @Override\n        protected void draw(UMatrixStack matrices, float x, float y, float scale, boolean example) {\n            if (example) {\n                TextRenderer.drawHUDText(exampleText, x, y, scale);\n                return;\n            }\n\n            if (enabled && Utils.isInDungeons() && waterAnswers != null) {\n                TextRenderer.drawHUDText(waterAnswers, x, y, scale);\n            }\n        }\n\n        @Override\n        protected float getWidth(float scale, boolean example) {\n            return RenderUtils.getWidthFromText(example ? exampleText : waterAnswers) * scale;\n        }\n\n        @Override\n        protected float getHeight(float scale, boolean example) {\n            return RenderUtils.getHeightFromText(example ? exampleText : waterAnswers) * scale;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/gui/WarningGui.java",
    "content": "package me.Danker.gui;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.utils.RenderUtils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.gui.GuiButton;\nimport net.minecraft.client.gui.GuiScreen;\nimport net.minecraft.util.EnumChatFormatting;\n\npublic class WarningGui extends GuiScreen {\n    private GuiButton close;\n\n    public WarningGui(){\n\n    }\n\n    @Override\n    public boolean doesGuiPauseGame() {\n        return false;\n    }\n\n    @Override\n    public void initGui() {\n        super.initGui();\n\n        int height = UResolution.getScaledHeight();\n        int width = UResolution.getScaledWidth();\n\n        close = new GuiButton(0, width / 2 - 100, (int) (height * 0.6), \"Close\");\n\n        this.buttonList.add(close);\n    }\n\n    @Override\n    public void drawScreen(int mouseX, int mouseY, float partialTicks) {\n        this.drawDefaultBackground();\n\n        RenderUtils.drawCenteredText(EnumChatFormatting.RED + \"WARNING!\", (int) (width * 0.9), (int) (height * 0.1), 2D);\n        RenderUtils.drawCenteredText(\"You are using SpiderFrog's Old Animations mod.\", width, (int) (height * 0.3), 1D);\n        RenderUtils.drawCenteredText(\"This mod breaks Danker's Skyblock Mod.\", width, (int) (height * 0.4), 1D);\n\n        super.drawScreen(mouseX, mouseY, partialTicks);\n    }\n\n    @Override\n    public void actionPerformed(GuiButton button){\n        if(button == close) {\n            Minecraft.getMinecraft().displayGuiScreen(null);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/gui/WarningGuiRedirect.java",
    "content": "package me.Danker.gui;\n\nimport net.minecraft.client.gui.GuiButton;\nimport net.minecraft.client.gui.GuiMainMenu;\nimport net.minecraft.client.gui.GuiScreen;\n\npublic class WarningGuiRedirect extends GuiMainMenu {\n    public GuiScreen guiToShow;\n    private GuiButton close;\n\n    protected void keyTyped(char par1, int par2){}\n    public WarningGuiRedirect(GuiScreen g){\n        guiToShow = g;\n    }\n\n    public void initGui(){\n        super.initGui();\n    }\n\n\n    public void drawScreen(int par1, int par2, float par3){\n        super.drawScreen(par1, par2, par3);\n\n        mc.displayGuiScreen(guiToShow);\n    }\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/gui/alerts/AlertActionGui.java",
    "content": "package me.Danker.gui.alerts;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.features.Alerts;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.gui.GuiButton;\nimport net.minecraft.client.gui.GuiScreen;\nimport net.minecraft.util.EnumChatFormatting;\n\npublic class AlertActionGui extends GuiScreen {\n\n    private final int id;\n\n    private GuiButton goBack;\n    private GuiButton toggle;\n    private GuiButton toggleDesktop;\n    private GuiButton edit;\n    private GuiButton delete;\n\n    public AlertActionGui(int id) {\n        this.id = id;\n    }\n\n    @Override\n    public boolean doesGuiPauseGame() {\n        return false;\n    }\n\n    @Override\n    public void initGui() {\n        super.initGui();\n\n        int height = UResolution.getScaledHeight();\n        int width = UResolution.getScaledWidth();\n\n        Alerts.Alert alert = Alerts.alerts.get(id);\n\n        goBack = new GuiButton(0, 2, height - 30, 100, 20, \"Go Back\");\n        toggle = new GuiButton(0, width / 2 - 100, (int) (height * 0.1), \"Enabled: \" + Utils.getColouredBoolean(alert.toggled));\n        toggleDesktop = new GuiButton(0, width / 2 - 100, (int) (height * 0.2), \"Desktop Notification: \" + Utils.getColouredBoolean(alert.desktop));\n        edit = new GuiButton(0, width / 2 - 100, (int) (height * 0.3), \"Edit >\");\n        delete = new GuiButton(0, width / 2 - 100, (int) (height * 0.8), EnumChatFormatting.RED + \"Delete Alert\");\n\n        this.buttonList.add(toggle);\n        this.buttonList.add(toggleDesktop);\n        this.buttonList.add(edit);\n        this.buttonList.add(delete);\n        this.buttonList.add(goBack);\n    }\n\n    @Override\n    public void drawScreen(int mouseX, int mouseY, float partialTicks) {\n        this.drawDefaultBackground();\n        super.drawScreen(mouseX, mouseY, partialTicks);\n\n        Alerts.Alert alert = Alerts.alerts.get(id);\n\n        RenderUtils.drawCenteredText(alert.alert, width, 10, 1D);\n    }\n\n    @Override\n    public void actionPerformed(GuiButton button) {\n        Alerts.Alert alert = Alerts.alerts.get(id);\n        if (button == goBack) {\n            mc.displayGuiScreen(new AlertsGui(1));\n        } else if (button == toggle) {\n            alert.toggle();\n            toggle.displayString = \"Enabled: \" + Utils.getColouredBoolean(alert.toggled);\n        } else if (button == toggleDesktop) {\n            alert.toggleDesktop();\n            toggleDesktop.displayString = \"Desktop Notification: \" + Utils.getColouredBoolean(alert.desktop);\n        } else if (button == edit) {\n            mc.displayGuiScreen(new AlertAddGui(alert, id));\n        } else if (button == delete) {\n            Alerts.alerts.remove(id);\n            Alerts.save();\n            mc.displayGuiScreen(new AlertsGui(1));\n            return;\n        }\n        Alerts.alerts.set(id, alert);\n        Alerts.save();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/gui/alerts/AlertAddGui.java",
    "content": "package me.Danker.gui.alerts;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.features.Alerts;\nimport me.Danker.handlers.TextRenderer;\nimport me.Danker.utils.RenderUtils;\nimport net.minecraft.client.gui.GuiButton;\nimport net.minecraft.client.gui.GuiScreen;\nimport net.minecraft.client.gui.GuiTextField;\nimport net.minecraftforge.fml.client.config.GuiCheckBox;\n\nimport java.io.IOException;\n\npublic class AlertAddGui extends GuiScreen {\n\n    private boolean editing;\n    private Alerts.Alert base = null;\n    private int id;\n\n    private GuiButton cancel;\n\n    private String mode = \"Contains\";\n    private String location = \"Skyblock\";\n    private GuiButton startsWith;\n    private GuiButton contains;\n    private GuiButton endsWith;\n    private GuiButton regex;\n    private GuiButton everywhere;\n    private GuiButton skyblock;\n    private GuiButton dungeons;\n    private GuiTextField message;\n    private GuiTextField alert;\n    private GuiCheckBox desktop;\n    private GuiCheckBox toggled;\n    private GuiButton add;\n\n    public AlertAddGui() {}\n\n    public AlertAddGui(Alerts.Alert alert, int id) {\n        editing = true;\n        base = alert;\n        this.id = id;\n    }\n\n    @Override\n    public boolean doesGuiPauseGame() {\n        return false;\n    }\n\n    @Override\n    public void initGui() {\n        super.initGui();\n\n        int height = UResolution.getScaledHeight();\n        int width = UResolution.getScaledWidth();\n\n        cancel = new GuiButton(0, 2, height - 30, 100, 20, \"Cancel\");\n\n        startsWith = new GuiButton(0, width / 2 - 260, (int) (height * 0.2), 120, 20, \"Starts With\");\n        contains = new GuiButton(0, width / 2 - 130, (int) (height * 0.2), 120, 20, \"Contains\");\n        endsWith = new GuiButton(0, width / 2 + 10, (int) (height * 0.2), 120, 20, \"Ends With\");\n        regex = new GuiButton(0, width / 2 + 140, (int) (height * 0.2), 120, 20, \"Regex\");\n        everywhere = new GuiButton(0, width / 2 - 200, (int) (height * 0.3), 120, 20, \"Everywhere\");\n        skyblock = new GuiButton(0, width / 2 - 60, (int) (height * 0.3), 120, 20, \"Skyblock\");\n        dungeons = new GuiButton(0, width / 2 + 80, (int) (height * 0.3), 120, 20, \"Dungeons\");\n        message = new GuiTextField(0, this.fontRendererObj, width / 2 - 100, (int) (height * 0.4), 200, 20);\n        alert = new GuiTextField(0, this.fontRendererObj, width / 2 - 100, (int) (height * 0.5), 200, 20);\n        desktop = new GuiCheckBox(0, width / 2 - 58, (int) (height * 0.6), \"Desktop Notification\", false);\n        toggled = new GuiCheckBox(0, width / 2 - 26, (int) (height * 0.65), \"Toggled\", true);\n        add = new GuiButton(0, width / 2 - 25, (int) (height * 0.8), 50, 20, \"Add\");\n\n        if (editing) {\n            mode = base.mode;\n            location = base.location;\n            message.setText(base.message);\n            alert.setText(base.alert);\n            desktop.setIsChecked(base.desktop);\n            toggled.setIsChecked(base.toggled);\n        }\n\n        message.setVisible(true);\n        message.setEnabled(true);\n        message.setMaxStringLength(100);\n        alert.setVisible(true);\n        alert.setEnabled(true);\n        alert.setMaxStringLength(100);\n\n        this.buttonList.add(cancel);\n        this.buttonList.add(startsWith);\n        this.buttonList.add(contains);\n        this.buttonList.add(endsWith);\n        this.buttonList.add(regex);\n        this.buttonList.add(everywhere);\n        this.buttonList.add(skyblock);\n        this.buttonList.add(dungeons);\n        this.buttonList.add(desktop);\n        this.buttonList.add(toggled);\n        this.buttonList.add(add);\n    }\n\n    @Override\n    public void drawScreen(int mouseX, int mouseY, float partialTicks) {\n        this.drawDefaultBackground();\n        super.drawScreen(mouseX, mouseY, partialTicks);\n\n        message.drawTextBox();\n        alert.drawTextBox();\n\n        RenderUtils.drawCenteredText(\"Mode: \" + mode, width, (int) (height * 0.1), 1D);\n        RenderUtils.drawCenteredText(\"Location: \" + location, width, (int) (height * 0.15), 1D);\n        TextRenderer.drawText(\"Trigger:\", width / 2 - 145, (int) (height * 0.42), 1D);\n        TextRenderer.drawText(\"Alert Text:\", width / 2 - 158, (int) (height * 0.52), 1D);\n    }\n\n    @Override\n    public void actionPerformed(GuiButton button) {\n        if (button == cancel) {\n            mc.displayGuiScreen(new AlertsGui(1));\n        } else if (button == startsWith) {\n            mode = \"Starts With\";\n        } else if (button == contains) {\n            mode = \"Contains\";\n        } else if (button == endsWith) {\n            mode = \"Ends With\";\n        } else if (button == regex) {\n            mode = \"Regex\";\n        } else if (button == everywhere) {\n            location = \"Everywhere\";\n        } else if (button == skyblock) {\n            location = \"Skyblock\";\n        } else if (button == dungeons) {\n            location = \"Dungeons\";\n        } else if (button == add) {\n            Alerts.Alert newAlert = new Alerts.Alert(mode, location, message.getText(), alert.getText(), desktop.isChecked(), toggled.isChecked());\n            if (editing) {\n                Alerts.alerts.set(id, newAlert);\n            } else {\n                Alerts.alerts.add(newAlert);\n            }\n            Alerts.save();\n            mc.displayGuiScreen(new AlertsGui(1));\n        }\n    }\n\n    @Override\n    protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {\n        super.mouseClicked(mouseX, mouseY, mouseButton);\n        message.mouseClicked(mouseX, mouseY, mouseButton);\n        alert.mouseClicked(mouseX, mouseY, mouseButton);\n    }\n\n    @Override\n    protected void keyTyped(char typedChar, int keyCode) throws IOException {\n        super.keyTyped(typedChar, keyCode);\n        message.textboxKeyTyped(typedChar, keyCode);\n        alert.textboxKeyTyped(typedChar, keyCode);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/gui/alerts/AlertsGui.java",
    "content": "package me.Danker.gui.alerts;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.features.Alerts;\nimport me.Danker.utils.RenderUtils;\nimport net.minecraft.client.gui.GuiButton;\nimport net.minecraft.client.gui.GuiScreen;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class AlertsGui extends GuiScreen {\n\n    private final int page;\n    private final List<GuiButton> allButtons = new ArrayList<>();\n\n    private GuiButton goBack;\n    private GuiButton backPage;\n    private GuiButton nextPage;\n    private GuiButton add;\n\n    public AlertsGui(int page) {\n        this.page = page;\n    }\n\n    @Override\n    public void initGui() {\n        super.initGui();\n\n        int height = UResolution.getScaledHeight();\n        int width = UResolution.getScaledWidth();\n\n        goBack = new GuiButton(0, 2, height - 30, 100, 20, \"Go Back\");\n        backPage = new GuiButton(0, width / 2 - 100, (int) (height * 0.8), 80, 20, \"< Back\");\n        nextPage = new GuiButton(0, width / 2 + 20, (int) (height * 0.8), 80, 20, \"Next >\");\n        add = new GuiButton(0, 0, 0, \"Add Alert\");\n\n        allButtons.clear();\n        allButtons.add(add);\n        for (int i = 0; i < Alerts.alerts.size(); i++) {\n            Alerts.Alert alert = Alerts.alerts.get(i);\n            GuiButton button = new GuiButton(i, 0, 0, alert.alert + \" >\");\n            allButtons.add(button);\n        }\n\n        reInit();\n    }\n\n    public void reInit() {\n        this.buttonList.clear();\n\n        for (int i = (page - 1) * 7, iteration = 0; iteration < 7 && i < allButtons.size(); i++, iteration++) {\n            GuiButton button = allButtons.get(i);\n            button.xPosition = width / 2 - 100;\n            button.yPosition = (int) (height * (0.1 * (iteration + 1)));\n            this.buttonList.add(button);\n        }\n\n        if (page > 1) this.buttonList.add(backPage);\n        if (page < Math.ceil(allButtons.size() / 7D)) this.buttonList.add(nextPage);\n\n        this.buttonList.add(goBack);\n    }\n\n    @Override\n    public void drawScreen(int mouseX, int mouseY, float partialTicks) {\n        this.drawDefaultBackground();\n        super.drawScreen(mouseX, mouseY, partialTicks);\n\n        String pageText = \"Page: \" + page + \"/\" + (int) Math.ceil(allButtons.size() / 7D);\n        RenderUtils.drawCenteredText(pageText, width, 10, 1D);\n    }\n\n    @Override\n    public void actionPerformed(GuiButton button) {\n        if (button == goBack) {\n            DankersSkyblockMod.config.openGui();\n        } else if (button == nextPage) {\n            mc.displayGuiScreen(new AlertsGui(page + 1));\n        } else if (button == backPage) {\n            mc.displayGuiScreen(new AlertsGui(page - 1));\n        } else if (button == add) {\n            mc.displayGuiScreen(new AlertAddGui());\n        } else {\n            mc.displayGuiScreen(new AlertActionGui(button.id));\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/gui/aliases/AliasesActionGui.java",
    "content": "package me.Danker.gui.aliases;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.features.ChatAliases;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.gui.GuiButton;\nimport net.minecraft.client.gui.GuiScreen;\nimport net.minecraft.util.EnumChatFormatting;\n\npublic class AliasesActionGui extends GuiScreen {\n\n    private final int id;\n\n    private GuiButton goBack;\n    private GuiButton toggle;\n    private GuiButton allowInCommand;\n    private GuiButton edit;\n    private GuiButton delete;\n\n    public AliasesActionGui(int id) {\n        this.id = id;\n    }\n\n    @Override\n    public boolean doesGuiPauseGame() {\n        return false;\n    }\n\n    @Override\n    public void initGui() {\n        super.initGui();\n\n        int height = UResolution.getScaledHeight();\n        int width = UResolution.getScaledWidth();\n\n        ChatAliases.Alias alias = ChatAliases.aliases.get(id);\n\n        goBack = new GuiButton(0, 2, height - 30, 100, 20, \"Go Back\");\n        toggle = new GuiButton(0, width / 2 - 100, (int) (height * 0.1), \"Enabled: \" + Utils.getColouredBoolean(alias.toggled));\n        allowInCommand = new GuiButton(0, width / 2 - 100, (int) (height * 0.2), \"Allow in Command: \" + Utils.getColouredBoolean(alias.allowInCommand));\n        edit = new GuiButton(0, width / 2 - 100, (int) (height * 0.3), \"Edit >\");\n        delete = new GuiButton(0, width / 2 - 100, (int) (height * 0.8), EnumChatFormatting.RED + \"Delete Alias\");\n\n        this.buttonList.add(toggle);\n        this.buttonList.add(allowInCommand);\n        this.buttonList.add(edit);\n        this.buttonList.add(delete);\n        this.buttonList.add(goBack);\n    }\n\n    @Override\n    public void drawScreen(int mouseX, int mouseY, float partialTicks) {\n        this.drawDefaultBackground();\n        super.drawScreen(mouseX, mouseY, partialTicks);\n\n        ChatAliases.Alias alias = ChatAliases.aliases.get(id);\n\n        RenderUtils.drawCenteredText(alias.text, width, 10, 1D);\n    }\n\n    @Override\n    public void actionPerformed(GuiButton button) {\n        ChatAliases.Alias alias = ChatAliases.aliases.get(id);\n        if (button == goBack) {\n            mc.displayGuiScreen(new AliasesGui(1));\n        } else if (button == toggle) {\n            alias.toggle();\n            toggle.displayString = \"Enabled: \" + Utils.getColouredBoolean(alias.toggled);\n        } else if (button == allowInCommand) {\n            alias.toggleInCommand();\n            allowInCommand.displayString = \"Allow in Command: \" + Utils.getColouredBoolean(alias.allowInCommand);\n        } else if (button == edit) {\n            mc.displayGuiScreen(new AliasesAddGui(alias, id));\n        } else if (button == delete) {\n            ChatAliases.aliases.remove(id);\n            ChatAliases.save();\n            mc.displayGuiScreen(new AliasesGui(1));\n            return;\n        }\n        ChatAliases.aliases.set(id, alias);\n        ChatAliases.save();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/gui/aliases/AliasesAddGui.java",
    "content": "package me.Danker.gui.aliases;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.features.ChatAliases;\nimport me.Danker.handlers.TextRenderer;\nimport net.minecraft.client.gui.GuiButton;\nimport net.minecraft.client.gui.GuiScreen;\nimport net.minecraft.client.gui.GuiTextField;\nimport net.minecraftforge.fml.client.config.GuiCheckBox;\n\nimport java.io.IOException;\n\npublic class AliasesAddGui extends GuiScreen {\n\n    private boolean editing;\n    private ChatAliases.Alias base = null;\n    private int id;\n\n    private GuiButton cancel;\n\n    private GuiTextField text;\n    private GuiTextField alias;\n    private GuiCheckBox toggled;\n    private GuiCheckBox allowInCommand;\n    private GuiButton add;\n\n    public AliasesAddGui() {}\n\n    public AliasesAddGui(ChatAliases.Alias alias, int id) {\n        editing = true;\n        base = alias;\n        this.id = id;\n    }\n\n    @Override\n    public boolean doesGuiPauseGame() {\n        return false;\n    }\n\n    @Override\n    public void initGui() {\n        super.initGui();\n\n        int height = UResolution.getScaledHeight();\n        int width = UResolution.getScaledWidth();\n\n        cancel = new GuiButton(0, 2, height - 30, 100, 20, \"Cancel\");\n\n        text = new GuiTextField(0, this.fontRendererObj, width / 2 - 100, (int) (height * 0.2), 200, 20);\n        alias = new GuiTextField(0, this.fontRendererObj, width / 2 - 100, (int) (height * 0.3), 200, 20);\n        toggled = new GuiCheckBox(0, width / 2 - 26, (int) (height * 0.4), \"Toggled\", true);\n        allowInCommand = new GuiCheckBox(0, width / 2 - 48, (int) (height * 0.5), \"Allow in Command\", true);\n        add = new GuiButton(0, width / 2 - 25, (int) (height * 0.8), 50, 20, \"Add\");\n\n        if (editing) {\n            text.setText(base.text);\n            alias.setText(base.alias);\n            toggled.setIsChecked(base.toggled);\n            allowInCommand.setIsChecked(base.allowInCommand);\n        }\n\n        text.setVisible(true);\n        text.setEnabled(true);\n        alias.setVisible(true);\n        alias.setEnabled(true);\n        alias.setMaxStringLength(100);\n\n        this.buttonList.add(cancel);\n        this.buttonList.add(toggled);\n        this.buttonList.add(allowInCommand);\n        this.buttonList.add(add);\n    }\n\n    @Override\n    public void drawScreen(int mouseX, int mouseY, float partialTicks) {\n        this.drawDefaultBackground();\n        super.drawScreen(mouseX, mouseY, partialTicks);\n\n        text.drawTextBox();\n        alias.drawTextBox();\n\n        TextRenderer.drawText(\"Text:\", width / 2 - 135, (int) (height * 0.22), 1D);\n        TextRenderer.drawText(\"Alias:\", width / 2 - 136, (int) (height * 0.32), 1D);\n    }\n\n    @Override\n    public void actionPerformed(GuiButton button) {\n        if (button == cancel) {\n            mc.displayGuiScreen(new AliasesGui(1));\n        } else if (button == add) {\n            ChatAliases.Alias newAlias = new ChatAliases.Alias(text.getText(), alias.getText(), toggled.isChecked(), allowInCommand.isChecked());\n            if (editing) {\n                ChatAliases.aliases.set(id, newAlias);\n            } else {\n                ChatAliases.aliases.add(newAlias);\n            }\n            ChatAliases.save();\n            mc.displayGuiScreen(new AliasesGui(1));\n        }\n    }\n\n    @Override\n    protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {\n        super.mouseClicked(mouseX, mouseY, mouseButton);\n        text.mouseClicked(mouseX, mouseY, mouseButton);\n        alias.mouseClicked(mouseX, mouseY, mouseButton);\n    }\n\n    @Override\n    protected void keyTyped(char typedChar, int keyCode) throws IOException {\n        super.keyTyped(typedChar, keyCode);\n        text.textboxKeyTyped(typedChar, keyCode);\n        alias.textboxKeyTyped(typedChar, keyCode);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/gui/aliases/AliasesGui.java",
    "content": "package me.Danker.gui.aliases;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.features.ChatAliases;\nimport me.Danker.utils.RenderUtils;\nimport net.minecraft.client.gui.GuiButton;\nimport net.minecraft.client.gui.GuiScreen;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class AliasesGui extends GuiScreen {\n\n    private final int page;\n    private final List<GuiButton> allButtons = new ArrayList<>();\n\n    private GuiButton goBack;\n    private GuiButton backPage;\n    private GuiButton nextPage;\n    private GuiButton add;\n\n    public AliasesGui(int page) {\n        this.page = page;\n    }\n\n    @Override\n    public boolean doesGuiPauseGame() {\n        return false;\n    }\n\n    @Override\n    public void initGui() {\n        super.initGui();\n\n        int height = UResolution.getScaledHeight();\n        int width = UResolution.getScaledWidth();\n\n        goBack = new GuiButton(0, 2, height - 30, 100, 20, \"Go Back\");\n        backPage = new GuiButton(0, width / 2 - 100, (int) (height * 0.8), 80, 20, \"< Back\");\n        nextPage = new GuiButton(0, width / 2 + 20, (int) (height * 0.8), 80, 20, \"Next >\");\n        add = new GuiButton(0, 0, 0, \"Add Alias\");\n\n        allButtons.clear();\n        allButtons.add(add);\n        for (int i = 0; i < ChatAliases.aliases.size(); i++) {\n            ChatAliases.Alias alias = ChatAliases.aliases.get(i);\n            GuiButton button = new GuiButton(i, 0, 0, alias.text + \" >\");\n            allButtons.add(button);\n        }\n\n        reInit();\n    }\n\n    public void reInit() {\n        this.buttonList.clear();\n\n        for (int i = (page - 1) * 7, iteration = 0; iteration < 7 && i < allButtons.size(); i++, iteration++) {\n            GuiButton button = allButtons.get(i);\n            button.xPosition = width / 2 - 100;\n            button.yPosition = (int) (height * (0.1 * (iteration + 1)));\n            this.buttonList.add(button);\n        }\n\n        if (page > 1) this.buttonList.add(backPage);\n        if (page < Math.ceil(allButtons.size() / 7D)) this.buttonList.add(nextPage);\n\n        this.buttonList.add(goBack);\n    }\n\n    @Override\n    public void drawScreen(int mouseX, int mouseY, float partialTicks) {\n        this.drawDefaultBackground();\n        super.drawScreen(mouseX, mouseY, partialTicks);\n\n        String pageText = \"Page: \" + page + \"/\" + (int) Math.ceil(allButtons.size() / 7D);\n        RenderUtils.drawCenteredText(pageText, width, 10, 1D);\n    }\n\n    @Override\n    public void actionPerformed(GuiButton button) {\n        if (button == goBack) {\n            DankersSkyblockMod.config.openGui();\n        } else if (button == nextPage) {\n            mc.displayGuiScreen(new AliasesGui(page + 1));\n        } else if (button == backPage) {\n            mc.displayGuiScreen(new AliasesGui(page - 1));\n        } else if (button == add) {\n            mc.displayGuiScreen(new AliasesAddGui());\n        } else {\n            mc.displayGuiScreen(new AliasesActionGui(button.id));\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/gui/buttons/FeatureButton.java",
    "content": "package me.Danker.gui.buttons;\n\nimport net.minecraft.client.gui.GuiButton;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class FeatureButton extends GuiButton {\n\n    public List<String> hoverText;\n\n    public FeatureButton(String displayString, String hoverText) {\n        super(0, 0, 0, displayString);\n        this.hoverText = Arrays.asList(hoverText.split(\"\\n\"));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/gui/buttons/LocationButton.java",
    "content": "package me.Danker.gui.buttons;\n\nimport me.Danker.handlers.TextRenderer;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.audio.SoundHandler;\nimport net.minecraft.client.gui.GuiButton;\n\npublic class LocationButton extends GuiButton {\n\n    private int x;\n    private int y;\n    private double scale;\n    private String text;\n    private String text2;\n    private Integer text2Offset;\n    private int longestText;\n    \n    public LocationButton(int x, int y, double scale, String text, String text2, Integer text2Offset) {\n        super(0, x, y, text);\n        this.x = x;\n        this.y = y;\n        this.scale = scale;\n        this.text = text;\n        this.text2 = text2;\n        this.text2Offset = text2Offset;\n\n        String[] splitText;\n        if (text2 == null) {\n            splitText = text.split(\"\\n\");\n        } else {\n            splitText = text2.split(\"\\n\");\n        }\n\n        int longestText = -1;\n        for (String s : splitText) {\n            int stringLength = Minecraft.getMinecraft().fontRendererObj.getStringWidth(s);\n            if (stringLength > longestText) {\n                longestText = stringLength;\n            }\n        }\n\n        this.longestText = longestText;\n        int offset = text2Offset == null ? 0 : text2Offset;\n        this.height = (int) ((splitText.length * 9 + 3) * scale);\n        this.width = (int) ((this.longestText + offset + 3) * scale);\n    }\n\n    public LocationButton(int x, int y, double scale, String text) {\n        this(x, y, scale, text, null, null);\n    }\n    \n    @Override\n    public void drawButton(Minecraft mc, int mouseX, int mouseY) {\n        drawRect(x - 2, y - 2, x + width, y + height, 0x40D3D3D3);\n        if (text2 != null) TextRenderer.drawText(text2, (x + (text2Offset * scale)), y, scale);\n        TextRenderer.drawText(text, x, y, scale);\n    }\n    \n    @Override\n    public void playPressSound(SoundHandler soundHandler) {}\n    \n}\n"
  },
  {
    "path": "src/main/java/me/Danker/gui/crystalhollowwaypoints/CrystalHollowAddWaypointGui.java",
    "content": "package me.Danker.gui.crystalhollowwaypoints;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.features.CrystalHollowWaypoints;\nimport me.Danker.handlers.TextRenderer;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.gui.GuiButton;\nimport net.minecraft.client.gui.GuiScreen;\nimport net.minecraft.client.gui.GuiTextField;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.BlockPos;\n\nimport java.io.IOException;\n\npublic class CrystalHollowAddWaypointGui extends GuiScreen {\n\n    private GuiButton cancel;\n\n    private GuiTextField name;\n    private GuiButton curPos;\n    private GuiTextField x;\n    private GuiTextField y;\n    private GuiTextField z;\n    private GuiButton add;\n\n    private int xPos = -1;\n    private int yPos = -1;\n    private int zPos = -1;\n\n    public CrystalHollowAddWaypointGui() {}\n\n    public CrystalHollowAddWaypointGui(int x, int y, int z) {\n        xPos = x;\n        yPos = y;\n        zPos = z;\n    }\n\n    @Override\n    public boolean doesGuiPauseGame() {\n        return false;\n    }\n\n    @Override\n    public void initGui() {\n        super.initGui();\n\n        int height = UResolution.getScaledHeight();\n        int width = UResolution.getScaledWidth();\n\n        cancel = new GuiButton(0, 2, height - 30, 100, 20, \"Cancel\");\n\n        name = new GuiTextField(0, this.fontRendererObj, width / 2 - 100, (int) (height * 0.1), 200, 20);\n        curPos = new GuiButton(0, width / 2 - 50, (int) (height * 0.25), 100, 20, \"Current Position\");\n        x = new GuiTextField(0, this.fontRendererObj, width / 2 - 85, (int) (height * 0.4), 50, 20);\n        y = new GuiTextField(0, this.fontRendererObj, width / 2 - 25, (int) (height * 0.4), 50, 20);\n        z = new GuiTextField(0, this.fontRendererObj, width / 2 + 35, (int) (height * 0.4), 50, 20);\n        add = new GuiButton(0, width / 2 - 25, (int) (height * 0.6), 50, 20, \"Add\");\n\n        name.setVisible(true);\n        name.setEnabled(true);\n        x.setVisible(true);\n        x.setEnabled(true);\n        if (xPos != -1) x.setText(xPos + \"\");\n        y.setVisible(true);\n        y.setEnabled(true);\n        if (yPos != -1) y.setText(yPos + \"\");\n        z.setVisible(true);\n        z.setEnabled(true);\n        if (zPos != -1) z.setText(zPos + \"\");\n\n        this.buttonList.add(cancel);\n        this.buttonList.add(curPos);\n        this.buttonList.add(add);\n    }\n\n    @Override\n    public void drawScreen(int mouseX, int mouseY, float partialTicks) {\n        this.drawDefaultBackground();\n        super.drawScreen(mouseX, mouseY, partialTicks);\n\n        name.drawTextBox();\n        x.drawTextBox();\n        y.drawTextBox();\n        z.drawTextBox();\n\n        TextRenderer.drawText(\"X:\", width / 2 - 85, (int) (height * 0.35), 1D);\n        TextRenderer.drawText(\"Y:\", width / 2 - 25, (int) (height * 0.35), 1D);\n        TextRenderer.drawText(\"Z:\", width / 2 + 35, (int) (height * 0.35), 1D);\n    }\n\n    @Override\n    public void actionPerformed(GuiButton button) {\n        EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n\n        if (button == cancel) {\n            mc.displayGuiScreen(new CrystalHollowWaypointsGui(1));\n        } else if (button == curPos) {\n            x.setText(Integer.toString(player.getPosition().getX()));\n            y.setText(Integer.toString(player.getPosition().getY()));\n            z.setText(Integer.toString(player.getPosition().getZ()));\n        } else if (button == add) {\n            String loc = name.getText().length() == 0 ? Integer.toString(CrystalHollowWaypoints.waypoints.size()) : name.getText();\n            int xPos = x.getText().matches(\"[-]?\\\\d+\") ? Integer.parseInt(x.getText()) : player.getPosition().getX();\n            int yPos = y.getText().matches(\"[-]?\\\\d+\") ? Integer.parseInt(y.getText()) : player.getPosition().getY();\n            int zPos = z.getText().matches(\"[-]?\\\\d+\") ? Integer.parseInt(z.getText()) : player.getPosition().getZ();\n\n            BlockPos pos = new BlockPos(xPos, yPos, zPos);\n            CrystalHollowWaypoints.waypoints.add(new CrystalHollowWaypoints.Waypoint(loc, pos));\n\n            mc.displayGuiScreen(new CrystalHollowWaypointsGui(1));\n        }\n    }\n\n    @Override\n    protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {\n        super.mouseClicked(mouseX, mouseY, mouseButton);\n        name.mouseClicked(mouseX, mouseY, mouseButton);\n        x.mouseClicked(mouseX, mouseY, mouseButton);\n        y.mouseClicked(mouseX, mouseY, mouseButton);\n        z.mouseClicked(mouseX, mouseY, mouseButton);\n    }\n\n    @Override\n    protected void keyTyped(char typedChar, int keyCode) throws IOException {\n        super.keyTyped(typedChar, keyCode);\n        name.textboxKeyTyped(typedChar, keyCode);\n        x.textboxKeyTyped(typedChar, keyCode);\n        y.textboxKeyTyped(typedChar, keyCode);\n        z.textboxKeyTyped(typedChar, keyCode);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/gui/crystalhollowwaypoints/CrystalHollowWaypointActionGui.java",
    "content": "package me.Danker.gui.crystalhollowwaypoints;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.features.CrystalHollowWaypoints;\nimport me.Danker.utils.RenderUtils;\nimport me.Danker.utils.Utils;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.entity.EntityPlayerSP;\nimport net.minecraft.client.gui.GuiButton;\nimport net.minecraft.client.gui.GuiScreen;\nimport net.minecraft.util.EnumChatFormatting;\n\npublic class CrystalHollowWaypointActionGui extends GuiScreen {\n\n    private int id;\n\n    private GuiButton goBack;\n    private GuiButton toggle;\n    private GuiButton sendNormal;\n    private GuiButton sendDSM;\n    private GuiButton sendSBE;\n    private GuiButton delete;\n\n    public CrystalHollowWaypointActionGui(int id) {\n        this.id = id;\n    }\n\n    @Override\n    public boolean doesGuiPauseGame() {\n        return false;\n    }\n\n    @Override\n    public void initGui() {\n        super.initGui();\n\n        int height = UResolution.getScaledHeight();\n        int width = UResolution.getScaledWidth();\n\n        CrystalHollowWaypoints.Waypoint waypoint = CrystalHollowWaypoints.waypoints.get(id);\n\n        goBack = new GuiButton(0, 2, height - 30, 100, 20, \"Go Back\");\n        toggle = new GuiButton(0, width / 2 - 100, (int) (height * 0.1), \"Set Visibility: \" + Utils.getColouredBoolean(waypoint.toggled));\n        sendNormal = new GuiButton(0, width / 2 - 100, (int) (height * 0.2), \"Send Location And Coordinates\");\n        sendDSM = new GuiButton(0, width / 2 - 100, (int) (height * 0.3), \"Send DSM Formatted Waypoint\");\n        sendSBE = new GuiButton(0, width / 2 - 100, (int) (height * 0.4), \"Send SBE Formatted Waypoint\");\n        delete = new GuiButton(0, width / 2 - 100, (int) (height * 0.8), EnumChatFormatting.RED + \"Delete Waypoint\");\n\n        this.buttonList.add(toggle);\n        this.buttonList.add(sendNormal);\n        this.buttonList.add(sendDSM);\n        this.buttonList.add(sendSBE);\n        this.buttonList.add(delete);\n        this.buttonList.add(goBack);\n    }\n\n    @Override\n    public void drawScreen(int mouseX, int mouseY, float partialTicks) {\n        this.drawDefaultBackground();\n        super.drawScreen(mouseX, mouseY, partialTicks);\n\n        CrystalHollowWaypoints.Waypoint waypoint = CrystalHollowWaypoints.waypoints.get(id);\n\n        RenderUtils.drawCenteredText(waypoint.location + \" @ \" + waypoint.getPos(), width, 10, 1D);\n    }\n\n    @Override\n    public void actionPerformed(GuiButton button) {\n        CrystalHollowWaypoints.Waypoint waypoint = CrystalHollowWaypoints.waypoints.get(id);\n        EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;\n        if (button == goBack) {\n            mc.displayGuiScreen(new CrystalHollowWaypointsGui(1));\n        } else if (button == toggle) {\n            waypoint.toggle();\n            toggle.displayString = \"Set Visibility: \" + Utils.getColouredBoolean(waypoint.toggled);\n        } else if (button == sendNormal) {\n            player.sendChatMessage(waypoint.location + \" @ \" + waypoint.getPos());\n        } else if (button == sendDSM) {\n            player.sendChatMessage(\"$DSMCHWP:\" + waypoint.getFormattedWaypoint());\n        } else if (button == sendSBE) {\n            player.sendChatMessage(\"$SBECHWP:\" + waypoint.getFormattedWaypoint());\n        } else if (button == delete) {\n            CrystalHollowWaypoints.waypoints.remove(id);\n            mc.displayGuiScreen(new CrystalHollowWaypointsGui(1));\n            return;\n        }\n        CrystalHollowWaypoints.waypoints.set(id, waypoint);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/gui/crystalhollowwaypoints/CrystalHollowWaypointsGui.java",
    "content": "package me.Danker.gui.crystalhollowwaypoints;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.features.CrystalHollowWaypoints;\nimport me.Danker.utils.RenderUtils;\nimport net.minecraft.client.gui.GuiButton;\nimport net.minecraft.client.gui.GuiScreen;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class CrystalHollowWaypointsGui extends GuiScreen {\n\n    private final int page;\n    private final List<GuiButton> allButtons = new ArrayList<>();\n\n    private GuiButton goBack;\n    private GuiButton backPage;\n    private GuiButton nextPage;\n    private GuiButton add;\n\n    public CrystalHollowWaypointsGui(int page) {\n        this.page = page;\n    }\n\n    @Override\n    public boolean doesGuiPauseGame() {\n        return false;\n    }\n\n    @Override\n    public void initGui() {\n        super.initGui();\n\n        int height = UResolution.getScaledHeight();\n        int width = UResolution.getScaledWidth();\n\n        goBack = new GuiButton(0, 2, height - 30, 100, 20, \"Go Back\");\n        backPage = new GuiButton(0, width / 2 - 100, (int) (height * 0.8), 80, 20, \"< Back\");\n        nextPage = new GuiButton(0, width / 2 + 20, (int) (height * 0.8), 80, 20, \"Next >\");\n        add = new GuiButton(0, 0, 0, \"Add Waypoint\");\n\n        allButtons.clear();\n        allButtons.add(add);\n        for (int i = 0; i < CrystalHollowWaypoints.waypoints.size(); i++) {\n            CrystalHollowWaypoints.Waypoint waypoint = CrystalHollowWaypoints.waypoints.get(i);\n            GuiButton button = new GuiButton(i, 0, 0, waypoint.location + \" >\");\n            allButtons.add(button);\n        }\n\n        reInit();\n    }\n\n    public void reInit() {\n        this.buttonList.clear();\n\n        for (int i = (page - 1) * 7, iteration = 0; iteration < 7 && i < allButtons.size(); i++, iteration++) {\n            GuiButton button = allButtons.get(i);\n            button.xPosition = width / 2 - 100;\n            button.yPosition = (int) (height * (0.1 * (iteration + 1)));\n            this.buttonList.add(button);\n        }\n\n        if (page > 1) this.buttonList.add(backPage);\n        if (page < Math.ceil(allButtons.size() / 7D)) this.buttonList.add(nextPage);\n\n        this.buttonList.add(goBack);\n    }\n\n    @Override\n    public void drawScreen(int mouseX, int mouseY, float partialTicks) {\n        this.drawDefaultBackground();\n        super.drawScreen(mouseX, mouseY, partialTicks);\n\n        String pageText = \"Page: \" + page + \"/\" + (int) Math.ceil(allButtons.size() / 7D);\n        RenderUtils.drawCenteredText(pageText, width, 10, 1D);\n    }\n\n    @Override\n    public void actionPerformed(GuiButton button) {\n        if (button == goBack) {\n            DankersSkyblockMod.config.openGui();\n        } else if (button == nextPage) {\n            mc.displayGuiScreen(new CrystalHollowWaypointsGui(page + 1));\n        } else if (button == backPage) {\n            mc.displayGuiScreen(new CrystalHollowWaypointsGui(page - 1));\n        } else if (button == add) {\n            mc.displayGuiScreen(new CrystalHollowAddWaypointGui());\n        } else {\n            mc.displayGuiScreen(new CrystalHollowWaypointActionGui(button.id));\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/handlers/APIHandler.java",
    "content": "package me.Danker.handlers;\n\nimport com.google.gson.Gson;\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonObject;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.ChatComponentText;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClientBuilder;\nimport org.apache.http.util.EntityUtils;\n\nimport javax.net.ssl.*;\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.security.SecureRandom;\nimport java.security.cert.X509Certificate;\nimport java.util.Scanner;\n\npublic class APIHandler {\n\n    private static SSLSocketFactory sslSocketFactory = null;\n\n    public static SSLSocketFactory getSSLSocketFactory() {\n        if (sslSocketFactory == null) {\n            TrustManager[] trustManagers = new TrustManager[]{\n                new X509TrustManager() {\n                    public X509Certificate[] getAcceptedIssuers() {\n                        return null;\n                    }\n\n                    public void checkClientTrusted(X509Certificate[] certs, String authType) {}\n                    public void checkServerTrusted(X509Certificate[] certs, String authType) {}\n                }\n            };\n\n            try {\n                SSLContext context = SSLContext.getInstance(\"SSL\");\n                context.init(null, trustManagers, new SecureRandom());\n                sslSocketFactory = context.getSocketFactory();\n            } catch (Exception ex) {\n                return null;\n            }\n        }\n\n        return sslSocketFactory;\n    }\n\n    public static JsonObject getResponse(String urlString, boolean hasError) {\n        EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n        \n        try {\n            URL url = new URL(urlString);\n            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();\n            conn.setRequestMethod(\"GET\");\n            conn.setRequestProperty(\"User-Agent\", \"Dsm/\" + DankersSkyblockMod.VERSION);\n            conn.setSSLSocketFactory(getSSLSocketFactory());\n            \n            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {\n                BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));\n                String input;\n                StringBuilder response = new StringBuilder();\n                \n                while ((input = in.readLine()) != null) {\n                    response.append(input);\n                }\n                in.close();\n                \n                Gson gson = new Gson();\n\n                return gson.fromJson(response.toString(), JsonObject.class);\n            } else {\n                if (hasError) {\n                    InputStream errorStream = conn.getErrorStream();\n                    try (Scanner scanner = new Scanner(errorStream)) {\n                        scanner.useDelimiter(\"\\\\Z\");\n                        String error = scanner.next();\n                        \n                        Gson gson = new Gson();\n                        return gson.fromJson(error, JsonObject.class);\n                    }\n                } else if (urlString.startsWith(\"https://api.mojang.com/users/profiles/minecraft/\") && (conn.getResponseCode() == 204 || conn.getResponseCode() == 404)) {\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Failed with reason: Player does not exist.\"));\n                } else {\n                    player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Request failed. HTTP Error Code: \" + conn.getResponseCode()));\n                }\n            }\n        } catch (IOException ex) {\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"An error has occured. See logs for more details.\"));\n            ex.printStackTrace();\n        }\n\n        return new JsonObject();\n    }\n\n    public static JsonObject getResponsePOST(String urlString, JsonObject body, boolean hasError) throws IOException {\n        EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n\n        try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {\n            HttpPost req = new HttpPost(urlString);\n            StringEntity params = new StringEntity(body.toString());\n            req.addHeader(\"content-type\", \"application/json\");\n            req.setEntity(params);\n            HttpResponse response = httpClient.execute(req);\n\n            return new Gson().fromJson(EntityUtils.toString(response.getEntity(), \"UTF-8\"), JsonObject.class);\n        } catch (Exception ex) {\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"An error has occured. See logs for more details.\"));\n            ex.printStackTrace();\n        }\n\n        return new JsonObject();\n    }\n\n    public static JsonArray getArrayResponse(String urlString) {\n        EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n        \n        try {\n            URL url = new URL(urlString);\n            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();\n            conn.setRequestMethod(\"GET\");\n            conn.setRequestProperty(\"User-Agent\", \"Dsm/\" + DankersSkyblockMod.VERSION);\n            conn.setSSLSocketFactory(getSSLSocketFactory());\n            \n            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {\n                BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));\n                String input;\n                StringBuilder response = new StringBuilder();\n                \n                while ((input = in.readLine()) != null) {\n                    response.append(input);\n                }\n                in.close();\n                \n                Gson gson = new Gson();\n\n                return gson.fromJson(response.toString(), JsonArray.class);\n            } else {\n                player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Request failed. HTTP Error Code: \" + conn.getResponseCode()));\n            }\n        } catch (IOException ex) {\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"An error has occured. See logs for more details.\"));\n            ex.printStackTrace();\n        }\n\n        return new JsonArray();\n    }\n    \n    public static String getUUID(String username) {\n        JsonObject uuidResponse = getResponse(\"https://api.mojang.com/users/profiles/minecraft/\" + username, false);\n        return uuidResponse.get(\"id\").getAsString();\n    }\n\n    public static String getName(String uuid) {\n        JsonObject nameResponse = getResponse(\"https://sessionserver.mojang.com/session/minecraft/profile/\" + uuid, false);\n        return nameResponse.get(\"name\").getAsString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/handlers/ConfigHandler.java",
    "content": "package me.Danker.handlers;\n\nimport me.Danker.config.CfgConfig;\nimport me.Danker.config.JsonConfig;\n\npublic class ConfigHandler {\n\n    public static void reloadConfig() {\n        CfgConfig.reloadConfig();\n        JsonConfig.reloadConfig();\n        // DankersSkyblockMod.config.reInitialize();\n        // ^^ breaks config saving huds\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/handlers/HypixelAPIHandler.java",
    "content": "package me.Danker.handlers;\n\nimport cc.polyfrost.oneconfig.utils.JsonUtils;\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonObject;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.exceptions.AuthenticationException;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.ModConfig;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.util.ChatComponentText;\nimport org.apache.commons.io.IOUtils;\n\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.UUID;\n\npublic class HypixelAPIHandler {\n\n    public static final String URL = \"https://api.polyfrost.cc/ursa/v1/hypixel/\";\n\n    private static String token;\n    private static Instant expiry;\n    private static String username;\n    private static String serverId;\n\n    public static JsonObject getJsonObjectAuth(String url) { // handles auth for you\n        HttpURLConnection connection = setupConnection(url);\n        if (connection == null) {\n            return null; // if connection is null (something bad happened), return null. you probably want null checks in your code\n        }\n        try (InputStreamReader input = new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)) {\n            JsonElement element = JsonUtils.parseString(IOUtils.toString(input));\n            if (username != null && serverId != null) { // if we passed username and serverid, we need to get the token and expiry to use in future requests\n                token = connection.getHeaderField(\"x-ursa-token\"); // get the token and expiry from the headers\n                expiry = calculateExpiry(connection.getHeaderField(\"x-ursa-expires\"));\n                username = null; // reset username and serverid\n                serverId = null;\n            }\n            if (element == null || !element.isJsonObject()) { // if the element is null or not a json object, return null\n                return null;\n            }\n            return element.getAsJsonObject();\n        } catch (IOException e) {\n            e.printStackTrace();\n            return null; // if something bad happened, return null\n        }\n    }\n\n    private static HttpURLConnection setupConnection(String url) {\n        HttpURLConnection connection;\n        try {\n            connection = ((HttpURLConnection) new URL(url).openConnection());\n            connection.setRequestMethod(\"GET\");\n            connection.setUseCaches(false);\n            connection.addRequestProperty(\"User-Agent\", \"Dsm/\" + DankersSkyblockMod.VERSION); // IMPORTANT: change this to your own user agent\n            connection.setReadTimeout(5000);\n            connection.setConnectTimeout(5000);\n            connection.setDoOutput(true);\n            if (token != null && expiry != null && expiry.isAfter(Instant.now())) { // if we have a token and it hasnt expired, use it\n                connection.addRequestProperty(\"x-ursa-token\", token); // add the token and expiry to the headers\n            } else {\n                token = null; // reset token and expiry\n                expiry = null; // this is important, otherwise we will keep using the old token\n                if (authorize()) { // if we successfully authorized, add the username and serverid we used to authorize to the headers\n                    connection.addRequestProperty(\"x-ursa-username\", username);\n                    connection.addRequestProperty(\"x-ursa-serverid\", serverId);\n                } else {\n                    return null;\n                }\n            }\n            return connection;\n        } catch (IOException e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    private static boolean authorize() {\n        String serverId = UUID.randomUUID().toString(); // generate a random serverid\n        try {\n            GameProfile profile = Minecraft.getMinecraft().getSession().getProfile(); // get the user's game profile\n            String token = Minecraft.getMinecraft().getSession().getToken(); // get the user's token\n            Minecraft.getMinecraft().getSessionService().joinServer(profile, token, serverId); // authenticate with MC to confirm with the server that we are who we say we are and to prevent spam\n            username = profile.getName(); // set the username and serverid - we will use these later and pass them to the server\n            HypixelAPIHandler.serverId = serverId;\n        } catch (AuthenticationException e) {\n            e.printStackTrace();\n            return false;\n        }\n        return true;\n    }\n\n    private static Instant calculateExpiry(String expiry) {\n        try {\n            long expiryLong = Long.parseLong(expiry); // parse the expiry to a long\n            return Instant.ofEpochMilli(expiryLong); // convert the long to an instant\n        } catch (NumberFormatException e) {\n            return Instant.now().plus(Duration.ofMinutes(55)); // if the expiry is invalid, return 55 minutes from now which should be safe enough\n        }\n    }\n\n    public static JsonObject getLatestProfile(String UUID) {\n        EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n\n        // Get profiles\n        System.out.println(\"Fetching profiles...\");\n\n        JsonObject profilesResponse = getJsonObjectAuth(URL + \"v2/skyblock/profiles/\" + UUID);\n        if (profilesResponse == null) {\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Could not connect to API.\"));\n            return null;\n        }\n        if (!profilesResponse.get(\"success\").getAsBoolean()) {\n            String reason = profilesResponse.get(\"cause\").getAsString();\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Failed with reason: \" + reason));\n            return null;\n        }\n        if (profilesResponse.get(\"profiles\").isJsonNull()) {\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"This player doesn't appear to have played SkyBlock.\"));\n            return null;\n        }\n\n        // Loop through profiles to find latest\n        System.out.println(\"Looping through profiles...\");\n        JsonArray profilesArray = profilesResponse.getAsJsonArray(\"profiles\");\n\n        for (JsonElement profile : profilesArray) {\n            JsonObject profileJSON = profile.getAsJsonObject();\n\n            if (profileJSON.get(\"selected\").getAsBoolean()) {\n                return profileJSON;\n            }\n        }\n\n        return null;\n    }\n\n    public static String getLatestProfileID(String UUID) {\n        EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n\n        // Get profiles\n        System.out.println(\"Fetching profiles...\");\n\n        JsonObject profilesResponse = getJsonObjectAuth(URL + \"v2/skyblock/profiles/\" + UUID);\n        if (profilesResponse == null) {\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Could not connect to API.\"));\n            return null;\n        }\n        if (!profilesResponse.get(\"success\").getAsBoolean()) {\n            String reason = profilesResponse.get(\"cause\").getAsString();\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"Failed with reason: \" + reason));\n            return null;\n        }\n        if (profilesResponse.get(\"profiles\").isJsonNull()) {\n            player.addChatMessage(new ChatComponentText(ModConfig.getColour(ModConfig.errorColour) + \"This player doesn't appear to have played SkyBlock.\"));\n            return null;\n        }\n\n        // Loop through profiles to find latest\n        System.out.println(\"Looping through profiles...\");\n        JsonArray profilesArray = profilesResponse.getAsJsonArray(\"profiles\");\n\n        for (JsonElement profile : profilesArray) {\n            JsonObject profileJSON = profile.getAsJsonObject();\n\n            if (profileJSON.get(\"selected\").getAsBoolean()) {\n                return profileJSON.get(\"profile_id\").getAsString();\n            }\n        }\n\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/handlers/PacketHandler.java",
    "content": "package me.Danker.handlers;\n\nimport io.netty.channel.ChannelDuplexHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelPromise;\nimport me.Danker.events.PacketReadEvent;\nimport me.Danker.events.PacketWriteEvent;\nimport net.minecraft.network.Packet;\nimport net.minecraftforge.common.MinecraftForge;\n\npublic class PacketHandler extends ChannelDuplexHandler {\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n        if (msg instanceof Packet) {\n            if (MinecraftForge.EVENT_BUS.post(new PacketReadEvent((Packet) msg))) return;\n        }\n\n        super.channelRead(ctx, msg);\n    }\n\n    @Override\n    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {\n        if (msg instanceof Packet) {\n            if (MinecraftForge.EVENT_BUS.post(new PacketWriteEvent((Packet) msg))) return;\n        }\n\n        super.write(ctx, msg, promise);\n    }\n    \n}\n"
  },
  {
    "path": "src/main/java/me/Danker/handlers/ScoreboardHandler.java",
    "content": "package me.Danker.handlers;\n\nimport com.google.common.collect.Iterables;\nimport com.google.common.collect.Lists;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.scoreboard.Score;\nimport net.minecraft.scoreboard.ScoreObjective;\nimport net.minecraft.scoreboard.ScorePlayerTeam;\nimport net.minecraft.scoreboard.Scoreboard;\nimport net.minecraft.util.StringUtils;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.ConcurrentModificationException;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\npublic class ScoreboardHandler {\n    \n    public static String cleanSB(String scoreboard) {\n        char[] nvString = StringUtils.stripControlCodes(scoreboard).toCharArray();\n        StringBuilder cleaned = new StringBuilder();\n        \n        for (char c : nvString) {\n            if ((int) c > 20 && (int) c < 127) {\n                cleaned.append(c);\n            }\n        }\n        \n        return cleaned.toString();\n    }\n    \n    public static List<String> getSidebarLines() {\n        List<String> lines = new ArrayList<>();\n        if (Minecraft.getMinecraft().theWorld == null) return lines;\n        Scoreboard scoreboard = Minecraft.getMinecraft().theWorld.getScoreboard();\n        if (scoreboard == null) return lines;\n        \n        ScoreObjective objective = scoreboard.getObjectiveInDisplaySlot(1);\n        if (objective == null) return lines;\n        \n        Collection<Score> scores;\n        try {\n            scores = scoreboard.getSortedScores(objective);\n        } catch (ConcurrentModificationException ex) {\n            ex.printStackTrace();\n            return new ArrayList<>();\n        }\n\n        List<Score> list = scores.stream()\n                .filter(input -> input != null && input.getPlayerName() != null && !input.getPlayerName()\n                .startsWith(\"#\"))\n                .collect(Collectors.toList());\n        \n        if (list.size() > 15) {\n            scores = Lists.newArrayList(Iterables.skip(list, scores.size() - 15));\n        } else {\n            scores = list;\n        }\n        \n        for (Score score : scores) {\n            ScorePlayerTeam team = scoreboard.getPlayersTeam(score.getPlayerName());\n            lines.add(ScorePlayerTeam.formatPlayerName(team, score.getPlayerName()));\n        }\n        \n        return lines;\n    }\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/handlers/TextRenderer.java",
    "content": "package me.Danker.handlers;\n\nimport me.Danker.config.ModConfig;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.gui.FontRenderer;\nimport net.minecraft.client.gui.Gui;\nimport net.minecraft.client.renderer.GlStateManager;\nimport net.minecraft.util.StringUtils;\n\npublic class TextRenderer extends Gui {\n\n    static Minecraft mc = Minecraft.getMinecraft();\n    static FontRenderer fr = mc.fontRendererObj;\n\n    public static void drawText(String text, double x, double y, double scale) {\n        if (text == null) return;\n\n        GlStateManager.pushMatrix();\n        GlStateManager.scale(scale, scale, 1);\n\n        String[] split = text.split(\"\\n\");\n        for (String line : split) {\n            if (ModConfig.outlineText) {\n                String noColorLine = StringUtils.stripControlCodes(line);\n                fr.drawString(noColorLine, (int) Math.round(x / scale) - 1, (int) Math.round(y / scale), 0x000000, false);\n                fr.drawString(noColorLine, (int) Math.round(x / scale) + 1, (int) Math.round(y / scale), 0x000000, false);\n                fr.drawString(noColorLine, (int) Math.round(x / scale), (int) Math.round(y / scale) - 1, 0x000000, false);\n                fr.drawString(noColorLine, (int) Math.round(x / scale), (int) Math.round(y / scale) + 1, 0x000000, false);\n                fr.drawString(line, (int) Math.round(x / scale), (int) Math.round(y / scale), 0xFFFFFF, false);\n            } else {\n                fr.drawString(line, (float) (x / scale), (float) (y / scale), 0xFFFFFF, true);\n            }\n            y += fr.FONT_HEIGHT * scale;\n        }\n\n        GlStateManager.popMatrix();\n        GlStateManager.color(1, 1, 1, 1);\n    }\n\n    public static void drawHUDText(String text, double x, double y, double scale) {\n        GlStateManager.pushMatrix();\n        GlStateManager.translate(0, 0, -1);\n        drawText(text, x, y, scale);\n        GlStateManager.popMatrix();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/locations/DungeonFloor.java",
    "content": "package me.Danker.locations;\n\npublic enum DungeonFloor {\n    NONE,\n    E0,\n    F1,\n    F2,\n    F3,\n    F4,\n    F5,\n    F6,\n    F7,\n    M1,\n    M2,\n    M3,\n    M4,\n    M5,\n    M6,\n    M7\n}"
  },
  {
    "path": "src/main/java/me/Danker/locations/Location.java",
    "content": "package me.Danker.locations;\n\npublic enum Location {\n    NONE(\"\"),\n    CATACOMBS(\"Catacombs\"),\n    CRIMSON_ISLE(\"Crimson Isle\"),\n    CRYSTAL_HOLLOWS(\"Crystal Hollows\"),\n    DEEP_CAVERNS(\"Deep Caverns\"),\n    DUNGEON_HUB(\"Dungeon Hub\"),\n    DWARVEN_MINES(\"Dwarven Mines\"),\n    END(\"The End\"),\n    FARMING_ISLANDS(\"The Farming Islands\"),\n    GARDEN(\"Garden\"),\n    GOLD_MINE(\"Gold Mine\"),\n    HUB(\"Hub\"),\n    KUUDRA(\"Kuudra\"),\n    JERRY_WORKSHOP(\"Jerry's Workshop\"),\n    MINESHAFT(\"Mineshaft\"),\n    PARK(\"The Park\"),\n    PRIVATE_ISLAND(\"Private Island\"),\n    RIFT(\"The Rift\"),\n    SPIDERS_DEN(\"Spider's Den\");\n\n    final String text;\n\n    Location(String text) {\n        this.text = text;\n    }\n\n    public static Location fromTab(String text) {\n        for (Location location : Location.values()) {\n            if (location.text.equalsIgnoreCase(text)) return location;\n        }\n        return NONE;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/utils/BoulderUtils.java",
    "content": "package me.Danker.utils;\n\nimport me.Danker.features.puzzlesolvers.BoulderSolver;\nimport net.minecraft.util.AxisAlignedBB;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.Vec3;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\n\npublic class BoulderUtils {\n\n    public static HashSet<String> seenBoardStates = new HashSet<>();\n    public static long iterations = 0;\n    public static int fastestSolution = 10;\n\n    /*\n    CC BY-SA 4.0\n    Unmodified\n    Question: https://stackoverflow.com/questions/5617016/\n    Answer: https://stackoverflow.com/a/53397359\n    Author: https://stackoverflow.com/users/3647002/gayan-weerakutti\n    */\n    public static char[][] copy(char[][] array) {\n        return Arrays.stream(array).map(char[]::clone).toArray(char[][]::new);\n    }\n\n    public static char[][] flipVertically(char[][] board) {\n        char[][] newBoard = new char[7][7];\n\n        for (int row = 0; row < 7; row++) {\n            System.arraycopy(board[6 - row], 0, newBoard[row], 0, 7);\n        }\n\n        return newBoard;\n    }\n\n    public static char[][] flipHorizontally(char[][] board) {\n        char[][] newBoard = new char[7][7];\n\n        for (int row = 0; row < 7; row++) {\n            for (int column = 0; column < 7; column++) {\n                newBoard[row][column] = board[row][6 - column];\n            }\n        }\n\n        return newBoard;\n    }\n\n    public static char[][] rotateClockwise(char[][] board) {\n        char[][] newBoard = new char[7][7];\n\n        for (int row = 0; row < 7; row++) {\n            for (int column = 0; column < 7; column++) {\n                newBoard[column][6 - row] = board[row][column];\n            }\n        }\n\n        return newBoard;\n    }\n\n    public static char[][] removeFirstRow(char[][] board) {\n        List<char[]> list = new ArrayList<>(Arrays.asList(board));\n        list.remove(0);\n        return list.toArray(new char[][]{});\n    }\n\n    public static String toString(char[][] board) {\n        StringBuilder sb = new StringBuilder();\n        for (char[] row : board) {\n            for (char column : row) {\n                sb.append(column);\n            }\n        }\n        return sb.toString();\n    }\n\n    public static int findSolution(char[][] board, int depth, List<int[]> route) {\n        if (depth > 9) return 10;\n        String boardString = toString(board);\n        if (seenBoardStates.contains(boardString)) return 10; // this line turns 600 million iterations to 700 thousand\n        seenBoardStates.add(boardString);\n        if (hasOpenPath(board)) return depth;\n\n        char[][] floodFilledBoard = floodFillBottom(board);\n        List<int[]> newRoute = new ArrayList<>(route);\n        int solutionLength = 10;\n        int bestRow = -1;\n        int bestColumn = -1;\n        int bestDirection = -1;\n        for (int row = 0; row < 6; row++) {\n            for (int column = 0; column < 7; column++) {\n                iterations++;\n                if (floodFilledBoard[row][column] == 'X' && isTouchingOpenSpace(floodFilledBoard, row, column)) {\n                    if (canBePushed(floodFilledBoard, row, column, 'u')) {\n                        int solution = findSolution(push(board, row, column, 'u'), depth + 1, add(newRoute, new int[]{row, column, 1}));\n                        if (solution < solutionLength) {\n                            solutionLength = solution;\n                            bestRow = row;\n                            bestColumn = column;\n                            bestDirection = 1;\n                        }\n                    }\n                    if (canBePushed(floodFilledBoard, row, column, 'd')) {\n                        int solution = findSolution(push(board, row, column, 'd'), depth + 1, add(newRoute, new int[]{row, column, 2}));\n                        if (solution < solutionLength) {\n                            solutionLength = solution;\n                            bestRow = row;\n                            bestColumn = column;\n                            bestDirection = 2;\n                        }\n                    }\n                    if (canBePushed(floodFilledBoard, row, column, 'l')) {\n                        int solution = findSolution(push(board, row, column, 'l'), depth + 1, add(newRoute, new int[]{row, column, 3}));\n                        if (solution < solutionLength) {\n                            solutionLength = solution;\n                            bestRow = row;\n                            bestColumn = column;\n                            bestDirection = 3;\n                        }\n                    }\n                    if (canBePushed(floodFilledBoard, row, column, 'r')) {\n                        int solution = findSolution(push(board, row, column, 'r'), depth + 1, add(newRoute, new int[]{row, column, 4}));\n                        if (solution < solutionLength) {\n                            solutionLength = solution;\n                            bestRow = row;\n                            bestColumn = column;\n                            bestDirection = 4;\n                        }\n                    }\n                }\n            }\n        }\n\n        if (bestRow != -1) {\n            newRoute.add(0, new int[]{bestRow, bestColumn, bestDirection});\n        }\n        if (solutionLength < fastestSolution) {\n            fastestSolution = solutionLength;\n            newRoute.add(newRoute.remove(0)); // dont know why the last one goes first but this fixes it\n            BoulderSolver.route = new ArrayList<>(newRoute);\n        }\n        return solutionLength;\n    }\n\n    public static boolean canBePushed(char[][] floodFilledBoard, int row, int column, char direction) {\n        switch (direction) {\n            case 'u':\n                if (row > 0 && row < 5 && floodFilledBoard[row - 1][column] != 'X' && floodFilledBoard[row + 1][column] == 'O') return true;\n                break;\n            case 'd':\n                if (row > 0 && row < 5 && floodFilledBoard[row - 1][column] == 'O' && floodFilledBoard[row + 1][column] != 'X') return true;\n                break;\n            case 'l':\n                if (column > 0 && column < 6 && floodFilledBoard[row][column - 1] != 'X' && floodFilledBoard[row][column + 1] == 'O') return true;\n                break;\n            case 'r':\n                if (column > 0 && column < 6 && floodFilledBoard[row][column - 1] == 'O' && floodFilledBoard[row][column + 1] != 'X') return true;\n                break;\n        }\n        return false;\n    }\n\n    public static char[][] push(char[][] board, int row, int column, char direction) {\n        char[][] newBoard = copy(board);\n        switch (direction) {\n            case 'u':\n                newBoard[row - 1][column] = 'X';\n                break;\n            case 'd':\n                newBoard[row + 1][column] = 'X';\n                break;\n            case 'l':\n                newBoard[row][column - 1] = 'X';\n                break;\n            case 'r':\n                newBoard[row][column + 1] = 'X';\n        }\n        newBoard[row][column] = '\\0';\n        return newBoard;\n    }\n\n    public static boolean isTouchingOpenSpace(char[][] floodFilledBoard, int row, int column) {\n        return (row > 0 && floodFilledBoard[row - 1][column] == 'O') ||\n                (row < 5 && floodFilledBoard[row + 1][column] == 'O') ||\n                (column > 0 && floodFilledBoard[row][column - 1] == 'O') ||\n                (column < 6 && floodFilledBoard[row][column + 1] == 'O');\n    }\n\n    public static boolean hasOpenPath(char[][] board) {\n        char[][] newBoard = floodFillBottom(copy(board));\n        // Check if flood fill reached top\n        for (int column = 0; column < 7; column++) {\n            if (newBoard[0][column] == 'O') return true;\n        }\n        return false;\n    }\n\n    public static char[][] floodFillBottom(char[][] board) {\n        char[][] newBoard = copy(board);\n        for (int column = 0; column < 7; column++) {\n            if (newBoard[5][column] == '\\0') {\n                newBoard = floodFill(newBoard, 5, column);\n            }\n        }\n        return newBoard;\n    }\n\n    public static char[][] floodFill(char[][] board, int row, int column) {\n        if (row < 0 || row > 5 || column < 0 || column > 6) return board;\n        if (board[row][column] == '\\0') {\n            board[row][column] = 'O';\n            floodFill(board, row - 1, column);\n            floodFill(board, row + 1, column);\n            floodFill(board, row, column - 1);\n            floodFill(board, row, column + 1);\n            return board;\n        }\n        return board;\n    }\n\n    public static List<int[]> add(List<int[]> list, int[] arrayToAdd) {\n        List<int[]> newList = new ArrayList<>(list);\n        newList.add(arrayToAdd);\n        return newList;\n    }\n\n    public static AxisAlignedBB getBoulder(int row, int column, BlockPos chestLocation, String boulderRoomDirection) {\n        BlockPos boulderPosition;\n        switch (boulderRoomDirection) {\n            case \"north\":\n                boulderPosition = chestLocation.add(3 * column - 10, -2, 3 * row + 4);\n                break;\n            case \"east\":\n                boulderPosition = chestLocation.add(-3 * row - 6, -2, 3 * column - 10);\n                break;\n            case \"south\":\n                boulderPosition = chestLocation.add(-3 * column + 8, -2, -3 * row - 6);\n                break;\n            case \"west\":\n                boulderPosition = chestLocation.add(3 * row + 4, -2, -3 * column + 8);\n                break;\n            default:\n                return null;\n        }\n        return new AxisAlignedBB(boulderPosition.getX() - 0.01, boulderPosition.getY() - 0.01, boulderPosition.getZ() - 0.01, boulderPosition.getX() + 3.01, boulderPosition.getY() + 3.01, boulderPosition.getZ() + 3.01);\n    }\n\n    public static void drawArrow(AxisAlignedBB aabb, String boulderRoomDirection, char direction, int colourInt, float partialTicks) {\n        double averageX = (aabb.minX + aabb.maxX) / 2;\n        double thirtyPercent = (aabb.maxX - aabb.minX) * 0.3;\n        double averageZ = (aabb.minZ + aabb.maxZ) / 2;\n        if (((boulderRoomDirection.equals(\"north\") || boulderRoomDirection.equals(\"south\")) && (direction == 'u' || direction == 'd')) ||\n            ((boulderRoomDirection.equals(\"east\") || boulderRoomDirection.equals(\"west\")) && (direction == 'l' || direction == 'r'))) {\n            RenderUtils.draw3DLine(new Vec3(averageX, aabb.minY, aabb.minZ), new Vec3(averageX, aabb.minY, aabb.maxZ), colourInt, 10, false, partialTicks);\n        } else {\n            RenderUtils.draw3DLine(new Vec3(aabb.minX, aabb.minY, averageZ), new Vec3(aabb.maxX, aabb.minY, averageZ), colourInt, 10, false, partialTicks);\n        }\n\n        if ((boulderRoomDirection.equals(\"north\") && direction == 'u') || (boulderRoomDirection.equals(\"south\") && direction == 'd') ||\n            (boulderRoomDirection.equals(\"east\") && direction == 'l') || (boulderRoomDirection.equals(\"west\") && direction == 'r')) {\n            RenderUtils.draw3DLine(new Vec3(averageX, aabb.minY, aabb.minZ), new Vec3(aabb.minX + thirtyPercent, aabb.minY, aabb.minZ + thirtyPercent), colourInt, 10, false, partialTicks);\n            RenderUtils.draw3DLine(new Vec3(averageX, aabb.minY, aabb.minZ), new Vec3(aabb.maxX - thirtyPercent, aabb.minY, aabb.minZ + thirtyPercent), colourInt, 10, false, partialTicks);\n        } else if ((boulderRoomDirection.equals(\"north\") && direction == 'd') || (boulderRoomDirection.equals(\"south\") && direction == 'u') ||\n                    (boulderRoomDirection.equals(\"east\") && direction == 'r') || (boulderRoomDirection.equals(\"west\") && direction == 'l')) {\n            RenderUtils.draw3DLine(new Vec3(averageX, aabb.minY, aabb.maxZ), new Vec3(aabb.minX + thirtyPercent, aabb.minY, aabb.maxZ - thirtyPercent), colourInt, 10, false, partialTicks);\n            RenderUtils.draw3DLine(new Vec3(averageX, aabb.minY, aabb.maxZ), new Vec3(aabb.maxX - thirtyPercent, aabb.minY, aabb.maxZ - thirtyPercent), colourInt, 10, false, partialTicks);\n        } else if ((boulderRoomDirection.equals(\"north\") && direction == 'l') || (boulderRoomDirection.equals(\"south\") && direction == 'r') ||\n                    (boulderRoomDirection.equals(\"east\") && direction == 'd') || (boulderRoomDirection.equals(\"west\") && direction == 'u')) {\n            RenderUtils.draw3DLine(new Vec3(aabb.minX, aabb.minY, averageZ), new Vec3(aabb.minX + thirtyPercent, aabb.minY, aabb.minZ + thirtyPercent), colourInt, 10, false, partialTicks);\n            RenderUtils.draw3DLine(new Vec3(aabb.minX, aabb.minY, averageZ), new Vec3(aabb.minX + thirtyPercent, aabb.minY, aabb.maxZ - thirtyPercent), colourInt, 10, false, partialTicks);\n        } else {\n            RenderUtils.draw3DLine(new Vec3(aabb.maxX, aabb.minY, averageZ), new Vec3(aabb.maxX - thirtyPercent, aabb.minY, aabb.minZ + thirtyPercent), colourInt, 10, false, partialTicks);\n            RenderUtils.draw3DLine(new Vec3(aabb.maxX, aabb.minY, averageZ), new Vec3(aabb.maxX - thirtyPercent, aabb.minY, aabb.maxZ - thirtyPercent), colourInt, 10, false, partialTicks);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/utils/IceWalkUtils.java",
    "content": "package me.Danker.utils;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\npublic class IceWalkUtils {\n\n    public static List<Point> solve(char[][] board) {\n        Point startPos = new Point(board.length - 1, board[0].length / 2);\n        Point endPos = new Point(0, board[0].length / 2);\n        List<Point> route = new ArrayList<>();\n        route.add(startPos);\n        return findSolution(board, startPos, endPos, route);\n    }\n\n    public static List<Point> findSolution(char[][] board, Point startPos, Point endPos, List<Point> route) {\n        for (Direction direction : Direction.values()) {\n            Point nextPoint = move(board, startPos, direction);\n            if (nextPoint == null || route.contains(nextPoint)) continue;\n            List<Point> newRoute = new ArrayList<>(route);\n            newRoute.add(nextPoint);\n            if (nextPoint.equals(endPos) && isComplete(board, newRoute)) return newRoute;\n            List<Point> solution = findSolution(board, nextPoint, endPos, newRoute);\n            if (solution == null) continue;\n            return solution;\n        }\n        return null;\n    }\n\n    public static Point move(char[][] board, Point pos, Direction direction) {\n        switch (direction) {\n            case UP:\n                if (pos.row != 0 && board[pos.row - 1][pos.column] != 'X') {\n                    return new Point(pos.row - 1, pos.column);\n                }\n                break;\n            case DOWN:\n                if (pos.row != board.length - 1 && board[pos.row + 1][pos.column] != 'X') {\n                    return new Point(pos.row + 1, pos.column);\n                }\n                break;\n            case LEFT:\n                if (pos.column != 0 && board[pos.row][pos.column - 1] != 'X') {\n                    return new Point(pos.row, pos.column - 1);\n                }\n                break;\n            case RIGHT:\n                if (pos.column != board[0].length - 1 && board[pos.row][pos.column + 1] != 'X') {\n                    return new Point(pos.row, pos.column + 1);\n                }\n                break;\n        }\n        return null;\n    }\n\n    public static boolean isComplete(char[][] board, List<Point> route) {\n        for (int row = 0; row < board.length; row++) {\n            for (int column = 0; column < board[0].length; column++) {\n                if (board[row][column] != 'X' && !route.contains(new Point(row, column))) return false;\n            }\n        }\n        return true;\n    }\n\n    public static class Point {\n\n        public int row;\n        public int column;\n\n        public Point(int row, int column) {\n            this.row = row;\n            this.column = column;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(row, column);\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (obj instanceof Point) {\n                Point point = (Point) obj;\n                return row == point.row && column == point.column;\n            }\n            return false;\n        }\n\n    }\n\n    enum Direction {\n        UP,\n        DOWN,\n        LEFT,\n        RIGHT\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/utils/RenderUtils.java",
    "content": "package me.Danker.utils;\n\nimport cc.polyfrost.oneconfig.libs.universal.UResolution;\nimport me.Danker.features.CrystalHollowWaypoints;\nimport me.Danker.handlers.TextRenderer;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.gui.FontRenderer;\nimport net.minecraft.client.gui.Gui;\nimport net.minecraft.client.renderer.*;\nimport net.minecraft.client.renderer.entity.RenderManager;\nimport net.minecraft.client.renderer.vertex.DefaultVertexFormats;\nimport net.minecraft.entity.Entity;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.util.AxisAlignedBB;\nimport net.minecraft.util.BlockPos;\nimport net.minecraft.util.EnumChatFormatting;\nimport net.minecraft.util.Vec3;\nimport org.lwjgl.opengl.GL11;\n\nimport java.awt.*;\n\npublic class RenderUtils {\n\n    public static void drawTitle(String text) {\n        Minecraft mc = Minecraft.getMinecraft();\n\n        int height = UResolution.getScaledHeight();\n        int width = UResolution.getScaledWidth();\n        int drawHeight = 0;\n        String[] splitText = text.split(\"\\n\");\n        for (String title : splitText) {\n            int textLength = mc.fontRendererObj.getStringWidth(title);\n\n            double scale = 4;\n            if (textLength * scale > (width * 0.9F)) {\n                scale = (width * 0.9F) / (float) textLength;\n            }\n\n            int titleX = (int) ((width / 2) - (textLength * scale / 2));\n            int titleY = (int) ((height * 0.45) / scale) + (int) (drawHeight * scale);\n            TextRenderer.drawHUDText(title, titleX, titleY, scale);\n            drawHeight += mc.fontRendererObj.FONT_HEIGHT;\n        }\n    }\n\n    public static void drawOnSlot(int size, int xSlotPos, int ySlotPos, int colour) {\n        int guiLeft = (UResolution.getScaledWidth() - 176) / 2;\n        int guiTop = (UResolution.getScaledHeight() - 222) / 2;\n        int x = guiLeft + xSlotPos;\n        int y = guiTop + ySlotPos;\n        // Move down when chest isn't 6 rows\n        if (size != 90) y += (6 - (size - 36) / 9) * 9;\n\n        GL11.glTranslated(0, 0, 1);\n        Gui.drawRect(x, y, x + 16, y + 16, colour);\n        GL11.glTranslated(0, 0, -1);\n    }\n\n    public static void drawTextOnSlot(int size, int xSlotPos, int ySlotPos, String text) {\n        Minecraft mc = Minecraft.getMinecraft();\n        int guiLeft = (UResolution.getScaledWidth() - 176) / 2;\n        int guiTop = (UResolution.getScaledHeight() - 222) / 2;\n        int x = guiLeft + xSlotPos;\n        int y = guiTop + ySlotPos;\n        // Move down when chest isn't 6 rows\n        if (size != 90) y += (6 - (size - 36) / 9) * 9;\n\n        int width = mc.fontRendererObj.getStringWidth(text);\n        GL11.glTranslated(0, 0, 1);\n        mc.fontRendererObj.drawString(text, x + 8 - width / 2, y + 5, 0xFFFFFF, true);\n        GL11.glTranslated(0, 0, -1);\n    }\n\n    public static void draw3DLine(Vec3 pos1, Vec3 pos2, int colourInt, int lineWidth, boolean depth, float partialTicks) {\n        Entity render = Minecraft.getMinecraft().getRenderViewEntity();\n        WorldRenderer worldRenderer = Tessellator.getInstance().getWorldRenderer();\n        Color colour = new Color(colourInt);\n\n        double realX = render.lastTickPosX + (render.posX - render.lastTickPosX) * partialTicks;\n        double realY = render.lastTickPosY + (render.posY - render.lastTickPosY) * partialTicks;\n        double realZ = render.lastTickPosZ + (render.posZ - render.lastTickPosZ) * partialTicks;\n\n        GlStateManager.pushMatrix();\n        GlStateManager.translate(-realX, -realY, -realZ);\n        GlStateManager.disableTexture2D();\n        GlStateManager.enableBlend();\n        GlStateManager.disableAlpha();\n        GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);\n        GL11.glLineWidth(lineWidth);\n        if (!depth) {\n            GL11.glDisable(GL11.GL_DEPTH_TEST);\n            GlStateManager.depthMask(false);\n        }\n        GlStateManager.color(colour.getRed() / 255f, colour.getGreen() / 255f, colour.getBlue() / 255f, colour.getAlpha() / 255f);\n        worldRenderer.begin(GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION);\n\n        worldRenderer.pos(pos1.xCoord, pos1.yCoord, pos1.zCoord).endVertex();\n        worldRenderer.pos(pos2.xCoord, pos2.yCoord, pos2.zCoord).endVertex();\n        Tessellator.getInstance().draw();\n\n        GlStateManager.translate(realX, realY, realZ);\n        if (!depth) {\n            GL11.glEnable(GL11.GL_DEPTH_TEST);\n            GlStateManager.depthMask(true);\n        }\n        GlStateManager.disableBlend();\n        GlStateManager.enableAlpha();\n        GlStateManager.enableTexture2D();\n        GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);\n        GlStateManager.popMatrix();\n    }\n\n    public static void draw3DString(BlockPos pos, String text, int colour, float partialTicks) {\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayer player = mc.thePlayer;\n        double x = (pos.getX() - player.lastTickPosX) + ((pos.getX() - player.posX) - (pos.getX() - player.lastTickPosX)) * partialTicks;\n        double y = (pos.getY() - player.lastTickPosY) + ((pos.getY() - player.posY) - (pos.getY() - player.lastTickPosY)) * partialTicks;\n        double z = (pos.getZ() - player.lastTickPosZ) + ((pos.getZ() - player.posZ) - (pos.getZ() - player.lastTickPosZ)) * partialTicks;\n        RenderManager renderManager = mc.getRenderManager();\n\n        float f = 1.6F;\n        float f1 = 0.016666668F * f;\n        int width = mc.fontRendererObj.getStringWidth(text) / 2;\n        GlStateManager.pushMatrix();\n        GlStateManager.translate(x, y, z);\n        GL11.glNormal3f(0f, 1f, 0f);\n        GlStateManager.rotate(-renderManager.playerViewY, 0f, 1f, 0f);\n        GlStateManager.rotate(renderManager.playerViewX, 1f, 0f, 0f);\n        GlStateManager.scale(-f1, -f1, -f1);\n        GlStateManager.enableBlend();\n        GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);\n        mc.fontRendererObj.drawString(text, -width, 0, colour);\n        GlStateManager.disableBlend();\n        GlStateManager.popMatrix();\n    }\n\n    public static void draw3DString(double x, double y, double z, String text, int colour, float partialTicks) {\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayer player = mc.thePlayer;\n        double realX = (x - player.lastTickPosX) + ((x - player.posX) - (x - player.lastTickPosX)) * partialTicks;\n        double realY = (y - player.lastTickPosY) + ((y - player.posY) - (y - player.lastTickPosY)) * partialTicks;\n        double realZ = (z - player.lastTickPosZ) + ((z - player.posZ) - (z - player.lastTickPosZ)) * partialTicks;\n        RenderManager renderManager = mc.getRenderManager();\n\n        float f = 1.6F;\n        float f1 = 0.016666668F * f;\n        int width = mc.fontRendererObj.getStringWidth(text) / 2;\n        GlStateManager.pushMatrix();\n        GlStateManager.translate(realX, realY, realZ);\n        GL11.glNormal3f(0f, 1f, 0f);\n        GlStateManager.rotate(-renderManager.playerViewY, 0f, 1f, 0f);\n        GlStateManager.rotate(renderManager.playerViewX, 1f, 0f, 0f);\n        GlStateManager.scale(-f1, -f1, -f1);\n        GlStateManager.enableBlend();\n        GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);\n        mc.fontRendererObj.drawString(text, -width, 0, colour);\n        GlStateManager.disableBlend();\n        GlStateManager.popMatrix();\n    }\n\n    // I couldnt get waypoint strings to work so in the end I just copied from NEU\n    // If anyone sees this please help\n    /*public static void draw3DWaypointString(CrystalHollowWaypoints.Waypoint waypoint, float partialTicks) {\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayer player = mc.thePlayer;\n        BlockPos pos = waypoint.pos;\n        double x = (pos.getX() - player.lastTickPosX) + ((pos.getX() - player.posX) - (pos.getX() - player.lastTickPosX)) * partialTicks;\n        double y = (pos.getY() - player.lastTickPosY) + ((pos.getY() - player.posY) - (pos.getY() - player.lastTickPosY)) * partialTicks;\n        double z = (pos.getZ() - player.lastTickPosZ) + ((pos.getZ() - player.posZ) - (pos.getZ() - player.lastTickPosZ)) * partialTicks;\n\n        double distance = player.getDistance(x, y, z);\n        if (distance > 12) {\n            x *= 12 / distance;\n            y *= 12 / distance;\n            z *= 12 / distance;\n        }\n\n        RenderManager renderManager = mc.getRenderManager();\n        Entity viewer = Minecraft.getMinecraft().getRenderViewEntity();\n\n        float f = 1.6F;\n        float f1 = 0.016666668F * f;\n        int width = mc.fontRendererObj.getStringWidth(waypoint.location) / 2;\n        int width2 = mc.fontRendererObj.getStringWidth(waypoint.getDistance(player)) / 2;\n        GlStateManager.pushMatrix();\n        GlStateManager.translate(x, y, z);\n        GL11.glNormal3f(0f, 1f, 0f);\n        GlStateManager.rotate(-renderManager.playerViewY, 0f, 1f, 0f);\n        GlStateManager.rotate(renderManager.playerViewX, 1f, 0f, 0f);\n        GlStateManager.scale(-f1, -f1, -f1);\n        GlStateManager.enableBlend();\n        GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);\n        GL11.glDisable(GL11.GL_DEPTH_TEST);\n        GlStateManager.depthMask(false);\n\n        mc.fontRendererObj.drawString(waypoint.location, -width, 0, 0x55FFFF);\n\n        GlStateManager.rotate(-renderManager.playerViewY, 0.0F, 1.0F, 0.0F);\n        GlStateManager.rotate(renderManager.playerViewX, 1.0F, 0.0F, 0.0F);\n        GlStateManager.translate(0, -1, 0);\n        GlStateManager.rotate(-renderManager.playerViewX, 1.0F, 0.0F, 0.0F);\n        GlStateManager.rotate(renderManager.playerViewY, 0.0F, 1.0F, 0.0F);\n\n        mc.fontRendererObj.drawString(waypoint.getDistance(player), -width2, 0, 0xFFFF55);\n\n        GL11.glEnable(GL11.GL_DEPTH_TEST);\n        GlStateManager.depthMask(true);\n        GlStateManager.disableBlend();\n        GlStateManager.popMatrix();\n    }*/\n\n    // https://github.com/Moulberry/NotEnoughUpdates/blob/master/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DwarvenMinesWaypoints.java#L261\n    public static void draw3DWaypointString(CrystalHollowWaypoints.Waypoint waypoint, float partialTicks) {\n        GlStateManager.alphaFunc(516, 0.1F);\n\n        GlStateManager.pushMatrix();\n\n        Entity viewer = Minecraft.getMinecraft().getRenderViewEntity();\n        double viewerX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * partialTicks;\n        double viewerY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * partialTicks;\n        double viewerZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * partialTicks;\n\n        double x = waypoint.pos.getX()-viewerX+0.5f;\n        double y = waypoint.pos.getY()-viewerY-viewer.getEyeHeight();\n        double z = waypoint.pos.getZ()-viewerZ+0.5f;\n\n        double distSq = x*x + y*y + z*z;\n        double dist = Math.sqrt(distSq);\n        if(distSq > 144) {\n            x *= 12/dist;\n            y *= 12/dist;\n            z *= 12/dist;\n        }\n        GlStateManager.translate(x, y, z);\n        GlStateManager.translate(0, viewer.getEyeHeight(), 0);\n\n        renderNametag(EnumChatFormatting.AQUA + waypoint.location);\n\n        GlStateManager.rotate(-Minecraft.getMinecraft().getRenderManager().playerViewY, 0.0F, 1.0F, 0.0F);\n        GlStateManager.rotate(Minecraft.getMinecraft().getRenderManager().playerViewX, 1.0F, 0.0F, 0.0F);\n        GlStateManager.translate(0, -0.25f, 0);\n        GlStateManager.rotate(-Minecraft.getMinecraft().getRenderManager().playerViewX, 1.0F, 0.0F, 0.0F);\n        GlStateManager.rotate(Minecraft.getMinecraft().getRenderManager().playerViewY, 0.0F, 1.0F, 0.0F);\n\n        renderNametag(EnumChatFormatting.YELLOW + waypoint.getDistance(Minecraft.getMinecraft().thePlayer));\n\n        GlStateManager.popMatrix();\n\n        GlStateManager.disableLighting();\n    }\n\n    // https://github.com/Moulberry/NotEnoughUpdates/blob/master/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DwarvenMinesWaypoints.java#L300\n    public static void renderNametag(String str) {\n        FontRenderer fontrenderer = Minecraft.getMinecraft().fontRendererObj;\n        float f = 1.6F;\n        float f1 = 0.016666668F * f;\n        GlStateManager.pushMatrix();\n        GL11.glNormal3f(0.0F, 1.0F, 0.0F);\n        GlStateManager.rotate(-Minecraft.getMinecraft().getRenderManager().playerViewY, 0.0F, 1.0F, 0.0F);\n        GlStateManager.rotate(Minecraft.getMinecraft().getRenderManager().playerViewX, 1.0F, 0.0F, 0.0F);\n        GlStateManager.scale(-f1, -f1, f1);\n        GlStateManager.disableLighting();\n        GlStateManager.depthMask(false);\n        GlStateManager.disableDepth();\n        GlStateManager.enableBlend();\n        GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);\n        Tessellator tessellator = Tessellator.getInstance();\n        WorldRenderer worldrenderer = tessellator.getWorldRenderer();\n        int i = 0;\n\n        int j = fontrenderer.getStringWidth(str) / 2;\n        GlStateManager.disableTexture2D();\n        worldrenderer.begin(7, DefaultVertexFormats.POSITION_COLOR);\n        worldrenderer.pos(-j - 1, -1 + i, 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();\n        worldrenderer.pos(-j - 1, 8 + i, 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();\n        worldrenderer.pos(j + 1, 8 + i, 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();\n        worldrenderer.pos(j + 1, -1 + i, 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();\n        tessellator.draw();\n        GlStateManager.enableTexture2D();\n        fontrenderer.drawString(str, -fontrenderer.getStringWidth(str) / 2, i, 553648127);\n        GlStateManager.depthMask(true);\n\n        fontrenderer.drawString(str, -fontrenderer.getStringWidth(str) / 2, i, -1);\n\n        GlStateManager.enableDepth();\n        GlStateManager.enableBlend();\n        GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);\n        GlStateManager.popMatrix();\n    }\n\n    public static void draw3DBox(AxisAlignedBB aabb, int colourInt, float partialTicks) {\n        Entity render = Minecraft.getMinecraft().getRenderViewEntity();\n        Color colour = new Color(colourInt, true);\n\n        double realX = render.lastTickPosX + (render.posX - render.lastTickPosX) * partialTicks;\n        double realY = render.lastTickPosY + (render.posY - render.lastTickPosY) * partialTicks;\n        double realZ = render.lastTickPosZ + (render.posZ - render.lastTickPosZ) * partialTicks;\n\n        GlStateManager.pushMatrix();\n        GlStateManager.translate(-realX, -realY, -realZ);\n        GlStateManager.disableTexture2D();\n        GlStateManager.enableBlend();\n        GlStateManager.disableAlpha();\n        GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);\n        GL11.glLineWidth(2);\n\n        RenderGlobal.drawOutlinedBoundingBox(aabb, colour.getRed(), colour.getGreen(), colour.getBlue(), colour.getAlpha());\n\n        GlStateManager.translate(realX, realY, realZ);\n        GlStateManager.disableBlend();\n        GlStateManager.enableAlpha();\n        GlStateManager.enableTexture2D();\n        GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);\n        GlStateManager.popMatrix();\n    }\n\n    public static void drawFilled3DBox(AxisAlignedBB aabb, int colourInt, boolean translucent, boolean depth, float partialTicks) {\n        Entity render = Minecraft.getMinecraft().getRenderViewEntity();\n        WorldRenderer worldRenderer = Tessellator.getInstance().getWorldRenderer();\n        Color colour = new Color(colourInt);\n\n        double realX = render.lastTickPosX + (render.posX - render.lastTickPosX) * partialTicks;\n        double realY = render.lastTickPosY + (render.posY - render.lastTickPosY) * partialTicks;\n        double realZ = render.lastTickPosZ + (render.posZ - render.lastTickPosZ) * partialTicks;\n\n        GlStateManager.pushMatrix();\n        GlStateManager.pushAttrib();\n        GlStateManager.translate(-realX, -realY, -realZ);\n        GlStateManager.disableTexture2D();\n        GlStateManager.enableAlpha();\n        GlStateManager.enableBlend();\n        GlStateManager.disableCull();\n        GlStateManager.tryBlendFuncSeparate(770, translucent ? 1 : 771, 1, 0);\n        if (!depth) {\n            GL11.glDisable(GL11.GL_DEPTH_TEST);\n            GlStateManager.depthMask(false);\n        }\n        GlStateManager.color(colour.getRed() / 255f, colour.getGreen() / 255f, colour.getBlue() / 255f, colour.getAlpha() / 255f);\n        worldRenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION);\n        // Bottom\n        worldRenderer.pos(aabb.minX, aabb.minY, aabb.minZ).endVertex();\n        worldRenderer.pos(aabb.maxX, aabb.minY, aabb.minZ).endVertex();\n        worldRenderer.pos(aabb.maxX, aabb.minY, aabb.maxZ).endVertex();\n        worldRenderer.pos(aabb.minX, aabb.minY, aabb.maxZ).endVertex();\n        // Top\n        worldRenderer.pos(aabb.minX, aabb.maxY, aabb.minZ).endVertex();\n        worldRenderer.pos(aabb.maxX, aabb.maxY, aabb.minZ).endVertex();\n        worldRenderer.pos(aabb.maxX, aabb.maxY, aabb.maxZ).endVertex();\n        worldRenderer.pos(aabb.minX, aabb.maxY, aabb.maxZ).endVertex();\n        // West\n        worldRenderer.pos(aabb.minX, aabb.minY, aabb.minZ).endVertex();\n        worldRenderer.pos(aabb.minX, aabb.maxY, aabb.minZ).endVertex();\n        worldRenderer.pos(aabb.minX, aabb.maxY, aabb.maxZ).endVertex();\n        worldRenderer.pos(aabb.minX, aabb.minY, aabb.maxZ).endVertex();\n        // East\n        worldRenderer.pos(aabb.maxX, aabb.minY, aabb.minZ).endVertex();\n        worldRenderer.pos(aabb.maxX, aabb.maxY, aabb.minZ).endVertex();\n        worldRenderer.pos(aabb.maxX, aabb.maxY, aabb.maxZ).endVertex();\n        worldRenderer.pos(aabb.maxX, aabb.minY, aabb.maxZ).endVertex();\n        // North\n        worldRenderer.pos(aabb.minX, aabb.minY, aabb.minZ).endVertex();\n        worldRenderer.pos(aabb.maxX, aabb.minY, aabb.minZ).endVertex();\n        worldRenderer.pos(aabb.maxX, aabb.maxY, aabb.minZ).endVertex();\n        worldRenderer.pos(aabb.minX, aabb.maxY, aabb.minZ).endVertex();\n        // South\n        worldRenderer.pos(aabb.minX, aabb.minY, aabb.maxZ).endVertex();\n        worldRenderer.pos(aabb.maxX, aabb.minY, aabb.maxZ).endVertex();\n        worldRenderer.pos(aabb.maxX, aabb.maxY, aabb.maxZ).endVertex();\n        worldRenderer.pos(aabb.minX, aabb.maxY, aabb.maxZ).endVertex();\n        Tessellator.getInstance().draw();\n\n        GlStateManager.translate(realX, realY, realZ);\n        if (!depth) {\n            GL11.glEnable(GL11.GL_DEPTH_TEST);\n            GlStateManager.depthMask(true);\n        }\n        GlStateManager.enableCull();\n        GlStateManager.disableAlpha();\n        GlStateManager.disableBlend();\n        GlStateManager.enableTexture2D();\n        GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);\n        GlStateManager.popAttrib();\n        GlStateManager.popMatrix();\n    }\n\n    public static void renderItem(ItemStack stack, int x, int y, double scale) {\n        renderItem(stack, x, y, 0, scale);\n    }\n\n    public static void renderItem(ItemStack stack, int x, int y, int z, double scale) {\n        GlStateManager.enableRescaleNormal();\n        RenderHelper.enableGUIStandardItemLighting();\n\n        GlStateManager.pushMatrix();\n        GlStateManager.translate(x, y, z);\n        GlStateManager.scale(scale, scale, scale);\n\n        Minecraft.getMinecraft().getRenderItem().renderItemAndEffectIntoGUI(stack, 0, 0);\n\n        GlStateManager.popMatrix();\n\n        RenderHelper.disableStandardItemLighting();\n        GlStateManager.disableRescaleNormal();\n    }\n\n    public static void drawCenteredText(String text, int screenWidth, int height, double scale) {\n        Minecraft mc = Minecraft.getMinecraft();\n        int textWidth = mc.fontRendererObj.getStringWidth(text);\n        TextRenderer.drawText(text, screenWidth / 2 - textWidth / 2, height, scale);\n    }\n\n    public static void drawModalRectWithCustomSizedTexture(double x, double y, float u, float v, int width, int height, float textureWidth, float textureHeight)\n    {\n        float f = 1.0F / textureWidth;\n        float f1 = 1.0F / textureHeight;\n        Tessellator tessellator = Tessellator.getInstance();\n        WorldRenderer worldrenderer = tessellator.getWorldRenderer();\n        worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX);\n        worldrenderer.pos(x, y + height, 0.0D).tex(u * f, (v + (float)height) * f1).endVertex();\n        worldrenderer.pos(x + width, y + height, 0.0D).tex((u + (float)width) * f, (v + (float)height) * f1).endVertex();\n        worldrenderer.pos(x + width, y, 0.0D).tex((u + (float)width) * f, v * f1).endVertex();\n        worldrenderer.pos(x, y, 0.0D).tex(u * f, v * f1).endVertex();\n        tessellator.draw();\n    }\n\n    public static int getWidthFromText(String text) {\n        if (text == null) return 0;\n\n        FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;\n        String[] splitText = text.split(\"\\n\");\n\n        int width = 0;\n        for (String line : splitText) {\n            int stringLength = fr.getStringWidth(line);\n            if (stringLength > width) {\n                width = stringLength;\n            }\n        }\n\n        return width;\n    }\n\n    public static int getHeightFromText(String text) {\n        if (text == null) return 0;\n\n        FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;\n        String[] splitText = text.split(\"\\n\");\n        return splitText.length * fr.FONT_HEIGHT;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/utils/SilverfishUtils.java",
    "content": "package me.Danker.utils;\n\nimport java.util.*;\n\npublic class SilverfishUtils {\n\n    // bfs\n    public static List<Point> solve(char[][] board, Point startPos, List<Point> endColumns) {\n        LinkedList<Point> queue = new LinkedList<>();\n        Map<Point, Point> visited = new HashMap<>();\n        queue.add(startPos);\n        visited.put(startPos, null);\n        while (!queue.isEmpty()) {\n            if (queue.size() > 1000000) break;\n            Point position = queue.pollFirst();\n            for (Direction direction : Direction.values()) {\n                Point pushedPoint = push(board, position, direction);\n                if (visited.containsKey(pushedPoint)) continue;\n                queue.add(pushedPoint);\n                visited.put(pushedPoint, position);\n                for (Point endColumn : endColumns) {\n                    if (pushedPoint.equals(endColumn)) {\n                        List<Point> route = new ArrayList<>();\n                        Point lastPoint = pushedPoint;\n                        while (lastPoint != null) {\n                            route.add(0, lastPoint);\n                            lastPoint = visited.get(lastPoint);\n                        }\n                        return route;\n                    }\n                }\n            }\n        }\n        return new ArrayList<>();\n    }\n\n    public static Point push(char[][] board, Point pos, Direction direction) {\n        switch (direction) {\n            case UP:\n                for (int row = pos.row; row >= 0; row--) {\n                    if (board[row][pos.column] == 'X') {\n                        return new Point(row + 1, pos.column);\n                    }\n                }\n                return new Point(0, pos.column);\n            case DOWN:\n                for (int row = pos.row; row <= 18; row++) {\n                    if (board[row][pos.column] == 'X') {\n                        return new Point(row - 1, pos.column);\n                    }\n                }\n                return new Point(18, pos.column);\n            case LEFT:\n                for (int column = pos.column; column >= 0; column--) {\n                    if (board[pos.row][column] == 'X') {\n                        return new Point(pos.row, column + 1);\n                    }\n                }\n                return new Point(pos.row, 0);\n            case RIGHT:\n                for (int column = pos.column; column <= 18; column++) {\n                    if (board[pos.row][column] == 'X') {\n                        return new Point(pos.row, column - 1);\n                    }\n                }\n                return new Point(pos.row, 18);\n        }\n        return null;\n    }\n\n    public static class Point {\n\n        public int row;\n        public int column;\n\n        public Point(int row, int column) {\n            this.row = row;\n            this.column = column;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(row, column);\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (obj instanceof Point) {\n                Point point = (Point) obj;\n                return row == point.row && column == point.column;\n            }\n            return false;\n        }\n\n    }\n\n    enum Direction {\n        UP,\n        DOWN,\n        LEFT,\n        RIGHT\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/utils/TicTacToeUtils.java",
    "content": "package me.Danker.utils;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class TicTacToeUtils {\n\n    public static int getBestMove(char[][] board) {\n        HashMap<Integer, Integer> moves = new HashMap<>();\n        for (int row = 0; row < board.length; row++) {\n            for (int col = 0; col < board[row].length; col++) {\n                if (board[row][col] != '\\0') continue;\n                board[row][col] = 'O';\n                int score = minimax(board, false, 0);\n                board[row][col] = '\\0';\n                moves.put(row * 3 + col + 1, score);\n            }\n        }\n        return Collections.max(moves.entrySet(), Map.Entry.comparingByValue()).getKey();\n    }\n\n    public static boolean hasMovesLeft(char[][] board) {\n        for (char[] rows : board) {\n            for (char col : rows) {\n                if (col == '\\0') return true;\n            }\n        }\n        return false;\n    }\n\n    public static int getBoardRanking(char[][] board) {\n        for (int row = 0; row < 3; row++) {\n            if (board[row][0] == board[row][1] && board[row][0] == board[row][2]) {\n                if (board[row][0] == 'X') {\n                    return -10;\n                } else if (board[row][0] == 'O') {\n                    return 10;\n                }\n            }\n        }\n\n        for (int col = 0; col < 3; col++) {\n            if (board[0][col] == board[1][col] && board[0][col] == board[2][col]) {\n                if (board[0][col] == 'X') {\n                    return -10;\n                } else if (board[0][col] == 'O') {\n                    return 10;\n                }\n            }\n        }\n\n        if (board[0][0] == board[1][1] && board[0][0] == board[2][2]) {\n            if (board[0][0] == 'X') {\n                return -10;\n            } else if (board[0][0] == 'O') {\n                return 10;\n            }\n        } else if (board[0][2] == board[1][1] && board[0][2] == board[2][0]) {\n            if (board[0][2] == 'X') {\n                return -10;\n            } else if (board[0][2] == 'O') {\n                return 10;\n            }\n        }\n\n        return 0;\n    }\n\n    public static int minimax(char[][] board, boolean max, int depth) {\n        int score = getBoardRanking(board);\n        if (score == 10 || score == -10) return score;\n        if (!hasMovesLeft(board)) return 0;\n\n        if (max) {\n            int bestScore = -1000;\n            for (int row = 0; row < 3; row++) {\n                for (int col = 0; col < 3; col++) {\n                    if (board[row][col] == '\\0') {\n                        board[row][col] = 'O';\n                        bestScore = Math.max(bestScore, minimax(board, false, depth + 1));\n                        board[row][col] = '\\0';\n                    }\n                }\n            }\n            return bestScore - depth;\n        } else {\n            int bestScore = 1000;\n            for (int row = 0; row < 3; row++) {\n                for (int col = 0; col < 3; col++) {\n                    if (board[row][col] == '\\0') {\n                        board[row][col] = 'X';\n                        bestScore = Math.min(bestScore, minimax(board, true, depth + 1));\n                        board[row][col] = '\\0';\n                    }\n                }\n            }\n            return bestScore + depth;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/me/Danker/utils/Utils.java",
    "content": "package me.Danker.utils;\n\nimport com.google.gson.*;\nimport me.Danker.DankersSkyblockMod;\nimport me.Danker.config.CfgConfig;\nimport me.Danker.config.ModConfig;\nimport me.Danker.features.ColouredNames;\nimport me.Danker.features.GoldenEnchants;\nimport me.Danker.handlers.APIHandler;\nimport me.Danker.handlers.ScoreboardHandler;\nimport me.Danker.locations.DungeonFloor;\nimport me.Danker.locations.Location;\nimport net.minecraft.block.Block;\nimport net.minecraft.client.Minecraft;\nimport net.minecraft.client.network.NetworkPlayerInfo;\nimport net.minecraft.entity.item.EntityItem;\nimport net.minecraft.entity.item.EntityItemFrame;\nimport net.minecraft.entity.player.EntityPlayer;\nimport net.minecraft.init.Blocks;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.nbt.NBTTagCompound;\nimport net.minecraft.nbt.NBTTagList;\nimport net.minecraft.scoreboard.ScoreObjective;\nimport net.minecraft.util.*;\n\nimport java.awt.*;\nimport java.util.List;\nimport java.util.*;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\npublic class Utils {\n    \n    public static boolean inSkyblock = false;\n    public static Location currentLocation = Location.NONE;\n    public static DungeonFloor currentFloor = DungeonFloor.NONE;\n    public static int[] skillXPPerLevel = {0, 50, 125, 200, 300, 500, 750, 1000, 1500, 2000, 3500, 5000, 7500, 10000, 15000, 20000, 30000, 50000,\n                                           75000, 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000, 1100000,\n                                           1200000, 1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000, 2200000,\n                                           2300000, 2400000, 2500000, 2600000, 2750000, 2900000, 3100000, 3400000, 3700000, 4000000, 4300000,\n                                           4600000, 4900000, 5200000, 5500000, 5800000, 6100000, 6400000, 6700000, 7000000};\n    static int[] dungeonsXPPerLevel = {0, 50, 75, 110, 160, 230, 330, 470, 670, 950, 1340, 1890, 2665, 3760, 5260, 7380, 10300, 14400,\n                                      20000, 27600, 38000, 52500, 71500, 97000, 132000, 180000, 243000, 328000, 445000, 600000, 800000,\n                                      1065000, 1410000, 1900000, 2500000, 3300000, 4300000, 5600000, 7200000, 9200000, 12000000, 15000000,\n                                      19000000, 24000000, 30000000, 38000000, 48000000, 60000000, 75000000, 93000000, 116250000};\n    static int[] expertiseKills = {50, 100, 250, 500, 1000, 2500, 5500, 10000, 15000};\n    static Pattern boldPattern = Pattern.compile(\"(?i)\\\\u00A7L\");\n    static Map<Character, Integer> romanNumerals = new HashMap<Character, Integer>(){{\n        put('I', 1);\n        put('V', 5);\n        put('X', 10);\n        put('L', 50);\n        put('C', 100);\n        put('D', 500);\n        put('M', 1000);\n    }};\n    \n    public static int getItems(String item) {\n        Minecraft mc = Minecraft.getMinecraft();\n        EntityPlayer player = mc.thePlayer;\n        \n        double x = player.posX;\n        double y = player.posY;\n        double z = player.posZ;\n        AxisAlignedBB scan = new AxisAlignedBB(x - 6, y - 6, z - 6, x + 6, y + 6, z + 6);\n        List<EntityItem> items = mc.theWorld.getEntitiesWithinAABB(EntityItem.class, scan);\n        \n        for (EntityItem i : items) {\n            String itemName = StringUtils.stripControlCodes(i.getEntityItem().getDisplayName());\n            if (itemName.equals(item)) return i.getEntityItem().stackSize;\n        }\n        // No items found\n        return 0;\n    }\n    \n    public static String returnGoldenEnchants(String line) {\n        Matcher matcher = GoldenEnchants.t6EnchantPattern.matcher(line);\n        StringBuffer out = new StringBuffer();\n        \n        while (matcher.find()) {\n            matcher.appendReplacement(out, GoldenEnchants.t6Enchants.get(matcher.group(1)));\n        }\n        matcher.appendTail(out);\n        \n        return out.toString();\n    }\n    \n    public static List<String> getMatchingPlayers(String arg) {\n        List<String> matchingPlayers = new ArrayList<>();\n        Collection<NetworkPlayerInfo> players = Minecraft.getMinecraft().getNetHandler().getPlayerInfoMap();\n        \n        for (NetworkPlayerInfo player : players) {\n            String playerName = player.getGameProfile().getName();\n            if (playerName.startsWith(\"!\")) continue; // New tablist\n            if (playerName.toLowerCase().startsWith(arg.toLowerCase())) {\n                matchingPlayers.add(playerName);\n            }\n        }\n        \n        return matchingPlayers;\n    }\n    \n    public static void createTitle(String text, int seconds) {\n        Minecraft.getMinecraft().thePlayer.playSound(ModConfig.alertNoise, 1, (float) 0.5);\n        DankersSkyblockMod.titleTimer = seconds * 20;\n        DankersSkyblockMod.showTitle = true;\n        DankersSkyblockMod.titleText = text;\n    }\n\n    public static boolean isOnHypixel() {\n        Minecraft mc = Minecraft.getMinecraft();\n        if (mc != null && mc.theWorld != null && !mc.isSingleplayer()) {\n            if (mc.thePlayer != null && mc.thePlayer.getClientBrand() != null && mc.thePlayer.getClientBrand().toLowerCase().contains(\"hypixel\")) {\n                return true;\n            }\n            if (mc.getCurrentServerData().serverIP.toLowerCase().contains(\"hypixel\")) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static void checkForSkyblock() {\n        Minecraft mc = Minecraft.getMinecraft();\n        if (mc != null && mc.theWorld != null && !mc.isSingleplayer()) {\n            ScoreObjective scoreboardObj = mc.theWorld.getScoreboard().getObjectiveInDisplaySlot(1);\n            if (scoreboardObj != null) {\n                String scObjName = ScoreboardHandler.cleanSB(scoreboardObj.getDisplayName());\n                if (scObjName.contains(\"SKYBLOCK\")) {\n                    inSkyblock = true;\n                    return;\n                }\n            }\n        }\n        inSkyblock = false;\n    }\n\n    public static void checkTabLocation() {\n        if (inSkyblock) {\n            Collection<NetworkPlayerInfo> players = Minecraft.getMinecraft().getNetHandler().getPlayerInfoMap();\n            for (NetworkPlayerInfo player : players) {\n                if (player == null || player.getDisplayName() == null) continue;\n                String text = player.getDisplayName().getUnformattedText();\n                if (text.startsWith(\"Area: \") || text.startsWith(\"Dungeon: \")) {\n                    currentLocation = Location.fromTab(text.substring(text.indexOf(\":\") + 2));\n                    return;\n                }\n            }\n        }\n        currentLocation = Location.NONE;\n    }\n\n    public static boolean isInDungeons() { // update this whenever new dungeons come out\n        return currentLocation == Location.CATACOMBS;\n    }\n\n    public static void checkForDungeonFloor() {\n        if (isInDungeons()) {\n            List<String> scoreboard = ScoreboardHandler.getSidebarLines();\n\n            for (String s : scoreboard) {\n                String sCleaned = ScoreboardHandler.cleanSB(s);\n\n                if (sCleaned.contains(\"The Catacombs (\")) {\n                    String floor = sCleaned.substring(sCleaned.indexOf(\"(\") + 1, sCleaned.indexOf(\")\"));\n\n                    try {\n                        currentFloor = DungeonFloor.valueOf(floor);\n                    } catch (IllegalArgumentException ex) {\n                        currentFloor = DungeonFloor.NONE;\n                        ex.printStackTrace();\n                    }\n\n                    break;\n                }\n            }\n        } else {\n            currentFloor = DungeonFloor.NONE;\n        }\n    }\n\n    public static boolean isInScoreboard(String text) {\n        List<String> scoreboard = ScoreboardHandler.getSidebarLines();\n        for (String s : scoreboard) {\n            String sCleaned = ScoreboardHandler.cleanSB(s);\n            if (sCleaned.contains(text)) return true;\n        }\n        return false;\n    }\n    \n    public static String capitalizeString(String string) {\n        if (string == null) return null;\n        String[] words = string.split(\"_\");\n        \n        for (int i = 0; i < words.length; i++) {\n            if (words[i].length() < 2) words[i] = words[i].toUpperCase();\n            else words[i] = words[i].substring(0, 1).toUpperCase() + words[i].substring(1).toLowerCase();\n        }\n        \n        return String.join(\" \", words);\n    }\n    \n    public static double getPercentage(int num1, int num2) {\n        if (num2 == 0) return 0D;\n        double result = ((double) num1 * 100D) / (double) num2;\n        result = Math.round(result * 100D) / 100D;\n        return result;\n    }\n    \n    public static String getTimeBetween(double timeOne, double timeTwo) {\n        double secondsBetween = Math.floor(timeTwo - timeOne);\n        \n        String timeFormatted;\n        int days;\n        int hours;\n        int minutes;\n        int seconds;\n        \n        if (secondsBetween > 86400) {\n            // More than 1d, display #d#h\n            days = (int) (secondsBetween / 86400);\n            hours = (int) (secondsBetween % 86400 / 3600);\n            timeFormatted = days + \"d\" + hours + \"h\";\n        } else if (secondsBetween > 3600) {\n            // More than 1h, display #h#m\n            hours = (int) (secondsBetween / 3600);\n            minutes = (int) (secondsBetween % 3600 / 60);\n            timeFormatted = hours + \"h\" + minutes + \"m\";\n        } else {\n            // Display #m#s\n            minutes = (int) (secondsBetween / 60);\n            seconds = (int) (secondsBetween % 60);\n            timeFormatted = minutes + \"m\" + seconds + \"s\";\n        }\n        \n        return timeFormatted;\n    }\n    \n    public static String getMoneySpent(double coins) {\n        double coinsSpentMillions = coins / 1000000D;\n        coinsSpentMillions = Math.floor(coinsSpentMillions * 100D) / 100D;\n        return coinsSpentMillions + \"M\";\n    }\n    \n    public static double xpToSkillLevel(double xp, int limit) {\n        for (int i = 0, xpAdded = 0; i < limit + 1; i++) {\n            xpAdded += skillXPPerLevel[i];\n            if (xp < xpAdded) {\n                return (i - 1) + (xp - (xpAdded - skillXPPerLevel[i])) / skillXPPerLevel[i];\n            }\n        }\n        return limit;\n    }\n\n    public static int skillLevelToXp(int level) {\n        int sum = 0;\n\n        for (int i = 1; i <= level; i++) {\n            sum += skillXPPerLevel[i];\n        }\n\n        return sum;\n    }\n    \n    public static double xpToDungeonsLevel(double xp) {\n        for (int i = 0, xpAdded = 0; i < dungeonsXPPerLevel.length; i++) {\n            xpAdded += dungeonsXPPerLevel[i];\n            if (xp < xpAdded) {\n                double level =  (i - 1) + (xp - (xpAdded - dungeonsXPPerLevel[i])) / dungeonsXPPerLevel[i];\n                return (double) Math.round(level * 100D) / 100;\n            }\n        }\n        return 50D + MathHelper.clamp_double(Math.round((xp - 569809640D) / 200000000D * 100D) / 100D, 0D, 49D);\n    }\n    \n    public static int expertiseKillsLeft(int kills) {\n        for (int i = 0; i < expertiseKills.length; i++) {\n            if (kills < expertiseKills[i]) {\n                return expertiseKills[i] - kills;\n            }\n        }\n        return -1;\n    }\n\n    // Only used when over limit\n    public static int getPastXpEarned(int currentLevelXp, int limit) {\n        if (currentLevelXp == 0) {\n            int xpAdded = 0;\n            for (int i = 1; i <= limit; i++) {\n                xpAdded += skillXPPerLevel[i];\n            }\n            return xpAdded;\n        }\n        for (int i = 1, xpAdded = 0; i <= limit; i++) {\n            xpAdded += skillXPPerLevel[i - 1];\n            if (currentLevelXp == skillXPPerLevel[i]) return xpAdded;\n        }\n        return 0;\n    }\n\n    public static double getTotalXpEarned(int currentLevel, double percentage) {\n        double progress = 0;\n        if (currentLevel < 60) progress = skillXPPerLevel[currentLevel + 1] * (percentage / 100D);\n        double xpAdded = 0;\n        for (int i = 1; i <= currentLevel; i++) {\n            xpAdded += skillXPPerLevel[i];\n        }\n        return xpAdded + progress;\n    }\n    \n    public static String getColouredBoolean(boolean bool) {\n        return bool ? EnumChatFormatting.GREEN + \"On\" : EnumChatFormatting.RED + \"Off\";\n    }\n\n    // Taken from SkyblockAddons\n    public static List<String> getItemLore(ItemStack itemStack) {\n        final int NBT_INTEGER = 3;\n        final int NBT_STRING = 8;\n        final int NBT_LIST = 9;\n        final int NBT_COMPOUND = 10;\n\n        if (itemStack.hasTagCompound() && itemStack.getTagCompound().hasKey(\"display\", NBT_COMPOUND)) {\n            NBTTagCompound display = itemStack.getTagCompound().getCompoundTag(\"display\");\n\n            if (display.hasKey(\"Lore\", NBT_LIST)) {\n                NBTTagList lore = display.getTagList(\"Lore\", NBT_STRING);\n\n                List<String> loreAsList = new ArrayList<>();\n                for (int lineNumber = 0; lineNumber < lore.tagCount(); lineNumber++) {\n                    loreAsList.add(lore.getStringTagAt(lineNumber));\n                }\n\n                return Collections.unmodifiableList(loreAsList);\n            }\n        }\n\n        return Collections.emptyList();\n    }\n\n    public static boolean hasRightClickAbility(ItemStack itemStack) {\n        return Utils.getItemLore(itemStack).stream().anyMatch(line -> {\n            String stripped = StringUtils.stripControlCodes(line);\n            return stripped.startsWith(\"Item Ability:\") && stripped.endsWith(\"RIGHT CLICK\");\n        });\n    }\n    \n    public static BlockPos getFirstBlockPosAfterVectors(Minecraft mc, Vec3 pos1, Vec3 pos2, int strength, int distance) {\n        double x = pos2.xCoord - pos1.xCoord;\n        double y = pos2.yCoord - pos1.yCoord;\n        double z = pos2.zCoord - pos1.zCoord;\n        \n        for (int i = strength; i < distance * strength; i++) { // Start at least 1 strength away\n            double newX = pos1.xCoord + ((x / strength) * i);\n            double newY = pos1.yCoord + ((y / strength) * i);\n            double newZ = pos1.zCoord + ((z / strength) * i);\n            \n            BlockPos newBlock = new BlockPos(newX, newY, newZ);\n            if (mc.theWorld.getBlockState(newBlock).getBlock() != Blocks.air) {\n                return newBlock;\n            }\n        }\n        \n        return null;\n    }\n    \n    public static BlockPos getNearbyBlock(Minecraft mc, BlockPos pos, Block... blockTypes) {\n        if (pos == null) return null;\n        BlockPos pos1 = new BlockPos(pos.getX() - 2, pos.getY() - 3, pos.getZ() - 2);\n        BlockPos pos2 = new BlockPos(pos.getX() + 2, pos.getY() + 3, pos.getZ() + 2);\n        \n        BlockPos closestBlock = null;\n        double closestBlockDistance = 99;\n        Iterable<BlockPos> blocks = BlockPos.getAllInBox(pos1, pos2);\n        \n        for (BlockPos block : blocks) {\n            for (Block blockType : blockTypes) {\n                if (mc.theWorld.getBlockState(block).getBlock() == blockType && block.distanceSq(pos) < closestBlockDistance) {\n                    closestBlock = block;\n                    closestBlockDistance = block.distanceSq(pos);\n                }\n            }\n        }\n        \n        return closestBlock;\n    }\n    \n    public static BlockPos getBlockUnderItemFrame(EntityItemFrame itemFrame) {\n        switch (itemFrame.facingDirection) {\n            case NORTH:\n                return new BlockPos(itemFrame.posX, itemFrame.posY, itemFrame.posZ + 1);\n            case EAST:\n                return new BlockPos(itemFrame.posX - 1, itemFrame.posY, itemFrame.posZ - 0.5);\n            case SOUTH:\n                return new BlockPos(itemFrame.posX, itemFrame.posY, itemFrame.posZ - 1);\n            case WEST:\n                return new BlockPos(itemFrame.posX + 1, itemFrame.posY, itemFrame.posZ - 0.5);\n            default:\n                return null;\n        }\n    }\n\n    public static boolean isRealPlayer(EntityPlayer player) {\n        return player.getUniqueID().version() == 4 && !player.isPlayerSleeping();\n    }\n\n    public static String removeBold(String text) {\n        return boldPattern.matcher(text).replaceAll(\"\");\n    }\n\n    public static int getIntFromString(String text, boolean romanNumeral) {\n        if (text.matches(\".*\\\\d.*\")) {\n            return Integer.parseInt(StringUtils.stripControlCodes(text).replaceAll(\"\\\\D\", \"\"));\n        } else if (romanNumeral) {\n            int number = 0;\n\n            for (int i = 0; i < text.length(); i++) {\n                if (!romanNumerals.containsKey(text.charAt(i))) continue;\n                int roman = romanNumerals.get(text.charAt(i));\n\n                if (i != text.length() - 1 && romanNumerals.containsKey(text.charAt(i + 1)) && roman < romanNumerals.get(text.charAt(i + 1))) {\n                    number += romanNumerals.get(text.charAt(i + 1)) - roman;\n                    i++;\n                } else {\n                    number += roman;\n                }\n            }\n\n            return number;\n        }\n\n        return -1;\n    }\n\n    public static boolean skillsInitialized() {\n        return DankersSkyblockMod.miningLevel != -1;\n    }\n\n    public static int initializeSkill(ItemStack skillStack, String configValue) {\n        int level = -1;\n\n        if (skillStack != null) {\n            String display = skillStack.getDisplayName();\n            if (display.startsWith(\"§a\")) {\n                if (display.contains(\" \")) {\n                    level = Utils.getIntFromString(display.substring(display.indexOf(\" \") + 1), true);\n                } else {\n                    level = 0;\n                }\n            }\n        }\n\n        CfgConfig.writeIntConfig(\"skills\", configValue, level);\n        return level;\n    }\n\n    public static void refreshRepo() {\n        DankersSkyblockMod.data = APIHandler.getResponse(\"https://raw.githubusercontent.com/bowser0000/SkyblockMod-REPO/main/data.json\", false);\n        System.out.println(\"Loaded data from GitHub?: \" + (DankersSkyblockMod.data != null && DankersSkyblockMod.data.has(\"trivia\")));\n        ColouredNames.users = DankersSkyblockMod.data.getAsJsonObject(\"colourednames\").entrySet().stream()\n                .map(Map.Entry::getKey)\n                .collect(Collectors.toCollection(ArrayList::new));\n        System.out.println(\"Refreshed DSM repo at \" + System.currentTimeMillis());\n    }\n\n    public static int getCooldownFromAbility(String ability) {\n        EntityPlayer player = Minecraft.getMinecraft().thePlayer;\n        boolean foundAbility = false;\n\n        List<ItemStack> itemsToSearch = new ArrayList<>();\n\n        for (int i = 0; i < 8; i++) {\n            ItemStack hotbarItem = player.inventory.getStackInSlot(i);\n            if (hotbarItem == null) continue;\n            itemsToSearch.add(hotbarItem);\n        }\n\n        for (int i = 0; i < 4; i++) {\n            ItemStack armorItem = player.inventory.armorItemInSlot(0);\n            if (armorItem == null) continue;\n            itemsToSearch.add(armorItem);\n        }\n\n        for (ItemStack item : itemsToSearch) {\n            if (foundAbility) break;\n            List<String> tooltip = item.getTooltip(player, false);\n\n            for (String line : tooltip) {\n                if (line.contains(EnumChatFormatting.GOLD + \"Ability: \") || line.contains(EnumChatFormatting.GOLD + \"Full Set Bonus: \")) {\n                    if (line.contains(EnumChatFormatting.GOLD + \"Ability: \" + ability)) {\n                        foundAbility = true;\n                        continue;\n                    } else if (foundAbility) {\n                        break;\n                    }\n                }\n\n                if (foundAbility && line.contains(EnumChatFormatting.DARK_GRAY + \"Cooldown: \")) {\n                    return Integer.parseInt(StringUtils.stripControlCodes(line).replaceAll(\"\\\\D\", \"\"));\n                }\n            }\n        }\n\n        return 0;\n    }\n\n    public static double getCooldownReductionFromLevel(int level) {\n        return (Math.floor(level / 2D) + 25) / 100D;\n    }\n\n    public static void desktopNotification(String name, String title, String text, TrayIcon.MessageType messageType) {\n        try {\n            final SystemTray tray = SystemTray.getSystemTray();\n            final Image image = Toolkit.getDefaultToolkit().createImage(\"icon.png\");\n            final TrayIcon trayIcon = new TrayIcon(image, name);\n            trayIcon.setImageAutoSize(true);\n            trayIcon.setToolTip(name);\n            tray.add(trayIcon);\n            trayIcon.displayMessage(title, text, messageType);\n            tray.remove(trayIcon);\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    public static JsonObject deepCopy(JsonObject obj) {\n        JsonObject newObj = new JsonObject();\n\n        for (Map.Entry<String, JsonElement> entry : obj.entrySet()) {\n            newObj.add(entry.getKey(), entry.getValue());\n        }\n\n        return newObj;\n    }\n\n    public static JsonArray deepCopy(JsonArray array) {\n        JsonArray newArray = new JsonArray();\n\n        for (JsonElement element : array) {\n            if (element.isJsonObject()) {\n                newArray.add(deepCopy(element.getAsJsonObject()));\n            } else if (element.isJsonArray()) {\n                newArray.add(deepCopy(element.getAsJsonArray()));\n            } else  {\n                newArray.add(element);\n            }\n        }\n\n        return newArray;\n    }\n\n    // https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/java/codes/biscuit/skyblockaddons/utils/ItemUtils.java#L139-L148\n    public static NBTTagCompound getExtraAttributes(ItemStack item) {\n        if (item == null || !item.hasTagCompound()) return null;\n        return item.getSubCompound(\"ExtraAttributes\", false);\n    }\n\n    // https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/java/codes/biscuit/skyblockaddons/utils/ItemUtils.java#L116-L131\n    public static String getSkyblockItemID(ItemStack item) {\n        if (item == null) return null;\n\n        NBTTagCompound extraAttributes = getExtraAttributes(item);\n        if (extraAttributes == null || !extraAttributes.hasKey(\"id\", 8)) return null;\n\n        return extraAttributes.getString(\"id\");\n    }\n\n    public static JsonObject getTrophyFromAPI(JsonObject obj, String name) {\n        JsonObject tiers = new JsonObject();\n\n        tiers.addProperty(\"BRONZE\", obj.has(name + \"_bronze\") ? obj.get(name + \"_bronze\").getAsInt() : 0);\n        tiers.addProperty(\"SILVER\", obj.has(name + \"_silver\") ? obj.get(name + \"_silver\").getAsInt() : 0);\n        tiers.addProperty(\"GOLD\", obj.has(name + \"_gold\") ? obj.get(name + \"_gold\").getAsInt() : 0);\n        tiers.addProperty(\"DIAMOND\", obj.has(name + \"_diamond\") ? obj.get(name + \"_diamond\").getAsInt() : 0);\n\n        return tiers;\n    }\n\n    public static boolean isJson(String obj) {\n        try {\n            new JsonParser().parse(obj);\n        } catch (JsonSyntaxException ex) {\n            return false;\n        }\n        return true;\n    }\n\n    public static int parseInt(String integer){\n        String cleanInt = integer.replaceAll(\"\\\\D\", \"\");\n        return Integer.parseInt(cleanInt);\n    }\n\n    public static JsonObject getObjectFromPath(JsonObject obj, String path) {\n        if (obj == null) return null;\n\n        String[] split = path.split(\"\\\\.\");\n        JsonObject newObj = obj;\n\n        for (String id : split) {\n            if (!newObj.has(id)) {\n                System.out.println(id + \" does not exist in path \" + path);\n                return null;\n            }\n\n            newObj = newObj.getAsJsonObject(id);\n        }\n\n        return newObj;\n    }\n\n    public static int getSkillMaxLevel(String skill) {\n        if (DankersSkyblockMod.data == null) return 50;\n        return DankersSkyblockMod.data.getAsJsonObject(\"skills\").get(skill).getAsInt();\n    }\n\n}\n"
  },
  {
    "path": "src/main/resources/mcmod.info",
    "content": "[\n{\n  \"modid\": \"${id}\",\n  \"name\": \"${name}\",\n  \"description\": \"QOL changes that enhances your Hypixel Skyblock experience.\",\n  \"version\": \"${version}\",\n  \"mcversion\": \"${mcVersionStr}\",\n  \"url\": \"https://github.com/bowser0000/SkyblockMod\",\n  \"authorList\": [\"Danker\"]\n}\n]\n"
  },
  {
    "path": "versions/mainProject",
    "content": "1.8.9-forge"
  }
]