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