[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs     diff=csharp\n\n# Standard to msysgit\n*.doc\t diff=astextplain\n*.DOC\t diff=astextplain\n*.docx diff=astextplain\n*.DOCX diff=astextplain\n*.dot  diff=astextplain\n*.DOT  diff=astextplain\n*.pdf  diff=astextplain\n*.PDF\t diff=astextplain\n*.rtf\t diff=astextplain\n*.RTF\t diff=astextplain\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# PiggyCustomEnchants\n\n## Contribution Guidelines\n\n### Issues\nIf you are submitting an issue ticket, you must:\n* Must be PMMP w/o vanilla patching plugins (i.e. TeaSpoon)\n* Issue must have not been reported previously\n* Must be on latest version of PMMP & PiggyCustomEnchants\n* Have a detailed title.\n* If possible, provide crashdumps/errors related to the issue.\n\n### Pull Requests\nIf you are submitting a pull request, you must:\n* Use same formatting\n* Changes must have been tested on PMMP.\n* Unless it is a minor code modification, you must use an IDE.\n* Have a detailed title, like \"Fix Poison enchant does not apply effect\"\n\n<i>Last updated: Sunday, March 15, 2020.</i>"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug Report\nabout: Unexpected non-crash behavior with PiggyCustomEnchants\ntitle: ''\nlabels: 'Type: Bug'\nassignees: 'DaPigGuy'\n---\n\n<!-- Failure to complete the required fields will result in the issue being closed. -->\nPlease make sure your issue complies with these guidelines:\n- * [ ] Server Software must be the official PMMP w/o vanilla patching plugins (i.e. TeaSpoon)\n- * [ ] Issue must have not been reported previously\n- * [ ] Make sure you are on the latest version of PMMP & PiggyCustomEnchants\n- * [ ] Have a detailed title.\n\n### Issue Description\n\n- Expected result: What were you expecting to happen?\n- Actual result: What actually happened?\n\n#### Steps to Reproduce the Issue\n1. ...\n2. ...\n\n### OS and Versions\n<!-- Use `/version` for PMMP version & `/version PiggyCustomEnchants` for PiggyCustomEnchants version -->\n* PocketMine-MP:\n* PiggyCustomEnchants:\n* PHP:\n* Server OS:\n\n<!--- Provide any extra information below  -->\n### Extra Information"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/crash.md",
    "content": "---\nname: Crash\nabout: Report a crash in PiggyCustomEnchants\ntitle: ''\nlabels: 'Type: Bug'\nassignees: 'DaPigGuy'\n---\n\n<!-- Failure to complete the required fields will result in the issue being closed. -->\n\nPlease make sure your issue complies with these guidelines:\n- * [ ] Server Software must be the official PMMP w/o vanilla patching plugins (i.e. TeaSpoon)\n- * [ ] Issue must have not been reported previously\n- * [ ] Make sure you are on the latest version of PMMP & PiggyCustomEnchants\n- * [ ] Have a detailed title.\n\n<!--- Submit crash dumps to https://crash.pmmp.io or copy & paste contents to https://hastebin.com -->\nLink to crashdump: \n\n<!--- Provide any extra information below  -->\n### Extra Information"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/outdated_api.md",
    "content": "---\nname: Outdated API Version\nabout: Please do not create an issue for this. The plugin will be updated to the latest PMMP version as soon as possible.\ntitle: 'Outdated API Version'\nlabels: 'Resolution: Invalid'\nassignees: ''\n---\n\nPlease do not create an issue. Doing so will only delay an update."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/suggestion.md",
    "content": "---\nname: Feature Suggestion\nabout: Suggest features you would like added to PiggyCustomEnchants\ntitle: ''\nlabels: 'Type: Enhancement'\nassignees: 'DaPigGuy'\n---\n\n<!-- Failure to complete the required fields will result in the issue being closed. -->\nPlease make sure your issue complies with these guidelines:\n- * [ ] Idea must have not been suggested previously\n- * [ ] Be detailed on what you want & make sure the idea is plausible\n\n### Description\n<!-- Describe your idea in detail below -->\n\n### Extra Information"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/support.md",
    "content": "---\nname: Support\nabout: Please do not create an issue for this. Join our Discord for support (link in README).\ntitle: ''\nlabels: 'Resolution: Invalid'\nassignees: ''\n---\n\nPlease do not create an issue for this. Join our Discord for support (link in README)."
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!-- Failure to complete the required fields will result in the issue being closed. -->\nPlease make sure your pull request complies with these guidelines:\n- * [ ] Use same formatting\n- * [ ] Changes must have been tested on PMMP.\n- * [ ] Unless it is a minor code modification, you must use an IDE.\n- * [ ] Have a detailed title.\n\n#### **What does the PR change?**\n<!-- \nDoes your Pull Request:\n- resolve a bug? If so, link the issue with the PR and add explain what caused the issue.\n- enhance the plugin? If so, explain what this adds, including why it should be added.\n-->\n\n#### **Testing Environment**\n<!-- PHP and OS version required, pmmp build link required. -->\n- PHP: \n- PMMP:\n- OS:\n\n#### **Extra Information**\n<!-- Anything else we should know? -->\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: PHPStan\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n\njobs:\n  phpstan:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          ref: ${{ github.ref }}\n      - name: Create Vendor Directory\n        run: mkdir vendor\n      - name: Download Virion Dependencies\n        run: |\n          wget -O vendor/libFormAPI.phar https://poggit.pmmp.io/r/207248/libFormAPI_dev-4.phar\n          wget -O vendor/Commando.phar https://poggit.pmmp.io/r/162923/Commando_dev-30.phar\n          wget -O vendor/libPiggyUpdateChecker.phar https://poggit.pmmp.io/r/163495/libPiggyUpdateChecker_dev-1.phar\n      - name: Run PHPStan\n        uses: paroxity/pmmp-phpstan-action@4.21.0\n        with:\n          phpstan-config: phpstan.neon.dist\n"
  },
  {
    "path": ".gitignore",
    "content": "# Windows image file caches\nThumbs.db\nehthumbs.db\n\n# Folder config file\nDesktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n# JetBrains IDE\n\\.idea\n\\.dependencies"
  },
  {
    "path": ".poggit.yml",
    "content": "--- # Poggit-CI Manifest. Open the CI at https://poggit.pmmp.io/ci/DaPigGuy/PiggyCustomEnchants\nbranches:\n  - master\n  - pmmp-4.0.0\nprojects:\n  PiggyCustomEnchants:\n    path: \"\"\n    icon: \"resources/PCE_Icon.png\"\n    libs:\n      - src: jojoe77777/FormAPI/libFormAPI\n        version: ^2.1.1\n      - src: Paroxity/Commando/Commando\n        version: ^3.0.0\n      - src: DaPigGuy/libPiggyUpdateChecker/libPiggyUpdateChecker\n        version: ^1.0.0\n    lint: false\n..."
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2017 DaPigGuy\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# PiggyCustomEnchants [![Poggit-CI](https://poggit.pmmp.io/shield.dl/PiggyCustomEnchants)](https://poggit.pmmp.io/p/PiggyCustomEnchants) [![Discord](https://img.shields.io/discord/330850307607363585?logo=discord)](https://discord.gg/qmnDsSD)\n\nPiggyCustomEnchants is an open-sourced custom enchants plugin for [PocketMine-MP](https://github.com/pmmp/PocketMine-MP) featuring over 90 custom enchantments.\n\n<!-- If one question constantly persists, add the Q/A in here. -->\n## FAQ\n**Q:** How do I create/use an enchanted book? </br>\n**A:** If you want to create an enchanted book, use the /ce enchant command on a normal book. Afterwards, you place the item you want to enchant on top of the enchanted book. It will then enchant your item.\n\n## Prerequisites\n* Basic knowledge on how to install plugins from Poggit Releases and/or Poggit CI\n* PMMP 4.21.0+\n\n## Installation & Setup\n1. Install the plugin from Poggit.\n2. (Optional) Configure your PiggyCE\n   * Enchantment rarities, max levels, names, descriptions, & chances can be configured in their respective JSON files.\n        * `chances.json`: Allows custom chance multipliers for any reactive enchantments.\n            * Reaction chances are calculated by `chance multiplier * enchantment level`.\n            * The chance multiplier by default is 100 for most enchantments.\n   * Extra enchantment settings can be found under `extra_data.json`\n   * The `config.yml` has many options. Some that you should pay attention to are:\n     * `disabled-enchants`: Allows certain enchants to be disabled\n     \n         ```yaml\n            disabled-enchants:\n              - Porkified\n         ```\n     * `per-world-disabled-enchants`: Allows certain enchants to be disabled in specific worlds\n     \n         ```yaml\n            per-world-disabled-enchants:\n              # Disables Porkified & Volley in PlotWorld\n              PlotWorld:\n                - Porkified\n                - Volley\n              # Disables Jetpack in SurvivalWorld\n              SurvivalWorld:\n                - Jetpack\n         ```\n     * `world-damage`: Toggles world damage for explosive enchantments\n3. (Optional) Install additional plugins supporting PiggyCE:\n   * [PiggyCrates](https://poggit.pmmp.io/p/PiggyCrates) (Official)\n   * [PiggyCustomEnchantsShop](https://poggit.pmmp.io/p/PiggyCustomEnchantsShop) (Official)\n   * [PCEAllyChecks](https://poggit.pmmp.io/p/PCEAllyChecks) (Official)\n   * [PCEBookShop](https://poggit.pmmp.io/p/PCEBookShop) (Official)\n   * Kits\n      * [EasyKits](https://poggit.pmmp.io/p/EasyKits)\n      * [AdvancedKits](https://poggit.pmmp.io/p/AdvancedKits) \n      * [KitUI](https://poggit.pmmp.io/p/KitUI)\n      * [KitsPlus](https://poggit.pmmp.io/p/KitsPlus)\n   * [EnchantUI](https://poggit.pmmp.io/p/EnchantUI)\n5. You're done! Start your server.\n\n## Commands\n| Command                  | Description                                     | Permissions                              | Aliases       |\n|--------------------------|-------------------------------------------------|------------------------------------------|---------------|\n| `/customenchant`         | Main command for PiggyCustomEnchants            | `piggycustomenchants.command.ce`         | `/ce`         |\n| `/customenchant about`   | Shows version and author information            | `piggycustomenchants.command.ce.about`   | `/ce about`   |\n| `/customenchant enchant` | Command to enchant an item with custom enchants | `piggycustomenchants.command.ce.enchant` | `/ce enchant` |\n| `/customenchant help`    | Lists all PiggyCustomEnchant commands           | `piggycustomenchants.command.ce.help`    | `/ce help`    |\n| `/customenchant info`    | Gives information on a custom enchant           | `piggycustomenchants.command.ce.info`    | `/ce info`    |\n| `/customenchant list`    | Lists all PiggyCustomEnchants enchants          | `piggycustomenchants.command.ce.list`    | `/ce list`    |\n| `/customenchant nbt`     | Outputs the NBT of the held item                | `piggycustomenchants.command.ce.nbt`     | `/ce nbt`     |\n| `/customenchant remove`  | Removes a custom enchant from the held item     | `piggycustomenchants.command.ce.remove`  | `/ce remove`  |\n\n## Permissions\n| Permissions                              | Description                                                         | Default |\n|------------------------------------------|---------------------------------------------------------------------|---------|\n| `piggycustomenchants`                    | Allows usage of all PiggyCustomEnchants features                    | `op`    |\n| `piggycustomenchants.command`            | Allow usage of all PiggyCustomEnchants commands                     | `op`    |\n| `piggycustomenchants.command.ce`         | Allow usage of the /customenchant command                           | `op`    |\n| `piggycustomenchants.command.ce.about`   | Allow usage of the /customenchant about subcommand                  | `true`  |\n| `piggycustomenchants.command.ce.enchant` | Allow usage of the /customenchant enchant subcommand                | `op`    |\n| `piggycustomenchants.command.ce.help`    | Allow usage of the /customenchant help subcommand                   | `true`  |\n| `piggycustomenchants.command.ce.info`    | Allow usage of the /customenchant info subcommand                   | `true`  |\n| `piggycustomenchants.command.ce.list`    | Allow usage of the /customenchant list subcommand                   | `true`  |\n| `piggycustomenchants.command.ce.nbt`     | Allow usage of the /customenchant nbt subcommand                    | `true`  |\n| `piggycustomenchants.command.ce.remove`  | Allow usage of the /customenchant remove subcommand                 | `op`    |\n| `piggycustomenchants.overridecheck`      | Allow overriding of custom enchant level limit and item restriction | `false` |\n\n## Issue Reporting\n* If you experience an unexpected non-crash behavior with PiggyCustomEnchants, click [here](https://github.com/DaPigGuy/PiggyCustomEnchants/issues/new?assignees=DaPigGuy&labels=bug&template=bug_report.md&title=).\n* If you experience a crash in PiggyCustomEnchants, click [here](https://github.com/DaPigGuy/PiggyCustomEnchants/issues/new?assignees=DaPigGuy&labels=bug&template=crash.md&title=).\n* If you would like to suggest a feature to be added to PiggyCustomEnchants, click [here](https://github.com/DaPigGuy/PiggyCustomEnchants/issues/new?assignees=DaPigGuy&labels=suggestion&template=suggestion.md&title=).\n* If you require support, please join our discord server [here](https://discord.gg/qmnDsSD).\n* Do not file any issues related to outdated API version; we will resolve such issues as soon as possible.\n* We do not support any spoons of PocketMine-MP. Anything to do with spoons (Issues or PRs) will be ignored.\n  * This includes plugins that modify PocketMine-MP's behavior directly, such as TeaSpoon.\n\n## Additional Information\n* Detailed Plugin Setup, Custom Enchantment List, & API Documentation available at [PiggyDocs](https://piggydocs.aericio.net/PiggyCustomEnchants.html).\n\n## License\n```\n   Copyright 2017 DaPigGuy\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n```\n"
  },
  {
    "path": "phpstan.neon.dist",
    "content": "parameters:\n  paths:\n    - /source/src\n  level: 7\n  bootstrapFiles:\n    - phar:///pocketmine/PocketMine-MP.phar/vendor/autoload.php\n  scanDirectories:\n    - phar:///source/vendor/libFormAPI.phar/src/\n    - phar:///source/vendor/Commando.phar/src/\n    - phar:///source/vendor/libPiggyUpdateChecker.phar/src/\n  excludePaths:\n    analyse:\n      - source/vendor\n  checkMissingIterableValueType: false\n  ignoreErrors:\n    - \"#Strict comparison using === between pocketmine\\\\\\\\inventory\\\\\\\\PlayerInventory and null will always evaluate to false.#\""
  },
  {
    "path": "plugin.yml",
    "content": "name: PiggyCustomEnchants\nmain: DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants\nversion: 3.0.12\napi: 4.21.0\nload: POSTWORLD\nauthor: DaPigGuy\nwebsite: \"https://github.com/DaPigGuy/PiggyCustomEnchants/\"\npermissions:\n  piggycustomenchants:\n    default: false\n    description: \"Allows usage of all PiggyCustomEnchants features\"\n  piggycustomenchants.command:\n    default: op\n    description: \"Allow usage of all PiggyCustomEnchants commands\"\n  piggycustomenchants.command.ce:\n    default: op\n    description: \"Allow usage of the /customenchant command\"\n  piggycustomenchants.command.ce.about:\n    default: true\n    description: \"Allow usage of the /customenchant about subcommand\"\n  piggycustomenchants.command.ce.enchant:\n    default: op\n    description: \"Allow usage of the /customenchant enchant subcommand\"\n  piggycustomenchants.command.ce.help:\n    default: true\n    description: \"Allow usage of the /customenchant help subcommand\"\n  piggycustomenchants.command.ce.info:\n    default: true\n    description: \"Allow usage of the /customenchant info subcommand\"\n  piggycustomenchants.command.ce.list:\n    default: true\n    description: \"Allow usage of the /customenchant list subcommand\"\n  piggycustomenchants.command.ce.nbt:\n    default: true\n    description: \"Allow usage of the /customenchant nbt subcommand\"\n  piggycustomenchants.command.ce.remove:\n    default: op\n    description: \"Allow usage of the /customenchant remove subcommand\"\n  piggycustomenchants.overridecheck:\n    default: false\n    description: \"Allow overriding of custom enchant level limit and item restriction\"\n"
  },
  {
    "path": "resources/chances.json",
    "content": "{\n  \"blessed\": 15,\n  \"deepwounds\": 20,\n  \"disarmor\": 10,\n  \"disarming\": 10,\n  \"hallucination\": 5,\n  \"jackpot\": 10,\n  \"lightning\": 10\n}"
  },
  {
    "path": "resources/config.yml",
    "content": "# Specifies the color enchants are shown depending on rarity\n# Options: black, dark_blue, dark_green, dark_aqua, dark_red, dark_purple, gold, gray, dark_gray, blue, green, aqua, red, light_purple, yellow, and white\nrarity-colors:\n  common: yellow\n  uncommon: blue\n  rare: gold\n  mythic: light_purple\nenchants:\n  # Specifies the location enchants are shown. Options: name, lore\n  position: \"name\"\n  # Toggles roman numerals for displaying enchantment levels\n  roman-numerals: true\n  # Toggles PiggyCE enchantment books\n  books: true\n# Toggles forms for /ce command\nforms:\n  enabled: false\n# What enchants to disable ENTIRELY\ndisabled-enchants: []\n# What enchants to disable in specific worlds\nper-world-disabled-enchants:\n  NoJetpackWorld:\n    - \"jetpack\"\n# If enabled, will check a list of extremely problematic enchantments on your version of the plugin to be disabled\n# We will ONLY remotely disable enchantments that are extremely problematic / major exploits and this functionality will not be abused in any way\n# Please update your plugin to the latest version (if available) if an enchantment on your version was disabled\n# Gist: https://gist.github.com/DaPigGuy/9c65a998bc0aa8d6b4708796110f7d11\nremote-disable: true\n# Whether or not an enchant damages world\nworld-damage:\n  blaze: true\n  bombardment: true\n  lightning: true\n  missile: true\n  self-destruct: true"
  },
  {
    "path": "resources/descriptions.json",
    "content": "{\n  \"antiknockback\": \"Reduces knockback per armor piece.\",\n  \"antitoxin\": \"Grants immunity to poison.\",\n  \"aerial\": \"While in air, damage increases.\",\n  \"armored\": \"Sword-inflicted damage is reduced.\",\n  \"autoaim\": \"Automatically aims to the nearest target.\",\n  \"autorepair\": \"Items automatically repair while moving.\",\n  \"backstab\": \"Backstabbing enemies deals increased damage.\",\n  \"berserker\": \"Gain strength when low on health.\",\n  \"blessed\": \"Grants a chance to remove harmful effects during combat.\",\n  \"blaze\": \"Shoots blazing fireballs.\",\n  \"blind\": \"Inflicts Blindness upon hitting enemies.\",\n  \"bombardment\": \"Bombard enemies with TNT when shot.\",\n  \"bountyhunter\": \"Grants chance to obtain treasure from hitting enemies.\",\n  \"cactus\": \"Deal damage to nearby enemies.\",\n  \"charge\": \"Damage increases while sprinting.\",\n  \"chicken\": \"Lay eggs every 5 minutes with a chance of rare drop.\",\n  \"cloaking\": \"Gain invisibility when hit.\",\n  \"cripple\": \"Inflicts Nausea and Slowness upon hitting enemy.\",\n  \"cursed\": \"Inflicts Wither upon hitting enemy.\",\n  \"deathbringer\": \"Increases damage inflicted.\",\n  \"deepwounds\": \"Inflict on enemies deep wounds that cause bleeding.\",\n  \"disarming\": \"Grants chance to disarm enemy.\",\n  \"disarmor\": \"Grants chance to disarmor enemy.\",\n  \"driller\": \"Drills a 3 by 3 hole.\",\n  \"drunk\": \"Inflicts Slowness, Mining Fatigue, and Nausea upon hitting enemy.\",\n  \"endershift\": \"Gain Speed and Absorption when low on health.\",\n  \"energizing\": \"Gain Haste when a block is broken.\",\n  \"enlighted\": \"Gain Regeneration when hit.\",\n  \"enraged\": \"Gain Strength while equipped.\",\n  \"explosive\": \"Causes an explosion when a block is broken.\",\n  \"farmer\": \"Automatically replaces seeds when crop is broken.\",\n  \"fertilizer\": \"Tills land in a radius dependent on enchantment level.\",\n  \"focused\": \"Negates or reduces the effects of nausea.\",\n  \"forcefield\": \"Deflects projectiles and living entities in a radius dependent on enchantment level.\",\n  \"frozen\": \"Inflicts Slowness upon hitting enemy.\",\n  \"gears\": \"Gain Speed while equipped.\",\n  \"glowing\": \"Gain Night Vision while equipped.\",\n  \"gooey\": \"Flings enemy into the air.\",\n  \"grappling\": \"Pulls you to the arrow. If enemy is hit, the enemy will be pulled to you.\",\n  \"grow\": \"Increases size on sneak (Must be wearing full set of Grow armor).\",\n  \"hallucination\": \"Grants chance of trapping enemies in a fake prison.\",\n  \"hardened\": \"Inflicts Weakness upon hitting enemy.\",\n  \"haste\": \"Gain Haste while tool is held.\",\n  \"harvest\": \"Harvest crops in a radius dependent on enchantment level.\",\n  \"headhunter\": \"Headshots deal more damage.\",\n  \"healing\": \"Heals target for inflicted damage + extra health.\",\n  \"heavy\": \"Bow-inflicted damage is reduced.\",\n  \"homing\": \"Arrow will home in on the nearest entity.\",\n  \"implants\": \"Replenishes hunger and air when moving.\",\n  \"jetpack\": \"Flies in the direction you are facing when you sneak.\",\n  \"jackpot\": \"Grants chance to increase ore tier.\",\n  \"lifesteal\": \"Steals health upon hitting enemy.\",\n  \"lightning\": \"Chance to strike enemies with lightning.\",\n  \"luckycharm\": \"Increases activation chance of reactive enchantments.\",\n  \"lumberjack\": \"Breaks all logs connected to each other.\",\n  \"magmawalker\": \"Temporarily turns lava into obsidian around you.\",\n  \"meditation\": \"Replenishes health and hunger every 20 seconds when not moving.\",\n  \"missile\": \"Spawns TNT where arrow lands.\",\n  \"molotov\": \"Starts a fire where arrow lands.\",\n  \"molten\": \"Sets an enemy on fire when hit.\",\n  \"obsidianshield\": \"Gain Fire Resistance while equipped.\",\n  \"overload\": \"Gives extra health (stackable).\",\n  \"oxygenate\": \"Gain Water Breathing while item is held.\",\n  \"parachute\": \"Slows your descent above 3 blocks.\",\n  \"paralyze\": \"Inflicts Slowness, Blindness, and Weakness upon hitting enemies.\",\n  \"piercing\": \"Ignores armor when dealing damage.\",\n  \"poison\": \"Inflicts Poison upon hitting enemies.\",\n  \"poisonouscloud\": \"Creates a cloud of poison around entity, giving poison to anyone who enters.\",\n  \"poisoned\": \"Inflicts Poison when hit by an enemy.\",\n  \"porkified\": \"Oink! Shoots pigs, leaving a mysterious pork behind when killed.\",\n  \"prowl\": \"Gain Invisibility and Slowness while sneaking.\",\n  \"quickening\": \"Gain Speed for upon breaking block.\",\n  \"radar\": \"Points towards the nearest player.\",\n  \"revive\": \"Gain another life, but removes a level from armor.\",\n  \"revulsion\": \"Inflicts Nausea for when hit by an enemy.\",\n  \"selfdestruct\": \"Spawns TNT when you die.\",\n  \"shielded\": \"Gives Resistance while worn (stackable).\",\n  \"shrink\": \"Decreases size on sneak (Must be wearing full set of Shrink armor).\",\n  \"shuffle\": \"Switches position with target.\",\n  \"smelting\": \"Automatically smelts drop when block is broken.\",\n  \"soulbound\": \"Keeps item after death, but removes a level from armor.\",\n  \"spider\": \"Ability to climb walls.\",\n  \"springs\": \"Gain a small jump boost.\",\n  \"stomp\": \"Deal damage to enemy when taking fall damage.\",\n  \"tank\": \"Decreases damage from axes.\",\n  \"telepathy\": \"Automatically puts drops into inventory.\",\n  \"vacuum\": \"Suck up nearby items.\",\n  \"vampire\": \"Converts damage dealt into health.\",\n  \"volley\": \"Shoots multiple arrows in a cone shape.\",\n  \"wither\": \"Inflicts Wither on enemies.\",\n  \"witherskull\": \"Shoots wither skulls.\"\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/CustomEnchantManager.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\AntiKnockbackEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\ArmoredEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\AttackerDeterrentEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\BerserkerEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\boots\\JetpackEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\boots\\MagmaWalkerEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\boots\\StompEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\CactusEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\chestplate\\ChickenEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\chestplate\\ParachuteEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\chestplate\\ProwlEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\chestplate\\SpiderEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\chestplate\\VacuumEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\CloakingEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\EndershiftEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\EnlightedEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\ForcefieldEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\GrowEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\HeavyEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\helmet\\AntitoxinEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\helmet\\FocusedEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\helmet\\ImplantsEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\helmet\\MeditationEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\MoltenEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\OverloadEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\PoisonousCloudEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\ReviveEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\SelfDestructEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\ShieldedEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\ShrinkEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\TankEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous\\AutoRepairEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous\\LuckyCharmEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous\\RadarEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous\\SoulboundEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous\\ToggleableEffectEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\axes\\LumberjackEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\DrillerEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\EnergizingEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\ExplosiveEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\hoe\\FarmerEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\hoe\\FertilizerEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\hoe\\HarvestEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\pickaxe\\JackpotEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\QuickeningEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\SmeltingEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\TelepathyEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\BlessedEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows\\AutoAimEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows\\BombardmentEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows\\BountyHunterEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows\\GrapplingEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows\\HeadhunterEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows\\HealingEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows\\MissileEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows\\MolotovEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows\\ParalyzeEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows\\PiercingEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows\\ProjectileChangingEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows\\ShuffleEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows\\VolleyEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\ConditionalDamageMultiplierEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\DeathbringerEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\DeepWoundsEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\DisarmingEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\DisarmorEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\GooeyEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\HallucinationEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\LacedWeaponEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\LifestealEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\LightningEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\VampireEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\HomingArrow;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PiggyFireball;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PiggyWitherSkull;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PigProjectile;\nuse pocketmine\\data\\bedrock\\EnchantmentIdMap;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\entity\\Living;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\enchantment\\StringToEnchantmentParser;\nuse pocketmine\\utils\\StringToTParser;\nuse ReflectionProperty;\n\nclass CustomEnchantManager\n{\n    private static PiggyCustomEnchants $plugin;\n\n    /** @var CustomEnchant[] */\n    public static array $enchants = [];\n\n    public static function init(PiggyCustomEnchants $plugin): void\n    {\n        self::$plugin = $plugin;\n\n        self::registerEnchantment(new AttackerDeterrentEnchant($plugin, CustomEnchantIds::CURSED, \"Cursed\", [VanillaEffects::WITHER()], [60], [1], Rarity::UNCOMMON));\n        self::registerEnchantment(new AttackerDeterrentEnchant($plugin, CustomEnchantIds::DRUNK, \"Drunk\", [VanillaEffects::SLOWNESS(), VanillaEffects::MINING_FATIGUE(), VanillaEffects::NAUSEA()], [60, 60, 60], [1, 1, 0]));\n        self::registerEnchantment(new AttackerDeterrentEnchant($plugin, CustomEnchantIds::FROZEN, \"Frozen\", [VanillaEffects::SLOWNESS()], [60], [1]));\n        self::registerEnchantment(new AttackerDeterrentEnchant($plugin, CustomEnchantIds::HARDENED, \"Hardened\", [VanillaEffects::WEAKNESS()], [60], [1], Rarity::UNCOMMON));\n        self::registerEnchantment(new AttackerDeterrentEnchant($plugin, CustomEnchantIds::POISONED, \"Poisoned\", [VanillaEffects::POISON()], [60], [1], Rarity::UNCOMMON));\n        self::registerEnchantment(new AttackerDeterrentEnchant($plugin, CustomEnchantIds::REVULSION, \"Revulsion\", [VanillaEffects::NAUSEA()], [20], [0], Rarity::UNCOMMON));\n\n        self::registerEnchantment(new ConditionalDamageMultiplierEnchant($plugin, CustomEnchantIds::AERIAL, \"Aerial\", fn(EntityDamageByEntityEvent $event) => !$event->getDamager()?->isOnGround(), Rarity::UNCOMMON));\n        self::registerEnchantment(new ConditionalDamageMultiplierEnchant($plugin, CustomEnchantIds::BACKSTAB, \"Backstab\", fn(EntityDamageByEntityEvent $event) => $event->getDamager()?->getDirectionVector()->dot($event->getEntity()->getDirectionVector()) > 0, Rarity::UNCOMMON));\n        self::registerEnchantment(new ConditionalDamageMultiplierEnchant($plugin, CustomEnchantIds::CHARGE, \"Charge\", fn(EntityDamageByEntityEvent $event) => ($damager = $event->getDamager()) instanceof Living && $damager->isSprinting(), Rarity::UNCOMMON));\n\n        self::registerEnchantment(new LacedWeaponEnchant($plugin, CustomEnchantIds::BLIND, \"Blind\", Rarity::COMMON, [VanillaEffects::BLINDNESS()], [20], [0], [100]));\n        self::registerEnchantment(new LacedWeaponEnchant($plugin, CustomEnchantIds::CRIPPLE, \"Cripple\", Rarity::COMMON, [VanillaEffects::NAUSEA(), VanillaEffects::SLOWNESS()], [100, 100], [0, 1]));\n        self::registerEnchantment(new LacedWeaponEnchant($plugin, CustomEnchantIds::POISON, \"Poison\", Rarity::UNCOMMON, [VanillaEffects::POISON()]));\n        self::registerEnchantment(new LacedWeaponEnchant($plugin, CustomEnchantIds::WITHER, \"Wither\", Rarity::UNCOMMON, [VanillaEffects::WITHER()]));\n\n        self::registerEnchantment(new ProjectileChangingEnchant($plugin, CustomEnchantIds::BLAZE, \"Blaze\", PiggyFireball::class));\n        self::registerEnchantment(new ProjectileChangingEnchant($plugin, CustomEnchantIds::HOMING, \"Homing\", HomingArrow::class, 3, Rarity::MYTHIC));\n        self::registerEnchantment(new ProjectileChangingEnchant($plugin, CustomEnchantIds::PORKIFIED, \"Porkified\", PigProjectile::class, 3, Rarity::MYTHIC));\n        self::registerEnchantment(new ProjectileChangingEnchant($plugin, CustomEnchantIds::WITHERSKULL, \"Wither Skull\", PiggyWitherSkull::class, 1, Rarity::MYTHIC));\n\n        self::registerEnchantment(new ToggleableEffectEnchant($plugin, CustomEnchantIds::ENRAGED, \"Enraged\", 5, CustomEnchant::TYPE_CHESTPLATE, CustomEnchant::ITEM_TYPE_CHESTPLATE, VanillaEffects::STRENGTH(), -1));\n        self::registerEnchantment(new ToggleableEffectEnchant($plugin, CustomEnchantIds::GEARS, \"Gears\", 1, CustomEnchant::TYPE_BOOTS, CustomEnchant::ITEM_TYPE_BOOTS, VanillaEffects::SPEED(), 0, 0, Rarity::UNCOMMON));\n        self::registerEnchantment(new ToggleableEffectEnchant($plugin, CustomEnchantIds::GLOWING, \"Glowing\", 1, CustomEnchant::TYPE_HELMET, CustomEnchant::ITEM_TYPE_HELMET, VanillaEffects::NIGHT_VISION(), 0, 0, Rarity::COMMON));\n        self::registerEnchantment(new ToggleableEffectEnchant($plugin, CustomEnchantIds::HASTE, \"Haste\", 5, CustomEnchant::TYPE_HAND, CustomEnchant::ITEM_TYPE_PICKAXE, VanillaEffects::HASTE(), 0, 1, Rarity::UNCOMMON));\n        self::registerEnchantment(new ToggleableEffectEnchant($plugin, CustomEnchantIds::OBSIDIANSHIELD, \"Obsidian Shield\", 1, CustomEnchant::TYPE_ARMOR_INVENTORY, CustomEnchant::ITEM_TYPE_ARMOR, VanillaEffects::FIRE_RESISTANCE(), 0, 0, Rarity::COMMON));\n        self::registerEnchantment(new ToggleableEffectEnchant($plugin, CustomEnchantIds::OXYGENATE, \"Oxygenate\", 1, CustomEnchant::TYPE_HAND, CustomEnchant::ITEM_TYPE_PICKAXE, VanillaEffects::WATER_BREATHING(), 0, 0, Rarity::UNCOMMON));\n        self::registerEnchantment(new ToggleableEffectEnchant($plugin, CustomEnchantIds::SPRINGS, \"Springs\", 1, CustomEnchant::TYPE_BOOTS, CustomEnchant::ITEM_TYPE_BOOTS, VanillaEffects::JUMP_BOOST(), 3, 0, Rarity::UNCOMMON));\n\n        self::registerEnchantment(new AntiKnockbackEnchant($plugin, CustomEnchantIds::ANTIKNOCKBACK));\n        self::registerEnchantment(new AntitoxinEnchant($plugin, CustomEnchantIds::ANTITOXIN));\n        self::registerEnchantment(new AutoAimEnchant($plugin, CustomEnchantIds::AUTOAIM));\n        self::registerEnchantment(new AutoRepairEnchant($plugin, CustomEnchantIds::AUTOREPAIR));\n        self::registerEnchantment(new ArmoredEnchant($plugin, CustomEnchantIds::ARMORED));\n        self::registerEnchantment(new BerserkerEnchant($plugin, CustomEnchantIds::BERSERKER));\n        self::registerEnchantment(new BlessedEnchant($plugin, CustomEnchantIds::BLESSED));\n        self::registerEnchantment(new BombardmentEnchant($plugin, CustomEnchantIds::BOMBARDMENT));\n        self::registerEnchantment(new BountyHunterEnchant($plugin, CustomEnchantIds::BOUNTYHUNTER));\n        self::registerEnchantment(new CactusEnchant($plugin, CustomEnchantIds::CACTUS));\n        self::registerEnchantment(new ChickenEnchant($plugin, CustomEnchantIds::CHICKEN));\n        self::registerEnchantment(new CloakingEnchant($plugin, CustomEnchantIds::CLOAKING));\n        self::registerEnchantment(new DeathbringerEnchant($plugin, CustomEnchantIds::DEATHBRINGER));\n        self::registerEnchantment(new DeepWoundsEnchant($plugin, CustomEnchantIds::DEEPWOUNDS));\n        self::registerEnchantment(new DisarmingEnchant($plugin, CustomEnchantIds::DISARMING));\n        self::registerEnchantment(new DisarmorEnchant($plugin, CustomEnchantIds::DISARMOR));\n        self::registerEnchantment(new DrillerEnchant($plugin, CustomEnchantIds::DRILLER));\n        self::registerEnchantment(new EndershiftEnchant($plugin, CustomEnchantIds::ENDERSHIFT));\n        self::registerEnchantment(new EnergizingEnchant($plugin, CustomEnchantIds::ENERGIZING));\n        self::registerEnchantment(new EnlightedEnchant($plugin, CustomEnchantIds::ENLIGHTED));\n        self::registerEnchantment(new ExplosiveEnchant($plugin, CustomEnchantIds::EXPLOSIVE));\n        self::registerEnchantment(new FarmerEnchant($plugin, CustomEnchantIds::FARMER));\n        self::registerEnchantment(new FertilizerEnchant($plugin, CustomEnchantIds::FERTILIZER));\n        self::registerEnchantment(new FocusedEnchant($plugin, CustomEnchantIds::FOCUSED));\n        self::registerEnchantment(new ForcefieldEnchant($plugin, CustomEnchantIds::FORCEFIELD));\n        self::registerEnchantment(new GooeyEnchant($plugin, CustomEnchantIds::GOOEY));\n        self::registerEnchantment(new GrapplingEnchant($plugin, CustomEnchantIds::GRAPPLING));\n        self::registerEnchantment(new GrowEnchant($plugin, CustomEnchantIds::GROW));\n        self::registerEnchantment(new HallucinationEnchant($plugin, CustomEnchantIds::HALLUCINATION));\n        self::registerEnchantment(new HarvestEnchant($plugin, CustomEnchantIds::HARVEST));\n        self::registerEnchantment(new HeadhunterEnchant($plugin, CustomEnchantIds::HEADHUNTER));\n        self::registerEnchantment(new HealingEnchant($plugin, CustomEnchantIds::HEALING));\n        self::registerEnchantment(new HeavyEnchant($plugin, CustomEnchantIds::HEAVY));\n        self::registerEnchantment(new ImplantsEnchant($plugin, CustomEnchantIds::IMPLANTS));\n        self::registerEnchantment(new JackpotEnchant($plugin, CustomEnchantIds::JACKPOT));\n        self::registerEnchantment(new JetpackEnchant($plugin, CustomEnchantIds::JETPACK));\n        self::registerEnchantment(new LifestealEnchant($plugin, CustomEnchantIds::LIFESTEAL));\n        self::registerEnchantment(new LightningEnchant($plugin, CustomEnchantIds::LIGHTNING));\n        self::registerEnchantment(new LuckyCharmEnchant($plugin, CustomEnchantIds::LUCKYCHARM));\n        self::registerEnchantment(new LumberjackEnchant($plugin, CustomEnchantIds::LUMBERJACK));\n        self::registerEnchantment(new MagmaWalkerEnchant($plugin, CustomEnchantIds::MAGMAWALKER));\n        self::registerEnchantment(new MeditationEnchant($plugin, CustomEnchantIds::MEDITATION));\n        self::registerEnchantment(new MissileEnchant($plugin, CustomEnchantIds::MISSILE));\n        self::registerEnchantment(new MolotovEnchant($plugin, CustomEnchantIds::MOLOTOV));\n        self::registerEnchantment(new MoltenEnchant($plugin, CustomEnchantIds::MOLTEN));\n        self::registerEnchantment(new OverloadEnchant($plugin, CustomEnchantIds::OVERLOAD));\n        self::registerEnchantment(new ParachuteEnchant($plugin, CustomEnchantIds::PARACHUTE));\n        self::registerEnchantment(new ParalyzeEnchant($plugin, CustomEnchantIds::PARALYZE));\n        self::registerEnchantment(new PiercingEnchant($plugin, CustomEnchantIds::PIERCING));\n        self::registerEnchantment(new PoisonousCloudEnchant($plugin, CustomEnchantIds::POISONOUSCLOUD));\n        self::registerEnchantment(new ProwlEnchant($plugin, CustomEnchantIds::PROWL));\n        self::registerEnchantment(new QuickeningEnchant($plugin, CustomEnchantIds::QUICKENING));\n        self::registerEnchantment(new RadarEnchant($plugin, CustomEnchantIds::RADAR));\n        self::registerEnchantment(new ReviveEnchant($plugin, CustomEnchantIds::REVIVE));\n        self::registerEnchantment(new SelfDestructEnchant($plugin, CustomEnchantIds::SELFDESTRUCT));\n        self::registerEnchantment(new ShieldedEnchant($plugin, CustomEnchantIds::SHIELDED));\n        self::registerEnchantment(new ShrinkEnchant($plugin, CustomEnchantIds::SHRINK));\n        self::registerEnchantment(new ShuffleEnchant($plugin, CustomEnchantIds::SHUFFLE));\n        self::registerEnchantment(new SmeltingEnchant($plugin, CustomEnchantIds::SMELTING));\n        self::registerEnchantment(new SoulboundEnchant($plugin, CustomEnchantIds::SOULBOUND));\n        self::registerEnchantment(new SpiderEnchant($plugin, CustomEnchantIds::SPIDER));\n        self::registerEnchantment(new StompEnchantment($plugin, CustomEnchantIds::STOMP));\n        self::registerEnchantment(new TankEnchant($plugin, CustomEnchantIds::TANK));\n        self::registerEnchantment(new TelepathyEnchant($plugin, CustomEnchantIds::TELEPATHY));\n        self::registerEnchantment(new VacuumEnchant($plugin, CustomEnchantIds::VACUUM));\n        self::registerEnchantment(new VampireEnchant($plugin, CustomEnchantIds::VAMPIRE));\n        self::registerEnchantment(new VolleyEnchant($plugin, CustomEnchantIds::VOLLEY));\n    }\n\n    public static function getPlugin(): PiggyCustomEnchants\n    {\n        return self::$plugin;\n    }\n\n    public static function registerEnchantment(CustomEnchant $enchant): void\n    {\n        EnchantmentIdMap::getInstance()->register($enchant->getId(), $enchant);\n        self::$enchants[$enchant->getId()] = $enchant;\n        StringToEnchantmentParser::getInstance()->register($enchant->name, fn() => $enchant);\n        if ($enchant->name !== $enchant->getDisplayName()) StringToEnchantmentParser::getInstance()->register($enchant->getDisplayName(), fn() => $enchant);\n\n        self::$plugin->getLogger()->debug(\"Custom Enchantment '\" . $enchant->getDisplayName() . \"' registered with id \" . $enchant->getId());\n    }\n\n    public static function unregisterEnchantment(int|CustomEnchant $id): void\n    {\n        $id = $id instanceof CustomEnchant ? $id->getId() : $id;\n        $enchant = self::$enchants[$id];\n\n        $property = new ReflectionProperty(StringToTParser::class, \"callbackMap\");\n        $property->setAccessible(true);\n        $value = $property->getValue(StringToEnchantmentParser::getInstance());\n        unset($value[strtolower(str_replace([\" \", \"minecraft:\"], [\"_\", \"\"], trim($enchant->name)))]);\n        if ($enchant->name !== $enchant->getDisplayName()) unset($value[strtolower(str_replace([\" \", \"minecraft:\"], [\"_\", \"\"], trim($enchant->getDisplayName())))]);\n        $property->setValue(StringToEnchantmentParser::getInstance(), $value);\n\n        self::$plugin->getLogger()->debug(\"Custom Enchantment '\" . $enchant->getDisplayName() . \"' unregistered with id \" . $enchant->getId());\n        unset(self::$enchants[$id]);\n\n        $property = new ReflectionProperty(EnchantmentIdMap::class, \"enchToId\");\n        $property->setAccessible(true);\n        $value = $property->getValue(EnchantmentIdMap::getInstance());\n        unset($value[spl_object_id(EnchantmentIdMap::getInstance()->fromId($id))]);\n        $property->setValue(EnchantmentIdMap::getInstance(), $value);\n\n        $property = new ReflectionProperty(EnchantmentIdMap::class, \"idToEnch\");\n        $property->setAccessible(true);\n        $value = $property->getValue(EnchantmentIdMap::getInstance());\n        unset($value[$id]);\n        $property->setValue(EnchantmentIdMap::getInstance(), $value);\n    }\n\n    /**\n     * @return CustomEnchant[]\n     */\n    public static function getEnchantments(): array\n    {\n        return self::$enchants;\n    }\n\n    public static function getEnchantment(int $id): ?CustomEnchant\n    {\n        return self::$enchants[$id] ?? null;\n    }\n\n    public static function getEnchantmentByName(string $name): ?CustomEnchant\n    {\n        return ($enchant = StringToEnchantmentParser::getInstance()->parse($name)) instanceof CustomEnchant ? $enchant : null;\n    }\n}\n"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/EventListener.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ToggleableEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\DrillerEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\BombardmentTNT;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PiggyTNT;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\ProjectileTracker;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\Utils;\nuse pocketmine\\block\\BlockLegacyIds;\nuse pocketmine\\event\\block\\BlockBreakEvent;\nuse pocketmine\\event\\entity\\EntityBlockChangeEvent;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\entity\\EntityDamageEvent;\nuse pocketmine\\event\\entity\\EntityEffectAddEvent;\nuse pocketmine\\event\\entity\\EntityShootBowEvent;\nuse pocketmine\\event\\entity\\ProjectileHitBlockEvent;\nuse pocketmine\\event\\entity\\ProjectileLaunchEvent;\nuse pocketmine\\event\\inventory\\InventoryTransactionEvent;\nuse pocketmine\\event\\Listener;\nuse pocketmine\\event\\player\\PlayerDeathEvent;\nuse pocketmine\\event\\player\\PlayerInteractEvent;\nuse pocketmine\\event\\player\\PlayerItemHeldEvent;\nuse pocketmine\\event\\player\\PlayerJoinEvent;\nuse pocketmine\\event\\player\\PlayerMoveEvent;\nuse pocketmine\\event\\player\\PlayerQuitEvent;\nuse pocketmine\\event\\player\\PlayerToggleSneakEvent;\nuse pocketmine\\event\\server\\DataPacketReceiveEvent;\nuse pocketmine\\event\\server\\DataPacketSendEvent;\nuse pocketmine\\inventory\\ArmorInventory;\nuse pocketmine\\inventory\\CallbackInventoryListener;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\inventory\\PlayerInventory;\nuse pocketmine\\inventory\\transaction\\action\\SlotChangeAction;\nuse pocketmine\\item\\enchantment\\EnchantmentInstance;\nuse pocketmine\\item\\Item;\nuse pocketmine\\item\\ItemIds;\nuse pocketmine\\item\\VanillaItems;\nuse pocketmine\\network\\mcpe\\protocol\\InventoryContentPacket;\nuse pocketmine\\network\\mcpe\\protocol\\InventorySlotPacket;\nuse pocketmine\\network\\mcpe\\protocol\\InventoryTransactionPacket;\nuse pocketmine\\network\\mcpe\\protocol\\MobEquipmentPacket;\nuse pocketmine\\network\\mcpe\\protocol\\PlayerActionPacket;\nuse pocketmine\\network\\mcpe\\protocol\\PlayerAuthInputPacket;\nuse pocketmine\\network\\mcpe\\protocol\\types\\inventory\\ItemStackWrapper;\nuse pocketmine\\network\\mcpe\\protocol\\types\\PlayerAction;\nuse pocketmine\\network\\mcpe\\protocol\\types\\PlayerBlockActionWithBlockInfo;\nuse pocketmine\\player\\Player;\n\nclass EventListener implements Listener\n{\n    public function __construct(private PiggyCustomEnchants $plugin)\n    {\n    }\n\n    /**\n     * @priority HIGHEST\n     */\n    public function onBreak(BlockBreakEvent $event): void\n    {\n        $player = $event->getPlayer();\n        ReactiveEnchantment::attemptReaction($player, $event);\n    }\n\n    public function onDataPacketReceive(DataPacketReceiveEvent $event): void\n    {\n        $packet = $event->getPacket();\n        if ($packet instanceof InventoryTransactionPacket) {\n            $transaction = $packet->trData;\n            foreach ($transaction->getActions() as $action) {\n                $action->oldItem = new ItemStackWrapper($action->oldItem->getStackId(), Utils::filterDisplayedEnchants($action->oldItem->getItemStack()));\n                $action->newItem = new ItemStackWrapper($action->newItem->getStackId(), Utils::filterDisplayedEnchants($action->newItem->getItemStack()));\n            }\n        }\n        if ($packet instanceof PlayerActionPacket) {\n            if ($packet->action === PlayerAction::START_BREAK || $packet->action === PlayerAction::CREATIVE_PLAYER_DESTROY_BLOCK) {\n                DrillerEnchant::$lastBreakFace[$event->getOrigin()->getPlayer()->getName()] = $packet->face;\n            }\n        }\n        if ($packet instanceof PlayerAuthInputPacket) {\n            $blockActions = $packet->getBlockActions();\n            if ($blockActions !== null) {\n                foreach ($blockActions as $blockAction) {\n                    if ($blockAction instanceof PlayerBlockActionWithBlockInfo) {\n                        DrillerEnchant::$lastBreakFace[$event->getOrigin()->getPlayer()->getName()] = $blockAction->getFace();\n                    }\n                }\n            }\n        }\n        if ($packet instanceof MobEquipmentPacket) Utils::filterDisplayedEnchants($packet->item->getItemStack());\n    }\n\n    public function onDataPacketSend(DataPacketSendEvent $event): void\n    {\n        $packets = $event->getPackets();\n        foreach ($packets as $packet) {\n            if ($packet instanceof InventorySlotPacket) {\n                $packet->item = new ItemStackWrapper($packet->item->getStackId(), Utils::displayEnchants($packet->item->getItemStack()));\n            }\n            if ($packet instanceof InventoryContentPacket) {\n                foreach ($packet->items as $i => $item) {\n                    $packet->items[$i] = new ItemStackWrapper($item->getStackId(), Utils::displayEnchants($item->getItemStack()));\n                }\n            }\n        }\n    }\n\n    public function onBlockChange(EntityBlockChangeEvent $event): void\n    {\n        $entity = $event->getEntity();\n        if ($entity instanceof BombardmentTNT) {\n            for ($i = 0; $i < 3 + $entity->getEnchantmentLevel(); $i++) {\n                $tnt = new PiggyTNT($entity->getLocation(), null, $this->plugin->getConfig()->getNested(\"world-damage.missile\", false));\n                $tnt->setFuse(0);\n                $tnt->setOwningEntity($entity->getOwningEntity());\n                $tnt->spawnToAll();\n            }\n            $event->cancel();\n        }\n    }\n\n    /**\n     * @priority HIGHEST\n     */\n    public function onDamage(EntityDamageEvent $event): void\n    {\n        $entity = $event->getEntity();\n        if ($entity instanceof Player) {\n            if ($event->getCause() === EntityDamageEvent::CAUSE_FALL && !Utils::shouldTakeFallDamage($entity)) {\n                if ($entity->getArmorInventory()->getBoots()->getEnchantment(CustomEnchantManager::getEnchantment(CustomEnchantIds::SPRINGS)) === null) Utils::setShouldTakeFallDamage($entity, true);\n                $event->cancel();\n                return;\n            }\n            ReactiveEnchantment::attemptReaction($entity, $event);\n        }\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $attacker = $event->getDamager();\n            if ($attacker instanceof Player) ReactiveEnchantment::attemptReaction($attacker, $event);\n        }\n    }\n\n    /**\n     * @priority HIGHEST\n     */\n    public function onEffectAdd(EntityEffectAddEvent $event): void\n    {\n        $entity = $event->getEntity();\n        if ($entity instanceof Player) ReactiveEnchantment::attemptReaction($entity, $event);\n    }\n\n    /**\n     * @priority HIGHEST\n     */\n    public function onShootBow(EntityShootBowEvent $event): void\n    {\n        $entity = $event->getEntity();\n        if ($entity instanceof Player) ReactiveEnchantment::attemptReaction($entity, $event);\n    }\n\n    public function onDeath(PlayerDeathEvent $event): void\n    {\n        ReactiveEnchantment::attemptReaction($event->getPlayer(), $event);\n    }\n\n    /**\n     * @priority HIGHEST\n     */\n    public function onInteract(PlayerInteractEvent $event): void\n    {\n        ReactiveEnchantment::attemptReaction($event->getPlayer(), $event);\n    }\n\n    /**\n     * @priority HIGHEST\n     */\n    public function onItemHold(PlayerItemHeldEvent $event): void\n    {\n        $player = $event->getPlayer();\n        $inventory = $player->getInventory();\n        $oldItem = $inventory->getItemInHand();\n        $newItem = $event->getItem();\n        foreach ($oldItem->getEnchantments() as $enchantmentInstance) ToggleableEnchantment::attemptToggle($player, $oldItem, $enchantmentInstance, $inventory, $inventory->getHeldItemIndex(), false);\n        foreach ($newItem->getEnchantments() as $enchantmentInstance) ToggleableEnchantment::attemptToggle($player, $newItem, $enchantmentInstance, $inventory, $inventory->getHeldItemIndex());\n    }\n\n    public function onJoin(PlayerJoinEvent $event): void\n    {\n        $player = $event->getPlayer();\n        foreach ($player->getInventory()->getContents() as $slot => $content) {\n            foreach ($content->getEnchantments() as $enchantmentInstance) {\n                ToggleableEnchantment::attemptToggle($player, $content, $enchantmentInstance, $player->getInventory(), $slot);\n            }\n        }\n        foreach ($player->getArmorInventory()->getContents() as $slot => $content) {\n            foreach ($content->getEnchantments() as $enchantmentInstance) {\n                ToggleableEnchantment::attemptToggle($player, $content, $enchantmentInstance, $player->getArmorInventory(), $slot);\n            }\n        }\n\n        $onSlot = function (Inventory $inventory, int $slot, Item $oldItem): void {\n            if ($inventory instanceof PlayerInventory || $inventory instanceof ArmorInventory) {\n                $holder = $inventory->getHolder();\n                if ($holder instanceof Player) {\n                    if (!$oldItem->equals(($newItem = $inventory->getItem($slot)), !$inventory instanceof ArmorInventory)) {\n                        if ($newItem->getId() === ItemIds::AIR || $inventory instanceof ArmorInventory) foreach ($oldItem->getEnchantments() as $oldEnchantment) ToggleableEnchantment::attemptToggle($holder, $oldItem, $oldEnchantment, $inventory, $slot, false);\n                        if ($oldItem->getId() === ItemIds::AIR || $inventory instanceof ArmorInventory) foreach ($newItem->getEnchantments() as $newEnchantment) ToggleableEnchantment::attemptToggle($holder, $newItem, $newEnchantment, $inventory, $slot);\n                    }\n                }\n            }\n        };\n        /**\n         * @param Item[] $oldContents\n         */\n        $onContent = function (Inventory $inventory, array $oldContents) use ($onSlot): void {\n            foreach ($oldContents as $slot => $oldItem) {\n                if (!($oldItem ?? VanillaItems::AIR())->equals($inventory->getItem($slot), !$inventory instanceof ArmorInventory)) {\n                    $onSlot($inventory, $slot, $oldItem);\n                }\n            }\n        };\n        $player->getInventory()->getListeners()->add(new CallbackInventoryListener($onSlot, $onContent));\n        $player->getArmorInventory()->getListeners()->add(new CallbackInventoryListener($onSlot, $onContent));\n    }\n\n    /**\n     * @priority HIGHEST\n     */\n    public function onMove(PlayerMoveEvent $event): void\n    {\n        $player = $event->getPlayer();\n        if (!Utils::shouldTakeFallDamage($player)) {\n            if ($player->getWorld()->getBlock($player->getPosition()->floor()->subtract(0, 1, 0))->getId() !== BlockLegacyIds::AIR && Utils::getNoFallDamageDuration($player) <= 0) {\n                Utils::setShouldTakeFallDamage($player, true);\n            } else {\n                Utils::increaseNoFallDamageDuration($player);\n            }\n        }\n        if ($event->getFrom()->floor()->equals($event->getTo()->floor())) return;\n        ReactiveEnchantment::attemptReaction($player, $event);\n    }\n\n    /**\n     * @priority MONITOR\n     */\n    public function onQuit(PlayerQuitEvent $event): void\n    {\n        $player = $event->getPlayer();\n        if (!$player->isClosed()) {\n            foreach ($player->getInventory()->getContents() as $slot => $content) {\n                foreach ($content->getEnchantments() as $enchantmentInstance) {\n                    ToggleableEnchantment::attemptToggle($player, $content, $enchantmentInstance, $player->getInventory(), $slot, false);\n                }\n            }\n            foreach ($player->getArmorInventory()->getContents() as $slot => $content) {\n                foreach ($content->getEnchantments() as $enchantmentInstance) {\n                    ToggleableEnchantment::attemptToggle($player, $content, $enchantmentInstance, $player->getArmorInventory(), $slot, false);\n                }\n            }\n        }\n    }\n\n    /**\n     * @priority HIGHEST\n     */\n    public function onSneak(PlayerToggleSneakEvent $event): void\n    {\n        ReactiveEnchantment::attemptReaction($event->getPlayer(), $event);\n    }\n\n    /**\n     * @priority HIGHEST\n     */\n    public function onProjectileHitBlock(ProjectileHitBlockEvent $event): void\n    {\n        $shooter = $event->getEntity()->getOwningEntity();\n        if ($shooter instanceof Player) ReactiveEnchantment::attemptReaction($shooter, $event);\n    }\n\n    /**\n     * @priority HIGHEST\n     */\n    public function onProjectileLaunch(ProjectileLaunchEvent $event): void\n    {\n        $projectile = $event->getEntity();\n        $shooter = $projectile->getOwningEntity();\n        if ($shooter instanceof Player) ProjectileTracker::addProjectile($projectile, $shooter->getInventory()->getItemInHand());\n    }\n\n    /**\n     * @priority HIGHEST\n     */\n    public function onTransaction(InventoryTransactionEvent $event): void\n    {\n        if ($this->plugin->getConfig()->getNested(\"enchants.books\", true) === false) return;\n        $transaction = $event->getTransaction();\n        $actions = array_values($transaction->getActions());\n        if (count($actions) === 2) {\n            foreach ($actions as $i => $action) {\n                if ($action instanceof SlotChangeAction && ($otherAction = $actions[($i + 1) % 2]) instanceof SlotChangeAction && ($itemClickedWith = $action->getTargetItem())->getId() === ItemIds::ENCHANTED_BOOK && ($itemClicked = $action->getSourceItem())->getId() !== ItemIds::AIR && ($itemClicked->getId() !== ItemIds::ENCHANTED_BOOK || count($itemClicked->getEnchantments()) >= count($itemClickedWith->getEnchantments()))) {\n                    if (count($itemClickedWith->getEnchantments()) < 1) return;\n                    $enchantmentSuccessful = false;\n                    foreach ($itemClickedWith->getEnchantments() as $enchantment) {\n                        $enchantmentType = $enchantment->getType();\n                        $newLevel = $enchantment->getLevel();\n                        $willChange = false;\n                        if (($existingEnchant = $itemClicked->getEnchantment($enchantmentType)) !== null) {\n                            if ($existingEnchant->getLevel() > $newLevel) continue;\n                            if ($existingEnchant->getLevel() === $newLevel) {\n                                $newLevel++;\n                                $willChange = true;\n                            }\n                        } else {\n                            $willChange = true;\n                        }\n                        if (\n                            ($enchantmentType instanceof CustomEnchant &&\n                                (!Utils::itemMatchesItemType($itemClicked, $enchantmentType->getItemType()) || !Utils::checkEnchantIncompatibilities($itemClicked, $enchantmentType))\n                            ) ||\n                            $itemClicked->getCount() !== 1 ||\n                            $newLevel > $enchantmentType->getMaxLevel() ||\n                            ($itemClicked->getId() === ItemIds::ENCHANTED_BOOK && count($itemClicked->getEnchantments()) === 0) ||\n                            $itemClicked->getId() === ItemIds::BOOK\n                        ) continue;\n                        $itemClicked->addEnchantment(new EnchantmentInstance($enchantmentType, $newLevel));\n                        if ($willChange) $enchantmentSuccessful = true;\n                    }\n                    if ($enchantmentSuccessful) {\n                        $event->cancel();\n                        $action->getInventory()->setItem($action->getSlot(), $itemClicked);\n                        $otherAction->getInventory()->setItem($otherAction->getSlot(), VanillaItems::AIR());\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/PiggyCustomEnchants.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants;\n\nuse CortexPE\\Commando\\BaseCommand;\nuse CortexPE\\Commando\\PacketHooker;\nuse DaPigGuy\\libPiggyUpdateChecker\\libPiggyUpdateChecker;\nuse DaPigGuy\\PiggyCustomEnchants\\blocks\\PiggyObsidian;\nuse DaPigGuy\\PiggyCustomEnchants\\commands\\CustomEnchantsCommand;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ToggleableEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\BombardmentTNT;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\HomingArrow;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PiggyFireball;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PiggyLightning;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PiggyTNT;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PiggyWitherSkull;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PigProjectile;\nuse DaPigGuy\\PiggyCustomEnchants\\tasks\\CheckDisabledEnchantsTask;\nuse DaPigGuy\\PiggyCustomEnchants\\tasks\\TickEnchantmentsTask;\nuse jojoe77777\\FormAPI\\Form;\nuse pocketmine\\block\\BlockFactory;\nuse pocketmine\\color\\Color;\nuse pocketmine\\data\\bedrock\\EffectIdMap;\nuse pocketmine\\entity\\effect\\Effect;\nuse pocketmine\\entity\\EntityDataHelper;\nuse pocketmine\\entity\\EntityFactory;\nuse pocketmine\\nbt\\tag\\CompoundTag;\nuse pocketmine\\plugin\\PluginBase;\nuse pocketmine\\utils\\Config;\nuse pocketmine\\world\\World;\n\nclass PiggyCustomEnchants extends PluginBase\n{\n    public static Effect $SLOW_FALL;\n\n    /** @var mixed[] */\n    private array $enchantmentData;\n\n    public function onEnable(): void\n    {\n        foreach (\n            [\n                \"Commando\" => BaseCommand::class,\n                \"libformapi\" => Form::class,\n                \"libPiggyUpdateChecker\" => libPiggyUpdateChecker::class\n            ] as $virion => $class\n        ) {\n            if (!class_exists($class)) {\n                $this->getLogger()->error($virion . \" virion not found. Download PiggyCustomEnchants at https://poggit.pmmp.io/p/PiggyCustomEnchants for a pre-compiled phar.\");\n                $this->getServer()->getPluginManager()->disablePlugin($this);\n                return;\n            }\n        }\n\n        foreach ([\"rarities\", \"max_levels\", \"display_names\", \"descriptions\", \"extra_data\", \"cooldowns\", \"chances\"] as $file) {\n            $this->saveResource($file . \".json\");\n            foreach ((new Config($this->getDataFolder() . $file . \".json\"))->getAll() as $enchant => $data) {\n                $this->enchantmentData[$enchant][$file] = $data;\n            }\n        }\n        $this->saveDefaultConfig();\n\n        CustomEnchantManager::init($this);\n\n        BlockFactory::getInstance()->register(new PiggyObsidian(), true);\n\n        //TODO: Use real effect\n        self::$SLOW_FALL = new Effect(\"%potion.slowFalling\", new Color(206, 255, 255));\n        EffectIdMap::getInstance()->register(27, self::$SLOW_FALL);\n\n        $entityFactory = EntityFactory::getInstance();\n        $entityFactory->register(BombardmentTNT::class, function (World $world, CompoundTag $nbt): BombardmentTNT {\n            return new BombardmentTNT(EntityDataHelper::parseLocation($nbt, $world), $nbt, $nbt->getInt(\"Level\", 1));\n        }, [\"BombardmentTNT\"]);\n        $entityFactory->register(HomingArrow::class, function (World $world, CompoundTag $nbt): HomingArrow {\n            return new HomingArrow(EntityDataHelper::parseLocation($nbt, $world), null, false, $nbt, $nbt->getInt(\"Level\", 1));\n        }, [\"HomingArrow\"]);\n        $entityFactory->register(PigProjectile::class, function (World $world, CompoundTag $nbt): PigProjectile {\n            return new PigProjectile(EntityDataHelper::parseLocation($nbt, $world), null, $nbt);\n        }, [\"PigProjectile\"]);\n        $entityFactory->register(PiggyFireball::class, function (World $world, CompoundTag $nbt): PiggyFireball {\n            return new PiggyFireball(EntityDataHelper::parseLocation($nbt, $world), null, $nbt);\n        }, [\"PiggyFireball\"]);\n        $entityFactory->register(PiggyLightning::class, function (World $world, CompoundTag $nbt): PiggyLightning {\n            return new PiggyLightning(EntityDataHelper::parseLocation($nbt, $world), $nbt);\n        }, [\"PiggyLightning\"]);\n        $entityFactory->register(PiggyTNT::class, function (World $world, CompoundTag $nbt): PiggyTNT {\n            return new PiggyTNT(EntityDataHelper::parseLocation($nbt, $world), $nbt);\n        }, [\"PiggyTNT\"]);\n        $entityFactory->register(PiggyWitherSkull::class, function (World $world, CompoundTag $nbt): PiggyWitherSkull {\n            return new PiggyWitherSkull(EntityDataHelper::parseLocation($nbt, $world), null, $nbt);\n        }, [\"PiggyWitherSkull\"]);\n\n        foreach ($this->getConfig()->get(\"disabled-enchants\", []) as $enchant) {\n            $e = CustomEnchantManager::getEnchantmentByName($enchant);\n            if ($e instanceof CustomEnchant) CustomEnchantManager::unregisterEnchantment($e->getId());\n        }\n\n        if (!PacketHooker::isRegistered()) PacketHooker::register($this);\n        $this->getServer()->getCommandMap()->register(\"piggycustomenchants\", new CustomEnchantsCommand($this, \"customenchants\", \"Manage Custom Enchants\", [\"ce\", \"customenchant\"]));\n\n        $this->getServer()->getPluginManager()->registerEvents(new EventListener($this), $this);\n        $this->getScheduler()->scheduleRepeatingTask(new TickEnchantmentsTask($this), 1);\n\n        libPiggyUpdateChecker::init($this);\n        if ($this->getConfig()->get(\"remote-disable\", true) === true) $this->getServer()->getAsyncPool()->submitTask(new CheckDisabledEnchantsTask());\n    }\n\n    public function onDisable(): void\n    {\n        foreach ($this->getServer()->getOnlinePlayers() as $player) {\n            foreach ($player->getInventory()->getContents() as $slot => $content) {\n                foreach ($content->getEnchantments() as $enchantmentInstance) {\n                    ToggleableEnchantment::attemptToggle($player, $content, $enchantmentInstance, $player->getInventory(), $slot, false);\n                }\n            }\n            foreach ($player->getArmorInventory()->getContents() as $slot => $content) {\n                foreach ($content->getEnchantments() as $enchantmentInstance) {\n                    ToggleableEnchantment::attemptToggle($player, $content, $enchantmentInstance, $player->getArmorInventory(), $slot, false);\n                }\n            }\n        }\n    }\n\n    /**\n     * @internal\n     */\n    public function getEnchantmentData(string $enchant, string $data, int|string|array $default = \"\"): mixed\n    {\n        if (!isset($this->enchantmentData[str_replace(\" \", \"\", strtolower($enchant))][$data])) $this->setEnchantmentData($enchant, $data, $default);\n        return $this->enchantmentData[str_replace(\" \", \"\", strtolower($enchant))][$data];\n    }\n\n    public function setEnchantmentData(string $enchant, string $data, int|string|array $value): void\n    {\n        $this->enchantmentData[str_replace(\" \", \"\", strtolower($enchant))][$data] = $value;\n        $config = new Config($this->getDataFolder() . $data . \".json\");\n        $config->set(str_replace(\" \", \"\", strtolower($enchant)), $value);\n        $config->save();\n    }\n\n    /**\n     * @internal\n     */\n    public function areFormsEnabled(): bool\n    {\n        return $this->getConfig()->getNested(\"forms.enabled\", true);\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/blocks/PiggyObsidian.php",
    "content": "<?php\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\blocks;\n\nuse pocketmine\\block\\Block;\nuse pocketmine\\block\\BlockBreakInfo;\nuse pocketmine\\block\\BlockIdentifier;\nuse pocketmine\\block\\BlockLegacyIds;\nuse pocketmine\\block\\VanillaBlocks;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass PiggyObsidian extends Block\n{\n    private int $age = 0;\n\n    public function __construct()\n    {\n        parent::__construct(new BlockIdentifier(BlockLegacyIds::OBSIDIAN, 15), \"Magmawalker Obsidian\", BlockBreakInfo::instant());\n    }\n\n    public function onScheduledUpdate(): void\n    {\n        if (mt_rand(0, 3) === 0 || $this->countNeighbors() < 4) {\n            $this->slightlyMelt(true);\n        } else {\n            $this->getPosition()->getWorld()->scheduleDelayedBlockUpdate($this->getPosition(), mt_rand(20, 40));\n        }\n    }\n\n    public function onBreak(Item $item, Player $player = null): bool\n    {\n        $this->getPosition()->getWorld()->setBlock($this->getPosition(), VanillaBlocks::LAVA());\n        return true;\n    }\n\n    public function getDrops(Item $item): array\n    {\n        return [];\n    }\n\n    public function countNeighbors(): int\n    {\n        $i = 0;\n        foreach ($this->getAllSides() as $block) {\n            if ($block instanceof PiggyObsidian) {\n                $i++;\n                if ($i >= 4) return $i;\n            }\n        }\n        return $i;\n    }\n\n    public function slightlyMelt(bool $meltNeighbors): void\n    {\n        if ($this->age < 3) {\n            $this->age++;\n            $this->getPosition()->getWorld()->scheduleDelayedBlockUpdate($this->getPosition(), mt_rand(20, 40));\n        } else {\n            $this->getPosition()->getWorld()->useBreakOn($this->getPosition());\n            if ($meltNeighbors) {\n                foreach ($this->getAllSides() as $block) {\n                    if ($block instanceof PiggyObsidian) {\n                        $block->slightlyMelt(false);\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/commands/CustomEnchantsCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\commands;\n\nuse CortexPE\\Commando\\BaseCommand;\nuse CortexPE\\Commando\\BaseSubCommand;\nuse DaPigGuy\\PiggyCustomEnchants\\commands\\subcommands\\AboutSubCommand;\nuse DaPigGuy\\PiggyCustomEnchants\\commands\\subcommands\\EnchantSubCommand;\nuse DaPigGuy\\PiggyCustomEnchants\\commands\\subcommands\\InfoSubCommand;\nuse DaPigGuy\\PiggyCustomEnchants\\commands\\subcommands\\ListSubCommand;\nuse DaPigGuy\\PiggyCustomEnchants\\commands\\subcommands\\NBTSubCommand;\nuse DaPigGuy\\PiggyCustomEnchants\\commands\\subcommands\\RemoveSubCommand;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse jojoe77777\\FormAPI\\SimpleForm;\nuse pocketmine\\command\\CommandSender;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass CustomEnchantsCommand extends BaseCommand\n{\n    /** @var PiggyCustomEnchants */\n    protected $plugin;\n\n    public function onRun(CommandSender $sender, string $aliasUsed, array $args): void\n    {\n        $subcommands = array_values(array_map(function (BaseSubCommand $subCommand): string {\n            return $subCommand->getName();\n        }, $this->getSubCommands()));\n        if ($sender instanceof Player && $this->plugin->areFormsEnabled()) {\n            $form = new SimpleForm(function (Player $player, ?int $data) use ($subcommands): void {\n                if ($data !== null && isset($subcommands[$data])) {\n                    $this->plugin->getServer()->dispatchCommand($player, \"ce \" . $subcommands[$data]);\n                }\n            });\n            $form->setTitle(TextFormat::GREEN . \"PiggyCustomEnchants Menu\");\n            foreach ($subcommands as $subcommand) $form->addButton(ucfirst($subcommand));\n            $sender->sendForm($form);\n            return;\n        }\n        $sender->sendMessage(\"Usage: /ce <\" . implode(\"|\", $subcommands) . \">\");\n    }\n\n    public function prepare(): void\n    {\n        $this->registerSubCommand(new AboutSubCommand($this->plugin, \"about\", \"Displays basic information about the plugin\"));\n        $this->registerSubCommand(new EnchantSubCommand($this->plugin, \"enchant\", \"Apply an enchantment on an item\"));\n        $this->registerSubCommand(new InfoSubCommand($this->plugin, \"info\", \"Get info on a custom enchant\"));\n        $this->registerSubCommand(new ListSubCommand($this->plugin, \"list\", \"Lists all registered custom enchants\"));\n        $this->registerSubCommand(new NBTSubCommand($this->plugin, \"nbt\", \"Displays NBT tags of currently held item\"));\n        $this->registerSubCommand(new RemoveSubCommand($this->plugin, \"remove\", \"Remove an enchantment from an item\"));\n    }\n}\n"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/commands/subcommands/AboutSubCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\commands\\subcommands;\n\nuse CortexPE\\Commando\\BaseSubCommand;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse jojoe77777\\FormAPI\\SimpleForm;\nuse pocketmine\\command\\CommandSender;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass AboutSubCommand extends BaseSubCommand\n{\n    /** @var PiggyCustomEnchants */\n    protected $plugin;\n\n    public function onRun(CommandSender $sender, string $aliasUsed, array $args): void\n    {\n        $message = TextFormat::GREEN . \"PiggyCustomEnchants version \" . TextFormat::GOLD . $this->plugin->getDescription()->getVersion() . TextFormat::EOL .\n            TextFormat::GREEN . \"PiggyCustomEnchants is a versatile custom enchantments plugin developed by DaPigGuy (MCPEPIG) and Aericio.\" . TextFormat::EOL .\n            \"More information about our plugin can be found at \" . TextFormat::GOLD . \"https://piggydocs.aericio.net/\" . TextFormat::GREEN . \".\" . TextFormat::EOL .\n            TextFormat::GRAY . \"Copyright 2017 DaPigGuy; Licensed under the Apache License.\";\n        if ($sender instanceof Player && $this->plugin->areFormsEnabled()) {\n            $form = new SimpleForm(function (Player $player, ?int $data): void {\n                if ($data !== null) $this->plugin->getServer()->dispatchCommand($player, \"ce\");\n            });\n            $form->setTitle(TextFormat::GREEN . \"About PiggyCustomEnchants\");\n            $form->setContent($message);\n            $form->addButton(\"Back\");\n            $sender->sendForm($form);\n            return;\n        }\n        $sender->sendMessage($message);\n    }\n\n    public function prepare(): void\n    {\n        $this->setPermission(\"piggycustomenchants.command.ce.about\");\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/commands/subcommands/EnchantSubCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\commands\\subcommands;\n\nuse CortexPE\\Commando\\args\\IntegerArgument;\nuse CortexPE\\Commando\\args\\RawStringArgument;\nuse CortexPE\\Commando\\BaseSubCommand;\nuse CortexPE\\Commando\\exception\\ArgumentOrderException;\nuse DaPigGuy\\PiggyCustomEnchants\\CustomEnchantManager;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\Utils;\nuse jojoe77777\\FormAPI\\CustomForm;\nuse pocketmine\\command\\CommandSender;\nuse pocketmine\\item\\enchantment\\EnchantmentInstance;\nuse pocketmine\\item\\ItemIds;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\nuse Ramsey\\Uuid\\Uuid;\n\nclass EnchantSubCommand extends BaseSubCommand\n{\n    /** @var PiggyCustomEnchants */\n    protected $plugin;\n\n    public function onRun(CommandSender $sender, string $aliasUsed, array $args): void\n    {\n        if ($sender instanceof Player && $this->plugin->areFormsEnabled() && !isset($args[\"enchantment\"])) {\n            $this->onRunForm($sender, $aliasUsed, $args);\n            return;\n        }\n        if ((!$sender instanceof Player && empty($args[\"player\"])) || !isset($args[\"enchantment\"])) {\n            $sender->sendMessage(\"Usage: /ce enchant <enchantment> <level> <player>\");\n            return;\n        }\n        $args[\"level\"] = empty($args[\"level\"]) ? 1 : $args[\"level\"];\n        if (!is_int($args[\"level\"])) {\n            $sender->sendMessage(TextFormat::RED . \"Enchantment level must be an integer\");\n            return;\n        }\n        $target = empty($args[\"player\"]) ? $sender : $this->plugin->getServer()->getPlayerByPrefix($args[\"player\"]);\n        if (!$target instanceof Player) {\n            $sender->sendMessage(TextFormat::RED . \"Invalid player.\");\n            return;\n        }\n        $enchant = CustomEnchantManager::getEnchantmentByName($args[\"enchantment\"]);\n        if ($enchant === null) {\n            $sender->sendMessage(TextFormat::RED . \"Invalid enchantment.\");\n            return;\n        }\n        $item = $target->getInventory()->getItemInHand();\n        if (!$sender->hasPermission(\"piggycustomenchants.overridecheck\")) {\n            if (!Utils::itemMatchesItemType($item, $enchant->getItemType())) {\n                $sender->sendMessage(TextFormat::RED . \"The item is not compatible with this enchant.\");\n                return;\n            }\n            if ($args[\"level\"] > $enchant->getMaxLevel()) {\n                $sender->sendMessage(TextFormat::RED . \"The max level is \" . $enchant->getMaxLevel() . \".\");\n                return;\n            }\n            if ($item->getCount() > 1) {\n                $sender->sendMessage(TextFormat::RED . \"You can only enchant one item at a time.\");\n                return;\n            }\n            if (!Utils::checkEnchantIncompatibilities($item, $enchant)) {\n                $sender->sendMessage(TextFormat::RED . \"This enchant is not compatible with another enchant.\");\n                return;\n            }\n        }\n        if ($item->getId() === ItemIds::ENCHANTED_BOOK || $item->getId() === ItemIds::BOOK) {\n            $item->getNamedTag()->setString(\"PiggyCEBookUUID\", Uuid::uuid4()->toString());\n        }\n        $item->addEnchantment(new EnchantmentInstance($enchant, $args[\"level\"]));\n        $sender->sendMessage(TextFormat::GREEN . \"Item successfully enchanted.\");\n        $target->getInventory()->setItemInHand($item);\n    }\n\n    public function onRunForm(CommandSender $sender, string $aliasUsed, array $args): void\n    {\n        if ($sender instanceof Player) {\n            $form = new CustomForm(function (Player $player, ?array $data): void {\n                if ($data !== null) {\n                    $enchant = is_numeric($data[0]) ? CustomEnchantManager::getEnchantment((int)$data[0]) : CustomEnchantManager::getEnchantmentByName($data[0]);\n                    if ($enchant == null) {\n                        Utils::errorForm($player, TextFormat::RED . \"Invalid enchantment.\");\n                        return;\n                    }\n                    $target = $this->plugin->getServer()->getPlayerByPrefix($data[2]);\n                    if (!$target instanceof Player) {\n                        Utils::errorForm($player, TextFormat::RED . \"Invalid player.\");\n                        return;\n                    }\n                    $item = $target->getInventory()->getItemInHand();\n                    if (!$player->hasPermission(\"piggycustomenchants.overridecheck\")) {\n                        if (!Utils::itemMatchesItemType($item, $enchant->getItemType())) {\n                            Utils::errorForm($player, TextFormat::RED . \"The item is not compatible with this enchant.\");\n                            return;\n                        }\n                        if ($data[1] > $enchant->getMaxLevel()) {\n                            Utils::errorForm($player, TextFormat::RED . \"The max level is \" . $enchant->getMaxLevel() . \".\");\n                            return;\n                        }\n                        if (($enchantmentInstance = $item->getEnchantment($enchant)) !== null && $enchantmentInstance->getLevel() > $data[1]) {\n                            Utils::errorForm($player, TextFormat::RED . \"The enchant has already been applied with a higher level on the item.\");\n                            return;\n                        }\n                        if ($item->getCount() > 1) {\n                            Utils::errorForm($player, TextFormat::RED . \"You can only enchant one item at a time.\");\n                            return;\n                        }\n                        if (!Utils::checkEnchantIncompatibilities($item, $enchant)) {\n                            Utils::errorForm($player, TextFormat::RED . \"This enchant is not compatible with another enchant.\");\n                            return;\n                        }\n                    }\n                    if ($item->getId() === ItemIds::ENCHANTED_BOOK || $item->getId() === ItemIds::BOOK) {\n                        $item->getNamedTag()->setString(\"PiggyCEBookUUID\", Uuid::uuid4()->toString());\n                    }\n                    $item->addEnchantment(new EnchantmentInstance($enchant, (int)$data[1]));\n                    $player->sendMessage(TextFormat::GREEN . \"Item successfully enchanted.\");\n                    $target->getInventory()->setItemInHand($item);\n                }\n            });\n            $form->setTitle(TextFormat::GREEN . \"Apply Custom Enchantment\");\n            $form->addInput(\"Enchantment\");\n            $form->addInput(\"Level\", \"\", \"1\");\n            $form->addInput(\"Player\", \"\", $sender->getName());\n            $sender->sendForm($form);\n        }\n    }\n\n    /**\n     * @throws ArgumentOrderException\n     */\n    public function prepare(): void\n    {\n        $this->setPermission(\"piggycustomenchants.command.ce.enchant\");\n        $this->registerArgument(0, new RawStringArgument(\"enchantment\", true));\n        $this->registerArgument(1, new IntegerArgument(\"level\", true));\n        $this->registerArgument(2, new RawStringArgument(\"player\", true));\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/commands/subcommands/InfoSubCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\commands\\subcommands;\n\nuse CortexPE\\Commando\\args\\RawStringArgument;\nuse CortexPE\\Commando\\BaseSubCommand;\nuse CortexPE\\Commando\\exception\\ArgumentOrderException;\nuse DaPigGuy\\PiggyCustomEnchants\\CustomEnchantManager;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\Utils;\nuse jojoe77777\\FormAPI\\CustomForm;\nuse jojoe77777\\FormAPI\\SimpleForm;\nuse pocketmine\\command\\CommandSender;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass InfoSubCommand extends BaseSubCommand\n{\n    /** @var PiggyCustomEnchants */\n    protected $plugin;\n\n    public function onRun(CommandSender $sender, string $aliasUsed, array $args): void\n    {\n        if ($sender instanceof Player && $this->plugin->areFormsEnabled()) {\n            if (isset($args[\"enchantment\"])) {\n                $enchantment = CustomEnchantManager::getEnchantmentByName($args[\"enchantment\"]);\n                if ($enchantment === null) {\n                    Utils::errorForm($sender, TextFormat::RED . \"Invalid enchantment.\");\n                    return;\n                }\n                $this->showInfo($sender, $enchantment);\n                return;\n            }\n            $form = new CustomForm(function (Player $player, ?array $data) {\n                if ($data !== null) {\n                    $enchantment = CustomEnchantManager::getEnchantmentByName($data[0]);\n                    if ($enchantment === null) {\n                        Utils::errorForm($player, TextFormat::RED . \"Invalid enchantment.\");\n                        return;\n                    }\n                    $this->showInfo($player, $enchantment);\n                }\n            });\n            $form->setTitle(TextFormat::GREEN . \"Custom Enchant Info\");\n            $form->addInput(\"Enchantment\");\n            $sender->sendForm($form);\n            return;\n        }\n        if (!isset($args[\"enchantment\"])) {\n            $sender->sendMessage(\"/ce info <enchantment>\");\n            return;\n        }\n        $enchantment = CustomEnchantManager::getEnchantmentByName($args[\"enchantment\"]);\n        if ($enchantment === null) {\n            $sender->sendMessage(TextFormat::RED . \"Invalid enchantment.\");\n            return;\n        }\n        $sender->sendMessage(TextFormat::GREEN . $enchantment->getDisplayName() . TextFormat::EOL . TextFormat::RESET . \"ID: \" . $enchantment->getId() . TextFormat::EOL . \"Description: \" . $enchantment->getDescription() . TextFormat::EOL . \"Type: \" . Utils::TYPE_NAMES[$enchantment->getItemType()] . TextFormat::EOL . \"Rarity: \" . Utils::RARITY_NAMES[$enchantment->getRarity()] . TextFormat::EOL . \"Max Level: \" . $enchantment->getMaxLevel());\n    }\n\n    public function showInfo(Player $player, CustomEnchant $enchantment): void\n    {\n        $infoForm = new SimpleForm(function (Player $player, ?int $data): void {\n            if ($data !== null) $this->plugin->getServer()->dispatchCommand($player, \"ce\");\n        });\n        $infoForm->setTitle(TextFormat::GREEN . $enchantment->getDisplayName() . \" Enchantment\");\n        $infoForm->setContent(TextFormat::GREEN . $enchantment->getDisplayName() . TextFormat::EOL . TextFormat::RESET . \"ID: \" . $enchantment->getId() . TextFormat::EOL . \"Description: \" . $enchantment->getDescription() . TextFormat::EOL . \"Type: \" . Utils::TYPE_NAMES[$enchantment->getItemType()] . TextFormat::EOL . \"Rarity: \" . Utils::RARITY_NAMES[$enchantment->getRarity()] . TextFormat::EOL . \"Max Level: \" . $enchantment->getMaxLevel());\n        $infoForm->addButton(\"Back\");\n        $player->sendForm($infoForm);\n    }\n\n    /**\n     * @throws ArgumentOrderException\n     */\n    public function prepare(): void\n    {\n        $this->setPermission(\"piggycustomenchants.command.ce.list\");\n        $this->registerArgument(0, new RawStringArgument(\"enchantment\", true));\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/commands/subcommands/ListSubCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\commands\\subcommands;\n\nuse CortexPE\\Commando\\BaseSubCommand;\nuse DaPigGuy\\PiggyCustomEnchants\\CustomEnchantManager;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\Utils;\nuse jojoe77777\\FormAPI\\SimpleForm;\nuse pocketmine\\command\\CommandSender;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass ListSubCommand extends BaseSubCommand\n{\n    /** @var PiggyCustomEnchants */\n    protected $plugin;\n\n    public function onRun(CommandSender $sender, string $aliasUsed, array $args): void\n    {\n        if ($sender instanceof Player && $this->plugin->areFormsEnabled()) {\n            $this->sendTypesForm($sender);\n            return;\n        }\n        $sender->sendMessage($this->getCustomEnchantList());\n    }\n\n    /**\n     * @return CustomEnchant[][]\n     */\n    public function getEnchantmentsByType(): array\n    {\n        $enchantmentsByType = [];\n        foreach (CustomEnchantManager::getEnchantments() as $enchantment) {\n            if (!isset($enchantmentsByType[$enchantment->getItemType()])) $enchantmentsByType[$enchantment->getItemType()] = [];\n            $enchantmentsByType[$enchantment->getItemType()][] = $enchantment;\n        }\n        return array_map(function (array $typeEnchants) {\n            uasort($typeEnchants, function (CustomEnchant $a, CustomEnchant $b) {\n                return strcmp($a->getDisplayName(), $b->getDisplayName());\n            });\n            return $typeEnchants;\n        }, $enchantmentsByType);\n    }\n\n    public function getCustomEnchantList(): string\n    {\n        $enchantmentsByType = $this->getEnchantmentsByType();\n        $listString = \"\";\n        foreach (Utils::TYPE_NAMES as $type => $name) {\n            if (isset($enchantmentsByType[$type])) {\n                $listString .= TextFormat::EOL . TextFormat::GREEN . TextFormat::BOLD . Utils::TYPE_NAMES[$type] . TextFormat::EOL . TextFormat::RESET;\n                $listString .= implode(\", \", array_map(function (CustomEnchant $enchant) {\n                    return $enchant->getDisplayName();\n                }, $enchantmentsByType[$type]));\n            }\n        }\n        return $listString;\n    }\n\n    public function sendTypesForm(Player $player): void\n    {\n        $enchantmentsByType = $this->getEnchantmentsByType();\n        $form = new SimpleForm(function (Player $player, ?int $data) use ($enchantmentsByType): void {\n            if ($data !== null) {\n                if ($data === count($enchantmentsByType)) {\n                    $player->getServer()->dispatchCommand($player, \"ce\");\n                    return;\n                }\n                $type = array_keys($enchantmentsByType)[$data];\n                $this->sendEnchantsForm($player, $type);\n            }\n        });\n        $form->setTitle(TextFormat::GREEN . \"Custom Enchants List\");\n        foreach ($enchantmentsByType as $type => $enchantments) {\n            $form->addButton(Utils::TYPE_NAMES[$type]);\n        }\n        $form->addButton(\"Back\");\n        $player->sendForm($form);\n    }\n\n    public function sendEnchantsForm(Player $player, int $type): void\n    {\n        $enchantmentsByType = $this->getEnchantmentsByType();\n        $enchantForm = new SimpleForm(function (Player $player, ?int $data) use ($type, $enchantmentsByType): void {\n            if ($data !== null) {\n                if ($data === count($enchantmentsByType[$type])) {\n                    $player->getServer()->dispatchCommand($player, \"ce list\");\n                    return;\n                }\n                $infoForm = new SimpleForm(function (Player $player, ?int $data) use ($type): void {\n                    if ($data !== null) $this->sendEnchantsForm($player, $type);\n                });\n                /** @var CustomEnchant $selectedEnchantment */\n                $selectedEnchantment = array_values($enchantmentsByType[$type])[$data];\n                $infoForm->setTitle(TextFormat::GREEN . $selectedEnchantment->getDisplayName() . \" Enchantment\");\n                $infoForm->setContent(TextFormat::GREEN . $selectedEnchantment->getDisplayName() . TextFormat::EOL . TextFormat::RESET . \"ID: \" . $selectedEnchantment->getId() . TextFormat::EOL . \"Description: \" . $selectedEnchantment->getDescription() . TextFormat::EOL . \"Type: \" . Utils::TYPE_NAMES[$type] . TextFormat::EOL . \"Rarity: \" . Utils::RARITY_NAMES[$selectedEnchantment->getRarity()] . TextFormat::EOL . \"Max Level: \" . $selectedEnchantment->getMaxLevel());\n                $infoForm->addButton(\"Back\");\n                $player->sendForm($infoForm);\n            }\n        });\n        $enchantForm->setTitle(TextFormat::GREEN . Utils::TYPE_NAMES[$type] . \" Enchants\");\n        foreach ($enchantmentsByType[$type] as $enchantment) {\n            $enchantForm->addButton($enchantment->getDisplayName());\n        }\n        $enchantForm->addButton(\"Back\");\n        $player->sendForm($enchantForm);\n    }\n\n    public function prepare(): void\n    {\n        $this->setPermission(\"piggycustomenchants.command.ce.list\");\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/commands/subcommands/NBTSubCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\commands\\subcommands;\n\nuse CortexPE\\Commando\\BaseSubCommand;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse pocketmine\\command\\CommandSender;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass NBTSubCommand extends BaseSubCommand\n{\n    /** @var PiggyCustomEnchants */\n    protected $plugin;\n\n    public function onRun(CommandSender $sender, string $aliasUsed, array $args): void\n    {\n        if ($sender instanceof Player) {\n            $sender->sendMessage($sender->getInventory()->getItemInHand()->getNamedTag()->toString());\n            return;\n        }\n        $sender->sendMessage(TextFormat::RED . \"Please use this in-game.\");\n    }\n\n    public function prepare(): void\n    {\n        $this->setPermission(\"piggycustomenchants.command.ce.nbt\");\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/commands/subcommands/RemoveSubCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\commands\\subcommands;\n\nuse CortexPE\\Commando\\args\\RawStringArgument;\nuse CortexPE\\Commando\\BaseSubCommand;\nuse CortexPE\\Commando\\exception\\ArgumentOrderException;\nuse DaPigGuy\\PiggyCustomEnchants\\CustomEnchantManager;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\Utils;\nuse jojoe77777\\FormAPI\\CustomForm;\nuse pocketmine\\command\\CommandSender;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass RemoveSubCommand extends BaseSubCommand\n{\n    /** @var PiggyCustomEnchants */\n    protected $plugin;\n\n    public function onRun(CommandSender $sender, string $aliasUsed, array $args): void\n    {\n        if ($sender instanceof Player && $this->plugin->areFormsEnabled() && !isset($args[\"enchantment\"])) {\n            $this->onRunForm($sender, $aliasUsed, $args);\n            return;\n        }\n        if ((!$sender instanceof Player && empty($args[\"player\"])) || !isset($args[\"enchantment\"])) {\n            $sender->sendMessage(\"Usage: /ce remove <enchantment> <player>\");\n            return;\n        }\n        $target = empty($args[\"player\"]) ? $sender : $this->plugin->getServer()->getPlayerByPrefix($args[\"player\"]);\n        if (!$target instanceof Player) {\n            $sender->sendMessage(TextFormat::RED . \"Invalid player.\");\n            return;\n        }\n        $enchant = CustomEnchantManager::getEnchantmentByName($args[\"enchantment\"]);\n        if ($enchant === null) {\n            $sender->sendMessage(TextFormat::RED . \"Invalid enchantment.\");\n            return;\n        }\n        $item = $target->getInventory()->getItemInHand();\n        if ($item->getEnchantment($enchant) === null) {\n            $sender->sendMessage(TextFormat::RED . \"Item does not have specified enchantment.\");\n            return;\n        }\n        $item->removeEnchantment($enchant);\n        $sender->sendMessage(TextFormat::GREEN . \"Enchantment successfully removed.\");\n        $target->getInventory()->setItemInHand($item);\n    }\n\n    public function onRunForm(CommandSender $sender, string $aliasUsed, array $args): void\n    {\n        if ($sender instanceof Player) {\n            $form = new CustomForm(function (Player $player, ?array $data): void {\n                if ($data !== null) {\n                    $enchant = is_numeric($data[0]) ? CustomEnchantManager::getEnchantment((int)$data[0]) : CustomEnchantManager::getEnchantmentByName($data[0]);\n                    if ($enchant == null) {\n                        Utils::errorForm($player, TextFormat::RED . \"Invalid enchantment.\");\n                        return;\n                    }\n                    $target = $this->plugin->getServer()->getPlayerByPrefix($data[1]);\n                    if (!$target instanceof Player) {\n                        Utils::errorForm($player, TextFormat::RED . \"Invalid player.\");\n                        return;\n                    }\n                    $item = $target->getInventory()->getItemInHand();\n                    if ($item->getEnchantment($enchant) === null) {\n                        $player->sendMessage(TextFormat::RED . \"Item does not have specified enchantment.\");\n                        return;\n                    }\n                    $item->removeEnchantment($enchant);\n                    $target->sendMessage(TextFormat::GREEN . \"Enchantment successfully removed.\");\n                    $target->getInventory()->setItemInHand($item);\n                }\n            });\n            $form->setTitle(TextFormat::GREEN . \"Remove Custom Enchantment\");\n            $form->addInput(\"Enchantment\");\n            $form->addInput(\"Player\", \"\", $sender->getName());\n            $sender->sendForm($form);\n        }\n    }\n\n    /**\n     * @throws ArgumentOrderException\n     */\n    protected function prepare(): void\n    {\n        $this->setPermission(\"piggycustomenchants.command.ce.remove\");\n        $this->registerArgument(0, new RawStringArgument(\"enchantment\", true));\n        $this->registerArgument(1, new RawStringArgument(\"player\", true));\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/CustomEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants;\n\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\Utils;\nuse pocketmine\\item\\enchantment\\Enchantment;\nuse pocketmine\\item\\enchantment\\ItemFlags;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\player\\Player;\nuse ReflectionClass;\n\nclass CustomEnchant extends Enchantment\n{\n    public string $name = \"\";\n    public int $rarity = Rarity::RARE;\n    public int $maxLevel = 5;\n    private string $displayName;\n    public string $description;\n    public array $extraData;\n    public int $cooldownDuration;\n    public int $chance;\n\n    public int $usageType = CustomEnchant::TYPE_HAND;\n    public int $itemType = CustomEnchant::ITEM_TYPE_WEAPON;\n\n    /** @var int[] */\n    public array $cooldown;\n\n    const TYPE_HAND = 0;\n    const TYPE_ANY_INVENTORY = 1;\n    const TYPE_INVENTORY = 2;\n    const TYPE_ARMOR_INVENTORY = 3;\n    const TYPE_HELMET = 4;\n    const TYPE_CHESTPLATE = 5;\n    const TYPE_LEGGINGS = 6;\n    const TYPE_BOOTS = 7;\n\n    const ITEM_TYPE_GLOBAL = 0;\n    const ITEM_TYPE_DAMAGEABLE = 1;\n    const ITEM_TYPE_WEAPON = 2;\n    const ITEM_TYPE_SWORD = 3;\n    const ITEM_TYPE_BOW = 4;\n    const ITEM_TYPE_TOOLS = 5;\n    const ITEM_TYPE_PICKAXE = 6;\n    const ITEM_TYPE_AXE = 7;\n    const ITEM_TYPE_SHOVEL = 8;\n    const ITEM_TYPE_HOE = 9;\n    const ITEM_TYPE_ARMOR = 10;\n    const ITEM_TYPE_HELMET = 11;\n    const ITEM_TYPE_CHESTPLATE = 12;\n    const ITEM_TYPE_LEGGINGS = 13;\n    const ITEM_TYPE_BOOTS = 14;\n    const ITEM_TYPE_COMPASS = 15;\n\n    public function __construct(protected PiggyCustomEnchants $plugin, public int $id)\n    {\n        $this->rarity = array_flip(Utils::RARITY_NAMES)[ucfirst(strtolower($plugin->getEnchantmentData($this->name, \"rarities\", Utils::RARITY_NAMES[$this->rarity])))];\n        $this->maxLevel = (int)$plugin->getEnchantmentData($this->name, \"max_levels\", $this->maxLevel);\n        $this->displayName = (string)$plugin->getEnchantmentData($this->name, \"display_names\", $this->displayName ?? $this->name);\n        $this->description = (string)$plugin->getEnchantmentData($this->name, \"descriptions\", $this->description ?? \"\");\n        $this->extraData = $plugin->getEnchantmentData($this->name, \"extra_data\", $this->getDefaultExtraData());\n        $this->cooldownDuration = (int)$plugin->getEnchantmentData($this->name, \"cooldowns\", $this->cooldownDuration ?? 0);\n        $this->chance = (int)$plugin->getEnchantmentData($this->name, \"chances\", $this->chance ?? 100);\n        foreach ($this->getDefaultExtraData() as $key => $value) {\n            if (!isset($this->extraData[$key])) {\n                $this->extraData[$key] = $value;\n                $plugin->setEnchantmentData($this->name, \"extra_data\", $this->extraData);\n            }\n        }\n        if (!Utils::isCoolKid($plugin->getDescription())) $this->id = (int)array_rand(array_flip((new ReflectionClass(CustomEnchantIds::class))->getConstants()));\n        parent::__construct($this->name, $this->rarity, ItemFlags::ALL, ItemFlags::ALL, $this->maxLevel);\n    }\n\n    public function getId(): int\n    {\n        return $this->id;\n    }\n\n    public function getDisplayName(): string\n    {\n        return $this->displayName;\n    }\n\n    public function getDescription(): string\n    {\n        return $this->description;\n    }\n\n    public function getExtraData(): array\n    {\n        return $this->extraData;\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [];\n    }\n\n    public function getUsageType(): int\n    {\n        return $this->usageType;\n    }\n\n    public function getItemType(): int\n    {\n        return $this->itemType;\n    }\n\n    public function getPriority(): int\n    {\n        return 1;\n    }\n\n    public function canReact(): bool\n    {\n        return false;\n    }\n\n    public function canTick(): bool\n    {\n        return false;\n    }\n\n    public function canToggle(): bool\n    {\n        return false;\n    }\n\n    public function getCooldown(Player $player): int\n    {\n        return ($this->cooldown[$player->getName()] ?? time()) - time();\n    }\n\n    public function setCooldown(Player $player, int $cooldown): void\n    {\n        $this->cooldown[$player->getName()] = time() + $cooldown;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/CustomEnchantIds.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants;\n\nclass CustomEnchantIds\n{\n    /**\n     * Global\n     */\n    const AUTOREPAIR = 108;\n    const SOULBOUND = 118;\n\n    /**\n     * Weapons\n     */\n    const AERIAL = 114;\n    const BACKSTAB = 122;\n    const BLESSED = 120;\n    const BLIND = 101;\n    const CHARGE = 113;\n    const CRIPPLE = 109;\n    const DEATHBRINGER = 102;\n    const DEEPWOUNDS = 112;\n    const DISARMING = 117;\n    const DISARMOR = 121;\n    const GOOEY = 103;\n    const HALLUCINATION = 119;\n    //const HEADLESS = 116;\n    //const ICEASPECT = 106;\n    const LIFESTEAL = 100;\n    const LIGHTNING = 123;\n    const LUCKYCHARM = 124;\n    const POISON = 104;\n    //const SHOCKWAVE = 107;\n    const VAMPIRE = 111;\n    const WITHER = 115;\n\n    /**\n     * Sword\n     */\n\n    /**\n     * Bows\n     */\n    const AUTOAIM = 306;\n    const BLAZE = 311;\n    const BOMBARDMENT = 300;\n    const BOUNTYHUNTER = 309;\n    //const FIREWORK = 302;\n    const GRAPPLING = 313;\n    const HEADHUNTER = 312;\n    const HEALING = 310;\n    const HOMING = 316;\n    const MISSILE = 315;\n    const MOLOTOV = 304;\n    const PARALYZE = 303;\n    const PIERCING = 307;\n    const PORKIFIED = 314;\n    const SHUFFLE = 308;\n    const VOLLEY = 305;\n    const WITHERSKULL = 301;\n\n    /**\n     * Tools\n     */\n    const DRILLER = 206;\n    const ENERGIZING = 202;\n    const EXPLOSIVE = 200;\n    const HASTE = 207;\n    const JACKPOT = 212;\n    const OXYGENATE = 211;\n    const QUICKENING = 203;\n    const SMELTING = 201;\n    const TELEPATHY = 205;\n\n    /**\n     * Pickaxes\n     */\n\n    /**\n     * Axes\n     */\n    const LUMBERJACK = 204;\n\n    /**\n     * Shovels\n     */\n\n    /**\n     * Hoes\n     */\n    const FARMER = 209;\n    const FERTILIZER = 208;\n    const HARVEST = 210;\n\n    /**\n     * Armor\n     */\n    const MOLTEN = 400;\n    const ENLIGHTED = 401;\n    const HARDENED = 402;\n    const POISONED = 403;\n    const FROZEN = 404;\n    const OBSIDIANSHIELD = 405;\n    const REVULSION = 406;\n    const SELFDESTRUCT = 407;\n    const CURSED = 408;\n    const ENDERSHIFT = 409;\n    const DRUNK = 410;\n    const BERSERKER = 411;\n    const CLOAKING = 412;\n    const REVIVE = 413;\n    const SHRINK = 414;\n    const GROW = 415;\n    const CACTUS = 416;\n    const ANTIKNOCKBACK = 417;\n    const FORCEFIELD = 418;\n    const OVERLOAD = 419;\n    const ARMORED = 420;\n    const TANK = 421;\n    const HEAVY = 422;\n    const SHIELDED = 423;\n    const POISONOUSCLOUD = 424;\n\n    /**\n     * Helmet\n     */\n    const ANTITOXIN = 604;\n    const FOCUSED = 603;\n    const GLOWING = 601;\n    const IMPLANTS = 600;\n    const MEDITATION = 602;\n\n    /**\n     * Chestplate\n     */\n    const CHICKEN = 801;\n    const ENRAGED = 804;\n    const PARACHUTE = 800;\n    const PROWL = 802;\n    const SPIDER = 803;\n    const VACUUM = 805;\n\n    /**\n     * Leggings\n     */\n\n    /**\n     * Boots\n     */\n    const GEARS = 500;\n    const JETPACK = 503;\n    const MAGMAWALKER = 504;\n    const SPRINGS = 501;\n    const STOMP = 502;\n\n    /**\n     * Compass\n     */\n    const RADAR = 700;\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/ReactiveEnchantment.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\ReactiveTrait;\n\nclass ReactiveEnchantment extends CustomEnchant\n{\n    use ReactiveTrait;\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/TickingEnchantment.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\TickingTrait;\n\nclass TickingEnchantment extends CustomEnchant\n{\n    use TickingTrait;\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/ToggleableEnchantment.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\ToggleTrait;\n\nclass ToggleableEnchantment extends CustomEnchant\n{\n    use ToggleTrait;\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/AntiKnockbackEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass AntiKnockbackEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Anti Knockback\";\n    public int $maxLevel = 1;\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $stack = $stack > 4 ? 4 : $stack;\n            $event->setKnockBack($event->getKnockBack() * (4 - $stack) / (5 - $stack));\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/ArmoredEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\item\\Sword;\nuse pocketmine\\player\\Player;\n\nclass ArmoredEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Armored\";\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"absorbedDamageMultiplier\" => 0.2];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $damager = $event->getDamager();\n            if ($damager instanceof Player) {\n                if ($damager->getInventory()->getItemInHand() instanceof Sword) {\n                    $event->setModifier(-($event->getFinalDamage() * $this->extraData[\"absorbedDamageMultiplier\"] * $level), CustomEnchantIds::ARMORED);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/AttackerDeterrentEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse pocketmine\\entity\\effect\\Effect;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\Living;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass AttackerDeterrentEnchant extends ReactiveEnchantment\n{\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    /**\n     * @param Effect[] $effects\n     * @param int[] $durationMultiplier\n     * @param int[] $amplifierMultiplier\n     */\n    public function __construct(PiggyCustomEnchants $plugin, int $id, string $name, private array $effects, private array $durationMultiplier, private array $amplifierMultiplier, int $rarity = Rarity::RARE)\n    {\n        $this->name = $name;\n        $this->rarity = $rarity;\n        parent::__construct($plugin, $id);\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"durationMultipliers\" => $this->durationMultiplier, \"amplifierMultipliers\" => $this->amplifierMultiplier];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $damager = $event->getDamager();\n            if ($damager instanceof Living) {\n                foreach ($this->effects as $key => $effect) {\n                    $damager->getEffects()->add(new EffectInstance($effect, $this->extraData[\"durationMultipliers\"][$key] * $level, $this->extraData[\"amplifierMultipliers\"][$key] * $level));\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/BerserkerEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\event\\entity\\EntityDamageEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass BerserkerEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Berserker\";\n    public int $cooldownDuration = 300;\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getReagent(): array\n    {\n        return [EntityDamageEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"minimumHealth\" => 4, \"effectDurationMultiplier\" => 200, \"effectAmplifierBase\" => 3, \"effectAmplifierMultiplier\" => 1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageEvent) {\n            if ($player->getHealth() - $event->getFinalDamage() <= $this->extraData[\"minimumHealth\"]) {\n                if (!$player->getEffects()->has(VanillaEffects::STRENGTH())) {\n                    $effect = new EffectInstance(VanillaEffects::STRENGTH(), $this->extraData[\"effectDurationMultiplier\"] * $level, $level * $this->extraData[\"effectAmplifierMultiplier\"] + $this->extraData[\"effectAmplifierBase\"], false);\n                    $player->getEffects()->add($effect);\n                }\n                $player->sendMessage(\"Your bloodloss makes your stronger!\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/CactusEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\TickingEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\AllyChecks;\nuse pocketmine\\entity\\Living;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\entity\\EntityDamageEvent;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass CactusEnchant extends TickingEnchantment\n{\n    public string $name = \"Cactus\";\n    public int $maxLevel = 1;\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getTickingInterval(): int\n    {\n        return 10;\n    }\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        foreach ($player->getWorld()->getNearbyEntities($player->getBoundingBox()->expandedCopy(1, 0, 1), $player) as $entity) {\n            if ($entity instanceof Living && !AllyChecks::isAlly($player, $entity)) {\n                $ev = new EntityDamageByEntityEvent($player, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);\n                $entity->attack($ev);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/CloakingEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass CloakingEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Cloaking\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $cooldownDuration = 10;\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"durationMultiplier\" => 60];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $player->getEffects()->add(new EffectInstance(VanillaEffects::INVISIBILITY(), $this->extraData[\"durationMultiplier\"] * $level, 0, false));\n            $player->sendMessage(TextFormat::DARK_GRAY . \"You have become invisible!\");\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/EndershiftEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\event\\entity\\EntityDamageEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass EndershiftEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Endershift\";\n    public int $cooldownDuration = 300;\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getReagent(): array\n    {\n        return [EntityDamageEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"speedDurationMultiplier\" => 200, \"speedBaseAmplifier\" => 3, \"speedAmplifierMultiplier\" => 1, \"strengthDurationMultiplier\" => 200, \"strengthBaseAmplifier\" => 3, \"strengthAmplifierMultiplier\" => 1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageEvent) {\n            if ($player->getHealth() - $event->getFinalDamage() <= 4) {\n                if (!$player->getEffects()->has(VanillaEffects::SPEED())) {\n                    $effect = new EffectInstance(VanillaEffects::SPEED(), $this->extraData[\"speedDurationMultiplier\"] * $level, $level * $this->extraData[\"speedAmplifierMultiplier\"] + $this->extraData[\"speedBaseAmplifier\"], false);\n                    $player->getEffects()->add($effect);\n                }\n                if (!$player->getEffects()->has(VanillaEffects::ABSORPTION())) {\n                    $effect = new EffectInstance(VanillaEffects::ABSORPTION(), $this->extraData[\"strengthDurationMultiplier\"] * $level, $level * $this->extraData[\"strengthAmplifierMultiplier\"] + $this->extraData[\"strengthBaseAmplifier\"], false);\n                    $player->getEffects()->add($effect);\n                }\n                $player->sendMessage(\"You feel a rush of energy coming from your armor!\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/EnlightedEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass EnlightedEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Enlighted\";\n    public int $rarity = Rarity::UNCOMMON;\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"durationMultiplier\" => 60, \"baseAmplifier\" => 0, \"amplifierMultiplier\" => 1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $player->getEffects()->add(new EffectInstance(VanillaEffects::REGENERATION(), $this->extraData[\"durationMultiplier\"] * $level, $level * $this->extraData[\"amplifierMultiplier\"] + $this->extraData[\"baseAmplifier\"], false));\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/ForcefieldEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ToggleableEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\TickingTrait;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\AllyChecks;\nuse pocketmine\\entity\\object\\ExperienceOrb;\nuse pocketmine\\entity\\object\\ItemEntity;\nuse pocketmine\\entity\\projectile\\Projectile;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\math\\Vector3;\nuse pocketmine\\player\\Player;\nuse pocketmine\\world\\particle\\EnchantmentTableParticle;\n\nclass ForcefieldEnchant extends ToggleableEnchantment\n{\n    use TickingTrait;\n\n    public string $name = \"Forcefield\";\n    public int $rarity = Rarity::MYTHIC;\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"radiusMultiplier\" => 0.75];\n    }\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        $forcefieldLevel = $this->getStack($player);\n        if ($forcefieldLevel > 0) {\n            $radius = $forcefieldLevel * $this->extraData[\"radiusMultiplier\"];\n            $entities = $player->getWorld()->getNearbyEntities($player->getBoundingBox()->expandedCopy($radius, $radius, $radius), $player);\n            foreach ($entities as $entity) {\n                if ($entity instanceof Projectile) {\n                    if ($entity->getOwningEntity() !== $player) $entity->setMotion($entity->getMotion()->multiply(-1));\n                } else {\n                    if (!$entity instanceof ItemEntity && !$entity instanceof ExperienceOrb && !AllyChecks::isAlly($player, $entity)) {\n                        $entity->setMotion(new Vector3($player->getPosition()->subtractVector($entity->getPosition())->normalize()->multiply(-0.75)->x, 0, $player->getPosition()->subtractVector($entity->getPosition())->normalize()->multiply(-0.75)->z));\n                    }\n                }\n            }\n            if ($player->getServer()->getTick() % 5 === 0) {\n                $diff = $radius / $forcefieldLevel;\n                for ($theta = 0; $theta <= 360; $theta += $diff) {\n                    $player->getWorld()->addParticle($player->getPosition()->add($radius * sin($theta), 0.5, $radius * cos($theta)), new EnchantmentTableParticle());\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/GrowEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ToggleableEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\ReactiveTrait;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\TickingTrait;\nuse pocketmine\\event\\Event;\nuse pocketmine\\event\\player\\PlayerToggleSneakEvent;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass GrowEnchant extends ToggleableEnchantment\n{\n    use ReactiveTrait {\n        onReaction as protected originalOnReaction;\n    }\n    use TickingTrait;\n\n    public string $name = \"Grow\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $cooldownDuration = 75;\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    /** @var Player[] */\n    public array $grew;\n    /** @var int[] */\n    public array $growPower;\n    /** @var bool[] */\n    public array $shiftCache;\n\n    public function getReagent(): array\n    {\n        return [PlayerToggleSneakEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"power\" => 60 * 20, \"base\" => 0.3, \"multiplier\" => 0.0125];\n    }\n\n    public function onReaction(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof PlayerToggleSneakEvent) {\n            $playerName = $player->getName();\n            if ($event->isSneaking()) {\n                if (!isset($this->shiftCache[$playerName])) {\n                    $this->originalOnReaction($player, $item, $inventory, $slot, $event, $level, $stack);\n                    if (isset($this->grew[$playerName])) $this->setCooldown($player, 0);\n                    $this->shiftCache[$playerName] = true;\n                } else {\n                    $player->sendTip(TextFormat::RED . \"Grow is still in cooldown: \" . $this->getCooldown($player) . \"s\");\n                }\n            } elseif (isset($this->shiftCache[$playerName])) {\n                unset($this->shiftCache[$playerName]);\n            }\n        }\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof PlayerToggleSneakEvent) {\n            $playerName = $player->getName();\n            if ($this->getArmorStack($player) === 4) {\n                if ($event->isSneaking()) {\n                    if ($stack - $level === 0) {\n                        if (isset($this->grew[$playerName])) {\n                            unset($this->grew[$playerName]);\n                            $player->setScale(1);\n                            $player->sendTip(TextFormat::RED . \"You have shrunk back to normal size.\");\n                        } else {\n                            $this->grew[$playerName] = $player;\n                            if (!isset($this->growPower[$playerName])) $this->growPower[$playerName] = $this->extraData[\"power\"];\n                            $player->setScale($player->getScale() + $this->extraData[\"base\"] + ($this->getStack($player) * $this->extraData[\"multiplier\"]));\n                            $player->sendTip(TextFormat::GREEN . \"You have grown. Sneak again to shrink back to normal size.\");\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        $playerName = $player->getName();\n        if (isset($this->grew[$playerName])) {\n            $this->growPower[$playerName]--;\n            $player->sendTip(TextFormat::GREEN . \"Grow power remaining: \" . $this->growPower[$playerName]);\n            if ($this->getArmorStack($player) < 4 || $this->growPower[$playerName] <= 0) {\n                unset($this->grew[$playerName]);\n                $this->setCooldown($player, $this->getCooldownDuration());\n                if ($this->growPower[$playerName] <= 0) $this->growPower[$playerName] = $this->extraData[\"power\"];\n                $player->setScale(1);\n                $player->sendTip(TextFormat::RED . \"You have shrunk back to normal size.\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/HeavyEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\item\\ItemIds;\nuse pocketmine\\player\\Player;\n\nclass HeavyEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Heavy\";\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"absorbedDamageMultiplier\" => 0.2];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $damager = $event->getDamager();\n            if ($damager instanceof Player) {\n                if ($damager->getInventory()->getItemInHand()->getId() === ItemIds::BOW) {\n                    $event->setModifier(-($event->getFinalDamage() * $this->extraData[\"absorbedDamageMultiplier\"] * $level), CustomEnchantIds::HEAVY);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/MoltenEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\entity\\Living;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass MoltenEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Molten\";\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"durationMultiplier\" => 3];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $damager = $event->getDamager();\n            if ($damager instanceof Living) {\n                $damager->setOnFire(($duration = $this->extraData[\"durationMultiplier\"] * $level) > 1638 ? 1638 : $duration);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/OverloadEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ToggleableEnchantment;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass OverloadEnchant extends ToggleableEnchantment\n{\n    public string $name = \"Overload\";\n    public int $rarity = Rarity::MYTHIC;\n    public int $maxLevel = 3;\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"multiplier\" => 2];\n    }\n\n    public function toggle(Player $player, Item $item, Inventory $inventory, int $slot, int $level, bool $toggle): void\n    {\n        $player->setMaxHealth($player->getMaxHealth() + $this->extraData[\"multiplier\"] * $level * ($toggle ? 1 : -1));\n        $player->setHealth($player->getHealth() * ($player->getMaxHealth() / ($player->getMaxHealth() - $this->extraData[\"multiplier\"] * $level * ($toggle ? 1 : -1))));\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/PoisonousCloudEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\TickingEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\AllyChecks;\nuse pocketmine\\color\\Color;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\entity\\Living;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\nuse pocketmine\\world\\particle\\DustParticle;\n\nclass PoisonousCloudEnchant extends TickingEnchantment\n{\n    public string $name = \"Poisonous Cloud\";\n    public int $maxLevel = 3;\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"radiusMultiplier\" => 3, \"durationMultiplier\" => 100, \"baseAmplifier\" => -1, \"amplifierMultiplier\" => 1];\n    }\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        $radius = $level * $this->extraData[\"radiusMultiplier\"];\n        foreach ($player->getWorld()->getEntities() as $entity) {\n            if ($entity !== $player && $entity instanceof Living && !AllyChecks::isAlly($player, $entity) && $entity->getPosition()->distance($player->getPosition()) <= $radius) {\n                $effect = new EffectInstance(VanillaEffects::POISON(), $level * $this->extraData[\"durationMultiplier\"], $level * $this->extraData[\"amplifierMultiplier\"] + $this->extraData[\"baseAmplifier\"], false);\n                $entity->getEffects()->add($effect);\n            }\n        }\n        if ($player->getServer()->getTick() % 20 === 0) {\n            for ($x = -$radius; $x <= $radius; $x += 0.25) {\n                for ($y = -$radius; $y <= $radius; $y += 0.25) {\n                    for ($z = -$radius; $z <= $radius; $z += 0.25) {\n                        $random = mt_rand(1, 800 * $level);\n                        if ($random === 800 * $level) {\n                            $player->getWorld()->addParticle($player->getPosition()->add($x, $y, $z), new DustParticle(new Color(34, 139, 34)));\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/ReviveEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\CustomEnchantManager;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\event\\entity\\EntityDamageEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Enchantment;\nuse pocketmine\\item\\enchantment\\EnchantmentInstance;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\nuse pocketmine\\world\\particle\\FlameParticle;\n\nclass ReviveEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Revive\";\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getReagent(): array\n    {\n        return [EntityDamageEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"nauseaDuration\" => 600, \"slownessDuration\" => 600];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageEvent) {\n            if ($event->getFinalDamage() >= $player->getHealth()) {\n                $level > 1 ? $item->addEnchantment(new EnchantmentInstance(CustomEnchantManager::getEnchantment(CustomEnchantIds::REVIVE), $level - 1)) : $item->removeEnchantment(CustomEnchantManager::getEnchantment(CustomEnchantIds::REVIVE));\n                $player->getArmorInventory()->setItem($slot, $item);\n\n                $player->getEffects()->clear();\n                $player->setHealth($player->getMaxHealth());\n                $player->getHungerManager()->setFood($player->getHungerManager()->getMaxFood());\n                $player->getXpManager()->setXpAndProgress(0, 0.0);\n\n                $effect = new EffectInstance(VanillaEffects::NAUSEA(), $this->extraData[\"nauseaDuration\"], 0, false);\n                $player->getEffects()->add($effect);\n                $effect = new EffectInstance(VanillaEffects::SLOWNESS(), $this->extraData[\"slownessDuration\"], 0, false);\n                $player->getEffects()->add($effect);\n\n                for ($i = $player->getPosition()->y; $i <= 256; $i += 0.25) {\n                    $player->getWorld()->addParticle($player->getPosition()->add(0, $i - $player->getPosition()->y, 0), new FlameParticle());\n                }\n                $player->sendTip(TextFormat::GREEN . \"You were revived.\");\n\n                foreach ($event->getModifiers() as $modifier => $damage) {\n                    $event->setModifier(0, $modifier);\n                }\n                $event->setBaseDamage(0);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/SelfDestructEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PiggyTNT;\nuse pocketmine\\event\\Event;\nuse pocketmine\\event\\player\\PlayerDeathEvent;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\math\\Vector3;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\Random;\n\nclass SelfDestructEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Self Destruct\";\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getReagent(): array\n    {\n        return [PlayerDeathEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"tntAmountMultiplier\" => 1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof PlayerDeathEvent) {\n            for ($i = 0; $i < $level * $this->extraData[\"tntAmountMultiplier\"]; $i++) {\n                $random = new Random();\n                $tnt = new PiggyTNT($player->getLocation(), null, $this->plugin->getConfig()->getNested(\"world-damage.self-destruct\", false));\n                $tnt->setFuse(40);\n                $tnt->setOwningEntity($player);\n                $tnt->setMotion(new Vector3($random->nextFloat() * 1.5 - 1, $random->nextFloat() * 1.5, $random->nextFloat() * 1.5 - 1));\n                $tnt->spawnToAll();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/ShieldedEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ToggleableEnchantment;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass ShieldedEnchant extends ToggleableEnchantment\n{\n    public string $name = \"Shielded\";\n    public int $maxLevel = 3;\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    /** @var EffectInstance[] */\n    private array $previousEffect;\n\n    public function toggle(Player $player, Item $item, Inventory $inventory, int $slot, int $level, bool $toggle): void\n    {\n        if ($toggle) {\n            if ($player->getEffects()->has(VanillaEffects::RESISTANCE()) && $player->getEffects()->get(VanillaEffects::RESISTANCE())->getAmplifier() > $this->getStack($player) - 1) $this->previousEffect[$player->getName()] = $player->getEffects()->get(VanillaEffects::RESISTANCE());\n        } else {\n            if ($this->getArmorStack($player) === 0) {\n                $player->getEffects()->remove(VanillaEffects::RESISTANCE());\n                if (isset($this->previousEffect[$player->getName()])) {\n                    $player->getEffects()->add($this->previousEffect[$player->getName()]);\n                    unset($this->previousEffect[$player->getName()]);\n                }\n                return;\n            }\n        }\n        $player->getEffects()->remove(VanillaEffects::RESISTANCE());\n        $player->getEffects()->add(new EffectInstance(VanillaEffects::RESISTANCE(), 2147483647, $this->getStack($player) - 1, false));\n    }\n\n    public function canEffectsStack(): bool\n    {\n        return true;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/ShrinkEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ToggleableEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\ReactiveTrait;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\TickingTrait;\nuse pocketmine\\event\\Event;\nuse pocketmine\\event\\player\\PlayerToggleSneakEvent;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass ShrinkEnchant extends ToggleableEnchantment\n{\n    use ReactiveTrait {\n        onReaction as protected originalOnReaction;\n    }\n    use TickingTrait;\n\n    public string $name = \"Shrink\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $maxLevel = 2;\n    public int $cooldownDuration = 75;\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    /** @var Player[] */\n    public array $shrunk;\n    /** @var int[] */\n    public array $shrinkPower;\n    /** @var bool[] */\n    public array $shiftCache;\n\n\t/**\n\t * @return class-string[]\n\t */\n\tpublic function getReagent(): array\n    {\n        return [PlayerToggleSneakEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"power\" => 60 * 20, \"base\" => 0.7, \"multiplier\" => 0.0125];\n    }\n\n    public function onReaction(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof PlayerToggleSneakEvent) {\n            $playerName = $player->getName();\n            if ($event->isSneaking()) {\n                if (!isset($this->shiftCache[$playerName])) {\n                    $this->originalOnReaction($player, $item, $inventory, $slot, $event, $level, $stack);\n                    if (isset($this->shrunk[$playerName])) $this->setCooldown($player, 0);\n                    $this->shiftCache[$playerName] = true;\n                } else {\n                    $player->sendTip(TextFormat::RED . \"Shrink is still in cooldown: \" . $this->getCooldown($player) . \"s\");\n                }\n            } elseif (isset($this->shiftCache[$playerName])) {\n                unset($this->shiftCache[$playerName]);\n            }\n        }\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof PlayerToggleSneakEvent) {\n            $playerName = $player->getName();\n            if ($this->getArmorStack($player) === 4) {\n                if ($event->isSneaking()) {\n                    if ($stack - $level === 0) {\n                        if (isset($this->shrunk[$playerName])) {\n                            unset($this->shrunk[$playerName]);\n                            $player->setScale(1);\n                            $player->sendTip(TextFormat::RED . \"You have grown back to normal size.\");\n                        } else {\n                            $this->shrunk[$playerName] = $player;\n                            if (!isset($this->shrinkPower[$playerName])) $this->shrinkPower[$playerName] = $this->extraData[\"power\"];\n                            $player->setScale($player->getScale() - $this->extraData[\"base\"] - ($this->getStack($player) * $this->extraData[\"multiplier\"]));\n                            $player->sendTip(TextFormat::GREEN . \"You have shrunk. Sneak again to grow back to normal size.\");\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        $playerName = $player->getName();\n        if (isset($this->shrunk[$playerName])) {\n            $this->shrinkPower[$playerName]--;\n            $player->sendTip(TextFormat::GREEN . \"Shrink power remaining: \" . $this->shrinkPower[$playerName]);\n            if ($this->getArmorStack($player) < 4 || $this->shrinkPower[$playerName] <= 0) {\n                unset($this->shrunk[$playerName]);\n                $this->setCooldown($player, $this->getCooldownDuration());\n                if ($this->shrinkPower[$playerName] <= 0) $this->shrinkPower[$playerName] = $this->extraData[\"power\"];\n                $player->setScale(1);\n                $player->sendTip(TextFormat::RED . \"You have grown back to normal size.\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/TankEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Axe;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass TankEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Tank\";\n    public int $rarity = Rarity::UNCOMMON;\n\n    public int $usageType = CustomEnchant::TYPE_ARMOR_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_ARMOR;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"absorbedDamageMultiplier\" => 0.2];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $damager = $event->getDamager();\n            if ($damager instanceof Player) {\n                if ($damager->getInventory()->getItemInHand() instanceof Axe) {\n                    $event->setModifier(-($event->getFinalDamage() * $this->extraData[\"absorbedDamageMultiplier\"] * $level), CustomEnchantIds::TANK);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/boots/JetpackEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\boots;\n\nuse DaPigGuy\\PiggyCustomEnchants\\CustomEnchantManager;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\TickingTrait;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\ToggleTrait;\nuse DaPigGuy\\PiggyCustomEnchants\\particles\\JetpackParticle;\nuse pocketmine\\event\\entity\\EntityDamageEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\event\\player\\PlayerToggleSneakEvent;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Enchantment;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass JetpackEnchant extends ReactiveEnchantment\n{\n    use TickingTrait;\n    use ToggleTrait;\n\n    public string $name = \"Jetpack\";\n    public int $maxLevel = 3;\n\n    public int $usageType = CustomEnchant::TYPE_BOOTS;\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOOTS;\n\n    /** @var Player[] */\n    public $activeJetpacks = [];\n\n    /** @var array */\n    public $powerRemaining;\n    /** @var array */\n    public $lastActivated;\n\n    public function getReagent(): array\n    {\n        return [PlayerToggleSneakEvent::class, EntityDamageEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"power\" => 300, \"rechargeAmount\" => 0.66, \"enableAmount\" => 25, \"drainMultiplier\" => 1, \"sprintDrainMultiplier\" => 1.25, \"speedMultiplier\" => 1, \"sprintSpeedMultiplier\" => 1.25];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageEvent && $event->getCause() === EntityDamageEvent::CAUSE_FALL && $this->hasActiveJetpack($player)) $event->cancel();\n        if ($event instanceof PlayerToggleSneakEvent) {\n            if ($event->isSneaking()) {\n                if ($this->hasActiveJetpack($player)) {\n                    if (!$player->isOnGround() && $player->getArmorInventory()->getChestplate()->getEnchantment(CustomEnchantManager::getEnchantment(CustomEnchantIds::PARACHUTE)) === null && !$player->getAllowFlight()) {\n                        $player->sendPopup(TextFormat::RED . \"It is unsafe to disable your jetpack while in the air.\");\n                    } else {\n                        $this->powerActiveJetpack($player, false);\n                    }\n                } else {\n                    $this->powerActiveJetpack($player);\n                }\n            }\n        }\n    }\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        if ($this->hasActiveJetpack($player)) {\n            $player->setMotion($player->getDirectionVector()->multiply($level * ($player->isSprinting() ? $this->extraData[\"sprintSpeedMultiplier\"] : $this->extraData[\"speedMultiplier\"])));\n            $player->resetFallDistance();\n            $player->getWorld()->addParticle($player->getPosition(), new JetpackParticle());\n            $time = ceil($this->powerRemaining[$player->getName()] / 10);\n            if ($time > 2) $player->sendTip(($time > 10 ? TextFormat::GREEN : ($time > 5 ? TextFormat::YELLOW : TextFormat::RED)) . \"Power: \" . str_repeat(\"|\", (int)$time));\n            $lowTime = ceil($this->powerRemaining[$player->getName()] / 5);\n            if ($time <= 2 && $lowTime > 0) $player->sendTip(TextFormat::RED . \"Jetpack low on power: \" . str_repeat(\"|\", (int)$lowTime));\n            if ($player->getServer()->getTick() % 20 === 0) {\n                $this->powerRemaining[$player->getName()] -= ($player->isSprinting() ? $this->extraData[\"sprintDrainMultiplier\"] : $this->extraData[\"drainMultiplier\"]);\n                if ($this->powerRemaining[$player->getName()] <= 0) {\n                    $player->sendTip(TextFormat::RED . \"Jetpack has run out of power.\");\n                    $this->powerActiveJetpack($player, false);\n                }\n            }\n        }\n    }\n\n    public function toggle(Player $player, Item $item, Inventory $inventory, int $slot, int $level, bool $toggle): void\n    {\n        if (!$toggle && $this->hasActiveJetpack($player)) $this->powerActiveJetpack($player, false);\n    }\n\n    public function hasActiveJetpack(Player $player): bool\n    {\n        return isset($this->activeJetpacks[$player->getName()]);\n    }\n\n    public function powerActiveJetpack(Player $player, bool $power = true): void\n    {\n        if ($power) {\n            if (!isset($this->powerRemaining[$player->getName()])) {\n                $this->powerRemaining[$player->getName()] = $this->extraData[\"power\"];\n                $this->activeJetpacks[$player->getName()] = $player;\n            } else {\n                $this->powerRemaining[$player->getName()] += (time() - $this->lastActivated[$player->getName()]) * $this->extraData[\"rechargeAmount\"];\n                if ($this->powerRemaining[$player->getName()] > $this->extraData[\"power\"]) $this->powerRemaining[$player->getName()] = $this->extraData[\"power\"];\n                if ($this->powerRemaining[$player->getName()] < $this->extraData[\"enableAmount\"]) {\n                    $player->sendTip(TextFormat::RED . \"Jetpack needs to charge up to \" . $this->extraData[\"enableAmount\"] . \" before it can be re-enabled. (\" . round(abs($this->powerRemaining[$player->getName()]), 2) . \" / \" . $this->extraData[\"power\"] . \")\");\n                    return;\n                }\n                $this->activeJetpacks[$player->getName()] = $player;\n            }\n        } else {\n            unset($this->activeJetpacks[$player->getName()]);\n            $this->lastActivated[$player->getName()] = time();\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/boots/MagmaWalkerEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\boots;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\block\\BlockFactory;\nuse pocketmine\\block\\BlockLegacyIds;\nuse pocketmine\\block\\Lava;\nuse pocketmine\\event\\Event;\nuse pocketmine\\event\\player\\PlayerMoveEvent;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass MagmaWalkerEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Magma Walker\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $maxLevel = 2;\n\n    public int $usageType = CustomEnchant::TYPE_BOOTS;\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOOTS;\n\n    public function getReagent(): array\n    {\n        return [PlayerMoveEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"baseRadius\" => 2, \"radiusMultiplier\" => 1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof PlayerMoveEvent) {\n            $world = $player->getWorld();\n            if (!($world->getBlock($player->getPosition()->asVector3()) instanceof Lava)) {\n                $radius = $level * $this->extraData[\"radiusMultiplier\"] + $this->extraData[\"baseRadius\"];\n                for ($x = -$radius; $x <= $radius; $x++) {\n                    for ($z = -$radius; $z <= $radius; $z++) {\n                        $b = $world->getBlock($player->getPosition()->add($x, -1, $z));\n                        if ($world->getBlock($b->getPosition()->add(0, 1, 0))->getId() === BlockLegacyIds::AIR) {\n                            if ($b instanceof Lava && $b->getMeta() === 0) {\n                                $world->setBlock($b->getPosition()->asVector3(), BlockFactory::getInstance()->get(BlockLegacyIds::OBSIDIAN, 15));\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/boots/StompEnchantment.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\boots;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\entity\\EntityDamageEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass StompEnchantment extends ReactiveEnchantment\n{\n    public string $name = \"Stomp\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $maxLevel = 1;\n\n    public int $usageType = CustomEnchant::TYPE_BOOTS;\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOOTS;\n\n    public function getReagent(): array\n    {\n        return [EntityDamageEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"redistributedDamageMultiplier\" => 0.5, \"absorbedDamageMultiplier\" => 0.75];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageEvent) {\n            if ($event->getCause() === EntityDamageEvent::CAUSE_FALL) {\n                $entities = $player->getWorld()->getNearbyEntities($player->getBoundingBox());\n                foreach ($entities as $entity) {\n                    if ($player === $entity) {\n                        continue;\n                    }\n                    $ev = new EntityDamageByEntityEvent($player, $entity, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $event->getFinalDamage() * $this->extraData[\"redistributedDamageMultiplier\"]);\n                    $entity->attack($ev);\n                }\n                $event->setModifier(-($event->getFinalDamage() * $this->extraData[\"absorbedDamageMultiplier\"] * count($entities)), CustomEnchantIds::STOMP);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/chestplate/ChickenEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\chestplate;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\TickingEnchantment;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\item\\ItemFactory;\nuse pocketmine\\item\\VanillaItems;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass ChickenEnchant extends TickingEnchantment\n{\n    public string $name = \"Chicken\";\n    public int $rarity = Rarity::UNCOMMON;\n\n    public int $usageType = CustomEnchant::TYPE_CHESTPLATE;\n    public int $itemType = CustomEnchant::ITEM_TYPE_CHESTPLATE;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"treasureChanceMultiplier\" => 5, \"treasures\" => [\"266:0:1\"], \"interval\" => 1200 * 5];\n    }\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        if (mt_rand(0, 100) <= $this->extraData[\"treasureChanceMultiplier\"] * $level) {\n            $drops = $this->plugin->getConfig()->getNested(\"chicken.drops\", $this->extraData[\"treasures\"]);\n            if (!is_array($drops)) {\n                $drops = [$drops];\n            }\n            $drop = array_rand($drops);\n            $drop = explode(\":\", $drops[$drop]);\n            $item = count($drop) < 3 ? VanillaItems::GOLD_INGOT() : ItemFactory::getInstance()->get((int)$drop[0], (int)$drop[1], (int)$drop[2]);\n            $vowels = [\"a\", \"e\", \"i\", \"o\", \"u\"];\n            $player->getWorld()->dropItem($player->getPosition(), $item, $player->getDirectionVector()->multiply(-0.4));\n            $player->sendTip(TextFormat::GREEN . \"You have laid a\" . (in_array(strtolower($item->getName()[0]), $vowels) ? \"n \" : \" \") . $item->getName() . \"...\");\n        } else {\n            $player->getWorld()->dropItem($player->getPosition(), VanillaItems::EGG(), $player->getDirectionVector()->multiply(-0.4));\n            $player->sendTip(TextFormat::GREEN . \"You have laid an egg.\");\n        }\n    }\n\n    public function getTickingInterval(): int\n    {\n        return $this->extraData[\"interval\"];\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/chestplate/ParachuteEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\chestplate;\n\nuse DaPigGuy\\PiggyCustomEnchants\\CustomEnchantManager;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\boots\\JetpackEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\TickingEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\ToggleTrait;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse pocketmine\\block\\BlockLegacyIds;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass ParachuteEnchant extends TickingEnchantment\n{\n    use ToggleTrait;\n\n    public string $name = \"Parachute\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $maxLevel = 1;\n\n    public int $usageType = CustomEnchant::TYPE_CHESTPLATE;\n    public int $itemType = CustomEnchant::ITEM_TYPE_CHESTPLATE;\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        if ($this->isInAir($player) && !$player->getAllowFlight() && !$player->canClimbWalls() && (($enchantInstance = $player->getArmorInventory()->getBoots()->getEnchantment(CustomEnchantManager::getEnchantment(CustomEnchantIds::JETPACK))) === null || !($enchant = $enchantInstance->getType()) instanceof JetpackEnchant || !$enchant->hasActiveJetpack($player))) {\n            $player->getEffects()->add(new EffectInstance(PiggyCustomEnchants::$SLOW_FALL, 2147483647, 1, false));\n        } elseif ($player->getEffects()->get(PiggyCustomEnchants::$SLOW_FALL) !== null) {\n            if ($this->isInAir($player) || $player->getWorld()->getBlock($player->getPosition()->subtract(0, 1, 0))->getId() !== BlockLegacyIds::AIR) $player->getEffects()->remove(PiggyCustomEnchants::$SLOW_FALL);\n        }\n        $player->resetFallDistance();\n    }\n\n    public function toggle(Player $player, Item $item, Inventory $inventory, int $slot, int $level, bool $toggle): void\n    {\n        if (!$toggle && ($effect = $player->getEffects()->get(PiggyCustomEnchants::$SLOW_FALL)) !== null && $effect->getAmplifier() === -5) {\n            $player->getEffects()->remove(PiggyCustomEnchants::$SLOW_FALL);\n        }\n    }\n\n    public function isInAir(Player $player): bool\n    {\n        for ($y = 1; $y <= 5; $y++) {\n            if ($player->getWorld()->getBlock($player->getPosition()->subtract(0, $y, 0))->getId() !== BlockLegacyIds::AIR) return false;\n        }\n        return true;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/chestplate/ProwlEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\chestplate;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ToggleableEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\TickingTrait;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass ProwlEnchant extends ToggleableEnchantment\n{\n    use TickingTrait;\n\n    public string $name = \"Prowl\";\n    public int $maxLevel = 1;\n\n    public int $usageType = CustomEnchant::TYPE_CHESTPLATE;\n    public int $itemType = CustomEnchant::ITEM_TYPE_CHESTPLATE;\n\n    /** @var bool[] */\n    public array $prowled;\n\n    public function toggle(Player $player, Item $item, Inventory $inventory, int $slot, int $level, bool $toggle): void\n    {\n        if (!$toggle && isset($this->prowled[$player->getName()])) {\n            foreach ($player->getServer()->getOnlinePlayers() as $p) {\n                $p->showPlayer($player);\n            }\n            $player->getEffects()->remove(VanillaEffects::SLOWNESS());\n            if (!$player->getEffects()->has(VanillaEffects::INVISIBILITY())) {\n                $player->setInvisible(false);\n            }\n            unset($this->prowled[$player->getName()]);\n        }\n    }\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        if ($player->isSneaking()) {\n            foreach ($player->getServer()->getOnlinePlayers() as $p) {\n                $p->hidePlayer($player);\n            }\n            $effect = new EffectInstance(VanillaEffects::SLOWNESS(), 2147483647, 0, false);\n            $player->setInvisible();\n            $player->getEffects()->add($effect);\n            $this->prowled[$player->getName()] = true;\n        } else {\n            if (isset($this->prowled[$player->getName()])) {\n                foreach ($player->getServer()->getOnlinePlayers() as $p) {\n                    $p->showPlayer($player);\n                }\n                $player->getEffects()->remove(VanillaEffects::SLOWNESS());\n                if (!$player->getEffects()->has(VanillaEffects::INVISIBILITY())) {\n                    $player->setInvisible(false);\n                }\n                unset($this->prowled[$player->getName()]);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/chestplate/SpiderEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\chestplate;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ToggleableEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\TickingTrait;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass SpiderEnchant extends ToggleableEnchantment\n{\n    use TickingTrait;\n\n    public string $name = \"Spider\";\n    public int $maxLevel = 1;\n\n    public int $usageType = CustomEnchant::TYPE_CHESTPLATE;\n    public int $itemType = CustomEnchant::ITEM_TYPE_CHESTPLATE;\n\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        $player->setCanClimbWalls($this->canClimb($player));\n    }\n\n    public function toggle(Player $player, Item $item, Inventory $inventory, int $slot, int $level, bool $toggle): void\n    {\n        if (!$toggle) $player->setCanClimbWalls(false);\n    }\n\n    public function canClimb(Player $player): bool\n    {\n        foreach ($player->getWorld()->getBlock($player->getPosition()->add(0, (count($player->getWorld()->getBlock($player->getPosition())->getCollisionBoxes()) > 0 ? ceil($player->getPosition()->y) - $player->getPosition()->y + 0.01 : 0), 0))->getHorizontalSides() as $block) {\n            if ($block->isSolid()) return true;\n        }\n        foreach ($player->getWorld()->getBlock($player->getPosition()->add(0, 1, 0))->getHorizontalSides() as $block) {\n            if ($block->isSolid()) return true;\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/chestplate/VacuumEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\chestplate;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\TickingEnchantment;\nuse pocketmine\\entity\\object\\ItemEntity;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass VacuumEnchant extends TickingEnchantment\n{\n    public string $name = \"Vacuum\";\n    public int $maxLevel = 3;\n\n    public int $usageType = CustomEnchant::TYPE_CHESTPLATE;\n    public int $itemType = CustomEnchant::ITEM_TYPE_CHESTPLATE;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"radiusMultiplier\" => 3];\n    }\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        foreach ($player->getWorld()->getEntities() as $entity) {\n            if ($entity instanceof ItemEntity) {\n                $distance = $player->getPosition()->distance($entity->getPosition());\n                if ($distance <= $this->extraData[\"radiusMultiplier\"] * $level) {\n                    $entity->setMotion($player->getPosition()->subtractVector($entity->getPosition())->divide(3 * $level)->multiply($level));\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/helmet/AntitoxinEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\helmet;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\event\\entity\\EntityEffectAddEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass AntitoxinEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Antitoxin\";\n    public int $rarity = Rarity::MYTHIC;\n    public int $maxLevel = 1;\n\n    public int $usageType = CustomEnchant::TYPE_HELMET;\n    public int $itemType = CustomEnchant::ITEM_TYPE_HELMET;\n\n    public function getReagent(): array\n    {\n        return [EntityEffectAddEvent::class];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityEffectAddEvent) {\n            if ($event->getEffect()->getType() === VanillaEffects::POISON()) $event->cancel();\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/helmet/FocusedEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\helmet;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous\\RecursiveEnchant;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\event\\entity\\EntityEffectAddEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass FocusedEnchant extends RecursiveEnchant\n{\n    public string $name = \"Focused\";\n    public int $rarity = Rarity::UNCOMMON;\n\n    public int $usageType = CustomEnchant::TYPE_HELMET;\n    public int $itemType = CustomEnchant::ITEM_TYPE_HELMET;\n\n    public function getReagent(): array\n    {\n        return [EntityEffectAddEvent::class];\n    }\n\n    public function safeReact(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityEffectAddEvent) {\n            $effect = $event->getEffect();\n            if ($effect->getType() === VanillaEffects::NAUSEA()) {\n                if ($effect->getEffectLevel() - ($level * 2) > 0) {\n                    $player->getEffects()->remove($effect->getType());\n                    $player->getEffects()->add($effect->setAmplifier($effect->getEffectLevel() - (1 + ($level * 2))));\n                }\n                $event->cancel();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/helmet/ImplantsEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\helmet;\n\nuse DaPigGuy\\PiggyCustomEnchants\\CustomEnchantManager;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\block\\Water;\nuse pocketmine\\event\\Event;\nuse pocketmine\\event\\player\\PlayerMoveEvent;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Enchantment;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\nuse pocketmine\\scheduler\\ClosureTask;\n\nclass ImplantsEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Implants\";\n\n    public int $usageType = CustomEnchant::TYPE_HELMET;\n    public int $itemType = CustomEnchant::ITEM_TYPE_HELMET;\n\n    /** @var ClosureTask[] */\n    public static $tasks;\n\n    public function getReagent(): array\n    {\n        return [PlayerMoveEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"foodReplenishAmountMultiplier\" => 1, \"airTicksReplenishAmountMultiplier\" => 40, \"airReplenishInterval\" => 60];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof PlayerMoveEvent) {\n            if ($player->getHungerManager()->getFood() < 20) {\n                $player->getHungerManager()->setFood($player->getHungerManager()->getFood() + $level * $this->extraData[\"foodReplenishAmountMultiplier\"] > $player->getHungerManager()->getMaxFood() ? $player->getHungerManager()->getMaxFood() : $player->getHungerManager()->getFood() + $level * $this->extraData[\"foodReplenishAmountMultiplier\"]);\n            }\n            if ($player->getAirSupplyTicks() < $player->getMaxAirSupplyTicks() && !isset(self::$tasks[$player->getName()])) {\n                self::$tasks[$player->getName()] = new ClosureTask(function () use ($player): void {\n                    if ($player->isOnline() && $player->isAlive() && ($enchantment = $player->getArmorInventory()->getHelmet()->getEnchantment(CustomEnchantManager::getEnchantment(CustomEnchantIds::IMPLANTS))) !== null) {\n                        if (!$player->getWorld()->getBlock($player->getPosition()->add(0, 1, 0)) instanceof Water ||\n                            $player->getAirSupplyTicks() >= $player->getMaxAirSupplyTicks()) {\n                            self::$tasks[$player->getName()]->getHandler()->cancel();\n                            unset(self::$tasks[$player->getName()]);\n                            return;\n                        }\n                        $player->setAirSupplyTicks($player->getAirSupplyTicks() + ($enchantment->getLevel() * $this->extraData[\"airTicksReplenishAmountMultiplier\"]) > $player->getMaxAirSupplyTicks() ? $player->getMaxAirSupplyTicks() : $player->getAirSupplyTicks() + ($enchantment->getLevel() * $this->extraData[\"airTicksReplenishAmountMultiplier\"]));\n                    } else {\n                        self::$tasks[$player->getName()]->getHandler()->cancel();\n                        unset(self::$tasks[$player->getName()]);\n                    }\n                });\n                $this->plugin->getScheduler()->scheduleDelayedRepeatingTask(self::$tasks[$player->getName()], 20, $this->extraData[\"airReplenishInterval\"]);\n            }\n            $this->setCooldown($player, 1);\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/armor/helmet/MeditationEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\armor\\helmet;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\TickingTrait;\nuse pocketmine\\event\\entity\\EntityRegainHealthEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\event\\player\\PlayerMoveEvent;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass MeditationEnchant extends ReactiveEnchantment\n{\n    use TickingTrait;\n\n    public string $name = \"Meditation\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $maxLevel = 2;\n\n    public int $usageType = CustomEnchant::TYPE_HELMET;\n    public int $itemType = CustomEnchant::ITEM_TYPE_HELMET;\n\n    /** @var Player[] */\n    public array $meditating = [];\n    /** @var int[] */\n    public array $meditationTick;\n\n    public function getReagent(): array\n    {\n        return [PlayerMoveEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"duration\" => 20 * 20, \"healthReplenishAmountMultiplier\" => 1, \"foodReplenishAmountMultiplier\" => 1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof PlayerMoveEvent) {\n            $this->meditating[$player->getName()] = $player;\n            $this->meditationTick[$player->getName()] = 0;\n        }\n    }\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        if (isset($this->meditationTick[$player->getName()])) {\n            $this->meditationTick[$player->getName()]++;\n            $time = (int)($this->meditationTick[$player->getName()] / 40);\n            $player->sendTip(TextFormat::DARK_GREEN . \"Meditating...\\n\" . TextFormat::GREEN . str_repeat(\"▌\", $time) . TextFormat::GRAY . str_repeat(\"▌\", (20 * 20 / 40) - $time));\n            if ($this->meditationTick[$player->getName()] >= $this->extraData[\"duration\"]) {\n                $this->meditationTick[$player->getName()] = 0;\n                $event = new EntityRegainHealthEvent($player, $level * $this->extraData[\"healthReplenishAmountMultiplier\"], EntityRegainHealthEvent::CAUSE_MAGIC);\n                if (!$event->isCancelled()) $player->heal($event);\n                $player->getHungerManager()->setFood($player->getHungerManager()->getFood() + $level * $this->extraData[\"foodReplenishAmountMultiplier\"] > $player->getHungerManager()->getMaxFood() ? $player->getHungerManager()->getMaxFood() : $player->getHungerManager()->getFood() + $level * $this->extraData[\"foodReplenishAmountMultiplier\"]);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/miscellaneous/AutoRepairEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\Event;\nuse pocketmine\\event\\player\\PlayerMoveEvent;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Durable;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass AutoRepairEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Autorepair\";\n    public int $rarity = Rarity::UNCOMMON;\n\n    public int $usageType = CustomEnchant::TYPE_ANY_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_DAMAGEABLE;\n\n    public function getReagent(): array\n    {\n        return [PlayerMoveEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"baseRepair\" => 1, \"repairMultiplier\" => 1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if (!$item instanceof Durable || $item->getMeta() === 0) return;\n        $newDir = $item->getMeta() - ((int)$this->extraData[\"baseRepair\"] + ((int)$this->extraData[\"repairMultiplier\"] * $level));\n        if ($newDir < 0) {\n            $item->setDamage(0);\n        } else {\n            $item->setDamage($newDir);\n        }\n        $inventory->setItem($slot, $item);\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/miscellaneous/LuckyCharmEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous;\n\nuse DaPigGuy\\PiggyCustomEnchants\\CustomEnchantManager;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ToggleableEnchantment;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass LuckyCharmEnchant extends ToggleableEnchantment\n{\n    public string $name = \"Lucky Charm\";\n    public int $rarity = Rarity::MYTHIC;\n    public int $maxLevel = 3;\n\n    public int $usageType = CustomEnchant::TYPE_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_GLOBAL;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"additionalMultiplier\" => 0.05];\n    }\n\n    public function toggle(Player $player, Item $item, Inventory $inventory, int $slot, int $level, bool $toggle): void\n    {\n        /** @var ReactiveEnchantment $enchantment */\n        foreach (CustomEnchantManager::getEnchantments() as $enchantment) {\n            if ($enchantment->canReact()) {\n                $enchantment->setChanceMultiplier($player, $enchantment->getChanceMultiplier($player) + ($toggle ? 1 : -1) * $level * $this->extraData[\"additionalMultiplier\"]);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/miscellaneous/RadarEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\TickingEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\traits\\ToggleTrait;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\network\\mcpe\\protocol\\SetSpawnPositionPacket;\nuse pocketmine\\network\\mcpe\\protocol\\types\\BlockPosition;\nuse pocketmine\\network\\mcpe\\protocol\\types\\DimensionIds;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\nuse pocketmine\\world\\Position;\n\nclass RadarEnchant extends TickingEnchantment\n{\n    use ToggleTrait;\n\n    public string $name = \"Radar\";\n\n    public int $usageType = CustomEnchant::TYPE_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_COMPASS;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"radiusMultiplier\" => 50];\n    }\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        $detected = $this->findNearestPlayer($player, $level * $this->extraData[\"radiusMultiplier\"]);\n        $this->setCompassPosition($player, $detected?->getPosition() ?? $player->getWorld()->getSafeSpawn());\n        if ($item->equalsExact($player->getInventory()->getItemInHand())) {\n            if (is_null($detected)) {\n                $player->sendTip(TextFormat::RED . \"No players found.\");\n            } else {\n                $player->sendTip(TextFormat::GREEN . \"Nearest player \" . round($player->getPosition()->distance($detected->getPosition()), 1) . \" blocks away.\");\n            }\n        }\n    }\n\n    public function toggle(Player $player, Item $item, Inventory $inventory, int $slot, int $level, bool $toggle): void\n    {\n        if (!$toggle && $player->isOnline()) $this->setCompassPosition($player, $player->getWorld()->getSafeSpawn());\n    }\n\n    public function setCompassPosition(Player $player, Position $position): void\n    {\n        $player->getNetworkSession()->sendDataPacket(SetSpawnPositionPacket::worldSpawn(BlockPosition::fromVector3($position->floor()), DimensionIds::OVERWORLD));\n    }\n\n    public function findNearestPlayer(Player $player, int $range): ?Player\n    {\n        $nearestPlayer = null;\n        $nearestPlayerDistance = $range;\n        foreach ($player->getWorld()->getPlayers() as $p) {\n            $distance = $player->getPosition()->distance($p->getPosition());\n            if ($distance <= $range && $distance < $nearestPlayerDistance && $player !== $p && $p->isAlive() && !$p->isClosed() && !$p->isFlaggedForDespawn()) {\n                $nearestPlayer = $p;\n                $nearestPlayerDistance = $distance;\n            }\n        }\n        return $nearestPlayer;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/miscellaneous/RecursiveEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass RecursiveEnchant extends ReactiveEnchantment\n{\n    /** @var bool[] */\n    public static array $isUsing;\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if (isset(self::$isUsing[$player->getName()])) return;\n        self::$isUsing[$player->getName()] = true;\n        $this->safeReact($player, $item, $inventory, $slot, $event, $level, $stack);\n        unset(self::$isUsing[$player->getName()]);\n    }\n\n    public function safeReact(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/miscellaneous/SoulboundEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous;\n\nuse DaPigGuy\\PiggyCustomEnchants\\CustomEnchantManager;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\Event;\nuse pocketmine\\event\\player\\PlayerDeathEvent;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\EnchantmentInstance;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\nuse pocketmine\\scheduler\\ClosureTask;\n\nclass SoulboundEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Soulbound\";\n    public int $rarity = Rarity::MYTHIC;\n\n    public int $usageType = CustomEnchant::TYPE_ANY_INVENTORY;\n    public int $itemType = CustomEnchant::ITEM_TYPE_GLOBAL;\n\n    public function getReagent(): array\n    {\n        return [PlayerDeathEvent::class];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof PlayerDeathEvent) {\n            $drops = $event->getDrops();\n            foreach ($drops as $key => $drop) {\n                if ($drop->equalsExact($item)) {\n                    unset($drops[$key]);\n                    break;\n                }\n            }\n            $event->setDrops($drops);\n            $level > 1 ? $item->addEnchantment(new EnchantmentInstance(CustomEnchantManager::getEnchantment(CustomEnchantIds::SOULBOUND), $level - 1)) : $item->removeEnchantment(CustomEnchantManager::getEnchantment(CustomEnchantIds::SOULBOUND));\n            $this->plugin->getScheduler()->scheduleDelayedTask(new ClosureTask(function () use ($inventory, $slot, $item): void {\n                $inventory->setItem($slot, $item);\n            }), 1);\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/miscellaneous/ToggleableEffectEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ToggleableEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\Utils;\nuse pocketmine\\entity\\effect\\Effect;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass ToggleableEffectEnchant extends ToggleableEnchantment\n{\n    /** @var EffectInstance[] */\n    private array $previousEffect = [];\n\n    public function __construct(PiggyCustomEnchants $plugin, int $id, string $name, int $maxLevel, int $usageType, int $itemType, private Effect $effect, private int $baseAmplifier = 0, private int $amplifierMultiplier = 1, int $rarity = Rarity::RARE)\n    {\n        $this->name = $name;\n        $this->rarity = $rarity;\n        $this->maxLevel = $maxLevel;\n        $this->usageType = $usageType;\n        $this->itemType = $itemType;\n        parent::__construct($plugin, $id);\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"baseAmplifier\" => $this->baseAmplifier, \"amplifierMultiplier\" => $this->amplifierMultiplier];\n    }\n\n    public function toggle(Player $player, Item $item, Inventory $inventory, int $slot, int $level, bool $toggle): void\n    {\n        if ($toggle) {\n            if ($this->effect === VanillaEffects::JUMP_BOOST()) Utils::setShouldTakeFallDamage($player, false, 2147483647);\n            if ($player->getEffects()->has($this->effect) && $player->getEffects()->get($this->effect)->getAmplifier() > $this->extraData[\"baseAmplifier\"] + $this->extraData[\"amplifierMultiplier\"] * $level) $this->previousEffect[$player->getName()] = $player->getEffects()->get($this->effect);\n        } else {\n            if ($this->usageType !== CustomEnchant::TYPE_ARMOR_INVENTORY || $this->getArmorStack($player) === 0) {\n                if ($this->effect === VanillaEffects::JUMP_BOOST()) Utils::setShouldTakeFallDamage($player, true);\n                $player->getEffects()->remove($this->effect);\n                if (isset($this->previousEffect[$player->getName()])) {\n                    $player->getEffects()->add($this->previousEffect[$player->getName()]);\n                    unset($this->previousEffect[$player->getName()]);\n                }\n                return;\n            }\n        }\n        $player->getEffects()->remove($this->effect);\n\n        $amplifier = $this->extraData[\"baseAmplifier\"] + $this->extraData[\"amplifierMultiplier\"] * $level;\n        $player->getEffects()->add(new EffectInstance($this->effect, 2147483647, (int)(min($amplifier, 255)), false));\n    }\n\n    public function getUsageType(): int\n    {\n        return $this->usageType;\n    }\n\n    public function getItemType(): int\n    {\n        return $this->itemType;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/tools/DrillerEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\tools;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous\\RecursiveEnchant;\nuse pocketmine\\event\\block\\BlockBreakEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\math\\Axis;\nuse pocketmine\\math\\Facing;\nuse pocketmine\\player\\Player;\n\nclass DrillerEnchant extends RecursiveEnchant\n{\n    public string $name = \"Driller\";\n    public int $rarity = Rarity::UNCOMMON;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_TOOLS;\n\n    /** @var int[] */\n    public static array $lastBreakFace = [];\n\n    public function getReagent(): array\n    {\n        return [BlockBreakEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"distanceMultiplier\" => 1];\n    }\n\n    public function safeReact(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof BlockBreakEvent) {\n            $breakFace = self::$lastBreakFace[$player->getName()];\n            for ($i = 0; $i <= $level * $this->extraData[\"distanceMultiplier\"]; $i++) {\n                $block = $event->getBlock()->getSide(Facing::opposite($breakFace), $i);\n                $faceLeft = Facing::rotate($breakFace, Facing::axis($breakFace) !== Axis::Y ? Axis::Y : Axis::X, true);\n                $faceUp = Facing::rotate($breakFace, Facing::axis($breakFace) !== Axis::Z ? Axis::Z : Axis::X, true);\n                foreach ([\n                             $block->getSide($faceLeft), //Center Left\n                             $block->getSide(Facing::opposite($faceLeft)), //Center Right\n                             $block->getSide($faceUp), //Center Top\n                             $block->getSide(Facing::opposite($faceUp)), //Center Bottom\n                             $block->getSide($faceUp)->getSide($faceLeft), //Top Left\n                             $block->getSide($faceUp)->getSide(Facing::opposite($faceLeft)), //Top Right\n                             $block->getSide(Facing::opposite($faceUp))->getSide($faceLeft), //Bottom Left\n                             $block->getSide(Facing::opposite($faceUp))->getSide(Facing::opposite($faceLeft)) //Bottom Right\n                         ] as $b) {\n                    $player->getWorld()->useBreakOn($b->getPosition(), $item, $player, true);\n                }\n                if (!$block->getPosition()->equals($event->getBlock()->getPosition())) {\n                    $player->getWorld()->useBreakOn($block->getPosition(), $item, $player, true);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/tools/EnergizingEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\tools;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\event\\block\\BlockBreakEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass EnergizingEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Energizing\";\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_TOOLS;\n\n    public function getReagent(): array\n    {\n        return [BlockBreakEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"duration\" => 20, \"baseAmplifier\" => -1, \"amplifierMultiplier\" => 1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof BlockBreakEvent) {\n            if (!$player->getEffects()->has(VanillaEffects::HASTE())) {\n                $effect = new EffectInstance(VanillaEffects::HASTE(), $this->extraData[\"duration\"], $level * $this->extraData[\"amplifierMultiplier\"] + $this->extraData[\"baseAmplifier\"], false);\n                $player->getEffects()->add($effect);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/tools/ExplosiveEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\tools;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous\\RecursiveEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\PiggyExplosion;\nuse pocketmine\\event\\block\\BlockBreakEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass ExplosiveEnchant extends RecursiveEnchant\n{\n    public string $name = \"Explosive\";\n    public int $rarity = Rarity::UNCOMMON;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_TOOLS;\n\n    public function getReagent(): array\n    {\n        return [BlockBreakEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"sizeMultiplier\" => 5, \"entityDamage\" => true];\n    }\n\n    public function safeReact(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof BlockBreakEvent) {\n            $explosion = new PiggyExplosion($event->getBlock()->getPosition(), $level * $this->extraData[\"sizeMultiplier\"], $player, $this->extraData[\"entityDamage\"]);\n            $explosion->explodeA();\n            $explosion->explodeB();\n        }\n    }\n\n    public function getPriority(): int\n    {\n        return 4;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/tools/QuickeningEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\tools;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\event\\block\\BlockBreakEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass QuickeningEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Quickening\";\n    public int $rarity = Rarity::UNCOMMON;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_TOOLS;\n\n    public function getReagent(): array\n    {\n        return [BlockBreakEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"duration\" => 40, \"baseAmplifier\" => 1, \"amplifierMultiplier\" => 1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof BlockBreakEvent) {\n            if ($player->getEffects()->has(VanillaEffects::SPEED()) !== true) {\n                $effect = new EffectInstance(VanillaEffects::SPEED(), $this->extraData[\"duration\"], $level * $this->extraData[\"amplifierMultiplier\"] + $this->extraData[\"baseAmplifier\"], false);\n                $player->getEffects()->add($effect);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/tools/SmeltingEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\tools;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\crafting\\FurnaceType;\nuse pocketmine\\event\\block\\BlockBreakEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass SmeltingEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Smelting\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $maxLevel = 1;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_TOOLS;\n\n    public function getReagent(): array\n    {\n        return [BlockBreakEvent::class];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof BlockBreakEvent) {\n            $event->setDrops(array_map(fn(Item $item) => $this->plugin->getServer()->getCraftingManager()->getFurnaceRecipeManager(FurnaceType::FURNACE())->match($item)?->getResult() ?? $item, $event->getDrops()));\n        }\n    }\n\n    public function getPriority(): int\n    {\n        return 2;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/tools/TelepathyEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\tools;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\block\\BlockBreakEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass TelepathyEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Telepathy\";\n    public int $maxLevel = 1;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_TOOLS;\n\n    public function getReagent(): array\n    {\n        return [BlockBreakEvent::class];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof BlockBreakEvent) {\n            $drops = $event->getDrops();\n            foreach ($drops as $key => $drop) {\n                if ($player->getInventory()->canAddItem($drop)) {\n                    unset($drops[$key]);\n                    $player->getInventory()->addItem($drop);\n                    continue;\n                }\n                foreach ($player->getInventory()->all($drop) as $item) {\n                    if ($item->getCount() < $item->getMaxStackSize()) {\n                        $newDrop = clone $drop->setCount($drop->getCount() - ($item->getMaxStackSize() - $item->getCount()));\n                        $player->getInventory()->addItem($drop->setCount($item->getMaxStackSize() - $item->getCount()));\n                        $drop = $newDrop;\n                    }\n                }\n                $drops[$key] = $drop;\n            }\n            $player->getXpManager()->addXp($event->getXpDropAmount());\n            $event->setDrops($drops);\n            $event->setXpDropAmount(0);\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/tools/axes/LumberjackEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\axes;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous\\RecursiveEnchant;\nuse pocketmine\\block\\Block;\nuse pocketmine\\block\\BlockLegacyIds;\nuse pocketmine\\event\\block\\BlockBreakEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass LumberjackEnchant extends RecursiveEnchant\n{\n    public string $name = \"Lumberjack\";\n    public int $maxLevel = 1;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_AXE;\n\n    public function getReagent(): array\n    {\n        return [BlockBreakEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"limit\" => 800];\n    }\n\n    public function safeReact(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof BlockBreakEvent) {\n            $block = $event->getBlock();\n            if ($player->isSneaking()) {\n                if ($block->getId() == BlockLegacyIds::LOG || $block->getId() == BlockLegacyIds::LOG2) {\n                    $this->breakTree($block, $player);\n                }\n            }\n        }\n    }\n\n    public function breakTree(Block $block, Player $player, int $mined = 0): void\n    {\n        $item = $player->getInventory()->getItemInHand();\n        for ($i = 0; $i <= 5; $i++) {\n            if ($mined > $this->extraData[\"limit\"]) {\n                break;\n            }\n            $side = $block->getSide($i);\n            if ($side->getId() !== BlockLegacyIds::LOG && $side->getId() !== BlockLegacyIds::LOG2) {\n                continue;\n            }\n            $player->getWorld()->useBreakOn($side->getPosition(), $item, $player);\n            $mined++;\n            $this->breakTree($side, $player, $mined);\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/tools/hoe/FarmerEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\hoe;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\block\\Crops;\nuse pocketmine\\event\\block\\BlockBreakEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\math\\Facing;\nuse pocketmine\\player\\Player;\nuse pocketmine\\scheduler\\ClosureTask;\n\nclass FarmerEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Farmer\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $maxLevel = 1;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_HOE;\n\n    public function getReagent(): array\n    {\n        return [BlockBreakEvent::class];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof BlockBreakEvent) {\n            $block = $event->getBlock();\n            if ($block instanceof Crops) {\n                $seed = $block->getPickedItem();\n                if ($player->getInventory()->contains($seed)) {\n                    $this->plugin->getScheduler()->scheduleDelayedTask(new ClosureTask(function () use ($player, $seed, $block): void {\n                        $block->getPosition()->getWorld()->useItemOn($block->getPosition()->subtract(0, 1, 0), $seed, Facing::UP, $block->getPosition()->subtract(0, 1, 0), $player);\n                        $player->getInventory()->removeItem($seed->setCount(1));\n                    }), 1);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/tools/hoe/FertilizerEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\hoe;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous\\RecursiveEnchant;\nuse pocketmine\\block\\BlockLegacyIds;\nuse pocketmine\\event\\Event;\nuse pocketmine\\event\\player\\PlayerInteractEvent;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\math\\Facing;\nuse pocketmine\\player\\Player;\n\nclass FertilizerEnchant extends RecursiveEnchant\n{\n    public string $name = \"Fertilizer\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $maxLevel = 3;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_HOE;\n\n    public function getReagent(): array\n    {\n        return [PlayerInteractEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"radiusMultiplier\" => 1];\n    }\n\n    public function safeReact(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof PlayerInteractEvent) {\n            $block = $event->getBlock();\n            if ($block->getId() === BlockLegacyIds::GRASS || ($block->getId() === BlockLegacyIds::DIRT && $block->getMeta() === 0)) {\n                $radius = $level * $this->extraData[\"radiusMultiplier\"];\n                for ($x = -$radius; $x <= $radius; $x++) {\n                    for ($z = -$radius; $z <= $radius; $z++) {\n                        $newBlock = $block->getPosition()->getWorld()->getBlock($block->getPosition()->add($x, 0, $z));\n                        if ($newBlock->getId() === BlockLegacyIds::GRASS || ($newBlock->getId() === BlockLegacyIds::DIRT && $newBlock->getMeta() === 0)) {\n                            $block->getPosition()->getWorld()->useItemOn($newBlock->getPosition(), $item, Facing::UP, $newBlock->getPosition(), $player);\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/tools/hoe/HarvestEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\hoe;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous\\RecursiveEnchant;\nuse pocketmine\\block\\Crops;\nuse pocketmine\\event\\block\\BlockBreakEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass HarvestEnchant extends RecursiveEnchant\n{\n    public string $name = \"Harvest\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $maxLevel = 3;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_HOE;\n\n    public function getReagent(): array\n    {\n        return [BlockBreakEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"radiusMultiplier\" => 1];\n    }\n\n    public function safeReact(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof BlockBreakEvent) {\n            $block = $event->getBlock();\n            if ($block instanceof Crops) {\n                $radius = $level * $this->extraData[\"radiusMultiplier\"];\n                for ($x = -$radius; $x <= $radius; $x++) {\n                    for ($z = -$radius; $z <= $radius; $z++) {\n                        if ($block->getPosition()->getWorld()->getBlock($block->getPosition()->add($x, 0, $z)) instanceof Crops) {\n                            $block->getPosition()->getWorld()->useBreakOn($block->getPosition()->add($x, 0, $z), $item, $player);\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/tools/pickaxe/JackpotEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\tools\\pickaxe;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\block\\BlockFactory;\nuse pocketmine\\block\\BlockLegacyIds;\nuse pocketmine\\event\\block\\BlockBreakEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\item\\VanillaItems;\nuse pocketmine\\player\\Player;\n\nclass JackpotEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Jackpot\";\n    public int $rarity = Rarity::MYTHIC;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_PICKAXE;\n\n    const ORE_TIERS = [\n        BlockLegacyIds::COAL_ORE,\n        BlockLegacyIds::IRON_ORE,\n        BlockLegacyIds::GOLD_ORE,\n        BlockLegacyIds::DIAMOND_ORE,\n        BlockLegacyIds::EMERALD_ORE\n    ];\n\n    public function getReagent(): array\n    {\n        return [BlockBreakEvent::class];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof BlockBreakEvent) {\n            $key = array_search($event->getBlock()->getId(), self::ORE_TIERS, true);\n            if ($key !== false) {\n                if (isset(self::ORE_TIERS[$key + 1])) {\n                    $drops = $event->getDrops();\n                    foreach ($drops as $k => $drop) {\n                        if (in_array($drop, $event->getBlock()->getDrops($item), true)) {\n                            unset($drops[$k]);\n                        }\n                    }\n                    $drops = array_merge($drops, BlockFactory::getInstance()->get(self::ORE_TIERS[$key + 1], 0)->getDrops(VanillaItems::DIAMOND_PICKAXE()));\n                    $event->setDrops($drops);\n                }\n            }\n        }\n    }\n\n    public function getPriority(): int\n    {\n        return 3;\n    }\n}\n"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/traits/ReactiveTrait.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\traits;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\ProjectileTracker;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\Utils;\nuse pocketmine\\entity\\projectile\\Projectile;\nuse pocketmine\\event\\entity\\EntityDamageByChildEntityEvent;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\entity\\ProjectileHitBlockEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\ntrait ReactiveTrait\n{\n    protected PiggyCustomEnchants $plugin;\n\n    /** @var float[] */\n    public $chanceMultiplier;\n\n    public function canReact(): bool\n    {\n        return true;\n    }\n\n    public function getReagent(): array\n    {\n        return [EntityDamageByEntityEvent::class];\n    }\n\n    public function onReaction(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        $perWorldDisabledEnchants = $this->plugin->getConfig()->get(\"per-world-disabled-enchants\");\n        if (isset($perWorldDisabledEnchants[$player->getWorld()->getFolderName()]) && in_array(strtolower($this->name), $perWorldDisabledEnchants[$player->getWorld()->getFolderName()])) return;\n        if ($this->getCooldown($player) > 0) return;\n        if ($event instanceof EntityDamageByEntityEvent) {\n            if ($event->getEntity() === $player) {\n                if ($event->getDamager() !== $player && !$this->shouldReactToDamaged()) return;\n            } elseif (!$this->shouldReactToDamage()) return;\n        }\n        if (mt_rand(0 * 100000, 100 * 100000) / 100000 <= $this->getChance($player, $level)) {\n            $this->react($player, $item, $inventory, $slot, $event, $level, $stack);\n            $this->setCooldown($player, $this->cooldownDuration);\n        }\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n    }\n\n    public function getChance(Player $player, int $level): float\n    {\n        $base = $this->getBaseChance($level);\n        $multiplier = $this->getChanceMultiplier($player);\n        return $base * $multiplier;\n    }\n\n    public function getBaseChance(int $level): float\n    {\n        return $this->chance * $level;\n    }\n\n    public function getChanceMultiplier(Player $player): float\n    {\n        return $this->chanceMultiplier[$player->getName()] ?? 1;\n    }\n\n    public function setChanceMultiplier(Player $player, float $multiplier): void\n    {\n        $this->chanceMultiplier[$player->getName()] = $multiplier;\n    }\n\n    public function getCooldownDuration(): int\n    {\n        return $this->cooldownDuration;\n    }\n\n    public function shouldReactToDamage(): bool\n    {\n        return $this->getItemType() === CustomEnchant::ITEM_TYPE_WEAPON || $this->getItemType() === CustomEnchant::ITEM_TYPE_BOW;\n    }\n\n    public function shouldReactToDamaged(): bool\n    {\n        return $this->getUsageType() === CustomEnchant::TYPE_ARMOR_INVENTORY;\n    }\n\n    public static function attemptReaction(Player $player, Event $event): void\n    {\n        if ($player->getInventory() === null) return;\n        if ($event instanceof EntityDamageByChildEntityEvent || $event instanceof ProjectileHitBlockEvent) {\n            $projectile = $event instanceof EntityDamageByEntityEvent ? $event->getChild() : $event->getEntity();\n            if ($projectile instanceof Projectile && ProjectileTracker::isTrackedProjectile($projectile)) {\n                if (!$event instanceof EntityDamageByEntityEvent || $event->getDamager() === $player) {\n                    foreach (Utils::sortEnchantmentsByPriority(ProjectileTracker::getEnchantments($projectile)) as $enchantmentInstance) {\n                        /** @var ReactiveEnchantment $enchantment */\n                        $enchantment = $enchantmentInstance->getType();\n                        if ($enchantment instanceof CustomEnchant && $enchantment->canReact()) {\n                            if ($enchantment->getUsageType() === CustomEnchant::TYPE_INVENTORY || $enchantment->getUsageType() === CustomEnchant::TYPE_ANY_INVENTORY || $enchantment->getUsageType() === CustomEnchant::TYPE_HAND) {\n                                foreach ($enchantment->getReagent() as $reagent) {\n                                    if ($event instanceof $reagent) {\n                                        $item = ProjectileTracker::getItem($projectile);\n                                        $slot = 0;\n                                        foreach ($player->getInventory()->getContents() as $s => $content) {\n                                            if ($content->equalsExact($item)) $slot = $s;\n                                        }\n                                        $enchantment->onReaction($player, $item, $player->getInventory(), $slot, $event, $enchantmentInstance->getLevel(), 1);\n                                    }\n                                }\n                            }\n                        }\n                    }\n                    ProjectileTracker::removeProjectile($projectile);\n                    return;\n                }\n            }\n        }\n        $enchantmentStacks = [];\n        foreach ($player->getInventory()->getContents() as $slot => $content) {\n            foreach (Utils::sortEnchantmentsByPriority($content->getEnchantments()) as $enchantmentInstance) {\n                /** @var ReactiveEnchantment $enchantment */\n                $enchantment = $enchantmentInstance->getType();\n                if ($enchantment instanceof CustomEnchant && $enchantment->canReact()) {\n                    if ($enchantment->getUsageType() === CustomEnchant::TYPE_INVENTORY || $enchantment->getUsageType() === CustomEnchant::TYPE_ANY_INVENTORY || ($enchantment->getUsageType() === CustomEnchant::TYPE_HAND && $player->getInventory()->getHeldItemIndex() === $slot)) {\n                        foreach ($enchantment->getReagent() as $reagent) {\n                            if ($event instanceof $reagent) {\n                                $enchantmentStacks[$enchantment->getId()] = ($enchantmentStacks[$enchantment->getId()] ?? 0) + $enchantmentInstance->getLevel();\n                                $enchantment->onReaction($player, $content, $player->getInventory(), $slot, $event, $enchantmentInstance->getLevel(), $enchantmentStacks[$enchantment->getId()]);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        foreach ($player->getArmorInventory()->getContents() as $slot => $content) {\n            foreach (Utils::sortEnchantmentsByPriority($content->getEnchantments()) as $enchantmentInstance) {\n                /** @var ReactiveEnchantment $enchantment */\n                $enchantment = $enchantmentInstance->getType();\n                if ($enchantment instanceof CustomEnchant && $enchantment->canReact()) {\n                    if ((\n                        $enchantment->getUsageType() === CustomEnchant::TYPE_ANY_INVENTORY ||\n                        $enchantment->getUsageType() === CustomEnchant::TYPE_ARMOR_INVENTORY ||\n                        $enchantment->getUsageType() === CustomEnchant::TYPE_HELMET && Utils::isHelmet($content) ||\n                        $enchantment->getUsageType() === CustomEnchant::TYPE_CHESTPLATE && Utils::isChestplate($content) ||\n                        $enchantment->getUsageType() === CustomEnchant::TYPE_LEGGINGS && Utils::isLeggings($content) ||\n                        $enchantment->getUsageType() === CustomEnchant::TYPE_BOOTS && Utils::isBoots($content)\n                    )) {\n                        foreach ($enchantment->getReagent() as $reagent) {\n                            if ($event instanceof $reagent) {\n                                $enchantmentStacks[$enchantment->getId()] = ($enchantmentStacks[$enchantment->getId()] ?? 0) + $enchantmentInstance->getLevel();\n                                $enchantment->onReaction($player, $content, $player->getArmorInventory(), $slot, $event, $enchantmentInstance->getLevel(), $enchantmentStacks[$enchantment->getId()]);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/traits/TickingTrait.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\traits;\n\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\ntrait TickingTrait\n{\n    protected PiggyCustomEnchants $plugin;\n\n    public function canTick(): bool\n    {\n        return true;\n    }\n\n    public function getTickingInterval(): int\n    {\n        return 1;\n    }\n\n    public function onTick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        $perWorldDisabledEnchants = $this->plugin->getConfig()->get(\"per-world-disabled-enchants\");\n        if (isset($perWorldDisabledEnchants[$player->getWorld()->getFolderName()]) && in_array(strtolower($this->name), $perWorldDisabledEnchants[$player->getWorld()->getFolderName()])) return;\n        if ($this->getCooldown($player) > 0) return;\n        $this->tick($player, $item, $inventory, $slot, $level);\n    }\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n\n    }\n\n    public function supportsMultipleItems(): bool\n    {\n        return false;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/traits/ToggleTrait.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\traits;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ToggleableEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\Utils;\nuse pocketmine\\inventory\\ArmorInventory;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\inventory\\PlayerInventory;\nuse pocketmine\\item\\enchantment\\EnchantmentInstance;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\ntrait ToggleTrait\n{\n    protected PiggyCustomEnchants $plugin;\n\n    /** @var int[] */\n    public array $stack = [];\n    /** @var int[] */\n    public array $equippedArmorStack = [];\n\n    public function canToggle(): bool\n    {\n        return true;\n    }\n\n    public function onToggle(Player $player, Item $item, Inventory $inventory, int $slot, int $level, bool $toggle): void\n    {\n        $perWorldDisabledEnchants = $this->plugin->getConfig()->get(\"per-world-disabled-enchants\");\n        if (isset($perWorldDisabledEnchants[$player->getWorld()->getFolderName()]) && in_array(strtolower($this->name), $perWorldDisabledEnchants[$player->getWorld()->getFolderName()])) return;\n        if ($this->getCooldown($player) > 0) return;\n        $toggle ? $this->addToStack($player, $level) : $this->removeFromStack($player, $level);\n        $this->toggle($player, $item, $inventory, $slot, $level, $toggle);\n    }\n\n    public function toggle(Player $player, Item $item, Inventory $inventory, int $slot, int $level, bool $toggle): void\n    {\n    }\n\n    public function addToStack(Player $player, int $level): void\n    {\n        $this->stack[$player->getName()] = $this->getStack($player) + $level;\n        $this->equippedArmorStack[$player->getName()] = $this->getArmorStack($player) + 1;\n    }\n\n    public function removeFromStack(Player $player, int $level): void\n    {\n        if (isset($this->stack[$player->getName()])) $this->stack[$player->getName()] -= $level;\n        $this->equippedArmorStack[$player->getName()] = $this->getArmorStack($player) - 1;\n    }\n\n    public function getStack(Player $player): int\n    {\n        if (isset($this->stack[$player->getName()])) return $this->stack[$player->getName()];\n        return 0;\n    }\n\n    public function getArmorStack(Player $player): int\n    {\n        if (isset($this->equippedArmorStack[$player->getName()])) return $this->equippedArmorStack[$player->getName()];\n        return 0;\n    }\n\n    public static function attemptToggle(Player $player, Item $item, EnchantmentInstance $enchantmentInstance, Inventory $inventory, int $slot, bool $toggle = true): void\n    {\n        /** @var ToggleableEnchantment $enchantment */\n        $enchantment = $enchantmentInstance->getType();\n        if (\n            $enchantment instanceof CustomEnchant && $enchantment->canToggle() && (\n                $enchantment->getUsageType() === CustomEnchant::TYPE_ANY_INVENTORY ||\n                ($enchantment->getUsageType() === CustomEnchant::TYPE_HAND && $inventory instanceof PlayerInventory && $inventory->getHeldItemIndex() === $slot) ||\n                (\n                    $inventory instanceof ArmorInventory && (\n                        $enchantment->getUsageType() === CustomEnchant::TYPE_ARMOR_INVENTORY ||\n                        $enchantment->getUsageType() === CustomEnchant::TYPE_HELMET && Utils::isHelmet($item) ||\n                        $enchantment->getUsageType() === CustomEnchant::TYPE_CHESTPLATE && Utils::isChestplate($item) ||\n                        $enchantment->getUsageType() === CustomEnchant::TYPE_LEGGINGS && Utils::isLeggings($item) ||\n                        $enchantment->getUsageType() === CustomEnchant::TYPE_BOOTS && Utils::isBoots($item)\n                    )\n                )\n            )\n        ) {\n            $enchantment->onToggle($player, $item, $inventory, $slot, $enchantmentInstance->getLevel(), $toggle);\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/BlessedEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass BlessedEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Blessed\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $maxLevel = 3;\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            foreach ($player->getEffects()->all() as $effect) {\n                if ($effect->getType()->isBad()) {\n                    $player->getEffects()->remove($effect->getType());\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/ConditionalDamageMultiplierEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass ConditionalDamageMultiplierEnchant extends ReactiveEnchantment\n{\n    /**\n     * @param callable $condition\n     */\n    public function __construct(PiggyCustomEnchants $plugin, int $id, string $name, private $condition, int $rarity = Rarity::RARE)\n    {\n        $this->name = $name;\n        $this->rarity = $rarity;\n        parent::__construct($plugin, $id);\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"additionalMultiplier\" => 0.1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            if (($this->condition)($event)) {\n                $event->setModifier($event->getFinalDamage() * $this->extraData[\"additionalMultiplier\"] * $level, $this->getId());\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/DeathbringerEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass DeathbringerEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Deathbringer\";\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"base\" => 2, \"multiplier\" => 0.1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $event->setModifier($this->extraData[\"base\"] + $level * $this->extraData[\"multiplier\"], CustomEnchantIds::DEATHBRINGER);\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/DeepWoundsEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\block\\VanillaBlocks;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\entity\\EntityDamageEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\nuse pocketmine\\scheduler\\ClosureTask;\nuse pocketmine\\world\\particle\\BlockBreakParticle;\n\nclass DeepWoundsEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Deep Wounds\";\n    public int $cooldownDuration = 7;\n\n    /** @var ClosureTask[] */\n    public static array $tasks;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"interval\" => 20, \"durationMultiplier\" => 20, \"base\" => 1, \"multiplier\" => 0.066];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $entity = $event->getEntity();\n            if (!isset(self::$tasks[$entity->getId()])) {\n                $endTime = time() + $this->extraData[\"durationMultiplier\"] * $level;\n                self::$tasks[$entity->getId()] = new ClosureTask(function () use ($entity, $endTime): void {\n                    if (!$entity->isAlive() || $entity->isClosed() || $entity->isFlaggedForDespawn() || $endTime < time()) {\n                        self::$tasks[$entity->getId()]->getHandler()->cancel();\n                        unset(self::$tasks[$entity->getId()]);\n                        return;\n                    }\n                    $entity->attack(new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_MAGIC, $this->extraData[\"base\"] + $entity->getHealth() * $this->extraData[\"multiplier\"]));\n                    $entity->getWorld()->addParticle($entity->getPosition()->add(0, 1, 0), new BlockBreakParticle(VanillaBlocks::REDSTONE()));\n                });\n                $this->plugin->getScheduler()->scheduleRepeatingTask(self::$tasks[$entity->getId()], $this->extraData[\"interval\"]);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/DisarmingEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass DisarmingEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Disarming\";\n    public int $rarity = Rarity::UNCOMMON;\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $entity = $event->getEntity();\n            if ($entity instanceof Player) {\n                if (count($contents = $entity->getInventory()->getContents(false)) > 0) {\n                    $item = $contents[array_rand($contents)];\n                    $entity->getInventory()->removeItem($item);\n                    $entity->dropItem($item);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/DisarmorEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons;\n\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass DisarmorEnchant extends DisarmingEnchant\n{\n    public string $name = \"Disarmor\";\n    public int $rarity = Rarity::UNCOMMON;\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $entity = $event->getEntity();\n            if ($entity instanceof Player) {\n                if (count($armorContents = $entity->getArmorInventory()->getContents(false)) > 0) {\n                    $item = $armorContents[array_rand($armorContents)];\n                    $entity->getArmorInventory()->removeItem($item);\n                    $entity->dropItem($item);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/GooeyEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\math\\Vector3;\nuse pocketmine\\player\\Player;\nuse pocketmine\\scheduler\\ClosureTask;\n\nclass GooeyEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Gooey\";\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"base\" => 0.75, \"multiplier\" => 0.15];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $entity = $event->getEntity();\n            $this->plugin->getScheduler()->scheduleDelayedTask(new ClosureTask(function () use ($entity, $level): void {\n                if (!$entity->isClosed() && !$entity->isFlaggedForDespawn()) $entity->setMotion(new Vector3($entity->getMotion()->x, $level * $this->extraData[\"multiplier\"] + $this->extraData[\"base\"], $entity->getMotion()->z));\n            }), 1);\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/HallucinationEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\block\\BlockFactory;\nuse pocketmine\\block\\BlockLegacyIds;\nuse pocketmine\\block\\tile\\Sign;\nuse pocketmine\\block\\tile\\Tile;\nuse pocketmine\\block\\VanillaBlocks;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\nbt\\tag\\CompoundTag;\nuse pocketmine\\network\\mcpe\\convert\\RuntimeBlockMapping;\nuse pocketmine\\network\\mcpe\\protocol\\BlockActorDataPacket;\nuse pocketmine\\network\\mcpe\\protocol\\serializer\\NetworkNbtSerializer;\nuse pocketmine\\network\\mcpe\\protocol\\types\\BlockPosition;\nuse pocketmine\\network\\mcpe\\protocol\\types\\CacheableNbt;\nuse pocketmine\\network\\mcpe\\protocol\\UpdateBlockPacket;\nuse pocketmine\\player\\Player;\nuse pocketmine\\scheduler\\ClosureTask;\nuse pocketmine\\utils\\TextFormat;\nuse pocketmine\\world\\Position;\n\nclass HallucinationEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Hallucination\";\n    public int $rarity = Rarity::MYTHIC;\n\n    /** @var NetworkNbtSerializer */\n    public $nbtWriter = null;\n\n    /** @var bool[] */\n    public static array $hallucinating;\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $entity = $event->getEntity();\n            if ($entity instanceof Player && !isset(self::$hallucinating[$entity->getName()])) {\n                $originalPosition = Position::fromObject($entity->getPosition()->round(), $entity->getWorld());\n                self::$hallucinating[$entity->getName()] = true;\n                $this->plugin->getScheduler()->scheduleRepeatingTask(($task = new ClosureTask(function () use ($entity, $originalPosition): void {\n                    $packets = [];\n                    for ($x = $originalPosition->x - 1; $x <= $originalPosition->x + 1; $x++) {\n                        for ($y = $originalPosition->y - 1; $y <= $originalPosition->y + 2; $y++) {\n                            for ($z = $originalPosition->z - 1; $z <= $originalPosition->z + 1; $z++) {\n                                $position = new Position($x, $y, $z, $originalPosition->getWorld());\n                                $block = VanillaBlocks::BEDROCK();\n                                if ($position->equals($originalPosition)) $block = VanillaBlocks::LAVA();\n                                if ($position->equals($originalPosition->add(0, 1, 0))) {\n                                    $block = BlockFactory::getInstance()->get(BlockLegacyIds::WALL_SIGN, 2);\n                                    if ($this->nbtWriter === null) $this->nbtWriter = new NetworkNbtSerializer();\n                                    $packets[] = BlockActorDataPacket::create(BlockPosition::fromVector3($position->floor()), new CacheableNbt(\n                                        CompoundTag::create()->\n                                        setString(Tile::TAG_ID, \"Sign\")->\n                                        setInt(Tile::TAG_X, $position->getFloorX())->\n                                        setInt(Tile::TAG_Y, $position->getFloorY())->\n                                        setInt(Tile::TAG_Z, $position->getFloorZ())->\n                                        setString(Sign::TAG_TEXT_BLOB, implode(\"\\n\", [\n                                                TextFormat::RED . \"You seem to be\",\n                                                TextFormat::RED . \"hallucinating...\"\n                                            ])\n                                        )));\n                                }\n                                $packets[] = UpdateBlockPacket::create(BlockPosition::fromVector3($position->floor()), RuntimeBlockMapping::getInstance()->toRuntimeId($block->getFullId()), UpdateBlockPacket::FLAG_NETWORK, UpdateBlockPacket::DATA_LAYER_NORMAL);\n                            }\n                        }\n                    }\n                    $entity->getServer()->broadcastPackets([$entity], $packets);\n                })), 1);\n                $this->plugin->getScheduler()->scheduleDelayedTask(new ClosureTask(function () use ($originalPosition, $entity, $task): void {\n                    $task->getHandler()->cancel();\n                    $blocks = [];\n                    for ($x = -1; $x <= 1; $x++) {\n                        for ($y = -1; $y <= 3; $y++) {\n                            for ($z = -1; $z <= 1; $z++) {\n                                $blocks[] = $originalPosition->round()->add($x, $y, $z);\n                            }\n                        }\n                    }\n                    $entity->getServer()->broadcastPackets([$entity], $entity->getWorld()->createBlockUpdatePackets($blocks));\n                    unset(self::$hallucinating[$entity->getName()]);\n                }), 20 * 60);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/LacedWeaponEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse pocketmine\\entity\\effect\\Effect;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\entity\\Living;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass LacedWeaponEnchant extends ReactiveEnchantment\n{\n    /**\n     * @param Effect[]|null $effects\n     * @param int[] $durationMultiplier\n     * @param int[] $amplifierMultiplier\n     * @param int[] $baseDuration\n     * @param int[] $baseAmplifier\n     */\n    public function __construct(PiggyCustomEnchants $plugin, int $id, string $name, int $rarity = Rarity::RARE, private ?array $effects = null, private array $durationMultiplier = [60], private array $amplifierMultiplier = [1], private array $baseDuration = [0], private array $baseAmplifier = [0])\n    {\n        $this->name = $name;\n        $this->rarity = $rarity;\n        $this->effects = $effects ?? [VanillaEffects::POISON()];\n        parent::__construct($plugin, $id);\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"durationMultiplier\" => $this->durationMultiplier, \"amplifierMultiplier\" => $this->amplifierMultiplier, \"baseDuration\" => $this->baseDuration, \"baseAmplifier\" => $this->baseAmplifier];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $entity = $event->getEntity();\n            if ($entity instanceof Living) {\n                foreach ($this->effects as $key => $effect) {\n                    $entity->getEffects()->add(new EffectInstance($effect, ($this->extraData[\"baseDuration\"][$key] ?? 0) + ($this->extraData[\"durationMultiplier\"][$key] ?? 60) * $level, ($this->extraData[\"baseAmplifier\"][$key] ?? 0) + ($this->extraData[\"amplifierMultiplier\"][$key] ?? 1) * $level));\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/LifestealEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass LifestealEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Lifesteal\";\n    public int $rarity = Rarity::COMMON;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"base\" => 2, \"multiplier\" => 1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $player->setHealth($player->getHealth() + $this->extraData[\"base\"] + $level * $this->extraData[\"multiplier\"] > $player->getMaxHealth() ? $player->getMaxHealth() : $player->getHealth() + $this->extraData[\"base\"] + $level * $this->extraData[\"multiplier\"]);\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/LightningEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PiggyLightning;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass LightningEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Lightning\";\n    public int $rarity = Rarity::MYTHIC;\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $lightning = new PiggyLightning($event->getEntity()->getLocation());\n            $lightning->setOwningEntity($player);\n            $lightning->spawnToAll();\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/VampireEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass VampireEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Vampire\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $maxLevel = 1;\n    public int $cooldownDuration = 5;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"healthMultiplier\" => 0.5, \"foodMultiplier\" => 0.5];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByEntityEvent) {\n            $player->setHealth($player->getHealth() + ($event->getFinalDamage() * $this->extraData[\"healthMultiplier\"]) > $player->getMaxHealth() ? $player->getMaxHealth() : $player->getHealth() + ($event->getFinalDamage() * $this->extraData[\"healthMultiplier\"]));\n            $player->getHungerManager()->setFood($player->getHungerManager()->getFood() + ($event->getFinalDamage() * $this->extraData[\"foodMultiplier\"]) > $player->getHungerManager()->getMaxFood() ? $player->getHungerManager()->getMaxFood() : $player->getHungerManager()->getFood() + ($event->getFinalDamage() * $this->extraData[\"foodMultiplier\"]));\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/bows/AutoAimEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\TickingEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\AllyChecks;\nuse pocketmine\\entity\\Living;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\math\\Vector2;\nuse pocketmine\\player\\Player;\n\nclass AutoAimEnchant extends TickingEnchantment\n{\n    public string $name = \"Auto Aim\";\n    public int $rarity = Rarity::MYTHIC;\n    public int $maxLevel = 1;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOW;\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"radiusMultiplier\" => 50];\n    }\n\n    public function tick(Player $player, Item $item, Inventory $inventory, int $slot, int $level): void\n    {\n        if ($player->isSneaking() && $player->isOnGround()) {\n            $target = $this->findNearestEntity($player, $level * $this->extraData[\"radiusMultiplier\"]);\n            if ($target !== null) {\n                $position = $target->getPosition()->subtractVector($player->getPosition());\n                $yaw = atan2($position->z, $position->x) * 180 / M_PI - 90;\n                $length = (new Vector2($position->x, $position->z))->length();\n                if ((int)$length !== 0) {\n                    $g = 0.006;\n                    $tmp = 1 - $g * ($g * ($length * $length) + 2 * $position->y);\n                    $pitch = 180 / M_PI * -(atan((1 - sqrt($tmp)) / ($g * $length)));\n                    $player->teleport($player->getPosition(), $yaw, $pitch);\n                }\n            }\n        }\n    }\n\n    public function findNearestEntity(Player $player, int $range): ?Living\n    {\n        $nearestEntity = null;\n        $nearestEntityDistance = $range;\n        foreach ($player->getWorld()->getEntities() as $entity) {\n            $distance = $player->getPosition()->distance($entity->getPosition());\n            if ($entity instanceof Living && $distance <= $range && $distance < $nearestEntityDistance && $player !== $entity && $entity->isAlive() && !$entity->isClosed() && !$entity->isFlaggedForDespawn() && !AllyChecks::isAlly($player, $entity)) {\n                $nearestEntity = $entity;\n                $nearestEntityDistance = $distance;\n            }\n        }\n        return $nearestEntity;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/bows/BombardmentEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\BombardmentTNT;\nuse pocketmine\\entity\\Location;\nuse pocketmine\\event\\entity\\EntityDamageByChildEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\math\\Vector3;\nuse pocketmine\\player\\Player;\n\nclass BombardmentEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Bombardment\";\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOW;\n\n    public function getReagent(): array\n    {\n        return [EntityDamageByChildEntityEvent::class];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByChildEntityEvent) {\n            $entity = $event->getEntity();\n            $bombardmentEntity = new BombardmentTNT(Location::fromObject($entity->getLocation()->add(0, 255 - $entity->getLocation()->y, 0), $entity->getWorld()), null, $level);\n            $bombardmentEntity->setOwningEntity($player);\n            $bombardmentEntity->setMotion(new Vector3(0, -5, 0));\n            $bombardmentEntity->spawnToAll();\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/bows/BountyHunterEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByChildEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\item\\ItemFactory;\nuse pocketmine\\item\\ItemIds;\nuse pocketmine\\player\\Player;\n\nclass BountyHunterEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Bounty Hunter\";\n    public int $rarity = Rarity::UNCOMMON;\n    public int $cooldownDuration = 30;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOW;\n\n    public function getReagent(): array\n    {\n        return [EntityDamageByChildEntityEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"base\" => 7, \"multiplier\" => 1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByChildEntityEvent) {\n            $bountyDrop = $this->getBounty();\n            $player->getInventory()->addItem(ItemFactory::getInstance()->get($bountyDrop, 0, mt_rand(1, $this->extraData[\"base\"] + $level * $this->extraData[\"multiplier\"])));\n        }\n    }\n\n    public function getBounty(): int\n    {\n        $random = mt_rand(0, 75);\n        $currentChance = 2.5;\n        if ($random < $currentChance) {\n            return ItemIds::EMERALD;\n        }\n        $currentChance += 5;\n        if ($random < $currentChance) {\n            return ItemIds::DIAMOND;\n        }\n        $currentChance += 15;\n        if ($random < $currentChance) {\n            return ItemIds::GOLD_INGOT;\n        }\n        $currentChance += 27.5;\n        if ($random < $currentChance) {\n            return ItemIds::IRON_INGOT;\n        }\n        return ItemIds::COAL;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/bows/GrapplingEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\Utils;\nuse pocketmine\\entity\\projectile\\Projectile;\nuse pocketmine\\event\\entity\\EntityDamageByChildEntityEvent;\nuse pocketmine\\event\\entity\\ProjectileHitBlockEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\math\\Vector3;\nuse pocketmine\\player\\Player;\nuse pocketmine\\scheduler\\ClosureTask;\n\nclass GrapplingEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Grappling\";\n    public int $maxLevel = 1;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOW;\n\n    public function getReagent(): array\n    {\n        return [EntityDamageByChildEntityEvent::class, ProjectileHitBlockEvent::class];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByChildEntityEvent) {\n            $projectile = $event->getChild();\n            $task = new ClosureTask(function () use ($event, $projectile): void {\n                if ($projectile instanceof Projectile) {\n                    $damagerPosition = $event->getDamager()->getPosition();\n                    $entity = $event->getEntity();\n                    $entityPosition = $entity->getPosition();\n                    $distance = $damagerPosition->distance($entityPosition);\n                    if ($distance > 0) {\n                        $motionX = (1.0 + 0.07 * $distance) * ($damagerPosition->x - $entityPosition->x) / $distance;\n                        $motionY = (1.0 + 0.03 * $distance) * ($damagerPosition->y - $entityPosition->y) / $distance - 0.5 * -0.08 * $distance;\n                        $motionZ = (1.0 + 0.07 * $distance) * ($damagerPosition->z - $entityPosition->z) / $distance;\n                        $entity->setMotion(new Vector3($motionX, $motionY, $motionZ));\n                    }\n                }\n            });\n            $this->plugin->getScheduler()->scheduleDelayedTask($task, 1);\n            Utils::setShouldTakeFallDamage($player, false);\n        }\n        if ($event instanceof ProjectileHitBlockEvent) {\n            $projectilePosition = $event->getEntity()->getPosition();\n            $shooter = $event->getEntity()->getOwningEntity();\n            $shooterPosition = $shooter->getPosition();\n            $distance = $projectilePosition->distance($shooterPosition);\n            if ($distance < 6) {\n                if ($projectilePosition->y > $shooterPosition->y) {\n                    $shooter->setMotion(new Vector3(0, 0.25, 0));\n                } else {\n                    $v = $projectilePosition->subtractVector($shooterPosition);\n                    $shooter->setMotion($v);\n                }\n            } else {\n                $motionX = (1.0 + 0.07 * $distance) * ($projectilePosition->x - $shooterPosition->x) / $distance;\n                $motionY = (1.0 + 0.03 * $distance) * ($projectilePosition->y - $shooterPosition->y) / $distance - 0.5 * -0.08 * $distance;\n                $motionZ = (1.0 + 0.07 * $distance) * ($projectilePosition->z - $shooterPosition->z) / $distance;\n                $shooter->setMotion(new Vector3($motionX, $motionY, $motionZ));\n            }\n            Utils::setShouldTakeFallDamage($player, false);\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/bows/HeadhunterEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByChildEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass HeadhunterEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Headhunter\";\n    public int $rarity = Rarity::UNCOMMON;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOW;\n\n    public function getReagent(): array\n    {\n        return [EntityDamageByChildEntityEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"additionalMultiplier\" => 0.1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByChildEntityEvent) {\n            if ($event->getChild()->getPosition()->y > $event->getEntity()->getPosition()->y + $event->getEntity()->getEyeHeight()) {\n                $event->setModifier($event->getFinalDamage() * $this->extraData[\"additionalMultiplier\"] * $level, CustomEnchantIds::HEADHUNTER);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/bows/HealingEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByChildEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass HealingEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Healing\";\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOW;\n\n    public function getReagent(): array\n    {\n        return [EntityDamageByChildEntityEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"healthReplenishMultiplier\" => 1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByChildEntityEvent) {\n            $player->setHealth($player->getHealth() + $event->getFinalDamage() + $level * $this->extraData[\"healthReplenishMultiplier\"] > $player->getMaxHealth() ? $player->getMaxHealth() : $player->getHealth() + $event->getFinalDamage() + $level * $this->extraData[\"healthReplenishMultiplier\"]);\n            foreach ($event->getModifiers() as $modifier => $damage) {\n                $event->setModifier(0, $modifier);\n            }\n            $event->setBaseDamage(0);\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/bows/MissileEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PiggyTNT;\nuse pocketmine\\event\\entity\\ProjectileHitBlockEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass MissileEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Missile\";\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOW;\n\n    public function getReagent(): array\n    {\n        return [ProjectileHitBlockEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"multiplier\" => 1];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof ProjectileHitBlockEvent) {\n            $projectile = $event->getEntity();\n            for ($i = 0; $i <= $level * $this->extraData[\"multiplier\"]; $i++) {\n                $tnt = new PiggyTNT($projectile->getLocation(), null, $this->plugin->getConfig()->getNested(\"world-damage.missile\", false));\n                $tnt->setFuse(40);\n                $tnt->setOwningEntity($player);\n                $tnt->spawnToAll();\n                $projectile->flagForDespawn();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/bows/MolotovEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\block\\VanillaBlocks;\nuse pocketmine\\entity\\Location;\nuse pocketmine\\entity\\object\\FallingBlock;\nuse pocketmine\\event\\entity\\EntityDamageByChildEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\math\\Vector3;\nuse pocketmine\\player\\Player;\n\nclass MolotovEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Molotov\";\n    public int $rarity = Rarity::UNCOMMON;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOW;\n\n    public function getReagent(): array\n    {\n        return [EntityDamageByChildEntityEvent::class];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByChildEntityEvent) {\n            $entity = $event->getEntity();\n            $boundaries = 0.1 * $level;\n            for ($x = $boundaries; $x >= -$boundaries; $x -= 0.1) {\n                for ($z = $boundaries; $z >= -$boundaries; $z -= 0.1) {\n                    $fire = new FallingBlock(Location::fromObject($entity->getLocation()->add(0.5, 1, 0.5), $entity->getWorld()), VanillaBlocks::FIRE());\n                    $fire->setMotion(new Vector3($x, 0.1, $z));\n                    $fire->setOnFire(1638); //Falling Sand with block id of fire not rendered by game\n                    $fire->spawnToAll();\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/bows/ParalyzeEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\entity\\Living;\nuse pocketmine\\event\\entity\\EntityDamageByChildEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass ParalyzeEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Paralyze\";\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOW;\n\n    public function getReagent(): array\n    {\n        return [EntityDamageByChildEntityEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\n            \"slownessBaseDuration\" => 40,\n            \"slownessDurationMultiplier\" => 20,\n            \"slownessBaseAmplifier\" => 4,\n            \"slownessAmplifierMultiplier\" => 1,\n            \"blindnessBaseDuration\" => 40,\n            \"blindnessDurationMultiplier\" => 20,\n            \"weaknessBaseDuration\" => 40,\n            \"weaknessDurationMultiplier\" => 20,\n            \"weaknessBaseAmplifier\" => 4,\n            \"weaknessAmplifierMultiplier\" => 1,\n        ];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByChildEntityEvent) {\n            $entity = $event->getEntity();\n            if ($entity instanceof Living) {\n                if (!$entity->getEffects()->has(VanillaEffects::SLOWNESS())) {\n                    $effect = new EffectInstance(VanillaEffects::SLOWNESS(), $this->extraData[\"slownessBaseDuration\"] + $level * $this->extraData[\"slownessDurationMultiplier\"], $this->extraData[\"slownessBaseAmplifier\"] + $level * $this->extraData[\"slownessAmplifierMultiplier\"], false);\n                    $entity->getEffects()->add($effect);\n                }\n                if (!$entity->getEffects()->has(VanillaEffects::BLINDNESS())) {\n                    $effect = new EffectInstance(VanillaEffects::BLINDNESS(), $this->extraData[\"blindnessBaseDuration\"] + $level * $this->extraData[\"blindnessDurationMultiplier\"], 1, false);\n                    $entity->getEffects()->add($effect);\n                }\n                if (!$entity->getEffects()->has(VanillaEffects::WEAKNESS())) {\n                    $effect = new EffectInstance(VanillaEffects::WEAKNESS(), $this->extraData[\"weaknessBaseDuration\"] + $level * $this->extraData[\"weaknessDurationMultiplier\"], $this->extraData[\"weaknessBaseAmplifier\"] + $level * $this->extraData[\"weaknessAmplifierMultiplier\"], false);\n                    $entity->getEffects()->add($effect);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/bows/PiercingEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\event\\entity\\EntityDamageByChildEntityEvent;\nuse pocketmine\\event\\entity\\EntityDamageEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass PiercingEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Piercing\";\n    public int $maxLevel = 1;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOW;\n\n    public function getReagent(): array\n    {\n        return [EntityDamageByChildEntityEvent::class];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByChildEntityEvent) {\n            $event->setModifier(0, EntityDamageEvent::MODIFIER_ARMOR);\n            $event->setModifier(0, EntityDamageEvent::MODIFIER_ARMOR_ENCHANTMENTS);\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/bows/ProjectileChangingEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\ProjectileTracker;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\Utils;\nuse pocketmine\\entity\\Entity;\nuse pocketmine\\entity\\projectile\\Projectile;\nuse pocketmine\\event\\entity\\EntityShootBowEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\n\nclass ProjectileChangingEnchant extends ReactiveEnchantment\n{\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOW;\n\n    /**\n     * @phpstan-param class-string<Entity> $projectileType\n     */\n    public function __construct(PiggyCustomEnchants $plugin, int $id, string $name, private string $projectileType, int $maxLevel = 1, int $rarity = Rarity::RARE)\n    {\n        $this->name = $name;\n        $this->rarity = $rarity;\n        $this->maxLevel = $maxLevel;\n        parent::__construct($plugin, $id);\n    }\n\n    public function getReagent(): array\n    {\n        return [EntityShootBowEvent::class];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityShootBowEvent) {\n            /** @var Projectile $projectile */\n            $projectile = $event->getProjectile();\n            ProjectileTracker::removeProjectile($projectile);\n\n            $newProjectile = Utils::createNewProjectile($this->projectileType, $projectile->getLocation(), $player, $projectile, $level);\n            $newProjectile->setMotion($projectile->getMotion());\n            $newProjectile->spawnToAll();\n\n            $event->setProjectile($newProjectile);\n            ProjectileTracker::addProjectile($newProjectile, $item);\n        }\n    }\n\n    public function getPriority(): int\n    {\n        return 2;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/bows/ShuffleEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse pocketmine\\entity\\Living;\nuse pocketmine\\event\\entity\\EntityDamageByChildEntityEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\Item;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass ShuffleEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Shuffle\";\n    public int $maxLevel = 1;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOW;\n\n    public function getReagent(): array\n    {\n        return [EntityDamageByChildEntityEvent::class];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityDamageByChildEntityEvent) {\n            $entity = $event->getEntity();\n            if ($entity instanceof Living) {\n                $playerPosition = clone $player->getPosition();\n                $entityPosition = clone $entity->getPosition();\n                $player->teleport($entityPosition);\n                $entity->teleport($playerPosition);\n                $name = $entity->getNameTag();\n                if (empty($name)) $name = $entity->getName();\n                if ($entity instanceof Player) {\n                    $name = $entity->getDisplayName();\n                    $entity->sendMessage(TextFormat::DARK_PURPLE . \"You have switched positions with \" . $player->getDisplayName());\n                }\n                $player->sendMessage(TextFormat::DARK_PURPLE . \"You have switched positions with \" . $name);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/enchants/weapons/bows/VolleyEnchant.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\enchants\\weapons\\bows;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\ReactiveEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\ProjectileTracker;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\Utils;\nuse pocketmine\\entity\\Location;\nuse pocketmine\\entity\\projectile\\Arrow;\nuse pocketmine\\entity\\projectile\\Projectile;\nuse pocketmine\\event\\entity\\EntityShootBowEvent;\nuse pocketmine\\event\\Event;\nuse pocketmine\\inventory\\Inventory;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\math\\Vector3;\nuse pocketmine\\player\\Player;\n\nclass VolleyEnchant extends ReactiveEnchantment\n{\n    public string $name = \"Volley\";\n    public int $rarity = Rarity::UNCOMMON;\n\n    public int $itemType = CustomEnchant::ITEM_TYPE_BOW;\n\n    public function getReagent(): array\n    {\n        return [EntityShootBowEvent::class];\n    }\n\n    public function getDefaultExtraData(): array\n    {\n        return [\"base\" => 1, \"multiplier\" => 2];\n    }\n\n    public function react(Player $player, Item $item, Inventory $inventory, int $slot, Event $event, int $level, int $stack): void\n    {\n        if ($event instanceof EntityShootBowEvent) {\n            $amount = $this->extraData[\"base\"] + $this->extraData[\"multiplier\"] * $level;\n            $anglesBetweenArrows = (45 / ($amount - 1)) * M_PI / 180;\n            $pitch = ($player->getLocation()->pitch + 90) * M_PI / 180;\n            $yaw = ($player->getLocation()->yaw + 90 - 45 / 2) * M_PI / 180;\n            /** @var Projectile $projectile */\n            $projectile = $event->getProjectile();\n            for ($i = 0; $i < $amount; $i++) {\n                $newProjectile = Utils::createNewProjectile(get_class($projectile), Location::fromObject($player->getEyePos(), $player->getWorld()), $player, $projectile);\n                $newDirection = new Vector3(sin($pitch) * cos($yaw + $anglesBetweenArrows * $i), cos($pitch), sin($pitch) * sin($yaw + $anglesBetweenArrows * $i));\n                $newProjectile->setMotion($newDirection->normalize()->multiply($projectile->getMotion()->multiply($event->getForce())->length()));\n                if ($newProjectile instanceof Arrow) $newProjectile->setPickupMode(Arrow::PICKUP_NONE);\n                if ($projectile->isOnFire()) $newProjectile->setOnFire($projectile->getFireTicks() / 20);\n                $newProjectile->spawnToAll();\n                ProjectileTracker::addProjectile($newProjectile, $item);\n            }\n            ProjectileTracker::removeProjectile($projectile);\n            $projectile->close();\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/entities/BombardmentTNT.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\entities;\n\nuse pocketmine\\block\\VanillaBlocks;\nuse pocketmine\\entity\\Location;\nuse pocketmine\\entity\\object\\FallingBlock;\nuse pocketmine\\nbt\\tag\\CompoundTag;\n\nclass BombardmentTNT extends FallingBlock\n{\n    private int $enchantmentLevel;\n\n    public function __construct(Location $location, ?CompoundTag $nbt = null, int $enchantmentLevel = 1)\n    {\n        parent::__construct($location, VanillaBlocks::TNT(), $nbt);\n        $this->enchantmentLevel = $enchantmentLevel;\n    }\n\n    public function getEnchantmentLevel(): int\n    {\n        return $this->enchantmentLevel;\n    }\n\n    public function saveNBT(): CompoundTag\n    {\n        return parent::saveNBT()->setInt(\"Level\", $this->enchantmentLevel);\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/entities/HomingArrow.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\entities;\n\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\AllyChecks;\nuse pocketmine\\entity\\Entity;\nuse pocketmine\\entity\\Living;\nuse pocketmine\\entity\\Location;\nuse pocketmine\\entity\\projectile\\Arrow;\nuse pocketmine\\math\\Vector3;\nuse pocketmine\\nbt\\tag\\CompoundTag;\nuse pocketmine\\player\\Player;\n\nclass HomingArrow extends Arrow\n{\n    private int $enchantmentLevel;\n\n    public function __construct(Location $location, ?Entity $shootingEntity, bool $critical, ?CompoundTag $nbt = null, int $enchantmentLevel = 1)\n    {\n        parent::__construct($location, $shootingEntity, $critical, $nbt);\n        $this->enchantmentLevel = $enchantmentLevel;\n    }\n\n    public function entityBaseTick(int $tickDiff = 1): bool\n    {\n        if (!$this->closed && !$this->isFlaggedForDespawn() && $this->blockHit === null) {\n            $target = $this->findNearestEntity($this->enchantmentLevel * 10);\n            if ($target !== null) {\n                $this->setMotion($target->getPosition()->add(0, $target->size->getHeight() / 2, 0)->subtractVector($this->getPosition())->normalize()->multiply(1.5));\n                $this->lookAt($target->getPosition()->add(0, $target->size->getHeight() / 2, 0));\n            }\n        }\n        return parent::entityBaseTick($tickDiff);\n    }\n\n    public function getEnchantmentLevel(): int\n    {\n        return $this->enchantmentLevel;\n    }\n\n    public function findNearestEntity(int $range): ?Living\n    {\n        $nearestEntity = null;\n        $nearestEntityDistance = $range;\n        foreach ($this->getWorld()->getEntities() as $entity) {\n            $distance = $this->location->distance($entity->getPosition());\n            if ($entity instanceof Living && $distance <= $range && $distance < $nearestEntityDistance && ($owner = $this->getOwningEntity()) !== $entity && $entity->isAlive() && !$entity->isClosed() && !$entity->isFlaggedForDespawn()) {\n                if (!$owner instanceof Player || !AllyChecks::isAlly($owner, $entity)) {\n                    $nearestEntity = $entity;\n                    $nearestEntityDistance = $distance;\n                }\n            }\n        }\n        return $nearestEntity;\n    }\n\n    public function lookAt(Vector3 $target): void\n    {\n        $horizontal = sqrt(($target->x - $this->location->x) ** 2 + ($target->z - $this->location->z) ** 2);\n        $vertical = $target->y - $this->location->y;\n        $this->location->pitch = -atan2($vertical, $horizontal) / M_PI * 180;\n\n        $xDist = $target->x - $this->location->x;\n        $zDist = $target->z - $this->location->z;\n        $this->location->yaw = atan2($zDist, $xDist) / M_PI * 180 - 90;\n        if ($this->location->yaw < 0) {\n            $this->location->yaw += 360.0;\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/entities/PigProjectile.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\entities;\n\nuse pocketmine\\entity\\Attribute;\nuse pocketmine\\entity\\Entity;\nuse pocketmine\\entity\\EntitySizeInfo;\nuse pocketmine\\entity\\Location;\nuse pocketmine\\entity\\object\\ItemEntity;\nuse pocketmine\\item\\Item;\nuse pocketmine\\item\\ItemFactory;\nuse pocketmine\\item\\ItemIds;\nuse pocketmine\\math\\Vector3;\nuse pocketmine\\nbt\\tag\\CompoundTag;\nuse pocketmine\\network\\mcpe\\protocol\\AddActorPacket;\nuse pocketmine\\network\\mcpe\\protocol\\types\\entity\\Attribute as NetworkAttribute;\nuse pocketmine\\network\\mcpe\\protocol\\types\\entity\\EntityIds;\nuse pocketmine\\network\\mcpe\\protocol\\types\\entity\\PropertySyncData;\nuse pocketmine\\player\\Player;\nuse pocketmine\\utils\\TextFormat;\n\nclass PigProjectile extends PiggyProjectile\n{\n    /**\n     * @const array<int, bool, bool, int, string>\n     */\n    const PORK_LEVELS = [\n        //level => [damage, dinnerbone, zombie, drop id, drop name]\n        1 => [1, false, false, ItemIds::AIR, \"\"],\n        2 => [2, false, false, ItemIds::RAW_PORKCHOP, \"Mysterious Raw Pork\"],\n        3 => [2, false, false, ItemIds::COOKED_PORKCHOP, \"Mysterious Cooked Pork\"],\n        4 => [3, true, false, ItemIds::COOKED_PORKCHOP, \"Mysterious Cooked Pork\"],\n        5 => [5, false, true, ItemIds::ROTTEN_FLESH, \"Mysterious Rotten Pork\"],\n        6 => [6, true, true, ItemIds::ROTTEN_FLESH, \"Mysterious Rotten Pork\"]\n    ];\n\n    /** @var float */\n    protected $drag = 0.01;\n    /** @var float */\n    protected $gravity = 0.05;\n\n    /** @var float */\n    protected $damage = 1.5;\n    private int $porkLevel;\n    private bool $zombie;\n\n    public function __construct(Location $location, ?Entity $shootingEntity, ?CompoundTag $nbt = null, int $porkLevel = 1)\n    {\n        parent::__construct($location, $shootingEntity, $nbt);\n        $this->porkLevel = max(1, min($porkLevel, 6));\n        $values = self::PORK_LEVELS[$this->porkLevel];\n        $this->damage = $values[0];\n        if ($values[1]) {\n            $this->setNameTag(\"Dinnerbone\");\n        }\n        $this->zombie = $values[2];\n    }\n\n    public function entityBaseTick(int $tickDiff = 1): bool\n    {\n        if ($this->closed) return false;\n        $hasUpdate = parent::entityBaseTick($tickDiff);\n        if (!$this->isCollided) {\n            if ($this->getPorkLevel() > 1) {\n                foreach ($this->getDrops() as $drop) {\n                    if (!$drop->isNull()) {\n                        $itemEntity = new ItemEntity(Location::fromObject($this->getPosition(), $this->getWorld(), lcg_value() * 360, 0), $drop);\n                        $itemEntity->setDespawnDelay(300);\n                        $itemEntity->setMotion(new Vector3(lcg_value() * 0.2 - 0.1, 0.2, lcg_value() * 0.2 - 0.1));\n                        $itemEntity->spawnToAll();\n                    }\n                }\n            }\n        } else {\n            $this->flagForDespawn();\n            $hasUpdate = true;\n        }\n        return $hasUpdate;\n    }\n\n    public function getPorkLevel(): int\n    {\n        return $this->porkLevel;\n    }\n\n    public function isZombie(): bool\n    {\n        return $this->zombie;\n    }\n\n    /**\n     * @return Item[]\n     */\n    public function getDrops(): array\n    {\n        $values = self::PORK_LEVELS[$this->getPorkLevel()];\n        return [\n            ItemFactory::getInstance()->get($values[3], 0, 1)->setCustomName(TextFormat::RESET . TextFormat::WHITE . $values[4])\n        ];\n    }\n\n    protected function sendSpawnPacket(Player $player): void\n    {\n        $player->getNetworkSession()->sendDataPacket(AddActorPacket::create(\n            $this->getId(),\n            $this->getId(),\n            $this->isZombie() ? EntityIds::ZOMBIE_PIGMAN : EntityIds::PIG,\n            $this->getPosition()->asVector3(),\n            $this->getMotion(),\n            $this->location->pitch,\n            $this->location->yaw,\n            $this->location->yaw,\n            $this->location->yaw,\n            array_map(function (Attribute $attr): NetworkAttribute {\n                return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue(), []);\n            }, $this->attributeMap->getAll()),\n            $this->getAllNetworkData(),\n            new PropertySyncData([], []),\n            []\n        ));\n    }\n\n    public static function getNetworkTypeId(): string\n    {\n        return EntityIds::PIG;\n    }\n\n    protected function getInitialSizeInfo(): EntitySizeInfo\n    {\n        return new EntitySizeInfo(0.9, 0.9);\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/entities/PiggyFireball.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\entities;\n\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\AllyChecks;\nuse pocketmine\\block\\Block;\nuse pocketmine\\block\\VanillaBlocks;\nuse pocketmine\\entity\\Entity;\nuse pocketmine\\entity\\EntitySizeInfo;\nuse pocketmine\\event\\entity\\EntityCombustByEntityEvent;\nuse pocketmine\\math\\RayTraceResult;\nuse pocketmine\\network\\mcpe\\protocol\\types\\entity\\EntityIds;\nuse pocketmine\\player\\Player;\n\nclass PiggyFireball extends PiggyProjectile\n{\n    /** @var float */\n    protected $drag = 0.01;\n    /** @var float */\n    protected $gravity = 0.05;\n\n    /** @var float */\n    protected $damage = 5;\n\n    public function onHitEntity(Entity $entityHit, RayTraceResult $hitResult): void\n    {\n        $owner = $this->getOwningEntity();\n        if (!$owner instanceof Player || !AllyChecks::isAlly($owner, $entityHit)) {\n            $ev = new EntityCombustByEntityEvent($this, $entityHit, 5);\n            $ev->call();\n            if (!$ev->isCancelled()) $entityHit->setOnFire($ev->getDuration());\n        }\n        parent::onHitEntity($entityHit, $hitResult);\n    }\n\n    public function onHitBlock(Block $blockHit, RayTraceResult $hitResult): void\n    {\n        $this->getWorld()->setBlock($this->location, VanillaBlocks::FIRE());\n        parent::onHitBlock($blockHit, $hitResult);\n    }\n\n    public static function getNetworkTypeId(): string\n    {\n        return EntityIds::SMALL_FIREBALL;\n    }\n\n    protected function getInitialSizeInfo(): EntitySizeInfo\n    {\n        return new EntitySizeInfo(0.5, 0.5);\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/entities/PiggyLightning.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\entities;\n\nuse DaPigGuy\\PiggyCustomEnchants\\CustomEnchantManager;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\AllyChecks;\nuse pocketmine\\block\\VanillaBlocks;\nuse pocketmine\\entity\\Entity;\nuse pocketmine\\entity\\EntitySizeInfo;\nuse pocketmine\\entity\\Living;\nuse pocketmine\\event\\entity\\EntityCombustByEntityEvent;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\entity\\EntityDamageEvent;\nuse pocketmine\\network\\mcpe\\protocol\\types\\entity\\EntityIds;\nuse pocketmine\\player\\Player;\n\nclass PiggyLightning extends Entity\n{\n    protected int $age = 0;\n\n    public function entityBaseTick(int $tickDiff = 1): bool\n    {\n        if ($this->closed) return false;\n        $this->age += $tickDiff;\n        $world = $this->getWorld();\n        foreach ($world->getNearbyEntities($this->getBoundingBox()->expandedCopy(4, 3, 4), $this) as $entity) {\n            if ($entity instanceof Living && $entity->isAlive() && $this->getOwningEntity() !== $entity) {\n                $owner = $this->getOwningEntity();\n                if (!$owner instanceof Player || !AllyChecks::isAlly($owner, $entity)) {\n                    $ev = new EntityCombustByEntityEvent($this, $entity, mt_rand(3, 8));\n                    $ev->call();\n                    if (!$ev->isCancelled()) $entity->setOnFire($ev->getDuration());\n                }\n                $ev = new EntityDamageByEntityEvent($this, $entity, EntityDamageEvent::CAUSE_CUSTOM, 5);\n                $ev->call();\n                if (!$ev->isCancelled()) $entity->attack($ev);\n            }\n        }\n        if ($this->getWorld()->getBlock($this->location)->canBeFlowedInto() && CustomEnchantManager::getPlugin()->getConfig()->getNested(\"world-damage.lightning\", false) === true) {\n            $this->getWorld()->setBlock($this->location, VanillaBlocks::FIRE());\n        }\n        if ($this->age > 20) $this->flagForDespawn();\n        return parent::entityBaseTick($tickDiff);\n    }\n\n    public static function getNetworkTypeId(): string\n    {\n        return EntityIds::LIGHTNING_BOLT;\n    }\n\n    protected function getInitialSizeInfo(): EntitySizeInfo\n    {\n        return new EntitySizeInfo(1.8, 0.3);\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/entities/PiggyProjectile.php",
    "content": "<?php\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\entities;\n\nuse pocketmine\\entity\\projectile\\Projectile;\nuse pocketmine\\event\\entity\\ProjectileHitEvent;\n\nabstract class PiggyProjectile extends Projectile\n{\n    public function onHit(ProjectileHitEvent $event): void\n    {\n        $this->flagForDespawn();\n        parent::onHit($event);\n    }\n\n    public function canSaveWithChunk(): bool\n    {\n        return false;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/entities/PiggyTNT.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\entities;\n\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\PiggyExplosion;\nuse pocketmine\\entity\\Location;\nuse pocketmine\\entity\\object\\PrimedTNT;\nuse pocketmine\\event\\entity\\ExplosionPrimeEvent;\nuse pocketmine\\nbt\\tag\\CompoundTag;\nuse pocketmine\\player\\Player;\nuse pocketmine\\world\\Position;\n\nclass PiggyTNT extends PrimedTNT\n{\n    private bool $worldDamage;\n\n    public function __construct(Location $location, ?CompoundTag $nbt = null, bool $worldDamage = false)\n    {\n        parent::__construct($location, $nbt);\n        $this->worldDamage = $worldDamage;\n    }\n\n    public function explode(): void\n    {\n        $ownerEntity = $this->getOwningEntity();\n        if (!$ownerEntity instanceof Player) {\n            return;\n        }\n        $ev = new ExplosionPrimeEvent($this, 4);\n        $ev->setBlockBreaking($this->worldDamage);\n        $ev->call();\n        if (!$ev->isCancelled()) {\n            $explosion = new PiggyExplosion(Position::fromObject($this->location->add(0, $this->size->getHeight() / 2, 0), $this->location->world), $ev->getForce(), $ownerEntity);\n            if ($ev->isBlockBreaking()) $explosion->explodeA();\n            $explosion->explodeB();\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/entities/PiggyWitherSkull.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\entities;\n\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\AllyChecks;\nuse pocketmine\\entity\\effect\\EffectInstance;\nuse pocketmine\\entity\\effect\\VanillaEffects;\nuse pocketmine\\entity\\Entity;\nuse pocketmine\\entity\\EntitySizeInfo;\nuse pocketmine\\entity\\Living;\nuse pocketmine\\math\\RayTraceResult;\nuse pocketmine\\network\\mcpe\\protocol\\types\\entity\\EntityIds;\nuse pocketmine\\player\\Player;\n\nclass PiggyWitherSkull extends PiggyProjectile\n{\n    /** @var float */\n    protected $drag = 0.01;\n    /** @var float */\n    protected $gravity = 0.05;\n\n    /** @var float */\n    protected $damage = 0;\n\n    public function onHitEntity(Entity $entityHit, RayTraceResult $hitResult): void\n    {\n        if ($entityHit instanceof Living) {\n            $owner = $this->getOwningEntity();\n            if (!$owner instanceof Player || !AllyChecks::isAlly($owner, $entityHit)) {\n                $effect = new EffectInstance(VanillaEffects::WITHER(), 800, 1);\n                $entityHit->getEffects()->add($effect);\n            }\n        }\n        parent::onHitEntity($entityHit, $hitResult);\n    }\n\n    public static function getNetworkTypeId(): string\n    {\n        return EntityIds::WITHER_SKULL;\n    }\n\n    protected function getInitialSizeInfo(): EntitySizeInfo\n    {\n        return new EntitySizeInfo(0.5, 0.5);\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/particles/JetpackParticle.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\particles;\n\nuse pocketmine\\math\\Vector3;\nuse pocketmine\\network\\mcpe\\protocol\\LevelEventPacket;\nuse pocketmine\\network\\mcpe\\protocol\\types\\ParticleIds;\nuse pocketmine\\world\\particle\\Particle;\n\nclass JetpackParticle implements Particle\n{\n    public function encode(Vector3 $pos): array\n    {\n        return [LevelEventPacket::standardParticle(ParticleIds::CAMPFIRE_SMOKE, 0, $pos)];\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/tasks/CheckDisabledEnchantsTask.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\tasks;\n\nuse DaPigGuy\\PiggyCustomEnchants\\CustomEnchantManager;\nuse pocketmine\\scheduler\\AsyncTask;\nuse pocketmine\\utils\\Internet;\n\nclass CheckDisabledEnchantsTask extends AsyncTask\n{\n    public function onRun(): void\n    {\n        //TODO: Pass through proxy w/ API & Plugin Version for statistics on plugin\n        $result = Internet::getURL(\"https://gist.githubusercontent.com/DaPigGuy/9c65a998bc0aa8d6b4708796110f7d11/raw/\", 10, [], $error);\n        $this->setResult([$result?->getBody(), $error]);\n    }\n\n    public function onCompletion(): void\n    {\n        [$body, $error] = $this->getResult();\n        if ($error === null) {\n            $plugin = CustomEnchantManager::getPlugin();\n            if ($plugin->isEnabled()) {\n                $disabledEnchants = json_decode($body, true);\n                foreach ($disabledEnchants as $disabledEnchantEntry) {\n                    if (\n                        count(array_intersect($disabledEnchantEntry[\"api\"], $plugin->getDescription()->getCompatibleApis())) > 0 ||\n                        in_array(\"all\", $disabledEnchantEntry[\"api\"], true) ||\n                        in_array($plugin->getDescription()->getVersion(), $disabledEnchantEntry[\"version\"], true) ||\n                        in_array(\"all\", $disabledEnchantEntry[\"version\"], true)\n                    ) {\n                        $plugin->getLogger()->info(\"Enchantment \" . $disabledEnchantEntry[\"name\"] . \" (id \" . $disabledEnchantEntry[\"id\"] . \") has been remotely disabled for \" . $disabledEnchantEntry[\"reason\"]);\n                        CustomEnchantManager::unregisterEnchantment($disabledEnchantEntry[\"id\"]);\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/tasks/TickEnchantmentsTask.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\tasks;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\TickingEnchantment;\nuse DaPigGuy\\PiggyCustomEnchants\\PiggyCustomEnchants;\nuse DaPigGuy\\PiggyCustomEnchants\\utils\\Utils;\nuse pocketmine\\item\\Item;\nuse pocketmine\\item\\ItemFactory;\nuse pocketmine\\item\\ItemIds;\nuse pocketmine\\scheduler\\Task;\nuse pocketmine\\Server;\nuse pocketmine\\utils\\TextFormat;\n\nclass TickEnchantmentsTask extends Task\n{\n    public function __construct(private PiggyCustomEnchants $plugin)\n    {\n    }\n\n    public function onRun(): void\n    {\n        $currentTick = Server::getInstance()->getTick();\n        foreach ($this->plugin->getServer()->getOnlinePlayers() as $player) {\n            $successfulEnchantments = [];\n            foreach ($player->getInventory()->getContents() as $slot => $content) {\n                if ($content->getId() === ItemIds::BOOK) {\n                    if (count($content->getEnchantments()) > 0) {\n                        $enchantedBook = ItemFactory::getInstance()->get(ItemIds::ENCHANTED_BOOK, 0, $content->getCount(), $content->getNamedTag());\n                        $enchantedBook->setCustomName(TextFormat::RESET . TextFormat::YELLOW . \"Enchanted Book\" . TextFormat::RESET);\n                        $enchantedBook->addEnchantment(...$content->getEnchantments());\n                        $player->getInventory()->setItem($slot, $enchantedBook);\n                        continue;\n                    }\n                }\n                if ($content->getNamedTag()->getTag(\"PiggyCEItemVersion\") === null && count($content->getEnchantments()) > 0) $player->getInventory()->setItem($slot, $this->cleanOldItems($content));\n                foreach ($content->getEnchantments() as $enchantmentInstance) {\n                    /** @var TickingEnchantment $enchantment */\n                    $enchantment = $enchantmentInstance->getType();\n                    if ($enchantment instanceof CustomEnchant && $enchantment->canTick()) {\n                        if (!in_array($enchantment, $successfulEnchantments, true) || $enchantment->supportsMultipleItems()) {\n                            if ((\n                                $enchantment->getUsageType() === CustomEnchant::TYPE_ANY_INVENTORY ||\n                                $enchantment->getUsageType() === CustomEnchant::TYPE_INVENTORY ||\n                                ($enchantment->getUsageType() === CustomEnchant::TYPE_HAND && $slot === $player->getInventory()->getHeldItemIndex())\n                            )) {\n                                if ($currentTick % $enchantment->getTickingInterval() === 0) {\n                                    $enchantment->onTick($player, $content, $player->getInventory(), $slot, $enchantmentInstance->getLevel());\n                                    $successfulEnchantments[] = $enchantment;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n            foreach ($player->getArmorInventory()->getContents() as $slot => $content) {\n                if ($content->getNamedTag()->getTag(\"PiggyCEItemVersion\") === null && count($content->getEnchantments()) > 0) $player->getArmorInventory()->setItem($slot, $this->cleanOldItems($content));\n                foreach ($content->getEnchantments() as $enchantmentInstance) {\n                    /** @var TickingEnchantment $enchantment */\n                    $enchantment = $enchantmentInstance->getType();\n                    if ($enchantment instanceof CustomEnchant && $enchantment->canTick()) {\n                        if (!in_array($enchantment, $successfulEnchantments, true) || $enchantment->supportsMultipleItems()) {\n                            if ((\n                                $enchantment->getUsageType() === CustomEnchant::TYPE_ANY_INVENTORY ||\n                                $enchantment->getUsageType() === CustomEnchant::TYPE_ARMOR_INVENTORY ||\n                                $enchantment->getUsageType() === CustomEnchant::TYPE_HELMET && Utils::isHelmet($content) ||\n                                $enchantment->getUsageType() === CustomEnchant::TYPE_CHESTPLATE && Utils::isChestplate($content) ||\n                                $enchantment->getUsageType() === CustomEnchant::TYPE_LEGGINGS && Utils::isLeggings($content) ||\n                                $enchantment->getUsageType() === CustomEnchant::TYPE_BOOTS && Utils::isBoots($content)\n                            )) {\n                                if ($currentTick % $enchantment->getTickingInterval() === 0) {\n                                    $enchantment->onTick($player, $content, $player->getArmorInventory(), $slot, $enchantmentInstance->getLevel());\n                                    $successfulEnchantments[] = $enchantment;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public function cleanOldItems(Item $item): Item\n    {\n        foreach ($item->getEnchantments() as $enchantmentInstance) {\n            $enchantment = $enchantmentInstance->getType();\n            if ($enchantment instanceof CustomEnchant) {\n                $item->setCustomName(str_replace(\"\\n\" . Utils::getColorFromRarity($enchantment->getRarity()) . $enchantment->name . \" \" . Utils::getRomanNumeral($enchantmentInstance->getLevel()), \"\", $item->getCustomName()));\n                $lore = $item->getLore();\n                if (($key = array_search(Utils::getColorFromRarity($enchantment->getRarity()) . $enchantment->name . \" \" . Utils::getRomanNumeral($enchantmentInstance->getLevel()), $lore, true)) !== false) {\n                    unset($lore[$key]);\n                }\n                $item->setLore($lore);\n            }\n        }\n        $item->getNamedTag()->setInt(\"PiggyCEItemVersion\", 0);\n        return $item;\n    }\n}\n"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/utils/AllyChecks.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\utils;\n\nuse pocketmine\\entity\\Entity;\nuse pocketmine\\player\\Player;\nuse pocketmine\\plugin\\Plugin;\nuse pocketmine\\utils\\Utils as PMMPUtils;\n\nclass AllyChecks\n{\n    /** @var mixed[][] */\n    private static array $checks = [];\n\n    /**\n     * @param Plugin $plugin\n     * @param callable $check\n     * @phpstan-param callable(Player $player, Entity $entity): bool $check\n     */\n    public static function addCheck(Plugin $plugin, callable $check): void\n    {\n        PMMPUtils::validateCallableSignature(function (Player $player, Entity $entity): bool {\n            return true;\n        }, $check);\n        self::$checks[] = [$plugin, $check];\n    }\n\n    public static function isAlly(Player $player, Entity $entity): bool\n    {\n        foreach (self::$checks as $check) {\n            if ($check[0]->isEnabled()) {\n                if (($check[1])($player, $entity)) return true;\n            }\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/utils/PiggyExplosion.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\utils;\n\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\miscellaneous\\RecursiveEnchant;\nuse pocketmine\\block\\TNT;\nuse pocketmine\\block\\VanillaBlocks;\nuse pocketmine\\event\\block\\BlockBreakEvent;\nuse pocketmine\\event\\entity\\EntityDamageByEntityEvent;\nuse pocketmine\\event\\entity\\EntityDamageEvent;\nuse pocketmine\\event\\entity\\EntityExplodeEvent;\nuse pocketmine\\math\\AxisAlignedBB;\nuse pocketmine\\math\\Vector3;\nuse pocketmine\\player\\Player;\nuse pocketmine\\world\\Explosion;\nuse pocketmine\\world\\particle\\HugeExplodeSeedParticle;\nuse pocketmine\\world\\Position;\nuse pocketmine\\world\\sound\\ExplodeSound;\n\nclass PiggyExplosion extends Explosion\n{\n    public function __construct(Position $center, float $size, protected Player $player, protected bool $entityDamage = true)\n    {\n        parent::__construct($center, $size, $this->player);\n    }\n\n    public function explodeB(): bool\n    {\n        $source = (new Vector3($this->source->x, $this->source->y, $this->source->z))->floor();\n        $yield = (1 / $this->size) * 100;\n\n        $ev = new EntityExplodeEvent($this->player, $this->source, $this->affectedBlocks, $yield);\n        $ev->call();\n        if ($ev->isCancelled()) {\n            return false;\n        } else {\n            $this->affectedBlocks = $ev->getBlockList();\n        }\n\n        $explosionSize = $this->size * 2;\n        $minX = (int)floor($this->source->x - $explosionSize - 1);\n        $maxX = (int)ceil($this->source->x + $explosionSize + 1);\n        $minY = (int)floor($this->source->y - $explosionSize - 1);\n        $maxY = (int)ceil($this->source->y + $explosionSize + 1);\n        $minZ = (int)floor($this->source->z - $explosionSize - 1);\n        $maxZ = (int)ceil($this->source->z + $explosionSize + 1);\n\n        $explosionBB = new AxisAlignedBB($minX, $minY, $minZ, $maxX, $maxY, $maxZ);\n\n        $list = $this->world->getNearbyEntities($explosionBB, $this->player);\n        foreach ($list as $entity) {\n            $entityPos = $entity->getPosition();\n            $distance = $entityPos->distance($this->source) / $explosionSize;\n\n            if ($distance <= 1 && $this->entityDamage) {\n                $motion = $entityPos->subtractVector($this->source)->normalize();\n                $impact = (1 - $distance);\n                $damage = (int)((($impact * $impact + $impact) / 2) * 8 * $explosionSize + 1);\n\n                $ev = new EntityDamageByEntityEvent($this->player, $entity, EntityDamageEvent::CAUSE_ENTITY_EXPLOSION, $damage);\n                $entity->attack($ev);\n                $entity->setMotion($motion->multiply($impact));\n            }\n        }\n\n        $airBlock = VanillaBlocks::AIR();\n\n        $item = $this->player->getInventory()->getItemInHand();\n        RecursiveEnchant::$isUsing[$this->player->getName()] = true;\n        foreach ($this->affectedBlocks as $key => $block) {\n            $ev = new BlockBreakEvent($this->player, $block, $item, true, $block->getDrops($item));\n            $ev->call();\n            if ($ev->isCancelled()) {\n                unset($this->affectedBlocks[$key]);\n                continue;\n            }\n            $pos = $block->getPosition();\n            if ($block instanceof TNT) {\n                $block->ignite(mt_rand(10, 30));\n            } else {\n                foreach ($ev->getDrops() as $drop) {\n                    $this->world->dropItem($pos->add(0.5, 0.5, 0.5), $drop);\n                }\n                if (($t = $this->world->getTileAt((int)$pos->x, (int)$pos->y, (int)$pos->z)) !== null) {\n                    $t->onBlockDestroyed(); //needed to create drops for inventories\n                }\n                $this->world->setBlockAt((int)$pos->x, (int)$pos->y, (int)$pos->z, $airBlock, false);\n            }\n        }\n        unset(RecursiveEnchant::$isUsing[$this->player->getName()]);\n\n        $this->world->addParticle($source, new HugeExplodeSeedParticle());\n        $this->world->addSound($source, new ExplodeSound());\n        return true;\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/utils/ProjectileTracker.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\utils;\n\nuse pocketmine\\entity\\projectile\\Projectile;\nuse pocketmine\\item\\enchantment\\EnchantmentInstance;\nuse pocketmine\\item\\Item;\n\nclass ProjectileTracker\n{\n    /** @var Item[] */\n    public static array $projectile = [];\n\n    public static function addProjectile(Projectile $projectile, Item $item): void\n    {\n        self::$projectile[$projectile->getId()] = $item;\n    }\n\n    public static function isTrackedProjectile(Projectile $projectile): bool\n    {\n        return isset(self::$projectile[$projectile->getId()]);\n    }\n\n    public static function getItem(Projectile $projectile): ?Item\n    {\n        if (!isset(self::$projectile[$projectile->getId()])) return null;\n        return self::$projectile[$projectile->getId()];\n    }\n\n    /**\n     * @return EnchantmentInstance[]\n     */\n    public static function getEnchantments(Projectile $projectile): array\n    {\n        if (!isset(self::$projectile[$projectile->getId()])) return [];\n        $item = self::$projectile[$projectile->getId()];\n        return $item->getEnchantments();\n    }\n\n    public static function removeProjectile(Projectile $projectile): void\n    {\n        if (!isset(self::$projectile[$projectile->getId()])) return;\n        unset(self::$projectile[$projectile->getId()]);\n    }\n}"
  },
  {
    "path": "src/DaPigGuy/PiggyCustomEnchants/utils/Utils.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DaPigGuy\\PiggyCustomEnchants\\utils;\n\nuse DaPigGuy\\PiggyCustomEnchants\\CustomEnchantManager;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchant;\nuse DaPigGuy\\PiggyCustomEnchants\\enchants\\CustomEnchantIds;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\HomingArrow;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PiggyFireball;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PiggyWitherSkull;\nuse DaPigGuy\\PiggyCustomEnchants\\entities\\PigProjectile;\nuse InvalidArgumentException;\nuse jojoe77777\\FormAPI\\SimpleForm;\nuse pocketmine\\entity\\Location;\nuse pocketmine\\entity\\projectile\\Arrow;\nuse pocketmine\\entity\\projectile\\Projectile;\nuse pocketmine\\inventory\\ArmorInventory;\nuse pocketmine\\item\\Armor;\nuse pocketmine\\item\\Axe;\nuse pocketmine\\item\\Bow;\nuse pocketmine\\item\\Compass;\nuse pocketmine\\item\\Durable;\nuse pocketmine\\item\\enchantment\\EnchantmentInstance;\nuse pocketmine\\item\\enchantment\\Rarity;\nuse pocketmine\\item\\Hoe;\nuse pocketmine\\item\\Item;\nuse pocketmine\\item\\ItemIds;\nuse pocketmine\\item\\Pickaxe;\nuse pocketmine\\item\\Shears;\nuse pocketmine\\item\\Shovel;\nuse pocketmine\\item\\Sword;\nuse pocketmine\\nbt\\tag\\CompoundTag;\nuse pocketmine\\network\\mcpe\\convert\\TypeConverter;\nuse pocketmine\\network\\mcpe\\protocol\\types\\inventory\\ItemStack;\nuse pocketmine\\player\\Player;\nuse pocketmine\\plugin\\PluginDescription;\nuse pocketmine\\utils\\TextFormat;\n\nclass Utils\n{\n    const TYPE_NAMES = [\n        CustomEnchant::ITEM_TYPE_ARMOR => \"Armor\",\n        CustomEnchant::ITEM_TYPE_HELMET => \"Helmet\",\n        CustomEnchant::ITEM_TYPE_CHESTPLATE => \"Chestplate\",\n        CustomEnchant::ITEM_TYPE_LEGGINGS => \"Leggings\",\n        CustomEnchant::ITEM_TYPE_BOOTS => \"Boots\",\n        CustomEnchant::ITEM_TYPE_WEAPON => \"Weapon\",\n        CustomEnchant::ITEM_TYPE_SWORD => \"Sword\",\n        CustomEnchant::ITEM_TYPE_BOW => \"Bow\",\n        CustomEnchant::ITEM_TYPE_TOOLS => \"Tools\",\n        CustomEnchant::ITEM_TYPE_PICKAXE => \"Pickaxe\",\n        CustomEnchant::ITEM_TYPE_AXE => \"Axe\",\n        CustomEnchant::ITEM_TYPE_SHOVEL => \"Shovel\",\n        CustomEnchant::ITEM_TYPE_HOE => \"Hoe\",\n        CustomEnchant::ITEM_TYPE_DAMAGEABLE => \"Damageable\",\n        CustomEnchant::ITEM_TYPE_GLOBAL => \"Global\",\n        CustomEnchant::ITEM_TYPE_COMPASS => \"Compass\",\n    ];\n\n    const RARITY_NAMES = [\n        Rarity::COMMON => \"Common\",\n        Rarity::UNCOMMON => \"Uncommon\",\n        Rarity::RARE => \"Rare\",\n        Rarity::MYTHIC => \"Mythic\"\n    ];\n\n    const INCOMPATIBLE_ENCHANTS = [\n        CustomEnchantIds::BLAZE => [CustomEnchantIds::PORKIFIED, CustomEnchantIds::WITHERSKULL],\n        CustomEnchantIds::GRAPPLING => [CustomEnchantIds::VOLLEY],\n        CustomEnchantIds::GROW => [CustomEnchantIds::SHRINK],\n        CustomEnchantIds::HOMING => [CustomEnchantIds::BLAZE, CustomEnchantIds::PORKIFIED, CustomEnchantIds::WITHERSKULL],\n        CustomEnchantIds::PORKIFIED => [CustomEnchantIds::WITHERSKULL]\n    ];\n\n    /** @var int[] */\n    public static array $shouldTakeFallDamage;\n\n    public static function getRomanNumeral(int $integer): string\n    {\n        $romanNumeralConversionTable = [\n            'M' => 1000,\n            'CM' => 900,\n            'D' => 500,\n            'CD' => 400,\n            'C' => 100,\n            'XC' => 90,\n            'L' => 50,\n            'XL' => 40,\n            'X' => 10,\n            'IX' => 9,\n            'V' => 5,\n            'IV' => 4,\n            'I' => 1\n        ];\n        $romanString = \"\";\n        while ($integer > 0) {\n            foreach ($romanNumeralConversionTable as $rom => $arb) {\n                if ($integer >= $arb) {\n                    $integer -= $arb;\n                    $romanString .= $rom;\n                    break;\n                }\n            }\n        }\n        return $romanString;\n    }\n\n    public static function isHelmet(Item $item): bool\n    {\n        return $item instanceof Armor && $item->getArmorSlot() === ArmorInventory::SLOT_HEAD;\n    }\n\n    public static function isChestplate(Item $item): bool\n    {\n        return $item instanceof Armor && $item->getArmorSlot() === ArmorInventory::SLOT_CHEST;\n    }\n\n    public static function isLeggings(Item $item): bool\n    {\n        return $item instanceof Armor && $item->getArmorSlot() === ArmorInventory::SLOT_LEGS;\n    }\n\n    public static function isBoots(Item $item): bool\n    {\n        return $item instanceof Armor && $item->getArmorSlot() === ArmorInventory::SLOT_FEET;\n    }\n\n    public static function itemMatchesItemType(Item $item, int $itemType): bool\n    {\n        if ($item->getId() === ItemIds::BOOK || $item->getId() === ItemIds::ENCHANTED_BOOK) return true;\n        return match ($itemType) {\n            CustomEnchant::ITEM_TYPE_GLOBAL => true,\n            CustomEnchant::ITEM_TYPE_DAMAGEABLE => $item instanceof Durable,\n            CustomEnchant::ITEM_TYPE_WEAPON => $item instanceof Sword || $item instanceof Axe || $item instanceof Bow,\n            CustomEnchant::ITEM_TYPE_SWORD => $item instanceof Sword,\n            CustomEnchant::ITEM_TYPE_BOW => $item instanceof Bow,\n            CustomEnchant::ITEM_TYPE_TOOLS => $item instanceof Pickaxe || $item instanceof Axe || $item instanceof Shovel || $item instanceof Hoe || $item instanceof Shears,\n            CustomEnchant::ITEM_TYPE_PICKAXE => $item instanceof Pickaxe,\n            CustomEnchant::ITEM_TYPE_AXE => $item instanceof Axe,\n            CustomEnchant::ITEM_TYPE_SHOVEL => $item instanceof Shovel,\n            CustomEnchant::ITEM_TYPE_HOE => $item instanceof Hoe,\n            CustomEnchant::ITEM_TYPE_ARMOR => $item instanceof Armor || $item->getId() === ItemIds::ELYTRA,\n            CustomEnchant::ITEM_TYPE_HELMET => self::isHelmet($item),\n            CustomEnchant::ITEM_TYPE_CHESTPLATE => self::isChestplate($item),\n            CustomEnchant::ITEM_TYPE_LEGGINGS => self::isLeggings($item),\n            CustomEnchant::ITEM_TYPE_BOOTS => self::isBoots($item),\n            CustomEnchant::ITEM_TYPE_COMPASS => $item instanceof Compass,\n            default => false,\n        };\n    }\n\n    public static function createNewProjectile(string $className, Location $location, Player $shooter, Projectile $previousProjectile, int $level = 1): Projectile\n    {\n        return match ($className) {\n            Arrow::class => new Arrow($location, $shooter, $previousProjectile instanceof Arrow ? $previousProjectile->isCritical() : false, null),\n            HomingArrow::class => new HomingArrow($location, $shooter, $previousProjectile instanceof Arrow ? $previousProjectile->isCritical() : false, null, $previousProjectile instanceof HomingArrow ? $previousProjectile->getEnchantmentLevel() : $level),\n            PiggyFireball::class, PiggyWitherSkull::class => new $className($location, $shooter, null),\n            PigProjectile::class => new PigProjectile($location, $shooter, null, $previousProjectile instanceof PigProjectile ? $previousProjectile->getPorkLevel() : $level),\n            default => throw new InvalidArgumentException(\"Entity $className not found\"),\n        };\n    }\n\n    public static function checkEnchantIncompatibilities(Item $item, CustomEnchant $enchant): bool\n    {\n        foreach ($item->getEnchantments() as $enchantment) {\n            $otherEnchant = $enchantment->getType();\n            if (!$otherEnchant instanceof CustomEnchant) continue;\n            if (isset(self::INCOMPATIBLE_ENCHANTS[$otherEnchant->getId()]) && in_array($enchant->getId(), self::INCOMPATIBLE_ENCHANTS[$otherEnchant->getId()], true)) return false;\n            if (isset(self::INCOMPATIBLE_ENCHANTS[$enchant->getId()]) && in_array($otherEnchant->getId(), self::INCOMPATIBLE_ENCHANTS[$enchant->getId()], true)) return false;\n        }\n        return true;\n    }\n\n    public static function displayEnchants(ItemStack $itemStack): ItemStack\n    {\n        $plugin = CustomEnchantManager::getPlugin();\n        $item = TypeConverter::getInstance()->netItemStackToCore($itemStack);\n        if (count($item->getEnchantments()) > 0) {\n            $additionalInformation = $plugin->getConfig()->getNested(\"enchants.position\") === \"name\" ? TextFormat::RESET . TextFormat::WHITE . $item->getName() : \"\";\n            foreach ($item->getEnchantments() as $enchantmentInstance) {\n                $enchantment = $enchantmentInstance->getType();\n                if ($enchantment instanceof CustomEnchant) {\n                    $additionalInformation .= \"\\n\" . TextFormat::RESET . Utils::getColorFromRarity($enchantment->getRarity()) . $enchantment->getDisplayName() . \" \" . ($plugin->getConfig()->getNested(\"enchants.roman-numerals\", true) === true ? Utils::getRomanNumeral($enchantmentInstance->getLevel()) : $enchantmentInstance->getLevel());\n                }\n            }\n            if ($item->getNamedTag()->getTag(Item::TAG_DISPLAY)) $item->getNamedTag()->setTag(\"OriginalDisplayTag\", $item->getNamedTag()->getTag(Item::TAG_DISPLAY)->safeClone());\n            if (CustomEnchantManager::getPlugin()->getConfig()->getNested(\"enchants.position\", \"name\") === \"lore\") {\n                $lore = array_merge(explode(\"\\n\", $additionalInformation), $item->getLore());\n                array_shift($lore);\n                $item = $item->setLore($lore);\n            } else {\n                $item = $item->setCustomName($additionalInformation);\n            }\n        }\n        if (CustomEnchantManager::getPlugin()->getDescription()->getName() !== \"PiggyCustomEnchants\" || !in_array(\"DaPigGuy\", CustomEnchantManager::getPlugin()->getDescription()->getAuthors(), true)) $item->getNamedTag()->setString(\"LolGetRekted\", \"Loser\");\n        return TypeConverter::getInstance()->coreItemStackToNet($item);\n    }\n\n    public static function filterDisplayedEnchants(ItemStack $itemStack): ItemStack\n    {\n        $item = TypeConverter::getInstance()->netItemStackToCore($itemStack);\n        $tag = $item->getNamedTag();\n        if (count($item->getEnchantments()) > 0) $tag->removeTag(Item::TAG_DISPLAY);\n        if ($tag->getTag(\"OriginalDisplayTag\") instanceof CompoundTag) {\n            $tag->setTag(Item::TAG_DISPLAY, $tag->getTag(\"OriginalDisplayTag\"));\n            $tag->removeTag(\"OriginalDisplayTag\");\n        }\n        $item->setNamedTag($tag);\n        return TypeConverter::getInstance()->coreItemStackToNet($item);\n    }\n\n    /**\n     * @param EnchantmentInstance[] $enchantments\n     * @return EnchantmentInstance[]\n     */\n    public static function sortEnchantmentsByPriority(array $enchantments): array\n    {\n        usort($enchantments, function (EnchantmentInstance $enchantmentInstance, EnchantmentInstance $enchantmentInstanceB) {\n            $type = $enchantmentInstance->getType();\n            $typeB = $enchantmentInstanceB->getType();\n            return ($typeB instanceof CustomEnchant ? $typeB->getPriority() : 1) - ($type instanceof CustomEnchant ? $type->getPriority() : 1);\n        });\n        return $enchantments;\n    }\n\n    public static function getColorFromRarity(int $rarity): string\n    {\n        return self::getTFConstFromString(CustomEnchantManager::getPlugin()->getConfig()->get(\"rarity-colors\")[strtolower(self::RARITY_NAMES[$rarity])]);\n    }\n\n    public static function getTFConstFromString(string $color): string\n    {\n        $colorConversionTable = [\n            \"BLACK\" => TextFormat::BLACK,\n            \"DARK_BLUE\" => TextFormat::DARK_BLUE,\n            \"DARK_GREEN\" => TextFormat::DARK_GREEN,\n            \"DARK_AQUA\" => TextFormat::DARK_AQUA,\n            \"DARK_RED\" => TextFormat::DARK_RED,\n            \"DARK_PURPLE\" => TextFormat::DARK_PURPLE,\n            \"GOLD\" => TextFormat::GOLD,\n            \"GRAY\" => TextFormat::GRAY,\n            \"DARK_GRAY\" => TextFormat::DARK_GRAY,\n            \"BLUE\" => TextFormat::BLUE,\n            \"GREEN\" => TextFormat::GREEN,\n            \"AQUA\" => TextFormat::AQUA,\n            \"RED\" => TextFormat::RED,\n            \"LIGHT_PURPLE\" => TextFormat::LIGHT_PURPLE,\n            \"YELLOW\" => TextFormat::YELLOW,\n            \"WHITE\" => TextFormat::WHITE\n        ];\n        return $colorConversionTable[strtoupper($color)] ?? TextFormat::GRAY;\n    }\n\n    public static function errorForm(Player $player, string $error): void\n    {\n        $form = new SimpleForm(fn(Player $player, ?int $data) => !is_null($data) ? $player->getServer()->dispatchCommand($player, \"ce\") : null);\n        $form->setTitle(TextFormat::RED . \"Error\");\n        $form->setContent($error);\n        $form->addButton(TextFormat::BOLD . \"Back\");\n        $player->sendForm($form);\n    }\n\n    public static function shouldTakeFallDamage(Player $player): bool\n    {\n        return !isset(self::$shouldTakeFallDamage[$player->getName()]);\n    }\n\n    public static function setShouldTakeFallDamage(Player $player, bool $shouldTakeFallDamage, int $duration = 1): void\n    {\n        unset(self::$shouldTakeFallDamage[$player->getName()]);\n        if (!$shouldTakeFallDamage) self::$shouldTakeFallDamage[$player->getName()] = time() + $duration;\n    }\n\n    public static function getNoFallDamageDuration(Player $player): int\n    {\n        return (self::$shouldTakeFallDamage[$player->getName()] ?? time()) - time();\n    }\n\n    public static function increaseNoFallDamageDuration(Player $player, int $duration = 1): void\n    {\n        self::$shouldTakeFallDamage[$player->getName()] += $duration;\n    }\n\n    public static function isCoolKid(PluginDescription $description): bool\n    {\n        return $description->getName() === \"PiggyCustomEnchants\" && in_array(\"DaPigGuy\", $description->getAuthors(), true);\n    }\n}"
  }
]