Compare commits

..

192 Commits

Author SHA1 Message Date
Auxilor
36c77d81eb Fixed included modules 2022-02-19 18:33:16 +00:00
Auxilor
b6cd56ad15 Fixed supported versions 2022-02-19 18:33:04 +00:00
Auxilor
1a524aea94 Updated to 6.25.2 2022-02-19 18:32:29 +00:00
Auxilor
2ebab99a06 Removed support for 1.16.5 2022-02-19 18:31:36 +00:00
Auxilor
46663f7edb Merge branch 'master' into develop 2022-02-19 18:29:18 +00:00
Will FP
4fad66cd90 Update README.md 2022-02-19 18:26:37 +00:00
Auxilor
a9fafeec00 Lightened cache on MySQL 2022-02-19 11:51:05 +00:00
Auxilor
0d8308d6cd Updated dependencies 2022-02-19 11:48:38 +00:00
Auxilor
13772002e8 Updated to 6.25.1 2022-02-17 17:03:16 +00:00
Auxilor
c9b84889e7 Fixed recursive caching bug 2022-02-17 17:03:10 +00:00
Auxilor
1513578266 Fixed recursive caching bug 2022-02-17 17:01:42 +00:00
Auxilor
89d6f2f867 Fixed initialization order 2022-02-17 12:53:54 +00:00
Auxilor
8e6d98c997 More MySQL Changes 2022-02-17 12:51:43 +00:00
Auxilor
5bc2cb31a4 Switched expiry from write to access (MySQL) 2022-02-17 12:47:59 +00:00
Auxilor
041575a103 Cached rows and columns with Caffeine 2022-02-17 12:47:32 +00:00
Auxilor
c88dac56b7 Added ability to manually categorize keys to improve performance 2022-02-17 12:21:26 +00:00
Auxilor
00da717f6d Changed key serialization 2022-02-17 11:49:26 +00:00
Auxilor
cc557378cc Preloaded known data keys 2022-02-16 18:16:09 +00:00
Auxilor
b5c49c79b8 Improvements to key saving 2022-02-16 18:13:04 +00:00
Auxilor
28018430e7 Categorized keys are now saved completely serialized 2022-02-16 18:01:41 +00:00
Auxilor
7b6c8d68a8 Key registration changes 2022-02-16 17:38:07 +00:00
Auxilor
ad3cb3a620 Fixed postInit 2022-02-16 16:48:40 +00:00
Auxilor
511a7e4830 Added optimisations to lazy column creation 2022-02-16 16:42:47 +00:00
Auxilor
5aeeafc041 MySQL Data Changes: Keys are now registered on first read/write 2022-02-16 16:32:38 +00:00
Auxilor
9a51fb8358 Updated to 6.25.0 2022-02-16 16:11:31 +00:00
Auxilor
eeefb9f40e Server persistence changes 2022-02-16 16:01:55 +00:00
Auxilor
aa1ce34cbc Updated to 6.24.4 2022-02-16 14:21:49 +00:00
Auxilor
47772c3ff7 Reverted Shaped Recipe changes 2022-02-16 14:21:03 +00:00
Auxilor
dfcac5d527 PR Changes 2022-02-14 13:28:37 +00:00
Auxilor
40f88f0b59 Revert "refactor(nms): Change checking if value is initialized to a lazy val"
This reverts commit 6361c0e8e9.
2022-02-14 13:28:25 +00:00
Auxilor
105355d967 Updated to 6.24.3 2022-02-14 13:15:55 +00:00
Will FP
3cddff22b8 Merge pull request #73
Bump com.github.johnrengelman.shadow from 7.1.0 to 7.1.2
2022-02-14 13:15:39 +00:00
Will FP
f8e930d29e Merge pull request #91
Update ShapedRecipeListener.kt
2022-02-14 13:15:28 +00:00
Will FP
9dbe088e66 Merge pull request #92
refactor(nms): Change checking if value is initialized to a lazy val
2022-02-14 13:15:17 +00:00
Racci
6361c0e8e9 refactor(nms): Change checking if value is initialized to a lazy val 2022-02-14 17:32:12 +11:00
casper
1135672241 Update ShapedRecipeListener.kt
| ShapedRecipeListener.kt Modified to change matrix at the end of the crafting to prevent duplication of items
2022-02-13 12:55:05 -05:00
Auxilor
80891e4a81 Fixed profile saveAll not working 2022-02-11 10:14:33 +00:00
Auxilor
3e0be3a629 Updated to 6.24.2 2022-02-09 15:20:30 +00:00
Auxilor
17819de2ea Fixed adult/baby parsers 2022-02-09 15:20:21 +00:00
Auxilor
209cdd6b0d Updated to 6.24.1 2022-02-05 17:05:29 +00:00
Auxilor
fbf6b2edd9 Added equipment arg parser 2022-02-05 17:05:18 +00:00
dependabot[bot]
8b9e8589a0 Bump com.github.johnrengelman.shadow from 7.1.0 to 7.1.2
Bumps com.github.johnrengelman.shadow from 7.1.0 to 7.1.2.

---
updated-dependencies:
- dependency-name: com.github.johnrengelman.shadow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-03 18:54:34 +00:00
Auxilor
525cc019ea Updated kotlin gradle plugin 2022-02-03 18:53:19 +00:00
Auxilor
04f2d15783 Fixed missing compileKotlin options 2022-02-03 18:46:36 +00:00
Auxilor
f988b591a4 Updated kotlin 2022-02-03 18:42:53 +00:00
Auxilor
9ebfb124c8 Refactored build logic 2022-02-03 18:42:01 +00:00
Auxilor
b9ab263f67 Updated CONTRIBUTING.md 2022-02-03 17:54:44 +00:00
Auxilor
bb5f68283b Updated empty (default) EcoPlugin constructor 2022-02-03 17:51:54 +00:00
Auxilor
9bbf1cfe36 Added EcoPlugin#mutateProps 2022-02-03 17:49:26 +00:00
Auxilor
19bb5f608c Updated more javadoc 2022-02-03 17:46:31 +00:00
Auxilor
a1c70d2081 Corrected PluginProps javadoc 2022-02-03 17:43:40 +00:00
Auxilor
979ddf0ff0 Safety checks to FastItemStack 2022-02-03 17:41:45 +00:00
Auxilor
232a63c00d Cleaned up FillerMask 2022-02-03 17:22:46 +00:00
Auxilor
e65cf9be2c Added extra methods to Items 2022-02-03 17:17:01 +00:00
Auxilor
fbf56037d4 Deprecated MaskMaterials in favour of MaskItems 2022-02-03 16:54:52 +00:00
Auxilor
aa0c4ee7fa Refactored props name 2022-02-03 16:08:18 +00:00
Auxilor
5f3375bf87 Added props validation 2022-02-03 15:11:15 +00:00
Auxilor
11dc6d0e67 Allowed custom props parameter 2022-02-03 15:06:35 +00:00
Auxilor
9cccbd10ba Removed need to reflectively instantiate props 2022-02-03 15:02:45 +00:00
Auxilor
1f0ad48480 Updated props javadoc 2022-02-03 14:58:12 +00:00
Auxilor
93322dcfa5 Updated props javadoc 2022-02-03 14:56:29 +00:00
Auxilor
e3b630fcb7 Improved props system 2022-02-03 14:54:43 +00:00
Auxilor
8690b75f4c Added namespacedKeyOf 2022-02-03 14:19:59 +00:00
Auxilor
6de792f308 Added more durability utils 2022-02-03 14:17:41 +00:00
Auxilor
e59037635e Removed debug from eco.yml 2022-02-03 13:52:48 +00:00
Auxilor
b9d50e261d Fixed missing javadoc 2022-02-03 13:44:15 +00:00
Auxilor
15173c8369 Finally added eco.yml 2022-02-03 13:38:14 +00:00
Auxilor
4ee0645a4e Codestyle 2022-02-03 12:57:29 +00:00
Auxilor
96bd53c089 Codestyle 2022-02-03 12:36:49 +00:00
Auxilor
e658bf3fa8 Removed redundant suppression 2022-02-03 12:36:14 +00:00
Auxilor
988836b5b9 Deprecated UnsupportedVersionException in favour of UnsupportedVersionError 2022-02-03 12:32:46 +00:00
Auxilor
5688f41b8b Fixed deprecation 2022-02-03 12:27:47 +00:00
Auxilor
4eaa6ab75c Fixed build issue 2022-02-03 12:25:39 +00:00
Auxilor
b29363cdf6 Fixed javadoc 2022-02-03 12:22:05 +00:00
Auxilor
c8648a92f5 Resolved PlayerUtils ambiguity in kotlin 2022-02-03 12:10:29 +00:00
Auxilor
0a59b6a208 ProxyFactory error changes 2022-02-03 12:06:00 +00:00
Auxilor
4e18a0ab78 Updated proxy errors 2022-02-03 12:05:22 +00:00
Auxilor
d49405f839 Updated create2DList method signature 2022-02-03 11:47:26 +00:00
Auxilor
e10566da66 Deprecated TeamUtils#getMaterialColorTeam 2022-02-03 11:45:56 +00:00
Auxilor
0c64cd98e0 Updated to 6.24.0 2022-02-03 11:43:47 +00:00
Auxilor
231af30c61 Deprecated + Marked requirement system for removal 2022-02-03 11:41:58 +00:00
Auxilor
9b5cc1fd9c Added more kotlin utilities 2022-02-03 11:23:07 +00:00
Auxilor
7628c0bbfd Renamed FastItemStack methods 2022-02-03 11:17:29 +00:00
Auxilor
0beedc6b07 Updated kotlin to use kotlin API 2022-02-03 11:09:36 +00:00
Auxilor
f3c69f1c15 Added NumberUtils extensions 2022-02-03 11:08:20 +00:00
Auxilor
a148f667e5 Added kotlin builder for commands and PlayerUtils#runExempted 2022-02-03 11:07:04 +00:00
Auxilor
b2370b4b6e Player only commands now can have non-player only subcommands 2022-02-03 10:41:24 +00:00
Auxilor
525bd5264a Removed checkstyle suppressions 2022-02-03 10:34:43 +00:00
Auxilor
54c27a0379 More CI changes 2022-02-03 10:30:22 +00:00
Auxilor
989dda0a4f Updated CI workflows 2022-02-03 10:25:38 +00:00
Auxilor
1f2bb3341e Suppression 2022-02-02 16:54:09 +00:00
Auxilor
65221bdddf Deprecated SlotModifier, replaced with SlotUpdater 2022-02-02 16:52:52 +00:00
Auxilor
b386f2df1b Updated CONTRIBUTING.md 2022-02-02 16:38:05 +00:00
Auxilor
969329486d Reverted publication changes 2022-02-02 16:00:01 +00:00
Auxilor
aab2e8237c Gave up trying to have separate java and kotlin modules 2022-02-02 15:57:45 +00:00
Auxilor
30457c29a1 Gave up trying to have separate java and kotlin modules 2022-02-02 15:57:37 +00:00
Auxilor
9ad480ecf0 Shadow publication attempt 1 2022-02-02 15:50:43 +00:00
Auxilor
b0d3256d1b Fixed conflicting jvm names 2022-02-02 14:23:51 +00:00
Auxilor
4ff9d82cc1 Added kotlin builders for GUIs 2022-02-02 13:21:28 +00:00
Auxilor
f9178e248b Updated paperweight userdev 2022-02-02 12:47:56 +00:00
Auxilor
cc8a799438 Added log-full-extension-errors 2022-02-02 12:46:49 +00:00
Auxilor
90b81f56df Codestyle 2022-02-02 12:43:55 +00:00
Auxilor
1240c14c14 Added kotlin extensions 2022-02-02 12:42:38 +00:00
Auxilor
ed46900f2f Re-added NMS Modules after build checks 2022-02-02 12:20:33 +00:00
Auxilor
dade3d7fbb Fixed build.gradle in eco-api 2022-02-02 12:16:39 +00:00
Auxilor
df141875d3 Updated CI workflows 2022-02-02 12:15:34 +00:00
Auxilor
50b07de5d1 Updated CI workflows 2022-02-02 12:13:58 +00:00
Auxilor
e2a033c24f Dev changes 2022-02-02 12:13:36 +00:00
Auxilor
3fa574105f Hopefully resolved circular dependencies 2022-02-02 11:40:39 +00:00
Auxilor
a64386f980 Hopefully resolved circular dependencies 2022-02-02 11:40:03 +00:00
Auxilor
4c5a0f9887 Even more buildscript changes 2022-02-02 11:31:21 +00:00
Auxilor
cbd43f5757 More buildscript changes 2022-02-02 11:24:33 +00:00
Auxilor
01f1425557 buildscript changes 2022-02-02 11:24:12 +00:00
Auxilor
25e8cc0837 Refactored API, added kotlin extensions 2022-02-02 11:22:19 +00:00
Auxilor
7ff3eeef06 Updated to 6.22.3 2022-02-01 19:09:24 +00:00
Auxilor
58faf6de23 Fixed more server profile issues 2022-02-01 19:09:10 +00:00
Auxilor
7f42cbe32e Updated to 6.22.2 2022-02-01 18:55:18 +00:00
Auxilor
ae12ab17fe Fixed server profile 2022-02-01 18:55:07 +00:00
Auxilor
9949ed4f5f Updated to 6.22.1 2022-02-01 18:16:47 +00:00
Auxilor
e3f81a51e8 Revert "Fixed WorldGuard antigrief integration"
This reverts commit feebbd8ec7.
2022-02-01 18:16:27 +00:00
Auxilor
a06d782dea Cleaned up StringUtils 2022-02-01 14:12:03 +00:00
Auxilor
7e60ee63ea Merge branch '0ft3n_master' into develop 2022-02-01 14:04:50 +00:00
Auxilor
e349f47e66 Swapped out guava cache for caffeine 2022-02-01 14:04:00 +00:00
Auxilor
f710a69455 Changed cache expiry times 2022-02-01 13:49:35 +00:00
Auxilor
20b06be1f2 Changed item cache off to guava 2022-02-01 13:24:36 +00:00
Auxilor
9992820580 Items changes 2022-02-01 13:17:52 +00:00
0ft3n
feebbd8ec7 Fixed WorldGuard antigrief integration 2022-02-01 15:26:40 +03:00
Auxilor
5302aa07a5 Un-did thing? 2022-02-01 11:19:23 +00:00
Auxilor
d124c5b274 Fixed build issues 2022-02-01 11:08:08 +00:00
Auxilor
f188919197 Fixed wrong suppression 2022-02-01 11:04:24 +00:00
Auxilor
388268e906 Minor changes 2022-02-01 11:03:02 +00:00
Auxilor
6367867d2b Suppressed warnings 2022-02-01 11:01:36 +00:00
Auxilor
291357e235 Updated to 6.22.0 2022-02-01 10:55:13 +00:00
Auxilor
07178b0645 Added cache to string formats 2022-02-01 10:54:13 +00:00
Auxilor
70ef99e875 Added guava caches to performance-sensitive components 2022-02-01 10:44:19 +00:00
Auxilor
885a7835ea Fixed CrashClaim integration not being registered 2022-02-01 10:09:41 +00:00
Auxilor
94e9b47f02 Renaming 2022-02-01 10:08:21 +00:00
Auxilor
e8f4bdd4aa Added toString methods on profile impl 2022-02-01 10:07:25 +00:00
Auxilor
c01e409904 Added ServerProfile, internal annotations 2022-02-01 10:06:39 +00:00
Auxilor
f1cf82160e Rewrote custom recipe listener in kotlin 2022-02-01 09:46:59 +00:00
0ft3n
d1c15f8699 Merge branch 'Auxilor:master' into master 2022-01-29 20:41:22 +03:00
_OfTeN_
be6e7b1f46 Added RPGHorses Antigrief integration
Fixed CustoMCrafting compatibility

Updated CustomCrafting Items lookup integration

Added a warning for empty recipes
2022-01-29 00:25:13 +03:00
Auxilor
b78fc2fb66 Suppressed warning 2022-01-28 09:30:57 +00:00
Auxilor
23a297b8e3 Updated to 6.21.1 2022-01-28 09:15:39 +00:00
Auxilor
4e99ca51f0 PR Codestyle 2022-01-28 09:15:16 +00:00
NicoNekoDev
47c93a6dbe Fix strange imports 2022-01-28 01:16:28 +02:00
NicoNekoDev
da7f47d1ba Fix getCustomItem lookup system for better performance 2022-01-28 01:14:55 +02:00
_OfTeN_
144ea0dd10 Added silent arg parser for entities 2022-01-27 16:51:39 +03:00
Auxilor
732aaa3bf1 Fixed NamespacedKeyUtils.fromString 2022-01-27 13:23:25 +00:00
Auxilor
a38387be33 Fixed more stupidity 2022-01-27 13:16:42 +00:00
Auxilor
582f9b08f3 Fixed stupidity 2022-01-27 13:15:19 +00:00
Auxilor
638367cbb2 Switched objenesis instantiator 2022-01-27 13:08:59 +00:00
Auxilor
ec35e7d779 Fixed lateinit issues 2022-01-27 13:04:33 +00:00
Auxilor
1cc2a585d6 NamespacedKey changes 2022-01-27 12:51:22 +00:00
Auxilor
aa553b96d6 Updated to 6.21.0 2022-01-27 12:41:53 +00:00
Auxilor
feb7ecee48 Added fast NamespacedKey creation 2022-01-27 12:41:18 +00:00
Auxilor
c0be6a12ff Changed behaviour to not be the same as enum behaviour 2022-01-26 12:42:05 +00:00
Auxilor
1dc6b651a0 Switched PersistentDataKeyType to not be an enum 2022-01-26 12:40:15 +00:00
Auxilor
3c26c02642 Added issue template 2022-01-26 11:19:02 +00:00
Auxilor
343508f099 Updated to 6.20.4 2022-01-20 09:44:08 +00:00
Auxilor
76dc4948bc Fixed playerless placeholders 2022-01-20 09:43:53 +00:00
Auxilor
8fa209a981 Switched from shallow to deep packet cloning for async 2022-01-18 09:19:14 +00:00
Auxilor
b3a0634ad0 Updated to 6.20.3 2022-01-18 09:18:36 +00:00
Auxilor
97d7acc0a9 Tweaked async display 2022-01-18 09:18:25 +00:00
Auxilor
ebac75b0ee Updated to 6.20.2 2022-01-18 08:41:04 +00:00
Auxilor
02d0fa85b5 Updated plugin.yml 2022-01-18 08:40:53 +00:00
Auxilor
168915868c Added support for CustomCrafting and ExecutableItems 2022-01-18 08:40:38 +00:00
Auxilor
d62d598fd6 Merge branch '0ft3n_master' into develop
# Conflicts:
#	eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt
2022-01-18 08:38:53 +00:00
0ft3n
06561c5387 Removed unneeded event call 2022-01-18 02:00:10 +03:00
Auxilor
c9805e91b4 Updated to 6.20.1 2022-01-17 17:09:06 +00:00
Auxilor
e3be95ca4d Added soft faliures to config updating 2022-01-17 17:08:57 +00:00
Auxilor
2e6463aed9 Fixed global placeholders 2022-01-17 11:15:18 +00:00
Auxilor
2501574eeb Updated to 6.20.0 2022-01-17 11:12:58 +00:00
Auxilor
3c237fd856 Codestyle 2022-01-17 11:12:45 +00:00
Auxilor
7b3fd1d0c2 Moved placeholders to be registered per-plugin 2022-01-17 11:11:46 +00:00
Auxilor
e599add6de Removed arg parsers that were marked for removal several versions ago 2022-01-12 16:27:43 +00:00
Auxilor
1bda970f6b Improved Items performance 2022-01-12 16:17:49 +00:00
Auxilor
eb1f694905 Added item-cache-ttl 2022-01-12 16:14:24 +00:00
Auxilor
efd3403eda Updated to 6.19.1 2022-01-12 16:02:14 +00:00
Auxilor
08b563d528 Improved Items#getCustomItem and Items#isCustomItem performance 2022-01-12 15:59:25 +00:00
Auxilor
c3f88bf7b0 Fixed updatechecker formatting 2022-01-12 11:23:01 +00:00
Auxilor
eb6d76e0c6 Updated to 6.19.0 2022-01-12 11:17:32 +00:00
Auxilor
f2d0e8c368 Merge branch 'master' into develop 2022-01-12 11:17:23 +00:00
Auxilor
5e7b9573a1 Switched try/catch blocks to runCatching in kotlin and improved async packet encoding 2022-01-12 11:17:03 +00:00
Auxilor
7d457ea496 Added more safety checks to compiled expressions 2022-01-12 08:31:45 +00:00
Auxilor
806bf9a43f Added getDouble/IntFromExpression to Config 2022-01-11 17:05:22 +00:00
Auxilor
316f134b71 NumberUtils changes 2022-01-11 16:54:32 +00:00
Auxilor
0d363b9fb6 Added error safety to CrunchHandler 2022-01-11 16:51:38 +00:00
Auxilor
2890083eaa Excluded lang3 2022-01-11 16:47:57 +00:00
Auxilor
694646431b Fixed commons lang issue 2022-01-11 16:45:30 +00:00
Auxilor
86d5e9d09e Added support for evaluating mathematical expressions via Crunch 2022-01-11 16:43:36 +00:00
often
c0547a7c34 Readded and fixed CustomItems support, added ExecutableItems support 2022-01-02 13:19:35 +03:00
168 changed files with 3708 additions and 1646 deletions

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Auxilor Community Discord
url: https://discord.gg/ZcwpSsE/
about: Join the Auxilor discord to get help from support staff and the general community!
- name: The most common issues people have
url: https://github.com/Auxilor/eco/issues/78
about: Check the list of known common issues to see if your issue has already been solved

31
.github/ISSUE_TEMPLATE/report-a-bug.md vendored Normal file
View File

@@ -0,0 +1,31 @@
---
name: Report a Bug
about: Report an issue with the plugin
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Server Information (please complete the following information):**
- Version: (output of `/ver` command)
- Version of plugin and eco (`/ver eco`, `/ver <plugin>`)
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Request a Feature
about: Suggest an idea for this plugin
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

15
.github/workflows/checkstyle.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
name: Check PR Codestyle
on: [ pull_request ]
jobs:
checkstyle:
name: Checkstyle
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: dbelyaev/action-checkstyle@v0.5.1
with:
github_token: ${{ secrets.github_token }}
reporter: github-pr-review
level: warning
checkstyle_config: ../../config/checkstyle/checkstyle.xml

View File

@@ -1,6 +1,6 @@
name: Java CI
on: [push]
on: [ push, pull_request ]
jobs:
build:

42
.github/workflows/test-publish.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Publish API (Dev)
on: [ push, pull_request ]
jobs:
publish-release:
runs-on: ubuntu-latest
steps:
- name: Checkout latest code
uses: actions/checkout@v2
- name: Set outputs
id: vars
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: 17
- name: Setup build cache
uses: actions/cache@v2.1.6
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Publish artifact
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# The GITHUB_REF tag comes in the format 'refs/tags/xxx'.
# So if we split on '/' and take the 3rd value, we can get the release name.
run: |
NEW_VERSION=$(echo "${GITHUB_REF}" | cut -d "/" -f3)
echo "New version: ${{ steps.vars.outputs.sha_short }}"
echo "Github username: ${GITHUB_ACTOR}"
./gradlew -Pversion=dev-${{ steps.vars.outputs.sha_short }} publish

View File

@@ -1,24 +1,38 @@
# How to contribute to eco
## Codestyle
1. The eco checkstyle is in /config/checkstyle.xml
- The pull request must not have any checkstyle issues.
- Every method and field must have a javadoc attached.
2. Use JetBrains annotations
- Every parameter should be annotated with @NotNull or @Nullable
- Use @NotNull over lombok @NonNull
3. Imports
- No group (*) imports.
- No static imports.
4. Kotlin
- Kotlin should be the only language used in the backend, java should be the only language used in the frontend.
- Kotlin API extensions should only be for creating extension functions and extra niceties that aren't possible in java.
Do not write API components in kotlin.
- Kotlin code should never be called directly from the frontend Java API. Kotlin API extensions should always rely on
java, not the other way round.
## Dependency Injection
- eco uses Dependency Injection
- Any calls to Eco#getHandler#getEcoPlugin are code smells and should never be used unless **absolutely necessary**.
- NamespacedKeys, FixedMetadataValues, Runnables, and Schedules should be managed using AbstractEcoPlugin through DI.
- Any DI class should extend PluginDependent where possible. If the class extends another, then you **must** store the plugin instance in a private final variable called **plugin** with a private or protected getter.
- Any DI class should extend PluginDependent where possible. If the class extends another, then you **must** store the
plugin instance in a private final variable called **plugin** with a private or protected getter.
## Other
- All drops **must** be sent through a DropQueue - calls to World#dropItem will get your PR rejected.
- eco is built with java 17.

View File

@@ -29,7 +29,7 @@ and many more.
# For server owners
- Requires ProtocolLib to be installed: get the latest version [here](https://www.spigotmc.org/resources/protocollib.1997/)
- Supports 1.16.5+
- Supports 1.17+
## Downloads

View File

@@ -1,8 +1,19 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
}
}
plugins {
id("java-library")
id("com.github.johnrengelman.shadow") version "7.1.0"
id("com.github.johnrengelman.shadow") version "7.1.2"
id("maven-publish")
id("java")
kotlin("jvm") version "1.6.10"
}
dependencies {
@@ -10,7 +21,6 @@ dependencies {
implementation(project(":eco-core:core-plugin"))
implementation(project(":eco-core:core-proxy"))
implementation(project(":eco-core:core-backend"))
implementation(project(":eco-core:core-nms:v1_16_R3"))
implementation(project(path = ":eco-core:core-nms:v1_17_R1", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_18_R1", configuration = "reobf"))
}
@@ -20,6 +30,7 @@ allprojects {
apply(plugin = "java-library")
apply(plugin = "maven-publish")
apply(plugin = "com.github.johnrengelman.shadow")
apply(plugin = "kotlin")
repositories {
mavenCentral()
@@ -64,19 +75,30 @@ allprojects {
// MythicMobs
maven("https://mvn.lumine.io/repository/maven-public/")
// Crunch
maven("https://redempt.dev")
// LibsDisguises
maven("https://repo.md-5.net/content/groups/public/")
}
dependencies {
compileOnly(kotlin("stdlib", version = "1.6.10"))
compileOnly("org.jetbrains:annotations:23.0.0")
// Test
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
// Adventure
compileOnly("net.kyori:adventure-api:4.9.3")
compileOnly("net.kyori:adventure-text-serializer-gson:4.9.3")
compileOnly("net.kyori:adventure-text-serializer-legacy:4.9.3")
// Other
compileOnly("com.google.guava:guava:31.0.1-jre")
compileOnly("com.github.ben-manes.caffeine:caffeine:3.0.5")
}
tasks.withType<JavaCompile> {
@@ -94,6 +116,14 @@ allprojects {
}
tasks {
compileKotlin {
kotlinOptions {
jvmTarget = "17"
}
targetCompatibility = "17"
sourceCompatibility = "17"
}
shadowJar {
relocate("org.bstats", "com.willfp.eco.shaded.bstats")
relocate("net.kyori.adventure.text.minimessage", "com.willfp.eco.shaded.minimessage")

View File

@@ -32,10 +32,6 @@
-->
<module name="Checker">
<module name="SuppressionFilter">
<property name="file" value="config/checkstyle/suppression.xml"/>
</module>
<!--
If you set the basedir property below, then all reported file
names will be relative to the specified directory. See

View File

@@ -1,24 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
<!-- Internals don't need javadoc. -->
<suppress files="[\\/]internal[\\/]" checks="MissingJavadocMethod"/>
<suppress files="[\\/]internal[\\/]" checks="JavadocVariable"/>
<suppress files="[\\/]eco[\\/]spigot[\\/]" checks="MissingJavadocMethod"/>
<suppress files="[\\/]eco[\\/]spigot[\\/]" checks="JavadocVariable"/>
<suppress files="[\\/]eco[\\/]proxy[\\/]" checks="MissingJavadocMethod"/>
<suppress files="[\\/]eco[\\/]proxy[\\/]" checks="JavadocVariable"/>
<!-- Modified version of library -->
<suppress files="ArmorEquipEvent.java" checks="JavadocVariable"/>
<suppress files="ArmorEquipEvent.java" checks="MissingJavadocMethod"/>
<suppress files="ArmorEquipEvent.java" checks="JavadocStyle"/>
<suppress files="ArmorListener.java" checks="JavadocVariable"/>
<suppress files="ArmorListener.java" checks="MissingJavadocMethod"/>
<suppress files="ArmorType.java" checks="JavadocVariable"/>
<suppress files="ArmorType.java" checks="MissingJavadocMethod"/>
</suppressions>

View File

@@ -1,10 +1,3 @@
plugins {
id 'com.github.johnrengelman.shadow'
}
group 'com.willfp'
version rootProject.version
dependencies {
// Adventure
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0'
@@ -15,13 +8,10 @@ dependencies {
compileOnly 'org.apache.maven:maven-artifact:3.8.1'
compileOnly 'com.comphenix.protocol:ProtocolLib:4.6.1-SNAPSHOT'
compileOnly 'com.google.code.gson:gson:2.8.8'
compileOnly 'org.apache.commons:commons-lang3:3.0'
}
java {
withJavadocJar()
}
group 'com.willfp'
version rootProject.version
build.dependsOn publishToMavenLocal

View File

@@ -4,6 +4,12 @@ import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Holds the instance of the eco handler for bridging between the frontend
* and backend.
@@ -52,6 +58,24 @@ public final class Eco {
return handler;
}
/**
* Eco Handler components are internals, so if a class is marked as a handler component,
* then it should be treated the same as if it was marked with {@link ApiStatus.Internal}.
* <p>
* If a class is marked with {@link HandlerComponent}, <strong>Do not reference it in
* your code!</strong> It can and will contain breaking changes between minor versions and
* even patches, and you will create compatibility issues by using them.
* <p>
* Handler components should also be marked with {@link ApiStatus.Internal} in order to
* cause compiler / IDE warnings.
*/
@Documented
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE})
public @interface HandlerComponent {
}
private Eco() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -152,10 +152,14 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
private final ProxyFactory proxyFactory;
/**
* Create a new plugin without a specified color, proxy support, polymart, or bStats.
* Create a new plugin.
* <p>
* Will read from eco.yml (like plugin.yml) to fetch values that would otherwise be passed
* into the constructor. If no eco.yml is present, the plugin will load without extension
* support, without proxy support, with no update-checker or bStats, and with the color white.
*/
protected EcoPlugin() {
this("&f");
this((PluginProps) null);
}
/**
@@ -236,6 +240,23 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
@NotNull final String proxyPackage,
@NotNull final String color,
final boolean supportingExtensions) {
this(
PluginProps.createSimple(
resourceId,
bStatsId,
proxyPackage,
color,
supportingExtensions
)
);
}
/**
* Create a new plugin.
*
* @param pluginProps The props. If left null, it will read from eco.yml.
*/
protected EcoPlugin(@Nullable final PluginProps pluginProps) {
/*
The handler must be initialized before any plugin's constructors
are called, as the constructors call Eco#getHandler().
@@ -253,15 +274,15 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
a standalone handler class, but then there would be an interface
left in the API that doesn't really help anything.
The other alternative would be do use reflection to get a 'createHandler'
method that only exists in EcoSpigotPlugin - but that feels really dirty
The other alternative would be to use reflection to get a 'createHandler'
method that only exists in EcoSpigotPlugin - but that feels filthy,
and I'd rather only use reflection where necessary.
*/
if (Eco.getHandler() == null && this instanceof Handler) {
/*
This code is only ever called by EcoSpigotPlugin (EcoHandler)
as it's the first plugin to load and it is a handler.
as it's the first plugin to load, and it is a handler.
Any other plugins will never call this code as the handler
will have already been initialized.
@@ -272,11 +293,16 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
assert Eco.getHandler() != null;
this.resourceId = resourceId;
this.bStatsId = bStatsId;
this.proxyPackage = proxyPackage;
this.color = color;
this.supportingExtensions = supportingExtensions;
PluginProps generatedProps = Eco.getHandler().getProps(pluginProps, this.getClass());
generatedProps.validate();
PluginProps props = this.mutateProps(generatedProps);
props.validate();
this.resourceId = props.getResourceId();
this.bStatsId = props.getBStatsId();
this.proxyPackage = props.getProxyPackage();
this.color = props.getColor();
this.supportingExtensions = props.isSupportingExtensions();
this.scheduler = Eco.getHandler().createScheduler(this);
this.eventManager = Eco.getHandler().createEventManager(this);
@@ -296,8 +322,8 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
/*
The minimum eco version check was moved here because it's very common
to add a lot of code in the constructor of plugins; meaning that the plugin
can throw errors without it being obvious to the user that the reason is
because they have an outdated version of eco installed.
can throw errors without it being obvious to the user that the reason is that
they have an outdated version of eco installed.
*/
DefaultArtifactVersion runningVersion = new DefaultArtifactVersion(Eco.getHandler().getEcoPlugin().getDescription().getVersion());
@@ -327,7 +353,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
DefaultArtifactVersion mostRecentVersion = new DefaultArtifactVersion(version);
if (!(currentVersion.compareTo(mostRecentVersion) > 0 || currentVersion.equals(mostRecentVersion))) {
this.outdated = true;
this.getLogger().warning("&c " + this.getName() + " is out of date! (Version " + this.getDescription().getVersion() + ")");
this.getLogger().warning("&c" + this.getName() + " is out of date! (Version " + this.getDescription().getVersion() + ")");
this.getLogger().warning("&cThe newest version is &f" + version);
this.getLogger().warning("&cDownload the new version!");
}
@@ -534,6 +560,21 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
}
/**
* Mutate the plugin props.
* <p>
* Useful for eco-based plugin libraries to enforce certain properties, such as
* forcing extensions to be enabled.
* <p>
* Props are validated both before and after calling this method.
*
* @param props The props.
* @return The mutated props.
*/
protected PluginProps mutateProps(@NotNull final PluginProps props) {
return props;
}
/**
* The plugin-specific integrations to be tested and loaded.
*
@@ -635,7 +676,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
* @return The proxy.
*/
public final <T> T getProxy(@NotNull final Class<T> proxyClass) {
Validate.notNull(proxyFactory, "Plugin does not support proxy!");
Validate.notNull(proxyFactory, "Plugin does not support proxies!");
return proxyFactory.getProxy(proxyClass);
}

View File

@@ -2,7 +2,7 @@ package com.willfp.eco.core;
import com.willfp.eco.core.config.updating.ConfigHandler;
import com.willfp.eco.core.config.wrapper.ConfigFactory;
import com.willfp.eco.core.data.PlayerProfileHandler;
import com.willfp.eco.core.data.ProfileHandler;
import com.willfp.eco.core.data.keys.KeyRegistry;
import com.willfp.eco.core.drops.DropQueueFactory;
import com.willfp.eco.core.events.EventManager;
@@ -15,10 +15,10 @@ import com.willfp.eco.core.gui.GUIFactory;
import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration;
import com.willfp.eco.core.proxy.Cleaner;
import com.willfp.eco.core.proxy.ProxyFactory;
import com.willfp.eco.core.requirement.RequirementFactory;
import com.willfp.eco.core.scheduling.Scheduler;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
@@ -32,6 +32,7 @@ import java.util.logging.Logger;
* @see Eco#getHandler()
*/
@ApiStatus.Internal
@SuppressWarnings("removal")
public interface Handler {
/**
* Create a scheduler.
@@ -209,7 +210,8 @@ public interface Handler {
* @return The factory.
*/
@NotNull
RequirementFactory getRequirementFactory();
@Deprecated(forRemoval = true)
com.willfp.eco.core.requirement.RequirementFactory getRequirementFactory();
/**
* Get Adventure audiences.
@@ -233,7 +235,7 @@ public interface Handler {
* @return The handler.
*/
@NotNull
PlayerProfileHandler getPlayerProfileHandler();
ProfileHandler getProfileHandler();
/**
* Create dummy entity - never spawned, exists purely in code.
@@ -243,4 +245,30 @@ public interface Handler {
*/
@NotNull
Entity createDummyEntity(@NotNull Location location);
/**
* Create a {@link NamespacedKey} quickly
* <p>
* Bypasses the constructor, allowing for the creation of invalid keys,
* therefore this is considered unsafe and should only be called after
* the key has been confirmed to be valid.
*
* @param namespace The namespace.
* @param key The key.
* @return The key.
*/
@NotNull
NamespacedKey createNamespacedKey(@NotNull String namespace,
@NotNull String key);
/**
* Return or get props for a plugin.
*
* @param existing The existing constructor props.
* @param plugin The plugin.
* @return The props.
*/
@NotNull
PluginProps getProps(@Nullable PluginProps existing,
@NotNull Class<? extends EcoPlugin> plugin);
}

View File

@@ -0,0 +1,275 @@
package com.willfp.eco.core;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
/**
* Plugin props are the arguments related to the plugin that are required on start-up.
* <p>
* This class is complex in how it works intentionally. This is done so that fields can be
* added to the props without breaking API backwards compatibility. Thus, there is no public
* constructor and no way to instantiate props without creating a parser.
*/
public final class PluginProps {
/**
* All registered parsers.
*/
private static final Map<Class<?>, PropsParser<?>> REGISTERED_PARSERS = new HashMap<>();
/**
* The polymart resource ID.
*/
@Nullable
private Integer resourceId;
/**
* The bStats ID.
*/
@Nullable
private Integer bStatsId;
/**
* The proxy package.
*/
@Nullable
private String proxyPackage;
/**
* The color.
*/
@Nullable
private String color;
/**
* If extensions are supported.
*/
@Nullable
private Boolean supportingExtensions;
/**
* Create new blank props.
*/
private PluginProps() {
}
/**
* Get resource ID.
*
* @return The resource ID.
*/
public int getResourceId() {
assert resourceId != null;
return resourceId;
}
/**
* Set resource ID.
*
* @param resourceId The resource ID.
*/
public void setResourceId(final int resourceId) {
this.resourceId = resourceId;
}
/**
* Get bStats ID.
*
* @return The bStats ID.
*/
public int getBStatsId() {
assert bStatsId != null;
return bStatsId;
}
/**
* Set bStats ID.
*
* @param bStatsId The bStats ID.
*/
public void setBStatsId(final int bStatsId) {
this.bStatsId = bStatsId;
}
/**
* Get the proxy package.
*
* @return The package.
*/
@NotNull
public String getProxyPackage() {
assert proxyPackage != null;
return proxyPackage;
}
/**
* Set the proxy package.
*
* @param proxyPackage The proxy package.
*/
public void setProxyPackage(@NotNull final String proxyPackage) {
this.proxyPackage = proxyPackage;
}
/**
* Get color.
*
* @return The color.
*/
@NotNull
public String getColor() {
assert color != null;
return color;
}
/**
* Set the color.
*
* @param color The color.
*/
public void setColor(@NotNull final String color) {
this.color = color;
}
/**
* Get if extensions are supported.
*
* @return If supported.
*/
public boolean isSupportingExtensions() {
assert supportingExtensions != null;
return supportingExtensions;
}
/**
* Set if extensions are supported.
*
* @param supportingExtensions If supported.
*/
public void setSupportingExtensions(final boolean supportingExtensions) {
this.supportingExtensions = supportingExtensions;
}
/**
* Ensure that all required props have been set.
*/
public void validate() {
if (
supportingExtensions == null
|| proxyPackage == null
|| color == null
|| bStatsId == null
|| resourceId == null
) {
throw new IllegalStateException("Missing required props!");
}
}
/**
* Parse props from source.
*
* @param source The source.
* @param sourceClass The source class.
* @param <T> The source type.
* @return The props.
*/
public static <T> PluginProps parse(@NotNull final T source,
@NotNull final Class<? extends T> sourceClass) {
for (Map.Entry<Class<?>, PropsParser<?>> entry : REGISTERED_PARSERS.entrySet()) {
Class<?> clazz = entry.getKey();
if (clazz.equals(sourceClass)) {
@SuppressWarnings("unchecked")
PropsParser<T> parser = (PropsParser<T>) entry.getValue();
return parser.parseFrom(source);
}
}
throw new IllegalArgumentException("No parser exists for class " + sourceClass);
}
/**
* Register a parser for a type.
*
* @param clazz The class.
* @param parser The parser.
* @param <T> The source type.
*/
public static <T> void registerParser(@NotNull final Class<T> clazz,
@NotNull final PropsParser<T> parser) {
REGISTERED_PARSERS.put(clazz, parser);
}
/**
* Get if there is a registered parser for a class.
*
* @param clazz The class.
* @return If there is a parser registered.
*/
public static boolean hasParserFor(@NotNull final Class<?> clazz) {
for (Class<?> test : REGISTERED_PARSERS.keySet()) {
if (test.equals(clazz)) {
return true;
}
}
return false;
}
/**
* Create new props from known values.
*
* Marked as internal as this method will break whenever the properties themselves
* are updated (e.g. if a new property is added) - so to prevent any potential
* backwards-compatibility bugs, this method cannot be invoked outside eco itself.
*
* @param resourceId The ID of the plugin on polymart.
* @param bStatsId The ID of the plugin on bStats.
* @param proxyPackage The package where proxies can be found.
* @param color The primary color of the plugin.
* @param supportsExtensions If the plugin should attempt to look for extensions.
* @return The props.
*/
@ApiStatus.Internal
static PluginProps createSimple(final int resourceId,
final int bStatsId,
@NotNull final String proxyPackage,
@NotNull final String color,
final boolean supportsExtensions) {
PluginProps props = new PluginProps();
props.setResourceId(resourceId);
props.setBStatsId(bStatsId);
props.setProxyPackage(proxyPackage);
props.setColor(color);
props.setSupportingExtensions(supportsExtensions);
return props;
}
/**
* Parse arguments into props for a plugin.
*
* @param <T> The type of source.
*/
public interface PropsParser<T> {
/**
* Parse props from a given source.
*
* @param source The source.
* @return The props.
*/
PluginProps parseFrom(@NotNull T source);
/**
* Get a new, blank props instance.
*
* @return Blank props.
*/
default PluginProps getBlankProps() {
return new PluginProps();
}
}
}

View File

@@ -51,7 +51,10 @@ public class Prerequisite {
/**
* Requires the server to be running 1.17.
*
* @deprecated eco no longer supports versions before 1.17.
*/
@Deprecated(since = "6.25.2")
public static final Prerequisite HAS_1_17 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("17") || HAS_1_18.isMet(),
"Requires server to be running 1.17+"

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.command;
import com.willfp.eco.core.EcoPlugin;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
@@ -66,6 +67,13 @@ public interface CommandBase {
return new ArrayList<>();
}
/**
* Get the plugin.
*
* @return The plugin.
*/
EcoPlugin getPlugin();
/**
* Get the handler.
*

View File

@@ -1,7 +1,6 @@
package com.willfp.eco.core.command.impl;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.command.CommandBase;
import com.willfp.eco.core.command.CommandHandler;
import com.willfp.eco.core.command.TabCompleteHandler;
@@ -25,7 +24,12 @@ import java.util.stream.Collectors;
* layer, hence why it's a package-private class.
*/
@SuppressWarnings({"DeprecatedIsStillUsed"})
abstract class HandledCommand extends PluginDependent<EcoPlugin> implements CommandBase {
abstract class HandledCommand implements CommandBase {
/**
* The plugin.
*/
private final EcoPlugin plugin;
/**
* The name of the command.
*/
@@ -78,7 +82,7 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
@NotNull final String name,
@NotNull final String permission,
final boolean playersOnly) {
super(plugin);
this.plugin = plugin;
this.name = name;
this.permission = permission;
this.playersOnly = playersOnly;
@@ -98,6 +102,16 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
return this;
}
/**
* Get the plugin.
*
* @return The plugin.
*/
@Override
public EcoPlugin getPlugin() {
return this.plugin;
}
/**
* Handle the command.
*
@@ -124,6 +138,11 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
}
}
if (this.isPlayersOnly() && !(sender instanceof Player)) {
sender.sendMessage(this.getPlugin().getLangYml().getMessage("not-player"));
return;
}
if (this.getHandler() != null) {
this.getHandler().onExecute(sender, Arrays.asList(args));
} else {
@@ -193,11 +212,6 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
public static boolean canExecute(@NotNull final CommandSender sender,
@NotNull final CommandBase command,
@NotNull final EcoPlugin plugin) {
if (command.isPlayersOnly() && !(sender instanceof Player)) {
sender.sendMessage(plugin.getLangYml().getMessage("not-player"));
return false;
}
if (!sender.hasPermission(command.getPermission()) && sender instanceof Player) {
sender.sendMessage(plugin.getLangYml().getNoPermission());
return false;

View File

@@ -5,7 +5,10 @@ import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.config.wrapper.ConfigWrapper;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
/**
@@ -21,6 +24,15 @@ public class TransientConfig extends ConfigWrapper<Config> {
super(Eco.getHandler().getConfigFactory().createConfig(config));
}
/**
* @param stream The InputStream.
*/
public TransientConfig(@Nullable final InputStream stream) {
super(stream != null ? Eco.getHandler().getConfigFactory().createConfig(YamlConfiguration.loadConfiguration(
new InputStreamReader(stream)
)) : new TransientConfig());
}
/**
* Create a new empty transient config.
*

View File

@@ -2,7 +2,9 @@ package com.willfp.eco.core.config.interfaces;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.TransientConfig;
import com.willfp.eco.util.NumberUtils;
import com.willfp.eco.util.StringUtils;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -108,6 +110,29 @@ public interface Config extends Cloneable {
return Objects.requireNonNullElse(getIntOrNull(path), def);
}
/**
* Get a decimal value via a mathematical expression.
*
* @param path The key to fetch the value from.
* @return The computed value, or 0 if not found or invalid.
*/
default int getIntFromExpression(@NotNull String path) {
return getIntFromExpression(path, null);
}
/**
* Get a decimal value via a mathematical expression.
*
* @param path The key to fetch the value from.
* @param player The player to evaluate placeholders with respect to.
* @return The computed value, or 0 if not found or invalid.
*/
default int getIntFromExpression(@NotNull String path,
@Nullable Player player) {
return Double.valueOf(getDoubleFromExpression(path, player)).intValue();
}
/**
* Get an integer from config.
*
@@ -210,7 +235,7 @@ public interface Config extends Cloneable {
*/
@NotNull
default String getString(@NotNull String path) {
return getString(path, false);
return getString(path, false, StringUtils.FormatOption.WITHOUT_PLACEHOLDERS);
}
/**
@@ -519,6 +544,28 @@ public interface Config extends Cloneable {
return Objects.requireNonNullElse(getDoubleOrNull(path), 0.0);
}
/**
* Get a decimal value via a mathematical expression.
*
* @param path The key to fetch the value from.
* @return The computed value, or 0 if not found or invalid.
*/
default double getDoubleFromExpression(@NotNull String path) {
return getDoubleFromExpression(path, null);
}
/**
* Get a decimal value via a mathematical expression.
*
* @param path The key to fetch the value from.
* @param player The player to evaluate placeholders with respect to.
* @return The computed value, or 0 if not found or invalid.
*/
default double getDoubleFromExpression(@NotNull String path,
@Nullable Player player) {
return NumberUtils.evaluateExpression(this.getString(path), player);
}
/**
* Get a decimal from config.
*

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.config.wrapper;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.Config;
@@ -14,6 +15,7 @@ import java.util.Map;
* Internal component to create backend config implementations.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface ConfigFactory {
/**
* Updatable config.

View File

@@ -1,7 +1,6 @@
package com.willfp.eco.core.data;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
@@ -12,26 +11,7 @@ import java.util.UUID;
* <p>
* Profiles save automatically, so there is no need to save after changes.
*/
public interface PlayerProfile {
/**
* Write a key to a player's persistent data.
*
* @param key The key.
* @param value The value.
* @param <T> The type of the key.
*/
<T> void write(@NotNull PersistentDataKey<T> key,
@NotNull T value);
/**
* Read a key from a player's persistent data.
*
* @param key The key.
* @param <T> The type of the key.
* @return The value, or the default value if not found.
*/
<T> @NotNull T read(@NotNull PersistentDataKey<T> key);
public interface PlayerProfile extends Profile {
/**
* Load a player profile.
*
@@ -51,6 +31,6 @@ public interface PlayerProfile {
*/
@NotNull
static PlayerProfile load(@NotNull final UUID uuid) {
return Eco.getHandler().getPlayerProfileHandler().load(uuid);
return Eco.getHandler().getProfileHandler().load(uuid);
}
}

View File

@@ -0,0 +1,30 @@
package com.willfp.eco.core.data;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.jetbrains.annotations.NotNull;
/**
* Persistent data storage interface.
* <p>
* Profiles save automatically, so there is no need to save after changes.
*/
public interface Profile {
/**
* Write a key to persistent data.
*
* @param key The key.
* @param value The value.
* @param <T> The type of the key.
*/
<T> void write(@NotNull PersistentDataKey<T> key,
@NotNull T value);
/**
* Read a key from persistent data.
*
* @param key The key.
* @param <T> The type of the key.
* @return The value, or the default value if not found.
*/
<T> @NotNull T read(@NotNull PersistentDataKey<T> key);
}

View File

@@ -1,15 +1,19 @@
package com.willfp.eco.core.data;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
import java.util.UUID;
/**
* API to handle player profiles.
* API to handle profiles.
*/
public interface PlayerProfileHandler {
@ApiStatus.Internal
@Eco.HandlerComponent
public interface ProfileHandler {
/**
* Load a player profile.
*
@@ -18,6 +22,13 @@ public interface PlayerProfileHandler {
*/
PlayerProfile load(@NotNull UUID uuid);
/**
* Load the server profile.
*
* @return The profile.
*/
ServerProfile loadServerProfile();
/**
* Unload a player profile from memory.
* <p>
@@ -37,7 +48,7 @@ public interface PlayerProfileHandler {
*/
@Deprecated
default void savePlayer(@NotNull UUID uuid) {
this.saveKeysForPlayer(uuid, PersistentDataKey.values());
this.saveKeysFor(uuid, PersistentDataKey.values());
}
/**
@@ -48,8 +59,8 @@ public interface PlayerProfileHandler {
* @param uuid The uuid.
* @param keys The keys.
*/
void saveKeysForPlayer(@NotNull UUID uuid,
@NotNull Set<PersistentDataKey<?>> keys);
void saveKeysFor(@NotNull UUID uuid,
@NotNull Set<PersistentDataKey<?>> keys);
/**
* Save all player data.

View File

@@ -0,0 +1,21 @@
package com.willfp.eco.core.data;
import com.willfp.eco.core.Eco;
import org.jetbrains.annotations.NotNull;
/**
* Persistent data storage interface for servers.
* <p>
* Profiles save automatically, so there is no need to save after changes.
*/
public interface ServerProfile extends Profile {
/**
* Load the server profile.
*
* @return The profile.
*/
@NotNull
static ServerProfile load() {
return Eco.getHandler().getProfileHandler().loadServerProfile();
}
}

View File

@@ -1,12 +1,18 @@
package com.willfp.eco.core.data.keys;
import com.willfp.eco.core.Eco;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
/**
* API to register persistent data keys.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface KeyRegistry {
/**
* Register a persistent data key to be stored.
@@ -21,4 +27,37 @@ public interface KeyRegistry {
* @return The keys.
*/
Set<PersistentDataKey<?>> getRegisteredKeys();
/**
* Mark key as category.
*
* @param key The key.
* @param category The category.
*/
void markKeyAs(@NotNull PersistentDataKey<?> key,
@NotNull KeyRegistry.KeyCategory category);
/**
* Get persistent data key from namespaced key.
*
* @param namespacedKey The key.
* @return The key, or null if not found.
*/
@Nullable
PersistentDataKey<?> getKeyFrom(@NotNull NamespacedKey namespacedKey);
/**
* Locations for key categorization.
*/
enum KeyCategory {
/**
* Player keys.
*/
PLAYER,
/**
* Server keys.
*/
SERVER
}
}

View File

@@ -3,7 +3,9 @@ package com.willfp.eco.core.data.keys;
import com.willfp.eco.core.Eco;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.Set;
/**
@@ -11,7 +13,7 @@ import java.util.Set;
*
* @param <T> The type of the data.
*/
public class PersistentDataKey<T> {
public final class PersistentDataKey<T> {
/**
* The key of the persistent data value.
*/
@@ -25,7 +27,7 @@ public class PersistentDataKey<T> {
/**
* The persistent data key type.
*/
private final PersistentDataKeyType type;
private final PersistentDataKeyType<T> type;
/**
* Create a new Persistent Data Key.
@@ -35,7 +37,7 @@ public class PersistentDataKey<T> {
* @param defaultValue The default value.
*/
public PersistentDataKey(@NotNull final NamespacedKey key,
@NotNull final PersistentDataKeyType type,
@NotNull final PersistentDataKeyType<T> type,
@NotNull final T defaultValue) {
this.key = key;
this.defaultValue = defaultValue;
@@ -53,15 +55,6 @@ public class PersistentDataKey<T> {
+ '}';
}
/**
* Get all persistent data keys.
*
* @return The keys.
*/
public static Set<PersistentDataKey<?>> values() {
return Eco.getHandler().getKeyRegistry().getRegisteredKeys();
}
/**
* Get the key.
*
@@ -85,7 +78,58 @@ public class PersistentDataKey<T> {
*
* @return The key type.
*/
public PersistentDataKeyType getType() {
public PersistentDataKeyType<T> getType() {
return this.type;
}
/**
* Categorize key as a server key, will register new column to MySQL
* database immediately rather than waiting for auto-categorization.
* <p>
* This will improve performance.
*
* @return The key.
*/
public PersistentDataKey<T> server() {
Eco.getHandler().getKeyRegistry().markKeyAs(this, KeyRegistry.KeyCategory.SERVER);
return this;
}
/**
* Categorize key as a player key, will register new column to MySQL
* database immediately rather than waiting for auto-categorization.
* <p>
* This will improve performance.
*
* @return The key.
*/
public PersistentDataKey<T> player() {
Eco.getHandler().getKeyRegistry().markKeyAs(this, KeyRegistry.KeyCategory.PLAYER);
return this;
}
/**
* Get all persistent data keys.
*
* @return The keys.
*/
public static Set<PersistentDataKey<?>> values() {
return Eco.getHandler().getKeyRegistry().getRegisteredKeys();
}
@Override
public boolean equals(@Nullable final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof PersistentDataKey that)) {
return false;
}
return Objects.equals(this.getKey(), that.getKey());
}
@Override
public int hashCode() {
return Objects.hash(this.getKey());
}
}

View File

@@ -1,26 +1,108 @@
package com.willfp.eco.core.data.keys;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* All storable data key types.
*
* @param <T> The type.
*/
public enum PersistentDataKeyType {
public final class PersistentDataKeyType<T> {
/**
* The registered key types.
*/
private static final List<PersistentDataKeyType<?>> VALUES = new ArrayList<>();
/**
* String.
*/
STRING,
public static final PersistentDataKeyType<String> STRING = new PersistentDataKeyType<>(String.class, "STRING");
/**
* Boolean.
*/
BOOLEAN,
public static final PersistentDataKeyType<Boolean> BOOLEAN = new PersistentDataKeyType<>(Boolean.class, "BOOLEAN");
/**
* Integer.
* Int.
*/
INT,
public static final PersistentDataKeyType<Integer> INT = new PersistentDataKeyType<>(Integer.class, "INT");
/**
* Double.
*/
DOUBLE
public static final PersistentDataKeyType<Double> DOUBLE = new PersistentDataKeyType<>(Double.class, "DOUBLE");
/**
* The class of the type.
*/
private final Class<T> typeClass;
/**
* The name of the key type.
*/
private final String name;
/**
* Get the class of the type.
*
* @return The class.
*/
public Class<T> getTypeClass() {
return typeClass;
}
/**
* Get the name of the key type.
*
* @return The name.
*/
public String name() {
return name;
}
/**
* Create new PersistentDataKeyType.
*
* @param typeClass The type class.
* @param name The name.
*/
private PersistentDataKeyType(@NotNull final Class<T> typeClass,
@NotNull final String name) {
VALUES.add(this);
this.typeClass = typeClass;
this.name = name;
}
/**
* Get all registered {@link PersistentDataKeyType}s.
*
* @return The registered types.
*/
@NotNull
public static PersistentDataKeyType<?>[] values() {
return VALUES.toArray(new PersistentDataKeyType[0]);
}
/**
* Get a key type from a name.
*
* @param name The name.
* @return The type, or null if not found.
*/
@Nullable
public static PersistentDataKeyType<?> valueOf(@NotNull final String name) {
for (PersistentDataKeyType<?> type : VALUES) {
if (type.name.equalsIgnoreCase(name)) {
return type;
}
}
return null;
}
}

View File

@@ -1,13 +1,17 @@
package com.willfp.eco.core.display;
import com.willfp.eco.core.Eco;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Interface for display implementations.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface DisplayHandler {
/**
* Register display module.

View File

@@ -1,11 +1,15 @@
package com.willfp.eco.core.drops;
import com.willfp.eco.core.Eco;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Internal component to create backend DropQueue implementations.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface DropQueueFactory {
/**
* Create a DropQueue.

View File

@@ -1,7 +1,9 @@
package com.willfp.eco.core.drops;
import com.willfp.eco.core.Eco;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@@ -9,6 +11,8 @@ import java.util.Collection;
/**
* Internal interface for backend DropQueue implementations.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface InternalDropQueue {
/**
* Add item to queue.

View File

@@ -1,6 +1,6 @@
package com.willfp.eco.core.entities;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity;

View File

@@ -2,7 +2,7 @@ package com.willfp.eco.core.entities.impl;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.entities.TestableEntity;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;

View File

@@ -1,7 +1,7 @@
package com.willfp.eco.core.entities.impl;
import com.willfp.eco.core.entities.TestableEntity;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;

View File

@@ -1,7 +1,7 @@
package com.willfp.eco.core.entities.impl;
import com.willfp.eco.core.entities.TestableEntity;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;

View File

@@ -22,8 +22,30 @@ public interface FastItemStack {
*
* @param checkStored If stored NBT should also be checked.
* @return A map of all enchantments.
* @deprecated Poorly named method. Use getEnchants instead.
*/
Map<Enchantment, Integer> getEnchantmentsOnItem(boolean checkStored);
@Deprecated(since = "6.24.0")
default Map<Enchantment, Integer> getEnchantmentsOnItem(boolean checkStored) {
return getEnchants(checkStored);
}
/**
* Get all enchantments on an item.
* Does not account for stored enchants.
*
* @return A map of all enchantments.
*/
default Map<Enchantment, Integer> getEnchants() {
return getEnchants(false);
}
/**
* Get all enchantments on an item.
*
* @param checkStored If stored enchantments should be accounted for.
* @return A map of all enchantments.
*/
Map<Enchantment, Integer> getEnchants(boolean checkStored);
/**
* Get the level of an enchantment on an item.

View File

@@ -1,15 +1,19 @@
package com.willfp.eco.core.gui;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.gui.menu.MenuBuilder;
import com.willfp.eco.core.gui.slot.SlotBuilder;
import com.willfp.eco.core.gui.slot.functional.SlotProvider;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Internal component used by {@link com.willfp.eco.core.gui.menu.Menu#builder(int)}
* and {@link com.willfp.eco.core.gui.slot.Slot#builder(ItemStack)}.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface GUIFactory {
/**
* Create slot builder.

View File

@@ -1,6 +1,8 @@
package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.items.builder.ItemStackBuilder;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
import com.willfp.eco.util.ListUtils;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
@@ -38,7 +40,7 @@ public class FillerMask {
*/
public FillerMask(@NotNull final Material material,
@NotNull final String... pattern) {
this(new MaskMaterials(material), pattern);
this(new MaskItems(new MaterialTestableItem(material)), pattern);
}
/**
@@ -46,17 +48,33 @@ public class FillerMask {
*
* @param materials The mask materials.
* @param pattern The pattern.
* @deprecated Use {@link MaskItems} instead.
*/
@Deprecated(since = "6.24.0")
public FillerMask(@NotNull final MaskMaterials materials,
@NotNull final String... pattern) {
if (Arrays.stream(materials.materials()).anyMatch(material -> material == Material.AIR)) {
throw new IllegalArgumentException("Materials cannot be air!");
this(
materials.toMaskItems(),
pattern
);
}
/**
* Create a new filler mask.
*
* @param items The mask items.
* @param pattern The pattern.
*/
public FillerMask(@NotNull final MaskItems items,
@NotNull final String... pattern) {
if (Arrays.stream(items.items()).anyMatch(item -> item instanceof EmptyTestableItem)) {
throw new IllegalArgumentException("Items cannot be empty!");
}
mask = ListUtils.create2DList(6, 9);
for (int i = 0; i < materials.materials().length; i++) {
ItemStack itemStack = new ItemStackBuilder(materials.materials()[i])
for (int i = 0; i < items.items().length; i++) {
ItemStack itemStack = new ItemStackBuilder(items.items()[i])
.setDisplayName("&r")
.build();

View File

@@ -0,0 +1,45 @@
package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.items.Items;
import com.willfp.eco.core.items.TestableItem;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* Mask materials store a set of items which can be accessed by
* a filler mask.
*
* @param items The items.
*/
public record MaskItems(@NotNull TestableItem... items) {
/**
* Create MaskItems from a list of item names.
*
* @param names The names.
* @return The mask items.
*/
public static MaskItems fromItemNames(@NotNull final Iterable<String> names) {
List<TestableItem> items = new ArrayList<>();
for (String name : names) {
TestableItem item = Items.lookup(name);
if (item instanceof EmptyTestableItem) {
continue;
}
items.add(item);
}
if (items.isEmpty()) {
return new MaskItems(new MaterialTestableItem(Material.BLACK_STAINED_GLASS_PANE));
}
return new MaskItems(items.toArray(new TestableItem[0]));
}
}

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.items.Items;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
@@ -8,7 +9,16 @@ import org.jetbrains.annotations.NotNull;
* a filler mask.
*
* @param materials The materials.
* @deprecated Use {@link MaskItems} instead.
*/
@Deprecated(since = "6.24.0")
public record MaskMaterials(@NotNull Material... materials) {
/**
* Convert MaskMaterials to MaskItems.
*
* @return The MaskItems.
*/
public MaskItems toMaskItems() {
return new MaskItems(Items.fromMaterials(this.materials()));
}
}

View File

@@ -2,6 +2,7 @@ package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.gui.slot.functional.SlotHandler;
import com.willfp.eco.core.gui.slot.functional.SlotModifier;
import com.willfp.eco.core.gui.slot.functional.SlotUpdater;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
@@ -106,8 +107,23 @@ public interface SlotBuilder {
*
* @param modifier The modifier.
* @return The builder.
* @deprecated Use {@link SlotBuilder#setUpdater(SlotUpdater)} instead.
*/
SlotBuilder setModifier(@NotNull SlotModifier modifier);
@Deprecated
default SlotBuilder setModifier(@NotNull SlotModifier modifier) {
return setUpdater((player, menu, previous) -> {
modifier.modify(player, menu, previous);
return previous;
});
}
/**
* Set the ItemStack updater.
*
* @param updater The updater.
* @return The builder.
*/
SlotBuilder setUpdater(@NotNull SlotUpdater updater);
/**
* Set slot to be a captive slot.

View File

@@ -7,8 +7,11 @@ import org.jetbrains.annotations.NotNull;
/**
* Interface to run on slot modify.
*
* @deprecated Use {@link SlotUpdater} instead.
*/
@FunctionalInterface
@Deprecated
public interface SlotModifier {
/**
* Performs this operation on the given arguments.

View File

@@ -0,0 +1,24 @@
package com.willfp.eco.core.gui.slot.functional;
import com.willfp.eco.core.gui.menu.Menu;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Interface to run on slot update.
*/
@FunctionalInterface
public interface SlotUpdater {
/**
* Performs this operation on the given arguments.
*
* @param player The player.
* @param menu The menu.
* @param previous The previous ItemStack.
* @return The new ItemStack.
*/
ItemStack update(@NotNull Player player,
@NotNull Menu menu,
@NotNull ItemStack previous);
}

View File

@@ -1,10 +1,12 @@
package com.willfp.eco.core.integrations.placeholder;
import com.willfp.eco.core.EcoPlugin;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Function;
/**
@@ -28,12 +30,20 @@ public class PlaceholderEntry {
*/
private final boolean requiresPlayer;
/**
* The plugin for the placeholder.
*/
@Nullable
private final EcoPlugin plugin;
/**
* Create a placeholder entry that doesn't require a player.
*
* @param identifier The identifier of the placeholder.
* @param function A lambda to get the result of the placeholder given a player.
* @deprecated Specify a plugin.
*/
@Deprecated
public PlaceholderEntry(@NotNull final String identifier,
@NotNull final Function<Player, String> function) {
this(identifier, function, false);
@@ -45,10 +55,41 @@ public class PlaceholderEntry {
* @param identifier The identifier of the placeholder.
* @param function A lambda to get the result of the placeholder.
* @param requiresPlayer If the placeholder requires a player.
* @deprecated Specify a plugin.
*/
@Deprecated
public PlaceholderEntry(@NotNull final String identifier,
@NotNull final Function<Player, String> function,
final boolean requiresPlayer) {
this(null, identifier, function, requiresPlayer);
}
/**
* Create a placeholder entry that doesn't require a player.
*
* @param plugin The plugin for the placeholder.
* @param identifier The identifier of the placeholder.
* @param function A lambda to get the result of the placeholder given a player.
*/
public PlaceholderEntry(@Nullable final EcoPlugin plugin,
@NotNull final String identifier,
@NotNull final Function<Player, String> function) {
this(plugin, identifier, function, false);
}
/**
* Create a placeholder entry that may require a player.
*
* @param plugin The plugin for the placeholder.
* @param identifier The identifier of the placeholder.
* @param function A lambda to get the result of the placeholder.
* @param requiresPlayer If the placeholder requires a player.
*/
public PlaceholderEntry(@Nullable final EcoPlugin plugin,
@NotNull final String identifier,
@NotNull final Function<Player, String> function,
final boolean requiresPlayer) {
this.plugin = plugin;
this.identifier = identifier;
this.function = function;
this.requiresPlayer = requiresPlayer;
@@ -85,10 +126,37 @@ public class PlaceholderEntry {
return identifier;
}
/**
* Get the plugin.
*
* @return The plugin.
*/
@Nullable
public EcoPlugin getPlugin() {
return plugin;
}
/**
* Register the placeholder.
*/
public void register() {
PlaceholderManager.registerPlaceholder(this);
}
@Override
public boolean equals(@Nullable final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof PlaceholderEntry entry)) {
return false;
}
return Objects.equals(this.getIdentifier(), entry.getIdentifier())
&& Objects.equals(this.getPlugin(), entry.getPlugin());
}
@Override
public int hashCode() {
return Objects.hash(this.getIdentifier(), this.getPlugin());
}
}

View File

@@ -5,6 +5,9 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* Wrapper class for placeholder integrations.
*/
@@ -24,4 +27,14 @@ public interface PlaceholderIntegration extends Integration {
*/
String translate(@NotNull String text,
@Nullable Player player);
/**
* Find all placeholders in a given text.
*
* @param text The text.
* @return The placeholders.
*/
default List<String> findPlaceholdersIn(@NotNull String text) {
return new ArrayList<>();
}
}

View File

@@ -1,13 +1,20 @@
package com.willfp.eco.core.integrations.placeholder;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Class to handle placeholder integrations.
@@ -16,17 +23,24 @@ public final class PlaceholderManager {
/**
* All registered placeholders.
*/
private static final Map<String, PlaceholderEntry> REGISTERED_PLACEHOLDERS = new HashMap<>();
private static final Map<EcoPlugin, Map<String, PlaceholderEntry>> REGISTERED_PLACEHOLDERS = new HashMap<>();
/**
* All registered placeholder integrations.
*/
private static final Set<PlaceholderIntegration> REGISTERED_INTEGRATIONS = new HashSet<>();
/**
* Placeholder Cache.
*/
private static final LoadingCache<EntryWithPlayer, String> PLACEHOLDER_CACHE = Caffeine.newBuilder()
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
.build(key -> key.entry.getResult(key.player));
/**
* Register a new placeholder integration.
*
* @param integration The {@link PlaceholderIntegration} to register.
* @param integration The {@link com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration} to register.
*/
public static void addIntegration(@NotNull final PlaceholderIntegration integration) {
integration.registerIntegration();
@@ -36,11 +50,14 @@ public final class PlaceholderManager {
/**
* Register a placeholder.
*
* @param expansion The {@link PlaceholderEntry} to register.
* @param expansion The {@link com.willfp.eco.core.integrations.placeholder.PlaceholderEntry} to register.
*/
public static void registerPlaceholder(@NotNull final PlaceholderEntry expansion) {
REGISTERED_PLACEHOLDERS.remove(expansion.getIdentifier());
REGISTERED_PLACEHOLDERS.put(expansion.getIdentifier(), expansion);
EcoPlugin plugin = expansion.getPlugin() == null ? Eco.getHandler().getEcoPlugin() : expansion.getPlugin();
Map<String, PlaceholderEntry> pluginPlaceholders = REGISTERED_PLACEHOLDERS
.getOrDefault(plugin, new HashMap<>());
pluginPlaceholders.put(expansion.getIdentifier(), expansion);
REGISTERED_PLACEHOLDERS.put(plugin, pluginPlaceholders);
}
/**
@@ -49,10 +66,36 @@ public final class PlaceholderManager {
* @param player The player to get the result from.
* @param identifier The placeholder identifier.
* @return The value of the placeholder.
* @deprecated Specify a plugin to get the result from.
*/
@Deprecated
public static String getResult(@Nullable final Player player,
@NotNull final String identifier) {
PlaceholderEntry entry = REGISTERED_PLACEHOLDERS.get(identifier.toLowerCase());
return getResult(player, identifier, null);
}
/**
* Get the result of a placeholder with respect to a player.
*
* @param player The player to get the result from.
* @param identifier The placeholder identifier.
* @param plugin The plugin for the placeholder.
* @return The value of the placeholder.
*/
public static String getResult(@Nullable final Player player,
@NotNull final String identifier,
@Nullable final EcoPlugin plugin) {
EcoPlugin owner = plugin == null ? Eco.getHandler().getEcoPlugin() : plugin;
PlaceholderEntry entry = REGISTERED_PLACEHOLDERS.getOrDefault(owner, new HashMap<>()).get(identifier.toLowerCase());
if (entry == null && plugin != null) {
PlaceholderEntry alternate = REGISTERED_PLACEHOLDERS.getOrDefault(Eco.getHandler().getEcoPlugin(), new HashMap<>())
.get(identifier.toLowerCase());
if (alternate != null) {
entry = alternate;
}
}
if (entry == null) {
return "";
}
@@ -61,7 +104,7 @@ public final class PlaceholderManager {
return "";
}
return entry.getResult(player);
return PLACEHOLDER_CACHE.get(new EntryWithPlayer(entry, player));
}
/**
@@ -80,6 +123,26 @@ public final class PlaceholderManager {
return processed;
}
/**
* Find all placeholders in a given text.
*
* @param text The text.
* @return The placeholders.
*/
public static List<String> findPlaceholdersIn(@NotNull final String text) {
List<String> found = new ArrayList<>();
for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) {
found.addAll(integration.findPlaceholdersIn(text));
}
return found;
}
private static record EntryWithPlayer(@NotNull PlaceholderEntry entry,
@Nullable Player player) {
}
private PlaceholderManager() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -0,0 +1,103 @@
package com.willfp.eco.core.items;
import com.willfp.eco.core.fast.FastItemStack;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* An item and its {@link com.willfp.eco.core.fast.FastItemStack} hash.
*/
public final class HashedItem {
/**
* The item.
*/
private final ItemStack item;
/**
* The hash.
*/
private final int hash;
/**
* Create new hashed item.
*
* @param item The item.
* @param hash The hash.
*/
private HashedItem(@NotNull final ItemStack item,
final int hash) {
this.item = item;
this.hash = hash;
}
/**
* Get the item.
*
* @return The ItemStack.
*/
public ItemStack getItem() {
return this.item;
}
/**
* Get the hash.
*
* @return The hash.
*/
public int getHash() {
return this.hash;
}
/**
* Kotlin destructuring support.
*
* @return The ItemStack.
*/
public ItemStack component1() {
return this.getItem();
}
/**
* Kotlin destructuring support.
*
* @return The hash.
*/
public int component2() {
return this.getHash();
}
@Override
public int hashCode() {
return this.hash;
}
@Override
public boolean equals(@Nullable final Object other) {
if (!(other instanceof HashedItem o)) {
return false;
}
return o.hash == this.hash;
}
/**
* Hashed item from an item.
*
* @param item The item.
* @return The hashed item.
*/
public static HashedItem of(@NotNull final ItemStack item) {
return new HashedItem(item, FastItemStack.wrap(item).hashCode());
}
/**
* Hashed item from a fast item stack.
*
* @param item The item.
* @return The hashed item.
*/
public static HashedItem of(@NotNull final FastItemStack item) {
return new HashedItem(item.unwrap(), item.hashCode());
}
}

View File

@@ -1,5 +1,7 @@
package com.willfp.eco.core.items;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.willfp.eco.core.items.args.LookupArgParser;
import com.willfp.eco.core.items.provider.ItemProvider;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
@@ -18,10 +20,13 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -34,6 +39,25 @@ public final class Items {
*/
private static final Map<NamespacedKey, TestableItem> REGISTRY = new ConcurrentHashMap<>();
/**
* Cached custom item lookups, using {@link HashedItem}.
*/
private static final LoadingCache<HashedItem, Optional<TestableItem>> CACHE = Caffeine.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES)
.build(
key -> {
TestableItem match = null;
for (TestableItem item : REGISTRY.values()) {
if (item.matches(key.getItem())) {
match = item;
break;
}
}
return Optional.ofNullable(match);
}
);
/**
* All item providers.
*/
@@ -194,7 +218,7 @@ public final class Items {
}
}
// Marked as redundant but i am covering all bases here
// Marked as redundant but I am covering all bases here
if (item == null || item instanceof EmptyTestableItem) {
return new EmptyTestableItem();
}
@@ -276,12 +300,7 @@ public final class Items {
* @return If is recipe.
*/
public static boolean isCustomItem(@NotNull final ItemStack itemStack) {
for (TestableItem item : REGISTRY.values()) {
if (item.matches(itemStack)) {
return true;
}
}
return false;
return getCustomItem(itemStack) != null;
}
/**
@@ -292,12 +311,7 @@ public final class Items {
*/
@Nullable
public static CustomItem getCustomItem(@NotNull final ItemStack itemStack) {
for (TestableItem item : REGISTRY.values()) {
if (item.matches(itemStack)) {
return getOrWrap(item);
}
}
return null;
return CACHE.get(HashedItem.of(itemStack)).map(Items::getOrWrap).orElse(null);
}
/**
@@ -331,6 +345,35 @@ public final class Items {
}
}
/**
* Convert an array of materials to an array of testable items.
*
* @param materials The materials.
* @return An array of functionally identical testable items.
*/
@NotNull
public static TestableItem[] fromMaterials(@NotNull final Material... materials) {
return Arrays.stream(materials)
.map(MaterialTestableItem::new)
.toArray(MaterialTestableItem[]::new);
}
/**
* Convert a collection of materials into a collection of testable items.
*
* @param materials The materials.
* @return A collection of functionally identical testable items.
*/
@NotNull
public static Collection<TestableItem> fromMaterials(@NotNull final Iterable<Material> materials) {
List<TestableItem> items = new ArrayList<>();
for (Material material : materials) {
items.add(new MaterialTestableItem(material));
}
return items;
}
private Items() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -1,36 +0,0 @@
package com.willfp.eco.core.items.args;
import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
/**
* Parse leather armor colors.
*
* @deprecated Moved to internals.
*/
@Deprecated(since = "6.16.0", forRemoval = true)
@ApiStatus.ScheduledForRemoval(inVersion = "6.18.2")
public class ColorArgParser implements LookupArgParser {
/**
* Instantiate arg parser.
*/
public ColorArgParser() {
Bukkit.getLogger().severe("Instantiation of class marked for removal! (" + this.getClass().getName() + "), this will throw an error in a future release!");
}
@Override
public @Nullable Predicate<ItemStack> parseArguments(@NotNull final String[] args,
@NotNull final ItemMeta meta) {
return null;
}
static {
Bukkit.getLogger().severe("Referencing a class marked for removal! (" + ColorArgParser.class.getName() + "), this will throw an error in the next release!");
}
}

View File

@@ -1,36 +0,0 @@
package com.willfp.eco.core.items.args;
import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
/**
* Parse custom model data.
*
* @deprecated Moved to internals.
*/
@Deprecated(since = "6.16.0", forRemoval = true)
@ApiStatus.ScheduledForRemoval(inVersion = "6.18.2")
public class CustomModelDataArgParser implements LookupArgParser {
/**
* Instantiate arg parser.
*/
public CustomModelDataArgParser() {
Bukkit.getLogger().severe("Instantiation of class marked for removal! (" + this.getClass().getName() + "), this will throw an error in a future release!");
}
@Override
public @Nullable Predicate<ItemStack> parseArguments(@NotNull final String[] args,
@NotNull final ItemMeta meta) {
return null;
}
static {
Bukkit.getLogger().severe("Referencing a class marked for removal! (" + CustomModelDataArgParser.class.getName() + "), this will throw an error in the next release!");
}
}

View File

@@ -1,36 +0,0 @@
package com.willfp.eco.core.items.args;
import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
/**
* Parses enchantment arguments.
*
* @deprecated Moved to internals.
*/
@Deprecated(since = "6.16.0", forRemoval = true)
@ApiStatus.ScheduledForRemoval(inVersion = "6.18.2")
public class EnchantmentArgParser implements LookupArgParser {
/**
* Instantiate arg parser.
*/
public EnchantmentArgParser() {
Bukkit.getLogger().severe("Instantiation of class marked for removal! (" + this.getClass().getName() + "), this will throw an error in a future release!");
}
@Override
public @Nullable Predicate<ItemStack> parseArguments(@NotNull final String[] args,
@NotNull final ItemMeta meta) {
return null;
}
static {
Bukkit.getLogger().severe("Referencing a class marked for removal! (" + EnchantmentArgParser.class.getName() + "), this will throw an error in the next release!");
}
}

View File

@@ -1,36 +0,0 @@
package com.willfp.eco.core.items.args;
import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
/**
* Parse skull textures.
*
* @deprecated Moved to internals.
*/
@Deprecated(since = "6.16.0", forRemoval = true)
@ApiStatus.ScheduledForRemoval(inVersion = "6.18.2")
public class TextureArgParser implements LookupArgParser {
/**
* Instantiate arg parser.
*/
public TextureArgParser() {
Bukkit.getLogger().severe("Instantiation of class marked for removal! (" + this.getClass().getName() + "), this will throw an error in a future release!");
}
@Override
public @Nullable Predicate<ItemStack> parseArguments(@NotNull final String[] args,
@NotNull final ItemMeta meta) {
return null;
}
static {
Bukkit.getLogger().severe("Referencing a class marked for removal! (" + TextureArgParser.class.getName() + "), this will throw an error in the next release!");
}
}

View File

@@ -5,12 +5,25 @@ import org.jetbrains.annotations.NotNull;
/**
* Generic error with proxy loading.
*/
public class ProxyError extends RuntimeException {
public class ProxyError extends Error {
/**
* Thrown if there is an error getting a proxy.
*
* @param message The message to send.
* @param cause The cause.
*/
public ProxyError(@NotNull final String message,
@NotNull final Throwable cause) {
super(message, cause);
}
/**
* Thrown if there is an error getting a proxy.
*
* @param message The message to send.
* @deprecated Proxy Errors should include a cause.
*/
@Deprecated
public ProxyError(@NotNull final String message) {
super(message);
}

View File

@@ -0,0 +1,15 @@
package com.willfp.eco.core.proxy.exceptions;
import com.willfp.eco.core.proxy.ProxyConstants;
/**
* Server running an unsupported version.
*/
public class UnsupportedVersionError extends Error {
/**
* Thrown if the server is running an unsupported version.
*/
public UnsupportedVersionError() {
super("You're running an unsupported server version: " + ProxyConstants.NMS_VERSION);
}
}

View File

@@ -1,17 +1,30 @@
package com.willfp.eco.core.proxy.exceptions;
import com.willfp.eco.core.proxy.ProxyConstants;
import org.jetbrains.annotations.NotNull;
/**
* Error if the server is running an unsupported version.
*
* @deprecated Poorly named, exception when it's actually an error, contains doubly nested errors.
*/
@Deprecated(since = "6.24.0", forRemoval = true)
public class UnsupportedVersionException extends ProxyError {
/**
* Thrown if the server is running an unsupported NMS version.
*
* @param message The message to send.
* @deprecated Use the default constructor.
*/
@Deprecated(since = "6.24.0")
public UnsupportedVersionException(@NotNull final String message) {
super(message);
}
/**
* Thrown if the server is running an unsupported NMS version.
*/
public UnsupportedVersionException() {
super("You're running an unsupported server version: " + ProxyConstants.NMS_VERSION, new IllegalStateException());
}
}

View File

@@ -6,6 +6,8 @@ import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.items.Items;
import com.willfp.eco.core.recipe.recipes.CraftingRecipe;
import com.willfp.eco.core.recipe.recipes.ShapedCraftingRecipe;
import com.willfp.eco.util.NamespacedKeyUtils;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -16,7 +18,6 @@ import java.util.List;
/**
* Utility class to manage and register crafting recipes.
*/
@SuppressWarnings("deprecation")
public final class Recipes {
/**
* Registry of all recipes.
@@ -58,7 +59,10 @@ public final class Recipes {
}
if (key.getKey().contains("_displayed")) {
NamespacedKey otherKey = new NamespacedKey(key.getNamespace(), key.getKey().replace("_displayed", ""));
NamespacedKey otherKey = NamespacedKeyUtils.create(
key.getNamespace(),
key.getKey().replace("_displayed", "")
);
return RECIPES.get(otherKey);
}
@@ -92,6 +96,7 @@ public final class Recipes {
* @param permission The permission.
* @return The recipe.
*/
@Nullable
public static CraftingRecipe createAndRegisterRecipe(@NotNull final EcoPlugin plugin,
@NotNull final String key,
@NotNull final ItemStack output,
@@ -105,6 +110,12 @@ public final class Recipes {
builder.setRecipePart(i, Items.lookup(recipeStrings.get(i)));
}
if (builder.isAir()) {
Bukkit.getLogger().warning("RECIPE ERROR! " + plugin.getName() + ":" + key + " consists only");
Bukkit.getLogger().warning("of air or invalid items! Please change that or disable this recipe.");
return null;
}
ShapedCraftingRecipe recipe = builder.build();
recipe.register();

View File

@@ -287,6 +287,20 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
return this;
}
/**
* Check if recipe parts are all air.
*
* @return If recipe parts are all air.
*/
public boolean isAir() {
for (TestableItem recipePart : this.recipeParts) {
if (recipePart != null && !(recipePart instanceof EmptyTestableItem)) {
return false;
}
}
return true;
}
/**
* Build the recipe.
*

View File

@@ -7,7 +7,11 @@ import java.util.List;
/**
* A requirement is a defined goal that a player must meet.
*
* @deprecated No typing, weak definitions, and not an API component. Shouldn't be in eco.
*/
@Deprecated(since = "6.24.0", forRemoval = true)
@SuppressWarnings("DeprecatedIsStillUsed")
public abstract class Requirement {
/**
* Create a new requirement.

View File

@@ -1,10 +1,18 @@
package com.willfp.eco.core.requirement;
import com.willfp.eco.core.Eco;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Interface for internal requirement factory implementations.
*
* @deprecated See {@link Requirement}.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
@Deprecated(since = "6.24.0", forRemoval = true)
@SuppressWarnings({"removal", "DeprecatedIsStillUsed"})
public interface RequirementFactory {
/**
* Create a requirement.

View File

@@ -5,7 +5,11 @@ import org.jetbrains.annotations.NotNull;
/**
* Contains methods and fields pertaining to requirements.
*
* @deprecated See {@link Requirement}.
*/
@Deprecated(since = "6.24.0", forRemoval = true)
@SuppressWarnings("removal")
public final class Requirements {
/**
* Requires a player to have a permission.

View File

@@ -26,11 +26,26 @@ public final class DurabilityUtils {
* @param item The item to damage.
* @param damage The amount of damage to deal.
* @param slot The slot in the inventory of the item.
* @deprecated The slot is not required.
*/
@Deprecated(since = "6.24.0")
public static void damageItem(@NotNull final Player player,
@NotNull final ItemStack item,
final int damage,
final int slot) {
damageItem(player, item, damage);
}
/**
* Damage an item in a player's inventory.
*
* @param player The player.
* @param item The item to damage.
* @param damage The amount of damage to deal.
*/
public static void damageItem(@NotNull final Player player,
@NotNull final ItemStack item,
final int damage) {
if (item.getItemMeta() == null) {
return;
}
@@ -61,7 +76,7 @@ public final class DurabilityUtils {
item.setItemMeta((ItemMeta) meta);
PlayerItemBreakEvent event = new PlayerItemBreakEvent(player, item);
Bukkit.getPluginManager().callEvent(event);
player.getInventory().clear(slot);
item.setType(Material.AIR);
player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, SoundCategory.BLOCKS, 1, 1);
} else {
item.setItemMeta((ItemMeta) meta);
@@ -69,6 +84,44 @@ public final class DurabilityUtils {
}
}
/**
* Damage an item.
*
* @param item The item to damage.
* @param damage The amount of damage to deal.
*/
public static void damageItem(@NotNull final ItemStack item,
final int damage) {
if (item.getItemMeta() == null) {
return;
}
if (item.getItemMeta().isUnbreakable()) {
return;
}
if (!(item.getItemMeta() instanceof Damageable)) {
return;
}
// Special edge case
if (item.getType() == Material.CARVED_PUMPKIN || item.getType() == Material.PLAYER_HEAD) {
return;
}
Damageable meta = (Damageable) item.getItemMeta();
meta.setDamage(meta.getDamage() + damage);
if (meta.getDamage() >= item.getType().getMaxDurability()) {
meta.setDamage(item.getType().getMaxDurability());
item.setItemMeta((ItemMeta) meta);
item.setType(Material.AIR);
} else {
item.setItemMeta((ItemMeta) meta);
}
}
/**
* Damage an item in a player's inventory without breaking it.
*

View File

@@ -1,7 +1,9 @@
package com.willfp.eco.util;
import com.willfp.eco.core.Eco;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
@@ -17,7 +19,7 @@ public final class NamespacedKeyUtils {
*/
@NotNull
public static NamespacedKey createEcoKey(@NotNull final String string) {
return Objects.requireNonNull(NamespacedKey.fromString("eco:" + string));
return NamespacedKeyUtils.create("eco", string);
}
/**
@@ -30,7 +32,45 @@ public final class NamespacedKeyUtils {
@NotNull
public static NamespacedKey create(@NotNull final String namespace,
@NotNull final String key) {
return Objects.requireNonNull(NamespacedKey.fromString(namespace + ":" + key));
return Eco.getHandler().createNamespacedKey(
namespace,
key
);
}
/**
* Create a NamespacedKey from a string.
* <p>
* Preferred over {@link NamespacedKey#fromString(String)} for performance reasons.
*
* @param string The string.
* @return The key.
*/
@NotNull
public static NamespacedKey fromString(@NotNull final String string) {
return Objects.requireNonNull(NamespacedKeyUtils.fromStringOrNull(string));
}
/**
* Create a NamespacedKey from a string.
* <p>
* Preferred over {@link NamespacedKey#fromString(String)} for performance reasons.
*
* @param string The string.
* @return The key, or null if not a key.
*/
@Nullable
public static NamespacedKey fromStringOrNull(@NotNull final String string) {
int index = string.indexOf(":");
if (index < 0) {
return null;
}
return NamespacedKeyUtils.create(
string.substring(0, index),
string.substring(index + 1)
);
}
private NamespacedKeyUtils() {

View File

@@ -1,11 +1,16 @@
package com.willfp.eco.util;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.DecimalFormat;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.BiFunction;
/**
* Utilities / API methods for numbers.
@@ -16,6 +21,11 @@ public final class NumberUtils {
*/
private static final double[] SIN_LOOKUP = new double[65536];
/**
* Crunch handler.
*/
private static BiFunction<String, Player, Double> crunch = null;
/**
* Set of roman numerals to look up.
*/
@@ -83,7 +93,9 @@ public final class NumberUtils {
* @param toChange The value to test.
* @param limit The maximum.
* @return The new value.
* @deprecated Pointless method.
*/
@Deprecated(since = "6.19.0")
public static int equalIfOver(final int toChange,
final int limit) {
return Math.min(toChange, limit);
@@ -95,7 +107,9 @@ public final class NumberUtils {
* @param toChange The value to test.
* @param limit The maximum.
* @return The new value.
* @deprecated Pointless method.
*/
@Deprecated(since = "6.19.0")
public static double equalIfOver(final double toChange,
final double limit) {
return Math.min(toChange, limit);
@@ -218,6 +232,39 @@ public final class NumberUtils {
return formatted.endsWith("00") ? String.valueOf((int) toFormat) : formatted;
}
/**
* Evaluate an expression.
*
* @param expression The expression.
* @return The value of the expression, or zero if invalid.
*/
public static double evaluateExpression(@NotNull final String expression) {
return evaluateExpression(expression, null);
}
/**
* Evaluate an expression with respect to a player (for placeholders).
*
* @param expression The expression.
* @param player The player.
* @return The value of the expression, or zero if invalid.
*/
public static double evaluateExpression(@NotNull final String expression,
@Nullable final Player player) {
return crunch.apply(expression, player);
}
/**
* Init crunch handler.
*
* @param handler The handler.
*/
@ApiStatus.Internal
public static void initCrunch(@NotNull final BiFunction<String, Player, Double> handler) {
Validate.isTrue(crunch == null, "Already initialized!");
crunch = handler;
}
private NumberUtils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -5,6 +5,7 @@ import com.willfp.eco.core.Prerequisite;
import com.willfp.eco.core.data.PlayerProfile;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import com.willfp.eco.core.data.keys.PersistentDataKeyType;
import com.willfp.eco.core.integrations.anticheat.AnticheatManager;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.OfflinePlayer;
@@ -12,6 +13,8 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
/**
* Utilities / API methods for players.
*/
@@ -107,6 +110,38 @@ public final class PlayerUtils {
profile.write(PLAYER_NAME_KEY, player.getDisplayName());
}
/**
* Run something with the player exempted.
*
* @param player The player.
* @param action The action.
*/
public static void runExempted(@NotNull final Player player,
@NotNull final Consumer<Player> action) {
try {
AnticheatManager.exemptPlayer(player);
action.accept(player);
} finally {
AnticheatManager.unexemptPlayer(player);
}
}
/**
* Run something with the player exempted.
*
* @param player The player.
* @param action The action.
*/
public static void runExempted(@NotNull final Player player,
@NotNull final Runnable action) {
try {
AnticheatManager.exemptPlayer(player);
action.run();
} finally {
AnticheatManager.unexemptPlayer(player);
}
}
private PlayerUtils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -1,5 +1,7 @@
package com.willfp.eco.util;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonSyntaxException;
@@ -20,6 +22,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -66,6 +69,42 @@ public final class StringUtils {
.emitLegacyHoverEvent()
.build();
/**
* String format cache.
*/
private static final LoadingCache<String, String> STRING_FORMAT_CACHE = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build(StringUtils::processFormatting);
/**
* Json -> Legacy Cache.
*/
private static final LoadingCache<String, String> JSON_TO_LEGACY = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build(
json -> {
try {
Component component = GSON_COMPONENT_SERIALIZER.deserialize(json);
return LEGACY_COMPONENT_SERIALIZER.serialize(component);
} catch (JsonSyntaxException e) {
return json;
}
}
);
/**
* Legacy -> Json Cache.
*/
private static final LoadingCache<String, String> LEGACY_TO_JSON = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build(
legacy -> GSON_COMPONENT_SERIALIZER.serialize(
Component.empty().decoration(TextDecoration.ITALIC, false).append(
LEGACY_COMPONENT_SERIALIZER.deserialize(legacy)
)
)
);
/**
* Color map.
*/
@@ -272,6 +311,11 @@ public final class StringUtils {
if (option == FormatOption.WITH_PLACEHOLDERS) {
processedMessage = PlaceholderManager.translatePlaceholders(processedMessage, player);
}
return STRING_FORMAT_CACHE.get(processedMessage);
}
private static String processFormatting(@NotNull final String message) {
String processedMessage = message;
processedMessage = ChatColor.translateAlternateColorCodes('&', processedMessage);
processedMessage = translateGradients(processedMessage);
processedMessage = translateHexColorCodes(processedMessage);
@@ -423,11 +467,8 @@ public final class StringUtils {
if (legacy == null) {
processed = "";
}
return GSON_COMPONENT_SERIALIZER.serialize(
Component.empty().decoration(TextDecoration.ITALIC, false).append(
LEGACY_COMPONENT_SERIALIZER.deserialize(processed)
)
);
return LEGACY_TO_JSON.get(processed);
}
/**
@@ -442,12 +483,7 @@ public final class StringUtils {
return "";
}
try {
Component component = GSON_COMPONENT_SERIALIZER.deserialize(json);
return LEGACY_COMPONENT_SERIALIZER.serialize(component);
} catch (JsonSyntaxException e) {
return json;
}
return JSON_TO_LEGACY.get(json);
}
/**

View File

@@ -2,7 +2,6 @@ package com.willfp.eco.util;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.willfp.eco.core.Prerequisite;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
@@ -69,8 +68,10 @@ public final class TeamUtils {
*
* @param material The material to find the team from.
* @return The team.
* @deprecated Stupid method.
*/
@NotNull
@Deprecated(since = "6.24.0")
public static Team getMaterialColorTeam(@NotNull final Material material) {
return fromChatColor(MATERIAL_COLORS.getOrDefault(material, ChatColor.WHITE));
}
@@ -89,17 +90,15 @@ public final class TeamUtils {
MATERIAL_COLORS.put(Material.EMERALD_ORE, ChatColor.GREEN);
MATERIAL_COLORS.put(Material.ANCIENT_DEBRIS, ChatColor.DARK_RED);
if (Prerequisite.HAS_1_17.isMet()) {
MATERIAL_COLORS.put(Material.COPPER_ORE, ChatColor.GOLD);
MATERIAL_COLORS.put(Material.DEEPSLATE_COPPER_ORE, ChatColor.GOLD);
MATERIAL_COLORS.put(Material.DEEPSLATE_COAL_ORE, ChatColor.BLACK);
MATERIAL_COLORS.put(Material.DEEPSLATE_IRON_ORE, ChatColor.GRAY);
MATERIAL_COLORS.put(Material.DEEPSLATE_GOLD_ORE, ChatColor.YELLOW);
MATERIAL_COLORS.put(Material.DEEPSLATE_LAPIS_ORE, ChatColor.BLUE);
MATERIAL_COLORS.put(Material.DEEPSLATE_REDSTONE_ORE, ChatColor.RED);
MATERIAL_COLORS.put(Material.DEEPSLATE_DIAMOND_ORE, ChatColor.AQUA);
MATERIAL_COLORS.put(Material.DEEPSLATE_EMERALD_ORE, ChatColor.GREEN);
}
MATERIAL_COLORS.put(Material.COPPER_ORE, ChatColor.GOLD);
MATERIAL_COLORS.put(Material.DEEPSLATE_COPPER_ORE, ChatColor.GOLD);
MATERIAL_COLORS.put(Material.DEEPSLATE_COAL_ORE, ChatColor.BLACK);
MATERIAL_COLORS.put(Material.DEEPSLATE_IRON_ORE, ChatColor.GRAY);
MATERIAL_COLORS.put(Material.DEEPSLATE_GOLD_ORE, ChatColor.YELLOW);
MATERIAL_COLORS.put(Material.DEEPSLATE_LAPIS_ORE, ChatColor.BLUE);
MATERIAL_COLORS.put(Material.DEEPSLATE_REDSTONE_ORE, ChatColor.RED);
MATERIAL_COLORS.put(Material.DEEPSLATE_DIAMOND_ORE, ChatColor.AQUA);
MATERIAL_COLORS.put(Material.DEEPSLATE_EMERALD_ORE, ChatColor.GREEN);
}
private TeamUtils() {

View File

@@ -0,0 +1,142 @@
@file:JvmName("CommandHelperExtensions")
package com.willfp.eco.core.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.CommandBase
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.eco.core.command.impl.Subcommand
import org.bukkit.command.CommandSender
/**
* Helper class for creating commands with builders.
*
* @param plugin The plugin.
* @param name The command name.
* @param permission The permission.
* @param playersOnly If only players should run the command.
* @param executor The command executor.
* @param tabCompleter The tab completer.
*/
class BuiltPluginCommand internal constructor(
plugin: EcoPlugin,
name: String,
permission: String,
playersOnly: Boolean = false,
var executor: (CommandSender, List<String>) -> Unit,
var tabCompleter: (CommandSender, List<String>) -> List<String>,
) : PluginCommand(plugin, name, permission, playersOnly) {
override fun onExecute(sender: CommandSender, args: List<String>) =
executor(sender, args)
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> =
tabCompleter(sender, args)
}
/**
* Helper class for creating commands with builders.
*
* @param plugin The plugin.
* @param name The command name.
* @param permission The permission.
* @param playersOnly If only players should run the command.
* @param executor The command executor.
* @param tabCompleter The tab completer.
*/
class BuiltSubcommand internal constructor(
plugin: EcoPlugin,
name: String,
permission: String,
playersOnly: Boolean = false,
var executor: (CommandSender, List<String>) -> Unit,
var tabCompleter: (CommandSender, List<String>) -> List<String>,
) : Subcommand(plugin, name, permission, playersOnly) {
internal constructor(
parent: CommandBase,
name: String,
executor: (CommandSender, List<String>) -> Unit,
tabCompleter: (CommandSender, List<String>) -> List<String>,
) : this(parent.plugin, name, parent.permission, parent.isPlayersOnly, executor, tabCompleter)
override fun onExecute(sender: CommandSender, args: List<String>) =
executor(sender, args)
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> =
tabCompleter(sender, args)
}
/**
* Kotlin builder for commands.
*
* @param plugin The plugin.
* @param name The command name.
* @param permission The permission.
* @param playersOnly If only players should execute the command.
* @param init The builder.
*/
fun command(
plugin: EcoPlugin,
name: String,
permission: String,
playersOnly: Boolean = false,
init: BuiltPluginCommand.() -> Unit
): PluginCommand {
val command = BuiltPluginCommand(
plugin,
name,
permission,
playersOnly,
{ _, _ -> },
{ _, _ -> emptyList() }
)
init(command)
return command
}
/**
* Kotlin builder for commands.
*
* @param name The command name.
* @param permission The permission.
* @param playersOnly If only players should execute the command.
* @param init The builder.
*/
fun CommandBase.addSubcommand(
name: String,
permission: String,
playersOnly: Boolean = false,
init: BuiltSubcommand.() -> Unit
): Subcommand {
val command = BuiltSubcommand(
this.plugin,
name,
permission,
playersOnly,
{ _, _ -> },
{ _, _ -> emptyList() }
)
init(command)
return command
}
/**
* Kotlin builder for commands.
* Inherits plugin, permission, players only.
*
* @param name The command name.
* @param init The builder.
*/
fun CommandBase.addSubcommand(
name: String,
init: BuiltSubcommand.() -> Unit
): Subcommand {
val command = BuiltSubcommand(
this,
name,
{ _, _ -> },
{ _, _ -> emptyList() }
)
init(command)
return command
}

View File

@@ -0,0 +1,18 @@
@file:JvmName("ProfileExtensions")
package com.willfp.eco.core.data
import org.bukkit.OfflinePlayer
import org.bukkit.Server
/**
* @see PlayerProfile.load
*/
val OfflinePlayer.profile: PlayerProfile
get() = PlayerProfile.load(this)
/**
* @see ServerProfile.load
*/
val Server.profile: ServerProfile
get() = ServerProfile.load()

View File

@@ -0,0 +1,11 @@
@file:JvmName("FastItemStackExtensions")
package com.willfp.eco.core.fast
import org.bukkit.inventory.ItemStack
/**
* @see FastItemStack.wrap
*/
fun ItemStack.fast(): FastItemStack =
FastItemStack.wrap(this)

View File

@@ -0,0 +1,105 @@
@file:JvmName("GUIHelperExtensions")
package com.willfp.eco.core.gui
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.menu.MenuBuilder
import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.core.gui.slot.SlotBuilder
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.inventory.ItemStack
/**
* @see SlotBuilder.onLeftClick
*/
fun SlotBuilder.onLeftClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onLeftClick { a, b, c -> action(a, b, c) }
/**
* @see SlotBuilder.onRightClick
*/
fun SlotBuilder.onRightClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onRightClick { a, b, c -> action(a, b, c) }
/**
* @see SlotBuilder.onShiftLeftClick
*/
fun SlotBuilder.onShiftLeftClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onShiftLeftClick { a, b, c -> action(a, b, c) }
/**
* @see SlotBuilder.onShiftRightClick
*/
fun SlotBuilder.onShiftRightClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onShiftRightClick { a, b, c -> action(a, b, c) }
/**
* @see SlotBuilder.onShiftRightClick
*/
fun SlotBuilder.onMiddleClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onMiddleClick { a, b, c -> action(a, b, c) }
/**
* @see SlotBuilder.setModifier
* @deprecated Use SlotUpdater instead.
*/
@Deprecated("Use SlotUpdater instead")
@Suppress("DEPRECATION")
fun SlotBuilder.setModifier(action: (Player, Menu, ItemStack) -> Unit): SlotBuilder =
this.setUpdater { a, b, c -> c.apply { action(a, b, c) } }
/**
* @see SlotBuilder.setUpdater
*/
fun SlotBuilder.setUpdater(action: (Player, Menu, ItemStack) -> ItemStack): SlotBuilder =
this.setUpdater { a, b, c -> action(a, b, c) }
/**
* Kotlin builder for slots.
*/
fun slot(
item: ItemStack,
init: SlotBuilder.() -> Unit
): Slot {
val builder = Slot.builder(item)
init(builder)
return builder.build()
}
/**
* Kotlin builder for slots.
*/
fun slot(
provider: (Player, Menu) -> ItemStack,
init: SlotBuilder.() -> Unit
): Slot {
val builder = Slot.builder { a, b -> provider(a, b) }
init(builder)
return builder.build()
}
/**
* @see MenuBuilder.onClose
*/
fun MenuBuilder.onClose(action: (InventoryCloseEvent, Menu) -> Unit): MenuBuilder =
this.onClose { a, b -> action(a, b) }
/**
* @see MenuBuilder.modify
*/
fun MenuBuilder.modify(modifier: (MenuBuilder) -> Unit): MenuBuilder =
this.modfiy { modifier(it) }
/**
* Kotlin builder for menus.
*/
fun menu(
rows: Int,
init: MenuBuilder.() -> Unit
): Menu {
val builder = Menu.builder(rows)
init(builder)
return builder.build()
}

View File

@@ -0,0 +1,12 @@
@file:JvmName("ArrowUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.entity.Arrow
import org.bukkit.inventory.ItemStack
/**
* @see ArrowUtils.getBow
*/
val Arrow.bow: ItemStack?
get() = ArrowUtils.getBow(this)

View File

@@ -0,0 +1,11 @@
@file:JvmName("BlockUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.block.Block
/**
* @see ArrowUtils.getBow
*/
val Block.isPlayerPlaced: Boolean
get() = BlockUtils.isPlayerPlaced(this)

View File

@@ -0,0 +1,18 @@
@file:JvmName("DurabilityUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
/**
* @see DurabilityUtils.damageItem
*/
fun ItemStack.damage(damage: Int) =
DurabilityUtils.damageItem(this, damage)
/**
* @see DurabilityUtils.damageItem
*/
fun ItemStack.damage(damage: Int, player: Player) =
DurabilityUtils.damageItem(player, this, damage)

View File

@@ -0,0 +1,21 @@
@file:JvmName("ListUtilsExtensions")
package com.willfp.eco.util
/**
* @see ListUtils.listToFrequencyMap
*/
fun <T> List<T>.toFrequencyMap(): Map<T, Int> =
ListUtils.listToFrequencyMap(this)
/**
* @see ListUtils.containsIgnoreCase
*/
fun Iterable<String>.containsIgnoreCase(element: String): Boolean =
ListUtils.containsIgnoreCase(this, element)
/**
* @see ListUtils.create2DList
*/
fun <T> create2DList(rows: Int, columns: Int): MutableList<MutableList<T>> =
ListUtils.create2DList(rows, columns)

View File

@@ -0,0 +1,29 @@
@file:JvmName("NamespacedKeyUtilsExtensions")
package com.willfp.eco.util
import com.willfp.eco.core.EcoPlugin
/**
* @see NamespacedKeyUtils.fromString
*/
fun namespacedKeyOf(string: String) =
NamespacedKeyUtils.fromString(string)
/**
* @see NamespacedKeyUtils.fromString
*/
fun safeNamespacedKeyOf(string: String) =
NamespacedKeyUtils.fromStringOrNull(string)
/**
* @see NamespacedKeyUtils.create
*/
fun namespacedKeyOf(namespace: String, key: String) =
NamespacedKeyUtils.create(namespace, key)
/**
* @see EcoPlugin.namespacedKeyFactory
*/
fun namespacedKeyOf(plugin: EcoPlugin, key: String) =
plugin.namespacedKeyFactory.create(key)

View File

@@ -0,0 +1,9 @@
@file:JvmName("NumberUtilsExtensions")
package com.willfp.eco.util
/**
* @see NumberUtils.toNumeral
*/
fun Number.toNumeral(): String =
NumberUtils.toNumeral(this.toInt())

View File

@@ -0,0 +1,32 @@
@file:JvmName("PlayerUtilsExtensions")
package com.willfp.eco.util
import net.kyori.adventure.audience.Audience
import org.bukkit.OfflinePlayer
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
/**
* @see PlayerUtils.getSavedDisplayName
*/
val OfflinePlayer.savedDisplayName: String
get() = PlayerUtils.getSavedDisplayName(this)
/**
* @see PlayerUtils.getAudience
*/
fun Player.asAudience(): Audience =
PlayerUtils.getAudience(this)
/**
* @see PlayerUtils.getAudience
*/
fun CommandSender.asAudience(): Audience =
PlayerUtils.getAudience(this)
/**
* @see PlayerUtils.runExempted
*/
fun Player.runExempted(action: () -> Unit) =
PlayerUtils.runExempted(this, action)

View File

@@ -0,0 +1,11 @@
@file:JvmName("PotionUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.potion.PotionData
/**
* @see PotionData.duration
*/
val PotionData.duration: Int
get() = PotionUtils.getDuration(this)

View File

@@ -0,0 +1,11 @@
@file:JvmName("ServerUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.Server
/**
* @see ServerUtils.getTps
*/
val Server.tps: Double
get() = ServerUtils.getTps()

View File

@@ -0,0 +1,17 @@
@file:JvmName("SkullUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.inventory.meta.SkullMeta
/**
* @see SkullUtils.getSkullTexture
* @see SkullUtils.setSkullTexture
*/
var SkullMeta.texture: String?
get() = SkullUtils.getSkullTexture(this)
set(value) {
if (value != null) {
SkullUtils.setSkullTexture(this, value)
}
}

View File

@@ -0,0 +1,42 @@
@file:JvmName("StringUtilsExtensions")
package com.willfp.eco.util
import net.kyori.adventure.text.Component
import org.bukkit.entity.Player
/**
* @see StringUtils.toComponent
*/
fun String.toComponent(): Component =
StringUtils.toComponent(this)
/**
* @see StringUtils.toLegacy
*/
fun Component.toLegacy(): String =
StringUtils.toLegacy(this)
/**
* @see StringUtils.format
*/
fun String.formatEco(
player: Player? = null,
formatPlaceholders: Boolean = false
) = StringUtils.format(
this,
player,
if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS
)
/**
* @see StringUtils.formatList
*/
fun List<String>.formatEco(
player: Player? = null,
formatPlaceholders: Boolean = false
): List<String> = StringUtils.formatList(
this,
player,
if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS
)

View File

@@ -0,0 +1,17 @@
@file:JvmName("VectorUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.util.Vector
/**
* @see VectorUtils.isFinite
*/
val Vector.isFinite: Boolean
get() = VectorUtils.isFinite(this)
/**
* @see VectorUtils.simplifyVector
*/
fun Vector.simplify(): Vector =
VectorUtils.simplifyVector(this)

View File

@@ -1,29 +1,8 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0"
}
}
group 'com.willfp'
version rootProject.version
subprojects {
apply plugin: "kotlin"
dependencies {
compileOnly project(":eco-api")
compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.6.0'
}
compileKotlin {
kotlinOptions {
jvmTarget = "17"
}
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_17
}
}
}

View File

@@ -7,5 +7,5 @@ dependencies {
compileOnly 'org.reflections:reflections:0.9.12'
compileOnly 'net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT'
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0'
compileOnly 'com.google.guava:guava:31.0.1-jre'
compileOnly 'org.objenesis:objenesis:3.2'
}

View File

@@ -0,0 +1,35 @@
package com.willfp.eco.internal
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.PluginProps
import com.willfp.eco.core.config.TransientConfig
import com.willfp.eco.core.config.interfaces.Config
object EcoPropsParser : PluginProps.PropsParser<Config> {
override fun parseFrom(config: Config): PluginProps {
val resourceId = config.getIntOrNull("resource-id") ?: 0
val bStatsId = config.getIntOrNull("bstats-id") ?: 0
val proxyPackage = config.getStringOrNull("proxy-package") ?: ""
val color = config.getStringOrNull("color") ?: "&f"
val supportsExtensions = config.getBoolOrNull("supports-extensions") ?: false
return blankProps.apply {
this.resourceId = resourceId
this.bStatsId = bStatsId
this.proxyPackage = proxyPackage
this.color = color
this.isSupportingExtensions = supportsExtensions
}
}
fun parseForPlugin(plugin: Class<out EcoPlugin>): PluginProps {
if (!PluginProps.hasParserFor(Config::class.java)) {
PluginProps.registerParser(Config::class.java, this)
}
return PluginProps.parse(
TransientConfig(plugin.getResourceAsStream("/eco.yml")),
Config::class.java
)
}
}

View File

@@ -15,7 +15,7 @@ import com.willfp.eco.internal.config.yaml.EcoYamlConfigSection
import org.bukkit.configuration.file.YamlConfiguration
import java.io.StringReader
class EcoConfigFactory : ConfigFactory {
object EcoConfigFactory : ConfigFactory {
override fun createConfig(config: YamlConfiguration): Config {
return EcoYamlConfigSection(config)
}

View File

@@ -24,11 +24,7 @@ open class EcoLoadableJSONConfig(
private val name: String = "$configName.json"
fun reloadFromFile() {
try {
init(configFile)
} catch (e: IOException) {
e.printStackTrace()
}
runCatching { init(configFile) }.onFailure { it.printStackTrace() }
}
final override fun createFile() {
@@ -94,11 +90,7 @@ open class EcoLoadableJSONConfig(
createFile()
}
configFile = File(directory, name)
try {
init(configFile)
} catch (e: IOException) {
e.printStackTrace()
}
init(configFile)
plugin.configHandler.addConfig(this)
}
}

View File

@@ -1,10 +1,8 @@
package com.willfp.eco.internal.config.json
import com.willfp.eco.core.PluginLike
import org.bukkit.configuration.InvalidConfigurationException
import org.bukkit.configuration.file.YamlConfiguration
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
@@ -21,48 +19,36 @@ open class EcoUpdatableJSONConfig(
fun update() {
super.clearCache()
try {
this.init(configFile)
val newConfig = configInJar
if (newConfig.getKeys(true) == this.getKeys(true)) {
return
}
newConfig.getKeys(true).forEach { key: String ->
if (!this.getKeys(true).contains(key)) {
if (updateBlacklist.stream().noneMatch { s: String -> key.contains(s) }) {
this.set(key, newConfig[key])
}
}
}
if (removeUnused) {
this.getKeys(true).forEach { s ->
if (!newConfig.getKeys(true).contains(s)) {
if (updateBlacklist.stream().noneMatch(s::contains)) {
this.set(s, null)
}
}
}
}
this.save()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InvalidConfigurationException) {
e.printStackTrace()
this.init(configFile)
val newConfig = configInJar ?: return
if (newConfig.getKeys(true) == this.getKeys(true)) {
return
}
newConfig.getKeys(true).forEach { key: String ->
if (!this.getKeys(true).contains(key)) {
if (updateBlacklist.stream().noneMatch { s: String -> key.contains(s) }) {
this.set(key, newConfig[key])
}
}
}
if (removeUnused) {
this.getKeys(true).forEach { s ->
if (!newConfig.getKeys(true).contains(s)) {
if (updateBlacklist.stream().noneMatch(s::contains)) {
this.set(s, null)
}
}
}
}
this.save()
}
private val configInJar: YamlConfiguration
private val configInJar: YamlConfiguration?
get() {
val newIn = this.source.getResourceAsStream(resourcePath) ?: throw NullPointerException("$name is null?")
val newIn = this.source.getResourceAsStream(resourcePath) ?: return null
val reader = BufferedReader(InputStreamReader(newIn, StandardCharsets.UTF_8))
val newConfig = YamlConfiguration()
try {
newConfig.load(reader)
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InvalidConfigurationException) {
e.printStackTrace()
}
newConfig.load(reader)
return newConfig
}

View File

@@ -24,15 +24,15 @@ class EcoConfigHandler(
override fun callUpdate() {
for (method in reflections.getMethodsAnnotatedWith(ConfigUpdater::class.java)) {
try {
kotlin.runCatching {
when (method.parameterCount) {
0 -> method.invoke(null)
1 -> method.invoke(null, this.plugin)
else -> throw InvalidUpdateMethodException("Update method must have 0 parameters or a plugin parameter.")
}
} catch (e: ReflectiveOperationException) {
e.printStackTrace()
throw InvalidUpdateMethodException("Update method generated an exception")
}.onFailure {
it.printStackTrace()
plugin.logger.severe("Update method ${method.toGenericString()} generated an exception")
}
}
}

View File

@@ -5,7 +5,6 @@ package com.willfp.eco.internal.config.yaml
import com.willfp.eco.core.PluginLike
import com.willfp.eco.core.config.interfaces.LoadableConfig
import com.willfp.eco.core.config.interfaces.WrappedYamlConfiguration
import org.bukkit.configuration.InvalidConfigurationException
import org.bukkit.configuration.file.YamlConfiguration
import java.io.File
import java.io.FileOutputStream
@@ -23,13 +22,7 @@ open class EcoLoadableYamlConfig(
private val name: String = "$configName.yml"
fun reloadFromFile() {
try {
handle.load(getConfigFile())
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InvalidConfigurationException) {
e.printStackTrace()
}
handle.load(getConfigFile())
}
final override fun createFile() {

View File

@@ -1,10 +1,8 @@
package com.willfp.eco.internal.config.yaml
import com.willfp.eco.core.PluginLike
import org.bukkit.configuration.InvalidConfigurationException
import org.bukkit.configuration.file.YamlConfiguration
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
@@ -21,48 +19,36 @@ class EcoUpdatableYamlConfig(
fun update() {
super.clearCache()
try {
this.handle.load(configFile)
val newConfig = configInJar
if (newConfig.getKeys(true) == this.handle.getKeys(true)) {
return
}
newConfig.getKeys(true).forEach { key ->
if (!this.handle.getKeys(true).contains(key)) {
if (updateBlacklist.stream().noneMatch { key.contains(it) }) {
this.handle.set(key, newConfig[key])
}
}
}
if (removeUnused) {
this.handle.getKeys(true).forEach { s ->
if (!newConfig.getKeys(true).contains(s)) {
if (updateBlacklist.stream().noneMatch(s::contains)) {
this.handle.set(s, null)
}
}
}
}
this.handle.save(configFile)
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InvalidConfigurationException) {
e.printStackTrace()
this.handle.load(configFile)
val newConfig = configInJar ?: return
if (newConfig.getKeys(true) == this.handle.getKeys(true)) {
return
}
newConfig.getKeys(true).forEach { key ->
if (!this.handle.getKeys(true).contains(key)) {
if (updateBlacklist.stream().noneMatch { key.contains(it) }) {
this.handle.set(key, newConfig[key])
}
}
}
if (removeUnused) {
this.handle.getKeys(true).forEach { s ->
if (!newConfig.getKeys(true).contains(s)) {
if (updateBlacklist.stream().noneMatch(s::contains)) {
this.handle.set(s, null)
}
}
}
}
this.handle.save(configFile)
}
private val configInJar: YamlConfiguration
private val configInJar: YamlConfiguration?
get() {
val newIn = source.getResourceAsStream(resourcePath) ?: throw NullPointerException("$name is null?")
val newIn = source.getResourceAsStream(resourcePath) ?: return null
val reader = BufferedReader(InputStreamReader(newIn, StandardCharsets.UTF_8))
val newConfig = YamlConfiguration()
try {
newConfig.load(reader)
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InvalidConfigurationException) {
e.printStackTrace()
}
newConfig.load(reader)
return newConfig
}

View File

@@ -5,7 +5,7 @@ import com.willfp.eco.core.display.Display
import com.willfp.eco.core.display.DisplayHandler
import com.willfp.eco.core.display.DisplayModule
import com.willfp.eco.core.display.DisplayPriority
import com.willfp.eco.core.fast.FastItemStack
import com.willfp.eco.core.fast.fast
import org.bukkit.NamespacedKey
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
@@ -60,7 +60,7 @@ class EcoDisplayHandler(plugin: EcoPlugin) : DisplayHandler {
Display.unfinalize(itemStack)
}
val fast = FastItemStack.wrap(itemStack)
val fast = itemStack.fast()
val lore = fast.lore
if (lore.isNotEmpty() && lore.removeIf { line: String ->

View File

@@ -10,7 +10,6 @@ import org.bukkit.Material
import org.bukkit.entity.EntityType
import org.bukkit.entity.ExperienceOrb
import org.bukkit.entity.Player
import org.bukkit.event.player.PlayerExpChangeEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.util.Vector
@@ -73,12 +72,10 @@ open class EcoDropQueue(val player: Player) : InternalDropQueue {
world.dropItem(location, drop!!).velocity = Vector()
}
if (xp > 0) {
val event = PlayerExpChangeEvent(player, xp)
Bukkit.getPluginManager().callEvent(event)
val orb =
world.spawnEntity(player.location.add(0.0, 0.2, 0.0), EntityType.EXPERIENCE_ORB) as ExperienceOrb
orb.velocity = Vector(0, 0, 0)
orb.experience = event.amount
orb.experience = xp
}
} else {
for (drop in items) {
@@ -94,4 +91,4 @@ open class EcoDropQueue(val player: Player) : InternalDropQueue {
init {
location = player.location
}
}
}

View File

@@ -2,7 +2,7 @@ package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.entity.Animals
import org.bukkit.entity.Ageable
class EntityArgParserAdult : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
@@ -20,14 +20,14 @@ class EntityArgParserAdult : EntityArgParser {
return EntityArgParseResult(
{
if (it !is Animals) {
if (it !is Ageable) {
return@EntityArgParseResult false
}
it.isAdult
},
{
(it as? Animals)?.setAdult()
(it as? Ageable)?.setAdult()
}
)
}

View File

@@ -2,7 +2,7 @@ package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.entity.Animals
import org.bukkit.entity.Ageable
class EntityArgParserBaby : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
@@ -20,14 +20,14 @@ class EntityArgParserBaby : EntityArgParser {
return EntityArgParseResult(
{
if (it !is Animals) {
if (it !is Ageable) {
return@EntityArgParseResult false
}
!it.isAdult
},
{
(it as? Animals)?.setBaby()
(it as? Ageable)?.setBaby()
}
)
}

View File

@@ -0,0 +1,62 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.TestableItem
import org.bukkit.entity.LivingEntity
import org.bukkit.inventory.EquipmentSlot
class EntityArgParserEquipment : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
val equipment = mutableMapOf<EquipmentSlot, TestableItem>()
for (arg in args) {
val argSplit = arg.split(":")
for (slot in EquipmentSlot.values()) {
if (!argSplit[0].equals(slot.name, ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
equipment[slot] = Items.lookup(argSplit[1])
}
}
if (equipment.isEmpty()) {
return null
}
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
val entityEquipment = it.equipment ?: return@EntityArgParseResult false
for ((slot, item) in equipment) {
if (!item.matches(entityEquipment.getItem(slot))) {
return@EntityArgParseResult false
}
}
return@EntityArgParseResult true
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
val entityEquipment = it.equipment ?: return@EntityArgParseResult
for ((slot, item) in equipment) {
entityEquipment.setItem(slot, item.item, false)
}
}
)
}
}

View File

@@ -0,0 +1,29 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
class EntityArgParserSilent : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var silent = false
for (arg in args) {
if (arg.equals("silent", true)) {
silent = true
}
}
if (!silent) {
return null
}
return EntityArgParseResult(
{
it.isSilent
},
{
it.isSilent = true
}
)
}
}

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.internal.extensions
import com.google.common.collect.ImmutableSet
import com.willfp.eco.core.Eco
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.config.TransientConfig
import com.willfp.eco.core.extensions.Extension
@@ -10,8 +11,6 @@ import com.willfp.eco.core.extensions.MalformedExtensionException
import org.bukkit.configuration.file.YamlConfiguration
import java.io.File
import java.io.InputStreamReader
import java.net.MalformedURLException
import java.net.URL
import java.net.URLClassLoader
class EcoExtensionLoader(
@@ -32,23 +31,18 @@ class EcoExtensionLoader(
continue
}
try {
loadExtension(extensionJar)
} catch (e: MalformedExtensionException) {
runCatching { loadExtension(extensionJar) }.onFailure {
this.plugin.logger.warning(extensionJar.name + " caused an error!")
if (Eco.getHandler().ecoPlugin.configYml.getBool("log-full-extension-errors")) {
it.printStackTrace()
}
}
}
}
@Throws(MalformedExtensionException::class)
private fun loadExtension(extensionJar: File) {
lateinit var url: URL
try {
url = extensionJar.toURI().toURL()
} catch (e: MalformedURLException) {
e.printStackTrace()
}
val url = extensionJar.toURI().toURL()
val classLoader = URLClassLoader(arrayOf(url), this.plugin::class.java.classLoader)
val ymlIn = classLoader.getResourceAsStream("extension.yml")

View File

@@ -2,10 +2,11 @@ package com.willfp.eco.internal.factory
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.factory.NamespacedKeyFactory
import com.willfp.eco.util.NamespacedKeyUtils
import org.bukkit.NamespacedKey
class EcoNamespacedKeyFactory(private val plugin: EcoPlugin) : NamespacedKeyFactory {
override fun create(key: String): NamespacedKey {
return NamespacedKey(plugin, key)
return NamespacedKeyUtils.create(plugin.name, key)
}
}

Some files were not shown because too many files have changed in this diff Show More