Compare commits

..

234 Commits

Author SHA1 Message Date
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
Auxilor
8635e5f7a5 Updated to 6.18.5 2022-01-11 10:01:49 +00:00
Auxilor
aa718649eb Fixed v1_18_R1 remapping bugs 2022-01-11 10:01:40 +00:00
Auxilor
1dc0fa449b Updated to 6.18.4 2022-01-11 09:20:52 +00:00
Auxilor
19e3061a13 Fixed MythicMobs NPE 2022-01-11 09:20:43 +00:00
Auxilor
ecafbd76de Updated to 6.18.3 2022-01-10 11:11:44 +00:00
Auxilor
3728f2fc7a Fixed apache commons lang not existing on classpath 2022-01-10 11:11:31 +00:00
Auxilor
56c124dbd2 Updated to 6.18.2 2022-01-09 18:19:29 +00:00
Auxilor
6730697fc5 Merge branch 'develop' 2022-01-09 18:19:15 +00:00
Auxilor
c8e1c83061 Merge remote-tracking branch 'origin/master' 2022-01-09 18:19:07 +00:00
Auxilor
a9fd5a9418 Merge remote-tracking branch 'origin/develop'
# Conflicts:
#	gradle.properties
2022-01-09 18:19:00 +00:00
Auxilor
7b1179f402 Fixed string getter for multiple-in-craft 2022-01-09 18:18:44 +00:00
Auxilor
f4907329d9 Updated to 6.18.2 2022-01-07 10:38:41 +00:00
Auxilor
1e23cbaa5e Fixed SuperiorSkyblockAPI build isseus 2022-01-07 10:38:09 +00:00
Auxilor
863818d2eb Fixed NoAI arg parser 2022-01-07 10:05:00 +00:00
Auxilor
d35285d0dc More config simplification 2022-01-07 09:26:06 +00:00
Auxilor
bc92f8a444 Added destructurability to EntityArgParseResult 2022-01-07 09:24:02 +00:00
Auxilor
2fafef17d7 Simplified internal config implementations 2022-01-07 09:22:32 +00:00
Auxilor
24078a2838 Merge remote-tracking branch 'origin/develop' into develop 2022-01-07 09:01:19 +00:00
Auxilor
73d13277be Made update checker less annoyign 2022-01-06 18:34:44 +00:00
Auxilor
0e4c23d70c Fixed potential remapping bugs 2022-01-06 18:21:51 +00:00
Auxilor
ddf5094c5a Added MythicMobs softdepend 2022-01-06 16:13:36 +00:00
Auxilor
925fc56cab MythicMobs integration uses apiHelper where possible 2022-01-06 16:13:17 +00:00
Auxilor
3208d0328f Added EmptyTestableEntity (dummy entities) for failed TestableEntity lookups 2022-01-06 16:05:10 +00:00
Auxilor
317824ae78 Removed broken test 2022-01-06 15:17:06 +00:00
Auxilor
41a4b4fc1a Scheduled old java arg parsers for removal in the next release 2022-01-06 15:01:36 +00:00
Auxilor
c528e4cd42 Referencing for-removal arg parsers at all will now log an error 2022-01-06 15:00:31 +00:00
Auxilor
2724f21d4e Referencing for-removal arg parsers at all will now log an error 2022-01-06 14:59:39 +00:00
Auxilor
5cb14e31b7 Finally updated Config string getters to not be formatted by default 2022-01-06 14:51:55 +00:00
Auxilor
6b9942f412 Updated to 6.18.0 2022-01-06 14:32:46 +00:00
Auxilor
fbe88ab0fd Added MythicMobs integration 2022-01-06 14:31:02 +00:00
Auxilor
d042211dbe Added Charged and Explosion radius arg parsers, fixed size arg parser 2022-01-06 14:10:20 +00:00
Auxilor
5781df011e Added adult arg parser 2022-01-06 14:03:59 +00:00
Auxilor
c191ff0767 Added baby arg parser 2022-01-06 14:03:06 +00:00
Auxilor
b9cbcbe7a0 Added Entity lookup system, TestableEntity, CustomEntity 2022-01-06 13:55:03 +00:00
Auxilor
6009122c48 Removed underscores from name arg parsers 2022-01-06 12:11:27 +00:00
Auxilor
7536794100 Added quote support to lookup strings (for names) 2022-01-06 12:05:38 +00:00
Auxilor
e80aa5f910 Added substrings (escaped with "") to arg parsers for cleaner syntax 2022-01-06 10:46:35 +00:00
Auxilor
b4aeeac570 Added tree growth to PlayerBlockListener.kt 2022-01-05 16:22:52 +00:00
Auxilor
33515aa5f7 Updated to 6.17.7 2022-01-05 13:44:47 +00:00
Auxilor
047b535a40 Merge remote-tracking branch 'origin/master' into develop 2022-01-05 13:44:22 +00:00
Auxilor
ef8093ec7f Updated to 6.17.6 2022-01-05 13:42:24 +00:00
Auxilor
9d0f95617d Fixed CrashClaim integration 2022-01-05 13:42:14 +00:00
Auxilor
b4f3988fc7 Updated to 6.17.7 2022-01-02 17:37:34 +00:00
Auxilor
e7e1751acc Disabled CrashClaim 2022-01-02 17:37:24 +00:00
Auxilor
e68d482aa5 Disabled CrashClaim 2022-01-02 17:37:19 +00:00
often
c0547a7c34 Readded and fixed CustomItems support, added ExecutableItems support 2022-01-02 13:19:35 +03:00
Auxilor
183b18c0ec Updated to 6.17.6 2021-12-29 18:47:44 +00:00
Auxilor
e026a767d9 Fixed v1_18_R1 bugs 2021-12-29 18:47:33 +00:00
Auxilor
d2966aa428 Updated to 6.17.5 2021-12-26 17:21:21 +00:00
Auxilor
9168e68b5a StringUtils#jsonToLegacy will now fail silently 2021-12-26 17:21:01 +00:00
Auxilor
51a61b65c6 Updated to 6.17.4 2021-12-26 16:57:54 +00:00
Auxilor
76be236dac Error catching to StringUtils#jsonToLegacy 2021-12-26 16:56:53 +00:00
Auxilor
f1bbac2dd0 Codestyle 2021-12-26 16:48:03 +00:00
Auxilor
6e88aef572 FastItemStack#getLore changes 2021-12-26 16:40:09 +00:00
Auxilor
804f187964 legacy <-> json changes 2021-12-26 16:34:52 +00:00
Auxilor
623b8a18f4 Codestyle 2021-12-26 16:20:38 +00:00
Auxilor
0d4e424582 Codestyle 2021-12-26 16:19:59 +00:00
Auxilor
452e499467 Added NumberUtils#logBase 2021-12-26 16:10:33 +00:00
Auxilor
b2950ab035 Added ListUtils#containsIgnoreCase 2021-12-26 12:53:57 +00:00
Auxilor
e47d05ccb2 NMS changes 2021-12-26 12:23:13 +00:00
Auxilor
b9e61b8c0d Merged v1_18_R1 thanks to paperweight update 2021-12-26 12:17:02 +00:00
Auxilor
0f35d5d16e Updated to 6.17.3 2021-12-21 12:20:33 +00:00
Stealth2800
3a7315d728 Make defensive copy of CustomItem's returned item 2021-12-20 20:24:21 -08:00
Auxilor
6f193f70b0 Staggered player profile loading to load when needed 2021-12-15 12:26:20 +00:00
Auxilor
bab3f078f6 Added @JvmStatic mention to @ConfigUpdater 2021-12-15 11:28:07 +00:00
Auxilor
5b4b17b97f Updated to 6.17.2 2021-12-15 10:31:16 +00:00
Auxilor
f0e02ca25e Added HikariCP to plugin.yml 2021-12-15 10:31:05 +00:00
Auxilor
7426e9adba Updated to use hikari 2021-12-15 10:30:49 +00:00
Auxilor
00905aa9d5 Updated to 6.17.1 2021-12-14 19:09:50 +00:00
Auxilor
f7b57880cb Switched essentials dependency 2021-12-14 19:09:38 +00:00
Auxilor
c1b673e30c Fixed config.yml bug 2021-12-14 08:51:33 +00:00
Auxilor
4cf45795d6 Clarified forRemoval 2021-12-14 08:40:58 +00:00
Auxilor
59d31584e6 Generalized ConfigYml into LoadableConfig for custom implementations 2021-12-14 08:38:51 +00:00
Auxilor
68e1f4afac Added piston moving / retracting support to BlockUtils#isPlayerPlaced 2021-12-14 08:30:34 +00:00
Auxilor
507fad186a Improved PlayerJumpEvent on paper 2021-12-13 13:00:05 +00:00
Auxilor
ca6b3185a3 Fixed legacy configs not having 100% parity 2021-12-13 12:56:22 +00:00
Auxilor
8e96329fdc Fixed ConfigWrapper constructor access 2021-12-13 12:24:12 +00:00
Auxilor
440605f636 Re-made ConfigWrapper abstract 2021-12-13 12:24:01 +00:00
Auxilor
bb686dca17 Config refactor 2021-12-13 12:23:41 +00:00
Auxilor
e595ea2247 Marked AbstractProxy for removal 2021-12-13 12:09:58 +00:00
Auxilor
a776b60f86 Deprecated AbstractProxy 2021-12-13 12:05:49 +00:00
Auxilor
db7ac55eb2 Minor codestyle changes 2021-12-13 11:49:46 +00:00
Auxilor
52d77d7861 Added TestableItem support to ItemStackBuilder 2021-12-13 11:43:36 +00:00
Auxilor
f8ece2d6c7 @NotNull to Handler#getPlayerProfileHandler 2021-12-13 11:35:46 +00:00
Auxilor
b353b5ec04 More javadoc 2021-12-13 10:45:33 +00:00
Auxilor
bbc412e589 Added ListUtils#getOrNull 2021-12-13 10:08:46 +00:00
Auxilor
b4a474c703 Integration / Scheduling changes 2021-12-13 09:59:33 +00:00
Auxilor
75e6a3da79 Documentation and visibility changes 2021-12-13 09:54:39 +00:00
Auxilor
a1afffdbbb Added since to deprecation 2021-12-13 09:35:55 +00:00
Auxilor
f6942192de Added since to deprecation 2021-12-12 15:52:39 +00:00
Auxilor
dab26cbe95 Deprecation changes and warnings 2021-12-12 15:47:46 +00:00
Auxilor
b945a3f948 Improved deprecation javadoc 2021-12-12 15:43:25 +00:00
Auxilor
b2c1d650de Removed DeprecatedIsStillUsed suppressions 2021-12-12 14:21:23 +00:00
Auxilor
4b994d5f4c Fixed javadoc 2021-12-12 14:04:53 +00:00
Auxilor
ed2dffb52c Fixed internal use of YamlBaseConfig 2021-12-12 14:04:21 +00:00
Auxilor
20c870da06 Fixed internal use of deprecated config class 2021-12-12 14:01:28 +00:00
Auxilor
7684e431f5 Even more config parity fixes 2021-12-12 13:58:53 +00:00
Auxilor
abcc13685f Fixed config parity bugs 2021-12-12 13:55:15 +00:00
Auxilor
ac902eaa08 Overhauled config system 2021-12-12 13:44:58 +00:00
Auxilor
4e52913504 Javadoc 2021-12-12 12:47:37 +00:00
Auxilor
7505f7732f Merge remote-tracking branch 'origin/dependabot/gradle/com.github.johnrengelman.shadow-7.1.0' into develop 2021-12-12 12:43:40 +00:00
Auxilor
15fae21fd5 Merge remote-tracking branch 'origin/dependabot/gradle/com.massivecraft-Factions-1.6.9.5-2.7.0-STABLE' into develop 2021-12-12 12:43:36 +00:00
Auxilor
e9d98816ce Merge remote-tracking branch 'origin/dependabot/gradle/org.junit.jupiter-junit-jupiter-api-5.8.2' into develop
# Conflicts:
#	build.gradle.kts
2021-12-12 12:43:32 +00:00
Auxilor
675fc07ebf Merge remote-tracking branch 'origin/dependabot/gradle/org.junit.jupiter-junit-jupiter-engine-5.8.2' into develop 2021-12-12 12:43:11 +00:00
Auxilor
b8b8fd70b5 Javadoc 2021-12-12 12:42:16 +00:00
Auxilor
1d9fca1fb8 Added permissions to recipes 2021-12-12 12:38:04 +00:00
Auxilor
9b83f6eab4 Added ListUtils#toSingletonList 2021-12-12 12:17:45 +00:00
Auxilor
8190660b8f Removed redundant suppression 2021-12-12 12:14:50 +00:00
Auxilor
cbf4d111fb More dev niceties 2021-12-12 12:14:24 +00:00
Auxilor
6a139bef67 Kotlin-friendliness 2021-12-12 12:09:12 +00:00
Auxilor
9e3fecfd13 Updated to 6.17.0 2021-12-12 12:00:20 +00:00
Auxilor
3b260e2e5d Improved command system 2021-12-12 12:00:09 +00:00
Auxilor
0c0370e256 Updated to 6.16.2 2021-12-08 20:47:22 +00:00
Auxilor
227b748f85 Fixed bStats issues 2021-12-08 20:46:26 +00:00
Auxilor
c8382bd8cf Updated to 6.16.1 2021-12-08 20:40:59 +00:00
Auxilor
df22768367 Fixed bugs 2021-12-08 20:40:39 +00:00
Auxilor
00ea3506ca config.yml changes 2021-12-08 20:32:55 +00:00
Auxilor
521659cfec bStats changes 2021-12-08 20:32:31 +00:00
Auxilor
bbe5f1eba4 Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	eco-core/core-plugin/build.gradle
2021-12-08 20:24:07 +00:00
dependabot[bot]
3d4c33860a Bump junit-jupiter-engine from 5.8.1 to 5.8.2
Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.8.1 to 5.8.2.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.8.1...r5.8.2)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter-engine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-08 20:18:37 +00:00
Auxilor
eae5d29f8d Downgraded bStats 2021-12-08 20:16:59 +00:00
Auxilor
c878d6fd12 Implemented stipped-down bStats directly (recoded in kotlin) 2021-12-08 16:08:03 +00:00
Auxilor
2b97c0072f Downgraded bStats 2021-12-08 14:18:24 +00:00
Auxilor
63079df745 Removed explicit buffer size 2021-12-08 12:41:24 +00:00
Auxilor
079b41e877 Switched to old config behavior 2021-12-08 12:40:13 +00:00
Auxilor
1aaab459d8 Updated bStats to 2.2.1 2021-12-08 12:34:38 +00:00
Auxilor
db78c2eb4c Fixed javadoc + codestyle 2021-12-08 12:22:51 +00:00
Auxilor
02fd07b3c8 Fixed shadowed name 2021-12-08 12:17:22 +00:00
Auxilor
3de2e53031 Fixed default captive items bug 2021-12-08 11:27:33 +00:00
Auxilor
cb088bb70b Allowed specifiying default captive items 2021-12-08 11:23:23 +00:00
Auxilor
36fca7016f Fixed ArgParserEnchantment never returning null 2021-12-08 11:11:59 +00:00
Auxilor
7e1137da06 Cleaned up SS2 integration 2021-12-08 10:53:16 +00:00
Auxilor
0da104d614 Added color:#fffff support x 2021-12-08 10:51:25 +00:00
Auxilor
9095de7d19 Updated to 6.16.0 2021-12-08 10:50:36 +00:00
Auxilor
7a8abac1a2 Pull Request Fixes / Changes, config changes 2021-12-08 10:50:12 +00:00
0ft3n
1ddcb6e964 Merge branch 'master' into master 2021-12-07 14:11:40 +03:00
_OfTeN_
4d0858ad84 Added AntigriefManager#canPickupItem and created and implemented DropQueuePushEvent event 2021-12-07 14:08:04 +03:00
_OfTeN_
3d05695a36 Added Items#getItem 2021-12-07 13:30:36 +03:00
Auxilor
d676be15ce Grammar 2021-12-06 13:46:27 +00:00
Auxilor
16848caec1 Fixed grammar errors 2021-12-06 13:08:45 +00:00
Auxilor
ef26fe4629 Removed legacy arg parser method bodies 2021-12-06 13:06:22 +00:00
Auxilor
29fbd785d7 Added ArgParserName 2021-12-06 12:54:28 +00:00
Auxilor
8c73676ee0 Added ArgParserUnbreakable 2021-12-06 12:50:26 +00:00
Auxilor
ebf27d28d9 Updated to 6.15.2 2021-12-06 12:49:10 +00:00
Auxilor
317bc13f65 Moved arg parsers to internals and added ArgParserFlag 2021-12-06 12:49:00 +00:00
Auxilor
b8ec0ee6fc Updated to 6.15.1 2021-12-06 10:14:14 +00:00
Auxilor
307e57c902 Display frame changes with PacketHeldWindowItems 2021-12-06 10:13:29 +00:00
Auxilor
db0d55659f Empty transient config 2021-12-06 10:10:35 +00:00
Auxilor
548529feb3 Javadoc formatting 2021-12-06 10:09:52 +00:00
Auxilor
fb56baf452 Fixed class-cast error 2021-12-06 10:02:24 +00:00
Auxilor
5d18b424d7 Added ColorArgParser 2021-12-04 15:37:29 +00:00
Auxilor
7be9a1bd10 Fixed EcoYamlConfigWrapper cast issues 2021-12-03 20:59:07 +00:00
Auxilor
97c39b56dd Updated to 6.15.0 2021-12-03 20:23:25 +00:00
_OfTeN_
3a9f5bc139 Added support for DecentHolograms 2021-12-03 21:10:40 +03:00
Auxilor
1e5955f249 Codestyle fixes 2021-12-03 16:21:47 +00:00
Auxilor
bad076bbe9 Added kotlin.code.style = official 2021-12-03 16:18:53 +00:00
Auxilor
e219b2f33c Config additions 2021-12-03 16:13:37 +00:00
Auxilor
2f7603409e Generic variance 2021-12-03 15:58:41 +00:00
Auxilor
28cdb65176 Added Config#getSubsections 2021-12-03 15:49:00 +00:00
_OfTeN_
03ae9e89b3 Added color:#FFFFFF, color:FFFFFF or color:red,green,blue parser for leather armor color 2021-12-02 23:26:38 +03:00
dependabot[bot]
651426ed76 Bump junit-jupiter-api from 5.8.1 to 5.8.2
Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.8.1 to 5.8.2.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.8.1...r5.8.2)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-30 19:41:43 +00:00
dependabot[bot]
1a49165656 Bump com.github.johnrengelman.shadow from 7.0.0 to 7.1.0
Bumps com.github.johnrengelman.shadow from 7.0.0 to 7.1.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-26 19:13:10 +00:00
dependabot[bot]
a48c3c2fed Bump Factions from 1.6.9.5-U0.5.10 to 1.6.9.5-2.7.0-STABLE
Bumps Factions from 1.6.9.5-U0.5.10 to 1.6.9.5-2.7.0-STABLE.

---
updated-dependencies:
- dependency-name: com.massivecraft:Factions
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-15 21:04:02 +00:00
225 changed files with 5965 additions and 1672 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.

View File

@@ -1,6 +1,6 @@
plugins { plugins {
id("java-library") id("java-library")
id("com.github.johnrengelman.shadow") version "7.0.0" id("com.github.johnrengelman.shadow") version "7.1.0"
id("maven-publish") id("maven-publish")
id("java") id("java")
} }
@@ -12,7 +12,7 @@ dependencies {
implementation(project(":eco-core:core-backend")) implementation(project(":eco-core:core-backend"))
implementation(project(":eco-core:core-nms:v1_16_R3")) 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_17_R1", configuration = "reobf"))
implementation(project(":eco-core:core-nms:v1_18_R1")) implementation(project(path = ":eco-core:core-nms:v1_18_R1", configuration = "reobf"))
} }
allprojects { allprojects {
@@ -35,7 +35,7 @@ allprojects {
// NMS (for jitpack compilation) // NMS (for jitpack compilation)
maven("https://repo.codemc.org/repository/nms/") maven("https://repo.codemc.org/repository/nms/")
// bStats, mcMMO, BentoBox // mcMMO, BentoBox
maven("https://repo.codemc.org/repository/maven-public/") maven("https://repo.codemc.org/repository/maven-public/")
// Spigot API, Bungee API // Spigot API, Bungee API
@@ -61,6 +61,15 @@ allprojects {
// IridiumSkyblock // IridiumSkyblock
maven("https://nexus.iridiumdevelopment.net/repository/maven-releases/") maven("https://nexus.iridiumdevelopment.net/repository/maven-releases/")
// 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 { dependencies {
@@ -68,12 +77,16 @@ allprojects {
// Test // Test
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1") testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
// Adventure // Adventure
compileOnly("net.kyori:adventure-api:4.9.3") compileOnly("net.kyori:adventure-api:4.9.3")
compileOnly("net.kyori:adventure-text-serializer-gson:4.9.3") compileOnly("net.kyori:adventure-text-serializer-gson:4.9.3")
compileOnly("net.kyori:adventure-text-serializer-legacy: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> { tasks.withType<JavaCompile> {

View File

@@ -4,11 +4,20 @@ import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; 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;
/** /**
* Base class to hold the handler. * Holds the instance of the eco handler for bridging between the frontend
* and backend.
* *
* @see Eco#getHandler()
* @see Handler * @see Handler
*/ */
@ApiStatus.Internal
public final class Eco { public final class Eco {
/** /**
* Instance of eco handler. * Instance of eco handler.
@@ -18,6 +27,7 @@ public final class Eco {
/** /**
* Set the handler. * Set the handler.
*
* @param handler The handler. * @param handler The handler.
*/ */
@ApiStatus.Internal @ApiStatus.Internal
@@ -28,18 +38,18 @@ public final class Eco {
} }
/** /**
* Get the instance of the eco handler. * Get the instance of the eco handler; the bridge between the api frontend
* and the implementation backend.
* <p> * <p>
* The handler is, in essence, a way to interface between the eco-api * <strong>Do not use the handler in your plugins!</strong> It can and will contain
* frontend module, and the eco-backend implementations. * breaking changes between minor versions and even patches, and you will create
* compatibility issues by using the handler. All parts of the handler have been abstracted
* into logically named API components that you can use.
* <p> * <p>
* There shouldn't really be any reason to ever use the handler * Prior to version 6.12.0, the handler was considered as an API component, but it has
* in your own plugins, and you are likely to break things. All parts of * since been moved into an internal component, and in 6.17.0, the first breaking change
* the handler are abstracted into logically named parts of the API. * was introduced to {@link com.willfp.eco.core.config.wrapper.ConfigFactory}. This means
* <p> * that any usages of the handler can now cause problems in your plugins.
* In versions of eco before 6.12.0, the handler was considered part of
* the eco API, however it has since been moved into an internal component
* that shouldn't be used in your plugins.
* *
* @return The handler. * @return The handler.
*/ */
@@ -48,6 +58,24 @@ public final class Eco {
return handler; 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() { private Eco() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
} }

View File

@@ -14,7 +14,6 @@ import com.willfp.eco.core.factory.NamespacedKeyFactory;
import com.willfp.eco.core.factory.RunnableFactory; import com.willfp.eco.core.factory.RunnableFactory;
import com.willfp.eco.core.integrations.IntegrationLoader; import com.willfp.eco.core.integrations.IntegrationLoader;
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager; import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
import com.willfp.eco.core.proxy.AbstractProxy;
import com.willfp.eco.core.proxy.ProxyFactory; import com.willfp.eco.core.proxy.ProxyFactory;
import com.willfp.eco.core.scheduling.Scheduler; import com.willfp.eco.core.scheduling.Scheduler;
import com.willfp.eco.core.web.UpdateChecker; import com.willfp.eco.core.web.UpdateChecker;
@@ -32,6 +31,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -327,11 +327,9 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
DefaultArtifactVersion mostRecentVersion = new DefaultArtifactVersion(version); DefaultArtifactVersion mostRecentVersion = new DefaultArtifactVersion(version);
if (!(currentVersion.compareTo(mostRecentVersion) > 0 || currentVersion.equals(mostRecentVersion))) { if (!(currentVersion.compareTo(mostRecentVersion) > 0 || currentVersion.equals(mostRecentVersion))) {
this.outdated = true; this.outdated = true;
this.getScheduler().runTimer(() -> { this.getLogger().warning("&c" + this.getName() + " is out of date! (Version " + this.getDescription().getVersion() + ")");
this.getLogger().info("&c " + this.getName() + " is out of date! (Version " + this.getDescription().getVersion() + ")"); this.getLogger().warning("&cThe newest version is &f" + version);
this.getLogger().info("&cThe newest version is &f" + version); this.getLogger().warning("&cDownload the new version!");
this.getLogger().info("&cDownload the new version!");
}, 0, 864000);
} }
}); });
} }
@@ -636,7 +634,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
* @param <T> The proxy type. * @param <T> The proxy type.
* @return The proxy. * @return The proxy.
*/ */
public final <T extends AbstractProxy> T getProxy(@NotNull final Class<T> proxyClass) { 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 proxy!");
return proxyFactory.getProxy(proxyClass); return proxyFactory.getProxy(proxyClass);
@@ -655,7 +653,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
public final FileConfiguration getConfig() { public final FileConfiguration getConfig() {
this.getLogger().warning("Call to default config method in eco plugin!"); this.getLogger().warning("Call to default config method in eco plugin!");
return this.getConfigYml().getBukkitHandle(); return Objects.requireNonNull(this.getConfigYml().getBukkitHandle());
} }
/** /**

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.updating.ConfigHandler;
import com.willfp.eco.core.config.wrapper.ConfigFactory; 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.data.keys.KeyRegistry;
import com.willfp.eco.core.drops.DropQueueFactory; import com.willfp.eco.core.drops.DropQueueFactory;
import com.willfp.eco.core.events.EventManager; import com.willfp.eco.core.events.EventManager;
@@ -18,6 +18,9 @@ import com.willfp.eco.core.proxy.ProxyFactory;
import com.willfp.eco.core.requirement.RequirementFactory; import com.willfp.eco.core.requirement.RequirementFactory;
import com.willfp.eco.core.scheduling.Scheduler; import com.willfp.eco.core.scheduling.Scheduler;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; 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.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -230,5 +233,30 @@ public interface Handler {
* *
* @return The handler. * @return The handler.
*/ */
PlayerProfileHandler getPlayerProfileHandler(); @NotNull
ProfileHandler getProfileHandler();
/**
* Create dummy entity - never spawned, exists purely in code.
*
* @param location The location.
* @return The entity.
*/
@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);
} }

View File

@@ -4,6 +4,13 @@ import org.jetbrains.annotations.NotNull;
/** /**
* Quick DI class to manage passing eco plugins. * Quick DI class to manage passing eco plugins.
* <p>
* Basically just a quick bit of laziness if you can't be bothered to add a private field
* and a protected getter, don't use this in kotlin as you can just specify
* {@code
* private val plugin: EcoPlugin
* }
* in the constructor.
* *
* @param <T> The eco plugin type. * @param <T> The eco plugin type.
*/ */

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.core;
import com.willfp.eco.core.config.updating.ConfigHandler; import com.willfp.eco.core.config.updating.ConfigHandler;
import java.io.File; import java.io.File;
import java.util.logging.Logger;
/** /**
* Represents any class that acts like a plugin, for example {@link EcoPlugin} * Represents any class that acts like a plugin, for example {@link EcoPlugin}
@@ -26,4 +27,11 @@ public interface PluginLike {
* @return The config handler. * @return The config handler.
*/ */
ConfigHandler getConfigHandler(); ConfigHandler getConfigHandler();
/**
* Get the logger.
*
* @return The logger.
*/
Logger getLogger();
} }

View File

@@ -1,7 +1,11 @@
package com.willfp.eco.core.command; package com.willfp.eco.core.command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/** /**
* Interface for all command implementations. * Interface for all command implementations.
*/ */
@@ -35,31 +39,70 @@ public interface CommandBase {
*/ */
CommandBase addSubcommand(@NotNull CommandBase command); CommandBase addSubcommand(@NotNull CommandBase command);
/**
* Handle command execution.
* <p>
* Marked as default void with no implementation for backwards compatibility.
*
* @param sender The sender.
* @param args The args.
*/
default void onExecute(@NotNull CommandSender sender,
@NotNull List<String> args) {
// Do nothing.
}
/**
* Handle tab completion.
* <p>
* Marked as default void with no implementation for backwards compatibility.
*
* @param sender The sender.
* @param args The args.
* @return The results.
*/
default List<String> tabComplete(@NotNull CommandSender sender,
@NotNull List<String> args) {
return new ArrayList<>();
}
/** /**
* Get the handler. * Get the handler.
* *
* @return The handler. * @return The handler.
* @see CommandHandler
* @deprecated Use {@link CommandBase#onExecute(CommandSender, List)} instead.
*/ */
@Deprecated
CommandHandler getHandler(); CommandHandler getHandler();
/** /**
* Set the handler. * Set the handler.
* *
* @param handler The handler. * @param handler The handler.
* @see CommandHandler
* @deprecated Handlers have been deprecated.
*/ */
@Deprecated
void setHandler(@NotNull CommandHandler handler); void setHandler(@NotNull CommandHandler handler);
/** /**
* Get the tab completer. * Get the tab completer.
* *
* @return The tab completer. * @return The tab completer.
* @see TabCompleteHandler
* @deprecated Use {@link CommandBase#tabComplete(CommandSender, List)} instead.
*/ */
@Deprecated
TabCompleteHandler getTabCompleter(); TabCompleteHandler getTabCompleter();
/** /**
* Set the tab completer. * Set the tab completer.
* *
* @param handler The handler. * @param handler The handler.
* @see TabCompleteHandler
* @deprecated Handlers have been deprecated.
*/ */
@Deprecated
void setTabCompleter(@NotNull TabCompleteHandler handler); void setTabCompleter(@NotNull TabCompleteHandler handler);
} }

View File

@@ -10,9 +10,13 @@ import java.util.List;
* A command handler handles the actual code for a command. * A command handler handles the actual code for a command.
* <p> * <p>
* The replacement for {@link org.bukkit.command.CommandExecutor#onCommand(CommandSender, Command, String, String[])} * The replacement for {@link org.bukkit.command.CommandExecutor#onCommand(CommandSender, Command, String, String[])}
*
* @see CommandBase * @see CommandBase
* @deprecated Handlers have been deprecated. This legacy system will eventually be removed,
* update to use the new system: {@link CommandBase#onExecute(CommandSender, List)}.
*/ */
@FunctionalInterface @FunctionalInterface
@Deprecated(since = "6.17.0")
public interface CommandHandler { public interface CommandHandler {
/** /**
* The code to be called on execution. * The code to be called on execution.

View File

@@ -10,9 +10,13 @@ import java.util.List;
* A Tab Complete handler handles the actual tab-completion code. * A Tab Complete handler handles the actual tab-completion code.
* <p> * <p>
* The replacement for {@link org.bukkit.command.TabCompleter#onTabComplete(CommandSender, Command, String, String[])} * The replacement for {@link org.bukkit.command.TabCompleter#onTabComplete(CommandSender, Command, String, String[])}
*
* @see CommandBase * @see CommandBase
* @deprecated Handlers have been deprecated. This legacy system will eventually be removed,
* update to use the new system: {@link CommandBase#tabComplete(CommandSender, List)}
*/ */
@FunctionalInterface @FunctionalInterface
@Deprecated(since = "6.17.0")
public interface TabCompleteHandler { public interface TabCompleteHandler {
/** /**
* Handle Tab Completion. * Handle Tab Completion.

View File

@@ -9,6 +9,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil; import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -23,6 +24,7 @@ import java.util.stream.Collectors;
* in order to execute the command-specific code. It's essentially an internal * in order to execute the command-specific code. It's essentially an internal
* layer, hence why it's a package-private class. * layer, hence why it's a package-private class.
*/ */
@SuppressWarnings({"DeprecatedIsStillUsed"})
abstract class HandledCommand extends PluginDependent<EcoPlugin> implements CommandBase { abstract class HandledCommand extends PluginDependent<EcoPlugin> implements CommandBase {
/** /**
* The name of the command. * The name of the command.
@@ -46,14 +48,16 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
/** /**
* The actual code to be executed in the command. * The actual code to be executed in the command.
*/ */
private CommandHandler handler = (sender, args) -> { @Deprecated
// Do nothing by default @Nullable
}; private CommandHandler handler = null;
/** /**
* The tab completion code to be executed in the command. * The tab completion code to be executed in the command.
*/ */
private TabCompleteHandler tabCompleter = (sender, args) -> new ArrayList<>(); @Deprecated
@Nullable
private TabCompleteHandler tabCompleter = null;
/** /**
* All subcommands for the command. * All subcommands for the command.
@@ -120,7 +124,11 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
} }
} }
this.getHandler().onExecute(sender, Arrays.asList(args)); if (this.getHandler() != null) {
this.getHandler().onExecute(sender, Arrays.asList(args));
} else {
this.onExecute(sender, Arrays.asList(args));
}
} }
/** /**
@@ -167,7 +175,11 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
} }
} }
return this.getTabCompleter().tabComplete(sender, Arrays.asList(args)); if (this.getTabCompleter() != null) {
return this.getTabCompleter().tabComplete(sender, Arrays.asList(args));
} else {
return this.tabComplete(sender, Arrays.asList(args));
}
} }
/** /**
@@ -221,24 +233,6 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
return this.playersOnly; return this.playersOnly;
} }
/**
* Get the actual code to be executed in the command.
*
* @return The code.
*/
public CommandHandler getHandler() {
return this.handler;
}
/**
* Get the tab completion code to be executed in the command.
*
* @return The code.
*/
public TabCompleteHandler getTabCompleter() {
return this.tabCompleter;
}
/** /**
* Get the subcommands of the command. * Get the subcommands of the command.
* *
@@ -248,21 +242,27 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
return this.subcommands; return this.subcommands;
} }
/** @Deprecated
* Set the command handler. @Override
* public @Nullable CommandHandler getHandler() {
* @param handler The handler. return this.handler;
*/ }
public void setHandler(@NotNull final CommandHandler handler) {
@Deprecated
@Override
public @Nullable TabCompleteHandler getTabCompleter() {
return this.tabCompleter;
}
@Deprecated
@Override
public void setHandler(@Nullable final CommandHandler handler) {
this.handler = handler; this.handler = handler;
} }
/** @Deprecated
* Set the tab completer. @Override
* public void setTabCompleter(@Nullable final TabCompleteHandler tabCompleter) {
* @param tabCompleter The tab completer.
*/
public void setTabCompleter(@NotNull final TabCompleteHandler tabCompleter) {
this.tabCompleter = tabCompleter; this.tabCompleter = tabCompleter;
} }
} }

View File

@@ -12,7 +12,9 @@ import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
/** /**
* PluginCommands are the class to be used instead of CommandExecutor. * PluginCommands are the class to be used instead of CommandExecutor,
* they function as the base command, e.g. {@code /ecoenchants} would be a base command, with each
* subsequent argument functioning as subcommands.
* <p> * <p>
* The command will not be registered until register() is called. * The command will not be registered until register() is called.
* <p> * <p>

View File

@@ -0,0 +1,35 @@
package com.willfp.eco.core.config;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.wrapper.LoadableConfigWrapper;
import org.jetbrains.annotations.NotNull;
/**
* Config implementation for configs present in the plugin's base directory (eg config.yml, lang.yml).
* <p>
* Automatically updates.
*/
public abstract class BaseConfig extends LoadableConfigWrapper {
/**
* Create new Base Config.
*
* @param plugin The plugin or extension.
* @param configName The config name (excluding extension).
* @param removeUnused If unused sections should be removed.
* @param type The config type.
*/
protected BaseConfig(@NotNull final String configName,
@NotNull final PluginLike plugin,
final boolean removeUnused,
@NotNull final ConfigType type) {
super(Eco.getHandler().getConfigFactory().createUpdatableConfig(
configName,
plugin,
"",
plugin.getClass(),
removeUnused,
type
));
}
}

View File

@@ -0,0 +1,16 @@
package com.willfp.eco.core.config;
/**
* Config types, classified by file extension.
*/
public enum ConfigType {
/**
* .json config.
*/
JSON,
/**
* .yml config.
*/
YAML
}

View File

@@ -0,0 +1,44 @@
package com.willfp.eco.core.config;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.wrapper.LoadableConfigWrapper;
import org.jetbrains.annotations.NotNull;
/**
* Config implementation for configs present in one of two places:
* <ul>
* <li>Plugin base directory (eg config.yml, lang.json)</li>
* <li>Other extension's configs</li>
* </ul>
* <p>
* Automatically updates.
*/
public abstract class ExtendableConfig extends LoadableConfigWrapper {
/**
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
* @param updateBlacklist Substring of keys to not add/remove keys for.
* @param subDirectoryPath The subdirectory path.
* @param type The config type.
* @param source The class that owns the resource.
*/
protected ExtendableConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final PluginLike plugin,
@NotNull final Class<?> source,
@NotNull final String subDirectoryPath,
@NotNull final ConfigType type,
@NotNull final String... updateBlacklist) {
super(Eco.getHandler().getConfigFactory().createUpdatableConfig(
configName,
plugin,
subDirectoryPath,
source,
removeUnused,
type,
updateBlacklist
));
}
}

View File

@@ -0,0 +1,32 @@
package com.willfp.eco.core.config;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.wrapper.LoadableConfigWrapper;
import org.jetbrains.annotations.NotNull;
/**
* Non-updatable yaml config that exists within a plugin jar.
*/
public abstract class StaticBaseConfig extends LoadableConfigWrapper {
/**
* Config implementation for configs present in the plugin's base directory (eg config.yml, lang.yml).
* <p>
* Does not automatically update.
*
* @param configName The name of the config
* @param plugin The plugin.
* @param type The config type.
*/
protected StaticBaseConfig(@NotNull final String configName,
@NotNull final PluginLike plugin,
@NotNull final ConfigType type) {
super(Eco.getHandler().getConfigFactory().createLoadableConfig(
configName,
plugin,
"",
plugin.getClass(),
type
));
}
}

View File

@@ -0,0 +1,48 @@
package com.willfp.eco.core.config;
import com.willfp.eco.core.Eco;
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 java.util.Map;
/**
* Config that exists purely in the code, not linked to any file.
* <p>
* Use for inline configs to move data around or to add subsections to other configs.
*/
public class TransientConfig extends ConfigWrapper<Config> {
/**
* @param config The YamlConfiguration handle.
*/
public TransientConfig(@NotNull final YamlConfiguration config) {
super(Eco.getHandler().getConfigFactory().createConfig(config));
}
/**
* Create a new empty transient config.
*
* @param values The values.
*/
public TransientConfig(@NotNull final Map<String, Object> values) {
super(Eco.getHandler().getConfigFactory().createConfig(values));
}
/**
* Create a new empty transient config.
*/
public TransientConfig() {
super(Eco.getHandler().getConfigFactory().createConfig("", ConfigType.YAML));
}
/**
* @param contents The contents of the config.
* @param type The config type.
*/
public TransientConfig(@NotNull final String contents,
@NotNull final ConfigType type) {
super(Eco.getHandler().getConfigFactory().createConfig(contents, type));
}
}

View File

@@ -1,20 +1,21 @@
package com.willfp.eco.core.config.base; package com.willfp.eco.core.config.base;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.config.yaml.YamlBaseConfig; import com.willfp.eco.core.config.BaseConfig;
import com.willfp.eco.core.config.ConfigType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Default plugin config.yml. * Default plugin config.yml.
*/ */
public class ConfigYml extends YamlBaseConfig { public class ConfigYml extends BaseConfig {
/** /**
* Config.yml. * Config.yml.
* *
* @param plugin The plugin. * @param plugin The plugin.
*/ */
public ConfigYml(@NotNull final EcoPlugin plugin) { public ConfigYml(@NotNull final EcoPlugin plugin) {
super("config", true, plugin); super("config", plugin, true, ConfigType.YAML);
} }
/** /**
@@ -25,7 +26,7 @@ public class ConfigYml extends YamlBaseConfig {
*/ */
public ConfigYml(@NotNull final EcoPlugin plugin, public ConfigYml(@NotNull final EcoPlugin plugin,
final boolean removeUnused) { final boolean removeUnused) {
super("config", removeUnused, plugin); super("config", plugin, removeUnused, ConfigType.YAML);
} }
/** /**
@@ -36,7 +37,7 @@ public class ConfigYml extends YamlBaseConfig {
*/ */
public ConfigYml(@NotNull final EcoPlugin plugin, public ConfigYml(@NotNull final EcoPlugin plugin,
@NotNull final String name) { @NotNull final String name) {
super(name, true, plugin); super(name, plugin, true, ConfigType.YAML);
} }
/** /**
@@ -49,7 +50,6 @@ public class ConfigYml extends YamlBaseConfig {
public ConfigYml(@NotNull final EcoPlugin plugin, public ConfigYml(@NotNull final EcoPlugin plugin,
@NotNull final String name, @NotNull final String name,
final boolean removeUnused) { final boolean removeUnused) {
super(name, removeUnused, plugin); super(name, plugin, removeUnused, ConfigType.YAML);
} }
} }

View File

@@ -1,21 +1,22 @@
package com.willfp.eco.core.config.base; package com.willfp.eco.core.config.base;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.config.yaml.YamlBaseConfig; import com.willfp.eco.core.config.BaseConfig;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.util.StringUtils; import com.willfp.eco.util.StringUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Default plugin lang.yml. * Default plugin lang.yml.
*/ */
public class LangYml extends YamlBaseConfig { public class LangYml extends BaseConfig {
/** /**
* Lang.yml. * Lang.yml.
* *
* @param plugin The plugin. * @param plugin The plugin.
*/ */
public LangYml(@NotNull final EcoPlugin plugin) { public LangYml(@NotNull final EcoPlugin plugin) {
super("lang", false, plugin); super("lang", plugin, false, ConfigType.YAML);
} }
/** /**

View File

@@ -1,13 +1,19 @@
package com.willfp.eco.core.config.interfaces; 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 com.willfp.eco.util.StringUtils;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* All canfigs implement this interface. * All configs implement this interface.
* <p> * <p>
* Contains all methods that must exist in yaml and json configurations. * Contains all methods that must exist in yaml and json configurations.
*/ */
@@ -66,10 +72,12 @@ public interface Config extends Cloneable {
* Get subsection from config. * Get subsection from config.
* *
* @param path The key to check. * @param path The key to check.
* @return The subsection. Throws NPE if not found. * @return The subsection. Returns an empty section if not found.
*/ */
@NotNull @NotNull
Config getSubsection(@NotNull String path); default Config getSubsection(@NotNull String path) {
return Objects.requireNonNullElse(getSubsectionOrNull(path), new TransientConfig());
}
/** /**
* Get subsection from config. * Get subsection from config.
@@ -86,7 +94,44 @@ public interface Config extends Cloneable {
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @return The found value, or 0 if not found. * @return The found value, or 0 if not found.
*/ */
int getInt(@NotNull String path); default int getInt(@NotNull String path) {
return Objects.requireNonNullElse(getIntOrNull(path), 0);
}
/**
* Get an integer from config with a specified default (not found) value.
*
* @param path The key to fetch the value from.
* @param def The value to default to if not found.
* @return The found value, or the default.
*/
default int getInt(@NotNull String path,
int def) {
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. * Get an integer from config.
@@ -97,16 +142,6 @@ public interface Config extends Cloneable {
@Nullable @Nullable
Integer getIntOrNull(@NotNull String path); Integer getIntOrNull(@NotNull String path);
/**
* Get an integer from config with a specified default (not found) value.
*
* @param path The key to fetch the value from.
* @param def The value to default to if not found.
* @return The found value, or the default.
*/
int getInt(@NotNull String path,
int def);
/** /**
* Get a list of integers from config. * Get a list of integers from config.
* *
@@ -114,7 +149,9 @@ public interface Config extends Cloneable {
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/ */
@NotNull @NotNull
List<Integer> getInts(@NotNull String path); default List<Integer> getInts(@NotNull String path) {
return Objects.requireNonNullElse(getIntsOrNull(path), new ArrayList<>());
}
/** /**
* Get a list of integers from config. * Get a list of integers from config.
@@ -131,7 +168,9 @@ public interface Config extends Cloneable {
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @return The found value, or false if not found. * @return The found value, or false if not found.
*/ */
boolean getBool(@NotNull String path); default boolean getBool(@NotNull String path) {
return Objects.requireNonNullElse(getBoolOrNull(path), false);
}
/** /**
* Get a boolean from config. * Get a boolean from config.
@@ -149,7 +188,9 @@ public interface Config extends Cloneable {
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/ */
@NotNull @NotNull
List<Boolean> getBools(@NotNull String path); default List<Boolean> getBools(@NotNull String path) {
return Objects.requireNonNullElse(getBoolsOrNull(path), new ArrayList<>());
}
/** /**
* Get a list of booleans from config. * Get a list of booleans from config.
@@ -168,7 +209,7 @@ public interface Config extends Cloneable {
*/ */
@NotNull @NotNull
default String getFormattedString(@NotNull String path) { default String getFormattedString(@NotNull String path) {
return getString(path, true); return getString(path, true, StringUtils.FormatOption.WITH_PLACEHOLDERS);
} }
/** /**
@@ -187,25 +228,25 @@ public interface Config extends Cloneable {
/** /**
* Get a string from config. * Get a string from config.
* <p> * <p>
* Formatted by default. * Not formatted.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @return The found value, or an empty string if not found. * @return The found value, or an empty string if not found.
*/ */
@NotNull @NotNull
default String getString(@NotNull String path) { default String getString(@NotNull String path) {
return getString(path, true); return getString(path, false);
} }
/** /**
* Get a string from config. * Get a string from config.
* <p>
* This will be deprecated when {@link Config#getString(String)} no longer formats by default.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @param format If the string should be formatted. * @param format If the string should be formatted.
* @return The found value, or an empty string if not found. * @return The found value, or an empty string if not found.
* @deprecated Since 6.18.0, {@link Config#getString(String)} is not formatted by default.
*/ */
@Deprecated(since = "6.18.0")
default String getString(@NotNull String path, default String getString(@NotNull String path,
boolean format) { boolean format) {
return this.getString(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS); return this.getString(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS);
@@ -235,9 +276,11 @@ public interface Config extends Cloneable {
* @return The found value, or an empty string if not found. * @return The found value, or an empty string if not found.
*/ */
@NotNull @NotNull
String getString(@NotNull String path, default String getString(@NotNull String path,
boolean format, boolean format,
@NotNull StringUtils.FormatOption option); @NotNull StringUtils.FormatOption option) {
return Objects.requireNonNullElse(getStringOrNull(path, format, option), "");
}
/** /**
* Get a formatted string from config. * Get a formatted string from config.
@@ -247,7 +290,7 @@ public interface Config extends Cloneable {
*/ */
@Nullable @Nullable
default String getFormattedStringOrNull(@NotNull String path) { default String getFormattedStringOrNull(@NotNull String path) {
return getStringOrNull(path, true); return getStringOrNull(path, true, StringUtils.FormatOption.WITH_PLACEHOLDERS);
} }
/** /**
@@ -273,19 +316,19 @@ public interface Config extends Cloneable {
*/ */
@Nullable @Nullable
default String getStringOrNull(@NotNull String path) { default String getStringOrNull(@NotNull String path) {
return getStringOrNull(path, true); return getStringOrNull(path, false, StringUtils.FormatOption.WITH_PLACEHOLDERS);
} }
/** /**
* Get a string from config. * Get a string from config.
* <p>
* This will be deprecated when {@link Config#getStringOrNull(String)} no longer formats by default.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @param format If the string should be formatted. * @param format If the string should be formatted.
* @return The found value, or null if not found. * @return The found value, or null if not found.
* @deprecated Since 6.18.0, {@link Config#getString(String)} is not formatted by default.
*/ */
@Nullable @Nullable
@Deprecated(since = "6.18.0")
default String getStringOrNull(@NotNull String path, default String getStringOrNull(@NotNull String path,
boolean format) { boolean format) {
return this.getStringOrNull(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS); return this.getStringOrNull(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS);
@@ -350,28 +393,26 @@ public interface Config extends Cloneable {
/** /**
* Get a list of strings from config. * Get a list of strings from config.
* <p> * <p>
* Formatted by default. * Not formatted.
* <p>
* This will be changed in newer versions to <b>not</b> format by default.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/ */
@NotNull @NotNull
default List<String> getStrings(@NotNull String path) { default List<String> getStrings(@NotNull String path) {
return getStrings(path, true); return getStrings(path, false, StringUtils.FormatOption.WITH_PLACEHOLDERS);
} }
/** /**
* Get a list of strings from config. * Get a list of strings from config.
* <p>
* This will be deprecated when {@link Config#getStrings(String)} no longer formats by default.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @param format If the strings should be formatted. * @param format If the strings should be formatted.
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
* @deprecated Since 6.18.0, {@link Config#getString(String)} is not formatted by default.
*/ */
@NotNull @NotNull
@Deprecated(since = "6.18.0")
default List<String> getStrings(@NotNull String path, default List<String> getStrings(@NotNull String path,
boolean format) { boolean format) {
return this.getStrings(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS); return this.getStrings(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS);
@@ -389,7 +430,7 @@ public interface Config extends Cloneable {
@Deprecated @Deprecated
default List<String> getStrings(@NotNull String path, default List<String> getStrings(@NotNull String path,
@NotNull StringUtils.FormatOption option) { @NotNull StringUtils.FormatOption option) {
return getStrings(path, true, option); return getStrings(path, false, option);
} }
/** /**
@@ -401,14 +442,16 @@ public interface Config extends Cloneable {
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/ */
@NotNull @NotNull
List<String> getStrings(@NotNull String path, default List<String> getStrings(@NotNull String path,
boolean format, boolean format,
@NotNull StringUtils.FormatOption option); @NotNull StringUtils.FormatOption option) {
return Objects.requireNonNullElse(getStringsOrNull(path, format, option), new ArrayList<>());
}
/** /**
* Get a list of strings from config. * Get a list of strings from config.
* <p> * <p>
* Formatted by default. * Formatted.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @return The found value, or null if not found. * @return The found value, or null if not found.
@@ -421,7 +464,7 @@ public interface Config extends Cloneable {
/** /**
* Get a list of strings from config. * Get a list of strings from config.
* <p> * <p>
* Formatted by default. * Formatted.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @param option The format option. * @param option The format option.
@@ -436,7 +479,7 @@ public interface Config extends Cloneable {
/** /**
* Get a list of strings from config. * Get a list of strings from config.
* <p> * <p>
* Formatted by default. * Not formatted.
* <p> * <p>
* This will be changed in newer versions to <b>not</b> format by default. * This will be changed in newer versions to <b>not</b> format by default.
* *
@@ -445,7 +488,7 @@ public interface Config extends Cloneable {
*/ */
@Nullable @Nullable
default List<String> getStringsOrNull(@NotNull String path) { default List<String> getStringsOrNull(@NotNull String path) {
return getStringsOrNull(path, true); return getStringsOrNull(path, false, StringUtils.FormatOption.WITH_PLACEHOLDERS);
} }
/** /**
@@ -454,8 +497,10 @@ public interface Config extends Cloneable {
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @param format If the strings should be formatted. * @param format If the strings should be formatted.
* @return The found value, or null if not found. * @return The found value, or null if not found.
* @deprecated Since 6.18.0, {@link Config#getString(String)} is not formatted by default.
*/ */
@Nullable @Nullable
@Deprecated(since = "6.18.0")
default List<String> getStringsOrNull(@NotNull String path, default List<String> getStringsOrNull(@NotNull String path,
boolean format) { boolean format) {
return getStringsOrNull(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS); return getStringsOrNull(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS);
@@ -473,7 +518,7 @@ public interface Config extends Cloneable {
@Deprecated @Deprecated
default List<String> getStringsOrNull(@NotNull String path, default List<String> getStringsOrNull(@NotNull String path,
@NotNull StringUtils.FormatOption option) { @NotNull StringUtils.FormatOption option) {
return getStringsOrNull(path, true, option); return getStringsOrNull(path, false, option);
} }
/** /**
@@ -495,7 +540,31 @@ public interface Config extends Cloneable {
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @return The found value, or 0 if not found. * @return The found value, or 0 if not found.
*/ */
double getDouble(@NotNull String path); default double getDouble(@NotNull String path) {
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. * Get a decimal from config.
@@ -513,7 +582,9 @@ public interface Config extends Cloneable {
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/ */
@NotNull @NotNull
List<Double> getDoubles(@NotNull String path); default List<Double> getDoubles(@NotNull String path) {
return Objects.requireNonNullElse(getDoublesOrNull(path), new ArrayList<>());
}
/** /**
* Get a list of decimals from config. * Get a list of decimals from config.
@@ -524,6 +595,34 @@ public interface Config extends Cloneable {
@Nullable @Nullable
List<Double> getDoublesOrNull(@NotNull String path); List<Double> getDoublesOrNull(@NotNull String path);
/**
* Get a list of subsections from config.
*
* @param path The key to fetch the value from.
* @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/
@NotNull
default List<? extends Config> getSubsections(@NotNull String path) {
return Objects.requireNonNullElse(getSubsectionsOrNull(path), new ArrayList<>());
}
/**
* Get a list of subsections from config.
*
* @param path The key to fetch the value from.
* @return The found value, or null if not found.
*/
@Nullable
List<? extends Config> getSubsectionsOrNull(@NotNull String path);
/**
* Get config type.
*
* @return The type.
*/
@NotNull
ConfigType getType();
/** /**
* Clone the config. * Clone the config.
* *

View File

@@ -3,13 +3,19 @@ package com.willfp.eco.core.config.interfaces;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* JSON configs have extra methods compared to yaml configs. * JSON config.
* <p> *
* If you need to use them, then use JSONConfig instead. * @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
@SuppressWarnings("DeprecatedIsStillUsed")
public interface JSONConfig extends Config { public interface JSONConfig extends Config {
/** /**
* Get a list of subsections from config. * Get a list of subsections from config.
@@ -18,7 +24,9 @@ public interface JSONConfig extends Config {
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/ */
@NotNull @NotNull
List<JSONConfig> getSubsections(@NotNull String path); default List<JSONConfig> getSubsections(@NotNull String path) {
return Objects.requireNonNullElse(getSubsectionsOrNull(path), new ArrayList<>());
}
/** /**
* Get a list of subsections from config. * Get a list of subsections from config.

View File

@@ -1,12 +1,16 @@
package com.willfp.eco.core.config.interfaces; package com.willfp.eco.core.config.interfaces;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
/** /**
* Interface for configs that physically exist as files in plugins. * Interface for configs that physically exist as files in plugins.
*/ */
public interface LoadableConfig { public interface LoadableConfig extends Config {
/** /**
* Create the file. * Create the file.
*/ */
@@ -39,4 +43,18 @@ public interface LoadableConfig {
* @return The name. * @return The name.
*/ */
String getName(); String getName();
/**
* Get bukkit {@link YamlConfiguration}.
* <p>
* This method is not recommended unless absolutely required as it
* only returns true if the type of config is {@link com.willfp.eco.core.config.ConfigType#YAML},
* and if the handle is an {@link YamlConfiguration} specifically. This depends on the internals
* and the implementation, and so may cause problems - it exists mostly for parity with
* {@link JavaPlugin#getConfig()}.
*
* @return The config, or null if config is not yaml-based.
*/
@Nullable
YamlConfiguration getBukkitHandle();
} }

View File

@@ -5,8 +5,12 @@ import org.bukkit.configuration.file.YamlConfiguration;
/** /**
* Interface for configs that wrap an {@link YamlConfiguration}. * Interface for configs that wrap an {@link YamlConfiguration}.
* *
* @see com.willfp.eco.core.config.yaml.wrapper.YamlConfigWrapper * @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
@SuppressWarnings("DeprecatedIsStillUsed")
public interface WrappedYamlConfiguration { public interface WrappedYamlConfiguration {
/** /**
* Get the ConfigurationSection handle. * Get the ConfigurationSection handle.

View File

@@ -3,6 +3,8 @@ package com.willfp.eco.core.config.json;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginLike; import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.JSONConfig;
import com.willfp.eco.core.config.json.wrapper.LoadableJSONConfigWrapper; import com.willfp.eco.core.config.json.wrapper.LoadableJSONConfigWrapper;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -10,7 +12,12 @@ import org.jetbrains.annotations.NotNull;
* Config implementation for configs present in the plugin's base directory (eg config.json). * Config implementation for configs present in the plugin's base directory (eg config.json).
* <p> * <p>
* Automatically updates. * Automatically updates.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
public abstract class JSONBaseConfig extends LoadableJSONConfigWrapper { public abstract class JSONBaseConfig extends LoadableJSONConfigWrapper {
/** /**
* @param configName The name of the config * @param configName The name of the config
@@ -23,13 +30,16 @@ public abstract class JSONBaseConfig extends LoadableJSONConfigWrapper {
@NotNull final PluginLike plugin, @NotNull final PluginLike plugin,
@NotNull final String... updateBlacklist) { @NotNull final String... updateBlacklist) {
super( super(
Eco.getHandler().getConfigFactory().createUpdatableJSONConfig( (JSONConfig)
configName, Eco.getHandler().getConfigFactory().createUpdatableConfig(
plugin, configName,
"", plugin,
plugin.getClass(), "",
removeUnused, updateBlacklist plugin.getClass(),
) removeUnused,
ConfigType.JSON,
updateBlacklist
)
); );
} }
@@ -42,13 +52,15 @@ public abstract class JSONBaseConfig extends LoadableJSONConfigWrapper {
final boolean removeUnused, final boolean removeUnused,
@NotNull final PluginLike plugin) { @NotNull final PluginLike plugin) {
super( super(
Eco.getHandler().getConfigFactory().createUpdatableJSONConfig( (JSONConfig)
configName, Eco.getHandler().getConfigFactory().createUpdatableConfig(
plugin, configName,
"", plugin,
plugin.getClass(), "",
removeUnused plugin.getClass(),
) removeUnused,
ConfigType.JSON
)
); );
} }

View File

@@ -3,6 +3,8 @@ package com.willfp.eco.core.config.json;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginLike; import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.JSONConfig;
import com.willfp.eco.core.config.json.wrapper.LoadableJSONConfigWrapper; import com.willfp.eco.core.config.json.wrapper.LoadableJSONConfigWrapper;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -14,7 +16,12 @@ import org.jetbrains.annotations.NotNull;
* </ul> * </ul>
* <p> * <p>
* Automatically updates. * Automatically updates.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
public abstract class JSONExtendableConfig extends LoadableJSONConfigWrapper { public abstract class JSONExtendableConfig extends LoadableJSONConfigWrapper {
/** /**
* @param configName The name of the config * @param configName The name of the config
@@ -31,16 +38,19 @@ public abstract class JSONExtendableConfig extends LoadableJSONConfigWrapper {
@NotNull final String subDirectoryPath, @NotNull final String subDirectoryPath,
@NotNull final String... updateBlacklist) { @NotNull final String... updateBlacklist) {
super( super(
Eco.getHandler().getConfigFactory().createUpdatableJSONConfig( (JSONConfig)
configName, Eco.getHandler().getConfigFactory().createUpdatableConfig(
plugin, configName,
subDirectoryPath, plugin,
source, subDirectoryPath,
removeUnused, source,
updateBlacklist removeUnused,
) ConfigType.JSON,
updateBlacklist
)
); );
} }
/** /**
* @param configName The name of the config * @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update. * @param removeUnused Whether keys not present in the default config should be removed on update.

View File

@@ -3,12 +3,19 @@ package com.willfp.eco.core.config.json;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginLike; import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.JSONConfig;
import com.willfp.eco.core.config.json.wrapper.LoadableJSONConfigWrapper; import com.willfp.eco.core.config.json.wrapper.LoadableJSONConfigWrapper;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Non-updatable JSON config that exists within a plugin jar. * Non-updatable JSON config that exists within a plugin jar.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
public abstract class JSONStaticBaseConfig extends LoadableJSONConfigWrapper { public abstract class JSONStaticBaseConfig extends LoadableJSONConfigWrapper {
/** /**
* Config implementation for configs present in the plugin's base directory (eg config.json, lang.json). * Config implementation for configs present in the plugin's base directory (eg config.json, lang.json).
@@ -20,7 +27,7 @@ public abstract class JSONStaticBaseConfig extends LoadableJSONConfigWrapper {
*/ */
protected JSONStaticBaseConfig(@NotNull final String configName, protected JSONStaticBaseConfig(@NotNull final String configName,
@NotNull final PluginLike plugin) { @NotNull final PluginLike plugin) {
super(Eco.getHandler().getConfigFactory().createLoadableJSONConfig(configName, plugin, "", plugin.getClass())); super((JSONConfig) Eco.getHandler().getConfigFactory().createLoadableConfig(configName, plugin, "", plugin.getClass(), ConfigType.JSON));
} }
/** /**

View File

@@ -1,14 +1,21 @@
package com.willfp.eco.core.config.json; package com.willfp.eco.core.config.json;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import com.willfp.eco.core.config.interfaces.JSONConfig;
import com.willfp.eco.core.config.json.wrapper.JSONConfigWrapper; import com.willfp.eco.core.config.json.wrapper.JSONConfigWrapper;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* Raw JSON config with a map of values at its core. * Raw JSON config with a map of values at its core.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
public class JSONTransientConfig extends JSONConfigWrapper { public class JSONTransientConfig extends JSONConfigWrapper {
/** /**
* Config implementation for passing maps. * Config implementation for passing maps.
@@ -18,6 +25,13 @@ public class JSONTransientConfig extends JSONConfigWrapper {
* @param values The map of values. * @param values The map of values.
*/ */
public JSONTransientConfig(@NotNull final Map<String, Object> values) { public JSONTransientConfig(@NotNull final Map<String, Object> values) {
super(Eco.getHandler().getConfigFactory().createJSONConfig(values)); super((JSONConfig) Eco.getHandler().getConfigFactory().createConfig(values));
}
/**
* Empty JSON config.
*/
public JSONTransientConfig() {
super((JSONConfig) Eco.getHandler().getConfigFactory().createConfig(new HashMap<>()));
} }
} }

View File

@@ -9,7 +9,12 @@ import java.util.List;
/** /**
* Wrapper to handle the backend JSON config implementations. * Wrapper to handle the backend JSON config implementations.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
public abstract class JSONConfigWrapper extends ConfigWrapper<JSONConfig> implements JSONConfig { public abstract class JSONConfigWrapper extends ConfigWrapper<JSONConfig> implements JSONConfig {
/** /**
* Create a config wrapper. * Create a config wrapper.

View File

@@ -3,14 +3,21 @@ package com.willfp.eco.core.config.json.wrapper;
import com.willfp.eco.core.config.interfaces.JSONConfig; import com.willfp.eco.core.config.interfaces.JSONConfig;
import com.willfp.eco.core.config.interfaces.LoadableConfig; import com.willfp.eco.core.config.interfaces.LoadableConfig;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
/** /**
* Wrapper to handle the backend loadable JSON config implementations. * Wrapper to handle the backend loadable JSON config implementations.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
public abstract class LoadableJSONConfigWrapper extends JSONConfigWrapper implements LoadableConfig { public abstract class LoadableJSONConfigWrapper extends JSONConfigWrapper implements LoadableConfig {
/** /**
* Create a config wrapper. * Create a config wrapper.
@@ -48,4 +55,9 @@ public abstract class LoadableJSONConfigWrapper extends JSONConfigWrapper implem
public String getName() { public String getName() {
return ((LoadableConfig) this.getHandle()).getName(); return ((LoadableConfig) this.getHandle()).getName();
} }
@Override
public @Nullable YamlConfiguration getBukkitHandle() {
return null;
}
} }

View File

@@ -23,10 +23,14 @@ import java.lang.annotation.Target;
* <p> * <p>
* The second: * The second:
* <pre>{@code * <pre>{@code
* public static void update(EcoPlugin plugin) {} * public static void update(EcoPlugin plugin) {
* // Update code * // Update code
* }
* }</pre> * }</pre>
* <p> * <p>
* If using kotlin, you have to annotate the method with {@code @JvmStatic}
* in order to prevent null pointer exceptions.
* <p>
* Config update methods in all classes in a plugin jar will be called * Config update methods in all classes in a plugin jar will be called
* on reload. * on reload.
* <p> * <p>

View File

@@ -1,9 +1,12 @@
package com.willfp.eco.core.config.wrapper; package com.willfp.eco.core.config.wrapper;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.PluginLike; import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.Config; import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.config.interfaces.JSONConfig; import com.willfp.eco.core.config.interfaces.LoadableConfig;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Map; import java.util.Map;
@@ -11,6 +14,8 @@ import java.util.Map;
/** /**
* Internal component to create backend config implementations. * Internal component to create backend config implementations.
*/ */
@ApiStatus.Internal
@Eco.HandlerComponent
public interface ConfigFactory { public interface ConfigFactory {
/** /**
* Updatable config. * Updatable config.
@@ -20,75 +25,57 @@ public interface ConfigFactory {
* @param subDirectoryPath The subdirectory path. * @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource. * @param source The class that owns the resource.
* @param removeUnused Whether keys not present in the default config should be removed on update. * @param removeUnused Whether keys not present in the default config should be removed on update.
* @param type The config type.
* @param updateBlacklist Substring of keys to not add/remove keys for. * @param updateBlacklist Substring of keys to not add/remove keys for.
* @return The config implementation. * @return The config implementation.
*/ */
Config createUpdatableYamlConfig(@NotNull String configName, LoadableConfig createUpdatableConfig(@NotNull String configName,
@NotNull PluginLike plugin,
@NotNull String subDirectoryPath,
@NotNull Class<?> source,
boolean removeUnused,
@NotNull String... updateBlacklist);
/**
* Updatable config.
*
* @param configName The name of the config
* @param plugin The plugin.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param updateBlacklist Substring of keys to not add/remove keys for.
* @return The config implementation.
*/
JSONConfig createUpdatableJSONConfig(@NotNull String configName,
@NotNull PluginLike plugin, @NotNull PluginLike plugin,
@NotNull String subDirectoryPath, @NotNull String subDirectoryPath,
@NotNull Class<?> source, @NotNull Class<?> source,
boolean removeUnused, boolean removeUnused,
@NotNull ConfigType type,
@NotNull String... updateBlacklist); @NotNull String... updateBlacklist);
/** /**
* JSON loadable config. * Loadable config.
* *
* @param configName The name of the config * @param configName The name of the config
* @param plugin The plugin. * @param plugin The plugin.
* @param subDirectoryPath The subdirectory path. * @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource. * @param source The class that owns the resource.
* @param type The config type.
* @return The config implementation. * @return The config implementation.
*/ */
JSONConfig createLoadableJSONConfig(@NotNull String configName, LoadableConfig createLoadableConfig(@NotNull String configName,
@NotNull PluginLike plugin, @NotNull PluginLike plugin,
@NotNull String subDirectoryPath, @NotNull String subDirectoryPath,
@NotNull Class<?> source); @NotNull Class<?> source,
@NotNull ConfigType type);
/** /**
* Yaml loadable config. * Create config.
*
* @param configName The name of the config
* @param plugin The plugin.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
* @return The config implementation.
*/
Config createLoadableYamlConfig(@NotNull String configName,
@NotNull PluginLike plugin,
@NotNull String subDirectoryPath,
@NotNull Class<?> source);
/**
* Yaml config.
* *
* @param config The handle. * @param config The handle.
* @return The config implementation. * @return The config implementation.
*/ */
Config createYamlConfig(@NotNull YamlConfiguration config); Config createConfig(@NotNull YamlConfiguration config);
/** /**
* JSON config. * Create config.
* *
* @param values The values. * @param values The values.
* @return The config implementation. * @return The config implementation.
*/ */
JSONConfig createJSONConfig(@NotNull Map<String, Object> values); Config createConfig(@NotNull Map<String, Object> values);
/**
* Create config.
*
* @param contents The file contents.
* @param type The type.
* @return The config implementation.
*/
Config createConfig(@NotNull String contents,
@NotNull ConfigType type);
} }

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.config.wrapper; package com.willfp.eco.core.config.wrapper;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.Config; import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.util.StringUtils; import com.willfp.eco.util.StringUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -15,6 +16,7 @@ import java.util.List;
* *
* @param <T> The type of the handle. * @param <T> The type of the handle.
*/ */
@SuppressWarnings("MethodDoesntCallSuperMethod")
public abstract class ConfigWrapper<T extends Config> implements Config { public abstract class ConfigWrapper<T extends Config> implements Config {
/** /**
* Configs from eco have an internal implementation, * Configs from eco have an internal implementation,
@@ -68,70 +70,31 @@ public abstract class ConfigWrapper<T extends Config> implements Config {
handle.set(path, object); handle.set(path, object);
} }
@Override
public @NotNull Config getSubsection(@NotNull final String path) {
return handle.getSubsection(path);
}
@Override @Override
public @Nullable Config getSubsectionOrNull(@NotNull final String path) { public @Nullable Config getSubsectionOrNull(@NotNull final String path) {
return handle.getSubsectionOrNull(path); return handle.getSubsectionOrNull(path);
} }
@Override
public int getInt(@NotNull final String path) {
return handle.getInt(path);
}
@Override @Override
public @Nullable Integer getIntOrNull(@NotNull final String path) { public @Nullable Integer getIntOrNull(@NotNull final String path) {
return handle.getIntOrNull(path); return handle.getIntOrNull(path);
} }
@Override
public int getInt(@NotNull final String path,
final int def) {
return handle.getInt(path, def);
}
@Override
public @NotNull List<Integer> getInts(@NotNull final String path) {
return handle.getInts(path);
}
@Override @Override
public @Nullable List<Integer> getIntsOrNull(@NotNull final String path) { public @Nullable List<Integer> getIntsOrNull(@NotNull final String path) {
return handle.getIntsOrNull(path); return handle.getIntsOrNull(path);
} }
@Override
public boolean getBool(@NotNull final String path) {
return handle.getBool(path);
}
@Override @Override
public @Nullable Boolean getBoolOrNull(@NotNull final String path) { public @Nullable Boolean getBoolOrNull(@NotNull final String path) {
return handle.getBoolOrNull(path); return handle.getBoolOrNull(path);
} }
@Override
public @NotNull List<Boolean> getBools(@NotNull final String path) {
return handle.getBools(path);
}
@Override @Override
public @Nullable List<Boolean> getBoolsOrNull(@NotNull final String path) { public @Nullable List<Boolean> getBoolsOrNull(@NotNull final String path) {
return handle.getBoolsOrNull(path); return handle.getBoolsOrNull(path);
} }
@Override
public @NotNull String getString(@NotNull final String path,
final boolean format,
@NotNull final StringUtils.FormatOption option) {
return handle.getString(path, format, option);
}
@Override @Override
public @Nullable String getStringOrNull(@NotNull final String path, public @Nullable String getStringOrNull(@NotNull final String path,
final boolean format, final boolean format,
@@ -139,13 +102,6 @@ public abstract class ConfigWrapper<T extends Config> implements Config {
return handle.getStringOrNull(path, format, option); return handle.getStringOrNull(path, format, option);
} }
@Override
public @NotNull List<String> getStrings(@NotNull final String path,
final boolean format,
@NotNull final StringUtils.FormatOption option) {
return handle.getStrings(path, format, option);
}
@Override @Override
public @Nullable List<String> getStringsOrNull(@NotNull final String path, public @Nullable List<String> getStringsOrNull(@NotNull final String path,
final boolean format, final boolean format,
@@ -153,31 +109,31 @@ public abstract class ConfigWrapper<T extends Config> implements Config {
return handle.getStringsOrNull(path, format, option); return handle.getStringsOrNull(path, format, option);
} }
@Override
public double getDouble(@NotNull final String path) {
return handle.getDouble(path);
}
@Override @Override
public @Nullable Double getDoubleOrNull(@NotNull final String path) { public @Nullable Double getDoubleOrNull(@NotNull final String path) {
return handle.getDoubleOrNull(path); return handle.getDoubleOrNull(path);
} }
@Override
public @NotNull List<Double> getDoubles(@NotNull final String path) {
return handle.getDoubles(path);
}
@Override @Override
public @Nullable List<Double> getDoublesOrNull(@NotNull final String path) { public @Nullable List<Double> getDoublesOrNull(@NotNull final String path) {
return handle.getDoublesOrNull(path); return handle.getDoublesOrNull(path);
} }
@Override
public @Nullable List<? extends Config> getSubsectionsOrNull(@NotNull final String path) {
return handle.getSubsectionsOrNull(path);
}
@Override @Override
public Config clone() { public Config clone() {
return handle.clone(); return handle.clone();
} }
@Override
public @NotNull ConfigType getType() {
return handle.getType();
}
/** /**
* Get the handle. * Get the handle.
* *

View File

@@ -0,0 +1,53 @@
package com.willfp.eco.core.config.wrapper;
import com.willfp.eco.core.config.interfaces.LoadableConfig;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
/**
* Wrapper to handle the backend loadable yaml config implementations.
*/
public abstract class LoadableConfigWrapper extends ConfigWrapper<LoadableConfig> implements LoadableConfig {
/**
* Create a config wrapper.
*
* @param handle The handle.
*/
protected LoadableConfigWrapper(@NotNull final LoadableConfig handle) {
super(handle);
}
@Override
public void createFile() {
this.getHandle().createFile();
}
@Override
public String getResourcePath() {
return this.getHandle().getResourcePath();
}
@Override
public void save() throws IOException {
this.getHandle().save();
}
@Override
public File getConfigFile() {
return this.getHandle().getConfigFile();
}
@Override
public String getName() {
return this.getHandle().getName();
}
@Override
public @Nullable YamlConfiguration getBukkitHandle() {
return this.getHandle().getBukkitHandle();
}
}

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.core.config.yaml;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginLike; import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.yaml.wrapper.LoadableYamlConfigWrapper; import com.willfp.eco.core.config.yaml.wrapper.LoadableYamlConfigWrapper;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -10,7 +11,12 @@ import org.jetbrains.annotations.NotNull;
* Config implementation for configs present in the plugin's base directory (eg config.yml, lang.yml). * Config implementation for configs present in the plugin's base directory (eg config.yml, lang.yml).
* <p> * <p>
* Automatically updates. * Automatically updates.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
public abstract class YamlBaseConfig extends LoadableYamlConfigWrapper { public abstract class YamlBaseConfig extends LoadableYamlConfigWrapper {
/** /**
* @param configName The name of the config * @param configName The name of the config
@@ -23,12 +29,14 @@ public abstract class YamlBaseConfig extends LoadableYamlConfigWrapper {
@NotNull final PluginLike plugin, @NotNull final PluginLike plugin,
@NotNull final String... updateBlacklist) { @NotNull final String... updateBlacklist) {
super( super(
Eco.getHandler().getConfigFactory().createUpdatableYamlConfig( Eco.getHandler().getConfigFactory().createUpdatableConfig(
configName, configName,
plugin, plugin,
"", "",
plugin.getClass(), plugin.getClass(),
removeUnused, updateBlacklist removeUnused,
ConfigType.YAML,
updateBlacklist
) )
); );
} }
@@ -42,12 +50,13 @@ public abstract class YamlBaseConfig extends LoadableYamlConfigWrapper {
final boolean removeUnused, final boolean removeUnused,
@NotNull final PluginLike plugin) { @NotNull final PluginLike plugin) {
super( super(
Eco.getHandler().getConfigFactory().createUpdatableYamlConfig( Eco.getHandler().getConfigFactory().createUpdatableConfig(
configName, configName,
plugin, plugin,
"", "",
plugin.getClass(), plugin.getClass(),
removeUnused removeUnused,
ConfigType.YAML
) )
); );
} }

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.core.config.yaml;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginLike; import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.yaml.wrapper.LoadableYamlConfigWrapper; import com.willfp.eco.core.config.yaml.wrapper.LoadableYamlConfigWrapper;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -14,7 +15,12 @@ import org.jetbrains.annotations.NotNull;
* </ul> * </ul>
* <p> * <p>
* Automatically updates. * Automatically updates.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
public abstract class YamlExtendableConfig extends LoadableYamlConfigWrapper { public abstract class YamlExtendableConfig extends LoadableYamlConfigWrapper {
/** /**
* @param configName The name of the config * @param configName The name of the config
@@ -31,16 +37,18 @@ public abstract class YamlExtendableConfig extends LoadableYamlConfigWrapper {
@NotNull final String subDirectoryPath, @NotNull final String subDirectoryPath,
@NotNull final String... updateBlacklist) { @NotNull final String... updateBlacklist) {
super( super(
Eco.getHandler().getConfigFactory().createUpdatableYamlConfig( Eco.getHandler().getConfigFactory().createUpdatableConfig(
configName, configName,
plugin, plugin,
subDirectoryPath, subDirectoryPath,
source, source,
removeUnused, removeUnused,
ConfigType.YAML,
updateBlacklist updateBlacklist
) )
); );
} }
/** /**
* @param configName The name of the config * @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update. * @param removeUnused Whether keys not present in the default config should be removed on update.

View File

@@ -3,12 +3,18 @@ package com.willfp.eco.core.config.yaml;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginLike; import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.yaml.wrapper.LoadableYamlConfigWrapper; import com.willfp.eco.core.config.yaml.wrapper.LoadableYamlConfigWrapper;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Non-updatable yaml config that exists within a plugin jar. * Non-updatable yaml config that exists within a plugin jar.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
public abstract class YamlStaticBaseConfig extends LoadableYamlConfigWrapper { public abstract class YamlStaticBaseConfig extends LoadableYamlConfigWrapper {
/** /**
* Config implementation for configs present in the plugin's base directory (eg config.yml, lang.yml). * Config implementation for configs present in the plugin's base directory (eg config.yml, lang.yml).
@@ -20,7 +26,7 @@ public abstract class YamlStaticBaseConfig extends LoadableYamlConfigWrapper {
*/ */
protected YamlStaticBaseConfig(@NotNull final String configName, protected YamlStaticBaseConfig(@NotNull final String configName,
@NotNull final PluginLike plugin) { @NotNull final PluginLike plugin) {
super(Eco.getHandler().getConfigFactory().createLoadableYamlConfig(configName, plugin, "", plugin.getClass())); super(Eco.getHandler().getConfigFactory().createLoadableConfig(configName, plugin, "", plugin.getClass(), ConfigType.YAML));
} }
/** /**

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.core.config.yaml; package com.willfp.eco.core.config.yaml;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.yaml.wrapper.YamlConfigWrapper; import com.willfp.eco.core.config.yaml.wrapper.YamlConfigWrapper;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -11,19 +12,31 @@ import java.io.StringReader;
* Config implementation for passing YamlConfigurations. * Config implementation for passing YamlConfigurations.
* <p> * <p>
* Does not automatically update. * Does not automatically update.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
public class YamlTransientConfig extends YamlConfigWrapper { public class YamlTransientConfig extends YamlConfigWrapper {
/** /**
* @param config The YamlConfiguration handle. * @param config The YamlConfiguration handle.
*/ */
public YamlTransientConfig(@NotNull final YamlConfiguration config) { public YamlTransientConfig(@NotNull final YamlConfiguration config) {
super(Eco.getHandler().getConfigFactory().createYamlConfig(config)); super(Eco.getHandler().getConfigFactory().createConfig(config));
} }
/** /**
* @param contents The contents of the config. * @param contents The contents of the config.
*/ */
public YamlTransientConfig(@NotNull final String contents) { public YamlTransientConfig(@NotNull final String contents) {
super(Eco.getHandler().getConfigFactory().createYamlConfig(YamlConfiguration.loadConfiguration(new StringReader(contents)))); super(Eco.getHandler().getConfigFactory().createConfig(contents, ConfigType.YAML));
}
/**
* Create a new empty transient config.
*/
public YamlTransientConfig() {
super(Eco.getHandler().getConfigFactory().createConfig(YamlConfiguration.loadConfiguration(new StringReader(""))));
} }
} }

View File

@@ -3,14 +3,21 @@ package com.willfp.eco.core.config.yaml.wrapper;
import com.willfp.eco.core.config.interfaces.Config; import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.config.interfaces.LoadableConfig; import com.willfp.eco.core.config.interfaces.LoadableConfig;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
/** /**
* Wrapper to handle the backend loadable yaml config implementations. * Wrapper to handle the backend loadable yaml config implementations.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
public abstract class LoadableYamlConfigWrapper extends YamlConfigWrapper implements LoadableConfig { public abstract class LoadableYamlConfigWrapper extends YamlConfigWrapper implements LoadableConfig {
/** /**
* Create a config wrapper. * Create a config wrapper.
@@ -48,4 +55,9 @@ public abstract class LoadableYamlConfigWrapper extends YamlConfigWrapper implem
public String getName() { public String getName() {
return ((LoadableConfig) this.getHandle()).getName(); return ((LoadableConfig) this.getHandle()).getName();
} }
@Override
public @Nullable YamlConfiguration getBukkitHandle() {
return ((LoadableConfig) this.getHandle()).getBukkitHandle();
}
} }

View File

@@ -8,7 +8,12 @@ import org.jetbrains.annotations.NotNull;
/** /**
* Wrapper to handle the backend yaml config implementations. * Wrapper to handle the backend yaml config implementations.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/ */
@Deprecated(since = "6.17.0")
public abstract class YamlConfigWrapper extends ConfigWrapper<Config> implements WrappedYamlConfiguration { public abstract class YamlConfigWrapper extends ConfigWrapper<Config> implements WrappedYamlConfiguration {
/** /**
* Create a config wrapper. * Create a config wrapper.

View File

@@ -1,7 +1,6 @@
package com.willfp.eco.core.data; package com.willfp.eco.core.data;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -12,26 +11,7 @@ import java.util.UUID;
* <p> * <p>
* Profiles save automatically, so there is no need to save after changes. * Profiles save automatically, so there is no need to save after changes.
*/ */
public interface PlayerProfile { public interface PlayerProfile extends Profile {
/**
* 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);
/** /**
* Load a player profile. * Load a player profile.
* *
@@ -51,6 +31,6 @@ public interface PlayerProfile {
*/ */
@NotNull @NotNull
static PlayerProfile load(@NotNull final UUID uuid) { 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; package com.willfp.eco.core.data;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.data.keys.PersistentDataKey; import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Set; import java.util.Set;
import java.util.UUID; 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. * Load a player profile.
* *
@@ -18,6 +22,13 @@ public interface PlayerProfileHandler {
*/ */
PlayerProfile load(@NotNull UUID uuid); PlayerProfile load(@NotNull UUID uuid);
/**
* Load the server profile.
*
* @return The profile.
*/
ServerProfile loadServerProfile();
/** /**
* Unload a player profile from memory. * Unload a player profile from memory.
* <p> * <p>
@@ -37,7 +48,7 @@ public interface PlayerProfileHandler {
*/ */
@Deprecated @Deprecated
default void savePlayer(@NotNull UUID uuid) { 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 uuid The uuid.
* @param keys The keys. * @param keys The keys.
*/ */
void saveKeysForPlayer(@NotNull UUID uuid, void saveKeysFor(@NotNull UUID uuid,
@NotNull Set<PersistentDataKey<?>> keys); @NotNull Set<PersistentDataKey<?>> keys);
/** /**
* Save all player data. * 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

@@ -25,7 +25,7 @@ public class PersistentDataKey<T> {
/** /**
* The persistent data key type. * The persistent data key type.
*/ */
private final PersistentDataKeyType type; private final PersistentDataKeyType<T> type;
/** /**
* Create a new Persistent Data Key. * Create a new Persistent Data Key.
@@ -35,7 +35,7 @@ public class PersistentDataKey<T> {
* @param defaultValue The default value. * @param defaultValue The default value.
*/ */
public PersistentDataKey(@NotNull final NamespacedKey key, public PersistentDataKey(@NotNull final NamespacedKey key,
@NotNull final PersistentDataKeyType type, @NotNull final PersistentDataKeyType<T> type,
@NotNull final T defaultValue) { @NotNull final T defaultValue) {
this.key = key; this.key = key;
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
@@ -53,15 +53,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. * Get the key.
* *
@@ -85,7 +76,16 @@ public class PersistentDataKey<T> {
* *
* @return The key type. * @return The key type.
*/ */
public PersistentDataKeyType getType() { public PersistentDataKeyType<T> getType() {
return this.type; return this.type;
} }
/**
* Get all persistent data keys.
*
* @return The keys.
*/
public static Set<PersistentDataKey<?>> values() {
return Eco.getHandler().getKeyRegistry().getRegisteredKeys();
}
} }

View File

@@ -1,26 +1,108 @@
package com.willfp.eco.core.data.keys; 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. * 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.
*/ */
STRING, public static final PersistentDataKeyType<String> STRING = new PersistentDataKeyType<>(String.class, "STRING");
/** /**
* Boolean. * 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.
*/ */
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

@@ -60,7 +60,7 @@ public final class Display {
* @return The ItemStack. * @return The ItemStack.
*/ */
public static ItemStack displayAndFinalize(@NotNull final ItemStack itemStack, public static ItemStack displayAndFinalize(@NotNull final ItemStack itemStack,
@Nullable final Player player) { @Nullable final Player player) {
return finalize(display(itemStack, player)); return finalize(display(itemStack, player));
} }

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,84 @@
package com.willfp.eco.core.entities;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* A custom entity has 3 components.
*
* <ul>
* <li>The key to identify it</li>
* <li>The test to check if any entity is this custom entity</li>
* <li>The supplier to spawn the custom {@link org.bukkit.entity.Entity}</li>
* </ul>
*/
public class CustomEntity implements TestableEntity {
/**
* The key.
*/
private final NamespacedKey key;
/**
* The test for Entities to pass.
*/
private final Predicate<@NotNull Entity> test;
/**
* The provider to spawn the entity.
*/
private final Function<Location, Entity> provider;
/**
* Create a new custom entity.
*
* @param key The entity key.
* @param test The test.
* @param provider The provider to spawn the entity.
*/
public CustomEntity(@NotNull final NamespacedKey key,
@NotNull final Predicate<@NotNull Entity> test,
@NotNull final Function<Location, Entity> provider) {
this.key = key;
this.test = test;
this.provider = provider;
}
@Override
public boolean matches(@Nullable final Entity entity) {
if (entity == null) {
return false;
}
return test.test(entity);
}
@Override
public Entity spawn(@NotNull final Location location) {
Validate.notNull(location.getWorld());
return provider.apply(location);
}
/**
* Register the entity.
*/
public void register() {
Entities.registerCustomEntity(this.getKey(), this);
}
/**
* Get the key.
*
* @return The key.
*/
public NamespacedKey getKey() {
return this.key;
}
}

View File

@@ -0,0 +1,239 @@
package com.willfp.eco.core.entities;
import com.willfp.eco.core.entities.args.EntityArgParseResult;
import com.willfp.eco.core.entities.args.EntityArgParser;
import com.willfp.eco.core.entities.impl.EmptyTestableEntity;
import com.willfp.eco.core.entities.impl.ModifiedTestableEntity;
import com.willfp.eco.core.entities.impl.SimpleTestableEntity;
import com.willfp.eco.util.NamespacedKeyUtils;
import com.willfp.eco.util.StringUtils;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/**
* Class to manage all custom and vanilla entities.
*/
public final class Entities {
/**
* All entities.
*/
private static final Map<NamespacedKey, TestableEntity> REGISTRY = new ConcurrentHashMap<>();
/**
* All entity parsers.
*/
private static final List<EntityArgParser> ARG_PARSERS = new ArrayList<>();
/**
* Register a new custom item.
*
* @param key The key of the item.
* @param item The item.
*/
public static void registerCustomEntity(@NotNull final NamespacedKey key,
@NotNull final TestableEntity item) {
REGISTRY.put(key, item);
}
/**
* Register a new arg parser.
*
* @param parser The parser.
*/
public static void registerArgParser(@NotNull final EntityArgParser parser) {
ARG_PARSERS.add(parser);
}
/**
* Remove an entity.
*
* @param key The key of the entity.
*/
public static void removeCustomEntity(@NotNull final NamespacedKey key) {
REGISTRY.remove(key);
}
/**
* This is the backbone of the entire eco entity system.
* <p>
* You can look up a TestableEntity for any type or custom entity,
* and it will return it with any modifiers passed as parameters.
* <p>
* If you want to get an Entity instance from this, then just call
* {@link TestableEntity#spawn(Location)}.
* <p>
* The advantages of the testable entity system are that there is the inbuilt
* {@link TestableEntity#matches(Entity)} - this allows to check if any entity
* is that testable entity; which may sound negligible, but actually it allows for
* much more power and flexibility. For example, you can have an entity with an
* extra metadata tag, extra lore lines, different display name - and it
* will still work as long as the test passes.
*
* @param key The lookup string.
* @return The testable entity, or an empty testable entity if not found.
*/
@NotNull
public static TestableEntity lookup(@NotNull final String key) {
if (key.contains("?")) {
String[] options = key.split("\\?");
for (String option : options) {
TestableEntity lookup = lookup(option);
if (!(lookup instanceof EmptyTestableEntity)) {
return lookup;
}
}
return new EmptyTestableEntity();
}
String[] args = StringUtils.parseTokens(key);
if (args.length == 0) {
return new EmptyTestableEntity();
}
TestableEntity entity;
String[] split = args[0].toLowerCase().split(":");
if (split.length == 1) {
EntityType type;
try {
type = EntityType.valueOf(args[0].toUpperCase());
} catch (IllegalArgumentException e) {
return new EmptyTestableEntity();
}
entity = new SimpleTestableEntity(type);
} else {
String namespace = split[0];
String keyID = split[1];
NamespacedKey namespacedKey = NamespacedKeyUtils.create(namespace, keyID);
TestableEntity part = REGISTRY.get(namespacedKey);
if (part == null) {
return new EmptyTestableEntity();
}
entity = part;
}
String[] modifierArgs = Arrays.copyOfRange(args, 1, args.length);
List<EntityArgParseResult> parseResults = new ArrayList<>();
for (EntityArgParser argParser : ARG_PARSERS) {
EntityArgParseResult result = argParser.parseArguments(modifierArgs);
if (result != null) {
parseResults.add(result);
}
}
Function<Location, Entity> spawner = entity::spawn;
if (!parseResults.isEmpty()) {
entity = new ModifiedTestableEntity(
entity,
test -> {
for (EntityArgParseResult parseResult : parseResults) {
if (!parseResult.test().test(test)) {
return false;
}
}
return true;
},
location -> {
Entity spawned = spawner.apply(location);
for (EntityArgParseResult parseResult : parseResults) {
parseResult.modifier().accept(spawned);
}
return spawned;
}
);
}
return entity;
}
/**
* Get a Testable Entity from an ItemStack.
* <p>
* Will search for registered entity first. If there are no matches in the registry,
* then it will return a {@link com.willfp.eco.core.entities.impl.SimpleTestableEntity} matching the entity type.
* <p>
* If the entity is not custom and has unknown type, this will return null.
*
* @param entity The Entity.
* @return The found Testable Entity.
*/
@Nullable
public static TestableEntity getEntity(@Nullable final Entity entity) {
if (entity == null) {
return null;
}
TestableEntity customEntity = getEntity(entity);
if (customEntity != null) {
return customEntity;
}
for (TestableEntity known : REGISTRY.values()) {
if (known.matches(entity)) {
return known;
}
}
if (entity.getType() == EntityType.UNKNOWN) {
return null;
}
return new SimpleTestableEntity(entity.getType());
}
/**
* Get if entity is a custom entity.
*
* @param entity The entity to check.
* @return If is custom.
*/
public static boolean isCustomEntity(@NotNull final Entity entity) {
for (TestableEntity testable : REGISTRY.values()) {
if (testable.matches(entity)) {
return true;
}
}
return false;
}
/**
* Get all registered custom items.
*
* @return A set of all items.
*/
public static Set<TestableEntity> getCustomEntities() {
return new HashSet<>(REGISTRY.values());
}
private Entities() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}

View File

@@ -0,0 +1,27 @@
package com.willfp.eco.core.entities;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* An item with a test to see if any item is that item.
*/
public interface TestableEntity {
/**
* If an Entity matches the test.
*
* @param entity The entity to test.
* @return If the entity matches.
*/
boolean matches(@Nullable Entity entity);
/**
* Spawn the entity.
*
* @param location The location.
* @return The entity.
*/
Entity spawn(@NotNull Location location);
}

View File

@@ -0,0 +1,33 @@
package com.willfp.eco.core.entities.args;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* @param test The test for the entity.
* @param modifier The modifier to apply to the entity.
* @see EntityArgParser
*/
public record EntityArgParseResult(@NotNull Predicate<Entity> test,
@NotNull Consumer<Entity> modifier) {
/**
* Kotlin destructuring support.
*
* @return The test.
*/
public Predicate<Entity> component1() {
return test;
}
/**
* Kotlin destructuring support.
*
* @return The modifier.
*/
public Consumer<Entity> component2() {
return modifier;
}
}

View File

@@ -0,0 +1,20 @@
package com.willfp.eco.core.entities.args;
import com.willfp.eco.core.entities.TestableEntity;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* An argument parser should generate the predicate as well
* as modify the Entity for {@link TestableEntity#spawn(Location)}.
*/
public interface EntityArgParser {
/**
* Parse the arguments.
*
* @param args The arguments.
* @return The predicate test to apply to the modified entity.
*/
@Nullable EntityArgParseResult parseArguments(@NotNull String[] args);
}

View File

@@ -0,0 +1,33 @@
package com.willfp.eco.core.entities.impl;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.entities.TestableEntity;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Empty entity.
*/
public class EmptyTestableEntity implements TestableEntity {
/**
* Create a new empty testable entity.
*/
public EmptyTestableEntity() {
}
@Override
public boolean matches(@Nullable final Entity entity) {
return false;
}
@Override
public Entity spawn(@NotNull final Location location) {
Validate.notNull(location.getWorld());
return Eco.getHandler().createDummyEntity(location);
}
}

View File

@@ -0,0 +1,69 @@
package com.willfp.eco.core.entities.impl;
import com.willfp.eco.core.entities.TestableEntity;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* Existing testable entity with an extra filter.
*
* @see com.willfp.eco.core.entities.CustomEntity
*/
public class ModifiedTestableEntity implements TestableEntity {
/**
* The item.
*/
private final TestableEntity handle;
/**
* The amount.
*/
private final Predicate<Entity> test;
/**
* The provider to spawn the entity.
*/
private final Function<Location, Entity> provider;
/**
* Create a new modified testable entity.
*
* @param entity The base entity.
* @param test The test.
* @param provider The provider to spawn the entity.
*/
public ModifiedTestableEntity(@NotNull final TestableEntity entity,
@NotNull final Predicate<@NotNull Entity> test,
@NotNull final Function<Location, Entity> provider) {
this.handle = entity;
this.test = test;
this.provider = provider;
}
@Override
public boolean matches(@Nullable final Entity entity) {
return entity != null && handle.matches(entity) && test.test(entity);
}
@Override
public Entity spawn(@NotNull final Location location) {
Validate.notNull(location.getWorld());
return provider.apply(location);
}
/**
* Get the handle.
*
* @return The handle.
*/
public TestableEntity getHandle() {
return this.handle;
}
}

View File

@@ -0,0 +1,53 @@
package com.willfp.eco.core.entities.impl;
import com.willfp.eco.core.entities.TestableEntity;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Default vanilla entities.
*/
public class SimpleTestableEntity implements TestableEntity {
/**
* The entity type.
*/
private final EntityType type;
/**
* Create a new simple testable entity.
*
* @param type The entity type.
*/
public SimpleTestableEntity(@NotNull final EntityType type) {
this.type = type;
Validate.notNull(type.getEntityClass(), "Entity cannot be of unknown type!");
}
@Override
public boolean matches(@Nullable final Entity entity) {
return entity != null && entity.getType() == type;
}
@Override
public Entity spawn(@NotNull final Location location) {
Validate.notNull(location.getWorld());
assert type.getEntityClass() != null;
return location.getWorld().spawn(location, type.getEntityClass());
}
/**
* Get the type.
*
* @return The type.
*/
public EntityType getType() {
return this.type;
}
}

View File

@@ -0,0 +1,143 @@
package com.willfp.eco.core.events;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* Called on DropQueue push.
*/
public class DropQueuePushEvent extends PlayerEvent implements Cancellable {
/**
* Cancel state.
*/
private boolean cancelled;
/**
* If telekinetic.
*/
private final boolean isTelekinetic;
/**
* The items.
*/
private final Collection<? extends ItemStack> items;
/**
* The xp.
*/
private final int xp;
/**
* The location.
*/
private final Location location;
/**
* Bukkit parity.
*/
private static final HandlerList HANDLERS = new HandlerList();
/**
* Create a new DropQueuePushEvent.
*
* @param player The player.
* @param items The items.
* @param location The location.
* @param xp The xp.
* @param isTelekinetic If the event is telekinetic.
*/
public DropQueuePushEvent(@NotNull final Player player,
@NotNull final Collection<? extends ItemStack> items,
@NotNull final Location location,
final int xp,
final boolean isTelekinetic) {
super(player);
this.items = items;
this.location = location;
this.xp = xp;
this.isTelekinetic = isTelekinetic;
}
/**
* Gets a list of handlers handling this event.
*
* @return A list of handlers handling this event.
*/
@Override
@NotNull
public HandlerList getHandlers() {
return HANDLERS;
}
/**
* Bukkit parity.
*
* @return The handler list.
*/
public static HandlerList getHandlerList() {
return HANDLERS;
}
/**
* Get cancel state.
*
* @return The cancel state.
*/
@Override
public boolean isCancelled() {
return this.cancelled;
}
/**
* Set cancel state.
*
* @param cancelled If cancelled.
*/
@Override
public void setCancelled(final boolean cancelled) {
this.cancelled = cancelled;
}
/**
* Get the items to be dropped.
*
* @return The items.
*/
public Collection<? extends ItemStack> getItems() {
return items;
}
/**
* Get the xp to be dropped.
*
* @return The xp.
*/
public int getXp() {
return xp;
}
/**
* Get the location.
*
* @return The location.
*/
public Location getLocation() {
return location;
}
/**
* Get force telekinesis state.
*
* @return The force telekinesis state.
*/
public boolean isTelekinetic() {
return this.isTelekinetic;
}
}

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.core.events; package com.willfp.eco.core.events;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
/** /**
* Manages listeners for a plugin. * Manages listeners for a plugin.
@@ -11,14 +12,14 @@ public interface EventManager {
* *
* @param listener The listener to register. * @param listener The listener to register.
*/ */
void registerListener(Listener listener); void registerListener(@NotNull Listener listener);
/** /**
* Unregister a listener with bukkit. * Unregister a listener with bukkit.
* *
* @param listener The listener to unregister. * @param listener The listener to unregister.
*/ */
void unregisterListener(Listener listener); void unregisterListener(@NotNull Listener listener);
/** /**
* Unregister all listeners associated with the plugin. * Unregister all listeners associated with the plugin.

View File

@@ -7,6 +7,7 @@ import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.File; import java.io.File;
import java.util.logging.Logger;
/** /**
* An extension is a separate jar file that hooks into the base plugin jar. * An extension is a separate jar file that hooks into the base plugin jar.
@@ -143,6 +144,11 @@ public abstract class Extension implements PluginLike {
return this.plugin.getConfigHandler(); return this.plugin.getConfigHandler();
} }
@Override
public Logger getLogger() {
return this.plugin.getLogger();
}
/** /**
* Get the plugin for the extension. * Get the plugin for the extension.
* *

View File

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

View File

@@ -1,7 +1,13 @@
package com.willfp.eco.core.integrations; package com.willfp.eco.core.integrations;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
/** /**
* An integration loader runs a runnable only if a specific plugin is present on the server. * An integration loader runs a runnable only if a specific plugin is present on the server.
* <p> * <p>
@@ -9,7 +15,15 @@ import org.jetbrains.annotations.NotNull;
*/ */
public class IntegrationLoader { public class IntegrationLoader {
/** /**
* The lambda to be ran if the plugin is present. * All loaded plugins on the server.
*/
private static final Set<String> LOADED_PLUGINS = Arrays.stream(Bukkit.getPluginManager().getPlugins())
.map(Plugin::getName)
.map(String::toLowerCase)
.collect(Collectors.toSet());
/**
* The lambda to be run if the plugin is present.
*/ */
private final Runnable runnable; private final Runnable runnable;
@@ -22,7 +36,7 @@ public class IntegrationLoader {
* Create a new Integration Loader. * Create a new Integration Loader.
* *
* @param pluginName The plugin to require. * @param pluginName The plugin to require.
* @param onLoad The lambda to be ran if the plugin is present. * @param onLoad The lambda to be run if the plugin is present.
*/ */
public IntegrationLoader(@NotNull final String pluginName, public IntegrationLoader(@NotNull final String pluginName,
@NotNull final Runnable onLoad) { @NotNull final Runnable onLoad) {
@@ -30,6 +44,15 @@ public class IntegrationLoader {
this.pluginName = pluginName; this.pluginName = pluginName;
} }
/**
* Load the integration if the specified plugin is present on the server.
*/
public void loadIfPresent() {
if (LOADED_PLUGINS.contains(this.pluginName.toLowerCase())) {
this.load();
}
}
/** /**
* Load the integration. * Load the integration.
*/ */

View File

@@ -24,7 +24,7 @@ public final class AnticheatManager {
* @param anticheat The anticheat to register. * @param anticheat The anticheat to register.
*/ */
public static void register(@NotNull final EcoPlugin plugin, public static void register(@NotNull final EcoPlugin plugin,
@NotNull final AnticheatWrapper anticheat) { @NotNull final AnticheatWrapper anticheat) {
if (anticheat instanceof Listener) { if (anticheat instanceof Listener) {
plugin.getEventManager().registerListener((Listener) anticheat); plugin.getEventManager().registerListener((Listener) anticheat);
} }

View File

@@ -37,6 +37,17 @@ public final class AntigriefManager {
REGISTERED.remove(antigrief); REGISTERED.remove(antigrief);
} }
/**
* Can player pickup item.
*
* @param player The player.
* @param location The location.
* @return If player can pick up item.
*/
public static boolean canPickupItem(@NotNull final Player player, @NotNull final Location location) {
return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canPickupItem(player, location));
}
/** /**
* Can player break block. * Can player break block.
* *
@@ -45,7 +56,7 @@ public final class AntigriefManager {
* @return If player can break block. * @return If player can break block.
*/ */
public static boolean canBreakBlock(@NotNull final Player player, public static boolean canBreakBlock(@NotNull final Player player,
@NotNull final Block block) { @NotNull final Block block) {
return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canBreakBlock(player, block)); return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canBreakBlock(player, block));
} }
@@ -57,7 +68,7 @@ public final class AntigriefManager {
* @return If player can create explosion. * @return If player can create explosion.
*/ */
public static boolean canCreateExplosion(@NotNull final Player player, public static boolean canCreateExplosion(@NotNull final Player player,
@NotNull final Location location) { @NotNull final Location location) {
return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canCreateExplosion(player, location)); return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canCreateExplosion(player, location));
} }
@@ -69,7 +80,7 @@ public final class AntigriefManager {
* @return If player can place block. * @return If player can place block.
*/ */
public static boolean canPlaceBlock(@NotNull final Player player, public static boolean canPlaceBlock(@NotNull final Player player,
@NotNull final Block block) { @NotNull final Block block) {
return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canPlaceBlock(player, block)); return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canPlaceBlock(player, block));
} }
@@ -81,7 +92,7 @@ public final class AntigriefManager {
* @return If player can injure. * @return If player can injure.
*/ */
public static boolean canInjure(@NotNull final Player player, public static boolean canInjure(@NotNull final Player player,
@NotNull final LivingEntity victim) { @NotNull final LivingEntity victim) {
return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canInjure(player, victim)); return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canInjure(player, victim));
} }

View File

@@ -5,6 +5,7 @@ import org.bukkit.Location;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/** /**
* Wrapper class for antigrief integrations. * Wrapper class for antigrief integrations.
@@ -17,7 +18,7 @@ public interface AntigriefWrapper extends Integration {
* @param block The block. * @param block The block.
* @return If player can break block. * @return If player can break block.
*/ */
boolean canBreakBlock(Player player, Block block); boolean canBreakBlock(@NotNull Player player, @NotNull Block block);
/** /**
* Can player create explosion at location. * Can player create explosion at location.
@@ -26,7 +27,7 @@ public interface AntigriefWrapper extends Integration {
* @param location The location. * @param location The location.
* @return If player can create explosion. * @return If player can create explosion.
*/ */
boolean canCreateExplosion(Player player, Location location); boolean canCreateExplosion(@NotNull Player player, @NotNull Location location);
/** /**
* Can player place block. * Can player place block.
@@ -35,7 +36,7 @@ public interface AntigriefWrapper extends Integration {
* @param block The block. * @param block The block.
* @return If player can place block. * @return If player can place block.
*/ */
boolean canPlaceBlock(Player player, Block block); boolean canPlaceBlock(@NotNull Player player, @NotNull Block block);
/** /**
* Can player injure living entity. * Can player injure living entity.
@@ -44,5 +45,16 @@ public interface AntigriefWrapper extends Integration {
* @param victim The victim. * @param victim The victim.
* @return If player can injure. * @return If player can injure.
*/ */
boolean canInjure(Player player, LivingEntity victim); boolean canInjure(@NotNull Player player, @NotNull LivingEntity victim);
/**
* Can player pick up item.
*
* @param player The player.
* @param location The location.
* @return If player can pick up item.
*/
default boolean canPickupItem(@NotNull Player player, @NotNull Location location) {
return true;
}
} }

View File

@@ -0,0 +1,40 @@
package com.willfp.eco.core.integrations.customentities;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
/**
* Class to handle custom entity integrations.
*/
public final class CustomEntitiesManager {
/**
* A set of all registered integrations.
*/
private static final Set<CustomEntitiesWrapper> REGISTERED = new HashSet<>();
/**
* Register a new integration.
*
* @param integration The integration to register.
*/
public static void register(@NotNull final CustomEntitiesWrapper integration) {
REGISTERED.add(integration);
}
/**
* Register all the custom entities for a specific plugin into eco.
*
* @see com.willfp.eco.core.entities.Entities
*/
public static void registerAllEntities() {
for (CustomEntitiesWrapper wrapper : REGISTERED) {
wrapper.registerAllEntities();
}
}
private CustomEntitiesManager() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}

View File

@@ -0,0 +1,15 @@
package com.willfp.eco.core.integrations.customentities;
import com.willfp.eco.core.integrations.Integration;
/**
* Wrapper class for custom item integrations.
*/
public interface CustomEntitiesWrapper extends Integration {
/**
* Register all the custom entities for a specific plugin into eco.
*
* @see com.willfp.eco.core.entities.Entities
*/
void registerAllEntities();
}

View File

@@ -41,7 +41,7 @@ public final class EconomyManager {
* @return If the player has the amount. * @return If the player has the amount.
*/ */
public static boolean hasAmount(@NotNull final OfflinePlayer player, public static boolean hasAmount(@NotNull final OfflinePlayer player,
final double amount) { final double amount) {
for (EconomyWrapper wrapper : REGISTERED) { for (EconomyWrapper wrapper : REGISTERED) {
return wrapper.hasAmount(player, amount); return wrapper.hasAmount(player, amount);
} }
@@ -57,7 +57,7 @@ public final class EconomyManager {
* @return If the transaction was a success. * @return If the transaction was a success.
*/ */
public static boolean giveMoney(@NotNull final OfflinePlayer player, public static boolean giveMoney(@NotNull final OfflinePlayer player,
final double amount) { final double amount) {
for (EconomyWrapper wrapper : REGISTERED) { for (EconomyWrapper wrapper : REGISTERED) {
return wrapper.giveMoney(player, amount); return wrapper.giveMoney(player, amount);
} }
@@ -73,7 +73,7 @@ public final class EconomyManager {
* @return If the transaction was a success. * @return If the transaction was a success.
*/ */
public static boolean removeMoney(@NotNull final OfflinePlayer player, public static boolean removeMoney(@NotNull final OfflinePlayer player,
final double amount) { final double amount) {
for (EconomyWrapper wrapper : REGISTERED) { for (EconomyWrapper wrapper : REGISTERED) {
return wrapper.removeMoney(player, amount); return wrapper.removeMoney(player, amount);
} }

View File

@@ -33,7 +33,7 @@ public final class HologramManager {
* @return The hologram. * @return The hologram.
*/ */
public static Hologram createHologram(@NotNull final Location location, public static Hologram createHologram(@NotNull final Location location,
@NotNull final List<String> contents) { @NotNull final List<String> contents) {
for (HologramWrapper wrapper : REGISTERED) { for (HologramWrapper wrapper : REGISTERED) {
return wrapper.createHologram(location, contents); return wrapper.createHologram(location, contents);
} }

View File

@@ -1,10 +1,12 @@
package com.willfp.eco.core.integrations.placeholder; package com.willfp.eco.core.integrations.placeholder;
import com.willfp.eco.core.EcoPlugin;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
/** /**
@@ -28,12 +30,20 @@ public class PlaceholderEntry {
*/ */
private final boolean requiresPlayer; private final boolean requiresPlayer;
/**
* The plugin for the placeholder.
*/
@Nullable
private final EcoPlugin plugin;
/** /**
* Create a placeholder entry that doesn't require a player. * Create a placeholder entry that doesn't require a player.
* *
* @param identifier The identifier of the placeholder. * @param identifier The identifier of the placeholder.
* @param function A lambda to get the result of the placeholder given a player. * @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, public PlaceholderEntry(@NotNull final String identifier,
@NotNull final Function<Player, String> function) { @NotNull final Function<Player, String> function) {
this(identifier, function, false); this(identifier, function, false);
@@ -45,10 +55,41 @@ public class PlaceholderEntry {
* @param identifier The identifier of the placeholder. * @param identifier The identifier of the placeholder.
* @param function A lambda to get the result of the placeholder. * @param function A lambda to get the result of the placeholder.
* @param requiresPlayer If the placeholder requires a player. * @param requiresPlayer If the placeholder requires a player.
* @deprecated Specify a plugin.
*/ */
@Deprecated
public PlaceholderEntry(@NotNull final String identifier, public PlaceholderEntry(@NotNull final String identifier,
@NotNull final Function<Player, String> function, @NotNull final Function<Player, String> function,
final boolean requiresPlayer) { 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.identifier = identifier;
this.function = function; this.function = function;
this.requiresPlayer = requiresPlayer; this.requiresPlayer = requiresPlayer;
@@ -85,10 +126,37 @@ public class PlaceholderEntry {
return identifier; return identifier;
} }
/**
* Get the plugin.
*
* @return The plugin.
*/
@Nullable
public EcoPlugin getPlugin() {
return plugin;
}
/** /**
* Register the placeholder. * Register the placeholder.
*/ */
public void register() { public void register() {
PlaceholderManager.registerPlaceholder(this); 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.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/** /**
* Wrapper class for placeholder integrations. * Wrapper class for placeholder integrations.
*/ */
@@ -24,4 +27,14 @@ public interface PlaceholderIntegration extends Integration {
*/ */
String translate(@NotNull String text, String translate(@NotNull String text,
@Nullable Player player); @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; 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.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit;
/** /**
* Class to handle placeholder integrations. * Class to handle placeholder integrations.
@@ -16,17 +23,24 @@ public final class PlaceholderManager {
/** /**
* All registered placeholders. * 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. * All registered placeholder integrations.
*/ */
private static final Set<PlaceholderIntegration> REGISTERED_INTEGRATIONS = new HashSet<>(); 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. * 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) { public static void addIntegration(@NotNull final PlaceholderIntegration integration) {
integration.registerIntegration(); integration.registerIntegration();
@@ -36,11 +50,14 @@ public final class PlaceholderManager {
/** /**
* Register a placeholder. * 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) { public static void registerPlaceholder(@NotNull final PlaceholderEntry expansion) {
REGISTERED_PLACEHOLDERS.remove(expansion.getIdentifier()); EcoPlugin plugin = expansion.getPlugin() == null ? Eco.getHandler().getEcoPlugin() : expansion.getPlugin();
REGISTERED_PLACEHOLDERS.put(expansion.getIdentifier(), expansion); 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 player The player to get the result from.
* @param identifier The placeholder identifier. * @param identifier The placeholder identifier.
* @return The value of the placeholder. * @return The value of the placeholder.
* @deprecated Specify a plugin to get the result from.
*/ */
@Deprecated
public static String getResult(@Nullable final Player player, public static String getResult(@Nullable final Player player,
@NotNull final String identifier) { @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) { if (entry == null) {
return ""; return "";
} }
@@ -61,7 +104,7 @@ public final class PlaceholderManager {
return ""; return "";
} }
return entry.getResult(player); return PLACEHOLDER_CACHE.get(new EntryWithPlayer(entry, player));
} }
/** /**
@@ -80,6 +123,26 @@ public final class PlaceholderManager {
return processed; 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() { private PlaceholderManager() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
} }

View File

@@ -66,7 +66,7 @@ public class CustomItem implements TestableItem {
@Override @Override
public ItemStack getItem() { public ItemStack getItem() {
return item; return item.clone();
} }
/** /**

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; 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.args.LookupArgParser;
import com.willfp.eco.core.items.provider.ItemProvider; import com.willfp.eco.core.items.provider.ItemProvider;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem; import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
@@ -8,6 +10,7 @@ import com.willfp.eco.core.recipe.parts.ModifiedTestableItem;
import com.willfp.eco.core.recipe.parts.TestableStack; import com.willfp.eco.core.recipe.parts.TestableStack;
import com.willfp.eco.util.NamespacedKeyUtils; import com.willfp.eco.util.NamespacedKeyUtils;
import com.willfp.eco.util.NumberUtils; import com.willfp.eco.util.NumberUtils;
import com.willfp.eco.util.StringUtils;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@@ -19,8 +22,10 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -33,6 +38,25 @@ public final class Items {
*/ */
private static final Map<NamespacedKey, TestableItem> REGISTRY = new ConcurrentHashMap<>(); 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. * All item providers.
*/ */
@@ -50,7 +74,7 @@ public final class Items {
* @param item The item. * @param item The item.
*/ */
public static void registerCustomItem(@NotNull final NamespacedKey key, public static void registerCustomItem(@NotNull final NamespacedKey key,
@NotNull final TestableItem item) { @NotNull final TestableItem item) {
REGISTRY.put(key, item); REGISTRY.put(key, item);
} }
@@ -84,7 +108,7 @@ public final class Items {
/** /**
* This is the backbone of the entire eco item system. * This is the backbone of the entire eco item system.
* <p> * <p>
* You can lookup a TestableItem for any material, custom item, * You can look up a TestableItem for any material, custom item,
* or item in general, and it will return it with any modifiers * or item in general, and it will return it with any modifiers
* passed as parameters. This includes stack size (item amount) * passed as parameters. This includes stack size (item amount)
* and enchantments that should be present on the item. * and enchantments that should be present on the item.
@@ -94,8 +118,8 @@ public final class Items {
* <p> * <p>
* The advantages of the testable item system are that there is the inbuilt * The advantages of the testable item system are that there is the inbuilt
* {@link TestableItem#matches(ItemStack)} - this allows to check if any item * {@link TestableItem#matches(ItemStack)} - this allows to check if any item
* is that testable item; which may sound negligible but actually it allows for * is that testable item; which may sound negligible, but actually it allows for
* much more power an flexibility. For example, you can have an item with an * much more power and flexibility. For example, you can have an item with an
* extra metadata tag, extra lore lines, different display name - and it * extra metadata tag, extra lore lines, different display name - and it
* will still work as long as the test passes. This is very important * will still work as long as the test passes. This is very important
* for custom crafting recipes where other plugins may add metadata * for custom crafting recipes where other plugins may add metadata
@@ -104,6 +128,7 @@ public final class Items {
* @param key The lookup string. * @param key The lookup string.
* @return The testable item, or an {@link EmptyTestableItem}. * @return The testable item, or an {@link EmptyTestableItem}.
*/ */
@NotNull
public static TestableItem lookup(@NotNull final String key) { public static TestableItem lookup(@NotNull final String key) {
if (key.contains("?")) { if (key.contains("?")) {
String[] options = key.split("\\?"); String[] options = key.split("\\?");
@@ -117,7 +142,8 @@ public final class Items {
return new EmptyTestableItem(); return new EmptyTestableItem();
} }
String[] args = key.split(" "); String[] args = StringUtils.parseTokens(key);
if (args.length == 0) { if (args.length == 0) {
return new EmptyTestableItem(); return new EmptyTestableItem();
} }
@@ -191,7 +217,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) { if (item == null || item instanceof EmptyTestableItem) {
return new EmptyTestableItem(); return new EmptyTestableItem();
} }
@@ -235,6 +261,37 @@ public final class Items {
} }
} }
/**
* Get a Testable Item from an ItemStack.
* <p>
* Will search for registered items first. If there are no matches in the registry,
* then it will return a {@link MaterialTestableItem} matching the item type.
* <p>
* Does not account for modifiers (arg parser data).
*
* @param item The ItemStack.
* @return The found Testable Item.
*/
@NotNull
public static TestableItem getItem(@Nullable final ItemStack item) {
if (item == null || item.getType().isAir()) {
return new EmptyTestableItem();
}
CustomItem customItem = getCustomItem(item);
if (customItem != null) {
return customItem;
}
for (TestableItem known : REGISTRY.values()) {
if (known.matches(item)) {
return known;
}
}
return new MaterialTestableItem(item.getType());
}
/** /**
* Get if itemStack is a custom item. * Get if itemStack is a custom item.
* *
@@ -242,12 +299,7 @@ public final class Items {
* @return If is recipe. * @return If is recipe.
*/ */
public static boolean isCustomItem(@NotNull final ItemStack itemStack) { public static boolean isCustomItem(@NotNull final ItemStack itemStack) {
for (TestableItem item : REGISTRY.values()) { return getCustomItem(itemStack) != null;
if (item.matches(itemStack)) {
return true;
}
}
return false;
} }
/** /**
@@ -258,12 +310,7 @@ public final class Items {
*/ */
@Nullable @Nullable
public static CustomItem getCustomItem(@NotNull final ItemStack itemStack) { public static CustomItem getCustomItem(@NotNull final ItemStack itemStack) {
for (TestableItem item : REGISTRY.values()) { return CACHE.get(HashedItem.of(itemStack)).map(Items::getOrWrap).orElse(null);
if (item.matches(itemStack)) {
return getOrWrap(item);
}
}
return null;
} }
/** /**
@@ -284,6 +331,7 @@ public final class Items {
* @param item The item. * @param item The item.
* @return The CustomItem. * @return The CustomItem.
*/ */
@NotNull
public static CustomItem getOrWrap(@NotNull final TestableItem item) { public static CustomItem getOrWrap(@NotNull final TestableItem item) {
if (item instanceof CustomItem) { if (item instanceof CustomItem) {
return (CustomItem) item; return (CustomItem) item;

View File

@@ -1,57 +0,0 @@
package com.willfp.eco.core.items.args;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
/**
* Parse custom model data.
*/
public class CustomModelDataArgParser implements LookupArgParser {
@Override
public @Nullable Predicate<ItemStack> parseArguments(@NotNull final String[] args,
@NotNull final ItemMeta meta) {
Integer modelData = null;
for (String arg : args) {
String[] argSplit = arg.split(":");
if (!argSplit[0].equalsIgnoreCase("custom-model-data")) {
continue;
}
if (argSplit.length < 2) {
continue;
}
String asString = argSplit[1];
try {
modelData = Integer.parseInt(asString);
} catch (NumberFormatException e) {
modelData = null;
}
}
if (modelData == null) {
return null;
}
meta.setCustomModelData(modelData);
int finalModelData = modelData;
return test -> {
if (!test.hasItemMeta()) {
return false;
}
ItemMeta testMeta = test.getItemMeta();
assert testMeta != null;
return testMeta.getCustomModelData() == finalModelData;
};
}
}

View File

@@ -1,83 +0,0 @@
package com.willfp.eco.core.items.args;
import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
/**
* Parses enchantment arguments.
*/
public class EnchantmentArgParser implements LookupArgParser {
@Override
public @Nullable Predicate<ItemStack> parseArguments(@NotNull final String[] args,
@NotNull final ItemMeta meta) {
Map<Enchantment, Integer> requiredEnchantments = new HashMap<>();
for (String enchantArg : args) {
String[] enchantArgSplit = enchantArg.split(":");
Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(enchantArgSplit[0].toLowerCase()));
if (enchantment == null) {
continue;
}
if (enchantArgSplit.length < 2) {
continue;
}
int level = Integer.parseInt(enchantArgSplit[1]);
requiredEnchantments.put(enchantment, level);
}
if (requiredEnchantments.isEmpty()) {
return null;
}
if (meta instanceof EnchantmentStorageMeta storageMeta) {
requiredEnchantments.forEach((enchantment, integer) -> storageMeta.addStoredEnchant(enchantment, integer, true));
} else {
requiredEnchantments.forEach((enchantment, integer) -> meta.addEnchant(enchantment, integer, true));
}
return test -> {
if (!test.hasItemMeta()) {
return false;
}
ItemMeta testMeta = test.getItemMeta();
assert testMeta != null;
if (testMeta instanceof EnchantmentStorageMeta storageMeta) {
for (Map.Entry<Enchantment, Integer> entry : requiredEnchantments.entrySet()) {
if (!storageMeta.hasStoredEnchant(entry.getKey())) {
return false;
}
if (storageMeta.getStoredEnchantLevel(entry.getKey()) < entry.getValue()) {
return false;
}
}
} else {
for (Map.Entry<Enchantment, Integer> entry : requiredEnchantments.entrySet()) {
if (!testMeta.hasEnchant(entry.getKey())) {
return false;
}
if (testMeta.getEnchantLevel(entry.getKey()) < entry.getValue()) {
return false;
}
}
}
return true;
};
}
}

View File

@@ -1,59 +0,0 @@
package com.willfp.eco.core.items.args;
import com.willfp.eco.util.SkullUtils;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
/**
* Parse skull textures.
*/
public class TextureArgParser implements LookupArgParser {
@Override
public @Nullable Predicate<ItemStack> parseArguments(@NotNull final String[] args,
@NotNull final ItemMeta meta) {
String skullTexture = null;
for (String arg : args) {
String[] argSplit = arg.split(":");
if (!argSplit[0].equalsIgnoreCase("texture")) {
continue;
}
if (argSplit.length < 2) {
continue;
}
skullTexture = argSplit[1];
}
if (meta instanceof SkullMeta skullMeta && skullTexture != null) {
SkullUtils.setSkullTexture(skullMeta, skullTexture);
}
if (skullTexture == null) {
return null;
}
String finalSkullTexture = skullTexture;
return test -> {
if (!test.hasItemMeta()) {
return false;
}
ItemMeta testMeta = test.getItemMeta();
assert testMeta != null;
if (testMeta instanceof SkullMeta skullMeta) {
return finalSkullTexture.equalsIgnoreCase(SkullUtils.getSkullTexture(skullMeta));
}
return true;
};
}
}

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.items.builder; package com.willfp.eco.core.items.builder;
import com.willfp.eco.core.items.TestableItem;
import com.willfp.eco.util.StringUtils; import com.willfp.eco.util.StringUtils;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Material; import org.bukkit.Material;
@@ -43,6 +44,15 @@ public abstract class AbstractItemStackBuilder<T extends ItemMeta, U extends Abs
this(new ItemStack(material)); this(new ItemStack(material));
} }
/**
* Create a new ItemStackBuilder to modify an existing item.
*
* @param item The item to start with.
*/
protected AbstractItemStackBuilder(@NotNull final TestableItem item) {
this(item.getItem());
}
/** /**
* Create a new ItemStackBuilder to modify an existing item. * Create a new ItemStackBuilder to modify an existing item.
* *

View File

@@ -39,7 +39,7 @@ public class EnchantedBookBuilder extends AbstractItemStackBuilder<EnchantmentSt
* @return The builder. * @return The builder.
*/ */
public EnchantedBookBuilder addStoredEnchantment(@NotNull final Supplier<Enchantment> enchantment, public EnchantedBookBuilder addStoredEnchantment(@NotNull final Supplier<Enchantment> enchantment,
final Supplier<Integer> level) { @NotNull final Supplier<Integer> level) {
return this.addStoredEnchantment(enchantment.get(), level.get()); return this.addStoredEnchantment(enchantment.get(), level.get());
} }
} }

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.items.builder; package com.willfp.eco.core.items.builder;
import com.willfp.eco.core.items.TestableItem;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
@@ -26,4 +27,13 @@ public class ItemStackBuilder extends AbstractItemStackBuilder<ItemMeta, ItemSta
public ItemStackBuilder(@NotNull final ItemStack base) { public ItemStackBuilder(@NotNull final ItemStack base) {
super(base); super(base);
} }
/**
* Create a new ItemStackBuilder to modify an existing item.
*
* @param item The item to start with.
*/
public ItemStackBuilder(@NotNull final TestableItem item) {
super(item);
}
} }

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.items.builder; package com.willfp.eco.core.items.builder;
import com.willfp.eco.core.items.TestableItem;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@@ -30,6 +31,15 @@ public class LeatherArmorBuilder extends AbstractItemStackBuilder<LeatherArmorMe
super(base); super(base);
} }
/**
* Create a new ItemStackBuilder to modify an existing item.
*
* @param item The item to start with.
*/
public LeatherArmorBuilder(@NotNull final TestableItem item) {
super(item);
}
/** /**
* Set leather color. * Set leather color.
* *

View File

@@ -1,14 +1,12 @@
package com.willfp.eco.core.proxy; package com.willfp.eco.core.proxy;
/** /**
* All proxies must implement this interface. * Prior to 6.17.0, all proxies were required to implement this interface,
* <p> * however it produced no functionality and was not even used internally.
* A proxy is an NMS implementation of a proxy interface. *
* <p> * @deprecated Unused class, not required. Will be removed in a subsequent release.
* This allows for cross-version support.
* <p>
* See the core-spigot and core-nms modules of eco to see an example.
*/ */
@Deprecated(since = "6.17.0", forRemoval = true)
public interface AbstractProxy { public interface AbstractProxy {
} }

View File

@@ -13,5 +13,5 @@ public interface ProxyFactory {
* @param <T> The proxy class. * @param <T> The proxy class.
* @return The proxy implementation. * @return The proxy implementation.
*/ */
<T extends AbstractProxy> @NotNull T getProxy(@NotNull Class<T> proxyClass); <T> @NotNull T getProxy(@NotNull Class<T> proxyClass);
} }

View File

@@ -6,6 +6,8 @@ import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.items.Items; import com.willfp.eco.core.items.Items;
import com.willfp.eco.core.recipe.recipes.CraftingRecipe; import com.willfp.eco.core.recipe.recipes.CraftingRecipe;
import com.willfp.eco.core.recipe.recipes.ShapedCraftingRecipe; 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.NamespacedKey;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -58,7 +60,10 @@ public final class Recipes {
} }
if (key.getKey().contains("_displayed")) { 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); return RECIPES.get(otherKey);
} }
@@ -79,12 +84,39 @@ public final class Recipes {
@NotNull final String key, @NotNull final String key,
@NotNull final ItemStack output, @NotNull final ItemStack output,
@NotNull final List<String> recipeStrings) { @NotNull final List<String> recipeStrings) {
ShapedCraftingRecipe.Builder builder = ShapedCraftingRecipe.builder(plugin, key).setOutput(output); return createAndRegisterRecipe(plugin, key, output, recipeStrings, null);
}
/**
* Create and register recipe.
*
* @param plugin The plugin.
* @param key The key.
* @param output The output.
* @param recipeStrings The recipe.
* @param permission The permission.
* @return The recipe.
*/
@Nullable
public static CraftingRecipe createAndRegisterRecipe(@NotNull final EcoPlugin plugin,
@NotNull final String key,
@NotNull final ItemStack output,
@NotNull final List<String> recipeStrings,
@Nullable final String permission) {
ShapedCraftingRecipe.Builder builder = ShapedCraftingRecipe.builder(plugin, key)
.setOutput(output)
.setPermission(permission);
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
builder.setRecipePart(i, Items.lookup(recipeStrings.get(i))); 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(); ShapedCraftingRecipe recipe = builder.build();
recipe.register(); recipe.register();

View File

@@ -4,6 +4,7 @@ import com.willfp.eco.core.items.TestableItem;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
@@ -31,6 +32,7 @@ public interface CraftingRecipe {
* *
* @return The parts. * @return The parts.
*/ */
@NotNull
List<TestableItem> getParts(); List<TestableItem> getParts();
/** /**
@@ -38,6 +40,7 @@ public interface CraftingRecipe {
* *
* @return The key. * @return The key.
*/ */
@NotNull
NamespacedKey getKey(); NamespacedKey getKey();
/** /**
@@ -45,6 +48,7 @@ public interface CraftingRecipe {
* *
* @return The key. * @return The key.
*/ */
@NotNull
NamespacedKey getDisplayedKey(); NamespacedKey getDisplayedKey();
/** /**
@@ -52,5 +56,16 @@ public interface CraftingRecipe {
* *
* @return The output. * @return The output.
*/ */
@NotNull
ItemStack getOutput(); ItemStack getOutput();
/**
* Get the recipe permission.
*
* @return The permission.
*/
@Nullable
default String getPermission() {
return null;
}
} }

View File

@@ -15,6 +15,7 @@ import org.bukkit.inventory.RecipeChoice;
import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -44,16 +45,23 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
*/ */
private final ItemStack output; private final ItemStack output;
/**
* The permission.
*/
private final String permission;
private ShapedCraftingRecipe(@NotNull final EcoPlugin plugin, private ShapedCraftingRecipe(@NotNull final EcoPlugin plugin,
@NotNull final String key, @NotNull final String key,
@NotNull final List<TestableItem> parts, @NotNull final List<TestableItem> parts,
@NotNull final ItemStack output) { @NotNull final ItemStack output,
@Nullable final String permission) {
super(plugin); super(plugin);
this.parts = parts; this.parts = parts;
this.key = plugin.getNamespacedKeyFactory().create(key); this.key = plugin.getNamespacedKeyFactory().create(key);
this.displayedKey = plugin.getNamespacedKeyFactory().create(key + "_displayed"); this.displayedKey = plugin.getNamespacedKeyFactory().create(key + "_displayed");
this.output = output; this.output = output;
this.permission = permission;
} }
@Override @Override
@@ -103,7 +111,7 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>(); List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
assert lore != null; assert lore != null;
lore.add(""); lore.add("");
String add = Eco.getHandler().getEcoPlugin().getLangYml().getString("multiple-in-craft"); String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
add = add.replace("%amount%", String.valueOf(item.getAmount())); add = add.replace("%amount%", String.valueOf(item.getAmount()));
lore.add(add); lore.add(add);
meta.setLore(lore); meta.setLore(lore);
@@ -140,6 +148,8 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
* *
* @return The parts. * @return The parts.
*/ */
@NotNull
@Override
public List<TestableItem> getParts() { public List<TestableItem> getParts() {
return this.parts; return this.parts;
} }
@@ -149,6 +159,8 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
* *
* @return The key. * @return The key.
*/ */
@NotNull
@Override
public NamespacedKey getKey() { public NamespacedKey getKey() {
return this.key; return this.key;
} }
@@ -158,6 +170,8 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
* *
* @return The displayed key. * @return The displayed key.
*/ */
@NotNull
@Override
public NamespacedKey getDisplayedKey() { public NamespacedKey getDisplayedKey() {
return this.displayedKey; return this.displayedKey;
} }
@@ -167,10 +181,23 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
* *
* @return The output. * @return The output.
*/ */
@NotNull
@Override
public ItemStack getOutput() { public ItemStack getOutput() {
return this.output; return this.output;
} }
/**
* Get the permission.
*
* @return The permission.
*/
@Nullable
@Override
public String getPermission() {
return permission;
}
/** /**
* Builder for recipes. * Builder for recipes.
*/ */
@@ -185,6 +212,11 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
*/ */
private ItemStack output = null; private ItemStack output = null;
/**
* The permission for the recipe.
*/
private String permission = null;
/** /**
* The key of the recipe. * The key of the recipe.
*/ */
@@ -244,6 +276,31 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
return this; return this;
} }
/**
* Set the permission required to craft the recipe.
*
* @param permission The permission.
* @return The builder.
*/
public Builder setPermission(@Nullable final String permission) {
this.permission = permission;
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. * Build the recipe.
* *
@@ -256,7 +313,7 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
} }
} }
return new ShapedCraftingRecipe(plugin, key.toLowerCase(), recipeParts, output); return new ShapedCraftingRecipe(plugin, key.toLowerCase(), recipeParts, output, permission);
} }
} }
} }

View File

@@ -1,10 +1,14 @@
package com.willfp.eco.core.requirement; package com.willfp.eco.core.requirement;
import com.willfp.eco.core.Eco;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Interface for internal requirement factory implementations. * Interface for internal requirement factory implementations.
*/ */
@ApiStatus.Internal
@Eco.HandlerComponent
public interface RequirementFactory { public interface RequirementFactory {
/** /**
* Create a requirement. * Create a requirement.

View File

@@ -18,6 +18,20 @@ public interface Scheduler {
BukkitTask runLater(@NotNull Runnable runnable, BukkitTask runLater(@NotNull Runnable runnable,
long ticksLater); long ticksLater);
/**
* Run the task after a specified tick delay.
* <p>
* Reordered for better kotlin interop.
*
* @param runnable The lambda to run.
* @param ticksLater The amount of ticks to wait before execution.
* @return The created {@link BukkitTask}.
*/
default BukkitTask runLater(long ticksLater,
@NotNull Runnable runnable) {
return runLater(runnable, ticksLater);
}
/** /**
* Run the task repeatedly on a timer. * Run the task repeatedly on a timer.
* *
@@ -30,6 +44,22 @@ public interface Scheduler {
long delay, long delay,
long repeat); long repeat);
/**
* Run the task repeatedly on a timer.
* <p>
* Reordered for better kotlin interop.
*
* @param runnable The lambda to run.
* @param delay The amount of ticks to wait before the first execution.
* @param repeat The amount of ticks to wait between executions.
* @return The created {@link BukkitTask}.
*/
default BukkitTask runTimer(long delay,
long repeat,
@NotNull Runnable runnable) {
return runTimer(runnable, delay, repeat);
}
/** /**
* Run the task repeatedly and asynchronously on a timer. * Run the task repeatedly and asynchronously on a timer.
* *
@@ -42,6 +72,22 @@ public interface Scheduler {
long delay, long delay,
long repeat); long repeat);
/**
* Run the task repeatedly and asynchronously on a timer.
* <p>
* Reordered for better kotlin interop.
*
* @param runnable The lambda to run.
* @param delay The amount of ticks to wait before the first execution.
* @param repeat The amount of ticks to wait between executions.
* @return The created {@link BukkitTask}.
*/
default BukkitTask runAsyncTimer(long delay,
long repeat,
@NotNull Runnable runnable) {
return runAsyncTimer(runnable, delay, repeat);
}
/** /**
* Run the task. * Run the task.
* *
@@ -70,6 +116,22 @@ public interface Scheduler {
long delay, long delay,
long repeat); long repeat);
/**
* Schedule the task to be ran repeatedly on a timer.
* <p>
* Reordered for better kotlin interop.
*
* @param runnable The lambda to run.
* @param delay The amount of ticks to wait before the first execution.
* @param repeat The amount of ticks to wait between executions.
* @return The id of the task.
*/
default int syncRepeating(long delay,
long repeat,
@NotNull Runnable runnable) {
return syncRepeating(runnable, delay, repeat);
}
/** /**
* Cancel all running tasks from the linked {@link EcoPlugin}. * Cancel all running tasks from the linked {@link EcoPlugin}.
*/ */

View File

@@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -21,8 +22,8 @@ public final class ListUtils {
* @return The list, filled will null objects. * @return The list, filled will null objects.
*/ */
@NotNull @NotNull
public static <@Nullable T> List<List<T>> create2DList(final int rows, public static <T> List<List<T>> create2DList(final int rows,
final int columns) { final int columns) {
List<List<T>> list = new ArrayList<>(rows); List<List<T>> list = new ArrayList<>(rows);
while (list.size() < rows) { while (list.size() < rows) {
List<T> row = new ArrayList<>(columns); List<T> row = new ArrayList<>(columns);
@@ -56,6 +57,58 @@ public final class ListUtils {
return frequencyMap; return frequencyMap;
} }
/**
* Convert nullable object to either singleton list or empty list.
*
* @param object The object.
* @param <T> The type of the object.
* @return The list.
*/
@NotNull
public static <T> List<T> toSingletonList(@Nullable final T object) {
if (object == null) {
return Collections.emptyList();
} else {
return Collections.singletonList(object);
}
}
/**
* Get element from list or return null if out of bounds.
*
* @param list The list.
* @param index The index.
* @param <T> The type of the list.
* @return The found element, or null if out of bounds.
*/
@Nullable
public static <T> T getOrNull(@Nullable final List<T> list,
final int index) {
if (list == null) {
return null;
}
return index >= 0 && index < list.size() ? list.get(index) : null;
}
/**
* Get if an iterable of strings contains a certain element regardless of case.
*
* @param list The list.
* @param element The element.
* @return If contained.
*/
public static boolean containsIgnoreCase(@NotNull final Iterable<String> list,
@NotNull final String element) {
for (String s : list) {
if (s.equalsIgnoreCase(element)) {
return true;
}
}
return false;
}
private ListUtils() { private ListUtils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
} }

View File

@@ -1,10 +1,9 @@
package com.willfp.eco.util; package com.willfp.eco.util;
import com.willfp.eco.core.Eco;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Objects;
/** /**
* Utilities / API methods for {@link NamespacedKey}s. * Utilities / API methods for {@link NamespacedKey}s.
*/ */
@@ -17,7 +16,7 @@ public final class NamespacedKeyUtils {
*/ */
@NotNull @NotNull
public static NamespacedKey createEcoKey(@NotNull final String string) { public static NamespacedKey createEcoKey(@NotNull final String string) {
return Objects.requireNonNull(NamespacedKey.fromString("eco:" + string)); return NamespacedKeyUtils.create("eco", string);
} }
/** /**
@@ -30,7 +29,28 @@ public final class NamespacedKeyUtils {
@NotNull @NotNull
public static NamespacedKey create(@NotNull final String namespace, public static NamespacedKey create(@NotNull final String namespace,
@NotNull final String key) { @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) {
int index = string.indexOf(":");
return NamespacedKeyUtils.create(
string.substring(0, index),
string.substring(index + 1)
);
} }
private NamespacedKeyUtils() { private NamespacedKeyUtils() {

View File

@@ -1,11 +1,16 @@
package com.willfp.eco.util; 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.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import java.util.function.BiFunction;
/** /**
* Utilities / API methods for numbers. * Utilities / API methods for numbers.
@@ -16,6 +21,11 @@ public final class NumberUtils {
*/ */
private static final double[] SIN_LOOKUP = new double[65536]; 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. * Set of roman numerals to look up.
*/ */
@@ -83,7 +93,9 @@ public final class NumberUtils {
* @param toChange The value to test. * @param toChange The value to test.
* @param limit The maximum. * @param limit The maximum.
* @return The new value. * @return The new value.
* @deprecated Pointless method.
*/ */
@Deprecated(since = "6.19.0")
public static int equalIfOver(final int toChange, public static int equalIfOver(final int toChange,
final int limit) { final int limit) {
return Math.min(toChange, limit); return Math.min(toChange, limit);
@@ -95,7 +107,9 @@ public final class NumberUtils {
* @param toChange The value to test. * @param toChange The value to test.
* @param limit The maximum. * @param limit The maximum.
* @return The new value. * @return The new value.
* @deprecated Pointless method.
*/ */
@Deprecated(since = "6.19.0")
public static double equalIfOver(final double toChange, public static double equalIfOver(final double toChange,
final double limit) { final double limit) {
return Math.min(toChange, limit); return Math.min(toChange, limit);
@@ -185,11 +199,23 @@ public final class NumberUtils {
/** /**
* Get Log base 2 of a number. * Get Log base 2 of a number.
* *
* @param toLog The number. * @param a The number.
* @return The result. * @return The result.
*/ */
public static int log2(final int toLog) { public static int log2(final int a) {
return (int) (Math.log(toLog) / Math.log(2)); return (int) logBase(a, 2);
}
/**
* Log with a base.
*
* @param a The number.
* @param base The base.
* @return The logarithm.
*/
public static double logBase(final double a,
final double base) {
return Math.log(a) / Math.log(base);
} }
/** /**
@@ -206,6 +232,39 @@ public final class NumberUtils {
return formatted.endsWith("00") ? String.valueOf((int) toFormat) : formatted; 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() { private NumberUtils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
} }

View File

@@ -16,30 +16,45 @@ public final class PotionUtils {
public static int getDuration(@NotNull final PotionData data) { public static int getDuration(@NotNull final PotionData data) {
if (data.isExtended()) { if (data.isExtended()) {
return switch (data.getType()) { return switch (data.getType()) {
case INSTANT_DAMAGE, INSTANT_HEAL: yield 0; case INSTANT_DAMAGE, INSTANT_HEAL:
case POISON, REGEN: yield 1800; yield 0;
case SLOW_FALLING, WEAKNESS, SLOWNESS: yield 4800; case POISON, REGEN:
case TURTLE_MASTER: yield 800; yield 1800;
default: yield 9600; case SLOW_FALLING, WEAKNESS, SLOWNESS:
yield 4800;
case TURTLE_MASTER:
yield 800;
default:
yield 9600;
}; };
} }
if (data.isUpgraded()) { if (data.isUpgraded()) {
return switch (data.getType()) { return switch (data.getType()) {
case INSTANT_DAMAGE, INSTANT_HEAL: yield 0; case INSTANT_DAMAGE, INSTANT_HEAL:
case POISON, REGEN: yield 420; yield 0;
case SLOW_FALLING, WEAKNESS, SLOWNESS: yield 440; case POISON, REGEN:
case TURTLE_MASTER: yield 400; yield 420;
default: yield 1800; case SLOW_FALLING, WEAKNESS, SLOWNESS:
yield 440;
case TURTLE_MASTER:
yield 400;
default:
yield 1800;
}; };
} }
return switch (data.getType()) { return switch (data.getType()) {
case INSTANT_DAMAGE, INSTANT_HEAL: yield 0; case INSTANT_DAMAGE, INSTANT_HEAL:
case POISON, REGEN: yield 900; yield 0;
case SLOW_FALLING, WEAKNESS, SLOWNESS: yield 400; case POISON, REGEN:
case TURTLE_MASTER: yield 1800; yield 900;
default: yield 3600; case SLOW_FALLING, WEAKNESS, SLOWNESS:
yield 400;
case TURTLE_MASTER:
yield 1800;
default:
yield 3600;
}; };
} }

View File

@@ -35,7 +35,7 @@ public final class SkullUtils {
* @param base64 The base64 texture. * @param base64 The base64 texture.
*/ */
public static void setSkullTexture(@NotNull final SkullMeta meta, public static void setSkullTexture(@NotNull final SkullMeta meta,
@NotNull final String base64) { @NotNull final String base64) {
Validate.isTrue(initialized, "Must be initialized!"); Validate.isTrue(initialized, "Must be initialized!");
Validate.notNull(metaSetConsumer, "Must be initialized!"); Validate.notNull(metaSetConsumer, "Must be initialized!");
@@ -64,7 +64,7 @@ public final class SkullUtils {
*/ */
@ApiStatus.Internal @ApiStatus.Internal
public static void initialize(@NotNull final BiConsumer<SkullMeta, String> function, public static void initialize(@NotNull final BiConsumer<SkullMeta, String> function,
@NotNull final Function<SkullMeta, String> function2) { @NotNull final Function<SkullMeta, String> function2) {
Validate.isTrue(!initialized, "Already initialized!"); Validate.isTrue(!initialized, "Already initialized!");
metaSetConsumer = function; metaSetConsumer = function;

View File

@@ -1,7 +1,10 @@
package com.willfp.eco.util; 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.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonSyntaxException;
import com.willfp.eco.core.Prerequisite; import com.willfp.eco.core.Prerequisite;
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager; import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
@@ -14,11 +17,12 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.awt.*; import java.awt.Color;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -58,6 +62,49 @@ public final class StringUtils {
.hexColors() .hexColors()
.build(); .build();
/**
* GSON serializer.
*/
private static final GsonComponentSerializer GSON_COMPONENT_SERIALIZER = GsonComponentSerializer.builder()
.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. * Color map.
*/ */
@@ -264,6 +311,11 @@ public final class StringUtils {
if (option == FormatOption.WITH_PLACEHOLDERS) { if (option == FormatOption.WITH_PLACEHOLDERS) {
processedMessage = PlaceholderManager.translatePlaceholders(processedMessage, player); 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 = ChatColor.translateAlternateColorCodes('&', processedMessage);
processedMessage = translateGradients(processedMessage); processedMessage = translateGradients(processedMessage);
processedMessage = translateHexColorCodes(processedMessage); processedMessage = translateHexColorCodes(processedMessage);
@@ -415,11 +467,8 @@ public final class StringUtils {
if (legacy == null) { if (legacy == null) {
processed = ""; processed = "";
} }
return GsonComponentSerializer.gson().serialize(
Component.empty().decoration(TextDecoration.ITALIC, false).append( return LEGACY_TO_JSON.get(processed);
LEGACY_COMPONENT_SERIALIZER.deserialize(processed)
)
);
} }
/** /**
@@ -429,10 +478,12 @@ public final class StringUtils {
* @return The legacy string. * @return The legacy string.
*/ */
@NotNull @NotNull
public static String jsonToLegacy(@NotNull final String json) { public static String jsonToLegacy(@Nullable final String json) {
return LEGACY_COMPONENT_SERIALIZER.serialize( if (json == null || json.isEmpty()) {
GsonComponentSerializer.gson().deserialize(json) return "";
); }
return JSON_TO_LEGACY.get(json);
} }
/** /**
@@ -462,6 +513,53 @@ public final class StringUtils {
return LEGACY_COMPONENT_SERIALIZER.serialize(component); return LEGACY_COMPONENT_SERIALIZER.serialize(component);
} }
/**
* Parse string into tokens.
* <p>
* Handles quoted strings for names.
*
* @param lookup The lookup string.
* @return An array of tokens to be processed.
* @author Shawn (https://stackoverflow.com/questions/70606170/split-a-list-on-spaces-and-group-quoted-characters/70606653#70606653)
*/
@NotNull
public static String[] parseTokens(@NotNull final String lookup) {
char[] chars = lookup.toCharArray();
List<String> tokens = new ArrayList<>();
StringBuilder tokenBuilder = new StringBuilder();
for (int i = 0; i < chars.length; i++) {
if (chars[i] == ' ') {
/*
Take the current value of the argument builder, append it to the
list of found tokens, and then clear it for the next argument.
*/
tokens.add(tokenBuilder.toString());
tokenBuilder.setLength(0);
} else if (chars[i] == '"') {
/*
Work until the next unescaped quote to handle quotes with
spaces in them - assumes the input string is well-formatted
*/
for (i++; chars[i] != '"'; i++) {
/*
If the found quote is escaped, ignore it in the parsing
*/
if (chars[i] == '\\') {
i++;
}
tokenBuilder.append(chars[i]);
}
} else {
/*
If it's a regular character, just append it to the current argument.
*/
tokenBuilder.append(chars[i]);
}
}
tokens.add(tokenBuilder.toString()); // Adds the last argument to the tokens.
return tokens.toArray(new String[0]);
}
/** /**
* Options for formatting. * Options for formatting.
*/ */

View File

@@ -7,5 +7,5 @@ dependencies {
compileOnly 'org.reflections:reflections:0.9.12' compileOnly 'org.reflections:reflections:0.9.12'
compileOnly 'net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT' compileOnly 'net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT'
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0' 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

@@ -1,87 +1,93 @@
package com.willfp.eco.internal.config package com.willfp.eco.internal.config
import com.willfp.eco.core.PluginLike import com.willfp.eco.core.PluginLike
import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.interfaces.Config import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.config.interfaces.JSONConfig import com.willfp.eco.core.config.interfaces.LoadableConfig
import com.willfp.eco.core.config.wrapper.ConfigFactory import com.willfp.eco.core.config.wrapper.ConfigFactory
import com.willfp.eco.internal.config.json.EcoJSONConfigSection import com.willfp.eco.internal.config.json.EcoJSONConfigSection
import com.willfp.eco.internal.config.json.EcoJSONConfigWrapper
import com.willfp.eco.internal.config.json.EcoLoadableJSONConfig import com.willfp.eco.internal.config.json.EcoLoadableJSONConfig
import com.willfp.eco.internal.config.json.EcoUpdatableJSONConfig import com.willfp.eco.internal.config.json.EcoUpdatableJSONConfig
import com.willfp.eco.internal.config.yaml.EcoLoadableYamlConfig import com.willfp.eco.internal.config.yaml.EcoLoadableYamlConfig
import com.willfp.eco.internal.config.yaml.EcoUpdatableYamlConfig import com.willfp.eco.internal.config.yaml.EcoUpdatableYamlConfig
import com.willfp.eco.internal.config.yaml.EcoYamlConfigSection import com.willfp.eco.internal.config.yaml.EcoYamlConfigSection
import org.bukkit.configuration.file.YamlConfiguration import org.bukkit.configuration.file.YamlConfiguration
import java.io.StringReader
class EcoConfigFactory : ConfigFactory { class EcoConfigFactory : ConfigFactory {
override fun createUpdatableYamlConfig( override fun createConfig(config: YamlConfiguration): Config {
configName: String,
plugin: PluginLike,
subDirectoryPath: String,
source: Class<*>,
removeUnused: Boolean,
vararg updateBlacklist: String
): Config {
return EcoUpdatableYamlConfig(
configName,
plugin,
subDirectoryPath,
source,
removeUnused,
*updateBlacklist
)
}
override fun createUpdatableJSONConfig(
configName: String,
plugin: PluginLike,
subDirectoryPath: String,
source: Class<*>,
removeUnused: Boolean,
vararg updateBlacklist: String
): JSONConfig {
return EcoUpdatableJSONConfig(
configName,
plugin,
subDirectoryPath,
source,
removeUnused,
*updateBlacklist
)
}
override fun createLoadableJSONConfig(
configName: String,
plugin: PluginLike,
subDirectoryPath: String,
source: Class<*>
): JSONConfig {
return EcoLoadableJSONConfig(
configName,
plugin,
subDirectoryPath,
source
)
}
override fun createLoadableYamlConfig(
configName: String,
plugin: PluginLike,
subDirectoryPath: String,
source: Class<*>
): Config {
return EcoLoadableYamlConfig(
configName,
plugin,
subDirectoryPath,
source
)
}
override fun createYamlConfig(config: YamlConfiguration): Config {
return EcoYamlConfigSection(config) return EcoYamlConfigSection(config)
} }
override fun createJSONConfig(values: Map<String, Any>): JSONConfig { override fun createConfig(values: MutableMap<String, Any>): Config {
return EcoJSONConfigSection(values) return EcoJSONConfigSection(values)
} }
override fun createConfig(contents: String, type: ConfigType): Config {
return if (type == ConfigType.JSON) {
@Suppress("UNCHECKED_CAST")
EcoJSONConfigSection(
EcoJSONConfigWrapper.gson.fromJson(
StringReader(contents), Map::class.java
) as MutableMap<String, Any>
)
} else {
EcoYamlConfigSection(YamlConfiguration.loadConfiguration(StringReader(contents)))
}
}
override fun createLoadableConfig(
configName: String,
plugin: PluginLike,
subDirectoryPath: String,
source: Class<*>,
type: ConfigType
): LoadableConfig {
return if (type == ConfigType.JSON) {
EcoLoadableJSONConfig(
configName,
plugin,
subDirectoryPath,
source
)
} else {
EcoLoadableYamlConfig(
configName,
plugin,
subDirectoryPath,
source
)
}
}
override fun createUpdatableConfig(
configName: String,
plugin: PluginLike,
subDirectoryPath: String,
source: Class<*>,
removeUnused: Boolean,
type: ConfigType,
vararg updateBlacklist: String
): LoadableConfig {
return if (type == ConfigType.JSON) {
EcoUpdatableJSONConfig(
configName,
plugin,
subDirectoryPath,
source,
removeUnused,
*updateBlacklist
)
} else {
EcoUpdatableYamlConfig(
configName,
plugin,
subDirectoryPath,
source,
removeUnused,
*updateBlacklist
)
}
}
} }

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.internal.config.json package com.willfp.eco.internal.config.json
@Suppress("UNCHECKED_CAST")
class EcoJSONConfigSection(values: Map<String, Any?>) : EcoJSONConfigWrapper() { class EcoJSONConfigSection(values: Map<String, Any?>) : EcoJSONConfigWrapper() {
init { init {
init(values) init(values)

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