[
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "<!-- Please make sure to read the following carefully.\n- Please do not post issues for unimplemented features, or updates.\n- No support will be provided for modified versions of GoMine.\n- Please fill out all fields and be as detailed as possible.\n-->\n\n#### Description\n<!-- \nWrite a detailed description about your issue.\nWhat happened? What did you expect to happen?\n-->\n\n\n#### Information\n<!-- Enter some of your information so we can trace the issue. -->\n* GoMine Version:\n<!-- 0.0.1 -->\n* GoMine Commit/Release:\n<!-- ddeafab63b55e4558a634dc007e32211152cb0a8/0.0.1 Release -->\n* Operating System:\n<!-- Windows/Linux -->\n* Game Variant:\n<!-- PE/W10/XBOX -->\n\n\n#### Plugins\n<!-- \nWhat plugins did you use when this issue occurred?\nHave you tried reproducing without any plugins? Did it still happen?\n-->\n\n\n#### Crash/Error\n<!-- Please post any error or crash that may have occurred between the triple quotes below. -->\n```go\n\n```\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea/\nextensions/\nworlds/\ngomine.log\ngomine.yml\ngomine.exe"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://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 <http://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<http://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<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "README.md",
    "content": "<a href=\"https://github.com/Irmine/GoMine\">\n    <img src=\"https://github.com/Irmine/GoMine/blob/master/GoMineBanner.jpg\" width=\"600\" height=\"200\" align=\"left\">\n</a> <br> <br> <br> <br> <br> <br> <br> <br> <hr>\n\n#### GoMine is a Minecraft Bedrock Edition server software written in Go.\n\n### Information\nGoMine is a fast multi-threaded Minecraft server software. It aims to provide a highly customizable API for plugin developers to use. GoMine aims to make the setup of a server very easy, (through an executable) with low compile times, and aims to make GoMine usable for other purposes than just a vanilla server.\n\n### Current State\nGoMine is currently under heavy development and is not usable for production servers yet. It lacks many features which are yet to be implemented, and has (yet unknown) bugs that should be resolved.\n\n### Releases and Development Builds\nDevelopment builds of GoMine might be unstable and should be used with care. It is always recommended to run officially released versions of GoMine for production where possible, to ensure no nasty bugs appear. If you do decide to run a development version, be aware that bugs may occur. Don't hesitate to report those bugs.\n\n### Setup\nGoMine aims to make the setup of a server very easily. The setup of GoMine can be explained in a couple steps.\nIf you want to use an official release:\n1. Download the executable for your operating system from `Releases` and move it to your setup directory.\n2. Execute the executable to run the server.\n\nIf you would like to use a development version:\n1. Install Go > 1.9 from the official release page.\n2. To clone the repository, execute `go get github.com/irmine/gomine`.\n3. Compile GoMine by navigating into the `irmine/gomine` folder and executing `go install`.\n4. Navigate to the folder at `GOBIN`, and grab the executable.\n5. Move it to your setup folder and execute the executable.\n\n### Issues\nIssues can be reported in the `Issues` tab. Please provide enough information for us to solve the problem. The more information you provide, the easier it makes it for us to fix your issue.\n\n### License\nGoMine is licensed under the GNU General Public License.\n"
  },
  {
    "path": "cmd/gomine/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/irmine/gomine\"\n\t\"github.com/irmine/gomine/resources\"\n\t\"github.com/irmine/gomine/text\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n)\n\nfunc main() {\n\tstartTime := time.Now()\n\tpath, err := GetServerPath()\n\tmust(err)\n\tSetUpDirectories(path)\n\n\tconfig := resources.NewGoMineConfig(path)\n\tserver := gomine.NewServer(path, config)\n\n\tmust(server.Start())\n\ttext.DefaultLogger.Info(\"Server startup done! Took:\", time.Now().Sub(startTime))\n\n\tvar ticker = time.NewTicker(time.Millisecond * 50)\n\tfor {\n\t\tselect{\n\t\tcase <- ticker.C:\n\t\t\tif !server.IsRunning() {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tserver.Tick()\n\t\t}\n\t}\n}\n\nfunc must(err error) {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// GetServerPath returns the server path.\nfunc GetServerPath() (string, error) {\n\texecutable, err := os.Executable()\n\treturn strings.Replace(filepath.Dir(executable)+\"/\", `\\`, \"/\", -1), err\n}\n\n// SetUpDirectories sets up all directories needed for GoMine.\nfunc SetUpDirectories(path string) {\n\tos.Mkdir(path+\"extensions\", 0700)\n\tos.Mkdir(path+\"extensions/plugins\", 0700)\n\tos.Mkdir(path+\"extensions/behavior_packs\", 0700)\n\tos.Mkdir(path+\"extensions/resource_packs\", 0700)\n}\n"
  },
  {
    "path": "cmd/gomine/shared_server_test.go",
    "content": "package main\n\nimport (\n\t\"github.com/irmine/gomine\"\n\t\"github.com/irmine/gomine/resources\"\n\t\"github.com/irmine/gomine/text\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestSharedServer(t *testing.T) {\n\tports := []uint16{19132, 19133, 19134, 19135, 19136}\n\tfor _, port := range ports {\n\t\tgo StartServer(port)\n\t}\n\ttime.Sleep(time.Minute * 10)\n}\n\nfunc StartServer(port uint16) {\n\ttext.DefaultLogger.Info(\"Starting server with port:\", port)\n\tstartTime := time.Now()\n\tpath, err := GetServerPath()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tSetUpDirectories(path)\n\tconfig := resources.NewGoMineConfig(path)\n\tconfig.ServerPort = port\n\tserver := gomine.NewServer(path, config)\n\n\tif err := server.Start(); err != nil {\n\t\tpanic(err)\n\t}\n\ttext.DefaultLogger.Info(\"Server startup done! Took:\", time.Now().Sub(startTime))\n\n\tfor range time.NewTicker(time.Second / 20).C {\n\t\tif !server.IsRunning() {\n\t\t\tbreak\n\t\t}\n\t\tserver.Tick()\n\t}\n}\n"
  },
  {
    "path": "commands/arguments/argument.go",
    "content": "package arguments\n\nimport \"strconv\"\n\ntype Argument struct {\n\tname               string\n\toptional           bool\n\tinputArgs          int\n\toutput             interface{}\n\tvalidationFunction func(argument string) bool\n\tconversionFunction func(argument string) interface{}\n\tshouldMerge        bool\n}\n\n// GetName returns the name of the argument.\nfunc (argument *Argument) GetName() string {\n\treturn argument.name\n}\n\n// SetName sets the name of the argument.\nfunc (argument *Argument) SetName(name string) {\n\targument.name = name\n}\n\n// IsOptional checks if the argument is optional.\nfunc (argument *Argument) IsOptional() bool {\n\treturn argument.optional\n}\n\n// SetOptional sets the argument optional or non-optional.\nfunc (argument *Argument) SetOptional(value bool) {\n\targument.optional = value\n}\n\n// GetInputAmount returns the amount of arguments of input this argument requires.\nfunc (argument *Argument) GetInputAmount() int {\n\treturn argument.inputArgs\n}\n\n// SetInputAmount sets the amount of arguments the input of this argument requires.\nfunc (argument *Argument) SetInputAmount(amount int) {\n\targument.inputArgs = amount\n}\n\n// SetOutput sets the output value of this argument.\nfunc (argument *Argument) SetOutput(value interface{}) {\n\targument.output = value\n}\n\n// GetOutput returns the output value of this argument.\nfunc (argument *Argument) GetOutput() interface{} {\n\treturn argument.output\n}\n\n// ShouldMerge returns whether this argument should merge all its values or not.\nfunc (argument *Argument) ShouldMerge() bool {\n\treturn argument.shouldMerge\n}\n\n// IsValidValue checks if the given value is valid for the argument.\nfunc (argument *Argument) IsValidValue(value string) bool {\n\treturn argument.validationFunction(value)\n}\n\n// ConvertValues returns the converted value of the value.\nfunc (argument *Argument) ConvertValue(value string) interface{} {\n\treturn argument.conversionFunction(value)\n}\n\n// IsInt checks if the input string is able to be parsed as an integer.\nfunc IsInt(value string) bool {\n\tvar _, err = strconv.Atoi(value)\n\treturn err == nil\n}\n\n// IsFloat checks if the input string is able to be parsed as an integer.\nfunc IsFloat(value string) bool {\n\tvar _, err = strconv.ParseFloat(value, 64)\n\treturn err == nil\n}"
  },
  {
    "path": "commands/arguments/basic.go",
    "content": "package arguments\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n)\n\n// NewFloat returns a new Float argument with the given name and optional value.\nfunc NewFloat(name string, optional bool) *Argument {\n\treturn &Argument{name, optional, 1, float64(0), func(value string) bool {\n\t\treturn IsFloat(value)\n\t}, func(value string) interface{} {\n\t\tvar float, _ = strconv.ParseFloat(value, 64)\n\t\treturn float\n\t}, false}\n}\n\n// NewInt returns a new Int argument with the given name and optional value.\nfunc NewInt(name string, optional bool) *Argument {\n\treturn &Argument{name, optional, 1, 0, func(value string) bool {\n\t\treturn IsInt(value)\n\t}, func(value string) interface{} {\n\t\tvar i, _ = strconv.ParseInt(value, 10, 64)\n\t\treturn i\n\t}, false}\n}\n\n// NewString returns a new String argument with the given name and optional value.\nfunc NewString(name string, optional bool) *Argument {\n\tvar arg = &Argument{name, optional, 1, \"\", func(value string) bool {\n\t\treturn true\n\t}, func(value string) interface{} {\n\t\treturn value\n\t}, true}\n\treturn arg\n}\n\n// NewStringEnum returns a new String Enum argument with the given name and optional value.\nfunc NewStringEnum(name string, optional bool, options []string) *Argument {\n\tvar arg = &Argument{name, optional, 1, \"\", func(value string) bool {\n\t\tfor _, option := range options {\n\t\t\tif strings.ToLower(option) == strings.ToLower(value) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\treturn false\n\t}, func(value string) interface{} {\n\t\treturn strings.ToLower(value)\n\t}, true}\n\treturn arg\n}\n"
  },
  {
    "path": "commands/command.go",
    "content": "package commands\n\nimport (\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/irmine/gomine/commands/arguments\"\n\t\"github.com/irmine/gomine/text\"\n)\n\ntype Command struct {\n\tname              string\n\tdescription       string\n\tpermission        string\n\taliases           []string\n\targuments         []*arguments.Argument\n\targumentTypes     []string\n\tusage             string\n\tpermissionExempt  bool\n\texecutionFunction interface{}\n}\n\n// NewCommand returns a new command with the given command function.\n// The permission used in the command should be registered in order to get correct output.\nfunc NewCommand(name string, description string, permission string, aliases []string, function interface{}) *Command {\n\tif reflect.TypeOf(function).Kind() != reflect.Func {\n\t\tfunction = func() {}\n\t}\n\treturn &Command{name: name, permission: permission, aliases: aliases, description: description, executionFunction: function}\n}\n\n// GetUsage returns the usage of this command.\n// The usage will get parsed if it had not yet been.\nfunc (command *Command) GetUsage() string {\n\tcommand.parseUsage()\n\treturn command.usage\n}\n\n// ExemptFromPermissionCheck sets the command exempted from permission checking, allowing anybody to use it.\nfunc (command *Command) ExemptFromPermissionCheck(value bool) {\n\tcommand.permissionExempt = value\n}\n\n// IsPermissionChecked checks if the user of this command is checked for the adequate permission.\nfunc (command *Command) IsPermissionChecked() bool {\n\treturn !command.permissionExempt\n}\n\n// GetName returns the command name.\nfunc (command *Command) GetName() string {\n\treturn command.name\n}\n\n// GetDescription returns the command description.\nfunc (command *Command) GetDescription() string {\n\treturn command.description\n}\n\n// SetDescription sets the description of the command.\nfunc (command *Command) SetDescription(description string) {\n\tcommand.description = description\n}\n\n// SetPermission sets the permission of the command.\nfunc (command *Command) SetPermission(permission string) {\n\tcommand.permission = permission\n}\n\n// GetPermission returns the command permission string.\nfunc (command *Command) GetPermission() string {\n\treturn command.permission\n}\n\n// GetAliases returns the aliases of this command.\nfunc (command *Command) GetAliases() []string {\n\treturn command.aliases\n}\n\n// GetArguments returns a slice with all arguments.\nfunc (command *Command) GetArguments() []*arguments.Argument {\n\treturn command.arguments\n}\n\n// SetArguments sets the command arguments.\nfunc (command *Command) SetArguments(arguments []*arguments.Argument) {\n\tcommand.arguments = arguments\n}\n\n// AppendArgument adds one argument to the command.\nfunc (command *Command) AppendArgument(argument *arguments.Argument) {\n\tcommand.argumentTypes = append(command.argumentTypes, reflect.TypeOf(argument.GetOutput()).Name())\n\n\tcommand.arguments = append(command.arguments, argument)\n}\n\n// parseUsage parses the usage into a readable and clear one.\nfunc (command *Command) parseUsage() {\n\tif command.usage == \"\" {\n\t\tvar usage = text.Yellow + \"Usage: /\" + command.GetName() + \" \"\n\t\tfor index, argument := range command.GetArguments() {\n\t\t\tif argument.IsOptional() {\n\t\t\t\tusage += \"[\"\n\t\t\t} else {\n\t\t\t\tusage += \"<\"\n\t\t\t}\n\n\t\t\tusage += argument.GetName() + \": \" + command.argumentTypes[index]\n\t\t\tif argument.GetInputAmount() > 1 && command.argumentTypes[index] != \"string\" {\n\t\t\t\tusage += \"(\" + strconv.Itoa(argument.GetInputAmount()) + \")\"\n\t\t\t}\n\n\t\t\tif argument.IsOptional() {\n\t\t\t\tusage += \"]\"\n\t\t\t} else {\n\t\t\t\tusage += \">\"\n\t\t\t}\n\t\t\tusage += \" \"\n\t\t}\n\t\tcommand.usage = usage\n\t}\n}\n\n// Execute executes the command with the given sender and command arguments.\nfunc (command *Command) Execute(sender Sender, commandArgs []string) {\n\tif _, ok := command.parse(sender, commandArgs); !ok {\n\t\treturn\n\t}\n\tcommand.parseArgsAndExecute(sender)\n}\n\n// Parse checks and parses the values of a command.\nfunc (command *Command) parse(sender Sender, commandArgs []string) ([]*arguments.Argument, bool) {\n\tif command.IsPermissionChecked() && !sender.HasPermission(command.GetPermission()) {\n\t\tsender.SendMessage(\"You do not have permission to execute this command.\")\n\t\treturn []*arguments.Argument{}, false\n\t}\n\n\tvar stringIndex = 0\n\tif len(commandArgs) == 0 {\n\t\tif len(command.GetArguments()) == 0 {\n\t\t\treturn command.GetArguments(), true\n\t\t}\n\t\tsender.SendMessage(command.GetUsage())\n\t\treturn nil, false\n\t}\n\tfor _, argument := range command.arguments {\n\t\tvar i = 0\n\t\tvar output []string\n\n\t\tfor i < argument.GetInputAmount() {\n\t\t\tif len(commandArgs) < stringIndex+i+1 {\n\t\t\t\tif !argument.IsOptional() {\n\t\t\t\t\tsender.SendMessage(command.GetUsage())\n\t\t\t\t\treturn nil, false\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcommandArgs[stringIndex+i] = strings.TrimSpace(commandArgs[stringIndex+i])\n\n\t\t\t\tif !argument.IsValidValue(commandArgs[stringIndex+i]) {\n\t\t\t\t\tsender.SendMessage(command.GetUsage())\n\t\t\t\t\treturn nil, false\n\t\t\t\t}\n\t\t\t\toutput = append(output, commandArgs[stringIndex+i])\n\t\t\t}\n\t\t\ti++\n\t\t}\n\t\tstringIndex += i\n\t\tvar processedOutput []interface{}\n\n\t\tfor _, value := range output {\n\t\t\tprocessedOutput = append(processedOutput, argument.ConvertValue(value))\n\t\t}\n\n\t\tif argument.ShouldMerge() {\n\t\t\targument.SetOutput(strings.Join(output, \" \"))\n\t\t} else {\n\t\t\tif len(processedOutput) == 1 {\n\t\t\t\targument.SetOutput(processedOutput[0])\n\t\t\t} else {\n\t\t\t\targument.SetOutput(processedOutput)\n\t\t\t}\n\t\t}\n\t}\n\treturn command.GetArguments(), true\n}\n\n// ParseArgsAndExecute parses the arguments into an output able to be typed against.\n// After parsing, the command gets called.\nfunc (command *Command) parseArgsAndExecute(sender Sender) {\n\tvar method = reflect.ValueOf(command.executionFunction)\n\tvar input = make([]reflect.Value, method.Type().NumIn())\n\n\tvar argOffset = 0\n\tfor i := 0; i < method.Type().NumIn(); i++ {\n\n\t\tif method.Type().In(i).String() == \"commands.Sender\" {\n\t\t\tinput[i] = reflect.ValueOf(sender)\n\t\t\tcontinue\n\t\t}\n\n\t\tinput[i] = reflect.ValueOf(command.arguments[argOffset].GetOutput())\n\t\targOffset++\n\t}\n\n\tmethod.Call(input)\n}\n"
  },
  {
    "path": "commands/manager.go",
    "content": "package commands\n\nimport (\n\t\"errors\"\n)\n\ntype Manager struct {\n\tcommands map[string]*Command\n\taliases  map[string]*Command\n}\n\n// NewManager returns a new Manager struct.\nfunc NewManager() *Manager {\n\treturn &Manager{make(map[string]*Command), make(map[string]*Command)}\n}\n\n// IsCommandRegistered checks if the command has been registered.\n// Also checks for aliases.\nfunc (holder *Manager) IsCommandRegistered(commandName string) bool {\n\tvar _, exists = holder.GetCommand(commandName)\n\treturn exists == nil\n}\n\n// DeregisterCommand deregisters a command from the command holder.\n// Also deregisters all command aliases.\nfunc (holder *Manager) DeregisterCommand(commandName string) bool {\n\tif !holder.IsCommandRegistered(commandName) {\n\t\treturn false\n\t}\n\tvar command, _ = holder.GetCommand(commandName)\n\n\tfor _, alias := range command.GetAliases() {\n\t\tholder.deregisterAlias(alias)\n\t}\n\tdelete(holder.commands, commandName)\n\treturn true\n}\n\n// GetCommand returns a command regardless whether it's an alias or the command name, or an error if none was found.\nfunc (holder *Manager) GetCommand(commandName string) (*Command, error) {\n\tvar command, err = holder.GetCommandByName(commandName)\n\tif err != nil {\n\t\tcommand, err = holder.GetCommandByAlias(commandName)\n\t}\n\treturn command, err\n}\n\n// GetCommandByAlias returns a command by alias, and an error if none was found.\nfunc (holder *Manager) GetCommandByAlias(aliasName string) (*Command, error) {\n\tif !holder.AliasExists(aliasName) {\n\t\treturn nil, errors.New(\"command alias \" + aliasName + \" not found\")\n\t}\n\treturn holder.aliases[aliasName], nil\n}\n\n// GetCommandByName returns a command by name, and an error if none was found.\nfunc (holder *Manager) GetCommandByName(commandName string) (*Command, error) {\n\tvar _, exists = holder.commands[commandName]\n\tif !exists {\n\t\treturn nil, errors.New(\"command \" + commandName + \" not found\")\n\t}\n\treturn holder.commands[commandName], nil\n}\n\n// RegisterCommand registers a command in the command holder with the including aliases.\nfunc (holder *Manager) RegisterCommand(command *Command) {\n\tholder.commands[command.GetName()] = command\n\tfor _, alias := range command.GetAliases() {\n\t\tholder.registerAlias(alias, command)\n\t}\n}\n\n// AliasExists checks if the given alias exists or not.\nfunc (holder *Manager) AliasExists(aliasName string) bool {\n\tvar _, exists = holder.aliases[aliasName]\n\treturn exists\n}\n\n// registerAlias registers a new alias for the given command.\nfunc (holder *Manager) registerAlias(aliasName string, command *Command) {\n\tholder.aliases[aliasName] = command\n}\n\n// DeregisterAlias deregisters an alias.\nfunc (holder *Manager) deregisterAlias(aliasName string) {\n\tdelete(holder.aliases, aliasName)\n}\n"
  },
  {
    "path": "commands/selectors/all_entities.go",
    "content": "package selectors\n\ntype AllEntitiesSelector struct {\n\t*TargetSelector\n}\n\nfunc NewAllEntitiesSelector() *AllEntitiesSelector {\n\treturn &AllEntitiesSelector{NewTargetSelector(AllEntities)}\n}\n"
  },
  {
    "path": "commands/selectors/all_players.go",
    "content": "package selectors\n\ntype AllPlayersSelector struct {\n\t*TargetSelector\n}\n\nfunc NewAllPlayersSelector() *AllPlayersSelector {\n\treturn &AllPlayersSelector{NewTargetSelector(AllPlayers)}\n}\n"
  },
  {
    "path": "commands/selectors/nearest_player.go",
    "content": "package selectors\n\ntype NearestPlayerSelector struct {\n\t*TargetSelector\n}\n\nfunc NewNearestPlayerSelector() *NearestPlayerSelector {\n\treturn &NearestPlayerSelector{NewTargetSelector(NearestPlayer)}\n}\n"
  },
  {
    "path": "commands/selectors/random_player.go",
    "content": "package selectors\n\ntype RandomPlayerSelector struct {\n\t*TargetSelector\n}\n\nfunc NewRandomPlayerSelector() *RandomPlayerSelector {\n\treturn &RandomPlayerSelector{NewTargetSelector(RandomPlayer)}\n}\n"
  },
  {
    "path": "commands/selectors/selector.go",
    "content": "package selectors\n\nconst (\n\tNearestPlayer = \"@p\"\n\tRandomPlayer  = \"@r\"\n\tAllPlayers    = \"@a\"\n\tAllEntities   = \"@e\"\n\tSelf          = \"@s\"\n)\n\ntype TargetSelector struct {\n\tvariable  string\n\targuments map[string]string\n}\n\nfunc NewTargetSelector(variable string) *TargetSelector {\n\treturn &TargetSelector{variable, make(map[string]string)}\n}\n"
  },
  {
    "path": "commands/selectors/self.go",
    "content": "package selectors\n\ntype SelfSelector struct {\n\t*TargetSelector\n}\n\nfunc NewSelfSelector() *SelfSelector {\n\treturn &SelfSelector{NewTargetSelector(Self)}\n}\n"
  },
  {
    "path": "commands/sender.go",
    "content": "package commands\n\ntype Sender interface {\n\tHasPermission(string) bool\n\tSendMessage(...interface{})\n}\n"
  },
  {
    "path": "default_commands.go",
    "content": "package gomine\n\nimport (\n\t\"github.com/irmine/gomine/commands\"\n\t\"github.com/irmine/gomine/net\"\n\t\"github.com/irmine/gomine/text\"\n\t\"strconv\"\n)\n\nfunc NewTest(_ *Server) *commands.Command {\n\tcmd := commands.NewCommand(\"chunk\", \"Lists the current chunk\", \"none\", []string{}, func(sender commands.Sender) {\n\t\tif session, ok := sender.(*net.MinecraftSession); ok {\n\t\t\ttext.DefaultLogger.Debug(session.GetPlayer().GetChunk().X, session.GetPlayer().GetChunk().Z)\n\t\t\tsession.SendMessage(session.GetPlayer().GetChunk().X, session.GetPlayer().GetChunk().Z)\n\t\t}\n\t})\n\tcmd.ExemptFromPermissionCheck(true)\n\treturn cmd\n}\n\nfunc NewList(server *Server) *commands.Command {\n\tvar list = commands.NewCommand(\"list\", \"Lists all players online\", \"gomine.list\", []string{}, func(sender commands.Sender) {\n\t\tvar s = \"s\"\n\t\tif len(server.SessionManager.GetSessions()) == 1 {\n\t\t\ts = \"\"\n\t\t}\n\n\t\tvar playerList = text.BrightGreen + \"-----\" + text.White + \" Player List (\" + strconv.Itoa(len(server.SessionManager.GetSessions())) + \" Player\" + s + \") \" + text.BrightGreen + \"-----\\n\"\n\t\tfor name, player := range server.SessionManager.GetSessions() {\n\t\t\tplayerList += text.BrightGreen + name + \": \" + text.Yellow + text.Bold + strconv.Itoa(int(player.GetPing())) + \"ms\" + text.Reset + \"\\n\"\n\t\t}\n\t\tsender.SendMessage(playerList)\n\t})\n\tlist.ExemptFromPermissionCheck(true)\n\treturn list\n}\n\nfunc NewPing() *commands.Command {\n\tvar ping = commands.NewCommand(\"ping\", \"Returns your latency\", \"gomine.ping\", []string{}, func(sender commands.Sender) {\n\t\tif session, ok := sender.(*net.MinecraftSession); ok {\n\t\t\tsession.SendMessage(text.Yellow+\"Your current latency/ping is:\", session.GetPing())\n\t\t} else {\n\t\t\tsender.SendMessage(text.Red + \"Please run this command as a player.\")\n\t\t}\n\t})\n\tping.ExemptFromPermissionCheck(true)\n\treturn ping\n}\n\nfunc NewStop(server *Server) *commands.Command {\n\treturn commands.NewCommand(\"stop\", \"Stops the server\", \"gomine.stop\", []string{\"shutdown\"}, func() {\n\t\tfor _, session := range server.SessionManager.GetSessions() {\n\t\t\tsession.Kick(\"Server Stopped\", false, true)\n\t\t}\n\n\t\tserver.Shutdown()\n\t})\n}\n"
  },
  {
    "path": "items/conversion.go",
    "content": "package items\n\nimport (\n\t\"fmt\"\n\t\"github.com/irmine/gomine/text\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// IdToState is a map used to convert\n// an ID + item data combination to item type.\n// The keys of these maps are created using the\n// getKey method.\nvar IdToType = map[string]Type{\n\tGetKey(0, 0): DefaultManager.stringIds[\"minecraft:air\"],\n\tGetKey(1, 0): DefaultManager.stringIds[\"minecraft:stone\"],\n}\n\n// TypeToId is a map used to convert\n// a block state to an ID + data combination.\nvar TypeToId = map[string]string{\n\tfmt.Sprint(DefaultManager.stringIds[\"minecraft:air\"]):   GetKey(0, 0),\n\tfmt.Sprint(DefaultManager.stringIds[\"minecraft:stone\"]): GetKey(1, 0),\n}\n\n// getKey returns the key of an ID + data combination,\n// which is used in both maps.\nfunc GetKey(id int16, data int16) string {\n\treturn fmt.Sprint(id, \":\", data)\n}\n\n// FromKey attempts to retrieve an ID + data combination,\n// from a string created with getKey.\n// Any errors that occur are logged to the default logger.\nfunc FromKey(key string) (int16, int16) {\n\tfragments := strings.Split(key, \":\")\n\tidFrag, dataFrag := fragments[0], fragments[1]\n\ti, err := strconv.Atoi(idFrag)\n\ttext.DefaultLogger.LogError(err)\n\td, err := strconv.Atoi(dataFrag)\n\ttext.DefaultLogger.LogError(err)\n\treturn int16(i), int16(d)\n}\n"
  },
  {
    "path": "items/enchantments/enchantable.go",
    "content": "package enchantments\n\ntype Enchantable struct {\n}\n"
  },
  {
    "path": "items/enchantments/enchantment.go",
    "content": "package enchantments\n\n// Type holds the data of the enchantment.\n// It is an immutable type, which is used\n// to identify an enchantment.\ntype Type struct {\n\tstringId string\n\tid       int16\n}\n\n// GetStringId returns the string ID of a type.\n// This string ID may be used to identify\n// enchantments by user output.\nfunc (t Type) GetStringId() string {\n\treturn t.stringId\n}\n\n// GetId returns the enchantment ID of a type.\n// It is used mainly to identify an enchantment.\nfunc (t Type) GetId() int16 {\n\treturn t.id\n}\n\n// Instance is an enchantment instance.\n// It holds an enchantment type,\n// and contains the leftover duration of an\n// enchantment, and the value of it.\ntype Instance struct {\n\tType\n\t// Level is the enchantment level.\n\t// This value indicates the strength of the\n\t// enchantment.\n\tLevel byte\n}\n"
  },
  {
    "path": "items/enchantments/enchantment_ids.go",
    "content": "package enchantments\n\nconst (\n\tProtection byte = iota\n\tFireProtection\n\tFeatherFalling\n\tBlastProtection\n\tProjectileProtection\n\tThorns\n\tRespiration\n\tDepthStrider\n\tAquaAffinity\n\tSharpness\n\tSmite\n\tBaneOfArthropods\n\tKnockback\n\tFireAspect\n\tLooting\n\tEfficiency\n\tSilkTouch\n\tUnbreaking\n\tFortune\n\tPower\n\tPunch\n\tFlame\n\tInfinity\n\tLuckOfTheSea\n\tLure\n\tFrostWalker\n\tMending\n)\n"
  },
  {
    "path": "items/enchantments/manager.go",
    "content": "package enchantments\n\n// Manager provides helper functions for managing enchantments,\n// such as registering, deregistering and checks for those.\ntype Manager struct {\n\t// stringIds is a map of enchantment types,\n\t// indexed with the string ID.\n\t// Example: \"minecraft:absorption\": Type\n\tstringIds map[string]Type\n\t// byteIds is a map of enchantment types,\n\t// indexed with the byte ID.\n\t// Example: 3: Type\n\tbyteIds map[byte]Type\n}\n\n// DefaultManager is the default enchantment manager.\n// The init function registers the default enchantments.\nvar DefaultManager = NewManager()\n\n// init registers default enchantments of the manager.\nfunc init() {\n\tDefaultManager.RegisterDefaults()\n}\n\n// NewManager returns a new enchantment manager.\n// Maps are allocated, but no default enchantments\n// are registered yet.\nfunc NewManager() *Manager {\n\treturn &Manager{make(map[string]Type), make(map[byte]Type)}\n}\n\n// RegisterDefaults registers all default enchantments.\n// This function should be called whenever a new manager\n// is made, in order to have all default enchantments registered.\nfunc (manager *Manager) RegisterDefaults() {\n\n}\n"
  },
  {
    "path": "items/inventory/inventory.go",
    "content": "package inventory\n\nimport (\n\t\"errors\"\n\t\"github.com/irmine/gomine/items\"\n\t\"strings\"\n)\n\n// Inventory is a container of item stacks.\n// Every inventory has a fixed amount of\n// max slots, and the item stack count will\n// never exceed these slots.\ntype Inventory struct {\n\t// items is a slice of item stacks.\n\t// The length of this slice will remain\n\t// fixed for the lifetime of an inventory.\n\titems []*items.Stack\n}\n\n// ExceedingSlot gets returned when an slot\n// gets given that exceeds the inventory size.\n// This may be for GetItem, or SetItem as example.\nvar ExceedingSlot = errors.New(\"slot given exceeds the inventory\")\n\n// EmptySlot gets returned in GetItem when a slot\n// gets given and no item is available in that slot.\nvar EmptySlot = errors.New(\"slot given contains no item\")\n\n// FullInventory gets returned in AddItem when the\n// inventory does not have enough space for the item.\nvar FullInventory = errors.New(\"inventory has no space for item\")\n\n// NewInventory returns a new inventory with size.\n// An item slice gets made with the size,\n// which's length will never grow or shrink.\nfunc NewInventory(size int) *Inventory {\n\treturn &Inventory{make([]*items.Stack, size)}\n}\n\n// IsEmpty checks if a slot in the inventory is empty.\n// True gets returned if no item was in the slot.\n// True is also returned when the slot exceeds the\n// maximum size of the inventory.\nfunc (inventory *Inventory) IsEmpty(slot int) bool {\n\tif slot >= len(inventory.items) {\n\t\treturn true\n\t}\n\titem := inventory.items[slot]\n\treturn item == nil\n}\n\n// GetItem returns an item in a slot in an inventory.\n// If the slot exceeds the max inventory size,\n// a nil item gets returned with ExceedingSlot error.\n// If there is no item available at that slot,\n// a nil item gets returned with EmptySlot.\n// If the item was retrieved successfully,\n// the item gets returned with no error.\nfunc (inventory *Inventory) GetItem(slot int) (*items.Stack, error) {\n\tif slot >= len(inventory.items) {\n\t\treturn nil, ExceedingSlot\n\t}\n\titem := inventory.items[slot]\n\tif item == nil {\n\t\treturn nil, EmptySlot\n\t}\n\treturn item, nil\n}\n\n// SetItem sets an item in a slot in an inventory.\n// If the slot exceeds the max inventory size,\n// a nil item gets returned with ExceedingSlot error,\n// otherwise returns nil.\nfunc (inventory *Inventory) SetItem(stack *items.Stack, slot int) error {\n\tif slot >= len(inventory.items) {\n\t\treturn ExceedingSlot\n\t}\n\tinventory.items[slot] = stack\n\treturn nil\n}\n\n// AddItem adds an item to the inventory.\n// FullInventory gets returned if there was\n// not sufficient space to fit the item.\n// Items are first attempted to be stacked onto\n// previously existed stacks, and once all\n// pre-existing stacks are filled new stacks\n// are created.\nfunc (inventory *Inventory) AddItem(item *items.Stack) error {\n\tfor slot, invItem := range inventory.items {\n\t\tif item.Count == 0 {\n\t\t\treturn nil\n\t\t}\n\t\tif invItem == nil {\n\t\t\tcontinue\n\t\t}\n\t\titem.StackOn(invItem)\n\t\tinventory.SetItem(invItem, slot)\n\t}\n\tfor slot, empty := range inventory.items {\n\t\tif item.Count == 0 {\n\t\t\treturn nil\n\t\t}\n\t\tif empty != nil {\n\t\t\tcontinue\n\t\t}\n\t\tn := *item\n\t\tn.Count = 0\n\t\titem.StackOn(&n)\n\t\tinventory.SetItem(&n, slot)\n\t}\n\tif item.Count == 0 {\n\t\treturn nil\n\t}\n\treturn FullInventory\n}\n\n// RemoveItem removes an item from an inventory.\n// A given item gets searched in the inventory,\n// removing every equal stack until the count\n// of the given stack has been exhausted.\n// Items may be removed from multiple stacks.\n// A bool gets returned to indicate if the\n// complete stack got removed from the inventory.\nfunc (inventory *Inventory) RemoveItem(searched *items.Stack) bool {\n\tcount := searched.Count\n\tfor slot, item := range inventory.items {\n\t\tif item == nil {\n\t\t\tcontinue\n\t\t}\n\t\tcanStack, _ := item.CanStackOn(searched)\n\t\tif canStack {\n\t\t\tif item.Count > count {\n\t\t\t\titem.Count -= count\n\t\t\t\tinventory.SetItem(item, slot)\n\t\t\t\tcount = 0\n\t\t\t} else {\n\t\t\t\tinventory.ClearSlot(slot)\n\t\t\t}\n\t\t\tcount -= item.Count\n\t\t\tif count <= 0 {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// ClearSlot clears a given slot in the inventory.\n// ClearSlot returns ExceedingSlot if the slot exceeds\n// the inventory size, and EmptySlot if the slot was\n// already empty before clearing.\nfunc (inventory *Inventory) ClearSlot(slot int) error {\n\tif slot >= len(inventory.items) {\n\t\treturn ExceedingSlot\n\t}\n\titem := inventory.items[slot]\n\tif item == nil {\n\t\treturn EmptySlot\n\t}\n\tinventory.SetItem(nil, slot)\n\treturn nil\n}\n\n// GetAll returns a copied slice of all item stacks,\n// that are currently contained within the inventory.\n// Operating on this slice will not operate directly\n// on the content of this inventory.\nfunc (inventory *Inventory) GetAll() []*items.Stack {\n\tslice := make([]*items.Stack, len(inventory.items))\n\tcopy(slice, inventory.items)\n\treturn slice\n}\n\n// SetAll sets all items in the inventory.\n// This function merely copies the items from\n// slice to slice, and does not implement any\n// other behaviour. Use SetItem where possible.\nfunc (inventory *Inventory) SetAll(items []*items.Stack) {\n\tcopy(inventory.items, items)\n}\n\n// Contains checks if the inventory contains an item.\n// This function checks through the whole inventory,\n// to try and find out the total count of items with\n// the same type of the item stack.\n// The checked item stack may therefore be split out\n// over multiple stacks in the inventory.\nfunc (inventory *Inventory) Contains(searched *items.Stack) bool {\n\tcount := searched.Count\n\tfor _, item := range inventory.items {\n\t\tif item == nil {\n\t\t\tcontinue\n\t\t}\n\t\tcanStack, _ := searched.CanStackOn(item)\n\t\tif canStack {\n\t\t\tcount -= item.Count\n\t\t\tif count <= 0 {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// String returns a string representation of an inventory.\n// String implements the fmt.Stringer interface.\nfunc (inventory *Inventory) String() string {\n\tm := make(map[string]string)\n\tfor _, item := range inventory.items {\n\t\tif item == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif _, ok := m[item.GetName()]; !ok {\n\t\t\tm[item.GetName()] = \"- \" + item.String()\n\t\t} else {\n\t\t\tm[item.GetName()] += \", \" + item.String()\n\t\t}\n\t}\n\tstr := \"\"\n\tfor _, instances := range m {\n\t\tstr += instances + \"\\n\"\n\t}\n\treturn \"Inventory contents:\\n\" + strings.TrimRight(str, \"\\n\")\n}\n"
  },
  {
    "path": "items/inventory/inventory_test.go",
    "content": "package inventory\n\nimport (\n\t\"fmt\"\n\t\"github.com/irmine/gomine/items\"\n\t\"testing\"\n)\n\nfunc Test(t *testing.T) {\n\tmanager := items.NewManager()\n\tmanager.Register(items.NewType(\"minecraft:emerald\"), true)\n\tmanager.Register(items.NewType(\"minecraft:glass_bottle\"), true)\n\n\tinv := NewInventory(9)\n\titem, _ := manager.Get(\"minecraft:emerald\", 8)\n\tinv.SetItem(item, 6)\n\tinv.SetItem(item, 4)\n\titem, _ = manager.Get(\"minecraft:glass_bottle\", 34)\n\tinv.SetItem(item, 8)\n\n\tif err := inv.SetItem(item, 9); err != nil {\n\t\tfmt.Println(\"Inventory size check works:\", err)\n\t}\n\n\tfmt.Println(inv)\n\n\titem, _ = manager.Get(\"minecraft:emerald\", 16)\n\tif inv.Contains(item) {\n\t\tfmt.Println(\"Inventory contains 16 emeralds.\")\n\t} else {\n\t\tfmt.Println(\"Inventory does not contain 16 emeralds.\")\n\t}\n\titem, _ = manager.Get(\"minecraft:glass_bottle\", 35)\n\tif inv.Contains(item) {\n\t\tfmt.Println(\"Inventory contains 35 glass bottles.\")\n\t} else {\n\t\tfmt.Println(\"Inventory does not contain 35 glass bottles.\")\n\t}\n\n\titem, _ = manager.Get(\"minecraft:emerald\", 10)\n\tinv.RemoveItem(item)\n\n\tfmt.Println(inv)\n\n\titem, _ = manager.Get(\"minecraft:emerald\", 90)\n\tinv.AddItem(item)\n\n\tfmt.Println(inv)\n}\n"
  },
  {
    "path": "items/inventory/io/inventory_action_io.go",
    "content": "package io\n\nimport (\n\t\"github.com/irmine/gomine/items\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\nconst (\n\tContainerSource = iota + 0\n\tWorldSource = 2\n\t//CreativeSource = 3\n)\n\ntype InventoryActionIO struct {\n\tSource uint32\n\tWindowId int32\n\tSourceFlags uint32\n\tInventorySlot uint32\n\tOldItem *items.Stack\n\tNewItem *items.Stack\n}\n\nfunc NewInventoryActionIO() InventoryActionIO{\n\treturn InventoryActionIO{}\n}\n\nfunc (IO *InventoryActionIO) WriteToBuffer(bs *packets.MinecraftStream) {\n\tbs.PutUnsignedVarInt(IO.Source)\n\n\tswitch IO.Source {\n\tcase ContainerSource:\n\t\tbs.PutVarInt(IO.WindowId)\n\t\tbreak\n\tcase WorldSource:\n\t\tbs.PutUnsignedVarInt(IO.SourceFlags)\n\t\tbreak\n\t}\n\n\tbs.PutUnsignedVarInt(IO.InventorySlot)\n\tbs.PutItem(IO.OldItem)\n\tbs.PutItem(IO.NewItem)\n}\n\nfunc (IO *InventoryActionIO) ReadFromBuffer(bs *packets.MinecraftStream) InventoryActionIO {\n\tIO.Source = bs.GetUnsignedVarInt()\n\n\tswitch IO.Source {\n\tcase ContainerSource:\n\t\tIO.WindowId = bs.GetVarInt()\n\t\tbreak\n\tcase WorldSource:\n\t\tIO.SourceFlags = bs.GetUnsignedVarInt()\n\t\tbreak\n\t}\n\n\tIO.InventorySlot = bs.GetUnsignedVarInt()\n\tIO.OldItem = bs.GetItem()\n\tIO.NewItem = bs.GetItem()\n\n\treturn *IO\n}"
  },
  {
    "path": "items/inventory/io/inventory_action_io_list.go",
    "content": "package io\n\nimport (\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype InventoryActionIOList struct {\n\tList []InventoryActionIO\n}\n\nfunc NewInventoryActionIOList() *InventoryActionIOList{\n\treturn &InventoryActionIOList{}\n}\n\nfunc (IOList *InventoryActionIOList) GetCount() int {\n\treturn len(IOList.List)\n}\n\nfunc (IOList *InventoryActionIOList) PutAction(io InventoryActionIO) {\n\tIOList.List = append(IOList.List, io)\n}\n\nfunc (IOList *InventoryActionIOList) WriteToBuffer(bs *packets.MinecraftStream) {\n\tc := len(IOList.List)\n\tbs.PutUnsignedVarInt(uint32(c))\n\tfor i := 0; i < c; i++ {\n\t\tIOList.List[i].WriteToBuffer(bs)\n\t}\n}\n\nfunc (IOList *InventoryActionIOList) ReadFromBuffer(bs *packets.MinecraftStream) *InventoryActionIOList{\n\tc := bs.GetUnsignedVarInt()\n\tfor i := uint32(0); i < c; i ++{\n\t\ta := NewInventoryActionIO()\n\t\ta.ReadFromBuffer(bs)\n\t\tIOList.PutAction(a)\n\t}\n\treturn IOList\n}"
  },
  {
    "path": "items/item_test.go",
    "content": "package items\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc Test(t *testing.T) {\n\tmanager := NewManager()\n\tmanager.RegisterDefaults()\n\tmanager.Register(NewType(\"minecraft:emerald\"), true)\n\n\temerald, ok := manager.Get(\"minecraft:emerald\", 5)\n\tif !ok {\n\t\tpanic(\"item not registered\")\n\t}\n\n\tfmt.Println(emerald.name, emerald.Count)\n}\n"
  },
  {
    "path": "items/manager.go",
    "content": "package items\n\nimport \"github.com/irmine/gonbt\"\n\n// Manager supplies helper functions for item type registering.\n// Item types get registered by their string ID,\n// and can be retrieved using these.\ntype Manager struct {\n\t// stringIds is a map containing item types,\n\t// indexed by string IDs.\n\t// Example: \"minecraft:golden_apple\": Type\n\tstringIds map[string]Type\n\t// creativeItems is a map containing item types,\n\t// indexed by string IDs, similarly to stringIds.\n\t// This map contains all items,\n\t// that should be displayed in the creative inventory.\n\tcreativeItems map[string]Type\n}\n\n// DefaultManager is the default item manager.\n// The default items are registered upon the init function.\nvar DefaultManager = NewManager()\n\n// init initializes all default item types,\n// of the default item manager.\nfunc init() {\n\tDefaultManager.RegisterDefaults()\n}\n\n// NewManager returns a new item registry.\n// New registries will not have default items registered.\n// Default registries should be registered using RegisterDefaults.\nfunc NewManager() *Manager {\n\treturn &Manager{make(map[string]Type), make(map[string]Type)}\n}\n\n// Register registers a new item type.\n// The item type will be registered to the stringIds map.\n// Registered item types can be deregistered,\n// using the Deregister functions.\n// If registerCreative is set to true,\n// the item will also be registered as creative item.\nfunc (registry *Manager) Register(t Type, registerCreative bool) {\n\tregistry.stringIds[t.GetId()] = t\n\tif registerCreative {\n\t\tregistry.RegisterCreativeType(t)\n\t}\n}\n\n// RegisterMultiple registers multiple types at once.\n// Item types will be registered to the stringIds map,\n// and can be deregistered separately from each other.\n// If registerCreative is set to true,\n// the items will also be registered as creative item.\nfunc (registry *Manager) RegisterMultiple(types []Type, registerCreative bool) {\n\tfor _, t := range types {\n\t\tregistry.stringIds[t.GetId()] = t\n\t\tif registerCreative {\n\t\t\tregistry.RegisterCreativeType(t)\n\t\t}\n\t}\n}\n\n// RegisterCreativeType registers an item type,\n// to the creative items map.\n// All creative items will be displayed,\n// in the creative inventory.\nfunc (registry *Manager) RegisterCreativeType(t Type) {\n\tregistry.creativeItems[t.GetId()] = t\n}\n\n// IsCreativeTypeRegistered checks if an item type\n// is registered to the creative inventory map.\nfunc (registry *Manager) IsCreativeTypeRegistered(stringId string) bool {\n\t_, ok := registry.creativeItems[stringId]\n\treturn ok\n}\n\n// DeregisterCreativeType deregisters a creative item.\n// Creative items can be deregistered using the string ID\n// of that particular item.\n// A bool gets returned to indicate success of the action.\nfunc (registry *Manager) DeregisterCreativeType(stringId string) bool {\n\t_, ok := registry.creativeItems[stringId]\n\tdelete(registry.creativeItems, stringId)\n\treturn ok\n}\n\n// GetCreativeTypes returns all creative items.\n// A map gets returned in the form of stringId => Type.\nfunc (registry *Manager) GetCreativeTypes() map[string]Type {\n\treturn registry.creativeItems\n}\n\n// IsRegistered checks if an item type is registered,\n// by its string ID in the stringIds map.\n// Returns true if the string ID is registered.\nfunc (registry *Manager) IsRegistered(stringId string) bool {\n\t_, ok := registry.stringIds[stringId]\n\treturn ok\n}\n\n// Deregister deregisters an item type,\n// by its string ID in the stringIds map.\n// Returns true if the item type was deregistered successfully.\nfunc (registry *Manager) Deregister(stringId string) bool {\n\t_, ok := registry.stringIds[stringId]\n\tif !ok {\n\t\treturn false\n\t}\n\tdelete(registry.stringIds, stringId)\n\treturn true\n}\n\n// Get attempts to return a new item stack by a string ID,\n// and sets the stack's count to the count given.\n// A bool gets returned to indicate whether any item was found.\n// If no item type could be found with the given string ID,\n// a default air item and a bool false gets returned.\nfunc (registry *Manager) Get(stringId string, count int) (*Stack, bool) {\n\tt, ok := registry.stringIds[stringId]\n\tif !ok {\n\t\tt = registry.stringIds[\"minecraft:air\"]\n\t}\n\treturn &Stack{Type: t, Count: count, DisplayName: t.name, cachedNBT: gonbt.NewCompound(\"\", make(map[string]gonbt.INamedTag))}, ok\n}\n\n// GetTypes returns all registered item types.\n// Item types are returned in a map of the form stringId => Type.\nfunc (registry *Manager) GetTypes() map[string]Type {\n\treturn registry.stringIds\n}\n\n// RegisterDefaults registers all default items.\n// This function should be called immediately after NewManager,\n// in order to register the proper default items.\nfunc (registry *Manager) RegisterDefaults() {\n\tregistry.Register(NewType(\"minecraft:air\"), false)\n\tregistry.Register(NewType(\"minecraft:stone\"), true)\n}\n"
  },
  {
    "path": "items/nbt_tag_names.go",
    "content": "package items\n\nconst (\n\tDisplay     = \"display\"\n\tDisplayName = \"Name\"\n\tDisplayLore = \"Lore\"\n\n\tEnch      = \"ench\"\n\tEnchId    = \"id\"\n\tEnchLevel = \"lvl\"\n)\n"
  },
  {
    "path": "items/stack.go",
    "content": "package items\n\nimport (\n\t\"fmt\"\n\t\"github.com/irmine/gomine/items/enchantments\"\n\t\"github.com/irmine/gonbt\"\n)\n\n// Stack is an instance of a given amount of items.\n// A stack may also be referred to as an item instance.\n// A stack holds additional information about an item,\n// that could differ on an every item base.\ntype Stack struct {\n\t// Stack embeds Type. Therefore functions\n\t// in the Type struct may also be used in Stack.\n\tType\n\t// Count is the current count of an item.\n\t// The count of an item is usually 16/64.\n\tCount int\n\t// Durability is the current left durability of the stack.\n\t// Durability on non-breakable item types has no effect.\n\tDurability int16\n\t// DisplayName is the display name of an item.\n\t// If a non-empty display name has been set,\n\t// this name will be displayed,\n\t// rather than the original Type name.\n\tDisplayName string\n\t// Lore is the displayed lore of an item.\n\t// The lore is displayed under the item,\n\t// when hovering over it in the inventory.\n\tLore []string\n\t// enchantments is a map of enchantment instances,\n\t// that are applied on this item.\n\t// The map is indexed by the enchantment IDs.\n\tenchantments map[string]enchantments.Instance\n\t// additionalData is raw additional data of an item stack.\n\t// The additionalData may not be directly used by plugins,\n\t// but should rather be modified by encapsulating items.\n\tadditionalData interface{}\n\t// cachedNBT is an NBT compound which gets set when parsing NBT.\n\t// This cached NBT is used to ensure no NBT gets lost while parsing,\n\t// and forms the base for NBT that gets emitted by the type.\n\tcachedNBT *gonbt.Compound\n}\n\n// GetDisplayName returns the displayed name of an item.\n// The custom name of the item always gets returned,\n// unless the custom name is empty; Then the actual\n// item type name gets returned.\nfunc (stack Stack) GetDisplayName() string {\n\tif stack.DisplayName == \"\" {\n\t\treturn stack.name\n\t}\n\treturn stack.DisplayName\n}\n\n// String returns a string representation of a stack.\n// It implements fmt.Stringer, and returns a string as such:\n// x29 Emerald (minecraft:emerald)\nfunc (stack Stack) String() string {\n\treturn fmt.Sprint(\"x\", stack.Count, stack.Type)\n}\n\n// CanStackWith checks if two stacks can stack with each other.\n// A bool is returned which indicates if the two can stack,\n// and an integer is returned which specifies the count of\n// of the item that can still be stacked on this stack.\n// The returned integer may be 0, if the stack is already\n// at the max stack size.\nfunc (stack Stack) CanStackOn(stack2 *Stack) (bool, int) {\n\tif !stack.Type.Equals(stack2.Type) || stack.DisplayName != stack2.DisplayName || !stack.EqualsEnchantments(stack2) || !stack.EqualsLore(stack2) {\n\t\treturn false, 0\n\t}\n\tcount := stack2.maxStackSize - stack2.Count\n\tcountLeft := stack.Count\n\tif countLeft < count {\n\t\tcount = countLeft\n\t}\n\treturn true, count\n}\n\n// StackOn attempts to stack a stack on another stack.\n// A first bool is returned which indicates if the two stacked\n// successfully. A second bool is returned which is true as long as\n// the item stack is not at count 0.\n// An integer is returned to specify the count of items that got stacked\n// on the other stack. The integer returned may be 0, which happens if the\n// other stack is already at max stack size.\nfunc (stack *Stack) StackOn(stack2 *Stack) (success bool, notZero bool, stackCount int) {\n\tcanStack, count := stack.CanStackOn(stack2)\n\tcountLeft := stack.Count != 0\n\tif !canStack {\n\t\treturn false, countLeft, count\n\t}\n\tstack2.Count += count\n\tstack.Count -= count\n\treturn true, countLeft, count\n}\n\n// Equals checks if two item stacks are considered equal.\n// Equals checks if the item type is equal and if the count is equal.\n// For more deep checks, EqualsExact should be used.\nfunc (stack Stack) Equals(stack2 *Stack) bool {\n\treturn stack.Type.Equals(stack2.Type) && stack2.Count == stack.Count && stack.Durability == stack2.Durability && stack.DisplayName == stack2.DisplayName\n}\n\n// EqualsExact checks if two item stacks are considered exact equal.\n// EqualsExact does all the checks Equals does,\n// and checks if the lore and enchantments are equal.\nfunc (stack Stack) EqualsExact(stack2 *Stack) bool {\n\treturn stack.Equals(stack2) && stack.EqualsLore(stack2) && stack.EqualsEnchantments(stack2)\n}\n\n// EqualsLore checks if the lore of two item\n// stacks are equal to each other.\nfunc (stack Stack) EqualsLore(stack2 *Stack) bool {\n\tif len(stack.Lore) != len(stack2.Lore) {\n\t\treturn false\n\t}\n\tfor key, val := range stack.Lore {\n\t\tif stack2.Lore[key] != val {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// EqualsEnchantments checks if enchantments of two\n// item stacks are equal to each other.\nfunc (stack Stack) EqualsEnchantments(stack2 *Stack) bool {\n\tif len(stack.enchantments) != len(stack2.enchantments) {\n\t\treturn false\n\t}\n\tfor key, val := range stack.enchantments {\n\t\tif stack2.enchantments[key] != val {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "items/type.go",
    "content": "package items\n\nimport (\n\t\"fmt\"\n\t\"github.com/irmine/gonbt\"\n\t\"strings\"\n)\n\n// Type is the type that identifies an item.\n// Types contain a string ID,\n// which can be used to construct a new item stack.\ntype Type struct {\n\t// NBTParseFunction gets called once NBT is attempted\n\t// to be decoded for an item. The compound passed is the\n\t// compound the NBT data should be coming out of, and the stack\n\t// passed is the stack that encapsulates this type.\n\tNBTParseFunction func(compound *gonbt.Compound, stack *Stack)\n\t// NBTEmitFunction gets called once NBT is attempted\n\t// to be obtained from an item. The compound passed is the\n\t// compound the NBT data should be going into, and the stack\n\t// passed is the stack that encapsulates this type.\n\tNBTEmitFunction func(compound *gonbt.Compound, stack *Stack)\n\n\t// name is the name of the item type.\n\t// This name is merely a modification of the string ID.\n\tname string\n\t// stringId is the identifier of the item type.\n\t// This string ID is always used, rather than numeric IDs.\n\tstringId string\n\t// breakable defines if the item is breakable.\n\t// Breakable items will have decrementing durability.\n\tbreakable bool\n\t// maxStackSize is the maximum size of a stack of this item.\n\t// Item stacks itself are not limited, but the stack size\n\t// of occurrences in an inventory of the item are.\n\tmaxStackSize int\n}\n\n// NewType returns a new non-breakable type.\n// The given string ID is used as identifier,\n// and all properties are immune in the type.\n// Type names prefixed with `minecraft:` get their\n// name set to it without the prefix.\n// Types get the default NBT parsing and emitting functions.\nfunc NewType(stringId string) Type {\n\tfragments := strings.Split(stringId[10:], \"_\")\n\tname := \"\"\n\tfor _, frag := range fragments {\n\t\tname += strings.Title(frag) + \" \"\n\t}\n\treturn Type{ParseNBT, EmitNBT, strings.TrimRight(name, \" \"), stringId, false, 64}\n}\n\n// NewType returns a new breakable type.\n// The given string ID is used as identifier,\n// and all properties are immune in the type.\n// Type names prefixed with `minecraft:` get their\n// name set to it without the prefix.\n// Types get the default NBT parsing and emitting functions.\nfunc NewBreakable(stringId string) Type {\n\tt := NewType(stringId)\n\tt.breakable = true\n\treturn t\n}\n\n// GetName returns the readable name of an item type.\n// This name may contains spaces.\nfunc (t Type) GetName() string {\n\treturn t.name\n}\n\n// GetId returns the string ID of an item type.\n// StringIds are a string used as an identifier,\n// in order to lookup items by it.\nfunc (t Type) GetId() string {\n\treturn t.stringId\n}\n\n// IsBreakable checks if an item is breakable.\n// Breakable items use data fields for durability,\n// but we separate them for forward compatibility sake.\nfunc (t Type) IsBreakable() bool {\n\treturn t.breakable\n}\n\n// GetMaximumStackSize returns the maximum stack size of an item.\n// Item stacks of the type are not limited to this size themselves,\n// but are when set into an inventory.\nfunc (t Type) GetMaximumStackSize() int {\n\treturn t.maxStackSize\n}\n\n// String returns a string representation of a type.\n// It implements fmt.Stringer, and returns a string as such:\n// Emerald(minecraft:emerald)\nfunc (t Type) String() string {\n\treturn fmt.Sprint(t.name, \"(\", t.stringId, \")\")\n}\n\n// GetAuxValue returns the aux value for the item stack with item data.\n// This aux value is used for writing stacks over network.\nfunc (t Type) GetAuxValue(stack *Stack, data int16) int32 {\n\tif t.IsBreakable() {\n\t\tdata = stack.Durability\n\t}\n\treturn int32(((data & 0x7fff) << 8) | int16(stack.Count))\n}\n\n// Equals checks if two item types are considered equal.\n// Item types are merely checked against each other's\n// string IDs, but should not require more comparisons.\nfunc (t Type) Equals(t2 Type) bool {\n\treturn t.stringId == t2.stringId\n}\n\n// ParseNBT implements default behaviour for parsing NBT.\n// This is the default function passed in for `NBTParseFunction`.\n// The cached NBT gets set when parsing NBT.\nfunc ParseNBT(compound *gonbt.Compound, stack *Stack) {\n\tif compound.HasTagWithType(Display, gonbt.TAG_Compound) {\n\t\tstack.DisplayName = compound.GetCompound(Display).GetString(DisplayName, stack.name)\n\t\tfor _, tag := range compound.GetCompound(Display).GetList(DisplayLore, gonbt.TAG_String).GetTags() {\n\t\t\tstack.Lore = append(stack.Lore, tag.Interface().(string))\n\t\t}\n\t}\n\tstack.cachedNBT = compound\n}\n\n// EmitNBT implements default behaviour for emitting NBT.\n// This is the default function passed in for `NBTEmitFunction`.\n// The compound first gets set to the cached compound of the item type.\nfunc EmitNBT(compound *gonbt.Compound, stack *Stack) {\n\tcompound = stack.cachedNBT\n\tcompound.SetCompound(Display, make(map[string]gonbt.INamedTag))\n\tif stack.DisplayName != \"\" {\n\t\tcompound.GetCompound(Display).SetString(DisplayName, stack.DisplayName)\n\t\tvar list []gonbt.INamedTag\n\t\tfor _, lore := range stack.Lore {\n\t\t\tlist = append(list, gonbt.NewString(\"\", lore))\n\t\t}\n\t\tcompound.GetCompound(Display).SetList(DisplayLore, gonbt.TAG_String, list)\n\t}\n}\n"
  },
  {
    "path": "net/info/info.go",
    "content": "package info\n\nconst (\n\tLatestProtocol           = 332\n\tLatestGameVersion        = \"v1.9.0\"\n\tLatestGameVersionNetwork = \"1.9.0\"\n)\n\ntype PacketIdList map[PacketName]int\n\ntype PacketName string\nconst (\n\tLoginPacket                       PacketName = \"LoginPacket\"\n\tPlayStatusPacket                  PacketName = \"PlayStatusPacket\"\n\tServerHandshakePacket             PacketName = \"ServerHandshakePacket\"\n\tClientHandshakePacket             PacketName = \"ClientHandshakePacket\"\n\tDisconnectPacket                  PacketName = \"DisconnectPacket\"\n\tResourcePackInfoPacket            PacketName = \"ResourcePackInfoPacket\"\n\tResourcePackStackPacket           PacketName = \"ResourcePackStackPacket\"\n\tResourcePackClientResponsePacket  PacketName = \"ResourcePackClientResponsePacket\"\n\tTextPacket                        PacketName = \"TextPacket\"\n\tSetTimePacket                     PacketName = \"SetTimePacket\"\n\tStartGamePacket                   PacketName = \"StartGamePacket\"\n\tAddPlayerPacket                   PacketName = \"AddPlayerPacket\"\n\tAddEntityPacket                   PacketName = \"AddEntityPacket\"\n\tRemoveEntityPacket                PacketName = \"RemoveEntityPacket\"\n\tAddItemEntityPacket               PacketName = \"AddItemEntityPacket\"\n\tAddHangingEntityPacket            PacketName = \"AddHangingEntityPacket\"\n\tTakeItemEntityPacket              PacketName = \"TakeItemEntityPacket\"\n\tMoveEntityPacket                  PacketName = \"MoveEntityPacket\"\n\tMovePlayerPacket                  PacketName = \"MovePlayerPacket\"\n\tRiderJumpPacket                   PacketName = \"RiderJumpPacket\"\n\tUpdateBlockPacket                 PacketName = \"UpdateBlockPacket\"\n\tAddPaintingPacket                 PacketName = \"AddPaintingPacket\"\n\tExplodePacket                     PacketName = \"ExplodePacket\"\n\tLevelSoundEventPacket             PacketName = \"LevelSoundEventPacket\"\n\tLevelEventPacket                  PacketName = \"LevelEventPacket\"\n\tBlockEventPacket                  PacketName = \"BlockEventPacket\"\n\tEntityEventPacket                 PacketName = \"EntityEventPacket\"\n\tMobEffectPacket                   PacketName = \"MobEffectPacket\"\n\tUpdateAttributesPacket            PacketName = \"UpdateAttributesPacket\"\n\tInventoryTransactionPacket        PacketName = \"InventoryTransactionPacket\"\n\tMobEquipmentPacket                PacketName = \"MobEquipmentPacket\"\n\tMobArmorEquipmentPacket           PacketName = \"MobArmorEquipmentPacket\"\n\tInteractPacket                    PacketName = \"InteractPacket\"\n\tBlockPickRequestPacket            PacketName = \"BlockPickRequestPacket\"\n\tEntityPickRequestPacket           PacketName = \"EntityPickRequestPacket\"\n\tPlayerActionPacket                PacketName = \"PlayerActionPacket\"\n\tEntityFallPacket                  PacketName = \"EntityFallPacket\"\n\tHurtArmorPacket                   PacketName = \"HurtArmorPacket\"\n\tSetEntityDataPacket               PacketName = \"SetEntityDataPacket\"\n\tSetEntityMotionPacket             PacketName = \"SetEntityMotionPacket\"\n\tSetEntityLinkPacket               PacketName = \"SetEntityLinkPacket\"\n\tSetHealthPacket                   PacketName = \"SetHealthPacket\"\n\tSetSpawnPositionPacket            PacketName = \"SetSpawnPositionPacket\"\n\tAnimatePacket                     PacketName = \"AnimatePacket\"\n\tRespawnPacket                     PacketName = \"RespawnPacket\"\n\tContainerOpenPacket               PacketName = \"ContainerOpenPacket\"\n\tContainerClosePacket              PacketName = \"ContainerClosePacket\"\n\tPlayerHotbarPacket                PacketName = \"PlayerHotbarPacket\"\n\tInventoryContentPacket            PacketName = \"InventoryContentPacket\"\n\tInventorySlotPacket               PacketName = \"InventorySlotPacket\"\n\tContainerSetDataPacket            PacketName = \"ContainerSetDataPacket\"\n\tCraftingDataPacket                PacketName = \"CraftingDataPacket\"\n\tCraftingEventPacket               PacketName = \"CraftingEventPacket\"\n\tGuiDataPickItemPacket             PacketName = \"GuiDataPickItemPacket\"\n\tAdventureSettingsPacket           PacketName = \"AdventureSettingsPacket\"\n\tBlockEntityDataPacket             PacketName = \"BlockEntityDataPacket\"\n\tPlayerInputPacket                 PacketName = \"PlayerInputPacket\"\n\tFullChunkDataPacket               PacketName = \"FullChunkDataPacket\"\n\tSetCommandsEnabledPacket          PacketName = \"SetCommandsEnabledPacket\"\n\tSetDifficultyPacket               PacketName = \"SetDifficultyPacket\"\n\tChangeDimensionPacket             PacketName = \"ChangeDimensionPacket\"\n\tSetPlayerGameTypePacket           PacketName = \"SetPlayerGameTypePacket\"\n\tPlayerListPacket                  PacketName = \"PlayerListPacket\"\n\tSimpleEventPacket                 PacketName = \"SimpleEventPacket\"\n\tEventPacket                       PacketName = \"EventPacket\"\n\tSpawnExperienceOrbPacket          PacketName = \"SpawnExperienceOrbPacket\"\n\tClientboundMapItemDataPacket      PacketName = \"ClientboundMapItemDataPacket\"\n\tMapInfoRequestPacket              PacketName = \"MapInfoRequestPacket\"\n\tRequestChunkRadiusPacket          PacketName = \"RequestChunkRadiusPacket\"\n\tChunkRadiusUpdatedPacket          PacketName = \"ChunkRadiusUpdatedPacket\"\n\tItemFrameDropItemPacket           PacketName = \"ItemFrameDropItemPacket\"\n\tGameRulesChangedPacket            PacketName = \"GameRulesChangedPacket\"\n\tCameraPacket                      PacketName = \"CameraPacket\"\n\tBossEventPacket                   PacketName = \"BossEventPacket\"\n\tShowCreditsPacket                 PacketName = \"ShowCreditsPacket\"\n\tAvailableCommandsPacket           PacketName = \"AvailableCommandsPacket\"\n\tCommandRequestPacket              PacketName = \"CommandRequestPacket\"\n\tCommandBlockUpdatePacket          PacketName = \"CommandBlockUpdatePacket\"\n\tCommandOutputPacket               PacketName = \"CommandOutputPacket\"\n\tUpdateTradePacket                 PacketName = \"UpdateTradePacket\"\n\tUpdateEquipPacket                 PacketName = \"UpdateEquipPacket\"\n\tResourcePackDataInfoPacket        PacketName = \"ResourcePackDataInfoPacket\"\n\tResourcePackChunkDataPacket       PacketName = \"ResourcePackChunkDataPacket\"\n\tResourcePackChunkRequestPacket    PacketName = \"ResourcePackChunkRequestPacket\"\n\tTransferPacket                    PacketName = \"TransferPacket\"\n\tPlaySoundPacket                   PacketName = \"PlaySoundPacket\"\n\tStopSoundPacket                   PacketName = \"StopSoundPacket\"\n\tSetTitlePacket                    PacketName = \"SetTitlePacket\"\n\tAddBehaviorTreePacket             PacketName = \"AddBehaviorTreePacket\"\n\tStructureBlockUpdatePacket        PacketName = \"StructureBlockUpdatePacket\"\n\tShowStoreOfferPacket              PacketName = \"ShowStoreOfferPacket\"\n\tPurchaseReceiptPacket             PacketName = \"PurchaseReceiptPacket\"\n\tPlayerSkinPacket                  PacketName = \"PlayerSkinPacket\"\n\tSubClientLoginPacket              PacketName = \"SubClientLoginPacket\"\n\tWSConnectPacket                   PacketName = \"WSConnectPacket\"\n\tSetLastHurtByPacket               PacketName = \"SetLastHurtByPacket\"\n\tBookEditPacket                    PacketName = \"BookEditPacket\"\n\tNpcRequestPacket                  PacketName = \"NpcRequestPacket\"\n\tPhotoTransferPacket               PacketName = \"PhotoTransferPacket\"\n\tModalFormRequestPacket            PacketName = \"ModalFormRequestPacket\"\n\tModalFormResponsePacket           PacketName = \"ModalFormResponsePacket\"\n\tServerSettingsRequestPacket       PacketName = \"ServerSettingsRequestPacket\"\n\tServerSettingsResponsePacket      PacketName = \"ServerSettingsResponsePacket\"\n\tShowProfilePacket                 PacketName = \"ShowProfilePacket\"\n\tSetDefaultGameTypePacket          PacketName = \"SetDefaultGameTypePacket\"\n\tNetworkChunkPublisherUpdatePacket PacketName = \"NetworkChunkPublisherUpdatePacket\"\n)\n"
  },
  {
    "path": "net/info/protocol_ids.go",
    "content": "package info\n\nvar PacketIds = PacketIdList{\n\tLoginPacket:                       0x01,\n\tPlayStatusPacket:                  0x02,\n\tServerHandshakePacket:             0x03,\n\tClientHandshakePacket:             0x04,\n\tDisconnectPacket:                  0x05,\n\tResourcePackInfoPacket:            0x06,\n\tResourcePackStackPacket:           0x07,\n\tResourcePackClientResponsePacket:  0x08,\n\tTextPacket:                        0x09,\n\tSetTimePacket:                     0x0a,\n\tStartGamePacket:                   0x0b,\n\tAddPlayerPacket:                   0x0c,\n\tAddEntityPacket:                   0x0d,\n\tRemoveEntityPacket:                0x0e,\n\tAddItemEntityPacket:               0x0f,\n\tAddHangingEntityPacket:            0x10,\n\tTakeItemEntityPacket:              0x11,\n\tMoveEntityPacket:                  0x12,\n\tMovePlayerPacket:                  0x13,\n\tRiderJumpPacket:                   0x14,\n\tUpdateBlockPacket:                 0x15,\n\tAddPaintingPacket:                 0x16,\n\tExplodePacket:                     0x17,\n\tLevelSoundEventPacket:             0x18,\n\tLevelEventPacket:                  0x19,\n\tBlockEventPacket:                  0x1a,\n\tEntityEventPacket:                 0x1b,\n\tMobEffectPacket:                   0x1c,\n\tUpdateAttributesPacket:            0x1d,\n\tInventoryTransactionPacket:        0x1e,\n\tMobEquipmentPacket:                0x1f,\n\tMobArmorEquipmentPacket:           0x20,\n\tInteractPacket:                    0x21,\n\tBlockPickRequestPacket:            0x22,\n\tEntityPickRequestPacket:           0x23,\n\tPlayerActionPacket:                0x24,\n\tEntityFallPacket:                  0x25,\n\tHurtArmorPacket:                   0x26,\n\tSetEntityDataPacket:               0x27,\n\tSetEntityMotionPacket:             0x28,\n\tSetEntityLinkPacket:               0x29,\n\tSetHealthPacket:                   0x2a,\n\tSetSpawnPositionPacket:            0x2b,\n\tAnimatePacket:                     0x2c,\n\tRespawnPacket:                     0x2d,\n\tContainerOpenPacket:               0x2e,\n\tContainerClosePacket:              0x2f,\n\tPlayerHotbarPacket:                0x30,\n\tInventoryContentPacket:            0x31,\n\tInventorySlotPacket:               0x32,\n\tContainerSetDataPacket:            0x33,\n\tCraftingDataPacket:                0x34,\n\tCraftingEventPacket:               0x35,\n\tGuiDataPickItemPacket:             0x36,\n\tAdventureSettingsPacket:           0x37,\n\tBlockEntityDataPacket:             0x38,\n\tPlayerInputPacket:                 0x39,\n\tFullChunkDataPacket:               0x3a,\n\tSetCommandsEnabledPacket:          0x3b,\n\tSetDifficultyPacket:               0x3c,\n\tChangeDimensionPacket:             0x3d,\n\tSetPlayerGameTypePacket:           0x3e,\n\tPlayerListPacket:                  0x3f,\n\tSimpleEventPacket:                 0x40,\n\tEventPacket:                       0x41,\n\tSpawnExperienceOrbPacket:          0x42,\n\tClientboundMapItemDataPacket:      0x43,\n\tMapInfoRequestPacket:              0x44,\n\tRequestChunkRadiusPacket:          0x45,\n\tChunkRadiusUpdatedPacket:          0x46,\n\tItemFrameDropItemPacket:           0x47,\n\tGameRulesChangedPacket:            0x48,\n\tCameraPacket:                      0x49,\n\tBossEventPacket:                   0x4a,\n\tShowCreditsPacket:                 0x4b,\n\tAvailableCommandsPacket:           0x4c,\n\tCommandRequestPacket:              0x4d,\n\tCommandBlockUpdatePacket:          0x4e,\n\tCommandOutputPacket:               0x4f,\n\tUpdateTradePacket:                 0x50,\n\tUpdateEquipPacket:                 0x51,\n\tResourcePackDataInfoPacket:        0x52,\n\tResourcePackChunkDataPacket:       0x53,\n\tResourcePackChunkRequestPacket:    0x54,\n\tTransferPacket:                    0x55,\n\tPlaySoundPacket:                   0x56,\n\tStopSoundPacket:                   0x57,\n\tSetTitlePacket:                    0x58,\n\tAddBehaviorTreePacket:             0x59,\n\tStructureBlockUpdatePacket:        0x5a,\n\tShowStoreOfferPacket:              0x5b,\n\tPurchaseReceiptPacket:             0x5c,\n\tPlayerSkinPacket:                  0x5d,\n\tSubClientLoginPacket:              0x5e,\n\tWSConnectPacket:                   0x5f,\n\tSetLastHurtByPacket:               0x60,\n\tBookEditPacket:                    0x61,\n\tNpcRequestPacket:                  0x62,\n\tPhotoTransferPacket:               0x63,\n\tModalFormRequestPacket:            0x64,\n\tModalFormResponsePacket:           0x65,\n\tServerSettingsRequestPacket:       0x66,\n\tServerSettingsResponsePacket:      0x67,\n\tShowProfilePacket:                 0x68,\n\tSetDefaultGameTypePacket:          0x69,\n\tNetworkChunkPublisherUpdatePacket: 0x79,\n}\n"
  },
  {
    "path": "net/manager.go",
    "content": "package net\n\nimport (\n\t\"fmt\"\n\t\"github.com/google/uuid\"\n\t\"github.com/irmine/goraklib/server\"\n\t\"sync\"\n)\n\n// SessionManager is a struct managing Minecraft sessions.\n// A session manager holds multiple maps used to find sessions by given keys.\ntype SessionManager struct {\n\tmutex      sync.RWMutex\n\tnameMap    map[string]*MinecraftSession\n\tuuidMap    map[uuid.UUID]*MinecraftSession\n\txuidMap    map[string]*MinecraftSession\n\tsessionMap map[string]*MinecraftSession\n}\n\n// NewSessionManager returns a new session manager.\nfunc NewSessionManager() *SessionManager {\n\treturn &SessionManager{sync.RWMutex{}, make(map[string]*MinecraftSession), make(map[uuid.UUID]*MinecraftSession), make(map[string]*MinecraftSession), make(map[string]*MinecraftSession)}\n}\n\n// GetSessions returns the name => session map of the manager.\nfunc (manager *SessionManager) GetSessions() map[string]*MinecraftSession {\n\treturn manager.nameMap\n}\n\n// AddMinecraftSession adds the given Minecraft session to the manager.\nfunc (manager *SessionManager) AddMinecraftSession(session *MinecraftSession) {\n\tmanager.mutex.Lock()\n\tmanager.nameMap[session.GetName()] = session\n\tmanager.uuidMap[session.GetUUID()] = session\n\tmanager.xuidMap[session.GetXUID()] = session\n\tmanager.sessionMap[fmt.Sprint(session.GetSession())] = session\n\tmanager.mutex.Unlock()\n}\n\n// RemoveMinecraftSession removes a Minecraft session from the manager.\nfunc (manager *SessionManager) RemoveMinecraftSession(session *MinecraftSession) {\n\tif session != nil {\n\t\tmanager.mutex.Lock()\n\t\tdelete(manager.nameMap, session.GetPlayer().GetName())\n\t\tdelete(manager.uuidMap, session.GetUUID())\n\t\tdelete(manager.xuidMap, session.GetXUID())\n\t\tdelete(manager.sessionMap, fmt.Sprint(session.GetSession()))\n\t\tmanager.mutex.Unlock()\n\t}\n}\n\n// GetSessionCount returns the session count of the manager.\nfunc (manager *SessionManager) GetSessionCount() int {\n\treturn len(manager.nameMap)\n}\n\n// HasSession checks if the session manager has a session with the given name.\nfunc (manager *SessionManager) HasSession(name string) bool {\n\tmanager.mutex.RLock()\n\tvar _, ok = manager.nameMap[name]\n\tmanager.mutex.RUnlock()\n\treturn ok\n}\n\n// GetSession attempts to retrieve a session by its name.\n// A bool is returned indicating success.\nfunc (manager *SessionManager) GetSession(name string) (*MinecraftSession, bool) {\n\tmanager.mutex.RLock()\n\tvar session, ok = manager.nameMap[name]\n\tmanager.mutex.RUnlock()\n\treturn session, ok\n}\n\n// HasSessionWithRakNetSession checks if the session manager has a session with the given RakNet session.\nfunc (manager *SessionManager) HasSessionWithRakNetSession(rakNetSession *server.Session) bool {\n\tmanager.mutex.RLock()\n\tvar _, ok = manager.sessionMap[fmt.Sprint(rakNetSession)]\n\tmanager.mutex.RUnlock()\n\treturn ok\n}\n\n// GetSessionByRakNetSession attempts to retrieve a session by its RakNet session.\n// A bool is returned indicating success.\nfunc (manager *SessionManager) GetSessionByRakNetSession(rakNetSession *server.Session) (*MinecraftSession, bool) {\n\tmanager.mutex.RLock()\n\tvar session, ok = manager.sessionMap[fmt.Sprint(rakNetSession)]\n\tmanager.mutex.RUnlock()\n\treturn session, ok\n}\n\n// HasSessionWithXUID checks if the session manager has a session with the given XUID.\nfunc (manager *SessionManager) HasSessionWithXUID(xuid string) bool {\n\tmanager.mutex.RLock()\n\tvar _, ok = manager.xuidMap[xuid]\n\tmanager.mutex.RUnlock()\n\treturn ok\n}\n\n// GetSessionByXUID attempts to retrieve a session by its XUID.\n// A bool is returned indicating success.\nfunc (manager *SessionManager) GetSessionByXUID(xuid string) (*MinecraftSession, bool) {\n\tmanager.mutex.RLock()\n\tvar session, ok = manager.xuidMap[xuid]\n\tmanager.mutex.RUnlock()\n\treturn session, ok\n}\n\n// HasSessionWithUUID checks if the session manager has a session with the given UUID.\nfunc (manager *SessionManager) HasSessionWithUUID(uuid uuid.UUID) bool {\n\tmanager.mutex.RLock()\n\tvar _, ok = manager.uuidMap[uuid]\n\tmanager.mutex.RUnlock()\n\treturn ok\n}\n\n// GetSessionByUUID attempts to retrieve a session by its UUID.\n// A bool is returned indicating success.\nfunc (manager *SessionManager) GetSessionByUUID(uuid uuid.UUID) (*MinecraftSession, bool) {\n\tmanager.mutex.RLock()\n\tvar session, ok = manager.uuidMap[uuid]\n\tmanager.mutex.RUnlock()\n\treturn session, ok\n}\n"
  },
  {
    "path": "net/minecraft_packet_batch.go",
    "content": "package net\n\nimport (\n\t\"bytes\"\n\t\"compress/zlib\"\n\t\"crypto/cipher\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"io/ioutil\"\n\n\t\"github.com/irmine/binutils\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/gomine/text\"\n)\n\nconst McpeFlag = 0xFE\n\ntype MinecraftPacketBatch struct {\n\t*binutils.Stream\n\traw             []byte\n\tpackets         []packets.IPacket\n\tsession         *MinecraftSession\n\tneedsEncryption bool\n}\n\n// NewMinecraftPacketBatch returns a new Minecraft Packet Batch used to decode/encode batches from Encapsulated Packets.\nfunc NewMinecraftPacketBatch(session *MinecraftSession) *MinecraftPacketBatch {\n\tvar batch = &MinecraftPacketBatch{}\n\tbatch.Stream = binutils.NewStream()\n\tbatch.session = session\n\n\tif session == nil {\n\t\tbatch.needsEncryption = false\n\t} else {\n\t\tbatch.needsEncryption = session.UsesEncryption()\n\t}\n\n\treturn batch\n}\n\n// Decode decodes the batch and separates packets. This does not decode the packets.\nfunc (batch *MinecraftPacketBatch) Decode() {\n\tdefer func() {\n\t\tif err := recover(); err != nil {\n\t\t\ttext.DefaultLogger.Debug(err)\n\t\t}\n\t}()\n\n\tvar mcpeFlag = batch.GetByte()\n\tif mcpeFlag != McpeFlag {\n\t\treturn\n\t}\n\tbatch.raw = batch.Buffer[batch.Offset:]\n\n\tif batch.needsEncryption {\n\t\tbatch.decrypt()\n\t}\n\tvar err = batch.decompress()\n\tif err != nil {\n\t\ttext.DefaultLogger.LogError(err)\n\t\treturn\n\t}\n\n\tbatch.ResetStream()\n\tbatch.SetBuffer(batch.raw)\n\n\tvar packetData [][]byte\n\n\tfor !batch.Feof() {\n\t\tpacketData = append(packetData, batch.GetLengthPrefixedBytes())\n\t}\n\n\tbatch.fetchPackets(packetData)\n}\n\n// Encode encodes all packets in the batch and zlib encodes them.\nfunc (batch *MinecraftPacketBatch) Encode() {\n\tbatch.ResetStream()\n\tbatch.PutByte(McpeFlag)\n\n\tvar stream = binutils.NewStream()\n\tbatch.putPackets(stream)\n\n\tvar zlibData = batch.compress(stream)\n\tvar data = zlibData\n\tif batch.needsEncryption {\n\t\tdata = batch.encrypt(data)\n\t}\n\n\tbatch.PutBytes(data)\n}\n\n// fetchPackets fetches all packets from the raw packet buffers.\nfunc (batch *MinecraftPacketBatch) fetchPackets(packetData [][]byte) {\n\tfor _, data := range packetData {\n\t\tif len(data) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tpacketId := int(data[0])\n\n\t\tif !batch.session.adapter.packetManager.IsPacketRegistered(packetId) {\n\t\t\ttext.DefaultLogger.Debug(\"Unknown Minecraft packet with ID:\", packetId)\n\t\t\tcontinue\n\t\t}\n\t\tpacket := batch.session.adapter.packetManager.GetPacket(packetId)\n\n\t\tpacket.SetBuffer(data)\n\t\tbatch.packets = append(batch.packets, packet)\n\t}\n}\n\n// peekProtocol peeks in the packet's payload, looking for the bedrock.\nfunc (batch *MinecraftPacketBatch) peekProtocol(packetData []byte) int32 {\n\tif packetData[0] != 0x01 {\n\t\treturn 0\n\t}\n\tvar protocolBytes = packetData[1:5]\n\tvar offset = 0\n\tvar protocol = binutils.ReadInt(&protocolBytes, &offset)\n\tif protocol == 0 {\n\t\toffset = 0\n\t\tprotocolBytes = packetData[3:7]\n\t\tprotocol = binutils.ReadInt(&protocolBytes, &offset)\n\t}\n\treturn protocol\n}\n\n// encrypt encrypts the data passed to the function.\nfunc (batch *MinecraftPacketBatch) encrypt(d []byte) []byte {\n\tvar data = batch.session.GetEncryptionHandler().Data\n\td = append(d, batch.session.GetEncryptionHandler().ComputeSendChecksum(d)...)\n\n\tfor i := range d {\n\t\tvar cfb = cipher.NewCFBEncrypter(data.EncryptCipher, data.EncryptIV)\n\t\tcfb.XORKeyStream(d[i:i+1], d[i:i+1])\n\t\tdata.EncryptIV = append(data.EncryptIV[1:], d[i])\n\t}\n\n\treturn d\n}\n\n// decrypt decrypts the buffer of the packet.\nfunc (batch *MinecraftPacketBatch) decrypt() {\n\tvar data = batch.session.GetEncryptionHandler().Data\n\tfor i, b := range batch.raw {\n\t\tvar cfb = cipher.NewCFBDecrypter(data.DecryptCipher, data.DecryptIV)\n\t\tcfb.XORKeyStream(batch.raw[i:i+1], batch.raw[i:i+1])\n\t\tdata.DecryptIV = append(data.DecryptIV[1:], b)\n\t}\n}\n\n// putPackets puts all packets of the batch inside of the stream.\nfunc (batch *MinecraftPacketBatch) putPackets(stream *binutils.Stream) {\n\tfor _, packet := range batch.GetPackets() {\n\t\tpacket.EncodeHeader()\n\t\tpacket.Encode()\n\t\tstream.PutLengthPrefixedBytes(packet.GetBuffer())\n\t}\n}\n\n// compress zlib compresses the data in the stream and returns it.\nfunc (batch *MinecraftPacketBatch) compress(stream *binutils.Stream) []byte {\n\tvar buff = bytes.Buffer{}\n\tvar writer = zlib.NewWriter(&buff)\n\twriter.Write(stream.Buffer)\n\twriter.Close()\n\n\treturn buff.Bytes()\n}\n\n// decompress decompresses the zlib compressed buffer.\nfunc (batch *MinecraftPacketBatch) decompress() error {\n\tvar reader = bytes.NewReader(batch.raw)\n\tzlibReader, err := zlib.NewReader(reader)\n\ttext.DefaultLogger.LogError(err)\n\n\tif err != nil {\n\t\ttext.DefaultLogger.Debug(hex.EncodeToString(batch.raw))\n\t\treturn err\n\t}\n\tif zlibReader == nil {\n\t\treturn errors.New(\"an error occurred when decompressing zlib\")\n\t}\n\tzlibReader.Close()\n\n\tbatch.raw, err = ioutil.ReadAll(zlibReader)\n\n\treturn err\n}\n\n// AddPacket adds a packet to the batch when encoding.\nfunc (batch *MinecraftPacketBatch) AddPacket(packet packets.IPacket) {\n\tbatch.packets = append(batch.packets, packet)\n}\n\n// GetPackets returns all packets inside of the batch.\n// This only returns correctly when done after decoding, or before encoding.\nfunc (batch *MinecraftPacketBatch) GetPackets() []packets.IPacket {\n\treturn batch.packets\n}\n"
  },
  {
    "path": "net/minecraft_session.go",
    "content": "package net\n\nimport (\n\t\"fmt\"\n\t\"github.com/google/uuid\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/gomine/net/packets/types\"\n\t\"github.com/irmine/gomine/permissions\"\n\t\"github.com/irmine/gomine/players\"\n\t\"github.com/irmine/gomine/text\"\n\t\"github.com/irmine/gomine/utils\"\n\t\"github.com/irmine/goraklib/protocol\"\n\t\"github.com/irmine/goraklib/server\"\n\t\"github.com/irmine/worlds\"\n\t\"github.com/irmine/worlds/blocks\"\n\t\"github.com/irmine/worlds/chunks\"\n\t\"math\"\n\t\"strings\"\n)\n\ntype MinecraftSession struct {\n\tadapter *NetworkAdapter\n\tsession *server.Session\n\n\tplayer *players.Player\n\n\tuuid     uuid.UUID\n\txuid     string\n\tclientId int\n\n\tprotocolNumber   int32\n\tminecraftVersion string\n\n\tlanguage string\n\n\tclientPlatform int32\n\n\tencryptionHandler     *utils.EncryptionHandler\n\tusesEncryption        bool\n\txboxLiveAuthenticated bool\n\n\tviewDistance int32\n\tchunkLoader  *worlds.Loader\n\n\tpermissions     map[string]*permissions.Permission\n\tpermissionGroup *permissions.Group\n\n\tConnected         bool\n}\n\n// NewMinecraftSession returns a new Minecraft session with the given RakNet session.\nfunc NewMinecraftSession(adapter *NetworkAdapter, session *server.Session) *MinecraftSession {\n\treturn &MinecraftSession{adapter, session, nil, uuid.New(), \"\", 0, 0, \"\", \"\", 0, utils.NewEncryptionHandler(), false, false, 0, nil, nil, nil, false}\n}\n\n// SetData sets the basic session data of the Minecraft Session\nfunc (session *MinecraftSession) SetData(permissionManager *permissions.Manager, data types.SessionData) {\n\tsession.permissions = make(map[string]*permissions.Permission)\n\tsession.permissionGroup = permissionManager.GetDefaultGroup()\n\n\tsession.uuid = data.ClientUUID\n\tsession.xuid = data.ClientXUID\n\tsession.clientId = data.ClientId\n\tsession.protocolNumber = data.ProtocolNumber\n\tsession.minecraftVersion = data.GameVersion\n\tsession.language = data.Language\n\tsession.clientPlatform = int32(data.DeviceOS)\n\tsession.chunkLoader = worlds.NewLoader(nil, 0, 0)\n\tsession.chunkLoader.PublisherUpdateFunction = func() {\n\t\tvar vector = session.player.Position\n\t\tvar position = blocks.NewPosition(int32(vector.X), uint32(vector.Y), int32(vector.Z))\n\t\tsession.SendNetworkChunkPublisherUpdate(position, uint32(session.GetViewDistance() * 16))\n\t}\n\tsession.chunkLoader.LoadFunction = func(chunk *chunks.Chunk) {\n\t\tsession.SendFullChunkData(chunk)\n\t\tchunk.AddViewer(session)\n\t\tchunk.AddEntity(session.player)\n\t}\n\tsession.chunkLoader.UnloadFunction = func(chunk *chunks.Chunk) {\n\t\tchunk.RemoveViewer(session)\n\t\tchunk.RemoveEntity(session.player.GetRuntimeId())\n\t}\n}\n\n// GetPlayer returns the player associated with the Minecraft session.\n// This player may not yet exist during the login sequence, and this function may return nil.\nfunc (session *MinecraftSession) GetPlayer() *players.Player {\n\treturn session.player\n}\n\n// SetPlayer sets the player associated with the Minecraft session.\n// Network actions will be executed on this player.\nfunc (session *MinecraftSession) SetPlayer(player *players.Player) {\n\tsession.player = player\n}\n\n// GetName returns the name of the player under the session.\nfunc (session *MinecraftSession) GetName() string {\n\tif session.player == nil {\n\t\treturn \"\"\n\t}\n\treturn session.player.GetName()\n}\n\n// GetDisplayName returns the display name of the player under the session.\nfunc (session *MinecraftSession) GetDisplayName() string {\n\tif session.player == nil {\n\t\treturn \"\"\n\t}\n\treturn session.player.GetDisplayName()\n}\n\n// HasSpawned checks if the player of the session has spawned.\nfunc (session *MinecraftSession) HasSpawned() bool {\n\treturn session.GetPlayer().GetDimension() != nil\n}\n\n// SetViewDistance sets the view distance of this player.\nfunc (session *MinecraftSession) SetViewDistance(distance int32) {\n\tsession.viewDistance = distance\n}\n\n// GetViewDistance returns the view distance of this player.\nfunc (session *MinecraftSession) GetViewDistance() int32 {\n\treturn session.viewDistance\n}\n\n// GetChunkLoader returns the chunk loader of the session.\nfunc (session *MinecraftSession) GetChunkLoader() *worlds.Loader {\n\treturn session.chunkLoader\n}\n\n// GetPlatform returns the platform the client uses to player the game.\nfunc (session *MinecraftSession) GetPlatform() int32 {\n\treturn session.clientPlatform\n}\n\n// GetProtocolNumber returns the bedrock number the client used to join the server.\nfunc (session *MinecraftSession) GetProtocolNumber() int32 {\n\treturn session.protocolNumber\n}\n\n// GetGameVersion returns the Minecraft version the player used to join the server.\nfunc (session *MinecraftSession) GetGameVersion() string {\n\treturn session.minecraftVersion\n}\n\n// GetSession returns the GoRakLib session of this session.\nfunc (session *MinecraftSession) GetSession() *server.Session {\n\treturn session.session\n}\n\n// GetPing returns the ping of the session in milliseconds.\nfunc (session *MinecraftSession) GetPing() int64 {\n\treturn session.session.CurrentPing\n}\n\n// GetUUID returns the UUID of this session.\nfunc (session *MinecraftSession) GetUUID() uuid.UUID {\n\treturn session.uuid\n}\n\n// GetXUID returns the XUID of this session.\nfunc (session *MinecraftSession) GetXUID() string {\n\treturn session.xuid\n}\n\n// SetLanguage sets the language (locale) of this session.\nfunc (session *MinecraftSession) SetLanguage(language string) {\n\tsession.language = language\n}\n\n// GetLanguage returns the language (locale) of this session.\nfunc (session *MinecraftSession) GetLanguage() string {\n\treturn session.language\n}\n\n// GetClientId returns the client ID of this session.\nfunc (session *MinecraftSession) GetClientId() int {\n\treturn session.clientId\n}\n\n// GetEncryptionHandler returns the handler used for encryption.\nfunc (session *MinecraftSession) GetEncryptionHandler() *utils.EncryptionHandler {\n\treturn session.encryptionHandler\n}\n\n// UsesEncryption checks if the session uses encryption or not.\nfunc (session *MinecraftSession) UsesEncryption() bool {\n\treturn session.usesEncryption\n}\n\n// EnableEncryption enables encryption for this session and computes secret key bytes.\nfunc (session *MinecraftSession) EnableEncryption() {\n\tsession.usesEncryption = true\n\tsession.encryptionHandler.Data.ComputeSharedSecret()\n\tsession.encryptionHandler.Data.ComputeSecretKeyBytes()\n}\n\n// IsXBOXLiveAuthenticated checks if the session logged in while being logged into XBOX Live.\nfunc (session *MinecraftSession) IsXBOXLiveAuthenticated() bool {\n\treturn session.xboxLiveAuthenticated\n}\n\n// SetXBOXLiveAuthenticated sets the session XBOX Live authenticated.\nfunc (session *MinecraftSession) SetXBOXLiveAuthenticated(value bool) {\n\tsession.xboxLiveAuthenticated = value\n}\n\n// SendMessage sends a text message to the Minecraft session.\nfunc (session *MinecraftSession) SendMessage(message ...interface{}) {\n\tsession.SendText(types.Text{Message: strings.Trim(fmt.Sprint(message), \"[]\")})\n}\n\n// GetPermissionGroup returns the permission group this session is in.\nfunc (session *MinecraftSession) GetPermissionGroup() *permissions.Group {\n\treturn session.permissionGroup\n}\n\n// SetPermissionGroup sets the permission group of this session.\nfunc (session *MinecraftSession) SetPermissionGroup(group *permissions.Group) {\n\tsession.permissionGroup = group\n}\n\n// HasPermission checks if this session has a permission.\nfunc (session *MinecraftSession) HasPermission(permission string) bool {\n\tif session.GetPermissionGroup().HasPermission(permission) {\n\t\treturn true\n\t}\n\tvar _, exists = session.permissions[permission]\n\treturn exists\n}\n\n// AddPermission adds a permission to the session.\n// Returns true if a permission with the same name was overwritten.\nfunc (session *MinecraftSession) AddPermission(permission *permissions.Permission) bool {\n\tvar hasPermission = session.HasPermission(permission.GetName())\n\n\tsession.permissions[permission.GetName()] = permission\n\n\treturn hasPermission\n}\n\n// RemovePermission deletes a permission from the session.\n// This does not delete the permission from the group the session is in.\nfunc (session *MinecraftSession) RemovePermission(permission string) bool {\n\tif !session.HasPermission(permission) {\n\t\treturn false\n\t}\n\tdelete(session.permissions, permission)\n\n\treturn true\n}\n\nfunc (session *MinecraftSession) SendSkin(target *MinecraftSession) {\n\tvar player = session.GetPlayer()\n\ttarget.SendPlayerSkin(player.GetUUID(), player.GetSkinId(), player.GetGeometryName(), player.GetGeometryData(), player.GetSkinData(), player.GetCapeData())\n}\n\n// SendPacket sends a packet to this session.\nfunc (session *MinecraftSession) SendPacket(packet packets.IPacket) {\n\tif session.session == nil {\n\t\treturn\n\t}\n\tvar b = NewMinecraftPacketBatch(session)\n\tb.AddPacket(packet)\n\n\tsession.SendBatch(b)\n}\n\n// SendBatch sends a batch to this session.\nfunc (session *MinecraftSession) SendBatch(batch *MinecraftPacketBatch) {\n\tif session.session == nil {\n\t\treturn\n\t}\n\tsession.session.SendPacket(batch, protocol.ReliabilityReliable, server.PriorityMedium)\n}\n\n// HandlePacket handles packets of this session.\nfunc (session *MinecraftSession) HandlePacket(packet packets.IPacket) {\n\tpriorityHandlers := session.adapter.packetManager.GetHandlersById(packet.GetId())\n\n\tvar handled = false\nhandling:\n\tfor _, h := range priorityHandlers {\n\t\tfor _, iHandler := range h {\n\t\t\tif handler, ok := iHandler.(*PacketHandler); ok {\n\t\t\t\tif packet.IsDiscarded() {\n\t\t\t\t\tbreak handling\n\t\t\t\t}\n\n\t\t\t\tret := handler.function(packet, session)\n\t\t\t\tif !handled {\n\t\t\t\t\thandled = ret\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif !handled {\n\t\ttext.DefaultLogger.Debug(\"Unhandled Minecraft packet with ID:\", packet.GetId())\n\t}\n}\n\nfunc (session *MinecraftSession) Close(reason string, hideDisconnectionScreen bool) {\n\tif session.Connected {\n\t\tloadedChunks := session.GetChunkLoader().GetLoadedChunks()\n\n\t\tfor _, online := range session.adapter.sessionManager.GetSessions() {\n\t\t\tonline.SendRemoveEntity(session.player.Entity.GetUniqueId())\n\t\t\tonline.player.RemoveViewer(session)\n\t\t}\n\n\t\tfor _, chunk := range loadedChunks {\n\t\t\tchunk.RemoveViewer(session)\n\t\t\tchunk.RemoveEntity(session.player.Entity.GetRuntimeId())\n\t\t}\n\n\t\tsession.player.Close()\n\t}\n\tsession.SendDisconnect(reason, hideDisconnectionScreen)\n}\n\nfunc (session *MinecraftSession) Kick(reason string, hideDisconnectionScreen bool, isAdmin bool) {\n\tif isAdmin {\n\t\treason = \"Kicked By Admin. Reason: \" + reason\n\t\tsession.Close(reason, hideDisconnectionScreen)\n\t\ttext.DefaultLogger.Info(session.GetDisplayName() + \" Disconnected.\", reason)\n\t}else{\n\t\tsession.Close(reason, hideDisconnectionScreen)\n\t\ttext.DefaultLogger.Info(session.GetDisplayName() + \" Disconnected.\", reason)\n\t}\n}\n\n// SyncMove synchronizes the server's player movement with the client movement.\nfunc (session *MinecraftSession) SyncMove(x, y, z float64, pitch, yaw, headYaw float64, onGround bool) {\n\tsession.player.SyncMove(x, y, z, pitch, yaw, headYaw, onGround)\n}\n\nfunc (session *MinecraftSession) Tick() {\n\tif session.Connected {\n\t\tsession.GetChunkLoader().Warp(session.GetPlayer().GetDimension(), int32(math.Floor(session.player.Position.X))>>4, int32(math.Floor(session.player.Position.Z))>>4)\n\t\tsession.GetChunkLoader().Request(session.GetViewDistance(), 40)\n\t}\n}\n"
  },
  {
    "path": "net/network_adapter.go",
    "content": "package net\n\nimport (\n\t\"github.com/irmine/gomine/net/packets\"\n\tprotocol2 \"github.com/irmine/gomine/net/protocol\"\n\t\"github.com/irmine/gomine/text\"\n\t\"github.com/irmine/goraklib/protocol\"\n\t\"github.com/irmine/goraklib/server\"\n\t\"net\"\n)\n\ntype NetworkAdapter struct {\n\trakLibManager   *server.Manager\n\tpacketManager   protocol2.IPacketManager\n\tsessionManager  *SessionManager\n}\n\n// NewNetworkAdapter returns a new Network adapter to adapt to the RakNet server.\nfunc NewNetworkAdapter(packetManager protocol2.IPacketManager, sessionManager *SessionManager) *NetworkAdapter {\n\tvar manager = server.NewManager()\n\tvar adapter = &NetworkAdapter{manager, packetManager, sessionManager}\n\n\tmanager.PacketFunction = func(packet []byte, session *server.Session) {\n\t\tvar minecraftSession *MinecraftSession\n\t\tvar ok bool\n\t\tif minecraftSession, ok = adapter.sessionManager.GetSessionByRakNetSession(session); !ok {\n\t\t\tminecraftSession = NewMinecraftSession(adapter, session)\n\t\t}\n\t\tadapter.HandlePacket(minecraftSession, packet)\n\t}\n\tmanager.DisconnectFunction = func(session *server.Session) {\n\t\ttext.DefaultLogger.Debug(session, \"disconnected!\")\n\n\t}\n\tmanager.ConnectFunction = func(session *server.Session) {\n\t\ttext.DefaultLogger.Debug(session, \"connected!\")\n\t}\n\treturn adapter\n}\n\n// GetRakLibManager returns the GoRakLib manager of the network adapter.\nfunc (adapter *NetworkAdapter) GetRakLibManager() *server.Manager {\n\treturn adapter.rakLibManager\n}\n\n// HandlePackets handles all packets of the given session + player.\nfunc (adapter *NetworkAdapter) HandlePacket(session *MinecraftSession, buffer []byte) {\n\tbatch := NewMinecraftPacketBatch(session)\n\tbatch.Buffer = buffer\n\tbatch.Decode()\n\n\tfor _, packet := range batch.GetPackets() {\n\t\tif session.GetProtocolNumber() < 120 {\n\t\t\tpacket.DecodeId()\n\t\t} else {\n\t\t\tpacket.DecodeHeader()\n\t\t}\n\t\tpacket.Decode()\n\n\t\tsession.HandlePacket(packet)\n\t}\n}\n\n// GetSession returns a GoRakLib session by an address and port.\nfunc (adapter *NetworkAdapter) GetSession(address string, port uint16) *server.Session {\n\tvar session, _ = adapter.rakLibManager.Sessions.GetSession(&net.UDPAddr{IP: net.ParseIP(address), Port: int(port)})\n\treturn session\n}\n\n// SendPacket sends a packet to the given Minecraft session with the given priority.\nfunc (adapter *NetworkAdapter) SendPacket(pk packets.IPacket, session *MinecraftSession, priority server.Priority) {\n\tvar b = NewMinecraftPacketBatch(session)\n\tb.AddPacket(pk)\n\n\tadapter.SendBatch(b, session.GetSession(), priority)\n}\n\n// SendBatch sends a Minecraft packet batch to the given GoRakLib session with the given priority.\nfunc (adapter *NetworkAdapter) SendBatch(batch *MinecraftPacketBatch, session *server.Session, priority server.Priority) {\n\tsession.SendPacket(batch, protocol.ReliabilityReliableOrdered, priority)\n}\n"
  },
  {
    "path": "net/packet_handler.go",
    "content": "package net\n\nimport (\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\n// Packet handlers can be registered to listen on certain packet IDs.\n// Handlers can be registered on unhandled packets in order to handle them from a plugin.\n// Every packet handler has a handling function that handles the incoming packet.\ntype PacketHandler struct {\n\tfunction func(packet packets.IPacket, session *MinecraftSession) bool\n\tpriority int\n}\n\n// NewPacketHandler returns a new packet handler with the given ID.\n// NewPacketHandler will by default use a priority of 5.\nfunc NewPacketHandler(function func(packet packets.IPacket, session *MinecraftSession) bool) *PacketHandler {\n\treturn &PacketHandler{function, 5}\n}\n\n// SetPriority sets the priority of this handler in an integer 0 - 10.\n// 0 is executed first, 10 is executed last.\nfunc (handler *PacketHandler) SetPriority(priority int) bool {\n\tif priority > 10 || priority < 0 {\n\t\treturn false\n\t}\n\thandler.priority = priority\n\treturn true\n}\n\n// GetPriority returns the priority of this handler in an integer 0 - 10.\nfunc (handler *PacketHandler) GetPriority() int {\n\treturn handler.priority\n}\n"
  },
  {
    "path": "net/packets/bedrock/add_entity.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/golang/geo/r3\"\n\t\"github.com/irmine/worlds/entities/data\"\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype AddEntityPacket struct {\n\t*packets.Packet\n\tUniqueId   int64\n\tRuntimeId  uint64\n\tEntityType uint32\n\tPosition   r3.Vector\n\tMotion     r3.Vector\n\tRotation   data.Rotation\n\n\tAttributes data.AttributeMap\n\tEntityData map[uint32][]interface{}\n}\n\nfunc NewAddEntityPacket() *AddEntityPacket {\n\treturn &AddEntityPacket{packets.NewPacket(info.PacketIds[info.AddEntityPacket]), 0, 0, 0, r3.Vector{}, r3.Vector{}, data.Rotation{}, data.NewAttributeMap(), nil}\n}\n\nfunc (pk *AddEntityPacket) Encode() {\n\tpk.PutEntityUniqueId(pk.UniqueId)\n\tpk.PutEntityRuntimeId(pk.RuntimeId)\n\tpk.PutUnsignedVarInt(pk.EntityType)\n\tpk.PutVector(pk.Position)\n\tpk.PutVector(pk.Motion)\n\tpk.PutEntityRotation(pk.Rotation)\n\tpk.PutAttributeMap(pk.Attributes)\n\tpk.PutEntityData(pk.EntityData)\n\tpk.PutUnsignedVarInt(0)\n}\n\nfunc (pk *AddEntityPacket) Decode() {\n\tpk.UniqueId = pk.GetEntityUniqueId()\n\tpk.RuntimeId = pk.GetEntityRuntimeId()\n\tpk.EntityType = pk.GetUnsignedVarInt()\n\tpk.Position = pk.GetVector()\n\tpk.Motion = pk.GetVector()\n\tpk.Rotation = pk.GetEntityRotation()\n\tpk.Attributes = pk.GetAttributeMap()\n\tpk.EntityData = pk.GetEntityData()\n}\n"
  },
  {
    "path": "net/packets/bedrock/add_player.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/golang/geo/r3\"\n\t\"github.com/google/uuid\"\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/worlds/entities/data\"\n)\n\ntype AddPlayerPacket struct {\n\t*packets.Packet\n\tUUID            uuid.UUID\n\tUsername        string\n\tPlatformChatId  string\n\tEntityUniqueId  int64\n\tEntityRuntimeId uint64\n\tPosition        r3.Vector\n\tMotion          r3.Vector\n\tRotation        data.Rotation\n\t// HandItem TODO: Items.\n\tMetadata          map[uint32][]interface{}\n\tFlags             uint32\n\tCommandPermission uint32\n\tFlags2            uint32\n\tPlayerPermission  uint32\n\tCustomFlags       uint32\n\tLong1             int64\n\t// EntityLinks TODO\n\tDeviceID          string\n}\n\nfunc NewAddPlayerPacket() *AddPlayerPacket {\n\treturn &AddPlayerPacket{Packet: packets.NewPacket(info.PacketIds[info.AddPlayerPacket]), Metadata: make(map[uint32][]interface{}), Motion: r3.Vector{}}\n}\n\nfunc (pk *AddPlayerPacket) Encode() {\n\tpk.PutUUID(pk.UUID)\n\tpk.PutString(pk.Username)\n\n\tpk.PutEntityUniqueId(pk.EntityUniqueId)\n\tpk.PutEntityRuntimeId(pk.EntityRuntimeId)\n\tpk.PutString(pk.PlatformChatId)\n\n\tpk.PutVector(pk.Position)\n\tpk.PutVector(pk.Motion)\n\tpk.PutPlayerRotation(pk.Rotation)\n\n\tpk.PutVarInt(0) // TODO\n\tpk.PutEntityData(pk.Metadata)\n\n\tpk.PutUnsignedVarInt(pk.Flags)\n\tpk.PutUnsignedVarInt(pk.CommandPermission)\n\tpk.PutUnsignedVarInt(pk.Flags2)\n\tpk.PutUnsignedVarInt(pk.PlayerPermission)\n\tpk.PutUnsignedVarInt(pk.CustomFlags)\n\n\tpk.PutVarLong(pk.Long1)\n\n\tpk.PutUnsignedVarInt(0) // TODO\n\tpk.PutString(pk.DeviceID)\n}\n\nfunc (pk *AddPlayerPacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/animate.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\nconst (\n\tSwingArm = 1\n\tStopSleeping = 3\n\tCriticalHit = 4\n)\n\ntype AnimatePacket struct {\n\t*packets.Packet\n\tAction int32\n\tRuntimeId uint64\n\tFloat float32\n}\n\nfunc NewAnimatePacket() *AnimatePacket {\n\treturn &AnimatePacket{ Packet: packets.NewPacket(info.PacketIds[info.AnimatePacket])}\n}\n\nfunc (pk *AnimatePacket) Encode() {\n\tpk.PutVarInt(pk.Action)\n\tpk.PutUnsignedVarLong(pk.RuntimeId)\n\tif uint(pk.Action) & 0x80 == 1 {\n\t\tpk.PutLittleFloat(pk.Float)\n\t}\n}\n\nfunc (pk *AnimatePacket) Decode() {\n\tpk.Action = pk.GetVarInt()\n\tpk.RuntimeId = pk.GetUnsignedVarLong()\n\tif uint(pk.Action) & 0x80 == 1 {\n\t\tpk.Float = pk.GetLittleFloat()\n\t}\n}"
  },
  {
    "path": "net/packets/bedrock/chunk_radius_updated.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype ChunkRadiusUpdatedPacket struct {\n\t*packets.Packet\n\tRadius int32\n}\n\nfunc NewChunkRadiusUpdatedPacket() *ChunkRadiusUpdatedPacket {\n\treturn &ChunkRadiusUpdatedPacket{packets.NewPacket(info.PacketIds[info.ChunkRadiusUpdatedPacket]), 0}\n}\n\nfunc (pk *ChunkRadiusUpdatedPacket) Encode() {\n\tpk.PutVarInt(pk.Radius)\n}\n\nfunc (pk *ChunkRadiusUpdatedPacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/client_handshake.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype ClientHandshakePacket struct {\n\t*packets.Packet\n}\n\nfunc NewClientHandshakePacket() *ClientHandshakePacket {\n\treturn &ClientHandshakePacket{packets.NewPacket(info.PacketIds[info.ClientHandshakePacket])}\n}\n\nfunc (pk *ClientHandshakePacket) Encode() {\n\n}\n\nfunc (pk *ClientHandshakePacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/command_request.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/google/uuid\"\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype CommandRequestPacket struct {\n\t*packets.Packet\n\tCommandText string\n\tType        uint32\n\tUUID        uuid.UUID\n\tRequestId   string\n\tInternal    bool\n}\n\nfunc NewCommandRequestPacket() *CommandRequestPacket {\n\treturn &CommandRequestPacket{packets.NewPacket(info.PacketIds[info.CommandRequestPacket]), \"\", 0, uuid.New(), \"\", false}\n}\n\nfunc (pk *CommandRequestPacket) Encode() {\n\n}\n\nfunc (pk *CommandRequestPacket) Decode() {\n\tpk.CommandText = pk.GetString()\n\tpk.Type = pk.GetUnsignedVarInt()\n\tpk.UUID = pk.GetUUID()\n\tpk.RequestId = pk.GetString()\n\tpk.Internal = pk.GetBool()\n}\n"
  },
  {
    "path": "net/packets/bedrock/crafting_data.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype CraftingDataPacket struct {\n\t*packets.Packet\n}\n\nfunc NewCraftingDataPacket() *CraftingDataPacket {\n\treturn &CraftingDataPacket{packets.NewPacket(info.PacketIds[info.CraftingDataPacket])}\n}\n\nfunc (pk *CraftingDataPacket) Encode() {\n\tpk.PutUnsignedVarInt(0)\n\tpk.PutBool(true)\n}\n\nfunc (pk *CraftingDataPacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/disconnect.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype DisconnectPacket struct {\n\t*packets.Packet\n\tHideDisconnectionScreen bool\n\tMessage                 string\n}\n\nfunc NewDisconnectPacket() *DisconnectPacket {\n\treturn &DisconnectPacket{packets.NewPacket(info.PacketIds[info.DisconnectPacket]), true, \"\"}\n}\n\nfunc (pk *DisconnectPacket) Encode() {\n\tpk.PutBool(pk.HideDisconnectionScreen)\n\tpk.PutString(pk.Message)\n}\n\nfunc (pk *DisconnectPacket) Decode() {\n\tpk.HideDisconnectionScreen = pk.GetBool()\n\tpk.Message = pk.GetString()\n}\n"
  },
  {
    "path": "net/packets/bedrock/full_chunk_data.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype FullChunkDataPacket struct {\n\t*packets.Packet\n\tChunkX    int32\n\tChunkZ    int32\n\tChunkData []byte\n}\n\nfunc NewFullChunkDataPacket() *FullChunkDataPacket {\n\treturn &FullChunkDataPacket{Packet: packets.NewPacket(info.PacketIds[info.FullChunkDataPacket])}\n}\n\nfunc (pk *FullChunkDataPacket) Encode() {\n\tpk.PutVarInt(pk.ChunkX)\n\tpk.PutVarInt(pk.ChunkZ)\n\tpk.PutLengthPrefixedBytes(pk.ChunkData)\n}\n\nfunc (pk *FullChunkDataPacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/interact_packet.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\nconst (\n\tRightClick = 1\n\tLeftClick = 2\n\tLeaveCehicle = 3\n\tMouseOver = 4\n)\n\ntype InteractPacket struct {\n\t*packets.Packet\n\tAction byte\n\tRuntimeId uint64\n}\n\nfunc NewInteractPacket() *InteractPacket {\n\treturn &InteractPacket{ packets.NewPacket(info.PacketIds[info.InteractPacket]), 0, 0}\n}\n\nfunc (pk *InteractPacket) Encode() {\n\tpk.PutByte(pk.Action)\n\tpk.PutUnsignedVarLong(pk.RuntimeId)\n}\n\nfunc (pk *InteractPacket) Decode() {\n\tpk.Action = pk.GetByte()\n\tpk.RuntimeId = pk.GetUnsignedVarLong()\n}"
  },
  {
    "path": "net/packets/bedrock/inventory_transaction.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/golang/geo/r3\"\n\t\"github.com/irmine/gomine/items\"\n\t\"github.com/irmine/gomine/items/inventory/io\"\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/worlds/blocks\"\n)\n\n// Transaction Types\nconst (\n\tNormal = iota + 0\n\tMismatch\n\tUseItem\n\tUseItemOnEntity\n\tReleaseItem\n)\n\n// Action Types\nconst (\n\tItemClickBlock = iota + 0\n\tItemClickAir\n\tItemBreakBlock\n\n\t//CONSUMABLE ITEMS\n\tItemRelease = iota + 0\n\tItemConsume\n)\n\n// Entity Action types\nconst (\n\tItemOnEntityInteract = iota + 0\n\tItemOnEntityAttack\n)\n\ntype InventoryTransactionPacket struct {\n\t*packets.Packet\n\tActionList *io.InventoryActionIOList\n\tTransactionType, ActionType uint32\n\tFace, HotbarSlot int32\n\tItemSlot *items.Stack\n\tBlockPosition blocks.Position\n\tPlayerPosition, ClickPosition, HeadPosition r3.Vector\n\tRuntimeId uint64\n}\n\nfunc NewInventoryTransactionPacket() *InventoryTransactionPacket {\n\tpk := &InventoryTransactionPacket{Packet: packets.NewPacket(info.PacketIds[info.InventoryTransactionPacket]),\n\t\tActionList: io.NewInventoryActionIOList(),\n\t\tTransactionType: 0,\n\t\tActionType: 0,\n\t\tFace: 0,\n\t\tHotbarSlot: 0,\n\t\tItemSlot: &items.Stack{},\n\t\tPlayerPosition: r3.Vector{},\n\t\tClickPosition: r3.Vector{},\n\t\tHeadPosition: r3.Vector{},\n\t\tRuntimeId: 0,\n\t}\n\treturn pk\n}\n\nfunc (pk *InventoryTransactionPacket) Encode()  {\n\tpk.PutUnsignedVarInt(pk.TransactionType)\n\tpk.ActionList.WriteToBuffer(pk.MinecraftStream)\n\n\tswitch pk.TransactionType {\n\tcase Normal, Mismatch:\n\t\tbreak\n\tcase UseItem:\n\t\tpk.PutUnsignedVarInt(pk.ActionType)\n\t\tpk.PutBlockPosition(pk.BlockPosition)\n\t\tpk.PutVarInt(pk.Face)\n\t\tpk.PutVarInt(pk.HotbarSlot)\n\t\tpk.PutItem(pk.ItemSlot)\n\t\tpk.PutVector(pk.PlayerPosition)\n\t\tpk.PutVector(pk.ClickPosition)\n\t\tbreak\n\tcase UseItemOnEntity:\n\t\tpk.PutUnsignedVarLong(pk.RuntimeId)\n\t\tpk.PutUnsignedVarInt(pk.ActionType)\n\t\tpk.PutVarInt(pk.HotbarSlot)\n\t\tpk.PutItem(pk.ItemSlot)\n\t\tpk.PutVector(pk.PlayerPosition)\n\t\tpk.PutVector(pk.ClickPosition)\n\t\tbreak\n\tcase ReleaseItem:\n\t\tpk.PutUnsignedVarInt(pk.ActionType)\n\t\tpk.PutVarInt(pk.HotbarSlot)\n\t\tpk.PutItem(pk.ItemSlot)\n\t\tpk.PutVector(pk.HeadPosition)\n\t\tbreak\n\tdefault:\n\t\tpanic(\"Unknown transaction type passed: \" + string(pk.TransactionType))\n\t}\n}\n\nfunc (pk *InventoryTransactionPacket) Decode() {\n\tpk.TransactionType = pk.GetUnsignedVarInt()\n\tpk.ActionList.ReadFromBuffer(pk.MinecraftStream)\n\n\tswitch pk.TransactionType{\n\tcase Normal, Mismatch:\n\t\tbreak\n\tcase UseItem:\n\t\tpk.ActionType = pk.GetUnsignedVarInt()\n\t\tpk.BlockPosition = pk.GetBlockPosition()\n\t\tpk.Face = pk.GetVarInt()\n\t\tpk.HotbarSlot = pk.GetVarInt()\n\t\tpk.ItemSlot = pk.GetItem()\n\t\tpk.PlayerPosition = pk.GetVector()\n\t\tpk.ClickPosition = pk.GetVector()\n\t\tbreak\n\tcase UseItemOnEntity:\n\t\tpk.RuntimeId = pk.GetUnsignedVarLong()\n\t\tpk.ActionType = pk.GetUnsignedVarInt()\n\t\tpk.HotbarSlot = pk.GetVarInt()\n\t\tpk.ItemSlot = pk.GetItem()\n\t\tpk.PlayerPosition = pk.GetVector()\n\t\tpk.ClickPosition = pk.GetVector()\n\t\tbreak\n\tcase ReleaseItem:\n\t\tpk.ActionType = pk.GetUnsignedVarInt()\n\t\tpk.HotbarSlot = pk.GetVarInt()\n\t\tpk.ItemSlot = pk.GetItem()\n\t\tpk.HeadPosition = pk.GetVector()\n\t\tbreak\n\tdefault:\n\t\tpanic(\"Error: Unknown transaction type received: \" + string(pk.TransactionType))\n\t}\n}\n"
  },
  {
    "path": "net/packets/bedrock/login.go",
    "content": "package bedrock\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"strings\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/irmine/binutils\"\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/gomine/net/packets/types\"\n\t\"github.com/irmine/gomine/utils\"\n)\n\ntype LoginPacket struct {\n\t*packets.Packet\n\tUsername          string\n\tProtocol          int32\n\tClientUUID        uuid.UUID\n\tClientId          int\n\tClientXUID        string\n\tIdentityPublicKey string\n\tServerAddress     string\n\tLanguage          string\n\n\tSkinId       string\n\tSkinData     []byte\n\tCapeData     []byte\n\tGeometryName string\n\tGeometryData string\n\n\tClientData types.ClientDataKeys\n\tChains     []types.Chain\n}\n\nfunc NewLoginPacket() *LoginPacket {\n\tpk := &LoginPacket{packets.NewPacket(info.PacketIds[info.LoginPacket]), \"\", 0, uuid.New(), 0, \"\", \"\", \"\", \"\", \"\", []byte{}, []byte{}, \"\", \"\", types.ClientDataKeys{}, []types.Chain{}}\n\treturn pk\n}\n\nfunc (pk *LoginPacket) Encode() {\n\n}\n\nfunc (pk *LoginPacket) Decode() {\n\tpk.Protocol = pk.GetInt()\n\n\tvar stream = binutils.NewStream()\n\tstream.Buffer = []byte(pk.GetString())\n\n\tvar length = int(stream.GetLittleInt())\n\n\tvar chainData = &types.ChainDataKeys{}\n\tjson.Unmarshal(stream.Get(length), &chainData)\n\n\tfor _, v := range chainData.RawChains {\n\t\tWebToken := &types.WebTokenKeys{}\n\t\tpk.Chains = append(pk.Chains, pk.BuildChain(v))\n\n\t\tutils.DecodeJwtPayload(v, WebToken)\n\n\t\tif v, ok := WebToken.ExtraData[\"displayName\"]; ok {\n\t\t\tpk.Username = v.(string)\n\t\t}\n\t\tif v, ok := WebToken.ExtraData[\"identity\"]; ok {\n\t\t\tpk.ClientUUID = uuid.Must(uuid.Parse(v.(string)))\n\t\t}\n\t\tif v, ok := WebToken.ExtraData[\"XUID\"]; ok {\n\t\t\tpk.ClientXUID = v.(string)\n\t\t}\n\t\tif len(WebToken.IdentityPublicKey) > 0 {\n\t\t\tpk.IdentityPublicKey = WebToken.IdentityPublicKey\n\t\t}\n\t}\n\n\tvar clientDataJwt = stream.Get(int(stream.GetLittleInt()))\n\tvar clientData = &types.ClientDataKeys{}\n\n\tutils.DecodeJwtPayload(string(clientDataJwt), clientData)\n\n\tpk.ClientId = clientData.ClientRandomId\n\tpk.ServerAddress = clientData.ServerAddress\n\n\tpk.Language = clientData.LanguageCode\n\tif pk.Language == \"\" {\n\t\tpk.Language = \"en_US\"\n\t}\n\n\tpk.SkinId = clientData.SkinId\n\tpk.GeometryName = clientData.GeometryId\n\tpk.SkinData, _ = base64.RawStdEncoding.DecodeString(clientData.SkinData)\n\tpk.CapeData, _ = base64.RawStdEncoding.DecodeString(clientData.CapeData)\n\tvar geometry, _ = base64.RawStdEncoding.DecodeString(clientData.GeometryData)\n\tpk.GeometryData = string(geometry)\n\n\tfor len(pk.SkinData) < 16384 {\n\t\tpk.SkinData = append(pk.SkinData, 0x00)\n\t}\n\n\tpk.ClientData = *clientData\n}\n\nfunc (pk *LoginPacket) BuildChain(raw string) types.Chain {\n\tjwt := utils.DecodeJwt(raw)\n\tvar base64s = strings.Split(raw, \".\")\n\n\tchain := types.Chain{}\n\tfor i, str := range jwt {\n\t\tswitch i {\n\t\tcase 0:\n\t\t\theader := types.ChainHeader{}\n\t\t\tjson.Unmarshal([]byte(str), &header)\n\t\t\theader.Raw = base64s[i]\n\t\t\tchain.Header = header\n\t\tcase 1:\n\t\t\tpayload := types.ChainPayload{}\n\t\t\tjson.Unmarshal([]byte(str), &payload)\n\t\t\tpayload.Raw = base64s[i]\n\t\t\tchain.Payload = payload\n\t\tcase 2:\n\t\t\tchain.Signature = str\n\t\t}\n\t}\n\treturn chain\n}\n"
  },
  {
    "path": "net/packets/bedrock/move_entity.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/golang/geo/r3\"\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\tdata2 \"github.com/irmine/worlds/entities/data\"\n)\n\ntype MoveEntityPacket struct {\n\t*packets.Packet\n\tRuntimeId uint64\n\tPosition  r3.Vector\n\tRotation  data2.Rotation\n\tFlags     byte\n}\n\nfunc NewMoveEntityPacket() *MoveEntityPacket {\n\treturn &MoveEntityPacket{Packet: packets.NewPacket(info.PacketIds[info.MoveEntityPacket]), Position: r3.Vector{}, Rotation: data2.Rotation{}, Flags: 0}\n}\n\nfunc (pk *MoveEntityPacket) Encode() {\n\tpk.PutEntityRuntimeId(pk.RuntimeId)\n\tpk.PutByte(pk.Flags)\n\tpk.PutVector(pk.Position)\n\tpk.PutEntityRotationBytes(pk.Rotation)\n}\n\nfunc (pk *MoveEntityPacket) Decode() {\n\tpk.RuntimeId = pk.GetEntityRuntimeId()\n\tpk.Flags = pk.GetByte()\n\tpk.Position = pk.GetVector()\n\tpk.Rotation = pk.GetEntityRotationBytes()\n}\n"
  },
  {
    "path": "net/packets/bedrock/move_player.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/golang/geo/r3\"\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/gomine/net/packets/data\"\n\tdata2 \"github.com/irmine/worlds/entities/data\"\n)\n\ntype MovePlayerPacket struct {\n\t*packets.Packet\n\tRuntimeId            uint64\n\tPosition             r3.Vector\n\tRotation             data2.Rotation\n\tMode                 byte\n\tOnGround             bool\n\tRidingRuntimeId      uint64\n\tTeleportCause, TeleportItem int32\n}\n\nfunc NewMovePlayerPacket() *MovePlayerPacket {\n\treturn &MovePlayerPacket{Packet: packets.NewPacket(info.PacketIds[info.MovePlayerPacket]), Position: r3.Vector{}, Rotation: data2.Rotation{}}\n}\n\nfunc (pk *MovePlayerPacket) Encode() {\n\tpk.PutEntityRuntimeId(pk.RuntimeId)\n\tpk.PutVector(pk.Position)\n\tpk.PutPlayerRotation(pk.Rotation)\n\tpk.PutByte(pk.Mode)\n\tpk.PutBool(pk.OnGround)\n\tpk.PutEntityRuntimeId(pk.RidingRuntimeId)\n\tif pk.Mode == data.MoveTeleport {\n\t\tpk.PutLittleInt(pk.TeleportCause)\n\t\tpk.PutLittleInt(pk.TeleportItem)\n\t}\n}\n\nfunc (pk *MovePlayerPacket) Decode() {\n\tpk.RuntimeId = pk.GetEntityRuntimeId()\n\tpk.Position = pk.GetVector()\n\tpk.Rotation = pk.GetPlayerRotation()\n\tpk.Mode = pk.GetByte()\n\tpk.OnGround = pk.GetBool()\n\tpk.RidingRuntimeId = pk.GetEntityRuntimeId()\n\tif pk.Mode == data.MoveTeleport {\n\t\tpk.TeleportCause = pk.GetLittleInt()\n\t\tpk.TeleportItem = pk.GetLittleInt()\n\t}\n}\n"
  },
  {
    "path": "net/packets/bedrock/network_chunk_publisher_update.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/worlds/blocks\"\n)\n\ntype NetworkChunkPublisherUpdatePacket struct {\n\t*packets.Packet\n\tPosition blocks.Position\n\tRadius uint32\n}\n\nfunc NewNetworkChunkPublisherUpdatePacket() *NetworkChunkPublisherUpdatePacket {\n\treturn &NetworkChunkPublisherUpdatePacket{packets.NewPacket(info.PacketIds[info.NetworkChunkPublisherUpdatePacket]), blocks.NewPosition(0, 0, 0), 0}\n}\n\nfunc (pk *NetworkChunkPublisherUpdatePacket) Encode() {\n\tpk.PutBlockPosition(pk.Position)\n\tpk.PutUnsignedVarInt(pk.Radius)\n}\n\nfunc (pk *NetworkChunkPublisherUpdatePacket) Decode() {\n}\n"
  },
  {
    "path": "net/packets/bedrock/play_status.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype PlayStatusPacket struct {\n\t*packets.Packet\n\tStatus int32\n}\n\nfunc NewPlayStatusPacket() *PlayStatusPacket {\n\treturn &PlayStatusPacket{packets.NewPacket(info.PacketIds[info.PlayStatusPacket]), 0}\n}\n\nfunc (pk *PlayStatusPacket) Encode() {\n\tpk.PutInt(pk.Status)\n}\n\nfunc (pk *PlayStatusPacket) Decode() {\n\tpk.Status = pk.GetInt()\n}\n"
  },
  {
    "path": "net/packets/bedrock/player_action.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/worlds/blocks\"\n)\n\nconst (\n\tPlayerStartBreak = iota\n\tPlayerAbortBreak\n\tPlayerStopBreak\n\tPlayerGetUpdatedBlock\n\tPlayerDropItem\n\tplayerStartSleeping\n\tPlayerStopSleeping\n\tPlayerRespawn\n\tPlayerJump\n\tPlayerStartSprint\n\tPlayerStopSprint\n\tPlayerStartSneak\n\tPlayerStopSneak\n\tPlayerDimensionChangeRequest\n\tPlayerDimensionChangeAck\n\tPlayerStartGlide\n\tPlayerStopGlide\n\tPlayerBuildDenied\n\tPlayerContinueBreak\n\n\t//TODO: add rest\n)\n\ntype PlayerActionPacket struct {\n\t*packets.Packet\n\tRuntimeId uint64\n\tAction    int32\n\tPosition  blocks.Position\n\tFace      int32\n}\n\nfunc NewPlayerActionPacket() *PlayerActionPacket {\n\treturn &PlayerActionPacket{ packets.NewPacket(info.PacketIds[info.PlayerActionPacket]), 0, 0, blocks.Position{}, 0}\n}\n\nfunc (pk *PlayerActionPacket) Encode() {\n\tpk.PutEntityRuntimeId(pk.RuntimeId)\n\tpk.PutVarInt(pk.Action)\n\tpk.PutBlockPosition(pk.Position)\n\tpk.PutVarInt(pk.Face)\n}\n\nfunc (pk *PlayerActionPacket) Decode() {\n\tpk.RuntimeId = pk.GetEntityRuntimeId()\n\tpk.Action = pk.GetVarInt()\n\tpk.Position = pk.GetBlockPosition()\n\tpk.Face = pk.GetVarInt()\n}"
  },
  {
    "path": "net/packets/bedrock/player_list.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/gomine/net/packets/data\"\n\t\"github.com/irmine/gomine/net/packets/types\"\n)\n\ntype PlayerListPacket struct {\n\t*packets.Packet\n\tListType byte\n\tEntries  map[string]types.PlayerListEntry\n}\n\nfunc NewPlayerListPacket() *PlayerListPacket {\n\treturn &PlayerListPacket{packets.NewPacket(info.PacketIds[info.PlayerListPacket]), 0, map[string]types.PlayerListEntry{}}\n}\n\nfunc (pk *PlayerListPacket) Encode() {\n\tpk.PutByte(pk.ListType)\n\tpk.PutUnsignedVarInt(uint32(len(pk.Entries)))\n\tfor _, entry := range pk.Entries {\n\t\tif pk.ListType == byte(data.ListTypeAdd) {\n\t\t\tpk.PutUUID(entry.UUID)\n\t\t\tpk.PutEntityUniqueId(entry.EntityUniqueId)\n\n\t\t\tpk.PutString(entry.Username)\n\n\t\t\tpk.PutString(entry.SkinId)\n\t\t\tpk.PutLengthPrefixedBytes(entry.SkinData)\n\t\t\tpk.PutLengthPrefixedBytes(entry.CapeData)\n\t\t\tpk.PutString(entry.GeometryName)\n\t\t\tpk.PutString(entry.GeometryData)\n\n\t\t\tpk.PutString(entry.XUID)\n\t\t\tpk.PutString(\"\")\n\t\t} else {\n\t\t\tpk.PutUUID(entry.UUID)\n\t\t}\n\t}\n}\n\nfunc (pk *PlayerListPacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/player_skin.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/google/uuid\"\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype PlayerSkinPacket struct {\n\t*packets.Packet\n\n\tUUID        uuid.UUID\n\tSkinId      string\n\tNewSkinName string\n\tOldSkinName string\n\n\tSkinData     []byte\n\tCapeData     []byte\n\tGeometryName string\n\tGeometryData string\n\n\tPremiumSkin  bool\n}\n\nfunc NewPlayerSkinPacket() *PlayerSkinPacket {\n\treturn &PlayerSkinPacket{packets.NewPacket(info.PacketIds[info.PlayerSkinPacket]), uuid.New(), \"\", \"\", \"\", []byte{}, []byte{}, \"\", \"\", false}\n}\n\nfunc (pk *PlayerSkinPacket) Encode() {\n\tpk.PutUUID(pk.UUID)\n\tpk.PutString(pk.SkinId)\n\tpk.PutString(pk.NewSkinName)\n\tpk.PutString(pk.OldSkinName)\n\tpk.PutLengthPrefixedBytes(pk.SkinData)\n\tpk.PutLengthPrefixedBytes(pk.CapeData)\n\tpk.PutString(pk.GeometryName)\n\tpk.PutString(pk.GeometryData)\n\tpk.PutBool(pk.PremiumSkin)\n}\n\nfunc (pk *PlayerSkinPacket) Decode() {\n\tpk.UUID = pk.GetUUID()\n\tpk.SkinId = pk.GetString()\n\tpk.NewSkinName = pk.GetString()\n\tpk.OldSkinName = pk.GetString()\n\tpk.SkinData = pk.GetLengthPrefixedBytes()\n\tpk.CapeData = pk.GetLengthPrefixedBytes()\n\tpk.GeometryName = pk.GetString()\n\tpk.GeometryData = pk.GetString()\n\tpk.PremiumSkin = pk.GetBool()\n}\n"
  },
  {
    "path": "net/packets/bedrock/remove_entity.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype RemoveEntityPacket struct {\n\t*packets.Packet\n\tEntityUniqueId int64\n}\n\nfunc NewRemoveEntityPacket() *RemoveEntityPacket {\n\treturn &RemoveEntityPacket{packets.NewPacket(info.PacketIds[info.RemoveEntityPacket]), 0}\n}\n\nfunc (pk *RemoveEntityPacket) Encode() {\n\tpk.PutEntityUniqueId(pk.EntityUniqueId)\n}\n\nfunc (pk *RemoveEntityPacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/request_chunk_radius.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype RequestChunkRadiusPacket struct {\n\t*packets.Packet\n\tRadius int32\n}\n\nfunc NewRequestChunkRadiusPacket() *RequestChunkRadiusPacket {\n\treturn &RequestChunkRadiusPacket{packets.NewPacket(info.PacketIds[info.RequestChunkRadiusPacket]), 0}\n}\n\nfunc (pk *RequestChunkRadiusPacket) Encode() {\n\n}\n\nfunc (pk *RequestChunkRadiusPacket) Decode() {\n\tpk.Radius = pk.GetVarInt()\n}\n"
  },
  {
    "path": "net/packets/bedrock/resource_pack_chunk_data.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype ResourcePackChunkDataPacket struct {\n\t*packets.Packet\n\tPackUUID   string\n\tChunkIndex int32\n\tProgress   int64\n\tChunkData  []byte\n}\n\nfunc NewResourcePackChunkDataPacket() *ResourcePackChunkDataPacket {\n\treturn &ResourcePackChunkDataPacket{packets.NewPacket(info.PacketIds[info.ResourcePackChunkDataPacket]), \"\", 0, 0, []byte{}}\n}\n\nfunc (pk *ResourcePackChunkDataPacket) Encode() {\n\tpk.PutString(pk.PackUUID)\n\tpk.PutLittleInt(pk.ChunkIndex)\n\tpk.PutLittleLong(pk.Progress)\n\tpk.PutLittleInt(int32(len(pk.ChunkData)))\n\tpk.PutBytes(pk.ChunkData)\n}\n\nfunc (pk *ResourcePackChunkDataPacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/resource_pack_chunk_request.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype ResourcePackChunkRequestPacket struct {\n\t*packets.Packet\n\tPackUUID   string\n\tChunkIndex int32\n}\n\nfunc NewResourcePackChunkRequestPacket() *ResourcePackChunkRequestPacket {\n\treturn &ResourcePackChunkRequestPacket{packets.NewPacket(info.PacketIds[info.ResourcePackChunkRequestPacket]), \"\", 0}\n}\n\nfunc (pk *ResourcePackChunkRequestPacket) Encode() {\n\n}\n\nfunc (pk *ResourcePackChunkRequestPacket) Decode() {\n\tpk.PackUUID = pk.GetString()\n\tpk.ChunkIndex = pk.GetLittleInt()\n}\n"
  },
  {
    "path": "net/packets/bedrock/resource_pack_client_response.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype ResourcePackClientResponsePacket struct {\n\t*packets.Packet\n\tStatus    byte\n\tPackUUIDs []string\n}\n\nfunc NewResourcePackClientResponsePacket() *ResourcePackClientResponsePacket {\n\treturn &ResourcePackClientResponsePacket{packets.NewPacket(info.PacketIds[info.ResourcePackClientResponsePacket]), 0, []string{}}\n}\n\nfunc (pk *ResourcePackClientResponsePacket) Encode() {\n\n}\n\nfunc (pk *ResourcePackClientResponsePacket) Decode() {\n\tpk.Status = pk.GetByte()\n\tvar idCount = pk.GetLittleShort()\n\tfor i := int16(0); i < idCount; i++ {\n\t\tpk.PackUUIDs = append(pk.PackUUIDs, pk.GetString())\n\t}\n}\n"
  },
  {
    "path": "net/packets/bedrock/resource_pack_data_info.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype ResourcePackDataInfoPacket struct {\n\t*packets.Packet\n\tPackUUID           string\n\tMaxChunkSize       int32\n\tChunkCount         int32\n\tCompressedPackSize int64\n\tSha256             string\n}\n\nfunc NewResourcePackDataInfoPacket() *ResourcePackDataInfoPacket {\n\treturn &ResourcePackDataInfoPacket{packets.NewPacket(info.PacketIds[info.ResourcePackDataInfoPacket]), \"\", 0, 0, 0, \"\"}\n}\n\nfunc (pk *ResourcePackDataInfoPacket) Encode() {\n\tpk.PutString(pk.PackUUID)\n\tpk.PutLittleInt(pk.MaxChunkSize)\n\tpk.PutLittleInt(pk.ChunkCount)\n\tpk.PutLittleLong(pk.CompressedPackSize)\n\tpk.PutString(pk.Sha256)\n}\n\nfunc (pk *ResourcePackDataInfoPacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/resource_pack_info.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/gomine/net/packets/types\"\n)\n\ntype ResourcePackInfoPacket struct {\n\t*packets.Packet\n\tMustAccept    bool\n\tBehaviorPacks []types.ResourcePackInfoEntry\n\tResourcePacks []types.ResourcePackInfoEntry\n\tBool1         bool\n}\n\nfunc NewResourcePackInfoPacket() *ResourcePackInfoPacket {\n\treturn &ResourcePackInfoPacket{packets.NewPacket(info.PacketIds[info.ResourcePackInfoPacket]), false, []types.ResourcePackInfoEntry{}, []types.ResourcePackInfoEntry{}, false}\n}\n\nfunc (pk *ResourcePackInfoPacket) Encode() {\n\tpk.PutBool(pk.MustAccept)\n\tpk.PutBool(pk.Bool1)\n\tpk.PutPackInfo(pk.BehaviorPacks)\n\tpk.PutPackInfo(pk.ResourcePacks)\n}\n\nfunc (pk *ResourcePackInfoPacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/resource_pack_stack.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/gomine/net/packets/types\"\n)\n\ntype ResourcePackStackPacket struct {\n\t*packets.Packet\n\tMustAccept    bool\n\tBehaviorPacks []types.ResourcePackStackEntry\n\tResourcePacks []types.ResourcePackStackEntry\n\tExperimental  bool\n}\n\nfunc NewResourcePackStackPacket() *ResourcePackStackPacket {\n\treturn &ResourcePackStackPacket{packets.NewPacket(info.PacketIds[info.ResourcePackStackPacket]), false, []types.ResourcePackStackEntry{}, []types.ResourcePackStackEntry{}, false}\n}\n\nfunc (pk *ResourcePackStackPacket) Encode() {\n\tpk.PutBool(pk.MustAccept)\n\tpk.PutPackStack(pk.BehaviorPacks)\n\tpk.PutPackStack(pk.ResourcePacks)\n\tpk.PutBool(pk.Experimental)\n}\n\nfunc (pk *ResourcePackStackPacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/server_handshake.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype ServerHandshakePacket struct {\n\t*packets.Packet\n\tJwt string\n}\n\nfunc NewServerHandshakePacket() *ServerHandshakePacket {\n\treturn &ServerHandshakePacket{packets.NewPacket(info.PacketIds[info.ServerHandshakePacket]), \"\"}\n}\n\nfunc (pk *ServerHandshakePacket) Encode() {\n\tpk.PutString(pk.Jwt)\n}\n\nfunc (pk *ServerHandshakePacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/set_entity_data.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype SetEntityDataPacket struct {\n\t*packets.Packet\n\tRuntimeId  uint64\n\tEntityData map[uint32][]interface{}\n}\n\nfunc NewSetEntityDataPacket() *SetEntityDataPacket {\n\treturn &SetEntityDataPacket{packets.NewPacket(info.PacketIds[info.SetEntityDataPacket]), 0, make(map[uint32][]interface{})}\n}\n\nfunc (pk *SetEntityDataPacket) Encode() {\n\tpk.PutEntityRuntimeId(pk.RuntimeId)\n\tpk.PutEntityData(pk.EntityData)\n}\n\nfunc (pk *SetEntityDataPacket) Decode() {\n\tpk.RuntimeId = pk.GetEntityRuntimeId()\n\tpk.EntityData = pk.GetEntityData()\n}\n"
  },
  {
    "path": "net/packets/bedrock/start_game.go",
    "content": "package bedrock\n\nimport (\n\t\"encoding/base64\"\n\n\t\"github.com/golang/geo/r3\"\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/gomine/net/packets/types\"\n\t\"github.com/irmine/worlds/blocks\"\n)\n\nconst (\n\tGameBroadcastSettingNone = iota\n\tGameBroadcastSettingInviteOnly\n\tGameBroadcastSettingFriendsOnly\n\tGameBroadcastSettingFriendsOfFriends\n\tGameBroadcastSettingPublic\n)\n\ntype StartGamePacket struct {\n\t*packets.Packet\n\tEntityUniqueId                 int64\n\tEntityRuntimeId                uint64\n\tPlayerGameMode                 int32\n\tPlayerPosition                 r3.Vector\n\tYaw                            float32\n\tPitch                          float32\n\tLevelSeed                      int32\n\tDimension                      int32\n\tGenerator                      int32\n\tLevelGameMode                  int32\n\tDifficulty                     int32\n\tLevelSpawnPosition             blocks.Position\n\tAchievementsDisabled           bool\n\tTime                           int32\n\tEduMode                        bool\n\tEduFeaturesEnabled             bool\n\tRainLevel                      float32\n\tLightningLevel                 float32\n\tBool1                          bool\n\tMultiPlayerGame                bool\n\tBroadcastToLan                 bool\n\tCommandsEnabled                bool\n\tForcedResourcePacks            bool\n\tGameRules                      map[string]types.GameRuleEntry\n\tBonusChest                     bool\n\tStartMap                       bool\n\tDefaultPermissionLevel         int32\n\tLevelName                      string\n\tIsTrial                        bool\n\tCurrentTick                    int64\n\tEnchantmentSeed                int32\n\tServerChunkTickRange           int32\n\tPlatformBroadcast              bool\n\tXBOXBroadcastIntent            int32\n\tPlatformBroadcastIntent        int32\n\tLockedBehaviorPack             bool\n\tLockedResourcePack             bool\n\tFromLockedWorldTemplate        bool\n\tUseMsaGamertagsOnly            bool\n\tFromWorldTemplate              bool\n\tWorldTemplateOptionLocked      bool\n\tRuntimeIdsTable                []byte\n\tMultiplayerCorrelationID       string\n}\n\nfunc NewStartGamePacket() *StartGamePacket {\n\treturn &StartGamePacket{Packet: packets.NewPacket(info.PacketIds[info.StartGamePacket]), GameRules: make(map[string]types.GameRuleEntry)}\n}\n\nfunc (pk *StartGamePacket) Encode() {\n\tpk.PutEntityUniqueId(pk.EntityUniqueId)   // Entity Unique ID\n\tpk.PutEntityRuntimeId(pk.EntityRuntimeId) // Entity runtime ID\n\n\tpk.PutVarInt(pk.PlayerGameMode) // Player game mode.\n\tpk.PutVector(pk.PlayerPosition) // Player pos.\n\n\tpk.PutLittleFloat(pk.Pitch) // Pitch\n\tpk.PutLittleFloat(pk.Yaw)   // Yaw\n\n\tpk.PutVarInt(pk.LevelSeed)     // Seed\n\tpk.PutVarInt(pk.Dimension)     // Dimension\n\tpk.PutVarInt(pk.Generator)     // Generator\n\tpk.PutVarInt(pk.LevelGameMode) // World gamemode\n\tpk.PutVarInt(pk.Difficulty)    // Difficulty\n\n\tpk.PutBlockPosition(pk.LevelSpawnPosition) // Spawn pos.\n\tpk.PutBool(pk.AchievementsDisabled)        // Achievements disabled\n\tpk.PutVarInt(pk.Time)                      // Time\n\tpk.PutBool(pk.EduMode)                     // Education mode\n\tpk.PutBool(pk.EduFeaturesEnabled)          // Education mode features enabled\n\n\tpk.PutLittleFloat(pk.RainLevel)      // Rain level\n\tpk.PutLittleFloat(pk.LightningLevel) // Lightning level\n\n\tpk.PutBool(pk.Bool1)\n\tpk.PutBool(pk.MultiPlayerGame)     // Multi-player game\n\tpk.PutBool(pk.BroadcastToLan)      // LAN Broadcast\n\tpk.PutVarInt(pk.XBOXBroadcastIntent)\n\tpk.PutVarInt(pk.PlatformBroadcastIntent)\n\n\tpk.PutBool(pk.CommandsEnabled)     // Commands Enabled\n\tpk.PutBool(pk.ForcedResourcePacks) // Texture packs required\n\n\tpk.PutGameRules(pk.GameRules) // Game rules\n\n\tpk.PutBool(pk.BonusChest)                // Bonus chest\n\tpk.PutBool(pk.StartMap)                  // Start map\n\tpk.PutVarInt(pk.DefaultPermissionLevel)  // Default permission level\n\tpk.PutLittleInt(pk.ServerChunkTickRange) // Server chunk tick range\n\tpk.PutBool(pk.LockedBehaviorPack)        // Has Locked Behavior Pack\n\tpk.PutBool(pk.LockedResourcePack)        // Has Locked Resource Pack\n\tpk.PutBool(pk.FromLockedWorldTemplate)   // From World Locked Template\n\tpk.PutBool(pk.UseMsaGamertagsOnly)       // Use Msa Gamertags Only\n\tpk.PutBool(pk.FromWorldTemplate)         // From World Template\n\tpk.PutBool(pk.WorldTemplateOptionLocked) // World template option locked\n\n\tpk.PutString(base64.RawStdEncoding.EncodeToString([]byte(pk.LevelName))) // Level name base64 encoded\n\tpk.PutString(pk.LevelName)                                               // Level name\n\tpk.PutString(\"\")                                                     // Premium world template ID\n\tpk.PutBool(pk.IsTrial)                                                   // Is Trial\n\tpk.PutLittleLong(pk.CurrentTick)                                         // Tick\n\tpk.PutVarInt(pk.EnchantmentSeed)                                         // Enchantment seed\n\tpk.PutBytes(pk.RuntimeIdsTable)\n\tpk.PutString(pk.MultiplayerCorrelationID)\n}\n\nfunc (pk *StartGamePacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/text.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/gomine/net/packets/data\"\n)\n\ntype TextPacket struct {\n\t*packets.Packet\n\tTextType byte\n\tTranslation bool\n\tSourceName string\n\tMessage string\n\tXUID string\n\tPlatformChatId string\n\n\tParams []string\n}\n\nfunc NewTextPacket() *TextPacket {\n\treturn &TextPacket{\n\t\tpackets.NewPacket(info.PacketIds[info.TextPacket]),\n\t\tdata.TextRaw,\n\t\tfalse,\n\t\t\"\",\n\t\t\"\",\n\t\t\"\",\n\t\t\"\",\n\t\t[]string{},\n\t}\n}\n\nfunc (pk *TextPacket) Encode()  {\n\tpk.PutByte(pk.TextType)\n\tpk.PutBool(pk.Translation)\n\n\tswitch pk.TextType {\n\tcase data.TextRaw, data.TextTip, data.TextSystem, data.TextJson:\n\t\tpk.PutString(pk.Message)\n\t\tbreak\n\tcase data.TextChat, data.TextWhisper, data.TextAnnouncement:\n\t\tpk.PutString(pk.SourceName)\n\t\tpk.PutString(pk.Message)\n\t\tbreak\n\tcase data.TextTranslation, data.TextPopup, data.TextJukeboxPopup:\n\t\tpk.PutString(pk.Message)\n\t\tpk.PutUnsignedVarInt(uint32(len(pk.Params)))\n\t\tfor _, v := range pk.Params {\n\t\t\tpk.PutString(v)\n\t\t}\n\t\tbreak\n\t}\n\n\tpk.PutString(pk.XUID)\n\tpk.PutString(pk.PlatformChatId)\n}\n\nfunc (pk *TextPacket) Decode() {\n\tpk.TextType = pk.GetByte()\n\tpk.Translation = pk.GetBool()\n\n\tswitch pk.TextType {\n\tcase data.TextRaw, data.TextTip, data.TextSystem:\n\t\tpk.Message = pk.GetString()\n\t\tbreak\n\tcase data.TextChat, data.TextWhisper, data.TextAnnouncement:\n\t\tpk.SourceName = pk.GetString()\n\t\tpk.Message = pk.GetString()\n\t\tbreak\n\tcase data.TextTranslation, data.TextPopup, data.TextJukeboxPopup:\n\t\tpk.Message = pk.GetString()\n\t\tc := pk.GetUnsignedVarInt()\n\t\tfor i := uint32(0); i < c; i++ {\n\t\t\tpk.Params = append(pk.Params, pk.GetString())\n\t\t}\n\t\tbreak\n\t}\n\n\tpk.XUID = pk.GetString()\n\tpk.PlatformChatId = pk.GetString()\n}"
  },
  {
    "path": "net/packets/bedrock/transfer.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n)\n\ntype TransferPacket struct {\n\t*packets.Packet\n\tAddress string\n\tPort    uint16\n}\n\nfunc NewTransferPacket() *TransferPacket {\n\treturn &TransferPacket{packets.NewPacket(info.PacketIds[info.TransferPacket]), \"\", 0}\n}\n\nfunc (pk *TransferPacket) Encode() {\n\tpk.PutString(pk.Address)\n\tpk.PutLittleShort(int16(pk.Port))\n}\n\nfunc (pk *TransferPacket) Decode() {\n\n}\n"
  },
  {
    "path": "net/packets/bedrock/update_attributes.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/worlds/entities/data\"\n)\n\ntype UpdateAttributesPacket struct {\n\t*packets.Packet\n\tRuntimeId  uint64\n\tAttributes data.AttributeMap\n}\n\nfunc NewUpdateAttributesPacket() *UpdateAttributesPacket {\n\treturn &UpdateAttributesPacket{packets.NewPacket(info.PacketIds[info.UpdateAttributesPacket]), 0, data.NewAttributeMap()}\n}\n\nfunc (pk *UpdateAttributesPacket) Encode() {\n\tpk.PutEntityRuntimeId(pk.RuntimeId)\n\tpk.PutAttributeMap(pk.Attributes)\n}\n\nfunc (pk *UpdateAttributesPacket) Decode() {\n\tpk.RuntimeId = pk.GetEntityRuntimeId()\n\tpk.Attributes = pk.GetAttributeMap()\n}\n"
  },
  {
    "path": "net/packets/bedrock/update_block.go",
    "content": "package bedrock\n\nimport (\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/worlds/blocks\"\n)\n\nconst (\n\tDataLayerNormal = iota\n\tDataLayerLiquid\n)\n\ntype UpdateBlockPacket struct {\n\t*packets.Packet\n\tPosition    blocks.Position\n\tBlockRuntimeId   uint32\n\tFlags       uint32\n\tDataLayerId uint32\n}\n\nfunc NewUpdateBlockPacket() *UpdateBlockPacket {\n\treturn &UpdateBlockPacket{Packet: packets.NewPacket(info.PacketIds[info.UpdateBlockPacket]), Flags: 0x02, DataLayerId: DataLayerNormal}\n}\n\nfunc (pk *UpdateBlockPacket) Encode() {\n\tpk.PutBlockPosition(pk.Position)\n\tpk.PutUnsignedVarInt(pk.BlockRuntimeId)\n\tpk.PutUnsignedVarInt(pk.Flags)\n\tpk.PutUnsignedVarInt(pk.DataLayerId)\n}\n\nfunc (pk *UpdateBlockPacket) Decode() {\n\tpk.Position = pk.GetBlockPosition()\n\tpk.BlockRuntimeId = pk.GetUnsignedVarInt()\n\tpk.Flags = pk.GetUnsignedVarInt()\n\tpk.DataLayerId = pk.GetUnsignedVarInt()\n}\n"
  },
  {
    "path": "net/packets/data/constants.go",
    "content": "package data\n\nconst (\n\tMojangPublicKey = \"MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V\"\n)\n\nconst (\n\tStatusLoginSuccess = iota\n\tStatusLoginFailedClient\n\tStatusLoginFailedServer\n\tStatusSpawn\n\tStatusLoginFailedInvalidTenant\n\tStatusLoginFailedVanillaEdu\n\tStatusLoginFailedEduVanilla\n)\n\nconst (\n\tMoveNormal = iota\n\tMoveReset\n\tMoveTeleport\n\tMovePitch\n)\n\nconst (\n\tMoveEntityGround = iota + 1\n\tMoveEntityTeleport\n)\n\nconst (\n\tStatusRefused = iota + 1\n\tStatusSendPacks\n\tStatusHaveAllPacks\n\tStatusCompleted\n)\n\nconst (\n\tTextRaw = iota\n\tTextChat\n\tTextTranslation\n\tTextPopup\n\tTextJukeboxPopup\n\tTextTip\n\tTextSystem\n\tTextWhisper\n\tTextAnnouncement\n\tTextJson\n)\n\nconst (\n\tResourcePackChunkSize = 1048576\n)\n\nconst (\n\tListTypeAdd = iota\n\tListTypeRemove\n)\n"
  },
  {
    "path": "net/packets/minecraft_stream.go",
    "content": "package packets\n\nimport (\n\t\"fmt\"\n\t\"github.com/golang/geo/r3\"\n\t\"github.com/google/uuid\"\n\t\"github.com/irmine/binutils\"\n\t\"github.com/irmine/gomine/items\"\n\t\"github.com/irmine/gomine/net/packets/types\"\n\t\"github.com/irmine/gonbt\"\n\t\"github.com/irmine/worlds/blocks\"\n\t\"github.com/irmine/worlds/entities/data\"\n)\n\n// MinecraftStream extends the binutils stream,\n// and implements methods for writing types specific\n// to the Minecraft bedrock.\ntype MinecraftStream struct {\n\t// MinecraftStream embeds binutils.Stream.\n\t// Usual binary encoding/decoding functions can\n\t// be called on a MinecraftStream.\n\t*binutils.Stream\n}\n\n// NewMinecraftStream reads a new MinecraftStream.\n// This stream is pre-initialized and ready for usage.\nfunc NewMinecraftStream() *MinecraftStream {\n\treturn &MinecraftStream{binutils.NewStream()}\n}\n\n// PutEntityRuntimeId writes the runtime ID of an entity.\n// Entity runtime IDs are an uint64.\nfunc (stream *MinecraftStream) PutEntityRuntimeId(id uint64) {\n\tstream.PutUnsignedVarLong(id)\n}\n\n// GetEntityRuntimeId reads the runtime ID of an entity.\n// Entity runtime IDs are an uint64, and can be looked up\n// in the level they belong to.\nfunc (stream *MinecraftStream) GetEntityRuntimeId() uint64 {\n\treturn stream.GetUnsignedVarLong()\n}\n\n// PutEntityUniqueId writes the unique ID of an entity.\n// Entity unique IDs are an int64, and remain the same through sessions.\nfunc (stream *MinecraftStream) PutEntityUniqueId(id int64) {\n\tstream.PutVarLong(id)\n}\n\n// GetEntityUniqueId reads the unique ID of an entity.\n// Unique IDs will currently always be identical to runtime IDs,\n// and will therefore have the same result.\nfunc (stream *MinecraftStream) GetEntityUniqueId() int64 {\n\treturn stream.GetVarLong()\n}\n\n// PutVector writes a float64 r3.Vector.\n// Vector values are first converted to a float32,\n// after which they are written little endian.\nfunc (stream *MinecraftStream) PutVector(vector r3.Vector) {\n\tstream.PutLittleFloat(float32(vector.X))\n\tstream.PutLittleFloat(float32(vector.Y))\n\tstream.PutLittleFloat(float32(vector.Z))\n}\n\n// GetVector reads a float64 r3.Vector.\n// Values read are actually float32, but converted to float64.\nfunc (stream *MinecraftStream) GetVector() r3.Vector {\n\treturn r3.Vector{X: float64(stream.GetLittleFloat()), Y: float64(stream.GetLittleFloat()), Z: float64(stream.GetLittleFloat())}\n}\n\n// PutBlockPosition writes a position of a block.\n// Block positions are always rounded numbers,\n// and the Y value is always positive.\nfunc (stream *MinecraftStream) PutBlockPosition(position blocks.Position) {\n\tstream.PutVarInt(position.X)\n\tstream.PutUnsignedVarInt(position.Y)\n\tstream.PutVarInt(position.Z)\n}\n\n// GetBlockPosition reads a position of a block.\n// Block positions are always rounded numbers,\n// and the Y value is always positive.\nfunc (stream *MinecraftStream) GetBlockPosition() blocks.Position {\n\treturn blocks.NewPosition(stream.GetVarInt(), stream.GetUnsignedVarInt(), stream.GetVarInt())\n}\n\n// PutEntityRotation writes the rotation of an entity in bytes.\n// The rotation of an entity will only contain yaw and pitch.\nfunc (stream *MinecraftStream) PutEntityRotationBytes(rotation data.Rotation) {\n\tstream.PutRotationByte(byte(rotation.Pitch))\n\tstream.PutRotationByte(byte(rotation.Yaw))\n\tstream.PutRotationByte(byte(rotation.Yaw))\n}\n\n// GetEntityRotation reads the rotation of an entity in bytes.\n// The rotation of an entity has no different head yaw,\n// which will therefore always be the same as the yaw when returned.\nfunc (stream *MinecraftStream) GetEntityRotationBytes() data.Rotation {\n\treturn data.Rotation{Pitch: float64(stream.getRotationByte()), Yaw: float64(stream.getRotationByte()), HeadYaw: float64(stream.getRotationByte())}\n}\n\n// PutEntityRotation writes the rotation of an entity.\n// The rotation of an entity will only contain yaw and pitch.\nfunc (stream *MinecraftStream) PutEntityRotation(rotation data.Rotation) {\n\tstream.PutLittleFloat(float32(rotation.Pitch))\n\tstream.PutLittleFloat(float32(rotation.Yaw))\n\tstream.PutLittleFloat(float32(rotation.Yaw))\n}\n\n// GetEntityRotation reads the rotation of an entity.\n// The rotation of an entity has no different head yaw,\n// which will therefore always be the same as the yaw when returned.\nfunc (stream *MinecraftStream) GetEntityRotation() data.Rotation {\n\treturn data.Rotation{Pitch: float64(stream.GetLittleFloat()), Yaw: float64(stream.GetLittleFloat()), HeadYaw: float64(stream.GetLittleFloat())}\n}\n\n// PutPlayerRotation writes the rotation of a player.\n// Players have a head yaw too, which gets written.\nfunc (stream *MinecraftStream) PutPlayerRotation(rot data.Rotation) {\n\tstream.PutLittleFloat(float32(rot.Pitch))\n\tstream.PutLittleFloat(float32(rot.Yaw))\n\tstream.PutLittleFloat(float32(rot.Yaw))\n}\n\n// GetPlayerRotation reads the rotation of a player.\n// Players are supposed to have a different head yaw than normal yaw,\n// but since recent updates the head yaw and yaw are always the same.\nfunc (stream *MinecraftStream) GetPlayerRotation() data.Rotation {\n\treturn data.Rotation{Pitch: float64(stream.GetLittleFloat()), Yaw: float64(stream.GetLittleFloat()), HeadYaw: float64(stream.GetLittleFloat())}\n}\n\nfunc (stream *MinecraftStream) PutRotationByte(rot byte){\n\tstream.PutByte(rot / (360 / 256))\n}\n\nfunc (stream *MinecraftStream) getRotationByte() byte {\n\treturn stream.GetByte() * (360 / 256)\n}\n\n// PutAttributeMap writes the attribute map of an entity.\n// The amount of attributes of the map is written,\n// after which the attribute properties follow.\nfunc (stream *MinecraftStream) PutAttributeMap(m data.AttributeMap) {\n\tstream.PutUnsignedVarInt(uint32(len(m)))\n\tfor _, v := range m {\n\t\tstream.PutLittleFloat(v.MinValue)\n\t\tstream.PutLittleFloat(v.MaxValue)\n\t\tstream.PutLittleFloat(v.Value)\n\t\tstream.PutLittleFloat(v.DefaultValue)\n\t\tstream.PutString(string(v.GetName()))\n\t}\n}\n\n// GetAttributeMap reads an attribute map of an entity.\n// There may be attributes in this attribute map that are\n// not set in the default attribute map, or missing attributes.\nfunc (stream *MinecraftStream) GetAttributeMap() data.AttributeMap {\n\tm := data.NewAttributeMap()\n\tc := stream.GetUnsignedVarInt()\n\tfor i := uint32(0); i < c; i++ {\n\t\tmin := stream.GetLittleFloat()\n\t\tmax := stream.GetLittleFloat()\n\t\tvalue := stream.GetLittleFloat()\n\t\tdefaultValue := stream.GetLittleFloat()\n\t\tname := data.AttributeName(stream.GetString())\n\t\tatt := data.NewAttribute(name, value, max)\n\t\tatt.DefaultValue = defaultValue\n\t\tatt.MinValue = min\n\t\tm.SetAttribute(att)\n\t}\n\treturn m\n}\n\n// PutItem writes an item stack.\n// Item stacks also get their NBT written to network,\n// through the call of Stack.EmitNBT().\nfunc (stream *MinecraftStream) PutItem(item *items.Stack) {\n\tid, v := items.FromKey(items.TypeToId[fmt.Sprint(item.Type)])\n\tstream.PutVarInt(int32(id))\n\tstream.PutVarInt(item.GetAuxValue(item, v))\n\n\twriter := gonbt.NewWriter(true, binutils.LittleEndian)\n\tcompound := gonbt.NewCompound(\"\", make(map[string]gonbt.INamedTag))\n\titem.NBTEmitFunction(compound, item)\n\twriter.WriteUncompressedCompound(compound)\n\td := writer.GetBuffer()\n\tstream.PutLittleShort(int16(len(d)))\n\tstream.PutBytes(d)\n\n\t// Fields for canPlaceOn and canBreak are not implemented.\n\t// TODO\n\tstream.PutVarInt(0)\n\tstream.PutVarInt(0)\n}\n\n// GetItem reads a new item stack.\n// The item stack returned may have NBT properties.\n// If the item ID was unknown, an air item gets returned.\nfunc (stream *MinecraftStream) GetItem() *items.Stack {\n\tid := stream.GetVarInt()\n\tif id <= 0 {\n\t\ti, _ := items.DefaultManager.Get(\"minecraft:air\", 0)\n\t\treturn i\n\t}\n\taux := stream.GetVarInt()\n\titemData := aux >> 8\n\n\tt := items.IdToType[items.GetKey(int16(id), int16(itemData))]\n\tcount := aux & 0xff\n\n\tvar nbtLength int16\n\tvar nbtData *gonbt.Compound\n\n\titem, _ := items.DefaultManager.Get(t.GetId(), int(count))\n\tnbtLength = stream.GetLittleShort()\n\t//text.DefaultLogger.Debug(nbtLength)\n\tif nbtLength > 0 {\n\t\treader := gonbt.NewReader(stream.Get(int(nbtLength)), true, binutils.LittleEndian)\n\t\tnbtData = reader.ReadUncompressedIntoCompound()\n\t}else if nbtLength == -1 {\n\t\tnbtCount := stream.GetUnsignedVarInt()\n\t\tfor i := uint32(0); i < nbtCount; i++ {\n\t\t\treader := gonbt.NewReader(stream.Buffer[stream.Offset:], true, binutils.LittleEndian)\n\t\t\tnbtData = reader.ReadUncompressedIntoCompound()\n\t\t\tstream.Offset += reader.GetOffset()\n\t\t}\n\t}\n\n\tif nbtData != nil {\n\t\titem.NBTParseFunction(nbtData, item)\n\t}\n\n\t// Fields for canPlaceOn and canBreak are not implemented.\n\t// TODO\n\tcanPlace := stream.GetVarInt()\n\tif canPlace > 0 {\n\t\tfor i := int32(0); i < canPlace; i++ {\n\t\t\tstream.GetString()\n\t\t}\n\t}\n\tcanBreak := stream.GetVarInt()\n\tif canBreak > 0 {\n\t\tfor i := int32(0); i < canBreak; i++ {\n\t\t\tstream.GetString()\n\t\t}\n\t}\n\n\t//text.DefaultLogger.Debug(canPlace, canBreak)\n\n\treturn item\n}\n\n// PutEntityData writes the data properties of an entity.\nfunc (stream *MinecraftStream) PutEntityData(entityData map[uint32][]interface{}) {\n\tvar count= uint32(len(entityData))\n\tstream.PutUnsignedVarInt(count)\n\tfor key, dataValues := range entityData {\n\t\tstream.PutUnsignedVarInt(key)\n\t\tvar flagId, ok = dataValues[0].(uint32)\n\t\tif !ok {\n\t\t\tstream.PutUnsignedVarInt(999999) // invalid flag id\n\t\t\tcontinue\n\t\t}\n\n\t\tstream.PutUnsignedVarInt(flagId)\n\n\t\tswitch flagId {\n\t\tcase data.EntityDataByte:\n\t\t\tif value, ok := dataValues[1].(byte); ok {\n\t\t\t\tstream.PutByte(value)\n\t\t\t}\n\t\t\tbreak\n\t\tcase data.EntityDataShort:\n\t\t\tif value, ok := dataValues[1].(int16); ok {\n\t\t\t\tstream.PutLittleShort(value)\n\t\t\t}\n\t\t\tbreak\n\t\tcase data.EntityDataInt:\n\t\t\tif value, ok := dataValues[1].(int32); ok {\n\t\t\t\tstream.PutVarInt(value)\n\t\t\t}\n\t\t\tbreak\n\t\tcase data.EntityDataFloat:\n\t\t\tif value, ok := dataValues[1].(float32); ok {\n\t\t\t\tstream.PutLittleFloat(value)\n\t\t\t}\n\t\t\tbreak\n\t\tcase data.EntityDataString:\n\t\t\tif value, ok := dataValues[1].(string); ok {\n\t\t\t\tstream.PutString(value)\n\t\t\t}\n\t\t\tbreak\n\t\tcase data.EntityDataItem:\n\t\t\tif value, ok := dataValues[1].(*items.Stack); ok {\n\t\t\t\tstream.PutItem(value)\n\t\t\t}\n\t\t\tbreak\n\t\tcase data.EntityDataPos:\n\t\t\tif value, ok := dataValues[1].(blocks.Position); ok {\n\t\t\t\tstream.PutBlockPosition(value)\n\t\t\t}\n\t\t\tbreak\n\t\tcase data.EntityDataLong:\n\t\t\tif value, ok := dataValues[1].(int64); ok {\n\t\t\t\tstream.PutVarLong(value)\n\t\t\t}\n\t\t\tbreak\n\t\tcase data.EntityDataVector:\n\t\t\tif value, ok := dataValues[1].(r3.Vector); ok {\n\t\t\t\tstream.PutVector(value)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// GetEntityData reads an entity data property map from an entity.\nfunc (stream *MinecraftStream) GetEntityData() map[uint32][]interface{} {\n\tentityData := make(map[uint32][]interface{})\n\tcount := stream.GetUnsignedVarInt()\n\tif count > 0 {\n\t\tfor i := uint32(0); i < count; i++ {\n\t\t\tvar key = stream.GetUnsignedVarInt()\n\t\t\tvar flagId = stream.GetUnsignedVarInt()\n\t\t\tswitch flagId {\n\t\t\tcase data.EntityDataByte:\n\t\t\t\tentityData[key] = []interface{}{flagId, stream.GetByte()}\n\t\t\t\tbreak\n\t\t\tcase data.EntityDataShort:\n\t\t\t\tentityData[key] = []interface{}{flagId, stream.GetLittleShort()}\n\t\t\t\tbreak\n\t\t\tcase data.EntityDataInt:\n\t\t\t\tentityData[key] = []interface{}{flagId, stream.GetVarInt()}\n\t\t\t\tbreak\n\t\t\tcase data.EntityDataFloat:\n\t\t\t\tentityData[key] = []interface{}{flagId, stream.GetLittleFloat()}\n\t\t\t\tbreak\n\t\t\tcase data.EntityDataString:\n\t\t\t\tentityData[key] = []interface{}{flagId, stream.GetString()}\n\t\t\t\tbreak\n\t\t\tcase data.EntityDataItem:\n\t\t\t\tentityData[key] = []interface{}{flagId, stream.GetItem()}\n\t\t\t\tbreak\n\t\t\tcase data.EntityDataPos:\n\t\t\t\tentityData[key] = []interface{}{flagId, stream.GetBlockPosition()}\n\t\t\t\tbreak\n\t\t\tcase data.EntityDataLong:\n\t\t\t\tentityData[key] = []interface{}{flagId, stream.GetVarLong()}\n\t\t\t\tbreak\n\t\t\tcase data.EntityDataVector:\n\t\t\t\tentityData[key] = []interface{}{flagId, stream.GetVector()}\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\treturn entityData\n}\n\n// PutGameRules writes a map of game rules.\n// Game rules get prefixed by the type of the game rule,\n// 1 being bool, 2 being uint32, 3 being float32.\nfunc (stream *MinecraftStream) PutGameRules(gameRules map[string]types.GameRuleEntry) {\n\tstream.PutUnsignedVarInt(uint32(len(gameRules)))\n\tfor _, gameRule := range gameRules {\n\t\tstream.PutString(gameRule.Name)\n\t\tswitch value := gameRule.Value.(type) {\n\t\tcase bool:\n\t\t\tstream.PutUnsignedVarInt(1)\n\t\t\tstream.PutBool(value)\n\t\tcase uint32:\n\t\t\tstream.PutUnsignedVarInt(2)\n\t\t\tstream.PutUnsignedVarInt(value)\n\t\tcase float32:\n\t\t\tstream.PutUnsignedVarInt(3)\n\t\t\tstream.PutLittleFloat(value)\n\t\t}\n\t}\n}\n\n// PutPackInfo writes the info of an array of resource pack entries.\n// The UUID, version and pack size gets written.\nfunc (stream *MinecraftStream) PutPackInfo(packs []types.ResourcePackInfoEntry) {\n\tstream.PutLittleShort(int16(len(packs)))\n\n\tfor _, pack := range packs {\n\t\tstream.PutString(pack.UUID)\n\t\tstream.PutString(pack.Version)\n\t\tstream.PutLittleLong(pack.PackSize)\n\t\tstream.PutString(\"\")\n\t\tstream.PutString(\"\")\n\t\tstream.PutString(\"\")\n\t\tstream.PutBool(false)\n\t}\n}\n\n// PutPackStack writes an array of resource pack entries.\n// The order of this array specifies the order the client should apply those,\n// with index 0 meaning highest priority.\nfunc (stream *MinecraftStream) PutPackStack(packs []types.ResourcePackStackEntry) {\n\tstream.PutUnsignedVarInt(uint32(len(packs)))\n\tfor _, pack := range packs {\n\t\tstream.PutString(pack.UUID)\n\t\tstream.PutString(pack.Version)\n\t\tstream.PutString(\"\")\n\t}\n}\n\n// PutUUID writes a UUID.\n// UUIDs are first re-ordered for little endian byte order,\n// after which they get written.\nfunc (stream *MinecraftStream) PutUUID(uuid uuid.UUID) {\n\tb, err := uuid.MarshalBinary()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfor i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {\n\t\tb[i], b[j] = b[j], b[i]\n\t}\n\tstream.PutBytes(b[8:])\n\tstream.PutBytes(b[:8])\n}\n\n// GetUUID reads a UUID.\n// TODO: Re-order for little endian byte order. Order gets messed up.\nfunc (stream *MinecraftStream) GetUUID() uuid.UUID {\n\treturn uuid.Must(uuid.FromBytes(stream.Get(16)))\n}\n"
  },
  {
    "path": "net/packets/packet.go",
    "content": "package packets\n\nimport (\n\t\"github.com/irmine/gomine/text\"\n)\n\n// IPacket gets implemented by every packet.\n// Every packet can be encoded and decoded.\ntype IPacket interface {\n\tSetBuffer([]byte)\n\tGetBuffer() []byte\n\tEncodeHeader()\n\tEncode()\n\tDecodeHeader()\n\tDecode()\n\tResetStream()\n\tGetOffset() int\n\tSetOffset(int)\n\tDiscard()\n\tIsDiscarded() bool\n\tEncodeId()\n\tDecodeId()\n\tGetId() int\n}\n\n// Packet is a Minecraft bedrock packet.\n// Packets have a given ID and contain two prefix\n// bytes, which are used for split screen.\n// Packets can be discarded during handling\n// of the packets to stop other handlers from\n// handling those packets.\ntype Packet struct {\n\t*MinecraftStream\n\t// PacketId is the ID of the packet.\n\t// Packet IDs may differ for different protocols.\n\tPacketId int\n\t// SenderIdentifier is used for split screen.\n\t// It specifies the sender sub ID.\n\tSenderIdentifier byte\n\t// ReceiverIdentifier is used for split screen.\n\t// It specifies the receiver sub ID.\n\tReceiverIdentifier byte\n\tdiscarded          bool\n}\n\n// NewPacket returns a new packet with packet ID.\n// The packet's stream gets pre-initialized.\nfunc NewPacket(id int) *Packet {\n\treturn &Packet{NewMinecraftStream(), id, 0, 0, false}\n}\n\n// GetId returns the packet ID of the packet.\nfunc (pk *Packet) GetId() int {\n\treturn pk.PacketId\n}\n\n// Discard discards the packet.\n// Once discarded, handlers will no longer\n// handle this packet.\nfunc (pk *Packet) Discard() {\n\tpk.discarded = true\n}\n\n// IsDiscard checks if a packet has been discarded.\n// Discarded packets are no longer processed,\n// and get disposed immediately.\nfunc (pk *Packet) IsDiscarded() bool {\n\treturn pk.discarded\n}\n\n// EncodeId encodes the ID of the packet.\nfunc (pk *Packet) EncodeId() {\n\tpk.PutUnsignedVarInt(uint32(pk.PacketId))\n}\n\n// DecodeId decodes the packet ID of the packet.\n// The function panics if the packet ID\n// and read ID do not match.\nfunc (pk *Packet) DecodeId() {\n\tid := int(pk.GetUnsignedVarInt())\n\tif id != pk.PacketId {\n\t\ttext.DefaultLogger.Debug(\"Packet IDs do not match. Expected:\", pk.PacketId, \"Got:\", id)\n\t}\n}\n\n// EncodeHeader encodes the header of a packet,\n// with bedrock >= 200.\n// First the packet ID gets encoded,\n// after which the sender and receiver ID bytes get written.\nfunc (pk *Packet) EncodeHeader() {\n\tpk.EncodeId()\n}\n\n// DecodeHeader decodes a header of a packet,\n// with bedrock >= 200.\n// First the packet ID gets decoded,\n// after which the sender and receiver ID bytes.\nfunc (pk *Packet) DecodeHeader() {\n\tpk.DecodeId()\n}\n\nfunc (pk *Packet) Encode() {}\n\nfunc (pk *Packet) Decode() {}\n"
  },
  {
    "path": "net/packets/types/levels.go",
    "content": "package types\n\ntype GameRuleEntry struct {\n\tName  string\n\tValue interface{}\n}\n"
  },
  {
    "path": "net/packets/types/net.go",
    "content": "package types\n\ntype ChainDataKeys struct {\n\tRawChains []string `json:\"chain\"`\n\tChains    []Chain\n}\n\ntype Chain struct {\n\tHeader    ChainHeader\n\tPayload   ChainPayload\n\tSignature string\n}\n\ntype ChainHeader struct {\n\tX5u string `json:\"x5u\"`\n\tAlg string `json:\"alg\"`\n\n\tRaw string\n}\n\ntype ChainPayload struct {\n\tCertificateAuthority bool   `json:\"certificateAuthority\"`\n\tExpirationTime       int64  `json:\"exp\"`\n\tIdentityPublicKey    string `json:\"identityPublicKey\"`\n\tNotBefore            int64  `json:\"nbf\"`\n\tRandomNonce          int    `json:\"randomNonce\"`\n\tIssuer               string `json:\"iss\"`\n\tIssuedAt             int64  `json:\"iat\"`\n\n\tRaw string\n}\n\ntype WebTokenKeys struct {\n\tExtraData         map[string]interface{} `json:\"extraData\"`\n\tIdentityPublicKey string                 `json:\"identityPublicKey\"`\n}\n\ntype ClientDataKeys struct {\n\tClientRandomId   int    `json:\"ClientRandomId\"`\n\tServerAddress    string `json:\"ServerAddress\"`\n\tLanguageCode     string `json:\"LanguageCode\"`\n\tSkinId           string `json:\"SkinId\"`\n\tSkinData         string `json:\"SkinData\"`\n\tCapeData         string `json:\"CapeData\"`\n\tGeometryId       string `json:\"SkinGeometryName\"`\n\tGeometryData     string `json:\"SkinGeometry\"`\n\tCurrentInputMode string `json:\"CurrentInputMode\"`\n\tDefaultInputMode string `json:\"DefaultInputMode\"`\n\tDeviceModel      string `json:\"DeviceModel\"`\n\tDeviceOS         int    `json:\"DeviceOS\"`\n\tGameVersion      string `json:\"GameVersion\"`\n\tGuiScale         int    `json:\"GuiScale\"`\n\tUIProfile        int    `json:\"UIProfile\"`\n\tThirdPartyName   string `json:\"ThirdPartyName\"`\n}"
  },
  {
    "path": "net/packets/types/players.go",
    "content": "package types\n\nimport (\n\t\"github.com/google/uuid\"\n)\n\ntype PlayerListEntry struct {\n\tUUID           uuid.UUID\n\tXUID           string\n\tEntityUniqueId int64\n\tUsername       string\n\tDisplayName    string\n\tPlatform       int32\n\tSkinId         string\n\tSkinData       []byte\n\tCapeData       []byte\n\tGeometryName   string\n\tGeometryData   string\n}\n\ntype SessionData struct {\n\tClientUUID     uuid.UUID\n\tClientXUID     string\n\tClientId       int\n\tProtocolNumber int32\n\tGameVersion    string\n\tLanguage       string\n\tDeviceOS       int\n}\n\ntype Text struct {\n\tMessage               string\n\tSourceName            string\n\tSourceXUID            string\n\tPlatformChatId        string\n\tTextType              byte\n\tIsTranslation         bool\n\tTranslationParameters []string\n}\n"
  },
  {
    "path": "net/packets/types/resource_packs.go",
    "content": "package types\n\ntype ResourcePackInfoEntry struct {\n\tUUID     string\n\tVersion  string\n\tPackSize int64\n}\n\ntype ResourcePackStackEntry struct {\n\tUUID    string\n\tVersion string\n}\n"
  },
  {
    "path": "net/protocol/entries.go",
    "content": "package protocol\n\nimport (\n\t\"github.com/golang/geo/r3\"\n\t\"github.com/google/uuid\"\n\t\"github.com/irmine/worlds\"\n\t\"github.com/irmine/worlds/entities/data\"\n)\n\ntype AddEntityEntry interface {\n\tGetUniqueId() int64\n\tGetRuntimeId() uint64\n\tGetEntityType() uint32\n\tGetPosition() r3.Vector\n\tGetMotion() r3.Vector\n\tGetRotation() data.Rotation\n\tGetAttributeMap() data.AttributeMap\n\tGetEntityData() map[uint32][]interface{}\n}\n\ntype AddPlayerEntry interface {\n\tAddEntityEntry\n\tGetDisplayName() string\n\tGetName() string\n}\n\ntype PlayerListEntry interface {\n\tAddPlayerEntry\n\tGetXUID() string\n\tGetUUID() uuid.UUID\n\tGetSkinId() string\n\tGetSkinData() []byte\n\tGetCapeData() []byte\n\tGetGeometryName() string\n\tGetGeometryData() string\n\tGetPlatform() int32\n}\n\ntype StartGameEntry interface {\n\tGetRuntimeId() uint64\n\tGetUniqueId() int64\n\tGetPosition() r3.Vector\n\tGetDimension() *worlds.Dimension\n}"
  },
  {
    "path": "net/protocol/handler.go",
    "content": "package protocol\n\n// Handler is an interface satisfied by every packet handler.\ntype Handler interface {\n\tGetPriority() int\n\tSetPriority(int) bool\n}\n"
  },
  {
    "path": "net/protocol/protocol.go",
    "content": "package protocol\n\nimport (\n\t\"github.com/golang/geo/r3\"\n\t\"github.com/google/uuid\"\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/gomine/net/packets/types\"\n\t\"github.com/irmine/gomine/packs\"\n\t\"github.com/irmine/worlds/blocks\"\n\t\"github.com/irmine/worlds/chunks\"\n\t\"github.com/irmine/worlds/entities/data\"\n)\n\ntype IPacketManager interface {\n\tGetIdList() info.PacketIdList\n\tGetHandlers(packet info.PacketName) [][]Handler\n\tGetHandlersById(id int) [][]Handler\n\tRegisterHandler(packet info.PacketName, handler Handler) bool\n\tDeregisterPacketHandlers(packet info.PacketName, priority int)\n\tGetPackets() map[int]func() packets.IPacket\n\tRegisterPacket(packetId int, packetFunc func() packets.IPacket)\n\tGetPacket(packetId int) packets.IPacket\n\tIsPacketRegistered(packetId int) bool\n\n\tGetAddEntity(AddEntityEntry) packets.IPacket\n\tGetAddPlayer(uuid.UUID, AddPlayerEntry) packets.IPacket\n\tGetChunkRadiusUpdated(int32) packets.IPacket\n\tGetCraftingData() packets.IPacket\n\tGetDisconnect(string, bool) packets.IPacket\n\tGetFullChunkData(*chunks.Chunk) packets.IPacket\n\tGetMovePlayer(uint64, r3.Vector, data.Rotation, byte, bool, uint64) packets.IPacket\n\tGetPlayerList(byte, map[string]PlayerListEntry) packets.IPacket\n\tGetPlayStatus(int32) packets.IPacket\n\tGetRemoveEntity(int64) packets.IPacket\n\tGetResourcePackChunkData(string, int32, int64, []byte) packets.IPacket\n\tGetResourcePackDataInfo(packs.Pack) packets.IPacket\n\tGetResourcePackInfo(bool, *packs.Stack, *packs.Stack) packets.IPacket\n\tGetResourcePackStack(bool, *packs.Stack, *packs.Stack) packets.IPacket\n\tGetServerHandshake(string) packets.IPacket\n\tGetSetEntityData(uint64, map[uint32][]interface{}) packets.IPacket\n\tGetStartGame(StartGameEntry, []byte) packets.IPacket\n\tGetText(types.Text) packets.IPacket\n\tGetTransfer(string, uint16) packets.IPacket\n\tGetUpdateAttributes(uint64, data.AttributeMap) packets.IPacket\n\tGetNetworkChunkPublisherUpdatePacket(position blocks.Position, radius uint32) packets.IPacket\n\tGetMoveEntity(uint64, r3.Vector, data.Rotation, byte, bool) packets.IPacket\n\tGetPlayerSkin(uuid2 uuid.UUID, skinId, geometryName, geometryData string, skinData, capeData []byte) packets.IPacket\n\tGetPlayerAction(runtimeId uint64, action int32, position blocks.Position, face int32) packets.IPacket\n\tGetAnimate(action int32, runtimeId uint64, float float32) packets.IPacket\n\tGetUpdateBlock(position blocks.Position, blockRuntimeId, dataLayerId uint32) packets.IPacket\n}\n\n// PacketManagerBase is a struct providing the base for a PacketManagerBase.\n// It provides utility functions for a basic PacketManagerBase implementation.\ntype PacketManagerBase struct {\n\tidList         info.PacketIdList\n\tpackets        map[int]func() packets.IPacket\n\thandlers       map[int][][]Handler\n}\n\n// NewBase returns a new PacketManagerBase with the given PacketManagerBase number and packets.\nfunc NewPacketManagerBase(idList info.PacketIdList, packets map[int]func() packets.IPacket, handlers map[int][][]Handler) *PacketManagerBase {\n\treturn &PacketManagerBase{idList, packets, handlers}\n}\n\n// GetIdList returns the packet name => Id list of the bedrock.\nfunc (Base *PacketManagerBase) GetIdList() info.PacketIdList {\n\treturn Base.idList\n}\n\n// GetHandlers returns all handlers registered for the given packet name.\nfunc (Base *PacketManagerBase) GetHandlers(packet info.PacketName) [][]Handler {\n\tvar id = Base.idList[packet]\n\treturn Base.handlers[id]\n}\n\n// GetHandlersById returns all handlers registered on the given ID.\nfunc (Base *PacketManagerBase) GetHandlersById(id int) [][]Handler {\n\treturn Base.handlers[id]\n}\n\n// RegisterHandler registers a new packet handler to listen for packets with the given ID.\n// This function uses the priority of the handler.\n// Returns a bool indicating success.\nfunc (Base *PacketManagerBase) RegisterHandler(packet info.PacketName, handler Handler) bool {\n\tvar id = Base.idList[packet]\n\tif Base.handlers[id] == nil {\n\t\tBase.handlers[id] = make([][]Handler, 11)\n\t}\n\tBase.handlers[id][handler.GetPriority()] = append(Base.handlers[id][handler.GetPriority()], handler)\n\treturn true\n}\n\n// DeregisterPackHandlers deregisters all packet handlers listening for packets with the given ID, on the given priority.\nfunc (Base *PacketManagerBase) DeregisterPacketHandlers(packet info.PacketName, priority int) {\n\tvar id = Base.idList[packet]\n\tBase.handlers[id][priority] = []Handler{}\n}\n\n// GetPackets returns a packet ID => packet function map containing all registered packets.\nfunc (Base *PacketManagerBase) GetPackets() map[int]func() packets.IPacket {\n\treturn Base.packets\n}\n\n// RegisterPacket registers a packet function with the given packet ID.\nfunc (Base *PacketManagerBase) RegisterPacket(packetId int, packetFunc func() packets.IPacket) {\n\tBase.packets[packetId] = packetFunc\n}\n\n// GetPacket returns a packet with the given packet ID.\nfunc (Base *PacketManagerBase) GetPacket(packetId int) packets.IPacket {\n\treturn Base.packets[packetId]()\n}\n\n// IsPacketRegistered checks if the PacketManagerBase has a packet with the given packet ID.\nfunc (Base *PacketManagerBase) IsPacketRegistered(packetId int) bool {\n\tvar _, ok = Base.packets[packetId]\n\treturn ok\n}\n"
  },
  {
    "path": "net/protocol_adapter.go",
    "content": "package net\n\nimport (\n\t\"github.com/golang/geo/r3\"\n\t\"github.com/google/uuid\"\n\t\"github.com/irmine/gomine/net/packets/types\"\n\t\"github.com/irmine/gomine/net/protocol\"\n\t\"github.com/irmine/gomine/packs\"\n\t\"github.com/irmine/worlds/blocks\"\n\t\"github.com/irmine/worlds/chunks\"\n\t\"github.com/irmine/worlds/entities/data\"\n)\n\nfunc (session *MinecraftSession) SendAddEntity(entity protocol.AddEntityEntry) {\n\tsession.SendPacket(session.adapter.packetManager.GetAddEntity(entity))\n}\n\nfunc (session *MinecraftSession) SendAddPlayer(uuid uuid.UUID, player protocol.AddPlayerEntry) {\n\tsession.SendPacket(session.adapter.packetManager.GetAddPlayer(uuid, player))\n}\n\nfunc (session *MinecraftSession) SendChunkRadiusUpdated(radius int32) {\n\tsession.SendPacket(session.adapter.packetManager.GetChunkRadiusUpdated(radius))\n}\n\nfunc (session *MinecraftSession) SendCraftingData() {\n\tsession.SendPacket(session.adapter.packetManager.GetCraftingData())\n}\n\nfunc (session *MinecraftSession) SendDisconnect(message string, hideDisconnect bool) {\n\tsession.SendPacket(session.adapter.packetManager.GetDisconnect(message, hideDisconnect))\n}\n\nfunc (session *MinecraftSession) SendFullChunkData(chunk *chunks.Chunk) {\n\tsession.SendPacket(session.adapter.packetManager.GetFullChunkData(chunk))\n}\n\nfunc (session *MinecraftSession) SendMovePlayer(runtimeId uint64, position r3.Vector, rotation data.Rotation, mode byte, onGround bool, ridingRuntimeId uint64) {\n\tsession.SendPacket(session.adapter.packetManager.GetMovePlayer(runtimeId, position, rotation, mode, onGround, ridingRuntimeId))\n}\n\nfunc (session *MinecraftSession) SendPlayerList(listType byte, players map[string]protocol.PlayerListEntry) {\n\tsession.SendPacket(session.adapter.packetManager.GetPlayerList(listType, players))\n}\n\nfunc (session *MinecraftSession) SendPlayStatus(status int32) {\n\tsession.SendPacket(session.adapter.packetManager.GetPlayStatus(status))\n}\n\nfunc (session *MinecraftSession) SendRemoveEntity(uniqueId int64) {\n\tsession.SendPacket(session.adapter.packetManager.GetRemoveEntity(uniqueId))\n}\n\nfunc (session *MinecraftSession) SendResourcePackChunkData(packUUID string, chunkIndex int32, progress int64, data []byte) {\n\tsession.SendPacket(session.adapter.packetManager.GetResourcePackChunkData(packUUID, chunkIndex, progress, data))\n}\n\nfunc (session *MinecraftSession) SendResourcePackDataInfo(pack packs.Pack) {\n\tsession.SendPacket(session.adapter.packetManager.GetResourcePackDataInfo(pack))\n}\n\nfunc (session *MinecraftSession) SendResourcePackInfo(mustAccept bool, resourcePacks *packs.Stack, behaviorPacks *packs.Stack) {\n\tsession.SendPacket(session.adapter.packetManager.GetResourcePackInfo(mustAccept, resourcePacks, behaviorPacks))\n}\n\nfunc (session *MinecraftSession) SendResourcePackStack(mustAccept bool, resourcePacks *packs.Stack, behaviorPacks *packs.Stack) {\n\tsession.SendPacket(session.adapter.packetManager.GetResourcePackStack(mustAccept, resourcePacks, behaviorPacks))\n}\n\nfunc (session *MinecraftSession) SendServerHandshake(encryptionJwt string) {\n\tsession.SendPacket(session.adapter.packetManager.GetServerHandshake(encryptionJwt))\n}\n\nfunc (session *MinecraftSession) SendSetEntityData(runtimeId uint64, data map[uint32][]interface{}) {\n\tsession.SendPacket(session.adapter.packetManager.GetSetEntityData(runtimeId, data))\n}\n\nfunc (session *MinecraftSession) SendStartGame(player protocol.StartGameEntry, runtimeIdsTable []byte) {\n\tsession.SendPacket(session.adapter.packetManager.GetStartGame(player, runtimeIdsTable))\n}\n\nfunc (session *MinecraftSession) SendText(text types.Text) {\n\tsession.SendPacket(session.adapter.packetManager.GetText(text))\n}\n\nfunc (session *MinecraftSession) Transfer(address string, port uint16) {\n\tsession.SendPacket(session.adapter.packetManager.GetTransfer(address, port))\n}\n\nfunc (session *MinecraftSession) SendUpdateAttributes(runtimeId uint64, attributes data.AttributeMap) {\n\tsession.SendPacket(session.adapter.packetManager.GetUpdateAttributes(runtimeId, attributes))\n}\n\nfunc (session *MinecraftSession) SendNetworkChunkPublisherUpdate(position blocks.Position, radius uint32) {\n\tsession.SendPacket(session.adapter.packetManager.GetNetworkChunkPublisherUpdatePacket(position, radius))\n}\n\nfunc (session *MinecraftSession) SendMoveEntity(runtimeId uint64, position r3.Vector, rot data.Rotation, flags byte, teleport bool) {\n\tsession.SendPacket(session.adapter.packetManager.GetMoveEntity(runtimeId, position, rot, flags, teleport))\n}\n\nfunc (session *MinecraftSession) SendPlayerSkin(uuid2 uuid.UUID, skinId, geometryName, geometryData string, skinData, capeData []byte) {\n\tsession.SendPacket(session.adapter.packetManager.GetPlayerSkin(uuid2, skinId, geometryName, geometryData, skinData, capeData))\n}\n\nfunc (session *MinecraftSession) SendPlayerAction(runtimeId uint64, action int32, position blocks.Position, face int32) {\n\tsession.SendPacket(session.adapter.packetManager.GetPlayerAction(runtimeId, action, position, face))\n}\n\nfunc (session *MinecraftSession) SendAnimate(action int32, runtimeId uint64, float float32) {\n\tsession.SendPacket(session.adapter.packetManager.GetAnimate(action, runtimeId, float))\n}\n\nfunc (session *MinecraftSession) SendUpdateBlock(position blocks.Position, blockRuntimeId, dataLayerId uint32) {\n\tsession.SendPacket(session.adapter.packetManager.GetUpdateBlock(position, blockRuntimeId, dataLayerId))\n}"
  },
  {
    "path": "packet_handler.go",
    "content": "package gomine\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/sha512\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"github.com/golang/geo/r3\"\n\t\"github.com/irmine/gomine/net\"\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/gomine/net/packets/bedrock\"\n\t\"github.com/irmine/gomine/net/packets/data\"\n\t\"github.com/irmine/gomine/net/packets/types\"\n\t\"github.com/irmine/gomine/net/protocol\"\n\t\"github.com/irmine/gomine/players\"\n\t\"github.com/irmine/gomine/text\"\n\t\"github.com/irmine/gomine/utils\"\n\t\"github.com/irmine/worlds/blocks\"\n\t\"github.com/irmine/worlds/chunks\"\n\tdata2 \"github.com/irmine/worlds/entities/data\"\n\tutils2 \"github.com/irmine/worlds/utils\"\n\t\"math/big\"\n\t\"strings\"\n\t\"time\"\n)\n\nfunc NewClientHandshakeHandler(server *Server) *net.PacketHandler {\n\treturn net.NewPacketHandler(func(packet packets.IPacket, session *net.MinecraftSession) bool {\n\t\tif _, ok := packet.(*bedrock.ClientHandshakePacket); ok {\n\t\t\tsession.SendPlayStatus(data.StatusLoginSuccess)\n\t\t\tsession.SendResourcePackInfo(server.Config.ForceResourcePacks, server.PackManager.GetResourceStack(), server.PackManager.GetBehaviorStack())\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t})\n}\n\nfunc NewCommandRequestHandler(server *Server) *net.PacketHandler {\n\treturn net.NewPacketHandler(func(packet packets.IPacket, session *net.MinecraftSession) bool {\n\t\tif pk, ok := packet.(*bedrock.CommandRequestPacket); ok {\n\t\t\tvar args = strings.Split(pk.CommandText, \" \")\n\t\t\tvar commandName = strings.TrimLeft(args[0], \"/\")\n\t\t\tvar i = 1\n\t\t\tfor !server.CommandManager.IsCommandRegistered(commandName) {\n\t\t\t\tif i == len(args) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcommandName += \" \" + args[i]\n\t\t\t\ti++\n\t\t\t}\n\t\t\tif !server.CommandManager.IsCommandRegistered(commandName) {\n\t\t\t\tsession.SendMessage(\"Command could not be found.\")\n\t\t\t\treturn false\n\t\t\t}\n\t\t\targs = args[i:]\n\t\t\tvar command, _ = server.CommandManager.GetCommand(commandName)\n\t\t\tcommand.Execute(session, args)\n\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t})\n}\n\nfunc NewLoginHandler(server *Server) *net.PacketHandler {\n\treturn net.NewPacketHandler(func(packet packets.IPacket, session *net.MinecraftSession) bool {\n\t\tif loginPacket, ok := packet.(*bedrock.LoginPacket); ok {\n\t\t\tvar _, ok = server.SessionManager.GetSession(loginPacket.Username)\n\t\t\tif ok {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif loginPacket.Protocol > info.LatestProtocol {\n\t\t\t\tsession.Kick(\"Outdated server.\", false, true)\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif loginPacket.Protocol < info.LatestProtocol {\n\t\t\t\tsession.Kick(\"Outdated client.\", false, true)\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tvar successful, authenticated, pubKey = VerifyLoginRequest(loginPacket.Chains, server)\n\n\t\t\tif !successful {\n\t\t\t\ttext.DefaultLogger.Debug(loginPacket.Username, \"has joined with invalid login data.\")\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\tif authenticated {\n\t\t\t\ttext.DefaultLogger.Debug(loginPacket.Username, \"has joined while being logged into XBOX Live.\")\n\t\t\t} else {\n\t\t\t\tif server.Config.XBOXLiveAuth {\n\t\t\t\t\ttext.DefaultLogger.Debug(loginPacket.Username, \"has tried to join while not being logged into XBOX Live.\")\n\t\t\t\t\tsession.Kick(\"XBOX Live account required.\", false, false)\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t\ttext.DefaultLogger.Debug(loginPacket.Username, \"has joined while not being logged into XBOX Live.\")\n\t\t\t}\n\n\t\t\tsession.SetData(server.PermissionManager, types.SessionData{ClientUUID: loginPacket.ClientUUID, ClientXUID: loginPacket.ClientXUID, ClientId: loginPacket.ClientId, ProtocolNumber: loginPacket.Protocol, GameVersion: loginPacket.ClientData.GameVersion, Language: loginPacket.Language, DeviceOS: loginPacket.ClientData.DeviceOS})\n\t\t\tsession.SetPlayer(players.NewPlayer(loginPacket.ClientUUID, loginPacket.ClientXUID, int32(loginPacket.ClientData.DeviceOS), loginPacket.Username))\n\n\t\t\tsession.GetEncryptionHandler().Data = &utils.EncryptionData{\n\t\t\t\tClientPublicKey:  pubKey,\n\t\t\t\tServerPrivateKey: server.GetPrivateKey(),\n\t\t\t\tServerToken:      server.GetServerToken(),\n\t\t\t}\n\n\t\t\tsession.GetPlayer().SetName(loginPacket.Username)\n\t\t\tsession.GetPlayer().SetDisplayName(loginPacket.Username)\n\t\t\tsession.GetPlayer().SetSkinId(loginPacket.SkinId)\n\t\t\tsession.GetPlayer().SetSkinData(loginPacket.SkinData)\n\t\t\tsession.GetPlayer().SetCapeData(loginPacket.CapeData)\n\t\t\tsession.GetPlayer().SetGeometryName(loginPacket.GeometryName)\n\t\t\tsession.GetPlayer().SetGeometryData(loginPacket.GeometryData)\n\t\t\tsession.SetXBOXLiveAuthenticated(authenticated)\n\n\t\t\tif server.Config.UseEncryption {\n\t\t\t\tvar jwt = utils.ConstructEncryptionJwt(server.GetPrivateKey(), server.GetServerToken())\n\t\t\t\tsession.SendServerHandshake(jwt)\n\t\t\t\tsession.EnableEncryption()\n\t\t\t} else {\n\t\t\t\tsession.SendPlayStatus(data.StatusLoginSuccess)\n\t\t\t\tsession.SendResourcePackInfo(server.Config.ForceResourcePacks, server.PackManager.GetResourceStack(), server.PackManager.GetBehaviorStack())\n\t\t\t}\n\n\t\t\tserver.SessionManager.AddMinecraftSession(session)\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t})\n}\n\nfunc NewMovePlayerHandler(_ *Server) *net.PacketHandler {\n\treturn net.NewPacketHandler(func(packet packets.IPacket, session *net.MinecraftSession) bool {\n\t\tif pk, ok := packet.(*bedrock.MovePlayerPacket); ok {\n\t\t\tif session.GetPlayer().GetDimension() == nil {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tsession.SyncMove(pk.Position.X, pk.Position.Y, pk.Position.Z, pk.Rotation.Pitch, pk.Rotation.Yaw, pk.Rotation.HeadYaw, pk.OnGround)\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t})\n}\n\nfunc NewRequestChunkRadiusHandler(server *Server) *net.PacketHandler {\n\treturn net.NewPacketHandler(func(packet packets.IPacket, session *net.MinecraftSession) bool {\n\t\tif chunkRadiusPacket, ok := packet.(*bedrock.RequestChunkRadiusPacket); ok {\n\t\t\tvar viewDistance = server.GetAllowedViewDistance(chunkRadiusPacket.Radius)\n\t\t\tsession.SetViewDistance(viewDistance)\n\t\t\tsession.SendChunkRadiusUpdated(viewDistance)\n\n\t\t\tvar sessions = server.SessionManager.GetSessions()\n\t\t\tvar viewers = make(map[string]protocol.PlayerListEntry)\n\t\t\tfor name, online := range sessions {\n\t\t\t\tif online.HasSpawned() {\n\t\t\t\t\tviewers[name] = online.GetPlayer()\n\t\t\t\t\tonline.SendPlayerList(data.ListTypeAdd, map[string]protocol.PlayerListEntry{session.GetName(): session.GetPlayer()})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsession.SendPlayerList(data.ListTypeAdd, viewers)\n\n\t\t\tfor _, online := range server.SessionManager.GetSessions() {\n\t\t\t\tif session.GetUUID() != online.GetUUID() {\n\t\t\t\t\tonline.GetPlayer().SpawnPlayerTo(session)\n\t\t\t\t\tonline.GetPlayer().AddViewer(session)\n\n\t\t\t\t\tsession.GetPlayer().SpawnPlayerTo(online)\n\t\t\t\t\tsession.GetPlayer().AddViewer(online)\n\n\t\t\t\t\tonline.SendSkin(session)\n\t\t\t\t\tsession.SendSkin(online)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsession.SendSetEntityData(session.GetPlayer().GetRuntimeId(), session.GetPlayer().GetEntityData())\n\t\t\tsession.SendUpdateAttributes(session.GetPlayer().GetRuntimeId(), session.GetPlayer().GetAttributeMap())\n\n\t\t\tserver.BroadcastMessage(text.Yellow+session.GetDisplayName(), \"has joined the server\")\n\t\t\tsession.SendPlayStatus(data.StatusSpawn)\n\n\t\t\tsession.Connected = true\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t})\n}\n\nfunc NewResourcePackChunkRequestHandler(server *Server) *net.PacketHandler {\n\treturn net.NewPacketHandler(func(packet packets.IPacket, session *net.MinecraftSession) bool {\n\t\tif request, ok := packet.(*bedrock.ResourcePackChunkRequestPacket); ok {\n\t\t\tif !server.PackManager.IsPackLoaded(request.PackUUID) {\n\t\t\t\t// TODO: Kick the player. We can't kick yet.\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tvar pack = server.PackManager.GetPack(request.PackUUID)\n\t\t\tsession.SendResourcePackChunkData(request.PackUUID, request.ChunkIndex, int64(data.ResourcePackChunkSize*request.ChunkIndex), pack.GetChunk(int(data.ResourcePackChunkSize*request.ChunkIndex), data.ResourcePackChunkSize))\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t})\n}\n\nfunc NewResourcePackClientResponseHandler(server *Server) *net.PacketHandler {\n\treturn net.NewPacketHandler(func(packet packets.IPacket, session *net.MinecraftSession) bool {\n\t\tif response, ok := packet.(*bedrock.ResourcePackClientResponsePacket); ok {\n\t\t\tswitch response.Status {\n\t\t\tcase data.StatusRefused:\n\t\t\t\t// TODO: Kick the player. We can't kick yet.\n\t\t\t\treturn false\n\t\t\tcase data.StatusSendPacks:\n\t\t\t\tfor _, packUUID := range response.PackUUIDs {\n\t\t\t\t\tif !server.PackManager.IsPackLoaded(packUUID) {\n\t\t\t\t\t\t// TODO: Kick the player. We can't kick yet.\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t\tsession.SendResourcePackDataInfo(server.PackManager.GetPack(packUUID))\n\t\t\t\t}\n\t\t\tcase data.StatusHaveAllPacks:\n\t\t\t\tsession.SendResourcePackStack(server.Config.ForceResourcePacks, server.PackManager.GetResourceStack(), server.PackManager.GetBehaviorStack())\n\t\t\tcase data.StatusCompleted:\n\t\t\t\tserver.LevelManager.GetDefaultLevel().GetDefaultDimension().LoadChunk(0, 0, func(chunk *chunks.Chunk) {\n\t\t\t\t\tserver.LevelManager.GetDefaultLevel().GetDefaultDimension().AddEntity(session.GetPlayer(), r3.Vector{X: 0, Y: 7, Z: 0})\n\t\t\t\t\tserver.LevelManager.GetDefaultLevel().GetDefaultDimension().AddViewer(session, r3.Vector{X: 0, Y: 7, Z: 0})\n\t\t\t\t\tsession.SendStartGame(session.GetPlayer(), blocks.GetRuntimeIdsTable())\n\t\t\t\t\tsession.SendCraftingData()\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t})\n}\n\nfunc NewTextHandler(server *Server) *net.PacketHandler {\n\treturn net.NewPacketHandler(func(packet packets.IPacket, session *net.MinecraftSession) bool {\n\t\tif textPacket, ok := packet.(*bedrock.TextPacket); ok {\n\t\t\tif textPacket.TextType != data.TextChat {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tfor _, receiver := range server.SessionManager.GetSessions() {\n\t\t\t\treceiver.SendText(types.Text{\n\t\t\t\t\tMessage: \"<\" + session.GetDisplayName() + \"> \" + textPacket.Message,\n\t\t\t\t\tPlatformChatId: textPacket.PlatformChatId,\n\t\t\t\t\tSourceXUID: session.GetXUID(),\n\t\t\t\t\tTextType: data.TextChat,\n\t\t\t\t})\n\t\t\t}\n\t\t\ttext.DefaultLogger.LogChat(\"<\" + session.GetDisplayName() + \"> \" + textPacket.Message)\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t})\n}\n\nfunc NewInteractHandler(_ *Server) *net.PacketHandler {\n\treturn net.NewPacketHandler(func(packet packets.IPacket, session *net.MinecraftSession) bool {\n\t\tif /*interactPacket*/ _, ok := packet.(*bedrock.InteractPacket); ok {\n\t\t}\n\t\treturn true\n\t})\n}\n\nfunc NewPlayerActionHandler(_ *Server) *net.PacketHandler {\n\treturn net.NewPacketHandler(func(packet packets.IPacket, session *net.MinecraftSession) bool {\n\t\t//TODO: fix sending to others\n\t\tif playerAction, ok := packet.(*bedrock.PlayerActionPacket); ok {\n\t\t\tswitch playerAction.Action {\n\t\t\tcase bedrock.PlayerStartSneak:\n\t\t\t\tsession.GetPlayer().SetEntityProperty(data2.EntityDataSneaking, true)\n\t\t\t\tbreak\n\t\t\tcase bedrock.PlayerStopSneak:\n\t\t\t\tsession.GetPlayer().SetEntityProperty(data2.EntityDataSneaking, false)\n\t\t\t\tbreak\n\t\t\tcase bedrock.PlayerStartSprint:\n\t\t\t\tsession.GetPlayer().SetEntityProperty(data2.EntityDataSprinting, true)\n\t\t\t\tbreak\n\t\t\tcase bedrock.PlayerStopSprint:\n\t\t\t\tsession.GetPlayer().SetEntityProperty(data2.EntityDataSprinting, false)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\treturn true\n\t})\n}\n\nfunc NewAnimateHandler(_ *Server) *net.PacketHandler {\n\treturn net.NewPacketHandler(func(packet packets.IPacket, session *net.MinecraftSession) bool {\n\t\tif animate, ok := packet.(*bedrock.AnimatePacket); ok {\n\t\t\tfor _, viewer := range session.GetPlayer().GetViewers() {\n\t\t\t\tif viewer, ok := viewer.(*net.MinecraftSession); ok {\n\t\t\t\t\tviewer.SendAnimate(animate.Action, animate.RuntimeId, animate.Float)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true\n\t})\n}\n\nfunc NewInventoryTransactionHandler(_ *Server) *net.PacketHandler {\n\treturn net.NewPacketHandler(func(packet packets.IPacket, session *net.MinecraftSession) bool {\n\t\tif invTransaction, ok := packet.(*bedrock.InventoryTransactionPacket); ok {\n\t\t\tvar clickPos = invTransaction.BlockPosition\n\t\t\tswitch invTransaction.TransactionType {\n\t\t\tcase bedrock.UseItem:\n\t\t\t\tswitch invTransaction.ActionType {\n\t\t\t\tcase bedrock.ItemBreakBlock:\n\t\t\t\t\truntimeId, ok := blocks.GetRuntimeId(0, 0)\n\t\t\t\t\tif ok {\n\t\t\t\t\t\tvar block= blocks.New(blocks.NewBlockState(\"air\", int32(runtimeId), 0, 0))\n\t\t\t\t\t\tsession.GetPlayer().GetDimension().SetBlockAt(utils2.PositionToVector(clickPos), block)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase bedrock.ItemClickBlock:\n\t\t\t\t\t// TODO: do block placing\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\treturn true\n\t})\n}\n\nfunc VerifyLoginRequest(chains []types.Chain, _ *Server) (successful bool, authenticated bool, clientPublicKey *ecdsa.PublicKey) {\n\tvar publicKey *ecdsa.PublicKey\n\tvar publicKeyRaw string\n\tfor _, chain := range chains {\n\t\tif publicKeyRaw == \"\" {\n\t\t\tif chain.Header.X5u == \"\" {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpublicKeyRaw = chain.Header.X5u\n\t\t}\n\n\t\tsig := []byte(chain.Signature)\n\t\td := []byte(chain.Header.Raw + \".\" + chain.Payload.Raw)\n\n\t\tvar b64, errB64 = base64.RawStdEncoding.DecodeString(publicKeyRaw)\n\t\ttext.DefaultLogger.LogError(errB64)\n\n\t\tkey, err := x509.ParsePKIXPublicKey(b64)\n\t\tif err != nil {\n\t\t\ttext.DefaultLogger.LogError(err)\n\t\t\treturn\n\t\t}\n\n\t\thash := sha512.New384()\n\t\thash.Write(d)\n\n\t\tpublicKey = key.(*ecdsa.PublicKey)\n\t\tr := new(big.Int).SetBytes(sig[:len(sig)/2])\n\t\ts := new(big.Int).SetBytes(sig[len(sig)/2:])\n\n\t\tif !ecdsa.Verify(publicKey, hash.Sum(nil), r, s) {\n\t\t\treturn\n\t\t}\n\n\t\tif publicKeyRaw == data.MojangPublicKey {\n\t\t\tauthenticated = true\n\t\t}\n\n\t\tt := time.Now().Unix()\n\t\tif chain.Payload.ExpirationTime <= t && chain.Payload.ExpirationTime != 0 || chain.Payload.NotBefore > t || chain.Payload.IssuedAt > chain.Payload.ExpirationTime {\n\t\t\treturn\n\t\t}\n\n\t\tpublicKeyRaw = chain.Payload.IdentityPublicKey\n\t}\n\n\tvar b64, errB64 = base64.RawStdEncoding.DecodeString(publicKeyRaw)\n\ttext.DefaultLogger.LogError(errB64)\n\n\tkey, err := x509.ParsePKIXPublicKey(b64)\n\tif err != nil {\n\t\ttext.DefaultLogger.LogError(err)\n\t\treturn\n\t}\n\n\tclientPublicKey = key.(*ecdsa.PublicKey)\n\n\tsuccessful = true\n\treturn\n}\n"
  },
  {
    "path": "packet_manager.go",
    "content": "package gomine\n\nimport (\n\t\"github.com/golang/geo/r3\"\n\t\"github.com/google/uuid\"\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets\"\n\t\"github.com/irmine/gomine/net/packets/bedrock\"\n\t\"github.com/irmine/gomine/net/packets/data\"\n\t\"github.com/irmine/gomine/net/packets/types\"\n\t\"github.com/irmine/gomine/net/protocol\"\n\t\"github.com/irmine/gomine/packs\"\n\t\"github.com/irmine/gomine/permissions\"\n\t\"github.com/irmine/worlds/blocks\"\n\t\"github.com/irmine/worlds/chunks\"\n\tdata2 \"github.com/irmine/worlds/entities/data\"\n\t\"math\"\n)\n\ntype PacketManager struct {\n\t*protocol.PacketManagerBase\n}\n\nfunc NewPacketManager(server *Server) *PacketManager {\n\tvar ids = info.PacketIds\n\tvar proto = &PacketManager{protocol.NewPacketManagerBase(info.PacketIds, map[int]func() packets.IPacket{\n\t\tids[info.LoginPacket]:                      func() packets.IPacket { return bedrock.NewLoginPacket() },\n\t\tids[info.ClientHandshakePacket]:            func() packets.IPacket { return bedrock.NewClientHandshakePacket() },\n\t\tids[info.ResourcePackClientResponsePacket]: func() packets.IPacket { return bedrock.NewResourcePackClientResponsePacket() },\n\t\tids[info.RequestChunkRadiusPacket]:         func() packets.IPacket { return bedrock.NewRequestChunkRadiusPacket() },\n\t\tids[info.MovePlayerPacket]:                 func() packets.IPacket { return bedrock.NewMovePlayerPacket() },\n\t\tids[info.CommandRequestPacket]:             func() packets.IPacket { return bedrock.NewCommandRequestPacket() },\n\t\tids[info.ResourcePackChunkRequestPacket]:   func() packets.IPacket { return bedrock.NewResourcePackChunkRequestPacket() },\n\t\tids[info.TextPacket]:                       func() packets.IPacket { return bedrock.NewTextPacket() },\n\t\tids[info.PlayerListPacket]:                 func() packets.IPacket { return bedrock.NewPlayerListPacket() },\n\t\tids[info.InteractPacket]:                   func() packets.IPacket { return bedrock.NewInteractPacket() },\n\t\tids[info.SetEntityDataPacket]:              func() packets.IPacket { return bedrock.NewSetEntityDataPacket() },\n\t\tids[info.PlayerActionPacket]:               func() packets.IPacket { return bedrock.NewPlayerActionPacket() },\n\t\tids[info.AnimatePacket]:                    func() packets.IPacket { return bedrock.NewAnimatePacket() },\n\t\tids[info.InventoryTransactionPacket]:       func() packets.IPacket { return bedrock.NewInventoryTransactionPacket() },\n\t}, map[int][][]protocol.Handler{})}\n\tproto.initHandlers(server)\n\n\treturn proto\n}\n\nfunc (protocol *PacketManager) initHandlers(server *Server) {\n\tprotocol.RegisterHandler(info.LoginPacket, NewLoginHandler(server))\n\tprotocol.RegisterHandler(info.ClientHandshakePacket, NewClientHandshakeHandler(server))\n\tprotocol.RegisterHandler(info.RequestChunkRadiusPacket, NewRequestChunkRadiusHandler(server))\n\tprotocol.RegisterHandler(info.ResourcePackClientResponsePacket, NewResourcePackClientResponseHandler(server))\n\tprotocol.RegisterHandler(info.MovePlayerPacket, NewMovePlayerHandler(server))\n\tprotocol.RegisterHandler(info.CommandRequestPacket, NewCommandRequestHandler(server))\n\tprotocol.RegisterHandler(info.ResourcePackChunkRequestPacket, NewResourcePackChunkRequestHandler(server))\n\tprotocol.RegisterHandler(info.TextPacket, NewTextHandler(server))\n\tprotocol.RegisterHandler(info.InteractPacket, NewInteractHandler(server))\n\tprotocol.RegisterHandler(info.PlayerActionPacket, NewPlayerActionHandler(server))\n\tprotocol.RegisterHandler(info.AnimatePacket, NewAnimateHandler(server))\n\tprotocol.RegisterHandler(info.InventoryTransactionPacket, NewInventoryTransactionHandler(server))\n}\n\nfunc (protocol *PacketManager) GetAddEntity(entity protocol.AddEntityEntry) packets.IPacket {\n\tvar pk = bedrock.NewAddEntityPacket()\n\tpk.UniqueId = entity.GetUniqueId()\n\tpk.RuntimeId = entity.GetRuntimeId()\n\tpk.EntityType = entity.GetEntityType()\n\tpk.Position = entity.GetPosition()\n\tpk.Motion = entity.GetMotion()\n\tpk.Rotation = entity.GetRotation()\n\tpk.Attributes = entity.GetAttributeMap()\n\tpk.EntityData = entity.GetEntityData()\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetAddPlayer(uuid uuid.UUID, player protocol.AddPlayerEntry) packets.IPacket {\n\tvar pk = bedrock.NewAddPlayerPacket()\n\tpk.UUID = uuid\n\tpk.Username = player.GetName()\n\tpk.EntityRuntimeId = player.GetRuntimeId()\n\tpk.EntityUniqueId = player.GetUniqueId()\n\tpk.Position = player.GetPosition()\n\tpk.Rotation = player.GetRotation()\n\tpk.Motion = player.GetMotion()\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetChunkRadiusUpdated(radius int32) packets.IPacket {\n\tvar pk = bedrock.NewChunkRadiusUpdatedPacket()\n\tpk.Radius = radius\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetCraftingData() packets.IPacket {\n\tvar pk = bedrock.NewCraftingDataPacket()\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetDisconnect(message string, hideDisconnectScreen bool) packets.IPacket {\n\tvar pk = bedrock.NewDisconnectPacket()\n\tpk.HideDisconnectionScreen = hideDisconnectScreen\n\tpk.Message = message\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetFullChunkData(chunk *chunks.Chunk) packets.IPacket {\n\tvar pk = bedrock.NewFullChunkDataPacket()\n\tpk.ChunkX, pk.ChunkZ = chunk.X, chunk.Z\n\tpk.ChunkData = chunk.ToBinary()\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetMovePlayer(runtimeId uint64, position r3.Vector, rotation data2.Rotation, mode byte, onGround bool, ridingRuntimeId uint64) packets.IPacket {\n\tvar pk = bedrock.NewMovePlayerPacket()\n\tpk.RuntimeId = runtimeId\n\tpk.Position = position\n\tpk.Rotation = rotation\n\tpk.Mode = mode\n\tpk.OnGround = onGround\n\tpk.RidingRuntimeId = ridingRuntimeId\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetPlayerList(listType byte, players map[string]protocol.PlayerListEntry) packets.IPacket {\n\tvar pk = bedrock.NewPlayerListPacket()\n\tpk.ListType = listType\n\tvar entries = map[string]types.PlayerListEntry{}\n\tfor name, player := range players {\n\t\tentries[name] = types.PlayerListEntry{\n\t\t\tUUID:           player.GetUUID(),\n\t\t\tXUID:           player.GetXUID(),\n\t\t\tEntityUniqueId: player.GetUniqueId(),\n\t\t\tUsername:       player.GetName(),\n\t\t\tDisplayName:    player.GetDisplayName(),\n\t\t\tPlatform:       player.GetPlatform(),\n\t\t\tSkinId:         player.GetSkinId(),\n\t\t\tSkinData:       player.GetSkinData(),\n\t\t\tCapeData:       player.GetCapeData(),\n\t\t\tGeometryName:   player.GetGeometryName(),\n\t\t\tGeometryData:   player.GetGeometryData(),\n\t\t}\n\t}\n\tpk.Entries = entries\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetPlayStatus(status int32) packets.IPacket {\n\tvar pk = bedrock.NewPlayStatusPacket()\n\tpk.Status = status\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetRemoveEntity(uniqueId int64) packets.IPacket {\n\tvar pk = bedrock.NewRemoveEntityPacket()\n\tpk.EntityUniqueId = uniqueId\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetResourcePackChunkData(packUUID string, chunkIndex int32, progress int64, data []byte) packets.IPacket {\n\tvar pk = bedrock.NewResourcePackChunkDataPacket()\n\tpk.PackUUID = packUUID\n\tpk.ChunkIndex = chunkIndex\n\tpk.Progress = progress\n\tpk.ChunkData = data\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetResourcePackDataInfo(pack packs.Pack) packets.IPacket {\n\tvar pk = bedrock.NewResourcePackDataInfoPacket()\n\tpk.PackUUID = pack.GetUUID()\n\tpk.MaxChunkSize = data.ResourcePackChunkSize\n\tpk.ChunkCount = int32(math.Ceil(float64(pack.GetFileSize()) / float64(data.ResourcePackChunkSize)))\n\tpk.CompressedPackSize = pack.GetFileSize()\n\tpk.Sha256 = pack.GetSha256()\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetResourcePackInfo(mustAccept bool, resourcePacks *packs.Stack, behaviorPacks *packs.Stack) packets.IPacket {\n\tvar pk = bedrock.NewResourcePackInfoPacket()\n\tpk.MustAccept = mustAccept\n\n\tvar resourceEntries []types.ResourcePackInfoEntry\n\tvar behaviorEntries []types.ResourcePackInfoEntry\n\tfor _, pack := range *resourcePacks {\n\t\tresourceEntries = append(resourceEntries, types.ResourcePackInfoEntry{\n\t\t\tUUID:     pack.GetUUID(),\n\t\t\tVersion:  pack.GetVersion(),\n\t\t\tPackSize: pack.GetFileSize(),\n\t\t})\n\t}\n\tfor _, pack := range *behaviorPacks {\n\t\tbehaviorEntries = append(behaviorEntries, types.ResourcePackInfoEntry{\n\t\t\tUUID:     pack.GetUUID(),\n\t\t\tVersion:  pack.GetVersion(),\n\t\t\tPackSize: pack.GetFileSize(),\n\t\t})\n\t}\n\n\tpk.ResourcePacks = resourceEntries\n\tpk.BehaviorPacks = behaviorEntries\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetResourcePackStack(mustAccept bool, resourcePacks *packs.Stack, behaviorPacks *packs.Stack) packets.IPacket {\n\tvar pk = bedrock.NewResourcePackStackPacket()\n\tpk.MustAccept = mustAccept\n\tvar resourceEntries []types.ResourcePackStackEntry\n\tvar behaviorEntries []types.ResourcePackStackEntry\n\tfor _, pack := range *resourcePacks {\n\t\tresourceEntries = append(resourceEntries, types.ResourcePackStackEntry{\n\t\t\tUUID:    pack.GetUUID(),\n\t\t\tVersion: pack.GetVersion(),\n\t\t})\n\t}\n\tfor _, pack := range *behaviorPacks {\n\t\tbehaviorEntries = append(behaviorEntries, types.ResourcePackStackEntry{\n\t\t\tUUID:    pack.GetUUID(),\n\t\t\tVersion: pack.GetVersion(),\n\t\t})\n\t}\n\n\tpk.ResourcePacks = resourceEntries\n\tpk.BehaviorPacks = behaviorEntries\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetServerHandshake(encryptionJwt string) packets.IPacket {\n\tvar pk = bedrock.NewServerHandshakePacket()\n\tpk.Jwt = encryptionJwt\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetSetEntityData(runtimeId uint64, data map[uint32][]interface{}) packets.IPacket {\n\tvar pk = bedrock.NewSetEntityDataPacket()\n\tpk.RuntimeId = runtimeId\n\tpk.EntityData = data\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetStartGame(player protocol.StartGameEntry, runtimeIdsTable []byte) packets.IPacket {\n\tvar pk = bedrock.NewStartGamePacket()\n\tpk.Generator = 1\n\tpk.LevelSeed = 312402\n\tpk.DefaultPermissionLevel = permissions.LevelMember\n\tpk.EntityRuntimeId = player.GetRuntimeId()\n\tpk.EntityUniqueId = player.GetUniqueId()\n\tpk.PlayerGameMode = 1\n\tpk.PlayerPosition = player.GetPosition()\n\tpk.LevelGameMode = 1\n\tpk.LevelSpawnPosition = blocks.NewPosition(0, 7, 0)\n\tpk.CommandsEnabled = true\n\n\tvar gameRules = player.GetDimension().GetLevel().GetGameRules()\n\tvar gameRuleEntries = map[string]types.GameRuleEntry{}\n\tfor name, gameRule := range gameRules {\n\t\tgameRuleEntries[string(name)] = types.GameRuleEntry{Name: string(gameRule.GetName()), Value: gameRule.GetValue()}\n\t}\n\n\tpk.GameRules = gameRuleEntries\n\tpk.LevelName = player.GetDimension().GetLevel().GetName()\n\tpk.CurrentTick = player.GetDimension().GetLevel().GetCurrentTick()\n\tpk.Time = 0\n\tpk.AchievementsDisabled = true\n\tpk.BroadcastToLan = true\n\tpk.RuntimeIdsTable = runtimeIdsTable\n\n\tpk.PlatformBroadcastIntent = bedrock.GameBroadcastSettingPublic\n\tpk.XBOXBroadcastIntent = bedrock.GameBroadcastSettingPublic\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetText(text types.Text) packets.IPacket {\n\tvar pk = bedrock.NewTextPacket()\n\tpk.TextType = text.TextType\n\tpk.Translation = text.IsTranslation\n\tpk.Params = text.TranslationParameters\n\tpk.SourceName = text.SourceName\n\tpk.XUID = text.SourceXUID\n\tpk.Message = text.Message\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetTransfer(address string, port uint16) packets.IPacket {\n\tvar pk = bedrock.NewTransferPacket()\n\tpk.Address = address\n\tpk.Port = port\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetUpdateAttributes(runtimeId uint64, attributeMap data2.AttributeMap) packets.IPacket {\n\tvar pk = bedrock.NewUpdateAttributesPacket()\n\tpk.RuntimeId = runtimeId\n\tpk.Attributes = attributeMap\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetNetworkChunkPublisherUpdatePacket(position blocks.Position, radius uint32) packets.IPacket {\n\tvar pk = bedrock.NewNetworkChunkPublisherUpdatePacket()\n\tpk.Position = position\n\tpk.Radius = radius\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetMoveEntity(runtimeId uint64, position r3.Vector, rot data2.Rotation, flags byte, teleport bool) packets.IPacket {\n\tvar pk = bedrock.NewMoveEntityPacket()\n\n\tpk.RuntimeId = runtimeId\n\tpk.Position = position\n\tpk.Rotation = rot\n\tpk.Flags = flags\n\n\tif teleport {\n\t\tpk.Flags |= data.MoveEntityTeleport\n\t}\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetPlayerSkin(uuid2 uuid.UUID, skinId, geometryName, geometryData string, skinData, capeData []byte) packets.IPacket {\n\tvar pk = bedrock.NewPlayerSkinPacket()\n\n\tpk.UUID = uuid2\n\tpk.SkinId = skinId\n\tpk.SkinData = skinData\n\tpk.CapeData = capeData\n\tpk.GeometryName = geometryName\n\tpk.GeometryData = geometryData\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetPlayerAction(runtimeId uint64, action int32, position blocks.Position, face int32) packets.IPacket {\n\tvar pk = bedrock.NewPlayerActionPacket()\n\n\tpk.RuntimeId = runtimeId\n\tpk.Action = action\n\tpk.Position = position\n\tpk.Face = face\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetAnimate(action int32, runtimeId uint64, float float32) packets.IPacket {\n\tvar pk = bedrock.NewAnimatePacket()\n\n\tpk.RuntimeId = runtimeId\n\tpk.Action = action\n\tpk.Float = float\n\n\treturn pk\n}\n\nfunc (protocol *PacketManager) GetUpdateBlock(position blocks.Position, blockRuntimeId, dataLayerId uint32) packets.IPacket {\n\tvar pk = bedrock.NewUpdateBlockPacket()\n\n\tpk.Position = position\n\tpk.BlockRuntimeId = blockRuntimeId\n\tpk.DataLayerId = dataLayerId\n\n\treturn pk\n}"
  },
  {
    "path": "packs/base.go",
    "content": "package packs\n\nimport (\n\t\"archive/zip\"\n\t\"crypto/sha256\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nconst (\n\tBehavior PackType = \"data\"\n\tResource PackType = \"resources\"\n)\n\n// PackType is a name of a pack type.\ntype PackType string\n\n// Pack is the main interface which both Resource- and BehaviorPack satisfy.\ntype Pack interface {\n\tGetUUID() string\n\tGetVersion() string\n\tGetFileSize() int64\n\tGetSha256() string\n\tGetChunk(offset int, length int) []byte\n\tGetPath() string\n}\n\n// PacketManagerBase is a struct that forms the base of every pack.\n// It has functions for loading, validating and pack data.\ntype Base struct {\n\tpackPath string\n\tmanifest *Manifest\n\tcontent  []byte\n\tsize     int64\n\tsha256   []byte\n\tpackType PackType\n}\n\n// Manifest is a struct that contains all information of a pack.\ntype Manifest struct {\n\tHeader struct {\n\t\tDescription   string    `json:\"description\"`\n\t\tName          string    `json:\"name\"`\n\t\tUUID          string    `json:\"uuid\"`\n\t\tVersion       []float64 `json:\"version\"`\n\t\tVersionString string\n\t} `json:\"header\"`\n\tModules []struct {\n\t\tDescription string    `json:\"description\"`\n\t\tType        string    `json:\"type\"`\n\t\tUUID        string    `json:\"uuid\"`\n\t\tVersion     []float64 `json:\"version\"`\n\t} `json:\"modules\"`\n\tDependencies []struct {\n\t\tDescription string    `json:\"description\"`\n\t\tType        string    `json:\"type\"`\n\t\tUUID        string    `json:\"uuid\"`\n\t\tVersion     []float64 `json:\"version\"`\n\t} `json:\"dependencies\"`\n}\n\n// newBase returns a new base at the given path and with the given pack type.\nfunc newBase(path string, packType PackType) *Base {\n\tvar reader, _ = os.Open(path)\n\tvar content, _ = ioutil.ReadAll(reader)\n\tvar sha = sha256.Sum256(content)\n\n\tvar shaBytes []byte\n\tfor _, b := range sha {\n\t\tshaBytes = append(shaBytes, b)\n\t}\n\treturn &Base{path, &Manifest{}, content, int64(len(content)), shaBytes, packType}\n}\n\n// Load loads the pack, and returns an error if any.\nfunc (pack *Base) Load() error {\n\tvar zipFile, err = zip.OpenReader(pack.packPath)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfor _, file := range zipFile.File {\n\t\tif file.Name != \"manifest.json\" && file.Name != \"pack_manifest.json\" {\n\t\t\tcontinue\n\t\t}\n\t\treader, _ := file.Open()\n\t\tbytes, _ := ioutil.ReadAll(reader)\n\n\t\tmanifest := &Manifest{}\n\t\terr := json.Unmarshal(bytes, manifest)\n\t\tpack.manifest = manifest\n\n\t\treader.Close()\n\n\t\treturn err\n\t}\n\treturn errors.New(\"No manifest.json or pack_manifest.json could be found in zip: \" + pack.packPath)\n}\n\n// GetPath returns the path of the pack.\nfunc (pack *Base) GetPath() string {\n\treturn pack.packPath\n}\n\n// GetSha256 returns the Sha256 checksum of the pack.\nfunc (pack *Base) GetSha256() string {\n\treturn string(pack.sha256)\n}\n\n// GetFileSize returns the file size of the pack.\nfunc (pack *Base) GetFileSize() int64 {\n\treturn pack.size\n}\n\n// GetUUID returns the UUID of the pack.\nfunc (pack *Base) GetUUID() string {\n\treturn pack.manifest.Header.UUID\n}\n\n// GetVersion returns the version string of the pack.\nfunc (pack *Base) GetVersion() string {\n\treturn pack.manifest.Header.VersionString\n}\n\n// GetManifest returns the manifest of the pack.\nfunc (pack *Base) GetManifest() *Manifest {\n\treturn pack.manifest\n}\n\n// GetContent returns the full byte array of the data of the pack.\nfunc (pack *Base) GetContent() []byte {\n\treturn pack.content\n}\n\n// ValidateManifest validates the manifest, and returns an error if any.\nfunc (pack *Base) ValidateManifest() error {\n\tvar manifest = pack.manifest\n\tif manifest.Header.Description == \"\" {\n\t\treturn errors.New(\"Pack at \" + pack.packPath + \" is missing a description.\")\n\t}\n\tif manifest.Header.Name == \"\" {\n\t\treturn errors.New(\"Pack at \" + pack.packPath + \" is missing a name.\")\n\t}\n\n\tif len(manifest.Header.Version) < 2 {\n\t\treturn errors.New(\"Pack at \" + pack.packPath + \" is missing a valid version.\")\n\t}\n\n\tvar versionStrings []string\n\tfor _, versionNumber := range manifest.Header.Version {\n\t\tversionStrings = append(versionStrings, strconv.Itoa(int(versionNumber)))\n\t}\n\tmanifest.Header.VersionString = strings.Join(versionStrings, \".\")\n\n\treturn pack.ValidateModules()\n}\n\n// ValidateModules validates the modules of the pack, and returns an error if any.\nfunc (pack *Base) ValidateModules() error {\n\tvar modules = pack.manifest.Modules\n\tif len(modules) == 0 {\n\t\treturn errors.New(\"Pack at \" + pack.packPath + \" doesn't have any modules.\")\n\t}\n\n\tfor index, module := range modules {\n\t\tif module.Description == \"\" {\n\t\t\treturn errors.New(\"Module \" + strconv.Itoa(index) + \" in pack at \" + pack.packPath + \" is missing a description.\")\n\t\t}\n\n\t\tif len(module.Version) < 2 {\n\t\t\treturn errors.New(\"Module \" + strconv.Itoa(index) + \" in pack at \" + pack.packPath + \" is missing a valid version.\")\n\t\t}\n\n\t\tif module.Type == \"\" {\n\t\t\treturn errors.New(\"Module \" + strconv.Itoa(index) + \" in pack at \" + pack.packPath + \" is missing a valid type.\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// GetChunk returns a chunk of the pack at the given offset with the given length.\nfunc (pack *Base) GetChunk(offset int, length int) []byte {\n\tif offset > len(pack.content) || offset < 0 || length < 1 {\n\t\treturn []byte{}\n\t}\n\tif offset+length > len(pack.content) {\n\t\tlength = int(pack.size) - offset\n\t}\n\treturn pack.content[offset : offset+length]\n}\n"
  },
  {
    "path": "packs/behavior.go",
    "content": "package packs\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n)\n\n// BehaviorPack is a pack used to modify the behavior of entities.\ntype BehaviorPack struct {\n\t*Base\n}\n\n// NewBehaviorPack returns a new behavior pack at the given path.\nfunc NewBehaviorPack(path string) *BehaviorPack {\n\treturn &BehaviorPack{newBase(path, Behavior)}\n}\n\n// ValidateDependencies validates all dependencies of the behavior pack, and returns an error if any.\nfunc (pack *BehaviorPack) ValidateDependencies(manager *Manager) error {\n\tvar dependencies = pack.manifest.Dependencies\n\tfor index, dependency := range dependencies {\n\t\tif dependency.Description == \"\" {\n\t\t\treturn errors.New(\"Dependency \" + strconv.Itoa(index) + \" in pack at \" + pack.packPath + \" is missing a description.\")\n\t\t}\n\n\t\tif !manager.IsResourcePackLoaded(dependency.UUID) {\n\t\t\treturn errors.New(\"Dependency with UUID: \" + dependency.UUID + \" is not loaded.\")\n\t\t}\n\n\t\tif len(dependency.Version) < 2 {\n\t\t\treturn errors.New(\"Dependency \" + strconv.Itoa(index) + \" in pack at \" + pack.packPath + \" is missing a valid version.\")\n\t\t}\n\n\t\tif dependency.Type != string(Resource) {\n\t\t\treturn errors.New(\"Dependency \" + strconv.Itoa(index) + \" in pack at \" + pack.packPath + \" is missing the correct type. Expected: 'resources', got: '\" + dependency.Type + \"'\")\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packs/manager.go",
    "content": "package packs\n\nimport (\n\t\"github.com/irmine/gomine/text\"\n\t\"io/ioutil\"\n\t\"path/filepath\"\n)\n\n// Manager manages the loading of packs.\n// It provides helper functions for both types of packs.\ntype Manager struct {\n\tserverPath string\n\n\tresourcePacks map[string]*ResourcePack\n\tresourceStack *Stack\n\n\tbehaviorPacks map[string]*BehaviorPack\n\tbehaviorStack *Stack\n}\n\n// NewManager returns a new pack manager with the given path.\nfunc NewManager(serverPath string) *Manager {\n\treturn &Manager{serverPath, make(map[string]*ResourcePack), NewStack(), make(map[string]*BehaviorPack), NewStack()}\n}\n\n// GetResourcePacks returns all resource maps in a UUID => pack map.\nfunc (manager *Manager) GetResourcePacks() map[string]*ResourcePack {\n\treturn manager.resourcePacks\n}\n\n// GetBehaviorPacks returns all behavior packs in a UUID => pack map.\nfunc (manager *Manager) GetBehaviorPacks() map[string]*BehaviorPack {\n\treturn manager.behaviorPacks\n}\n\n// GetResourceStack returns the resource pack stack.\nfunc (manager *Manager) GetResourceStack() *Stack {\n\treturn manager.resourceStack\n}\n\n// GetBehaviorStack returns the behavior pack stack.\nfunc (manager *Manager) GetBehaviorStack() *Stack {\n\treturn manager.behaviorStack\n}\n\n// LoadResourcePacks loads all resource packs in the `serverPath/extensions/resource_packs/` folder.\n// It returns an array of errors that occurred during the loading of all resource packs.\nfunc (manager *Manager) LoadResourcePacks() []error {\n\tvar path = manager.serverPath + \"extensions/resource_packs/\"\n\tvar files, _ = ioutil.ReadDir(path)\n\tvar errors []error\n\tfor _, file := range files {\n\t\tif file.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\textension := filepath.Ext(file.Name())\n\t\tif extension != \".mcpack\" && extension != \".zip\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tfilePath := path + file.Name()\n\n\t\tresourcePack := NewResourcePack(filePath)\n\t\terr := resourcePack.Load()\n\t\tif err != nil {\n\t\t\terrors = append(errors, err)\n\t\t\tcontinue\n\t\t}\n\n\t\terr = resourcePack.ValidateManifest()\n\t\tif err != nil {\n\t\t\terrors = append(errors, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tmanager.resourcePacks[resourcePack.manifest.Header.UUID] = resourcePack\n\t\ttext.DefaultLogger.Info(\"Loaded resource pack:\", text.Yellow+resourcePack.manifest.Header.Name)\n\t\tmanager.GetResourceStack().Push(resourcePack)\n\t}\n\treturn errors\n}\n\n// LoadBehaviorPacks loads all behavior packs in the `serverPath/extensions/behavior_packs/` folder.\n// It returns an array of errors that occurred during the loading of all behavior packs.\nfunc (manager *Manager) LoadBehaviorPacks() []error {\n\tvar path = manager.serverPath + \"extensions/behavior_packs/\"\n\tvar files, _ = ioutil.ReadDir(path)\n\tvar errors []error\n\tfor _, file := range files {\n\t\tif file.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\textension := filepath.Ext(file.Name())\n\t\tif extension != \".mcpack\" && extension != \".zip\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tfilePath := path + file.Name()\n\n\t\tbehaviorPack := NewBehaviorPack(filePath)\n\t\terr := behaviorPack.Load()\n\t\tif err != nil {\n\t\t\terrors = append(errors, err)\n\t\t\tcontinue\n\t\t}\n\n\t\terr = behaviorPack.ValidateManifest()\n\t\tif err != nil {\n\t\t\terrors = append(errors, err)\n\t\t\tcontinue\n\t\t}\n\n\t\terr = behaviorPack.ValidateDependencies(manager)\n\t\tif err != nil {\n\t\t\terrors = append(errors, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tmanager.behaviorPacks[behaviorPack.manifest.Header.UUID] = behaviorPack\n\t\tmanager.GetBehaviorStack().Push(behaviorPack)\n\t}\n\treturn errors\n}\n\n// IsResourcePackLoaded checks if a resource pack with the given UUID is loaded.\nfunc (manager *Manager) IsResourcePackLoaded(uuid string) bool {\n\tvar _, exists = manager.resourcePacks[uuid]\n\treturn exists\n}\n\n// IsBehaviorPackLoaded checks if a behavior pack with the given UUID is loaded.\nfunc (manager *Manager) IsBehaviorPackLoaded(uuid string) bool {\n\tvar _, exists = manager.behaviorPacks[uuid]\n\treturn exists\n}\n\n// IsPackLoaded checks if any pack with the given UUID is loaded.\nfunc (manager *Manager) IsPackLoaded(uuid string) bool {\n\treturn manager.IsResourcePackLoaded(uuid) || manager.IsBehaviorPackLoaded(uuid)\n}\n\n// GetResourcePack returns a resource pack by its UUID, or nil of none was found.\nfunc (manager *Manager) GetResourcePack(uuid string) *ResourcePack {\n\tif !manager.IsResourcePackLoaded(uuid) {\n\t\treturn nil\n\t}\n\treturn manager.resourcePacks[uuid]\n}\n\n// GetBehaviorPack returns a behavior pack by its UUID, or nil if none was found.\nfunc (manager *Manager) GetBehaviorPack(uuid string) *BehaviorPack {\n\tif !manager.IsBehaviorPackLoaded(uuid) {\n\t\treturn nil\n\t}\n\treturn manager.behaviorPacks[uuid]\n}\n\n// GetPack returns any pack that has the given UUID, or nil if none was found.\nfunc (manager *Manager) GetPack(uuid string) Pack {\n\tif manager.GetResourcePack(uuid) != nil {\n\t\treturn manager.GetResourcePack(uuid)\n\t}\n\treturn manager.GetBehaviorPack(uuid)\n}\n"
  },
  {
    "path": "packs/resource.go",
    "content": "package packs\n\n// ResourcePack is a pack that modifies the visual side of game play.\ntype ResourcePack struct {\n\t*Base\n}\n\n// NewResourcePack returns a new resource pack with the given path.\nfunc NewResourcePack(path string) *ResourcePack {\n\treturn &ResourcePack{newBase(path, Resource)}\n}\n"
  },
  {
    "path": "packs/stack.go",
    "content": "package packs\n\n// Stack is a struct that allows ordering the stack of packs.\ntype Stack []Pack\n\n// NewStack returns a new pack stack.\nfunc NewStack() *Stack {\n\treturn &Stack{}\n}\n\n// GetPackAtOffset returns the pack at the given offset on the stack.\nfunc (stack *Stack) GetPackAtOffset(offset int) Pack {\n\treturn (*stack)[offset]\n}\n\n// Pop removes the pack on top of the stack.\nfunc (stack *Stack) Pop() {\n\t*stack = (*stack)[1:]\n}\n\n// Push adds the given pack on top of the stack.\nfunc (stack *Stack) Push(pack Pack) {\n\t*stack = append([]Pack{pack}, *stack...)\n}\n\n// Swap swaps the packs at the given offsets with each other.\nfunc (stack *Stack) Swap(offset1, offset2 int) {\n\tpack1 := (*stack)[offset1]\n\tpack2 := (*stack)[offset2]\n\t(*stack)[offset1] = pack2\n\t(*stack)[offset2] = pack1\n}\n\n// Len returns the length of the stack.\nfunc (stack *Stack) Len() int {\n\treturn len(*stack)\n}\n\n// Peek returns the top pack of the stack.\nfunc (stack *Stack) Peek() Pack {\n\treturn (*stack)[0]\n}\n"
  },
  {
    "path": "permissions/group.go",
    "content": "package permissions\n\n// Group is a struct used for basic permission managing.\n// Groups can be granted a set of permissions.\ntype Group struct {\n\tname        string\n\tlevel       int\n\tpermissions map[string]*Permission\n}\n\n// NewGroup returns a new group with the given name and permission level.\nfunc NewGroup(name string, level int) *Group {\n\treturn &Group{name, level, make(map[string]*Permission)}\n}\n\n// GetName returns the name of the group.\nfunc (group *Group) GetName() string {\n\treturn group.name\n}\n\n// GetPermissions returns a name => permission map of all permissions of the group.\nfunc (group *Group) GetPermissions() map[string]*Permission {\n\treturn group.permissions\n}\n\n// HasPermission checks if the group has a permission with the name.\nfunc (group *Group) HasPermission(permission string) bool {\n\tvar _, ok = group.permissions[permission]\n\treturn ok\n}\n\n// AddPermission adds a permission to the group.\nfunc (group *Group) AddPermission(permission *Permission) {\n\tgroup.permissions[permission.GetName()] = permission\n}\n\n// RemovePermission removes a permission with the given name from the group.\nfunc (group *Group) RemovePermission(permission string) {\n\tdelete(group.permissions, permission)\n}\n\n// InheritGroup inherits all permissions from a group.\nfunc (group *Group) InheritGroup(inheritedGroup *Group) {\n\tfor _, permission := range inheritedGroup.GetPermissions() {\n\t\tgroup.AddPermission(permission)\n\t}\n}\n"
  },
  {
    "path": "permissions/level.go",
    "content": "package permissions\n\nconst (\n\tLevelVisitor  PermissionLevel = iota\n\tLevelMember                   = 1\n\tLevelOperator                 = 2\n\tLevelCustom                   = 3\n)\n\n// A Permission level is used to connect groups with permissions.\ntype PermissionLevel byte\n"
  },
  {
    "path": "permissions/manager.go",
    "content": "package permissions\n\nimport (\n\t\"errors\"\n)\n\n// Manager is a struct used to manage permissions and groups.\n// It provides helper functions and functions to register groups and permissions.\ntype Manager struct {\n\tdefaultGroup *Group\n\tpermissions  map[string]*Permission\n\tgroups       map[string]*Group\n}\n\nvar (\n\tUnknownPermission = errors.New(\"unknown permission\")\n\tUnknownGroup      = errors.New(\"unknown group\")\n)\n\n// NewManager returns a new permission manager.\nfunc NewManager() *Manager {\n\treturn &Manager{nil, make(map[string]*Permission), make(map[string]*Group)}\n}\n\n// GetDefaultGroup returns the default group of the manager.\nfunc (manager *Manager) GetDefaultGroup() *Group {\n\treturn manager.defaultGroup\n}\n\n// SetDefaultGroup sets the default group of the manager.\nfunc (manager *Manager) SetDefaultGroup(group *Group) {\n\tmanager.defaultGroup = group\n}\n\n// AddGroup adds a new group to the manager.\nfunc (manager *Manager) AddGroup(group *Group) {\n\tmanager.groups[group.GetName()] = group\n}\n\n// GetGroup returns a group in the manager with the given name and an error if it could not be found.\nfunc (manager *Manager) GetGroup(name string) (*Group, error) {\n\tif !manager.GroupExists(name) {\n\t\treturn nil, UnknownGroup\n\t}\n\treturn manager.groups[name], nil\n}\n\n// GroupExists checks if a group with the given name exists.\nfunc (manager *Manager) GroupExists(name string) bool {\n\tvar _, ok = manager.groups[name]\n\treturn ok\n}\n\n// RemoveGroup removes a group with the given name from the manager.\nfunc (manager *Manager) RemoveGroup(name string) {\n\tdelete(manager.groups, name)\n}\n\n// GetPermission returns a permission by its name, and an error if it could not be found.\nfunc (manager *Manager) GetPermission(name string) (*Permission, error) {\n\tif !manager.IsPermissionRegistered(name) {\n\t\treturn nil, UnknownPermission\n\t}\n\treturn manager.permissions[name], nil\n}\n\n// IsPermissionRegistered checks if a permission with the given name is registered.\nfunc (manager *Manager) IsPermissionRegistered(name string) bool {\n\tvar _, ok = manager.permissions[name]\n\treturn ok\n}\n\n// RegisterPermission registers a new permission.\nfunc (manager *Manager) RegisterPermission(permission *Permission) {\n\tmanager.permissions[permission.GetName()] = permission\n}\n"
  },
  {
    "path": "permissions/permissible.go",
    "content": "package permissions\n\n// Permissible is an interface used to satisfy for permission holders.\ntype Permissible interface {\n\tHasPermission(string) bool\n\tRemovePermission(string)\n\tAddPermission(*Permission)\n}\n"
  },
  {
    "path": "permissions/permission.go",
    "content": "package permissions\n\n// Permission is a struct with a name, a default level and children.\n// Every child permission can in turn have its own child permissions.\ntype Permission struct {\n\tname         string\n\tdefaultLevel int\n\tchildren     map[string]*Permission\n}\n\n// NewPermission returns a new permission with the given name and default level.\nfunc NewPermission(name string, defaultLevel int) *Permission {\n\treturn &Permission{name, defaultLevel & 0x04, make(map[string]*Permission)}\n}\n\n// GetName returns the name of the permission.\nfunc (permission *Permission) GetName() string {\n\treturn permission.name\n}\n\n// GetDefaultLevel returns the default level of required to be granted the permission.\nfunc (permission *Permission) GetDefaultLevel() int {\n\treturn permission.defaultLevel\n}\n\n// SetDefaultLevel sets the default level of the the permission.\nfunc (permission *Permission) SetDefaultLevel(level int) {\n\tpermission.defaultLevel = level & 0x04\n}\n\n// GetChildren returns a name => permission child permission map of all children.\nfunc (permission *Permission) GetChildren() map[string]*Permission {\n\treturn permission.children\n}\n\n// AddChild adds the given permission as child permission.\nfunc (permission *Permission) AddChild(child *Permission) {\n\tpermission.children[child.GetName()] = child\n}\n\n// HasChild checks if the permission has a child with the given name.\nfunc (permission *Permission) HasChild(name string) bool {\n\tvar _, ok = permission.children[name]\n\treturn ok\n}\n"
  },
  {
    "path": "players/player.go",
    "content": "package players\n\nimport (\n\t\"github.com/google/uuid\"\n\t\"github.com/irmine/worlds/entities\"\n\t\"math\"\n)\n\ntype Player struct {\n\t*entities.Entity\n\tuuid     uuid.UUID\n\txuid     string\n\tplatform int32\n\n\tplayerName  string\n\tdisplayName string\n\n\tskinId       string\n\tskinData     []byte\n\tcapeData     []byte\n\tgeometryName string\n\tgeometryData string\n}\n\n// NewPlayer returns a new player with the given name.\nfunc NewPlayer(uuid uuid.UUID, xuid string, platform int32, name string) *Player {\n\tvar player = &Player{Entity: entities.New(entities.Player)}\n\n\tplayer.uuid = uuid\n\tplayer.xuid = xuid\n\tplayer.platform = platform\n\n\tplayer.playerName = name\n\tplayer.displayName = name\n\n\treturn player\n}\n\n// GetName returns the username the player used to join the server.\nfunc (player *Player) GetName() string {\n\treturn player.playerName\n}\n\n// SetName sets the player name of this player.\n// Note: This function is internal, and should not be used by plugins.\nfunc (player *Player) SetName(name string) {\n\tplayer.playerName = name\n}\n\n// GetDisplayName returns the name the player shows in-game.\nfunc (player *Player) GetDisplayName() string {\n\treturn player.displayName\n}\n\n// SetDisplayName sets the name other players can see in-game.\nfunc (player *Player) SetDisplayName(name string) {\n\tplayer.displayName = name\n}\n\n// GetUUID returns the UUID of the player.\nfunc (player *Player) GetUUID() uuid.UUID {\n\treturn player.uuid\n}\n\n// GetXUID returns the XUID of the player.\nfunc (player *Player) GetXUID() string {\n\treturn player.xuid\n}\n\n// GetPlatform returns the platform of the player.\nfunc (player *Player) GetPlatform() int32 {\n\treturn player.platform\n}\n\n// SpawnPlayerTo spawns this player to the given other player.\nfunc (player *Player) SpawnPlayerTo(viewer entities.Viewer) {\n\tviewer.SendAddPlayer(player.GetUUID(), player)\n}\n\n// SpawnPlayerToAll spawns this player to all other players.\nfunc (player *Player) SpawnPlayerToAll() {\n\tfor _, p := range player.Dimension.GetViewers() {\n\t\tif p.GetUUID() == player.GetUUID() {\n\t\t\tcontinue\n\t\t}\n\t\tif viewer, ok := p.(entities.Viewer); ok {\n\t\t\tplayer.SpawnPlayerTo(viewer)\n\t\t}\n\t}\n}\n\n// SetSkinId sets the skin ID/name of the player.\nfunc (player *Player) SetSkinId(id string) {\n\tplayer.skinId = id\n}\n\n// GetSkinId returns the skin ID/name of the player.\nfunc (player *Player) GetSkinId() string {\n\treturn player.skinId\n}\n\n// GetSkinData returns the skin data of the player. (RGBA byte array)\nfunc (player *Player) GetSkinData() []byte {\n\treturn player.skinData\n}\n\n// SetSkinData sets the skin data of the player. (RGBA byte array)\nfunc (player *Player) SetSkinData(data []byte) {\n\tplayer.skinData = data\n}\n\n// GetCapeData returns the cape data of the player. (RGBA byte array)\nfunc (player *Player) GetCapeData() []byte {\n\treturn player.capeData\n}\n\n// SetCapeData sets the cape data of the player. (RGBA byte array)\nfunc (player *Player) SetCapeData(data []byte) {\n\tplayer.capeData = data\n}\n\n// GetGeometryName returns the geometry name of the player.\nfunc (player *Player) GetGeometryName() string {\n\treturn player.geometryName\n}\n\n// SetGeometryName sets the geometry name of the player.\nfunc (player *Player) SetGeometryName(name string) {\n\tplayer.geometryName = name\n}\n\n// GetGeometryData returns the geometry data (json string) of the player.\nfunc (player *Player) GetGeometryData() string {\n\treturn player.geometryData\n}\n\n// SetGeometryData sets the geometry data (json string) of the player.\nfunc (player *Player) SetGeometryData(data string) {\n\tplayer.geometryData = data\n}\n\n// SyncMove synchronizes the server's player movement with the client movement.\nfunc (player *Player) SyncMove(x, y, z, pitch, yaw, headYaw float64, onGround bool) {\n\tplayer.Position.X = x\n\tplayer.Position.Y = y\n\tplayer.Position.Z = z\n\tplayer.Rotation.Pitch = math.Mod(pitch, 360)\n\tplayer.Rotation.Yaw = math.Mod(yaw, 360)\n\tplayer.Rotation.HeadYaw = headYaw\n\tplayer.OnGround = onGround\n\tplayer.HasMovementUpdate = true\n}\n\n// Sends updated entity position and rotation to a certain viewer\n// this overrides the base entity function.\nfunc (player *Player) SendMovement(viewer entities.Viewer) {\n\tviewer.SendMovePlayer(player.GetRuntimeId(), player.Position, player.Rotation, 0, player.OnGround, player.GetRidingId())\n}\n\n// Sends updated player position and rotation to all viewers,\n// this overrides the base entity function.\nfunc (player *Player) BroadcastMovement() {\n\tfor _, viewer := range player.GetViewers() {\n\t\tviewer.SendMovePlayer(player.GetRuntimeId(), player.Position, player.Rotation, 0, player.OnGround, player.GetRidingId())\n\t}\n}\n\n// Tick ticks the player, this overrides the base entity tick.\nfunc (player Player) Tick() {\n\tif player.HasEntityDataUpdate {\n\t\tplayer.BroadcastUpdatedEntityData()\n\t\tplayer.HasEntityDataUpdate = false\n\t}\n\tif player.HasMovementUpdate {\n\t\tplayer.HasMovementUpdate = false\n\t}\n\tplayer.BroadcastMovement()\n}"
  },
  {
    "path": "plugin.go",
    "content": "package gomine\n\ntype Manifest struct {\n\tName         string\n\tDescription  string\n\tVersion      string\n\tAPIVersion   string\n\tAuthor       string\n\tOrganisation string\n}\n\ntype IManifest interface {\n\tGetName() string\n\tGetDescription() string\n\tGetVersion() string\n\tGetAPIVersion() string\n\tGetAuthor() string\n\tGetOrganisation() string\n}\n\ntype IPlugin interface {\n\tGetServer() *Server\n\tOnEnable()\n\n\tGetName() string\n\tGetVersion() string\n\tGetAuthor() string\n\tGetOrganisation() string\n\tGetAPIVersion() string\n\tsetManifest(IManifest)\n}\n\ntype Plugin struct {\n\tserver *Server\n\n\tmanifest IManifest\n}\n\nfunc NewPlugin(server *Server) *Plugin {\n\treturn &Plugin{server, Manifest{}}\n}\n\n// GetName returns the name of the manifest.\nfunc (manifest Manifest) GetName() string {\n\treturn manifest.Name\n}\n\n// GetVersion returns the version of the manifest.\nfunc (manifest Manifest) GetVersion() string {\n\treturn manifest.Version\n}\n\n// GetOrganisation returns the author of the manifest.\nfunc (manifest Manifest) GetOrganisation() string {\n\treturn manifest.Organisation\n}\n\n// GetAPIVersion returns the API Version of the manifest.\nfunc (manifest Manifest) GetAPIVersion() string {\n\treturn manifest.APIVersion\n}\n\n// GetAuthor returns the author of the manifest.\nfunc (manifest Manifest) GetAuthor() string {\n\treturn manifest.Author\n}\n\n// GetDescription returns the description of the manifest.\nfunc (manifest Manifest) GetDescription() string {\n\treturn manifest.Description\n}\n\n// GetName returns the name of the plugin.\nfunc (plug *Plugin) GetName() string {\n\treturn plug.manifest.GetName()\n}\n\n// GetVersion returns the version of the plugin.\nfunc (plug *Plugin) GetVersion() string {\n\treturn plug.manifest.GetVersion()\n}\n\n// GetAuthor returns the author of the plugin.\nfunc (plug *Plugin) GetOrganisation() string {\n\treturn plug.manifest.GetOrganisation()\n}\n\n// GetAPIVersion returns the API Version of the plugin.\nfunc (plug *Plugin) GetAPIVersion() string {\n\treturn plug.manifest.GetAPIVersion()\n}\n\n// GetAuthor returns the author of the plugin.\nfunc (plug *Plugin) GetAuthor() string {\n\treturn plug.manifest.GetAuthor()\n}\n\n// GetDescription returns the description of the plugin.\nfunc (plug *Plugin) GetDescription() string {\n\treturn plug.manifest.GetDescription()\n}\n\n// SetManifest sets the manifest of this plugin.\nfunc (plug *Plugin) setManifest(manifest IManifest) {\n\tplug.manifest = manifest\n}\n\n// GetServer returns the main server.\nfunc (plug *Plugin) GetServer() *Server {\n\treturn plug.server\n}\n"
  },
  {
    "path": "plugin_manager.go",
    "content": "package gomine\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"plugin\"\n\t\"strings\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/irmine/gomine/text\"\n)\n\nconst (\n\tApiVersion = \"0.0.1\"\n\n\tOutdatedPlugin     = \"plugin.Open: plugin was built with a different version of package\"\n\tNoPluginsSupported = \"plugin: not implemented\"\n)\n\ntype PluginManager struct {\n\tserver  *Server\n\tplugins map[string]IPlugin\n}\n\nfunc NewPluginManager(server *Server) *PluginManager {\n\treturn &PluginManager{server, make(map[string]IPlugin)}\n}\n\n// GetPlugins returns all plugins currently loaded on the server.\nfunc (manager *PluginManager) GetPlugins() map[string]IPlugin {\n\treturn manager.plugins\n}\n\n// GetServer returns the main server.\nfunc (manager *PluginManager) GetServer() *Server {\n\treturn manager.server\n}\n\n// GetPlugin returns a plugin with the given name, or nil if none could be found.\nfunc (manager *PluginManager) GetPlugin(name string) IPlugin {\n\tif !manager.IsPluginLoaded(name) {\n\t\treturn nil\n\t}\n\treturn manager.plugins[name]\n}\n\n// IsPluginLoaded checks if a plugin with the given name is loaded.\nfunc (manager *PluginManager) IsPluginLoaded(name string) bool {\n\tvar _, exists = manager.plugins[name]\n\treturn exists\n}\n\n// LoadPlugins loads all plugins in the 'extensions/plugins' folder.\nfunc (manager *PluginManager) LoadPlugins() {\n\tvar path = manager.server.ServerPath + \"extensions/plugins/\"\n\tvar files, _ = ioutil.ReadDir(path)\n\n\tfor _, file := range files {\n\t\tif file.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tfilePath := path + file.Name()\n\t\textension := filepath.Ext(filePath)\n\n\t\tif extension != \".so\" {\n\t\t\tcontinue\n\t\t}\n\n\t\terr := manager.LoadPlugin(filePath)\n\t\tif err != nil {\n\t\t\tif err.Error() == NoPluginsSupported {\n\t\t\t\ttext.DefaultLogger.Error(\"Go does currently not support plugins for your operating system.\")\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\ttext.DefaultLogger.LogError(err)\n\t}\n}\n\n// CompilePlugin compiles a plugin.go at the given path during runtime, and opens it. This action is extremely time consuming.\nfunc (manager *PluginManager) CompilePlugin(filePath string) (*plugin.Plugin, error) {\n\tvar compiledPath = strings.Replace(strings.Replace(filePath, \".go\", \"\", 1), \"\\\\\", \"/\", -1)\n\tcompiledPath += \"~\" + uuid.Must(uuid.NewRandom()).String() + \".so\"\n\n\tvar cmd = exec.Command(\"go\", \"build\", \"-buildmode=plugin\", \"-i\", \"-o\", compiledPath, filePath)\n\tvar output, err = cmd.CombinedOutput()\n\n\tif err != nil {\n\t\ttext.DefaultLogger.LogError(err)\n\t\ttext.DefaultLogger.Error(string(output))\n\t}\n\n\tplug, err := plugin.Open(compiledPath)\n\n\treturn plug, err\n}\n\n// RecompilePlugin recompiles a plugin.so at the given path, provided the main source file is at the same location suffixed with .go.\nfunc (manager *PluginManager) RecompilePlugin(filePath string) (*plugin.Plugin, error) {\n\tvar decompiledPath = strings.Replace(strings.Replace(filePath, \".so\", \".go\", 1), \"\\\\\", \"/\", -1)\n\tif strings.Contains(filePath, \"~\") {\n\t\tdecompiledPath = strings.Split(decompiledPath, \"~\")[0] + \".go\"\n\t}\n\n\tos.Remove(filePath)\n\n\treturn manager.CompilePlugin(decompiledPath)\n}\n\n// LoadPlugin loads a plugin at the given file path and returns an error if applicable.\nfunc (manager *PluginManager) LoadPlugin(filePath string) error {\n\tvar plug, err = plugin.Open(filePath)\n\n\tif err != nil {\n\t\tif strings.Contains(err.Error(), OutdatedPlugin) {\n\t\t\ttext.DefaultLogger.Notice(\"Outdated plugin. Recompiling plugin... This might take a bit.\")\n\t\t\tvar newPlugin, newErr = manager.RecompilePlugin(filePath)\n\t\t\tif newErr != nil {\n\t\t\t\treturn newErr\n\t\t\t}\n\t\t\tplug = newPlugin\n\t\t} else {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tmanifestSymbol, err := plug.Lookup(\"Manifest\")\n\tif err != nil {\n\t\treturn errors.New(\"Plugin at '\" + filePath + \"' does not have a Manifest.\")\n\t}\n\n\tmanifest, ok := manifestSymbol.(IManifest)\n\tif !ok {\n\t\treturn errors.New(\"Plugin at '\" + filePath + \"' does not have a valid Manifest.\")\n\t}\n\n\terr = manager.ValidateManifest(manifest, filePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnewPluginSymbol, err := plug.Lookup(\"NewPlugin\")\n\tif err != nil {\n\t\treturn errors.New(\"Plugin at '\" + filePath + \"' does not have a NewPlugin function.\")\n\t}\n\n\tpluginFunc, ok := newPluginSymbol.(func(server *Server) IPlugin)\n\tif !ok {\n\t\treturn errors.New(\"Plugin at '\" + filePath + \"' does not have a valid NewPlugin function.\")\n\t}\n\n\tvar finalPlugin = pluginFunc(manager.server)\n\tfinalPlugin.setManifest(manifest)\n\n\tmanager.plugins[finalPlugin.GetName()] = finalPlugin\n\tfinalPlugin.OnEnable()\n\n\treturn nil\n}\n\n// ValidateManifest validates the plugin manifest and checks for duplicated plugins.\nfunc (manager *PluginManager) ValidateManifest(manifest IManifest, path string) error {\n\tif manifest.GetName() == \"\" {\n\t\treturn errors.New(\"Plugin manifest at \" + path + \" is missing a name.\")\n\t}\n\tif manager.IsPluginLoaded(manifest.GetName()) {\n\t\treturn errors.New(\"Found duplicated plugin at \" + path)\n\t}\n\n\tif manifest.GetDescription() == \"\" {\n\t\treturn errors.New(\"Plugin manifest at \" + path + \" is missing a description.\")\n\t}\n\n\tvar dotCount = strings.Count(manifest.GetVersion(), \".\")\n\tif dotCount < 1 {\n\t\treturn errors.New(\"Plugin manifest at \" + path + \" is missing a valid version.\")\n\t}\n\n\tvar digits = strings.Split(manifest.GetAPIVersion(), \".\")\n\tif len(digits) < 2 {\n\t\treturn errors.New(\"Plugin manifest at \" + path + \" is missing a valid API version.\")\n\t}\n\tvar currentDigits = strings.Split(ApiVersion, \".\")\n\n\tif digits[0] != currentDigits[0] {\n\t\treturn errors.New(\"Plugin manifest at \" + path + \" has an incompatible greater API version. Got: \" + digits[0] + \".~, Expected: \" + currentDigits[0] + \".~\")\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "resources/gomine.yml.go",
    "content": "package resources\n\nimport (\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"gopkg.in/yaml.v2\"\n)\n\ntype GoMineConfig struct {\n\tServerName string `yaml:\"Server LAN Name\"`\n\tServerMotd string `yaml:\"Server MOTD\"`\n\tServerIp   string `yaml:\"Server IP\"`\n\tServerPort uint16 `yaml:\"Server Port\"`\n\n\tMaximumPlayers  uint `yaml:\"Maximum Players\"`\n\tDefaultGameMode byte `yaml:\"Default Gamemode\"`\n\n\tDebugMode bool `yaml:\"Debug Mode\"`\n\n\tDefaultLevel     string `yaml:\"Default Level\"`\n\tDefaultGenerator string `yaml:\"Default Generator\"`\n\n\tForceResourcePacks   bool   `yaml:\"Forced Resource Packs\"`\n\tSelectedResourcePack string `yaml:\"Selected Resource Pack\"`\n\n\tXBOXLiveAuth  bool `yaml:\"XBOX Live Auth\"`\n\tUseEncryption bool `yaml:\"Use Encryption\"`\n\n\tAllowQuery       bool `yaml:\"Allow Query\"`\n\tAllowPluginQuery bool `yaml:\"Allow Plugin Query\"`\n\n\tMaxViewDistance int32 `yaml:\"Max View Distance\"`\n}\n\n// NewGoMineConfig returns a new configuration struct.\n// Creates the file if it does not yet exist.\nfunc NewGoMineConfig(serverPath string) *GoMineConfig {\n\tinitializeConfig(serverPath)\n\treturn getGoMineConfig(serverPath)\n}\n\n// initializeConfig initializes the configuration file if it does not yet exist.\nfunc initializeConfig(serverPath string) {\n\tvar path = serverPath + \"gomine.yml\"\n\tvar _, err = os.Stat(path)\n\n\tif os.IsNotExist(err) {\n\t\tvar data, _ = yaml.Marshal(GoMineConfig{\n\t\t\tServerName: \"GoMine Server\",\n\t\t\tServerMotd: \"GoMine Testing Server\",\n\t\t\tServerIp:   \"0.0.0.0\",\n\t\t\tServerPort: 19132,\n\n\t\t\tMaximumPlayers:  20,\n\t\t\tDefaultGameMode: 1,\n\n\t\t\tDebugMode: true,\n\n\t\t\tDefaultLevel:     \"world\",\n\t\t\tDefaultGenerator: \"Flat\",\n\n\t\t\tForceResourcePacks:   false,\n\t\t\tSelectedResourcePack: \"\",\n\n\t\t\tXBOXLiveAuth:  true,\n\t\t\tUseEncryption: false,\n\n\t\t\tAllowQuery:       true,\n\t\t\tAllowPluginQuery: true,\n\n\t\t\tMaxViewDistance: 8,\n\t\t})\n\t\tvar file, _ = os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)\n\t\tfile.WriteString(string(data))\n\t\tfile.Sync()\n\t}\n}\n\n// getGoMineConfig parses the configuration file into a struct.\nfunc getGoMineConfig(serverPath string) *GoMineConfig {\n\tvar yamlFile, _ = ioutil.ReadFile(serverPath + \"gomine.yml\")\n\n\tvar config = &GoMineConfig{}\n\tyaml.Unmarshal(yamlFile, config)\n\n\treturn config\n}\n"
  },
  {
    "path": "server.go",
    "content": "package gomine\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"github.com/irmine/worlds/generation/defaults\"\n\t\"github.com/irmine/worlds/providers\"\n\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/irmine/gomine/commands\"\n\t\"github.com/irmine/gomine/net\"\n\t\"github.com/irmine/gomine/net/info\"\n\t\"github.com/irmine/gomine/net/packets/data\"\n\t\"github.com/irmine/gomine/net/protocol\"\n\t\"github.com/irmine/gomine/packs\"\n\t\"github.com/irmine/gomine/permissions\"\n\t\"github.com/irmine/gomine/resources\"\n\t\"github.com/irmine/gomine/text\"\n\t\"github.com/irmine/goraklib/server\"\n\t\"github.com/irmine/query\"\n\t\"github.com/irmine/worlds\"\n\tnet2 \"net\"\n\t\"os\"\n\t\"strings\"\n)\n\nconst (\n\tGoMineName    = \"GoMine\"\n\tGoMineVersion = \"0.0.1\"\n)\n\ntype Server struct {\n\tisRunning         bool\n\ttick              int64\n\tprivateKey        *ecdsa.PrivateKey\n\ttoken             []byte\n\tServerPath        string\n\tConfig            *resources.GoMineConfig\n\tCommandReader     *text.CommandReader\n\tCommandManager    *commands.Manager\n\tPackManager       *packs.Manager\n\tPermissionManager *permissions.Manager\n\tLevelManager      *worlds.Manager\n\tSessionManager    *net.SessionManager\n\tNetworkAdapter    *net.NetworkAdapter\n\tPluginManager     *PluginManager\n\tQueryManager      query.Manager\n}\n\n// AlreadyStarted gets returned during server startup,\n// if the server has already been started.\nvar AlreadyStarted = errors.New(\"server is already started\")\n\n// NewServer returns a new server with the given server path.\nfunc NewServer(serverPath string, config *resources.GoMineConfig) *Server {\n\tvar s = &Server{}\n\n\ts.ServerPath = serverPath\n\ts.Config = config\n\ttext.DefaultLogger.DebugMode = config.DebugMode\n\tfile, _ := os.OpenFile(serverPath+\"gomine.log\", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0700)\n\ttext.DefaultLogger.AddOutput(func(message []byte) {\n\t\t_, err := file.WriteString(text.ColoredString(message).StripAll())\n\t\tif err != nil {\n\t\t\ttext.DefaultLogger.LogError(err)\n\t\t}\n\t})\n\n\ts.LevelManager = worlds.NewManager(serverPath)\n\ts.CommandReader = text.NewCommandReader(os.Stdin)\n\ts.CommandReader.AddReadFunc(s.attemptReadCommand)\n\n\ts.CommandManager = commands.NewManager()\n\n\ts.SessionManager = net.NewSessionManager()\n\ts.NetworkAdapter = net.NewNetworkAdapter(NewPacketManager(s), s.SessionManager)\n\ts.NetworkAdapter.GetRakLibManager().PongData = s.GeneratePongData()\n\ts.NetworkAdapter.GetRakLibManager().RawPacketFunction = s.HandleRaw\n\ts.NetworkAdapter.GetRakLibManager().DisconnectFunction = s.HandleDisconnect\n\n\ts.PackManager = packs.NewManager(serverPath)\n\ts.PermissionManager = permissions.NewManager()\n\ts.PluginManager = NewPluginManager(s)\n\ts.QueryManager = query.NewManager()\n\n\tif config.UseEncryption {\n\t\tvar curve = elliptic.P384()\n\n\t\tvar err error\n\t\ts.privateKey, err = ecdsa.GenerateKey(curve, rand.Reader)\n\t\ttext.DefaultLogger.LogError(err)\n\n\t\tif !curve.IsOnCurve(s.privateKey.X, s.privateKey.Y) {\n\t\t\ttext.DefaultLogger.Error(\"Invalid private key generated\")\n\t\t}\n\n\t\tvar token = make([]byte, 128)\n\t\t_, err = rand.Read(token)\n\t\tif err != nil {\n\t\t\ttext.DefaultLogger.Error(err)\n\t\t}\n\t\ts.token = token\n\t}\n\n\treturn s\n}\n\n// RegisterDefaultCommands registers all default commands of the server.\nfunc (server *Server) RegisterDefaultCommands() {\n\tserver.CommandManager.RegisterCommand(NewStop(server))\n\tserver.CommandManager.RegisterCommand(NewList(server))\n\tserver.CommandManager.RegisterCommand(NewPing())\n\tserver.CommandManager.RegisterCommand(NewTest(server))\n}\n\n// IsRunning checks if the server is running.\nfunc (server *Server) IsRunning() bool {\n\treturn server.isRunning\n}\n\n// Start starts the server and loads levels, plugins, resource packs etc.\n// Start returns an error if one occurred during starting.\nfunc (server *Server) Start() error {\n\tif server.isRunning {\n\t\treturn AlreadyStarted\n\t}\n\ttext.DefaultLogger.Info(\"GoMine \"+GoMineVersion+\" is now starting...\", \"(\"+server.ServerPath+\")\")\n\n\tserver.LevelManager.SetDefaultLevel(worlds.NewLevel(\"world\", server.ServerPath))\n\tvar dimension = worlds.NewDimension(\"overworld\", server.LevelManager.GetDefaultLevel(), worlds.OverworldId)\n\tdimension.SetChunkProvider(providers.NewAnvil(server.ServerPath + \"worlds/world/overworld/region/\"))\n\tserver.LevelManager.GetDefaultLevel().SetDefaultDimension(dimension)\n\tdimension.SetGenerator(defaults.NewFlatGenerator())\n\n\tserver.RegisterDefaultCommands()\n\n\tserver.PackManager.LoadResourcePacks() // Behavior packs may depend on resource packs, so always load resource packs first.\n\tserver.PackManager.LoadBehaviorPacks()\n\n\tserver.PluginManager.LoadPlugins()\n\n\tserver.isRunning = true\n\treturn server.NetworkAdapter.GetRakLibManager().Start(server.Config.ServerIp, int(server.Config.ServerPort))\n}\n\n// Shutdown shuts down the server, saving and disabling everything.\nfunc (server *Server) Shutdown() {\n\tif !server.isRunning {\n\t\treturn\n\t}\n\ttext.DefaultLogger.Info(\"Server is shutting down.\")\n\n\ttext.DefaultLogger.Notice(\"Server stopped.\")\n\ttext.DefaultLogger.Wait()\n\n\tserver.isRunning = false\n}\n\n// GetMinecraftVersion returns the latest Minecraft game version.\n// It is prefixed with a 'v', for example: \"v1.2.10.1\"\nfunc (server *Server) GetMinecraftVersion() string {\n\treturn info.LatestGameVersion\n}\n\n// GetMinecraftNetworkVersion returns the latest Minecraft network version.\n// For example: \"1.2.10.1\"\nfunc (server *Server) GetMinecraftNetworkVersion() string {\n\treturn info.LatestGameVersionNetwork\n}\n\n// HasPermission returns if the server has a given permission.\n// Always returns true to satisfy the ICommandSender interface.\nfunc (server *Server) HasPermission(string) bool {\n\treturn true\n}\n\n// SendMessage sends a message to the server to satisfy the ICommandSender interface.\nfunc (server *Server) SendMessage(message ...interface{}) {\n\ttext.DefaultLogger.Notice(message)\n}\n\n// GetEngineName returns 'GoMine'.\nfunc (server *Server) GetEngineName() string {\n\treturn GoMineName\n}\n\n// GetName returns the LAN name of the server specified in the configuration.\nfunc (server *Server) GetName() string {\n\treturn server.Config.ServerName\n}\n\n// GetPort returns the port of the server specified in the configuration.\nfunc (server *Server) GetPort() uint16 {\n\treturn server.Config.ServerPort\n}\n\n// GetAddress returns the IP address specified in the configuration.\nfunc (server *Server) GetAddress() string {\n\treturn server.Config.ServerIp\n}\n\n// GetMaximumPlayers returns the maximum amount of players on the server.\nfunc (server *Server) GetMaximumPlayers() uint {\n\treturn server.Config.MaximumPlayers\n}\n\n// Returns the Message Of The Day of the server.\nfunc (server *Server) GetMotd() string {\n\treturn server.Config.ServerMotd\n}\n\n// Returns the max view distance allowed by the server\nfunc (server *Server) GetMaxViewDistance() int32 {\n\treturn server.Config.MaxViewDistance\n}\n\n// Returns the max view distance allowed by the server,\n// if it's 0 it returns the given distance which is the\n// distance given by a joining player\nfunc (server *Server) GetAllowedViewDistance(distance int32) int32 {\n\tvar maxViewDistance int32\n\tif maxViewDistance = server.GetMaxViewDistance(); maxViewDistance <= 0 {\n\t\treturn distance\n\t}\n\treturn maxViewDistance\n}\n\n// GetCurrentTick returns the current tick the server is on.\nfunc (server *Server) GetCurrentTick() int64 {\n\treturn server.tick\n}\n\n// BroadcastMessageTo broadcasts a message to all receivers.\nfunc (server *Server) BroadcastMessageTo(receivers []*net.MinecraftSession, message ...interface{}) {\n\tfor _, session := range receivers {\n\t\tsession.SendMessage(message)\n\t}\n\ttext.DefaultLogger.LogChat(message)\n}\n\n// Broadcast broadcasts a message to all players and the console in the server.\nfunc (server *Server) BroadcastMessage(message ...interface{}) {\n\tfor _, session := range server.SessionManager.GetSessions() {\n\t\tsession.SendMessage(message)\n\t}\n\ttext.DefaultLogger.LogChat(message)\n}\n\n// GetPrivateKey returns the ECDSA private key of the server.\nfunc (server *Server) GetPrivateKey() *ecdsa.PrivateKey {\n\treturn server.privateKey\n}\n\n// GetPublicKey returns the ECDSA public key of the private key of the server.\nfunc (server *Server) GetPublicKey() *ecdsa.PublicKey {\n\treturn &server.privateKey.PublicKey\n}\n\n// GetServerToken returns the server token byte sequence.\nfunc (server *Server) GetServerToken() []byte {\n\treturn server.token\n}\n\n// GenerateQueryResult returns the query data of the server in a byte array.\nfunc (server *Server) GenerateQueryResult() query.Result {\n\tvar plugs []string\n\tfor _, plug := range server.PluginManager.GetPlugins() {\n\t\tplugs = append(plugs, plug.GetName()+\" v\"+plug.GetVersion())\n\t}\n\n\tvar ps []string\n\tfor name := range server.SessionManager.GetSessions() {\n\t\tps = append(ps, name)\n\t}\n\n\tvar result = query.Result{\n\t\tMOTD:           server.GetMotd(),\n\t\tListPlugins:    server.Config.AllowPluginQuery,\n\t\tPluginNames:    plugs,\n\t\tPlayerNames:    ps,\n\t\tGameMode:       \"SMP\",\n\t\tVersion:        server.GetMinecraftVersion(),\n\t\tServerEngine:   server.GetEngineName(),\n\t\tWorldName:      server.LevelManager.GetDefaultLevel().GetName(),\n\t\tOnlinePlayers:  int(server.SessionManager.GetSessionCount()),\n\t\tMaximumPlayers: int(server.Config.MaximumPlayers),\n\t\tWhitelist:      \"off\",\n\t\tPort:           server.Config.ServerPort,\n\t\tAddress:        server.Config.ServerIp,\n\t}\n\n\treturn result\n}\n\n// HandleRaw handles a raw packet, for instance a query packet.\nfunc (server *Server) HandleRaw(packet []byte, addr *net2.UDPAddr) {\n\tif string(packet[0:2]) == string(query.Header) {\n\t\tif !server.Config.AllowQuery {\n\t\t\treturn\n\t\t}\n\n\t\tvar q = query.NewFromRaw(packet, addr)\n\t\tq.DecodeServer()\n\n\t\tserver.QueryManager.HandleQuery(q)\n\t\treturn\n\t}\n\ttext.DefaultLogger.Debug(\"Unhandled raw packet:\", hex.EncodeToString(packet))\n}\n\n// HandleDisconnect handles a disconnection from a session.\nfunc (server *Server) HandleDisconnect(s *server.Session) {\n\ttext.DefaultLogger.Debug(s, \"disconnected!\")\n\tsession, ok := server.SessionManager.GetSessionByRakNetSession(s)\n\tserver.SessionManager.RemoveMinecraftSession(session)\n\n\tif !ok {\n\t\treturn\n\t}\n\n\tif session.GetPlayer().Dimension != nil {\n\t\tfor _, online := range server.SessionManager.GetSessions() {\n\t\t\tonline.SendPlayerList(data.ListTypeRemove, map[string]protocol.PlayerListEntry{session.GetPlayer().GetName(): session.GetPlayer()})\n\t\t}\n\n\t\tsession.GetPlayer().Close()\n\t\tsession.Connected = false\n\n\t\tserver.BroadcastMessage(text.Yellow+session.GetDisplayName(), \"has left the server\")\n\t}\n}\n\n// GeneratePongData generates the GoRakLib pong data for the UnconnectedPong RakNet packet.\nfunc (server *Server) GeneratePongData() string {\n\treturn fmt.Sprint(\"MCPE;\", server.GetMotd(), \";\", info.LatestProtocol, \";\", server.GetMinecraftNetworkVersion(), \";\", server.SessionManager.GetSessionCount(), \";\", server.Config.MaximumPlayers, \";\", server.NetworkAdapter.GetRakLibManager().ServerId, \";\", server.GetEngineName(), \";Creative;\")\n}\n\n// Tick ticks the entire server. (Levels, scheduler, GoRakLib server etc.)\n// Internal. Not to be used by plugins.\nfunc (server *Server) Tick() {\n\tif !server.isRunning {\n\t\treturn\n\t}\n\tif server.tick%20 == 0 {\n\t\tserver.QueryManager.SetQueryResult(server.GenerateQueryResult())\n\t\tserver.NetworkAdapter.GetRakLibManager().PongData = server.GeneratePongData()\n\t}\n\n\tfor _, session := range server.SessionManager.GetSessions() {\n\t\tsession.Tick()\n\t}\n\n\tfor _, level := range server.LevelManager.GetLevels() {\n\t\tlevel.Tick()\n\t}\n\n\tserver.tick++\n}\n\nfunc (server *Server) attemptReadCommand(commandText string) {\n\targs := strings.Split(commandText, \" \")\n\tcommandName := args[0]\n\ti := 1\n\tfor !server.CommandManager.IsCommandRegistered(commandName) {\n\t\tif i == len(args) {\n\t\t\tbreak\n\t\t}\n\t\tcommandName += \" \" + args[i]\n\t\ti++\n\t}\n\tmanager := server.CommandManager\n\n\tif !manager.IsCommandRegistered(commandName) {\n\t\ttext.DefaultLogger.Error(\"Command could not be found.\")\n\t\treturn\n\t}\n\targs = args[i:]\n\n\tcommand, _ := manager.GetCommand(commandName)\n\tcommand.Execute(server, args)\n}\n"
  },
  {
    "path": "text/command_reader.go",
    "content": "package text\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"strings\"\n)\n\n// CommandReader implements command reading from io.Readers.\n// CommandReader continuously processes incoming commands,\n// and executes all associated functions with it.\ntype CommandReader struct {\n\t// reader is the bufio.Reader encapsulating the input reader.\n\treader *bufio.Reader\n\t// LineReadFunctions are all line read functions.\n\t// These functions get executed every time a line gets read.\n\tLineReadFunctions []func(line string)\n}\n\n// NewCommandReader returns a new CommandReader.\n// The input io.Reader is encapsulated by a bufio.Reader\n// and further used to continuously read from.\nfunc NewCommandReader(inputReader io.Reader) *CommandReader {\n\treader := &CommandReader{bufio.NewReader(inputReader), []func(string){}}\n\tgo func() {\n\t\tfor {\n\t\t\treader.readLine()\n\t\t}\n\t}()\n\treturn reader\n}\n\n// AddReadFunc adds a new line read function to the command reader.\n// The function passed will get called with the line read as argument,\n// every time a command gets read from the input reader.\n// Example:\n// func(line string) { os.Stdout.Write([]byte(\"You wrote: \" + line)) }\nfunc (reader *CommandReader) AddReadFunc(outputFunc func(string)) {\n\treader.LineReadFunctions = append(reader.LineReadFunctions, outputFunc)\n}\n\n// readLine continuously reads lines from the input reader.\n// Every time a line gets read from the input reader,\n// all LineReadFunctions are executed with the line read.\nfunc (reader *CommandReader) readLine() {\n\tcommand, _ := reader.reader.ReadString('\\n')\n\tcommand = strings.Trim(command, \"\\n\")\n\tfor _, f := range reader.LineReadFunctions {\n\t\tf(command)\n\t}\n}\n"
  },
  {
    "path": "text/font.go",
    "content": "package text\n\nimport \"strings\"\n\nconst (\n\tAnsiPre   = \"\\u001b[\"\n\tAnsiReset = AnsiPre + \"0m\"\n\n\tAnsiBold       = AnsiPre + \"1m\"\n\tAnsiItalic     = AnsiPre + \"3m\"\n\tAnsiUnderlined = AnsiPre + \"4m\"\n\n\tAnsiBlack   = AnsiPre + \"30m\"\n\tAnsiRed     = AnsiPre + \"31m\"\n\tAnsiGreen   = AnsiPre + \"32m\"\n\tAnsiYellow  = AnsiPre + \"33m\"\n\tAnsiBlue    = AnsiPre + \"34m\"\n\tAnsiMagenta = AnsiPre + \"35m\"\n\tAnsiCyan    = AnsiPre + \"36m\"\n\tAnsiWhite   = AnsiPre + \"37m\"\n\tAnsiGray    = AnsiPre + \"30;1m\"\n\n\tAnsiBrightRed     = AnsiPre + \"31;1m\"\n\tAnsiBrightGreen   = AnsiPre + \"32;1m\"\n\tAnsiBrightYellow  = AnsiPre + \"33;1m\"\n\tAnsiBrightBlue    = AnsiPre + \"34;1m\"\n\tAnsiBrightMagenta = AnsiPre + \"35;1m\"\n\tAnsiBrightCyan    = AnsiPre + \"36;1m\"\n\tAnsiBrightWhite   = AnsiPre + \"37;1m\"\n)\n\nconst (\n\tPre = \"§\"\n\n\tBlack      = Pre + \"0\"\n\tBlue       = Pre + \"1\"\n\tGreen      = Pre + \"2\"\n\tCyan       = Pre + \"3\"\n\tRed        = Pre + \"4\"\n\tMagenta    = Pre + \"5\"\n\tOrange     = Pre + \"6\"\n\tBrightGray = Pre + \"7\"\n\tGray       = Pre + \"8\"\n\tBrightBlue = Pre + \"9\"\n\n\tBrightGreen   = Pre + \"a\"\n\tBrightCyan    = Pre + \"b\"\n\tBrightRed     = Pre + \"c\"\n\tBrightMagenta = Pre + \"d\"\n\tYellow        = Pre + \"e\"\n\tWhite         = Pre + \"f\"\n\n\tObfuscated    = Pre + \"k\"\n\tBold          = Pre + \"l\"\n\tStrikeThrough = Pre + \"m\"\n\tUnderlined    = Pre + \"n\"\n\tItalic        = Pre + \"o\"\n\n\tReset = Pre + \"r\"\n)\n\n// ColoredString is a string containing colours.\n// ColoredString has functions to manipulate the colours it holds.\ntype ColoredString string\n\n// colorConvert is used to convert Minecraft colours\n// to ANSI colours and the other way around.\nvar colorConvert = map[string]string{\n\tBlack:         AnsiBlack,\n\tBlue:          AnsiBlue,\n\tGreen:         AnsiGreen,\n\tCyan:          AnsiCyan,\n\tRed:           AnsiRed,\n\tMagenta:       AnsiMagenta,\n\tOrange:        AnsiYellow,\n\tBrightGray:    AnsiWhite,\n\tGray:          AnsiGray,\n\tBrightBlue:    AnsiBrightBlue,\n\tBrightGreen:   AnsiBrightGreen,\n\tBrightCyan:    AnsiBrightCyan,\n\tBrightRed:     AnsiBrightRed,\n\tBrightMagenta: AnsiBrightMagenta,\n\tYellow:        AnsiBrightYellow,\n\tWhite:         AnsiBrightWhite,\n\tBold:          AnsiBold,\n\tUnderlined:    AnsiUnderlined,\n\tItalic:        AnsiItalic,\n\tReset:         AnsiReset,\n\tStrikeThrough: AnsiUnderlined,\n\tObfuscated:    AnsiUnderlined,\n}\n\n// ToANSI converts all Minecraft colors in a ColoredString to ANSI colors.\n// A new string is returned with the colors converted.\nfunc (str ColoredString) ToANSI() string {\n\ttext := string(str)\n\tfor toConvert, convertValue := range colorConvert {\n\t\ttext = strings.Replace(text, toConvert, convertValue, -1)\n\t}\n\treturn text\n}\n\n// ToMinecraft converts all ANSI colors in a ColoredString to Minecraft colors.\n// A new string is returned with the colors converted.\nfunc (str ColoredString) ToMinecraft() string {\n\ttext := string(str)\n\tfor convertValue, toConvert := range colorConvert {\n\t\ttext = strings.Replace(text, toConvert, convertValue, -1)\n\t}\n\treturn text\n}\n\n// StripMinecraft strips all Minecraft colors in a ColoredString.\n// A new string is returned with the colors stripped.\nfunc (str ColoredString) StripMinecraft() string {\n\ttext := string(str)\n\tfor toConvert := range colorConvert {\n\t\ttext = strings.Replace(text, toConvert, \"\", -1)\n\t}\n\treturn text\n}\n\n// StripANSI strips all ANSI colors in a ColoredString.\n// A new string is returned with the colors stripped.\nfunc (str ColoredString) StripANSI() string {\n\ttext := string(str)\n\tfor _, toConvert := range colorConvert {\n\t\ttext = strings.Replace(text, toConvert, \"\", -1)\n\t}\n\treturn text\n}\n\n// StripAll strips all colors (both ANSI and MCPE) in a ColoredString.\n// A new string is returned with the colors stripped.\nfunc (str ColoredString) StripAll() string {\n\ttext := string(str)\n\tfor mcpeColor, ansiColor := range colorConvert {\n\t\ttext = strings.Replace(text, mcpeColor, \"\", -1)\n\t\ttext = strings.Replace(text, ansiColor, \"\", -1)\n\t}\n\treturn text\n}\n"
  },
  {
    "path": "text/logger.go",
    "content": "package text\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"runtime/debug\"\n\t\"strings\"\n)\n\nconst (\n\tDebug      = \"[Debug]\"\n\tInfo       = \"[Info]\"\n\tNotice     = \"[Notice]\"\n\tAlert      = \"[Alert]\"\n\tError      = \"[Error]\"\n\tWarning    = \"[Warning]\"\n\tCritical   = \"[Critical]\"\n\tChat       = \"[Chat]\"\n\tStackTrace = \"[Stack Trace]\"\n)\n\n// Logger is a helper for writing log information to multiple\n// locations at the same time on a different goroutine.\n// Each logger has a prefix, which all messages will be\n// prefixed with, and a debug mode, which if turned on will\n// write debug messages too.\ntype Logger struct {\n\t// Prefix is the prefix of the logger.\n\t// Every message is prefixed with this string.\n\t// The prefix is enclosed in brackets, as such: [Prefix]\n\tPrefix string\n\t// DebugMode is the debug mode of the logger.\n\t// If true, writes debug messages.\n\tDebugMode bool\n\t// OutputFunctions contains all logger output functions.\n\t// Every output function gets called once a message gets logged.\n\tOutputFunctions []func(message []byte)\n\t// MessageQueue is the queue of messages to the processed.\n\t// These messages will be continuously processed on a different goroutine.\n\tMessageQueue chan string\n\n\t// waiting and waitRelease are used to manage the waiting state of the logger.\n\t// Both are used to notify the logger for waiting.\n\twaiting     bool\n\twaitRelease chan bool\n}\n\n// DefaultLogger is the default GoMine logger.\n// It has the prefix `GoMine` and has debug turned off.\n// The default logger will write only to Stdout.\nvar DefaultLogger = NewLogger(\"GoMine\", false)\n\n// init initializes the output of the default logger.\n// It writes to Stdout by default.\nfunc init() {\n\tDefaultLogger.AddOutput(func(message []byte) {\n\t\tos.Stdout.Write(message)\n\t})\n}\n\n// NewLogger returns a new logger with the given prefix and debug mode.\n// Additional output functions can be added to the logger once an\n// instance has been created using this function.\n// The logger will be made to process immediately when creating a new logger.\nfunc NewLogger(prefix string, debugMode bool) *Logger {\n\tlogger := &Logger{prefix, debugMode, []func([]byte){}, make(chan string, 128), false, make(chan bool)}\n\tgo logger.process()\n\treturn logger\n}\n\n// AddOutput adds a new output function to the logger.\n// The function passed will get called with the message\n// provided as argument every time a message gets logged.\n// Example:\n// func(message []byte) { os.Stdout.Write(message) }\nfunc (logger *Logger) AddOutput(f func(message []byte)) {\n\tlogger.OutputFunctions = append(logger.OutputFunctions, f)\n}\n\n// Write writes a byte array to the logger.\n// All Minecraft colors are first replaced with ANSI colors.\n// after which they get added to the message queue.\n// The message will then get processed on a different goroutine.\nfunc (logger *Logger) Write(message []byte) {\n\tlogger.MessageQueue <- ColoredString(string(message)).ToANSI() + AnsiReset + \"\\n\"\n}\n\n// Write writes a string to the logger.\n// All Minecraft colors are first replaced with ANSI colors.\n// after which they get added to the message queue.\n// The message will then get processed on a different goroutine.\nfunc (logger *Logger) WriteString(message string) {\n\tlogger.MessageQueue <- ColoredString(message).ToANSI() + AnsiReset + \"\\n\"\n}\n\n// process continuously processes queued messages in the logger.\n// Messages get fetched from the queue as soon as they're added,\n// and will be ran through every output function.\nfunc (logger *Logger) process() {\n\tfor {\n\t\tif len(logger.MessageQueue) == 0 && logger.waiting {\n\t\t\tlogger.waitRelease <- true\n\t\t\treturn\n\t\t}\n\t\tmessage := \"[\" + logger.Prefix + \"] \" + <-logger.MessageQueue\n\t\tfor _, f := range logger.OutputFunctions {\n\t\t\tf([]byte(message))\n\t\t}\n\t}\n}\n\n// Wait waits until the logger is done logging all messages\n// currently in the message queue. The current goroutine will be\n// blocked until the logger is done processing all messages,\n// and the writing goroutine will be stopped.\n// After waiting, the writing process gets restarted.\nfunc (logger *Logger) Wait() {\n\tlogger.waiting = true\n\t<-logger.waitRelease\n\tlogger.waiting = false\n\tgo logger.process()\n}\n\n// Notice logs a notice message.\nfunc (logger *Logger) Notice(messages ...interface{}) {\n\tlogger.WriteString(Yellow + Notice + \" \" + strings.Trim(fmt.Sprint(messages), \"[]\"))\n}\n\n// Debug logs a debug message.\nfunc (logger *Logger) Debug(messages ...interface{}) {\n\tlogger.WriteString(Orange + Debug + \" \" + strings.Trim(fmt.Sprint(messages), \"[]\"))\n}\n\n// Info logs an info message.\nfunc (logger *Logger) Info(messages ...interface{}) {\n\tlogger.WriteString(BrightCyan + Info + \" \" + strings.Trim(fmt.Sprint(messages), \"[]\"))\n}\n\n// Alert logs an alert.\nfunc (logger *Logger) Alert(messages ...interface{}) {\n\tlogger.WriteString(BrightRed + Alert + \" \" + strings.Trim(fmt.Sprint(messages), \"[]\"))\n}\n\n// Warning logs a warning message.\nfunc (logger *Logger) Warning(messages ...interface{}) {\n\tlogger.WriteString(BrightRed + Bold + Warning + \" \" + strings.Trim(fmt.Sprint(messages), \"[]\"))\n}\n\n// Critical logs a critical warning message.\nfunc (logger *Logger) Critical(messages ...interface{}) {\n\tlogger.WriteString(BrightRed + Underlined + Bold + Critical + \" \" + strings.Trim(fmt.Sprint(messages), \"[]\"))\n}\n\n// Error logs an error message.\nfunc (logger *Logger) Error(messages ...interface{}) {\n\tlogger.WriteString(Red + Error + \" \" + strings.Trim(fmt.Sprint(messages), \"[]\"))\n}\n\n// LogChat logs a chat message to the logger.\nfunc (logger *Logger) LogChat(messages ...interface{}) {\n\tlogger.WriteString(BrightCyan + Chat + \" \" + strings.Trim(fmt.Sprint(messages), \"[]\"))\n}\n\n// LogStack logs the stack trace.\nfunc (logger *Logger) LogStack() {\n\tlogger.WriteString(Yellow + StackTrace + \" \" + string(debug.Stack()))\n}\n\n// LogError logs an actual error to the logger.\n// A nil error may also be passed,\n// which the logger will completely ignore.\nfunc (logger *Logger) LogError(err error) {\n\tif err == nil {\n\t\treturn\n\t}\n\tlogger.Error(err.Error())\n}\n"
  },
  {
    "path": "text/logger_test.go",
    "content": "package text\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"testing\"\n)\n\nfunc TestLogger(t *testing.T) {\n\tlogger := NewLogger(\"Test Logger\", true)\n\tlogger.AddOutput(func(message []byte) {\n\t\tos.Stdout.Write(message)\n\t})\n\tlogger.WriteString(\"Raw message\")\n\tlogger.Info(\"Logger working.\")\n\tlogger.Debug(\"Debug message.\", \"another debug\")\n\tvar err error\n\tlogger.LogError(err) // err is nil, does not print anything.\n\terr = errors.New(\"error\")\n\tlogger.LogError(err)\n\tlogger.LogStack()\n\n\tlogger.Wait()\n}\n\nfunc TestDefault(t *testing.T) {\n\tDefaultLogger.Debug(\"Debug message\")\n\tDefaultLogger.Notice(\"Notice message\")\n\tDefaultLogger.LogStack()\n\tDefaultLogger.Wait()\n}\n\nfunc TestMultipleWait(t *testing.T) {\n\tlogger := NewLogger(\"Test Logger\", true)\n\tlogger.AddOutput(func(message []byte) {\n\t\tos.Stdout.Write(message)\n\t})\n\tlogger.LogStack()\n\tlogger.Wait()\n\tlogger.LogStack()\n\tlogger.Wait()\n}\n"
  },
  {
    "path": "utils/encryption.go",
    "content": "package utils\n\nimport (\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/ecdsa\"\n\t\"crypto/sha256\"\n\t\"github.com/irmine/binutils\"\n)\n\ntype EncryptionData struct {\n\tClientPublicKey       *ecdsa.PublicKey\n\tServerPrivateKey      *ecdsa.PrivateKey\n\tServerToken           []byte\n\tSharedSecret          []byte\n\tDecryptSecretKeyBytes [32]byte\n\tEncryptSecretKeyBytes [32]byte\n\n\tDecryptIV     []byte\n\tEncryptIV     []byte\n\tDecryptCipher cipher.Block\n\tEncryptCipher cipher.Block\n\n\tSendCounter int64\n}\n\nfunc (data *EncryptionData) ComputeSharedSecret() {\n\tvar x, _ = data.ClientPublicKey.Curve.ScalarMult(data.ClientPublicKey.X, data.ClientPublicKey.Y, data.ServerPrivateKey.D.Bytes())\n\tdata.SharedSecret = x.Bytes()\n}\n\nfunc (data *EncryptionData) ComputeSecretKeyBytes() {\n\tvar secret = sha256.Sum256(append(data.ServerToken, data.SharedSecret...))\n\tdata.DecryptSecretKeyBytes = secret\n\tdata.EncryptSecretKeyBytes = secret\n\n\tdata.DecryptCipher, _ = aes.NewCipher(data.DecryptSecretKeyBytes[:])\n\tdata.EncryptCipher, _ = aes.NewCipher(data.EncryptSecretKeyBytes[:])\n\n\tdata.DecryptIV = data.DecryptSecretKeyBytes[:aes.BlockSize]\n\tdata.EncryptIV = data.DecryptSecretKeyBytes[:aes.BlockSize]\n}\n\ntype EncryptionHandler struct {\n\tData *EncryptionData\n}\n\nfunc NewEncryptionHandler() *EncryptionHandler {\n\treturn &EncryptionHandler{&EncryptionData{}}\n}\n\nfunc (handler *EncryptionHandler) ComputeSendChecksum(d []byte) []byte {\n\tvar buffer []byte\n\tvar secret = handler.Data.EncryptSecretKeyBytes[:]\n\n\tbinutils.WriteLittleLong(&buffer, handler.Data.SendCounter)\n\thandler.Data.SendCounter++\n\n\tvar hash = sha256.New()\n\thash.Write(buffer)\n\thash.Write(d)\n\thash.Write(secret)\n\n\tvar sum = hash.Sum(nil)\n\treturn sum[:8]\n}\n"
  },
  {
    "path": "utils/utils.go",
    "content": "package utils\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/rand\"\n\t\"crypto/sha512\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype EncryptionHeader struct {\n\tAlgorithm string `json:\"alg\"`\n\tX5u       string `json:\"x5u\"`\n}\n\ntype EncryptionPayload struct {\n\tToken string `json:\"salt\"`\n}\n\nfunc DecodeJwtPayload(v string, t interface{}) {\n\tv = strings.Split(v, \".\")[1]\n\tstr, err := base64.RawURLEncoding.DecodeString(v)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\tjson.Unmarshal(str, t)\n}\n\nfunc DecodeJwt(v string) []string {\n\tvar splits = strings.Split(v, \".\")\n\tvar jwt []string\n\tfor _, split := range splits {\n\t\tstr, err := base64.RawURLEncoding.DecodeString(split)\n\n\t\tif err != nil {\n\t\t\tfmt.Println(err)\n\t\t\tcontinue\n\t\t}\n\n\t\tjwt = append(jwt, string(str))\n\t}\n\treturn jwt\n}\n\nfunc ConstructEncryptionJwt(key *ecdsa.PrivateKey, token []byte) string {\n\tvar header = EncryptionHeader{}\n\theader.Algorithm = \"ES384\"\n\tvar b, _ = x509.MarshalPKIXPublicKey(&key.PublicKey)\n\n\theader.X5u = base64.RawStdEncoding.EncodeToString(b)\n\n\tvar payload = EncryptionPayload{}\n\tpayload.Token = base64.RawStdEncoding.EncodeToString(token)\n\n\tvar headerData, _ = json.Marshal(header)\n\tvar headerStr = base64.RawURLEncoding.EncodeToString(headerData)\n\tvar payloadData, _ = json.Marshal(payload)\n\tvar payloadStr = base64.RawURLEncoding.EncodeToString(payloadData)\n\n\tvar hash = sha512.New384()\n\thash.Write([]byte(headerStr + \".\" + payloadStr))\n\n\tvar r, s, err = ecdsa.Sign(rand.Reader, key, hash.Sum(nil))\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\tvar signature = base64.RawURLEncoding.EncodeToString(append(r.Bytes(), s.Bytes()...))\n\n\treturn headerStr + \".\" + payloadStr + \".\" + signature\n}\n"
  }
]