Compare commits

..

177 Commits

Author SHA1 Message Date
Auxilor
d826a9f71f Switched FabledSkyblock to local jar 2022-09-14 21:18:55 +01:00
Auxilor
7ec3355237 Updated to 6.41.1 2022-09-14 21:18:28 +01:00
Auxilor
e59a8cc2e6 Oops 2022-09-14 21:13:33 +01:00
Auxilor
88f974fd10 Fixed long standing bug with ItemProvider (and scyther integration) 2022-09-14 21:08:14 +01:00
Auxilor
dfe2f1361b Updated to 6.41.0 2022-09-14 13:58:10 +01:00
Auxilor
3826f9f713 Added item price API 2022-09-14 13:57:01 +01:00
Auxilor
c2d2303c91 Added scyther integration and BigDecimal economy support 2022-09-14 13:45:32 +01:00
Auxilor
b1158ceb3d Added configurable host to Paste 2022-09-12 14:39:15 +01:00
Auxilor
af4048afbe Updated to 6.40.2 2022-09-12 13:53:51 +01:00
Auxilor
fce12020d5 Fixed bug with old MySQL versions 2022-09-12 13:53:35 +01:00
Auxilor
7e37332b64 Updated to 6.40.1 2022-09-11 10:47:23 +01:00
Auxilor
52dbf9ff52 Codestyle 2022-09-11 10:47:00 +01:00
Auxilor
78b6292367 Merge remote-tracking branch 'origin/master' 2022-09-11 10:46:43 +01:00
Will FP
09705e787b Merge pull request #193
Fix DeluxeCombat and FabledSkyBlock integration
2022-09-11 10:46:44 +01:00
Auxilor
9c86069a85 Added option to disable the update checker 2022-09-11 10:45:40 +01:00
Auxilor
0a7acceb83 Updated to 6.40.0 2022-09-10 19:59:07 +01:00
Auxilor
40aa8b17dd Fixed MySQL changes 2022-09-10 19:58:57 +01:00
Auxilor
71eb386a19 Reworked MySQL data handler and data migration 2022-09-10 19:22:29 +01:00
Kapitowa
c857df2360 fix FabledSkyBlock integration for proper check 2022-09-09 14:45:33 +03:00
Kapitowa
f4fc611f3b Fix when damager with DeluxeCombat protection can cause damage 2022-09-09 05:31:54 +03:00
Auxilor
0d91324d47 Updated crunch 2022-09-06 15:26:46 +01:00
Auxilor
e9dbc3ec73 Updated crunch 2022-09-06 15:11:42 +01:00
Auxilor
493d1b1b6d Updated crunch 2022-09-06 15:11:14 +01:00
Auxilor
68221d5912 Updated crunch 2022-09-06 15:07:29 +01:00
Auxilor
7f2ef4e038 Updated to 6.39.1 2022-09-06 15:06:11 +01:00
Auxilor
be0a19175b Added additional players to config expression getters 2022-09-06 15:05:52 +01:00
Auxilor
5afdcd75f7 Added min and max functions to crunch 2022-09-06 14:49:40 +01:00
Auxilor
a1c0b8c857 Fixed FUUID 2022-09-06 13:25:17 +01:00
Auxilor
0442ccf58f Fixed FactionsUUID jar 2022-09-06 13:23:59 +01:00
Auxilor
1c1a796610 FactionsUUID to local jar 2022-09-06 13:19:49 +01:00
Auxilor
eacb243493 Fixed FactionsUUID 2022-09-06 13:17:55 +01:00
Auxilor
7bbed31d4e Fixed FactionsUUID 2022-09-06 13:17:43 +01:00
Auxilor
58bccf3cd7 Added songoda repo for FabledSkyblock 2022-09-06 13:15:36 +01:00
Auxilor
4502e1e311 Removed ender.zone, using JitPack build instead 2022-09-06 13:14:27 +01:00
Auxilor
054a8d5a5e Updated to 6.39.0 2022-09-06 13:04:55 +01:00
Auxilor
dbdd4785ba Added AdditionalPlayer support to placeholders 2022-09-06 13:04:00 +01:00
Will FP
35f800b62a Merge pull request #178
Added FabledSkyBlock integration in AntigriefManager
2022-09-06 12:50:56 +01:00
Auxilor
591800dba8 Updated to 6.38.3 2022-08-22 14:16:20 +02:00
Auxilor
46673e8d24 Fixed SNBT 2022-08-22 14:16:07 +02:00
Kapitowa
bb7c300074 fix space and fill softdepend 2022-08-02 18:46:09 +03:00
Kapitowa
b003ec96f7 Added FabledSkyBlock integration in AntigriefManager 2022-08-02 18:33:18 +03:00
Will FP
a526f51780 Update README.md 2022-07-28 16:07:08 +01:00
Auxilor
dd14fc666a Updated to 6.38.2 2022-07-27 19:42:19 +01:00
Auxilor
ae0150f012 Bumped ShopGUI+ 2022-07-27 19:42:06 +01:00
Auxilor
04418fa038 Updated ProtocolLib for compatibility 2022-07-27 19:40:08 +01:00
Auxilor
bcb9523315 Updated to 6.38.1 2022-07-25 16:51:55 +01:00
Auxilor
43e7972ca3 Improved menu re-renders 2022-07-25 16:51:38 +01:00
Auxilor
7ea61eb393 Removed source/target compatibility no longer required by kotlin 1.7.x 2022-07-22 14:08:33 +01:00
Auxilor
5245a9b1d8 Updated to 6.38.0 2022-07-22 14:05:53 +01:00
Auxilor
195932463c Added DisplayProperties to DisplayModule 2022-07-22 14:04:42 +01:00
Auxilor
3cf60a7e2c Added MenuUtils#getOpenMenu 2022-07-22 13:54:45 +01:00
Auxilor
0f9f57fca2 Merge remote-tracking branch 'origin/master' 2022-07-22 13:47:03 +01:00
Will FP
fe21616dd5 Merge pull request #161 from Syrent/master
Add MythicMobs 5.X support.
2022-07-22 13:46:53 +01:00
Auxilor
396144abaa Added Vector#isSafeVelocity 2022-07-22 13:46:08 +01:00
Auxilor
50b4fa59ab Added onOpen to menu 2022-07-22 13:42:48 +01:00
Auxilor
a6754379e8 Updated to 6.37.3 2022-07-07 22:55:03 +01:00
Auxilor
bbd0182c2a Fixed weird bug 2022-07-07 22:54:54 +01:00
Auxilor
0370e9f454 Fixed startup order 2022-07-03 16:49:26 +01:00
Auxilor
8d585b58cb Fixed initializing text 2022-07-03 16:45:44 +01:00
Auxilor
0bfbd4c036 Updated to 6.37.2 2022-07-03 16:38:32 +01:00
Auxilor
881839955e Added player health fixer 2022-07-03 16:38:21 +01:00
Syrent
8ffc5f9c0f Add MythicMobs 5.X support. 2022-06-28 08:07:05 +04:30
Auxilor
709de3bb5f Updated to 6.37.1 2022-06-14 12:43:11 +01:00
Auxilor
f2aa2ffd9b Removed ExactTestableItem 2022-06-14 12:43:04 +01:00
Auxilor
5ce70399f0 Improved SNBT lookups 2022-06-14 12:42:49 +01:00
Auxilor
3f8759b08a Updated to 6.37.0 2022-06-14 12:14:33 +01:00
Auxilor
abecaa6e9f Added SNBT parsing 2022-06-14 12:13:48 +01:00
Auxilor
4744bfc78b Updated to 6.36.5 2022-06-09 19:24:49 +01:00
Auxilor
487e68221a Added 1.19 support 2022-06-09 19:24:37 +01:00
Auxilor
1c68992a8e Updated to 6.36.4 2022-05-29 17:46:52 +01:00
Auxilor
c5b7d0b644 Fixed conflict finder breaking the polymart autoupdater 2022-05-29 17:46:24 +01:00
Auxilor
0f91aec3b7 Slots can now be not captive for some players 2022-05-29 11:34:32 +01:00
Auxilor
d2bf38c5c9 Updated to 6.36.3 2022-05-29 11:11:33 +01:00
Auxilor
2c96b79aba Improved slots 2022-05-29 11:11:16 +01:00
Auxilor
d539b9e59e Improvements to captive items 2022-05-28 17:33:06 +01:00
Auxilor
b0b06ef402 Updated to 6.36.2 2022-05-28 17:20:35 +01:00
Auxilor
7a84c3de3b Captive from empty, take 2 2022-05-28 17:20:23 +01:00
Auxilor
9431321e1c Revert "Added captive defaults"
This reverts commit 7adcdd572d.
2022-05-28 17:08:36 +01:00
Auxilor
4816284fba Revert "Added captive default kotlin extension"
This reverts commit 2bcbf181a9.
2022-05-28 17:08:01 +01:00
Auxilor
a9874c9386 Revert "Updated to 6.37.0"
This reverts commit fc3c80f633.
2022-05-28 17:08:01 +01:00
Auxilor
fe68760184 Revert "Fixed backwards compatibility"
This reverts commit 1f7cf78491.
2022-05-28 17:08:01 +01:00
Auxilor
5ae8e72a98 Revert "Fixed captive default"
This reverts commit 15fc6053c8.
2022-05-28 17:08:01 +01:00
Auxilor
15fc6053c8 Fixed captive default 2022-05-28 16:54:58 +01:00
Auxilor
1f7cf78491 Fixed backwards compatibility 2022-05-28 16:43:35 +01:00
Auxilor
fc3c80f633 Updated to 6.37.0 2022-05-28 16:41:30 +01:00
Auxilor
2bcbf181a9 Added captive default kotlin extension 2022-05-28 16:41:20 +01:00
Auxilor
7adcdd572d Added captive defaults 2022-05-28 16:40:14 +01:00
Auxilor
f6eba21006 Updated to 6.36.1 2022-05-28 16:10:40 +01:00
Auxilor
cc02f26807 Fixed key registry 2022-05-28 16:10:30 +01:00
Auxilor
60f552ce65 KDoc Formatting 2022-05-28 14:38:59 +01:00
Auxilor
9fe8d4ad15 Added more slot builders 2022-05-28 14:36:48 +01:00
Auxilor
b835988eec Added toSingletonList 2022-05-28 14:32:35 +01:00
Auxilor
22366835de Added additional MaskItems constructor 2022-05-28 14:31:20 +01:00
Auxilor
cdd1baec6c Fixed codemc 2022-05-28 14:28:24 +01:00
Auxilor
1ea0da365a Removed villager-display-fix 2022-05-28 13:59:38 +01:00
Auxilor
852d40372d Added option to toggle displayed recipes 2022-05-28 13:59:03 +01:00
Auxilor
999c831dd7 Removed non-functional packet splitting 2022-05-28 13:47:44 +01:00
Auxilor
80fa5d346a Fixed recipe packet fixer 2022-05-28 12:37:47 +01:00
Auxilor
336cdc3716 Added recipe packet splitting 2022-05-28 12:31:55 +01:00
Auxilor
a49a9e92b4 Updated villager trade 2022-05-28 12:23:47 +01:00
Auxilor
1c6e64832e Minor changes 2022-05-28 12:12:35 +01:00
Auxilor
44a141cddc Improved economy helpers 2022-05-27 19:03:53 +01:00
Auxilor
ea4956870e Added more GUI kotlin utils 2022-05-27 19:02:47 +01:00
Auxilor
9207d1782b Various changes 2022-05-27 17:09:00 +01:00
Auxilor
9debcb7089 Server will no longer restart after data migration 2022-05-27 16:25:11 +01:00
Auxilor
ef53ee2ed3 Fixed constrained types 2022-05-27 16:17:31 +01:00
Auxilor
4c90360038 More MySQL fixes 2022-05-27 16:07:24 +01:00
Auxilor
d4b5102913 Fixed MySQL 2022-05-27 16:01:44 +01:00
Auxilor
f4553c544a Fixed MySQL 2022-05-27 15:57:15 +01:00
Auxilor
5ad1db72fc Fixed minimize 2022-05-27 15:52:36 +01:00
Auxilor
c761df9ee6 Data Handler changes 2022-05-27 15:48:13 +01:00
Auxilor
b6d79da4e1 Improved config.yml header 2022-05-27 15:43:02 +01:00
Auxilor
42f41618ca Added warning for MySQL users 2022-05-27 15:38:28 +01:00
Auxilor
de878fd423 Codestyle 2022-05-27 15:29:39 +01:00
Auxilor
7782657d57 Improved DataHandlers again 2022-05-27 15:29:03 +01:00
Auxilor
7778425936 Improved DataHandler 2022-05-27 15:12:05 +01:00
Auxilor
6446cef255 OOps 2022-05-27 15:06:18 +01:00
Auxilor
8dacecbcba Added big ominous comment to the MySQL Data Handler 2022-05-27 15:06:00 +01:00
Auxilor
5f8ec4f94a Added PersistentDataKeyType#STRING_LIST 2022-05-27 14:56:53 +01:00
Auxilor
d7847e9efc Optimized writes mongo 2022-05-27 14:17:17 +01:00
Auxilor
930ecd4896 Improved conflict finder 2022-05-27 14:03:54 +01:00
Auxilor
af8d6a4167 Added OfflinePlayer#balance kotlin extensions 2022-05-27 14:02:52 +01:00
Auxilor
361f0a0103 Added unused suppression 2022-05-27 13:58:45 +01:00
Auxilor
eb545a7d9e Fixed relocations 2022-05-27 13:53:28 +01:00
Auxilor
d3c64deef4 Fixed minimize / exclude 2022-05-27 13:51:20 +01:00
Auxilor
31db9dcb95 Minimzed plugin module 2022-05-27 13:24:35 +01:00
Auxilor
4938ad84bc Added clarifying comment 2022-05-27 13:02:51 +01:00
Auxilor
06b2301da1 Janky fix for mongo logging 2022-05-27 13:00:59 +01:00
Auxilor
c307878c09 More migration improvements 2022-05-26 20:40:57 +01:00
Auxilor
3b10ff01ec Updated to 6.36.0 2022-05-26 20:17:47 +01:00
Auxilor
e042754f5d Mongo improvements / Added data migration 2022-05-26 20:17:31 +01:00
Auxilor
c2b8a80560 Improved MongoDB 2022-05-25 20:21:50 +01:00
Auxilor
07c0e72564 Added MongoDB data handler 2022-05-25 20:08:24 +01:00
Auxilor
de9b961d83 Revert "Added LONG_STRING column type"
This reverts commit 83958c719c.
2022-05-25 19:20:47 +01:00
Auxilor
83958c719c Added LONG_STRING column type 2022-05-21 19:35:05 +01:00
Auxilor
9c3dfaeb01 Updated to 6.35.12 2022-05-19 17:13:00 +01:00
Auxilor
7e61340285 Fixed static placeholder string formatting 2022-05-19 17:12:51 +01:00
Auxilor
78b76cb453 Updated to 6.35.11 2022-05-18 16:02:56 +01:00
Auxilor
bb1da29704 Added placeholder injections to strings 2022-05-18 16:02:36 +01:00
Auxilor
cf152215d3 Cleaned up internal 2022-05-18 15:00:23 +01:00
Auxilor
e6a59fbc91 Updated to 6.35.10 2022-05-18 10:53:06 +01:00
Will FP
b787f8b76a Merge pull request #133
Bump io.papermc.paperweight.userdev from 1.3.5 to 1.3.6
2022-05-18 10:52:43 +01:00
Will FP
ccc83da5b0 Merge pull request #135
Bump caffeine from 3.0.6 to 3.1.0
2022-05-18 10:52:30 +01:00
Will FP
f11068f2f1 Merge pull request #145
add CMI gradient format
2022-05-18 10:52:18 +01:00
Will FP
a5cc1a5d32 Merge pull request #146
Add an exception for armorstand in interact flag of WG
2022-05-18 10:52:10 +01:00
Kapitowa
7440749ba5 Add an exception for armorstand in interact flag of WG 2022-05-18 01:28:10 +03:00
Kapitowa
75010d25fa add CMI gradient format 2022-05-18 01:01:07 +03:00
Auxilor
bb95376b93 Removed async-display 2022-05-17 19:55:13 +01:00
Auxilor
ab6d4c7aa2 Updated to 6.35.9 2022-05-17 16:53:57 +01:00
Auxilor
9ab8827e55 Fixed non-applied FIS Flags 2022-05-17 16:45:37 +01:00
Auxilor
991290095b Updated to 6.35.8 2022-05-17 10:19:48 +01:00
Auxilor
8735478fc3 More bit manip 2022-05-17 10:19:36 +01:00
Auxilor
6e44f09621 Fixed ItemFlags in FastItemStack 2022-05-17 10:11:04 +01:00
Auxilor
060106881e Updated to 6.35.7 2022-05-13 12:07:26 +01:00
Auxilor
96cc9706b3 Placeholder injection fixes 2022-05-13 12:07:15 +01:00
Auxilor
3d87b1eb73 Revert "Fixed placeholder injection bugs"
This reverts commit 06bcb10958.
2022-05-13 11:46:57 +01:00
Auxilor
4c4247b4ec Revert "Updated to 6.35.7"
This reverts commit b94dc4ac3a.
2022-05-13 11:46:57 +01:00
Auxilor
b94dc4ac3a Updated to 6.35.7 2022-05-13 11:34:58 +01:00
Auxilor
06bcb10958 Fixed placeholder injection bugs 2022-05-13 11:34:42 +01:00
Auxilor
295095e9ce Fixed spelling 2022-05-09 12:34:14 +01:00
Auxilor
ba9c5865e3 Updated to 6.35.6 2022-05-09 12:30:22 +01:00
Auxilor
d24be4121f Added conflict finder 2022-05-09 12:30:14 +01:00
Auxilor
bcc5e4ef08 Skull improvements 2022-05-09 10:23:35 +01:00
Auxilor
bf8609666a Codestyle 2022-05-09 10:20:05 +01:00
Auxilor
1a02335825 Fixed dumbest error of all time 2022-05-09 10:14:18 +01:00
Auxilor
f5ef98ec5c Improved custom item lookup 2022-05-09 10:11:06 +01:00
Auxilor
45135e2b55 Updated to 6.35.5 2022-05-08 17:27:14 +01:00
Auxilor
758b42ff8e Fixed ItemsAdder integration 2022-05-08 17:26:50 +01:00
Auxilor
4a134402da Fixed Prerequisite#HAS_PAPER 2022-05-06 09:09:54 +01:00
Auxilor
e6ad4c9268 Updated to 6.35.4 2022-05-06 09:08:38 +01:00
Auxilor
809dcbae85 Improved NaturalExpGainListeners for paper 2022-05-06 09:07:57 +01:00
Auxilor
d7fce6834c Updated to 6.35.3 2022-05-03 13:05:41 +01:00
Auxilor
ac807a991b Players can no longer tab-complete commands they don't have permission for 2022-05-03 13:05:32 +01:00
Auxilor
ba315ced3c Updated to 6.35.2 2022-04-29 22:45:42 +01:00
Auxilor
f2e65174f9 Reverted to old block vein code 2022-04-29 22:45:02 +01:00
dependabot[bot]
bd5555ff01 Bump caffeine from 3.0.6 to 3.1.0
Bumps [caffeine](https://github.com/ben-manes/caffeine) from 3.0.6 to 3.1.0.
- [Release notes](https://github.com/ben-manes/caffeine/releases)
- [Commits](https://github.com/ben-manes/caffeine/compare/v3.0.6...v3.1.0)

---
updated-dependencies:
- dependency-name: com.github.ben-manes.caffeine:caffeine
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-28 21:41:30 +00:00
dependabot[bot]
5f80b6052d Bump io.papermc.paperweight.userdev from 1.3.5 to 1.3.6
Bumps [io.papermc.paperweight.userdev](https://github.com/PaperMC/paperweight) from 1.3.5 to 1.3.6.
- [Release notes](https://github.com/PaperMC/paperweight/releases)
- [Commits](https://github.com/PaperMC/paperweight/compare/v1.3.5...v1.3.6)

---
updated-dependencies:
- dependency-name: io.papermc.paperweight.userdev
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-22 21:29:44 +00:00
141 changed files with 3226 additions and 1217 deletions

View File

@@ -39,7 +39,7 @@ and many more.
# For developers # For developers
## Javadoc ## Javadoc
The 6.27.2 Javadoc can be found [here](https://javadoc.jitpack.io/com/willfp/eco/6.27.2/javadoc/) The 6.38.2 Javadoc can be found [here](https://javadoc.jitpack.io/com/willfp/eco/6.38.2/javadoc/)
## Plugin Information ## Plugin Information

View File

@@ -4,7 +4,7 @@ buildscript {
} }
dependencies { dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10")
} }
} }
@@ -13,17 +13,18 @@ plugins {
id("com.github.johnrengelman.shadow") version "7.1.2" id("com.github.johnrengelman.shadow") version "7.1.2"
id("maven-publish") id("maven-publish")
id("java") id("java")
kotlin("jvm") version "1.6.21" kotlin("jvm") version "1.7.10"
} }
dependencies { dependencies {
implementation(project(":eco-api")) implementation(project(":eco-api"))
implementation(project(":eco-core:core-plugin")) implementation(project(path = ":eco-core:core-plugin", configuration = "shadow"))
implementation(project(":eco-core:core-proxy")) implementation(project(":eco-core:core-proxy"))
implementation(project(":eco-core:core-backend")) implementation(project(":eco-core:core-backend"))
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(path = ":eco-core:core-nms:v1_18_R1", configuration = "reobf")) implementation(project(path = ":eco-core:core-nms:v1_18_R1", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_18_R2", configuration = "reobf")) implementation(project(path = ":eco-core:core-nms:v1_18_R2", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_19_R1", configuration = "reobf"))
} }
allprojects { allprojects {
@@ -44,11 +45,8 @@ allprojects {
// SuperiorSkyblock2 // SuperiorSkyblock2
maven("https://repo.bg-software.com/repository/api/") maven("https://repo.bg-software.com/repository/api/")
// NMS (for jitpack compilation)
maven("https://repo.codemc.org/repository/nms/")
// mcMMO, BentoBox // mcMMO, BentoBox
maven("https://repo.codemc.org/repository/maven-public/") maven("https://repo.codemc.io/repository/maven-public/")
// Spigot API, Bungee API // Spigot API, Bungee API
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
@@ -63,7 +61,7 @@ allprojects {
maven("https://maven.enginehub.org/repo/") maven("https://maven.enginehub.org/repo/")
// FactionsUUID // FactionsUUID
maven("https://ci.ender.zone/plugin/repository/everything/") //maven("https://ci.ender.zone/plugin/repository/everything/")
// NoCheatPlus // NoCheatPlus
maven("https://repo.md-5.net/content/repositories/snapshots/") maven("https://repo.md-5.net/content/repositories/snapshots/")
@@ -83,7 +81,8 @@ allprojects {
dependencies { dependencies {
// Kotlin // Kotlin
implementation(kotlin("stdlib", version = "1.6.21")) implementation(kotlin("stdlib", version = "1.7.10"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.2")
// Included in spigot jar, no need to move to implementation // Included in spigot jar, no need to move to implementation
compileOnly("org.jetbrains:annotations:23.0.0") compileOnly("org.jetbrains:annotations:23.0.0")
@@ -101,7 +100,7 @@ allprojects {
implementation("net.kyori:adventure-text-serializer-legacy:4.10.1") implementation("net.kyori:adventure-text-serializer-legacy:4.10.1")
// Other // Other
implementation("com.github.ben-manes.caffeine:caffeine:3.0.6") implementation("com.github.ben-manes.caffeine:caffeine:3.1.0")
implementation("org.apache.maven:maven-artifact:3.8.5") implementation("org.apache.maven:maven-artifact:3.8.5")
} }
@@ -130,8 +129,6 @@ allprojects {
kotlinOptions { kotlinOptions {
jvmTarget = "17" jvmTarget = "17"
} }
targetCompatibility = "17"
sourceCompatibility = "17"
} }
shadowJar { shadowJar {
@@ -154,6 +151,13 @@ allprojects {
relocate("google.protobuf", "com.willfp.eco.libs.protobuf") // Still don't know relocate("google.protobuf", "com.willfp.eco.libs.protobuf") // Still don't know
relocate("com.zaxxer.hikari", "com.willfp.eco.libs.hikari") relocate("com.zaxxer.hikari", "com.willfp.eco.libs.hikari")
//relocate("com.mysql", "com.willfp.eco.libs.mysql") //relocate("com.mysql", "com.willfp.eco.libs.mysql")
relocate("de.undercouch.bson4jackson", "com.willfp.eco.libs.bson4jackson")
relocate("com.fasterxml.jackson", "com.willfp.eco.libs.jackson")
relocate("com.mongodb", "com.willfp.eco.libs.mongodb")
relocate("org.bson", "com.willfp.eco.libs.bson")
relocate("org.litote", "com.willfp.eco.libs.litote")
relocate("org.reactivestreams", "com.willfp.eco.libs.reactivestreams")
relocate("reactor.", "com.willfp.eco.libs.reactor.") // Dot in name to be safe
/* /*
Kotlin and caffeine are not shaded so that they can be accessed directly by eco plugins. Kotlin and caffeine are not shaded so that they can be accessed directly by eco plugins.

View File

@@ -304,6 +304,11 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
this.color = props.getColor(); this.color = props.getColor();
this.supportingExtensions = props.isSupportingExtensions(); this.supportingExtensions = props.isSupportingExtensions();
this.proxyFactory = this.proxyPackage.equalsIgnoreCase("") ? null : Eco.getHandler().createProxyFactory(this);
this.logger = Eco.getHandler().createLogger(this);
this.getLogger().info("Initializing " + this.getColor() + this.getName());
this.scheduler = Eco.getHandler().createScheduler(this); this.scheduler = Eco.getHandler().createScheduler(this);
this.eventManager = Eco.getHandler().createEventManager(this); this.eventManager = Eco.getHandler().createEventManager(this);
this.namespacedKeyFactory = Eco.getHandler().createNamespacedKeyFactory(this); this.namespacedKeyFactory = Eco.getHandler().createNamespacedKeyFactory(this);
@@ -311,16 +316,12 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
this.runnableFactory = Eco.getHandler().createRunnableFactory(this); this.runnableFactory = Eco.getHandler().createRunnableFactory(this);
this.extensionLoader = Eco.getHandler().createExtensionLoader(this); this.extensionLoader = Eco.getHandler().createExtensionLoader(this);
this.configHandler = Eco.getHandler().createConfigHandler(this); this.configHandler = Eco.getHandler().createConfigHandler(this);
this.logger = Eco.getHandler().createLogger(this);
this.proxyFactory = this.proxyPackage.equalsIgnoreCase("") ? null : Eco.getHandler().createProxyFactory(this);
this.langYml = this.createLangYml(); this.langYml = this.createLangYml();
this.configYml = this.createConfigYml(); this.configYml = this.createConfigYml();
Eco.getHandler().addNewPlugin(this); Eco.getHandler().addNewPlugin(this);
this.getLogger().info("Initializing " + this.getColor() + this.getName());
/* /*
The minimum eco version check was moved here because it's very common The minimum eco version check was moved here because it's very common
to add a lot of code in the constructor of plugins; meaning that the plugin to add a lot of code in the constructor of plugins; meaning that the plugin
@@ -349,7 +350,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
this.getLogger().info(""); this.getLogger().info("");
this.getLogger().info("Loading " + this.getColor() + this.getName()); this.getLogger().info("Loading " + this.getColor() + this.getName());
if (this.getResourceId() != 0) { if (this.getResourceId() != 0 && !Eco.getHandler().getEcoPlugin().getConfigYml().getBool("no-update-checker")) {
new UpdateChecker(this).getVersion(version -> { new UpdateChecker(this).getVersion(version -> {
DefaultArtifactVersion currentVersion = new DefaultArtifactVersion(this.getDescription().getVersion()); DefaultArtifactVersion currentVersion = new DefaultArtifactVersion(this.getDescription().getVersion());
DefaultArtifactVersion mostRecentVersion = new DefaultArtifactVersion(version); DefaultArtifactVersion mostRecentVersion = new DefaultArtifactVersion(version);
@@ -376,12 +377,12 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
PlaceholderManager.addIntegration(Eco.getHandler().createPAPIIntegration(this)); PlaceholderManager.addIntegration(Eco.getHandler().createPAPIIntegration(this));
} }
this.loadIntegrationLoaders().forEach((integrationLoader -> { this.loadIntegrationLoaders().forEach(integrationLoader -> {
if (enabledPlugins.contains(integrationLoader.getPluginName().toLowerCase())) { if (enabledPlugins.contains(integrationLoader.getPluginName().toLowerCase())) {
this.loadedIntegrations.add(integrationLoader.getPluginName()); this.loadedIntegrations.add(integrationLoader.getPluginName());
integrationLoader.load(); integrationLoader.load();
} }
})); });
this.getLogger().info("Loaded integrations: " + String.join(", ", this.getLoadedIntegrations())); this.getLogger().info("Loaded integrations: " + String.join(", ", this.getLoadedIntegrations()));

View File

@@ -15,6 +15,7 @@ import com.willfp.eco.core.factory.RunnableFactory;
import com.willfp.eco.core.fast.FastItemStack; import com.willfp.eco.core.fast.FastItemStack;
import com.willfp.eco.core.gui.GUIFactory; import com.willfp.eco.core.gui.GUIFactory;
import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration; import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration;
import com.willfp.eco.core.items.SNBTHandler;
import com.willfp.eco.core.proxy.Cleaner; import com.willfp.eco.core.proxy.Cleaner;
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;
@@ -282,8 +283,7 @@ public interface Handler {
* @param <T> The mob type. * @param <T> The mob type.
* @return The controlled entity. * @return The controlled entity.
*/ */
@NotNull @NotNull <T extends Mob> EntityController<T> createEntityController(@NotNull T mob);
<T extends Mob> EntityController<T> createEntityController(@NotNull T mob);
/** /**
* Adapt base PDC to extended PDC. * Adapt base PDC to extended PDC.
@@ -301,4 +301,12 @@ public interface Handler {
*/ */
@NotNull @NotNull
PersistentDataContainer newPdc(); PersistentDataContainer newPdc();
/**
* Get SNBT handler.
*
* @return The SNBT handler.
*/
@NotNull
SNBTHandler getSNBTHandler();
} }

View File

@@ -26,7 +26,7 @@ public class Prerequisite {
* Requires the server to be running an implementation of paper. * Requires the server to be running an implementation of paper.
*/ */
public static final Prerequisite HAS_PAPER = new Prerequisite( public static final Prerequisite HAS_PAPER = new Prerequisite(
() -> ClassUtils.exists("com.destroystokyo.paper.event.player.PlayerElytraBoostEvent"), () -> ClassUtils.exists("com.destroystokyo.paper.event.block.BeaconEffectEvent"),
"Requires server to be running paper (or a fork)" "Requires server to be running paper (or a fork)"
); );
@@ -41,11 +41,19 @@ public class Prerequisite {
"Requires server to have vault" "Requires server to have vault"
); );
/**
* Requires the server to be running 1.19.
*/
public static final Prerequisite HAS_1_19 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("19"),
"Requires server to be running 1.19+"
);
/** /**
* Requires the server to be running 1.18. * Requires the server to be running 1.18.
*/ */
public static final Prerequisite HAS_1_18 = new Prerequisite( public static final Prerequisite HAS_1_18 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("18"), () -> ProxyConstants.NMS_VERSION.contains("18") || HAS_1_19.isMet(),
"Requires server to be running 1.18+" "Requires server to be running 1.18+"
); );

View File

@@ -167,7 +167,10 @@ abstract class HandledCommand implements CommandBase {
StringUtil.copyPartialMatches( StringUtil.copyPartialMatches(
args[0], args[0],
this.getSubcommands().stream().map(CommandBase::getName).collect(Collectors.toList()), this.getSubcommands().stream()
.filter(subCommand -> sender.hasPermission(subCommand.getPermission()))
.map(CommandBase::getName)
.collect(Collectors.toList()),
completions completions
); );
@@ -182,6 +185,10 @@ abstract class HandledCommand implements CommandBase {
HandledCommand command = null; HandledCommand command = null;
for (CommandBase subcommand : this.getSubcommands()) { for (CommandBase subcommand : this.getSubcommands()) {
if (!sender.hasPermission(subcommand.getPermission())) {
continue;
}
if (args[0].equalsIgnoreCase(subcommand.getName())) { if (args[0].equalsIgnoreCase(subcommand.getName())) {
command = (HandledCommand) subcommand; command = (HandledCommand) subcommand;
} }

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.core.config.interfaces;
import com.willfp.eco.core.config.BuildableConfig; import com.willfp.eco.core.config.BuildableConfig;
import com.willfp.eco.core.config.ConfigType; import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.TransientConfig; import com.willfp.eco.core.config.TransientConfig;
import com.willfp.eco.core.placeholder.AdditionalPlayer;
import com.willfp.eco.core.placeholder.InjectablePlaceholder; import com.willfp.eco.core.placeholder.InjectablePlaceholder;
import com.willfp.eco.core.placeholder.PlaceholderInjectable; import com.willfp.eco.core.placeholder.PlaceholderInjectable;
import com.willfp.eco.util.NumberUtils; import com.willfp.eco.util.NumberUtils;
@@ -14,6 +15,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.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -77,7 +79,6 @@ public interface Config extends Cloneable, PlaceholderInjectable {
/** /**
* Get an object from config. * Get an object from config.
* Default implementations call {@link org.bukkit.configuration.file.YamlConfiguration#get(String)}.
* *
* @param path The path. * @param path The path.
* @return The object. * @return The object.
@@ -87,7 +88,6 @@ public interface Config extends Cloneable, PlaceholderInjectable {
/** /**
* Set an object in config. * Set an object in config.
* Default implementations call {@link org.bukkit.configuration.file.YamlConfiguration#set(String, Object)}
* *
* @param path The path. * @param path The path.
* @param object The object. * @param object The object.
@@ -159,6 +159,20 @@ public interface Config extends Cloneable, PlaceholderInjectable {
return Double.valueOf(getDoubleFromExpression(path, player)).intValue(); return Double.valueOf(getDoubleFromExpression(path, player)).intValue();
} }
/**
* 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.
* @param additionalPlayers The additional players 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,
@NotNull Collection<AdditionalPlayer> additionalPlayers) {
return Double.valueOf(getDoubleFromExpression(path, player, additionalPlayers)).intValue();
}
/** /**
* Get an integer from config. * Get an integer from config.
@@ -474,6 +488,20 @@ public interface Config extends Cloneable, PlaceholderInjectable {
return NumberUtils.evaluateExpression(this.getString(path), player, this); return NumberUtils.evaluateExpression(this.getString(path), player, this);
} }
/**
* 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.
* @param additionalPlayers The additional players 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,
@NotNull Collection<AdditionalPlayer> additionalPlayers) {
return NumberUtils.evaluateExpression(this.getString(path), player, this, additionalPlayers);
}
/** /**
* Get a decimal from config. * Get a decimal from config.
* *

View File

@@ -68,7 +68,7 @@ public interface ProfileHandler {
* @param async If the saving should be done asynchronously. * @param async If the saving should be done asynchronously.
* @deprecated async is now handled automatically depending on implementation. * @deprecated async is now handled automatically depending on implementation.
*/ */
@Deprecated @Deprecated(forRemoval = true)
default void saveAll(boolean async) { default void saveAll(boolean async) {
saveAll(); saveAll();
} }
@@ -77,8 +77,13 @@ public interface ProfileHandler {
* Save all player data. * Save all player data.
* <p> * <p>
* Can run async if using MySQL. * Can run async if using MySQL.
*
* @deprecated Never used.
*/ */
void saveAll(); @Deprecated(since = "6.36.0", forRemoval = true)
default void saveAll() {
// Do nothing.
}
/** /**
* Commit all changes to the file. * Commit all changes to the file.

View File

@@ -28,15 +28,6 @@ public interface KeyRegistry {
*/ */
Set<PersistentDataKey<?>> getRegisteredKeys(); Set<PersistentDataKey<?>> getRegisteredKeys();
/**
* Mark key as category.
*
* @param key The key.
* @param category The category.
*/
void markKeyAs(@NotNull PersistentDataKey<?> key,
@NotNull KeyRegistry.KeyCategory category);
/** /**
* Get persistent data key from namespaced key. * Get persistent data key from namespaced key.
* *
@@ -45,19 +36,4 @@ public interface KeyRegistry {
*/ */
@Nullable @Nullable
PersistentDataKey<?> getKeyFrom(@NotNull NamespacedKey namespacedKey); PersistentDataKey<?> getKeyFrom(@NotNull NamespacedKey namespacedKey);
/**
* Locations for key categorization.
*/
enum KeyCategory {
/**
* Player keys.
*/
PLAYER,
/**
* Server keys.
*/
SERVER
}
} }

View File

@@ -83,28 +83,40 @@ public final class PersistentDataKey<T> {
} }
/** /**
* In older eco versions, keys would have to be categorized in order
* to register the columns in the MySQL database. This is no longer needed.
* <p>
* Old description is below:
* <p>
* Categorize key as a server key, will register new column to MySQL * Categorize key as a server key, will register new column to MySQL
* database immediately rather than waiting for auto-categorization. * database immediately rather than waiting for auto-categorization.
* <p> * <p>
* This will improve performance. * This will improve performance.
* *
* @return The key. * @return The key.
* @deprecated Not required since the new MySQL data handler was introduced.
*/ */
@Deprecated(since = "6.40.0", forRemoval = true)
public PersistentDataKey<T> server() { public PersistentDataKey<T> server() {
Eco.getHandler().getKeyRegistry().markKeyAs(this, KeyRegistry.KeyCategory.SERVER);
return this; return this;
} }
/** /**
* In older eco versions, keys would have to be categorized in order
* to register the columns in the MySQL database. This is no longer needed.
* <p>
* Old description is below:
* <p>
* Categorize key as a player key, will register new column to MySQL * Categorize key as a player key, will register new column to MySQL
* database immediately rather than waiting for auto-categorization. * database immediately rather than waiting for auto-categorization.
* <p> * <p>
* This will improve performance. * This will improve performance.
* *
* @return The key. * @return The key.
* @deprecated Not required since the new MySQL data handler was introduced.
*/ */
@Deprecated(since = "6.40.0", forRemoval = true)
public PersistentDataKey<T> player() { public PersistentDataKey<T> player() {
Eco.getHandler().getKeyRegistry().markKeyAs(this, KeyRegistry.KeyCategory.PLAYER);
return this; return this;
} }

View File

@@ -38,6 +38,11 @@ public final class PersistentDataKeyType<T> {
*/ */
public static final PersistentDataKeyType<Double> DOUBLE = new PersistentDataKeyType<>(Double.class, "DOUBLE"); public static final PersistentDataKeyType<Double> DOUBLE = new PersistentDataKeyType<>(Double.class, "DOUBLE");
/**
* String List.
*/
public static final PersistentDataKeyType<List<String>> STRING_LIST = new PersistentDataKeyType<>(null, "STRING_LIST");
/** /**
* The class of the type. * The class of the type.
*/ */
@@ -52,7 +57,10 @@ public final class PersistentDataKeyType<T> {
* Get the class of the type. * Get the class of the type.
* *
* @return The class. * @return The class.
* @deprecated String list type will return null.
*/ */
@Deprecated(since = "6.36.0", forRemoval = true)
@Nullable
public Class<T> getTypeClass() { public Class<T> getTypeClass() {
return typeClass; return typeClass;
} }
@@ -72,7 +80,7 @@ public final class PersistentDataKeyType<T> {
* @param typeClass The type class. * @param typeClass The type class.
* @param name The name. * @param name The name.
*/ */
private PersistentDataKeyType(@NotNull final Class<T> typeClass, private PersistentDataKeyType(@Nullable final Class<T> typeClass,
@NotNull final String name) { @NotNull final String name) {
VALUES.add(this); VALUES.add(this);

View File

@@ -64,6 +64,21 @@ public abstract class DisplayModule extends PluginDependent<EcoPlugin> {
// Technically optional. // Technically optional.
} }
/**
* Display an item.
*
* @param itemStack The item.
* @param player The player.
* @param properties The properties.
* @param args Optional args for display.
*/
public void display(@NotNull final ItemStack itemStack,
@Nullable final Player player,
@NotNull final DisplayProperties properties,
@NotNull final Object... args) {
// Technically optional.
}
/** /**
* Revert an item. * Revert an item.
* *

View File

@@ -0,0 +1,18 @@
package com.willfp.eco.core.display;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Extra properties passed into {@link DisplayModule}.
*
* @param inInventory If the item was in an inventory.
* @param inGui If the item is assumed to be in a gui. (Not perfectly accurate).
* @param originalItem The original item, not to be modified.
*/
public record DisplayProperties(
boolean inInventory,
boolean inGui,
@NotNull ItemStack originalItem
) {
}

View File

@@ -68,6 +68,14 @@ public interface MenuBuilder {
*/ */
MenuBuilder onClose(@NotNull CloseHandler action); MenuBuilder onClose(@NotNull CloseHandler action);
/**
* Set the menu open handler.
*
* @param action The handler.
* @return The builder.
*/
MenuBuilder onOpen(@NotNull OpenHandler action);
/** /**
* Set the action to run on render. * Set the action to run on render.
* *

View File

@@ -0,0 +1,19 @@
package com.willfp.eco.core.gui.menu;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* Interface to run on menu open.
*/
@FunctionalInterface
public interface OpenHandler {
/**
* Performs this operation on the given arguments.
*
* @param player The player.
* @param menu The menu.
*/
void handle(@NotNull Player player,
@NotNull Menu menu);
}

View File

@@ -8,6 +8,7 @@ import org.bukkit.Material;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
@@ -17,6 +18,15 @@ import java.util.List;
* @param items The items. * @param items The items.
*/ */
public record MaskItems(@NotNull TestableItem... items) { public record MaskItems(@NotNull TestableItem... items) {
/**
* Create mask items from materials.
*
* @param materials The materials.
*/
public MaskItems(@NotNull final Material... materials) {
this(Arrays.stream(materials).map(MaterialTestableItem::new).toList().toArray(new TestableItem[0]));
}
/** /**
* Create MaskItems from a list of item names. * Create MaskItems from a list of item names.
* *

View File

@@ -28,6 +28,26 @@ public interface Slot {
*/ */
boolean isCaptive(); boolean isCaptive();
/**
* If the slot is not captive for a player.
*
* @param player The player.
* @return If not captive for the player.
*/
default boolean isNotCaptiveFor(@NotNull Player player) {
return false;
}
/**
* If the slot is captive from empty.
* If true, a captive item will be returned even if the item is the same as the rendered item.
*
* @return If captive from empty.
*/
default boolean isCaptiveFromEmpty() {
return false;
}
/** /**
* Create a builder for an ItemStack. * Create a builder for an ItemStack.
* *

View File

@@ -3,10 +3,12 @@ package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.gui.slot.functional.SlotHandler; import com.willfp.eco.core.gui.slot.functional.SlotHandler;
import com.willfp.eco.core.gui.slot.functional.SlotModifier; import com.willfp.eco.core.gui.slot.functional.SlotModifier;
import com.willfp.eco.core.gui.slot.functional.SlotUpdater; import com.willfp.eco.core.gui.slot.functional.SlotUpdater;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Predicate;
/** /**
* Builder to create slots. * Builder to create slots.
@@ -102,6 +104,14 @@ public interface SlotBuilder {
*/ */
SlotBuilder onMiddleClick(@NotNull SlotHandler handler); SlotBuilder onMiddleClick(@NotNull SlotHandler handler);
/**
* Prevent captive for players that match a predicate.
*
* @param predicate The predicate. Returns true when the slot should not be captive.
* @return The builder.
*/
SlotBuilder notCaptiveFor(@NotNull Predicate<Player> predicate);
/** /**
* Modify the ItemStack. * Modify the ItemStack.
* *
@@ -130,7 +140,17 @@ public interface SlotBuilder {
* *
* @return The builder. * @return The builder.
*/ */
SlotBuilder setCaptive(); default SlotBuilder setCaptive() {
return setCaptive(false);
}
/**
* Set slot to be a captive slot.
*
* @param fromEmpty If an item with the same output as the rendered item counts as captive.
* @return The builder.
*/
SlotBuilder setCaptive(boolean fromEmpty);
/** /**
* Build the slot. * Build the slot.

View File

@@ -4,6 +4,8 @@ import com.willfp.eco.core.integrations.Integration;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.math.BigDecimal;
/** /**
* Wrapper class for economy integrations. * Wrapper class for economy integrations.
*/ */
@@ -45,4 +47,14 @@ public interface EconomyIntegration extends Integration {
* @return The balance. * @return The balance.
*/ */
double getBalance(@NotNull OfflinePlayer player); double getBalance(@NotNull OfflinePlayer player);
/**
* Get the balance of a player.
*
* @param player The player.
* @return The balance.
*/
default BigDecimal getExactBalance(@NotNull OfflinePlayer player) {
return BigDecimal.valueOf(getBalance(player));
}
} }

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.core.integrations.economy;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.math.BigDecimal;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@@ -96,6 +97,20 @@ public final class EconomyManager {
return 0; return 0;
} }
/**
* Get the balance of a player.
*
* @param player The player.
* @return The balance.
*/
public static BigDecimal getExactBalance(@NotNull final OfflinePlayer player) {
for (EconomyIntegration integration : REGISTERED) {
return integration.getExactBalance(player);
}
return BigDecimal.ZERO;
}
private EconomyManager() { private EconomyManager() {
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

@@ -4,6 +4,7 @@ import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache; import com.github.benmanes.caffeine.cache.LoadingCache;
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.placeholder.AdditionalPlayer;
import com.willfp.eco.core.placeholder.InjectablePlaceholder; import com.willfp.eco.core.placeholder.InjectablePlaceholder;
import com.willfp.eco.core.placeholder.Placeholder; import com.willfp.eco.core.placeholder.Placeholder;
import com.willfp.eco.core.placeholder.PlaceholderInjectable; import com.willfp.eco.core.placeholder.PlaceholderInjectable;
@@ -11,11 +12,13 @@ import com.willfp.eco.core.placeholder.PlayerPlaceholder;
import com.willfp.eco.core.placeholder.PlayerStaticPlaceholder; import com.willfp.eco.core.placeholder.PlayerStaticPlaceholder;
import com.willfp.eco.core.placeholder.PlayerlessPlaceholder; import com.willfp.eco.core.placeholder.PlayerlessPlaceholder;
import com.willfp.eco.core.placeholder.StaticPlaceholder; import com.willfp.eco.core.placeholder.StaticPlaceholder;
import com.willfp.eco.util.StringUtils;
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.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@@ -23,6 +26,8 @@ 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; import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* Class to handle placeholder integrations. * Class to handle placeholder integrations.
@@ -56,11 +61,17 @@ public final class PlaceholderManager {
} }
@Override @Override
public @NotNull List<InjectablePlaceholder> getPlaceholderInjections() { public @NotNull
List<InjectablePlaceholder> getPlaceholderInjections() {
return Collections.emptyList(); return Collections.emptyList();
} }
}; };
/**
* The default PlaceholderAPI pattern; brought in for compatibility.
*/
private static final Pattern PATTERN = Pattern.compile("[%]([^%]+)[%]");
/** /**
* Register a new placeholder integration. * Register a new placeholder integration.
* *
@@ -192,7 +203,45 @@ public final class PlaceholderManager {
public static String translatePlaceholders(@NotNull final String text, public static String translatePlaceholders(@NotNull final String text,
@Nullable final Player player, @Nullable final Player player,
@NotNull final PlaceholderInjectable context) { @NotNull final PlaceholderInjectable context) {
return translatePlaceholders(text, player, context, new ArrayList<>());
}
/**
* Translate all placeholders with respect to a player.
*
* @param text The text that may contain placeholders to translate.
* @param player The player to translate the placeholders with respect to.
* @param context The injectable context.
* @param additionalPlayers Additional players to translate placeholders for.
* @return The text, translated.
*/
public static String translatePlaceholders(@NotNull final String text,
@Nullable final Player player,
@NotNull final PlaceholderInjectable context,
@NotNull final Collection<AdditionalPlayer> additionalPlayers) {
String processed = text; String processed = text;
// Prevent running 2 scans if there are no additional players.
if (!additionalPlayers.isEmpty()) {
List<String> found = findPlaceholdersIn(text);
for (AdditionalPlayer additionalPlayer : additionalPlayers) {
for (String placeholder : found) {
String prefix = "%" + additionalPlayer.getIdentifier() + "_";
if (placeholder.startsWith(prefix)) {
processed = processed.replace(
placeholder,
translatePlaceholders(
"%" + StringUtils.removePrefix(prefix, placeholder),
additionalPlayer.getPlayer()
)
);
}
}
}
}
for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) { for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) {
processed = integration.translate(processed, player); processed = integration.translate(processed, player);
} }
@@ -214,12 +263,21 @@ public final class PlaceholderManager {
* @return The placeholders. * @return The placeholders.
*/ */
public static List<String> findPlaceholdersIn(@NotNull final String text) { public static List<String> findPlaceholdersIn(@NotNull final String text) {
List<String> found = new ArrayList<>(); Set<String> found = new HashSet<>();
// Mock PAPI for those without it installed
if (REGISTERED_INTEGRATIONS.isEmpty()) {
Matcher matcher = PATTERN.matcher(text);
while (matcher.find()) {
found.add(matcher.group());
}
}
for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) { for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) {
found.addAll(integration.findPlaceholdersIn(text)); found.addAll(integration.findPlaceholdersIn(text));
} }
return found; return new ArrayList<>(found);
} }
private record EntryWithPlayer(@NotNull PlayerPlaceholder entry, private record EntryWithPlayer(@NotNull PlayerPlaceholder entry,

View File

@@ -1,7 +1,10 @@
package com.willfp.eco.core.integrations.shop; package com.willfp.eco.core.integrations.shop;
import com.willfp.eco.core.integrations.Integration; import com.willfp.eco.core.integrations.Integration;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
/** /**
@@ -25,4 +28,27 @@ public interface ShopIntegration extends Integration {
// Do nothing unless overridden. // Do nothing unless overridden.
return null; return null;
} }
/**
* Get the price of an item.
*
* @param itemStack The item.
* @return The price.
*/
default double getPrice(@NotNull final ItemStack itemStack) {
// Do nothing unless overridden.
return 0.0;
}
/**
* Get the price of an item.
*
* @param itemStack The item.
* @param player The player.
* @return The price.
*/
default double getPrice(@NotNull final ItemStack itemStack,
@NotNull final Player player) {
return getPrice(itemStack);
}
} }

View File

@@ -1,9 +1,12 @@
package com.willfp.eco.core.integrations.shop; package com.willfp.eco.core.integrations.shop;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
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;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@@ -52,6 +55,40 @@ public final class ShopManager {
} }
} }
/**
* Get the price of an item.
*
* @param itemStack The item.
* @return The price.
*/
public static double getItemPrice(@Nullable final ItemStack itemStack) {
return getItemPrice(itemStack, null);
}
/**
* Get the price of an item.
*
* @param itemStack The item.
* @param player The player.
* @return The price.
*/
public static double getItemPrice(@Nullable final ItemStack itemStack,
@Nullable final Player player) {
if (itemStack == null) {
return 0.0;
}
for (ShopIntegration shopIntegration : REGISTERED) {
if (player == null) {
return shopIntegration.getPrice(itemStack);
} else {
return shopIntegration.getPrice(itemStack, player);
}
}
return 0.0;
}
private ShopManager() { private ShopManager() {
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

@@ -2,6 +2,7 @@ package com.willfp.eco.core.items;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache; import com.github.benmanes.caffeine.cache.LoadingCache;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.fast.FastItemStack; import com.willfp.eco.core.fast.FastItemStack;
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;
@@ -185,6 +186,10 @@ public final class Items {
*/ */
@NotNull @NotNull
public static TestableItem lookup(@NotNull final String key) { public static TestableItem lookup(@NotNull final String key) {
if (key.startsWith("{")) {
return Eco.getHandler().getSNBTHandler().createTestable(key);
}
return ITEMS_LOOKUP_HANDLER.parseKey(key); return ITEMS_LOOKUP_HANDLER.parseKey(key);
} }
@@ -222,11 +227,14 @@ public final class Items {
if (part == null && PROVIDERS.containsKey(namespace)) { if (part == null && PROVIDERS.containsKey(namespace)) {
ItemProvider provider = PROVIDERS.get(namespace); ItemProvider provider = PROVIDERS.get(namespace);
item = provider.provideForKey(keyID);
if (item instanceof EmptyTestableItem || item == null) { String reformattedKey = keyID.replace("__", ":");
part = provider.provideForKey(reformattedKey);
if (part instanceof EmptyTestableItem || part == null) {
return new EmptyTestableItem(); return new EmptyTestableItem();
} }
registerCustomItem(namespacedKey, item); registerCustomItem(namespacedKey, part);
} }
/* /*
@@ -517,6 +525,28 @@ public final class Items {
return fis.unwrap(); return fis.unwrap();
} }
/**
* Convert item to SNBT.
*
* @param itemStack The item.
* @return The NBT string.
*/
@NotNull
public static String toSNBT(@NotNull final ItemStack itemStack) {
return Eco.getHandler().getSNBTHandler().toSNBT(itemStack);
}
/**
* Get item from SNBT.
*
* @param snbt The NBT string.
* @return The ItemStack, or null if invalid.
*/
@Nullable
public static ItemStack fromSNBT(@NotNull final String snbt) {
return Eco.getHandler().getSNBTHandler().fromSNBT(snbt);
}
private Items() { private Items() {
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

@@ -0,0 +1,41 @@
package com.willfp.eco.core.items;
import com.willfp.eco.core.Eco;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* API to handle SNBT conversion.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface SNBTHandler {
/**
* Get item from SNBT.
*
* @param snbt The NBT string.
* @return The ItemStack, or null if invalid.
*/
@Nullable
ItemStack fromSNBT(@NotNull String snbt);
/**
* Convert item to SNBT.
*
* @param itemStack The item.
* @return The NBT string.
*/
@NotNull
String toSNBT(@NotNull ItemStack itemStack);
/**
* Make TestableItem from SNBT.
*
* @param snbt The NBT string.
* @return The TestableItem.
*/
@NotNull
TestableItem createTestable(@NotNull String snbt);
}

View File

@@ -0,0 +1,49 @@
package com.willfp.eco.core.placeholder;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* An additional player with an identifier to parse placeholders for the player.
*/
public class AdditionalPlayer {
/**
* The player.
*/
private final Player player;
/**
* The identifier.
*/
private final String identifier;
/**
* Create a new additional player.
*
* @param player The player.
* @param identifier The identifier.
*/
public AdditionalPlayer(@NotNull final Player player,
@NotNull final String identifier) {
this.player = player;
this.identifier = identifier;
}
/**
* Get the player.
*
* @return The player.
*/
public Player getPlayer() {
return player;
}
/**
* Get the identifier.
*
* @return The identifier.
*/
public String getIdentifier() {
return identifier;
}
}

View File

@@ -20,7 +20,8 @@ public final class ProxyConstants {
public static final List<String> SUPPORTED_VERSIONS = Arrays.asList( public static final List<String> SUPPORTED_VERSIONS = Arrays.asList(
"v1_17_R1", "v1_17_R1",
"v1_18_R1", "v1_18_R1",
"v1_18_R2" "v1_18_R2",
"v1_19_R1"
); );
private ProxyConstants() { private ProxyConstants() {

View File

@@ -96,50 +96,53 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
shapedRecipe.setIngredient(character, parts.get(i).getItem().getType()); shapedRecipe.setIngredient(character, parts.get(i).getItem().getType());
} }
ShapedRecipe displayedRecipe = new ShapedRecipe(this.getDisplayedKey(), this.getOutput()); if (Eco.getHandler().getEcoPlugin().getConfigYml().getBool("displayed-recipes")) {
displayedRecipe.shape("012", "345", "678"); ShapedRecipe displayedRecipe = new ShapedRecipe(this.getDisplayedKey(), this.getOutput());
for (int i = 0; i < 9; i++) { displayedRecipe.shape("012", "345", "678");
if (parts.get(i) instanceof EmptyTestableItem) { for (int i = 0; i < 9; i++) {
continue; if (parts.get(i) instanceof EmptyTestableItem) {
} continue;
char character = String.valueOf(i).toCharArray()[0];
List<TestableItem> items = new ArrayList<>();
if (parts.get(i) instanceof GroupedTestableItems group) {
items.addAll(group.getChildren());
} else {
items.add(parts.get(i));
}
List<ItemStack> displayedItems = new ArrayList<>();
for (TestableItem testableItem : items) {
if (testableItem instanceof TestableStack) {
ItemStack item = testableItem.getItem().clone();
ItemMeta meta = item.getItemMeta();
assert meta != null;
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
assert lore != null;
lore.add("");
String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
add = add.replace("%amount%", String.valueOf(item.getAmount()));
lore.add(add);
meta.setLore(lore);
item.setItemMeta(meta);
displayedItems.add(item);
} else {
displayedItems.add(testableItem.getItem());
} }
char character = String.valueOf(i).toCharArray()[0];
List<TestableItem> items = new ArrayList<>();
if (parts.get(i) instanceof GroupedTestableItems group) {
items.addAll(group.getChildren());
} else {
items.add(parts.get(i));
}
List<ItemStack> displayedItems = new ArrayList<>();
for (TestableItem testableItem : items) {
if (testableItem instanceof TestableStack) {
ItemStack item = testableItem.getItem().clone();
ItemMeta meta = item.getItemMeta();
assert meta != null;
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
assert lore != null;
lore.add("");
String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
add = add.replace("%amount%", String.valueOf(item.getAmount()));
lore.add(add);
meta.setLore(lore);
item.setItemMeta(meta);
displayedItems.add(item);
} else {
displayedItems.add(testableItem.getItem());
}
}
displayedRecipe.setIngredient(character, new RecipeChoice.ExactChoice(displayedItems));
} }
displayedRecipe.setIngredient(character, new RecipeChoice.ExactChoice(displayedItems)); Bukkit.getServer().addRecipe(displayedRecipe);
} }
Bukkit.getServer().addRecipe(shapedRecipe); Bukkit.getServer().addRecipe(shapedRecipe);
Bukkit.getServer().addRecipe(displayedRecipe);
} }
/** /**

View File

@@ -101,43 +101,46 @@ public final class ShapelessCraftingRecipe extends PluginDependent<EcoPlugin> im
shapelessRecipe.addIngredient(part.getItem().getType()); shapelessRecipe.addIngredient(part.getItem().getType());
} }
ShapelessRecipe displayedRecipe = new ShapelessRecipe(this.getDisplayedKey(), this.getOutput()); if (Eco.getHandler().getEcoPlugin().getConfigYml().getBool("displayed-recipes")) {
for (TestableItem part : parts) { ShapelessRecipe displayedRecipe = new ShapelessRecipe(this.getDisplayedKey(), this.getOutput());
List<TestableItem> items = new ArrayList<>(); for (TestableItem part : parts) {
if (part instanceof GroupedTestableItems group) { List<TestableItem> items = new ArrayList<>();
items.addAll(group.getChildren()); if (part instanceof GroupedTestableItems group) {
} else { items.addAll(group.getChildren());
items.add(part);
}
List<ItemStack> displayedItems = new ArrayList<>();
for (TestableItem testableItem : items) {
if (testableItem instanceof TestableStack) {
ItemStack item = testableItem.getItem().clone();
ItemMeta meta = item.getItemMeta();
assert meta != null;
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
assert lore != null;
lore.add("");
String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
add = add.replace("%amount%", String.valueOf(item.getAmount()));
lore.add(add);
meta.setLore(lore);
item.setItemMeta(meta);
displayedItems.add(item);
} else { } else {
displayedItems.add(testableItem.getItem()); items.add(part);
} }
List<ItemStack> displayedItems = new ArrayList<>();
for (TestableItem testableItem : items) {
if (testableItem instanceof TestableStack) {
ItemStack item = testableItem.getItem().clone();
ItemMeta meta = item.getItemMeta();
assert meta != null;
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
assert lore != null;
lore.add("");
String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
add = add.replace("%amount%", String.valueOf(item.getAmount()));
lore.add(add);
meta.setLore(lore);
item.setItemMeta(meta);
displayedItems.add(item);
} else {
displayedItems.add(testableItem.getItem());
}
}
displayedRecipe.addIngredient(new RecipeChoice.ExactChoice(displayedItems));
} }
displayedRecipe.addIngredient(new RecipeChoice.ExactChoice(displayedItems)); Bukkit.getServer().addRecipe(displayedRecipe);
} }
Bukkit.getServer().addRecipe(shapelessRecipe); Bukkit.getServer().addRecipe(shapelessRecipe);
Bukkit.getServer().addRecipe(displayedRecipe);
} }
/** /**

View File

@@ -25,13 +25,30 @@ public class Paste {
*/ */
private final String contents; private final String contents;
/**
* The host.
*/
private final String host;
/** /**
* Create a new paste. * Create a new paste.
* *
* @param contents The contents. * @param contents The contents.
*/ */
public Paste(@NotNull final String contents) { public Paste(@NotNull final String contents) {
this(contents, "https://paste.willfp.com");
}
/**
* Create a new paste.
*
* @param contents The contents.
* @param host The host.
*/
public Paste(@NotNull final String contents,
@NotNull final String host) {
this.contents = contents; this.contents = contents;
this.host = host;
} }
/** /**
@@ -47,7 +64,7 @@ public class Paste {
byte[] postData = URLEncoder.encode(contents, StandardCharsets.UTF_8).getBytes(StandardCharsets.UTF_8); byte[] postData = URLEncoder.encode(contents, StandardCharsets.UTF_8).getBytes(StandardCharsets.UTF_8);
int postDataLength = postData.length; int postDataLength = postData.length;
String requestURL = "https://paste.willfp.com/documents"; String requestURL = this.host + "/documents";
URL url = new URL(requestURL); URL url = new URL(requestURL);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(true); conn.setDoOutput(true);
@@ -85,14 +102,26 @@ public class Paste {
* @return The paste. * @return The paste.
*/ */
public static Paste getFromHastebin(@NotNull final String token) { public static Paste getFromHastebin(@NotNull final String token) {
return getFromHastebin(token, "https://paste.willfp.com");
}
/**
* Get paste from hastebin.
*
* @param token The token.
* @param host The host.
* @return The paste.
*/
public static Paste getFromHastebin(@NotNull final String token,
@NotNull final String host) {
try { try {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
URL url = new URL("https://paste.willfp.com/raw/" + token); URL url = new URL(host + "/raw/" + token);
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET"); conn.setRequestMethod("GET");
try (var reader = new BufferedReader( try (var reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) { new InputStreamReader(conn.getInputStream()))) {
for (String line; (line = reader.readLine()) != null;) { for (String line; (line = reader.readLine()) != null; ) {
result.append(line); result.append(line);
} }
} }

View File

@@ -23,26 +23,25 @@ public final class BlockUtils {
*/ */
private static final int MAX_BLOCKS = 2500; private static final int MAX_BLOCKS = 2500;
private static Set<Block> getNearbyBlocks(@NotNull final Block origin, private static Set<Block> getNearbyBlocks(@NotNull final Block start,
@NotNull final List<Material> allowedMaterials, @NotNull final List<Material> allowedMaterials,
@NotNull final Set<Block> blocks, @NotNull final Set<Block> blocks,
final int limit) { final int limit) {
for (BlockFace face : BlockFace.values()) { for (BlockFace face : BlockFace.values()) {
Block block = origin.getRelative(face); Block block = start.getRelative(face);
if (!allowedMaterials.contains(block.getType())) {
continue;
}
if (blocks.contains(block)) { if (blocks.contains(block)) {
continue; continue;
} }
if (blocks.size() >= limit || blocks.size() > MAX_BLOCKS) { if (allowedMaterials.contains(block.getType())) {
return blocks; blocks.add(block);
}
blocks.addAll(getNearbyBlocks(block, allowedMaterials, blocks, limit)); if (blocks.size() > limit || blocks.size() > MAX_BLOCKS) {
return blocks;
}
blocks.addAll(getNearbyBlocks(block, allowedMaterials, blocks, limit));
}
} }
return blocks; return blocks;

View File

@@ -1,12 +1,24 @@
package com.willfp.eco.util; package com.willfp.eco.util;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.tuples.Pair; import com.willfp.eco.core.tuples.Pair;
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.util.function.Function;
/** /**
* Utilities / API methods for menus. * Utilities / API methods for menus.
*/ */
public final class MenuUtils { public final class MenuUtils {
/**
* The menu supplier.
*/
private static Function<Player, Menu> menuGetter = null;
/** /**
* Convert 0-53 slot to row and column pair. * Convert 0-53 slot to row and column pair.
* *
@@ -20,6 +32,40 @@ public final class MenuUtils {
return new Pair<>(row + 1, column + 1); return new Pair<>(row + 1, column + 1);
} }
/**
* Convert row and column to 0-53 slot.
*
* @param row The row.
* @param column The column.
* @return The slot.
*/
public static int rowColumnToSlot(final int row, final int column) {
return (column - 1) + ((row - 1) * 9);
}
/**
* Get a player's open menu.
*
* @param player The player.
* @return The menu, or null if none open.
*/
@Nullable
public static Menu getOpenMenu(@NotNull final Player player) {
return menuGetter.apply(player);
}
/**
* Initialize the tps supplier function.
*
* @param function The function.
*/
@ApiStatus.Internal
public static void initialize(@NotNull final Function<Player, Menu> function) {
Validate.isTrue(menuGetter == null, "Already initialized!");
menuGetter = function;
}
private MenuUtils() { private MenuUtils() {
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,5 +1,6 @@
package com.willfp.eco.util; package com.willfp.eco.util;
import com.willfp.eco.core.placeholder.AdditionalPlayer;
import com.willfp.eco.core.placeholder.InjectablePlaceholder; import com.willfp.eco.core.placeholder.InjectablePlaceholder;
import com.willfp.eco.core.placeholder.PlaceholderInjectable; import com.willfp.eco.core.placeholder.PlaceholderInjectable;
import com.willfp.eco.core.placeholder.StaticPlaceholder; import com.willfp.eco.core.placeholder.StaticPlaceholder;
@@ -11,6 +12,7 @@ import org.jetbrains.annotations.Nullable;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -263,7 +265,8 @@ public final class NumberUtils {
} }
@Override @Override
public @NotNull List<InjectablePlaceholder> getPlaceholderInjections() { public @NotNull
List<InjectablePlaceholder> getPlaceholderInjections() {
return Collections.emptyList(); return Collections.emptyList();
} }
}); });
@@ -282,7 +285,7 @@ public final class NumberUtils {
public static double evaluateExpression(@NotNull final String expression, public static double evaluateExpression(@NotNull final String expression,
@Nullable final Player player, @Nullable final Player player,
@NotNull final Iterable<StaticPlaceholder> statics) { @NotNull final Iterable<StaticPlaceholder> statics) {
return crunch.evaluate(expression, player, new PlaceholderInjectable() { return evaluateExpression(expression, player, new PlaceholderInjectable() {
@Override @Override
public void clearInjectedPlaceholders() { public void clearInjectedPlaceholders() {
// Do nothing. // Do nothing.
@@ -304,13 +307,29 @@ public final class NumberUtils {
* *
* @param expression The expression. * @param expression The expression.
* @param player The player. * @param player The player.
* @param context The injectable placeholders. * @param context The injectable placeholders.
* @return The value of the expression, or zero if invalid. * @return The value of the expression, or zero if invalid.
*/ */
public static double evaluateExpression(@NotNull final String expression, public static double evaluateExpression(@NotNull final String expression,
@Nullable final Player player, @Nullable final Player player,
@NotNull final PlaceholderInjectable context) { @NotNull final PlaceholderInjectable context) {
return crunch.evaluate(expression, player, context); return evaluateExpression(expression, player, context, new ArrayList<>());
}
/**
* Evaluate an expression with respect to a player (for placeholders).
*
* @param expression The expression.
* @param player The player.
* @param context The injectable placeholders.
* @param additionalPlayers Additional players to parse placeholders for.
* @return The value of the expression, or zero if invalid.
*/
public static double evaluateExpression(@NotNull final String expression,
@Nullable final Player player,
@NotNull final PlaceholderInjectable context,
@NotNull final Collection<AdditionalPlayer> additionalPlayers) {
return crunch.evaluate(expression, player, context, additionalPlayers);
} }
/** /**
@@ -332,14 +351,16 @@ public final class NumberUtils {
/** /**
* Evaluate an expression. * Evaluate an expression.
* *
* @param expression The expression. * @param expression The expression.
* @param player The player. * @param player The player.
* @param injectable The injectable placeholders. * @param injectable The injectable placeholders.
* @param additionalPlayers The additional players.
* @return The value of the expression, or zero if invalid. * @return The value of the expression, or zero if invalid.
*/ */
double evaluate(@NotNull String expression, double evaluate(@NotNull String expression,
@Nullable Player player, @Nullable Player player,
@NotNull PlaceholderInjectable injectable); @NotNull PlaceholderInjectable injectable,
@NotNull Collection<AdditionalPlayer> additionalPlayers);
} }
private NumberUtils() { private NumberUtils() {

View File

@@ -43,6 +43,7 @@ public final class StringUtils {
.add(Pattern.compile("<G#([0-9A-Fa-f]{6})>(.*?)</G#([0-9A-Fa-f]{6})>", Pattern.CASE_INSENSITIVE)) .add(Pattern.compile("<G#([0-9A-Fa-f]{6})>(.*?)</G#([0-9A-Fa-f]{6})>", Pattern.CASE_INSENSITIVE))
.add(Pattern.compile("<#:([0-9A-Fa-f]{6})>(.*?)</#:([0-9A-Fa-f]{6})>")) .add(Pattern.compile("<#:([0-9A-Fa-f]{6})>(.*?)</#:([0-9A-Fa-f]{6})>"))
.add(Pattern.compile("\\{#:([0-9A-Fa-f]{6})}(.*?)\\{/#:([0-9A-Fa-f]{6})}")) .add(Pattern.compile("\\{#:([0-9A-Fa-f]{6})}(.*?)\\{/#:([0-9A-Fa-f]{6})}"))
.add(Pattern.compile("\\{#([0-9A-Fa-f]{6})>}(.*?)\\{#([0-9A-Fa-f]{6})<}"))
.build(); .build();
/** /**

View File

@@ -152,6 +152,20 @@ public final class VectorUtils {
return vectors.toArray(new Vector[0]); return vectors.toArray(new Vector[0]);
} }
/**
* Get if a vector is a safe velocity.
*
* @param vec The vector to check.
* @return If safe.
*/
public static boolean isSafeVelocity(@NotNull final Vector vec) {
double x = Math.abs(vec.getX());
double y = Math.abs(vec.getY());
double z = Math.abs(vec.getZ());
return x < 4 && y < 4 && z < 4;
}
private VectorUtils() { private VectorUtils() {
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

@@ -121,8 +121,8 @@ fun CommandBase.addSubcommand(
} }
/** /**
* Kotlin builder for commands. * Kotlin builder for commands. Inherits plugin, permission, players
* Inherits plugin, permission, players only. * only.
* *
* @param name The command name. * @param name The command name.
* @param init The builder. * @param init The builder.

View File

@@ -4,9 +4,7 @@ package com.willfp.eco.core.config
import com.willfp.eco.core.config.interfaces.Config import com.willfp.eco.core.config.interfaces.Config
/** /** Helper class to create configs with a kotlin DSL. */
* Helper class to create configs with a kotlin DSL.
*/
class DSLConfig internal constructor(type: ConfigType) : TransientConfig(emptyMap(), type) { class DSLConfig internal constructor(type: ConfigType) : TransientConfig(emptyMap(), type) {
/** /**
* Map a key to a value. * Map a key to a value.

View File

@@ -5,47 +5,33 @@ package com.willfp.eco.core.data
import org.bukkit.persistence.PersistentDataContainer import org.bukkit.persistence.PersistentDataContainer
import org.bukkit.persistence.PersistentDataType import org.bukkit.persistence.PersistentDataType
/** /** @see ExtendedPersistentDataContainer.set */
* @see ExtendedPersistentDataContainer.set
*/
fun <T : Any, Z : Any> PersistentDataContainer.set(key: String, dataType: PersistentDataType<T, Z>, value: Z) = fun <T : Any, Z : Any> PersistentDataContainer.set(key: String, dataType: PersistentDataType<T, Z>, value: Z) =
ExtendedPersistentDataContainer.extend(this).set(key, dataType, value) ExtendedPersistentDataContainer.extend(this).set(key, dataType, value)
/** /** @see ExtendedPersistentDataContainer.has */
* @see ExtendedPersistentDataContainer.has
*/
fun <T : Any, Z : Any> PersistentDataContainer.has(key: String, dataType: PersistentDataType<T, Z>): Boolean = fun <T : Any, Z : Any> PersistentDataContainer.has(key: String, dataType: PersistentDataType<T, Z>): Boolean =
ExtendedPersistentDataContainer.extend(this).has(key, dataType) ExtendedPersistentDataContainer.extend(this).has(key, dataType)
/** /** @see ExtendedPersistentDataContainer.get */
* @see ExtendedPersistentDataContainer.get
*/
fun <T : Any, Z : Any> PersistentDataContainer.get(key: String, dataType: PersistentDataType<T, Z>): Z? = fun <T : Any, Z : Any> PersistentDataContainer.get(key: String, dataType: PersistentDataType<T, Z>): Z? =
ExtendedPersistentDataContainer.extend(this).get(key, dataType) ExtendedPersistentDataContainer.extend(this).get(key, dataType)
/** /** @see ExtendedPersistentDataContainer.getOrDefault */
* @see ExtendedPersistentDataContainer.getOrDefault
*/
fun <T : Any, Z : Any> PersistentDataContainer.getOrDefault( fun <T : Any, Z : Any> PersistentDataContainer.getOrDefault(
key: String, key: String,
dataType: PersistentDataType<T, Z>, dataType: PersistentDataType<T, Z>,
defaultValue: Z defaultValue: Z
): Z = ExtendedPersistentDataContainer.extend(this).getOrDefault(key, dataType, defaultValue) ): Z = ExtendedPersistentDataContainer.extend(this).getOrDefault(key, dataType, defaultValue)
/** /** @see ExtendedPersistentDataContainer.getAllKeys */
* @see ExtendedPersistentDataContainer.getAllKeys
*/
fun PersistentDataContainer.getAllKeys(): Set<String> = fun PersistentDataContainer.getAllKeys(): Set<String> =
ExtendedPersistentDataContainer.extend(this).allKeys ExtendedPersistentDataContainer.extend(this).allKeys
/** /** @see ExtendedPersistentDataContainer.remove */
* @see ExtendedPersistentDataContainer.remove
*/
fun PersistentDataContainer.remove(key: String) = fun PersistentDataContainer.remove(key: String) =
ExtendedPersistentDataContainer.extend(this).remove(key) ExtendedPersistentDataContainer.extend(this).remove(key)
/** /** Create a new PDC without the need for an adapter context. */
* Create a new PDC without the need for an adapter context.
*/
fun newPersistentDataContainer() = fun newPersistentDataContainer() =
ExtendedPersistentDataContainer.create().base ExtendedPersistentDataContainer.create().base

View File

@@ -5,14 +5,10 @@ package com.willfp.eco.core.data
import org.bukkit.OfflinePlayer import org.bukkit.OfflinePlayer
import org.bukkit.Server import org.bukkit.Server
/** /** @see PlayerProfile.load */
* @see PlayerProfile.load
*/
val OfflinePlayer.profile: PlayerProfile val OfflinePlayer.profile: PlayerProfile
get() = PlayerProfile.load(this) get() = PlayerProfile.load(this)
/** /** @see ServerProfile.load */
* @see ServerProfile.load
*/
val Server.profile: ServerProfile val Server.profile: ServerProfile
get() = ServerProfile.load() get() = ServerProfile.load()

View File

@@ -5,8 +5,6 @@ package com.willfp.eco.core.entities
import com.willfp.eco.core.entities.ai.EntityController import com.willfp.eco.core.entities.ai.EntityController
import org.bukkit.entity.Mob import org.bukkit.entity.Mob
/** /** @see EntityController.getFor */
* @see EntityController.getFor
*/
val <T : Mob> T.controller: EntityController<T> val <T : Mob> T.controller: EntityController<T>
get() = EntityController.getFor(this) get() = EntityController.getFor(this)

View File

@@ -4,8 +4,6 @@ package com.willfp.eco.core.fast
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
/** /** @see FastItemStack.wrap */
* @see FastItemStack.wrap
*/
fun ItemStack.fast(): FastItemStack = fun ItemStack.fast(): FastItemStack =
FastItemStack.wrap(this) FastItemStack.wrap(this)

View File

@@ -6,41 +6,36 @@ import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.menu.MenuBuilder import com.willfp.eco.core.gui.menu.MenuBuilder
import com.willfp.eco.core.gui.slot.Slot import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.core.gui.slot.SlotBuilder import com.willfp.eco.core.gui.slot.SlotBuilder
import com.willfp.eco.core.items.TestableItem
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryClickEvent import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.InventoryCloseEvent import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
/** /** @see SlotBuilder.onLeftClick */
* @see SlotBuilder.onLeftClick
*/
fun SlotBuilder.onLeftClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder = fun SlotBuilder.onLeftClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onLeftClick { a, b, c -> action(a, b, c) } this.onLeftClick { a, b, c -> action(a, b, c) }
/** /** @see SlotBuilder.onRightClick */
* @see SlotBuilder.onRightClick
*/
fun SlotBuilder.onRightClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder = fun SlotBuilder.onRightClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onRightClick { a, b, c -> action(a, b, c) } this.onRightClick { a, b, c -> action(a, b, c) }
/** /** @see SlotBuilder.onShiftLeftClick */
* @see SlotBuilder.onShiftLeftClick
*/
fun SlotBuilder.onShiftLeftClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder = fun SlotBuilder.onShiftLeftClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onShiftLeftClick { a, b, c -> action(a, b, c) } this.onShiftLeftClick { a, b, c -> action(a, b, c) }
/** /** @see SlotBuilder.onShiftRightClick */
* @see SlotBuilder.onShiftRightClick
*/
fun SlotBuilder.onShiftRightClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder = fun SlotBuilder.onShiftRightClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onShiftRightClick { a, b, c -> action(a, b, c) } this.onShiftRightClick { a, b, c -> action(a, b, c) }
/** /** @see SlotBuilder.onShiftRightClick */
* @see SlotBuilder.onShiftRightClick
*/
fun SlotBuilder.onMiddleClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder = fun SlotBuilder.onMiddleClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onMiddleClick { a, b, c -> action(a, b, c) } this.onMiddleClick { a, b, c -> action(a, b, c) }
/** @see SlotBuilder.notCaptiveFor */
fun SlotBuilder.notCaptiveFor(test: (Player) -> Boolean): SlotBuilder =
this.notCaptiveFor { test(it) }
/** /**
* @see SlotBuilder.setModifier * @see SlotBuilder.setModifier
* @deprecated Use SlotUpdater instead. * @deprecated Use SlotUpdater instead.
@@ -50,15 +45,32 @@ fun SlotBuilder.onMiddleClick(action: (InventoryClickEvent, Slot, Menu) -> Unit)
fun SlotBuilder.setModifier(action: (Player, Menu, ItemStack) -> Unit): SlotBuilder = fun SlotBuilder.setModifier(action: (Player, Menu, ItemStack) -> Unit): SlotBuilder =
this.setUpdater { a, b, c -> c.apply { action(a, b, c) } } this.setUpdater { a, b, c -> c.apply { action(a, b, c) } }
/** /** @see SlotBuilder.setUpdater */
* @see SlotBuilder.setUpdater
*/
fun SlotBuilder.setUpdater(action: (Player, Menu, ItemStack) -> ItemStack): SlotBuilder = fun SlotBuilder.setUpdater(action: (Player, Menu, ItemStack) -> ItemStack): SlotBuilder =
this.setUpdater { a, b, c -> action(a, b, c) } this.setUpdater { a, b, c -> action(a, b, c) }
/** /** Kotlin builder for slots. */
* Kotlin builder for slots. fun captiveSlot(): Slot = Slot.builder().setCaptive().build()
*/
/** Kotlin builder for slots. */
fun captiveSlot(
init: SlotBuilder.() -> Unit
): Slot {
val builder = Slot.builder().setCaptive()
init(builder)
return builder.build()
}
/** Kotlin builder for slots. */
fun slot(
init: SlotBuilder.() -> Unit
): Slot {
val builder = Slot.builder()
init(builder)
return builder.build()
}
/** Kotlin builder for slots. */
fun slot( fun slot(
item: ItemStack, item: ItemStack,
init: SlotBuilder.() -> Unit init: SlotBuilder.() -> Unit
@@ -68,9 +80,17 @@ fun slot(
return builder.build() return builder.build()
} }
/** /** Kotlin builder for slots. */
* Kotlin builder for slots. fun slot(
*/ item: ItemStack
): Slot = Slot.builder(item).build()
/** Kotlin builder for slots. */
fun slot(
item: TestableItem
): Slot = Slot.builder(item.item).build()
/** Kotlin builder for slots. */
fun slot( fun slot(
provider: (Player, Menu) -> ItemStack, provider: (Player, Menu) -> ItemStack,
init: SlotBuilder.() -> Unit init: SlotBuilder.() -> Unit
@@ -80,27 +100,28 @@ fun slot(
return builder.build() return builder.build()
} }
/** /** Kotlin builder for slots. */
* @see MenuBuilder.onClose fun slot(
*/ provider: (Player, Menu) -> ItemStack
): Slot = Slot.builder { a, b -> provider(a, b) }.build()
/** @see MenuBuilder.onClose */
fun MenuBuilder.onClose(action: (InventoryCloseEvent, Menu) -> Unit): MenuBuilder = fun MenuBuilder.onClose(action: (InventoryCloseEvent, Menu) -> Unit): MenuBuilder =
this.onClose { a, b -> action(a, b) } this.onClose { a, b -> action(a, b) }
/** /** @see MenuBuilder.onOpen */
* @see MenuBuilder.modify fun MenuBuilder.onOpen(action: (Player, Menu) -> Unit): MenuBuilder =
*/ this.onOpen { a, b -> action(a, b) }
/** @see MenuBuilder.modify */
fun MenuBuilder.modify(modifier: (MenuBuilder) -> Unit): MenuBuilder = fun MenuBuilder.modify(modifier: (MenuBuilder) -> Unit): MenuBuilder =
this.modfiy { modifier(it) } this.modfiy { modifier(it) }
/** /** @see MenuBuilder.onRender */
* @see MenuBuilder.onRender
*/
fun MenuBuilder.onRender(action: (Player, Menu) -> Unit): MenuBuilder = fun MenuBuilder.onRender(action: (Player, Menu) -> Unit): MenuBuilder =
this.onRender { a, b -> action(a, b) } this.onRender { a, b -> action(a, b) }
/** /** Kotlin builder for menus. */
* Kotlin builder for menus.
*/
fun menu( fun menu(
rows: Int, rows: Int,
init: MenuBuilder.() -> Unit init: MenuBuilder.() -> Unit

View File

@@ -0,0 +1,42 @@
@file:JvmName("EconomyExtensions")
package com.willfp.eco.core.integrations.economy
import org.bukkit.OfflinePlayer
import java.math.BigDecimal
/** @see EconomyManager */
var OfflinePlayer.balance: Double
get() = EconomyManager.getBalance(this)
set(value) {
if (value <= 0) {
EconomyManager.removeMoney(this, this.balance)
return
}
val diff = this.balance - value
if (diff > 0) {
EconomyManager.removeMoney(this, diff)
} else if (diff < 0) {
EconomyManager.giveMoney(this, -diff)
}
}
/** @see EconomyManager */
var OfflinePlayer.exactBalance: BigDecimal
get() = EconomyManager.getBalance(this).toBigDecimal()
set(value) {
if (value <= BigDecimal.ZERO) {
EconomyManager.removeMoney(this, this.balance)
return
}
val diff = this.exactBalance - value
if (diff > BigDecimal.ZERO) {
EconomyManager.removeMoney(this, diff.toDouble())
} else if (diff < BigDecimal.ZERO) {
EconomyManager.giveMoney(this, -diff.toDouble())
}
}

View File

@@ -0,0 +1,14 @@
@file:JvmName("ShopExtensions")
package com.willfp.eco.core.integrations.shop
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
/** @see ShopManager.getItemPrice **/
val ItemStack.price: Double
get() = ShopManager.getItemPrice(this)
/** @see ShopManager.getItemPrice **/
fun ItemStack.getPrice(player: Player): Double =
ShopManager.getItemPrice(this, player)

View File

@@ -6,21 +6,15 @@ import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta import org.bukkit.inventory.meta.ItemMeta
import org.bukkit.persistence.PersistentDataContainer import org.bukkit.persistence.PersistentDataContainer
/** /** @see Items.toLookupString */
* @see Items.toLookupString
*/
fun ItemStack?.toLookupString(): String = fun ItemStack?.toLookupString(): String =
Items.toLookupString(this) Items.toLookupString(this)
/** /** @see Items.mergeFrom */
* @see Items.mergeFrom
*/
fun ItemStack.mergeFrom(other: ItemStack): ItemStack = fun ItemStack.mergeFrom(other: ItemStack): ItemStack =
Items.mergeFrom(other, this) Items.mergeFrom(other, this)
/** /** @see Items.mergeFrom */
* @see Items.mergeFrom
*/
fun ItemMeta.mergeFrom(other: ItemMeta): ItemMeta = fun ItemMeta.mergeFrom(other: ItemMeta): ItemMeta =
Items.mergeFrom(other, this) Items.mergeFrom(other, this)
@@ -34,8 +28,6 @@ var ItemStack.baseNBT: PersistentDataContainer
Items.setBaseNBT(this, value) Items.setBaseNBT(this, value)
} }
/** /** @see Items.setBaseNBT */
* @see Items.setBaseNBT
*/
fun ItemStack.clearNBT() = fun ItemStack.clearNBT() =
Items.setBaseNBT(this, null) Items.setBaseNBT(this, null)

View File

@@ -5,8 +5,6 @@ package com.willfp.eco.util
import org.bukkit.entity.Arrow import org.bukkit.entity.Arrow
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
/** /** @see ArrowUtils.getBow */
* @see ArrowUtils.getBow
*/
val Arrow.bow: ItemStack? val Arrow.bow: ItemStack?
get() = ArrowUtils.getBow(this) get() = ArrowUtils.getBow(this)

View File

@@ -4,8 +4,6 @@ package com.willfp.eco.util
import org.bukkit.block.Block import org.bukkit.block.Block
/** /** @see ArrowUtils.getBow */
* @see ArrowUtils.getBow
*/
val Block.isPlayerPlaced: Boolean val Block.isPlayerPlaced: Boolean
get() = BlockUtils.isPlayerPlaced(this) get() = BlockUtils.isPlayerPlaced(this)

View File

@@ -5,14 +5,10 @@ package com.willfp.eco.util
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
/** /** @see DurabilityUtils.damageItem */
* @see DurabilityUtils.damageItem
*/
fun ItemStack.damage(damage: Int) = fun ItemStack.damage(damage: Int) =
DurabilityUtils.damageItem(this, damage) DurabilityUtils.damageItem(this, damage)
/** /** @see DurabilityUtils.damageItem */
* @see DurabilityUtils.damageItem
*/
fun ItemStack.damage(damage: Int, player: Player) = fun ItemStack.damage(damage: Int, player: Player) =
DurabilityUtils.damageItem(player, this, damage) DurabilityUtils.damageItem(player, this, damage)

View File

@@ -2,20 +2,18 @@
package com.willfp.eco.util package com.willfp.eco.util
/** /** @see ListUtils.listToFrequencyMap */
* @see ListUtils.listToFrequencyMap
*/
fun <T> List<T>.toFrequencyMap(): Map<T, Int> = fun <T> List<T>.toFrequencyMap(): Map<T, Int> =
ListUtils.listToFrequencyMap(this) ListUtils.listToFrequencyMap(this)
/** /** @see ListUtils.containsIgnoreCase */
* @see ListUtils.containsIgnoreCase
*/
fun Iterable<String>.containsIgnoreCase(element: String): Boolean = fun Iterable<String>.containsIgnoreCase(element: String): Boolean =
ListUtils.containsIgnoreCase(this, element) ListUtils.containsIgnoreCase(this, element)
/** /** @see ListUtils.create2DList */
* @see ListUtils.create2DList
*/
fun <T> create2DList(rows: Int, columns: Int): MutableList<MutableList<T>> = fun <T> create2DList(rows: Int, columns: Int): MutableList<MutableList<T>> =
ListUtils.create2DList(rows, columns) ListUtils.create2DList(rows, columns)
/** @see ListUtils.toSingletonList */
fun <T> T.toSingletonList(): List<T> =
ListUtils.toSingletonList(this)

View File

@@ -0,0 +1,10 @@
@file:JvmName("MenuUtilsExtensions")
package com.willfp.eco.util
import com.willfp.eco.core.gui.menu.Menu
import org.bukkit.entity.Player
/** @see MenuUtils.getOpenMenu */
val Player.openMenu: Menu?
get() = MenuUtils.getOpenMenu(this)

View File

@@ -4,26 +4,18 @@ package com.willfp.eco.util
import com.willfp.eco.core.EcoPlugin import com.willfp.eco.core.EcoPlugin
/** /** @see NamespacedKeyUtils.fromString */
* @see NamespacedKeyUtils.fromString
*/
fun namespacedKeyOf(string: String) = fun namespacedKeyOf(string: String) =
NamespacedKeyUtils.fromString(string) NamespacedKeyUtils.fromString(string)
/** /** @see NamespacedKeyUtils.fromString */
* @see NamespacedKeyUtils.fromString
*/
fun safeNamespacedKeyOf(string: String) = fun safeNamespacedKeyOf(string: String) =
NamespacedKeyUtils.fromStringOrNull(string) NamespacedKeyUtils.fromStringOrNull(string)
/** /** @see NamespacedKeyUtils.create */
* @see NamespacedKeyUtils.create
*/
fun namespacedKeyOf(namespace: String, key: String) = fun namespacedKeyOf(namespace: String, key: String) =
NamespacedKeyUtils.create(namespace, key) NamespacedKeyUtils.create(namespace, key)
/** /** @see EcoPlugin.namespacedKeyFactory */
* @see EcoPlugin.namespacedKeyFactory
*/
fun namespacedKeyOf(plugin: EcoPlugin, key: String) = fun namespacedKeyOf(plugin: EcoPlugin, key: String) =
plugin.namespacedKeyFactory.create(key) plugin.namespacedKeyFactory.create(key)

View File

@@ -2,8 +2,6 @@
package com.willfp.eco.util package com.willfp.eco.util
/** /** @see NumberUtils.toNumeral */
* @see NumberUtils.toNumeral
*/
fun Number.toNumeral(): String = fun Number.toNumeral(): String =
NumberUtils.toNumeral(this.toInt()) NumberUtils.toNumeral(this.toInt())

View File

@@ -8,32 +8,22 @@ import org.bukkit.command.CommandSender
import org.bukkit.entity.Entity import org.bukkit.entity.Entity
import org.bukkit.entity.Player import org.bukkit.entity.Player
/** /** @see PlayerUtils.getSavedDisplayName */
* @see PlayerUtils.getSavedDisplayName
*/
val OfflinePlayer.savedDisplayName: String val OfflinePlayer.savedDisplayName: String
get() = PlayerUtils.getSavedDisplayName(this) get() = PlayerUtils.getSavedDisplayName(this)
/** /** @see PlayerUtils.getAudience */
* @see PlayerUtils.getAudience
*/
fun Player.asAudience(): Audience = fun Player.asAudience(): Audience =
PlayerUtils.getAudience(this) PlayerUtils.getAudience(this)
/** /** @see PlayerUtils.getAudience */
* @see PlayerUtils.getAudience
*/
fun CommandSender.asAudience(): Audience = fun CommandSender.asAudience(): Audience =
PlayerUtils.getAudience(this) PlayerUtils.getAudience(this)
/** /** @see PlayerUtils.runExempted */
* @see PlayerUtils.runExempted
*/
fun Player.runExempted(action: () -> Unit) = fun Player.runExempted(action: () -> Unit) =
PlayerUtils.runExempted(this, action) PlayerUtils.runExempted(this, action)
/** /** @see PlayerUtils.tryAsPlayer */
* @see PlayerUtils.tryAsPlayer
*/
fun Entity?.tryAsPlayer(): Player? = fun Entity?.tryAsPlayer(): Player? =
PlayerUtils.tryAsPlayer(this) PlayerUtils.tryAsPlayer(this)

View File

@@ -4,8 +4,6 @@ package com.willfp.eco.util
import org.bukkit.potion.PotionData import org.bukkit.potion.PotionData
/** /** @see PotionData.duration */
* @see PotionData.duration
*/
val PotionData.duration: Int val PotionData.duration: Int
get() = PotionUtils.getDuration(this) get() = PotionUtils.getDuration(this)

View File

@@ -4,8 +4,6 @@ package com.willfp.eco.util
import org.bukkit.Server import org.bukkit.Server
/** /** @see ServerUtils.getTps */
* @see ServerUtils.getTps
*/
val Server.tps: Double val Server.tps: Double
get() = ServerUtils.getTps() get() = ServerUtils.getTps()

View File

@@ -5,33 +5,23 @@ package com.willfp.eco.util
import net.kyori.adventure.text.Component import net.kyori.adventure.text.Component
import org.bukkit.entity.Player import org.bukkit.entity.Player
/** /** @see StringUtils.toComponent */
* @see StringUtils.toComponent
*/
fun String.toComponent(): Component = fun String.toComponent(): Component =
StringUtils.toComponent(this) StringUtils.toComponent(this)
/** /** @see StringUtils.jsonToComponent */
* @see StringUtils.jsonToComponent
*/
fun String.jsonToComponent(): Component = fun String.jsonToComponent(): Component =
StringUtils.jsonToComponent(this) StringUtils.jsonToComponent(this)
/** /** @see StringUtils.toLegacy */
* @see StringUtils.toLegacy
*/
fun Component.toLegacy(): String = fun Component.toLegacy(): String =
StringUtils.toLegacy(this) StringUtils.toLegacy(this)
/** /** @see StringUtils.componentToJson */
* @see StringUtils.componentToJson
*/
fun Component.toJSON(): String = fun Component.toJSON(): String =
StringUtils.componentToJson(this) StringUtils.componentToJson(this)
/** /** @see StringUtils.format */
* @see StringUtils.format
*/
fun String.formatEco( fun String.formatEco(
player: Player? = null, player: Player? = null,
formatPlaceholders: Boolean = false formatPlaceholders: Boolean = false
@@ -41,9 +31,7 @@ fun String.formatEco(
if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS
) )
/** /** @see StringUtils.formatList */
* @see StringUtils.formatList
*/
fun List<String>.formatEco( fun List<String>.formatEco(
player: Player? = null, player: Player? = null,
formatPlaceholders: Boolean = false formatPlaceholders: Boolean = false
@@ -53,14 +41,10 @@ fun List<String>.formatEco(
if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS
) )
/** /** @see StringUtils.splitAround */
* @see StringUtils.splitAround
*/
fun String.splitAround(separator: String): Array<String> = fun String.splitAround(separator: String): Array<String> =
StringUtils.splitAround(this, separator) StringUtils.splitAround(this, separator)
/** /** @see StringUtils.toNiceString */
* @see StringUtils.toNiceString
*/
fun Any?.toNiceString(): String = fun Any?.toNiceString(): String =
StringUtils.toNiceString(this) StringUtils.toNiceString(this)

View File

@@ -4,14 +4,14 @@ package com.willfp.eco.util
import org.bukkit.util.Vector import org.bukkit.util.Vector
/** /** @see VectorUtils.isFinite */
* @see VectorUtils.isFinite
*/
val Vector.isFinite: Boolean val Vector.isFinite: Boolean
get() = VectorUtils.isFinite(this) get() = VectorUtils.isFinite(this)
/** /** @see VectorUtils.simplifyVector */
* @see VectorUtils.simplifyVector
*/
fun Vector.simplify(): Vector = fun Vector.simplify(): Vector =
VectorUtils.simplifyVector(this) VectorUtils.simplifyVector(this)
/** @see VectorUtils.isSafeVelocity */
val Vector.isSafeVelocity: Boolean
get() = VectorUtils.isSafeVelocity(this)

View File

@@ -16,7 +16,7 @@ fun ConfigType.toMap(input: String?): Map<String, Any?> =
fun ConfigType.toString(map: Map<String, Any?>): String = fun ConfigType.toString(map: Map<String, Any?>): String =
this.handler.toString(map) this.handler.toString(map)
fun Any?.constrainConfigTypes(type: ConfigType): Any? = when (this) { internal fun Any?.constrainConfigTypes(type: ConfigType): Any? = when (this) {
is Map<*, *> -> EcoConfigSection(type, this.normalizeToConfig(type)) is Map<*, *> -> EcoConfigSection(type, this.normalizeToConfig(type))
is Iterable<*> -> { is Iterable<*> -> {
if (this.firstOrNull() == null) { if (this.firstOrNull() == null) {
@@ -31,7 +31,7 @@ fun Any?.constrainConfigTypes(type: ConfigType): Any? = when (this) {
else -> this else -> this
} }
fun Map<*, *>.normalizeToConfig(type: ConfigType): Map<String, Any?> { internal fun Map<*, *>.normalizeToConfig(type: ConfigType): Map<String, Any?> {
val building = mutableMapOf<String, Any?>() val building = mutableMapOf<String, Any?>()
for ((unprocessedKey, value) in this.entries) { for ((unprocessedKey, value) in this.entries) {

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.internal.config
import com.willfp.eco.core.config.ConfigType 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.placeholder.InjectablePlaceholder import com.willfp.eco.core.placeholder.InjectablePlaceholder
import com.willfp.eco.core.placeholder.StaticPlaceholder
import com.willfp.eco.util.StringUtils import com.willfp.eco.util.StringUtils
import org.bukkit.configuration.file.YamlConfiguration import org.bukkit.configuration.file.YamlConfiguration
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@@ -103,11 +104,13 @@ open class EcoConfig(
} }
override fun getSubsectionOrNull(path: String): Config? { override fun getSubsectionOrNull(path: String): Config? {
return get(path) as? Config return (get(path) as? Config)?.apply { this.addInjectablePlaceholder(injections) }
} }
override fun getSubsectionsOrNull(path: String): List<Config>? { override fun getSubsectionsOrNull(path: String): List<Config>? {
return (get(path) as? Iterable<Config>)?.toList() return (get(path) as? Iterable<Config>)
?.map { it.apply { this.addInjectablePlaceholder(injections) } }
?.toList()
} }
override fun getType(): ConfigType { override fun getType(): ConfigType {
@@ -135,7 +138,14 @@ open class EcoConfig(
format: Boolean, format: Boolean,
option: StringUtils.FormatOption option: StringUtils.FormatOption
): String? { ): String? {
val string = get(path)?.toString() ?: return null var string = get(path)?.toString() ?: return null
if (format && option == StringUtils.FormatOption.WITH_PLACEHOLDERS) {
for (injection in placeholderInjections) {
if (injection is StaticPlaceholder) {
string = string.replace("%${injection.identifier}%", injection.value)
}
}
}
return if (format) StringUtils.format(string, option) else string return if (format) StringUtils.format(string, option) else string
} }
@@ -144,7 +154,18 @@ open class EcoConfig(
format: Boolean, format: Boolean,
option: StringUtils.FormatOption option: StringUtils.FormatOption
): List<String>? { ): List<String>? {
val strings = (get(path) as? Iterable<*>)?.map { it.toString() } ?: return null val strings = (get(path) as? Iterable<*>)?.map { it.toString() }?.toMutableList() ?: return null
if (placeholderInjections.isNotEmpty() && format && option == StringUtils.FormatOption.WITH_PLACEHOLDERS) {
strings.replaceAll {
var string = it
for (injection in placeholderInjections) {
if (injection is StaticPlaceholder) {
string = string.replace("%${injection.identifier}%", injection.value)
}
}
string
}
}
return if (format) StringUtils.formatList(strings, option) else strings return if (format) StringUtils.formatList(strings, option) else strings
} }

View File

@@ -4,6 +4,7 @@ import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.display.Display import com.willfp.eco.core.display.Display
import com.willfp.eco.core.display.DisplayHandler import com.willfp.eco.core.display.DisplayHandler
import com.willfp.eco.core.display.DisplayModule import com.willfp.eco.core.display.DisplayModule
import com.willfp.eco.core.display.DisplayProperties
import com.willfp.eco.core.fast.fast import com.willfp.eco.core.fast.fast
import org.bukkit.NamespacedKey import org.bukkit.NamespacedKey
import org.bukkit.entity.Player import org.bukkit.entity.Player
@@ -32,13 +33,21 @@ class EcoDisplayHandler(plugin: EcoPlugin) : DisplayHandler {
} }
} }
Display.revert(itemStack) Display.revert(itemStack)
if (!itemStack.hasItemMeta()) { if (!itemStack.hasItemMeta()) {
return itemStack return itemStack
} }
val original = itemStack.clone()
val inventory = player?.openInventory?.topInventory
val inInventory = inventory?.contains(original) ?: false
val props = DisplayProperties(
inInventory,
inInventory && inventory?.holder == null,
original
)
for ((_, modules) in registeredModules) { for ((_, modules) in registeredModules) {
for (module in modules) { for (module in modules) {
@@ -48,6 +57,7 @@ class EcoDisplayHandler(plugin: EcoPlugin) : DisplayHandler {
if (player != null) { if (player != null) {
module.display(itemStack, player as Player?, *varargs) module.display(itemStack, player as Player?, *varargs)
module.display(itemStack, player as Player?, props, *varargs)
} }
} }
} }

View File

@@ -2,6 +2,7 @@ package com.willfp.eco.internal.gui.menu
import com.willfp.eco.core.gui.menu.CloseHandler import com.willfp.eco.core.gui.menu.CloseHandler
import com.willfp.eco.core.gui.menu.Menu import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.menu.OpenHandler
import com.willfp.eco.core.gui.slot.Slot import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.internal.gui.slot.EcoSlot import com.willfp.eco.internal.gui.slot.EcoSlot
import com.willfp.eco.util.NamespacedKeyUtils import com.willfp.eco.util.NamespacedKeyUtils
@@ -19,7 +20,8 @@ class EcoMenu(
val slots: List<MutableList<EcoSlot>>, val slots: List<MutableList<EcoSlot>>,
private val title: String, private val title: String,
private val onClose: CloseHandler, private val onClose: CloseHandler,
private val onRender: (Player, Menu) -> Unit private val onRender: (Player, Menu) -> Unit,
private val onOpen: OpenHandler
) : Menu { ) : Menu {
override fun getSlot(row: Int, column: Int): Slot { override fun getSlot(row: Int, column: Int): Slot {
if (row < 1 || row > this.rows) { if (row < 1 || row > this.rows) {
@@ -49,11 +51,14 @@ class EcoMenu(
player.openInventory(inventory) player.openInventory(inventory)
MenuHandler.registerInventory(inventory, this, player) MenuHandler.registerInventory(inventory, this, player)
onOpen.handle(player, this)
inventory.asRenderedInventory()?.generateCaptive()
return inventory return inventory
} }
fun handleClose(event: InventoryCloseEvent) { fun handleClose(event: InventoryCloseEvent) {
onClose.handle(event, this) onClose.handle(event, this)
event.inventory.asRenderedInventory()?.generateCaptive()
MenuHandler.unregisterInventory(event.inventory) MenuHandler.unregisterInventory(event.inventory)
} }

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.internal.gui.menu
import com.willfp.eco.core.gui.menu.CloseHandler import com.willfp.eco.core.gui.menu.CloseHandler
import com.willfp.eco.core.gui.menu.Menu import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.menu.MenuBuilder import com.willfp.eco.core.gui.menu.MenuBuilder
import com.willfp.eco.core.gui.menu.OpenHandler
import com.willfp.eco.core.gui.slot.FillerMask import com.willfp.eco.core.gui.slot.FillerMask
import com.willfp.eco.core.gui.slot.FillerSlot import com.willfp.eco.core.gui.slot.FillerSlot
import com.willfp.eco.core.gui.slot.Slot import com.willfp.eco.core.gui.slot.Slot
@@ -21,6 +22,7 @@ class EcoMenuBuilder(private val rows: Int ) : MenuBuilder {
private var maskSlots: List<MutableList<Slot?>> private var maskSlots: List<MutableList<Slot?>>
private val slots: List<MutableList<Slot?>> = ListUtils.create2DList(rows, 9) private val slots: List<MutableList<Slot?>> = ListUtils.create2DList(rows, 9)
private var onClose = CloseHandler { _, _ -> } private var onClose = CloseHandler { _, _ -> }
private var onOpen = OpenHandler { _, _ -> }
private var onRender: (Player, Menu) -> Unit = { _, _ -> } private var onRender: (Player, Menu) -> Unit = { _, _ -> }
override fun setTitle(title: String): MenuBuilder { override fun setTitle(title: String): MenuBuilder {
@@ -54,6 +56,11 @@ class EcoMenuBuilder(private val rows: Int ) : MenuBuilder {
return this return this
} }
override fun onOpen(action: OpenHandler): MenuBuilder {
onOpen = action
return this
}
override fun onRender(action: BiConsumer<Player, Menu>): MenuBuilder { override fun onRender(action: BiConsumer<Player, Menu>): MenuBuilder {
onRender = { a, b -> action.accept(a, b) } onRender = { a, b -> action.accept(a, b) }
return this return this
@@ -83,7 +90,7 @@ class EcoMenuBuilder(private val rows: Int ) : MenuBuilder {
finalSlots.add(tempRow) finalSlots.add(tempRow)
} }
return EcoMenu(rows, finalSlots, title, onClose, onRender) return EcoMenu(rows, finalSlots, title, onClose, onRender, onOpen)
} }
init { init {

View File

@@ -34,7 +34,7 @@ class MenuRenderedInventory(
menu.runOnRender(player) menu.runOnRender(player)
} }
private fun generateCaptive() { fun generateCaptive() {
captiveItems.clear() captiveItems.clear()
for (i in 0 until inventory.size) { for (i in 0 until inventory.size) {
val (row, column) = MenuUtils.convertSlotToRowColumn(i) val (row, column) = MenuUtils.convertSlotToRowColumn(i)
@@ -43,7 +43,17 @@ class MenuRenderedInventory(
val renderedItem = slot.getItemStack(player) val renderedItem = slot.getItemStack(player)
val itemStack = inventory.getItem(i) ?: continue val itemStack = inventory.getItem(i) ?: continue
if (itemStack == renderedItem || itemStack.type.isAir || itemStack.amount == 0) { if (slot.isNotCaptiveFor(player)) {
continue
}
if (!slot.isCaptiveFromEmpty) {
if (itemStack == renderedItem) {
continue
}
}
if (itemStack.type.isAir || itemStack.amount == 0) {
continue continue
} }

View File

@@ -2,23 +2,36 @@ package com.willfp.eco.internal.gui.slot
import com.willfp.eco.core.gui.slot.functional.SlotHandler import com.willfp.eco.core.gui.slot.functional.SlotHandler
import com.willfp.eco.core.gui.slot.functional.SlotProvider import com.willfp.eco.core.gui.slot.functional.SlotProvider
import org.bukkit.entity.Player
class EcoCaptiveSlot( class EcoCaptiveSlot(
provider: SlotProvider provider: SlotProvider,
private val captiveFromEmpty: Boolean,
private val notCaptiveFor: (Player) -> Boolean
) : EcoSlot( ) : EcoSlot(
provider, provider,
allowMovingItem, captiveWithTest(notCaptiveFor),
allowMovingItem, captiveWithTest(notCaptiveFor),
allowMovingItem, captiveWithTest(notCaptiveFor),
allowMovingItem, captiveWithTest(notCaptiveFor),
allowMovingItem, captiveWithTest(notCaptiveFor),
{ _, _, prev -> prev } { _, _, prev -> prev }
) { ) {
override fun isCaptive(): Boolean { override fun isCaptive(): Boolean {
return true return true
} }
override fun isCaptiveFromEmpty(): Boolean {
return captiveFromEmpty
}
override fun isNotCaptiveFor(player: Player): Boolean {
return notCaptiveFor(player)
}
} }
private val allowMovingItem = SlotHandler { event, _, _ -> private fun captiveWithTest(test: (Player) -> Boolean): SlotHandler {
event.isCancelled = false return SlotHandler { event, _, _ ->
} event.isCancelled = test(event.whoClicked as Player)
}
}

View File

@@ -38,7 +38,7 @@ open class EcoSlot(
} }
override fun getItemStack(player: Player): ItemStack { override fun getItemStack(player: Player): ItemStack {
val menu = player.openInventory.topInventory.getMenu()!! val menu = player.openInventory.topInventory.getMenu() ?: return ItemStack(Material.AIR)
val prev = provider.provide(player, menu) val prev = provider.provide(player, menu)
return updater.update(player, menu, prev) ?: ItemStack(Material.AIR) return updater.update(player, menu, prev) ?: ItemStack(Material.AIR)
} }

View File

@@ -1,25 +1,39 @@
package com.willfp.eco.internal.gui.slot package com.willfp.eco.internal.gui.slot
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.slot.Slot import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.core.gui.slot.SlotBuilder import com.willfp.eco.core.gui.slot.SlotBuilder
import com.willfp.eco.core.gui.slot.functional.SlotHandler import com.willfp.eco.core.gui.slot.functional.SlotHandler
import com.willfp.eco.core.gui.slot.functional.SlotProvider import com.willfp.eco.core.gui.slot.functional.SlotProvider
import com.willfp.eco.core.gui.slot.functional.SlotUpdater import com.willfp.eco.core.gui.slot.functional.SlotUpdater
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryClickEvent
import java.util.function.Predicate
internal object NoOpSlot : SlotHandler {
override fun handle(event: InventoryClickEvent, slot: Slot, menu: Menu) {
}
override fun equals(other: Any?): Boolean {
return other is NoOpSlot
}
}
internal class NoOpForPlayer
class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder { class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
private var captive = false private var captive = false
private var captiveFromEmpty = false
private var updater: SlotUpdater = SlotUpdater { player, menu, _ -> provider.provide(player, menu) } private var updater: SlotUpdater = SlotUpdater { player, menu, _ -> provider.provide(player, menu) }
private var onLeftClick = private var onLeftClick: SlotHandler = NoOpSlot
SlotHandler { _, _, _ -> run { } } private var onRightClick: SlotHandler = NoOpSlot
private var onRightClick = private var onShiftLeftClick: SlotHandler = NoOpSlot
SlotHandler { _, _, _ -> run { } } private var onShiftRightClick: SlotHandler = NoOpSlot
private var onShiftLeftClick = private var onMiddleClick: SlotHandler = NoOpSlot
SlotHandler { _, _, _ -> run { } }
private var onShiftRightClick = private var notCaptiveFor: (Player) -> Boolean = { false }
SlotHandler { _, _, _ -> run { } }
private var onMiddleClick =
SlotHandler { _, _, _ -> run { } }
override fun onLeftClick(action: SlotHandler): SlotBuilder { override fun onLeftClick(action: SlotHandler): SlotBuilder {
onLeftClick = action onLeftClick = action
@@ -46,8 +60,14 @@ class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
return this return this
} }
override fun setCaptive(): SlotBuilder { override fun notCaptiveFor(predicate: Predicate<Player>): SlotBuilder {
notCaptiveFor = { predicate.test(it) }
return this
}
override fun setCaptive(fromEmpty: Boolean): SlotBuilder {
captive = true captive = true
captiveFromEmpty = fromEmpty
return this return this
} }
@@ -58,9 +78,21 @@ class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
override fun build(): Slot { override fun build(): Slot {
return if (captive) { return if (captive) {
EcoCaptiveSlot(provider) EcoCaptiveSlot(
provider,
captiveFromEmpty,
notCaptiveFor
)
} else { } else {
EcoSlot(provider, onLeftClick, onRightClick, onShiftLeftClick, onShiftRightClick, onMiddleClick, updater) EcoSlot(
provider,
onLeftClick,
onRightClick,
onShiftLeftClick,
onShiftRightClick,
onMiddleClick,
updater
)
} }
} }
} }

View File

@@ -1,5 +1,5 @@
plugins { plugins {
id("io.papermc.paperweight.userdev") version "1.3.5" id("io.papermc.paperweight.userdev") version "1.3.6"
} }
group = "com.willfp" group = "com.willfp"

View File

@@ -26,6 +26,8 @@ import org.bukkit.inventory.ItemFlag
import org.bukkit.persistence.PersistentDataContainer import org.bukkit.persistence.PersistentDataContainer
import org.bukkit.persistence.PersistentDataType import org.bukkit.persistence.PersistentDataType
import kotlin.experimental.and import kotlin.experimental.and
import kotlin.experimental.inv
import kotlin.experimental.or
@Suppress("UsePropertyAccessSyntax") @Suppress("UsePropertyAccessSyntax")
class EcoFastItemStack( class EcoFastItemStack(
@@ -149,35 +151,29 @@ class EcoFastItemStack(
override fun getDisplayName(): String = displayNameComponent.toLegacy() override fun getDisplayName(): String = displayNameComponent.toLegacy()
override fun addItemFlags(vararg hideFlags: ItemFlag) { override fun addItemFlags(vararg hideFlags: ItemFlag) {
for (flag in hideFlags) { for (f in hideFlags) {
this.flagBits = this.flagBits or getBitModifier(flag) this.flagBits = this.flagBits or getBitModifier(f)
} }
apply() apply()
} }
override fun removeItemFlags(vararg hideFlags: ItemFlag) { override fun removeItemFlags(vararg hideFlags: ItemFlag) {
for (flag in hideFlags) { for (f in hideFlags) {
this.flagBits = this.flagBits and getBitModifier(flag) this.flagBits = this.flagBits and getBitModifier(f).inv()
} }
apply() apply()
} }
override fun getItemFlags(): MutableSet<ItemFlag> { override fun getItemFlags(): Set<ItemFlag> {
val flags = mutableSetOf<ItemFlag>() val currentFlags = mutableSetOf<ItemFlag>()
for (f in ItemFlag.values()) {
var flagArr: Array<ItemFlag> if (hasItemFlag(f)) {
val size = ItemFlag.values().also { flagArr = it }.size currentFlags.add(f)
for (i in 0 until size) {
val flag = flagArr[i]
if (this.hasItemFlag(flag)) {
flags.add(flag)
} }
} }
return currentFlags
return flags
} }
override fun hasItemFlag(flag: ItemFlag): Boolean { override fun hasItemFlag(flag: ItemFlag): Boolean {
@@ -194,15 +190,15 @@ class EcoFastItemStack(
} }
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION") @Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
private var flagBits: Int private var flagBits: Byte
get() = get() =
if (handle.hasTag() && handle.getTag()!!.contains( if (handle.hasTag() && handle.getTag()!!.contains(
"HideFlags", "HideFlags",
99 99
) )
) handle.getTag()!!.getInt("HideFlags") else 0 ) handle.getTag()!!.getInt("HideFlags").toByte() else 0
set(value) = set(value) =
handle.getOrCreateTag().putInt("HideFlags", value) handle.getOrCreateTag().putInt("HideFlags", value.toInt())
override fun getRepairCost(): Int { override fun getRepairCost(): Int {
return handle.getBaseRepairCost() return handle.getBaseRepairCost()
@@ -268,8 +264,8 @@ class EcoFastItemStack(
bukkit.mergeIfNeeded(handle) bukkit.mergeIfNeeded(handle)
} }
private fun getBitModifier(hideFlag: ItemFlag): Int { private fun getBitModifier(hideFlag: ItemFlag): Byte {
return 1 shl hideFlag.ordinal return (1 shl hideFlag.ordinal).toByte()
} }
override fun unwrap(): org.bukkit.inventory.ItemStack { override fun unwrap(): org.bukkit.inventory.ItemStack {

View File

@@ -1,5 +1,5 @@
plugins { plugins {
id("io.papermc.paperweight.userdev") version "1.3.5" id("io.papermc.paperweight.userdev") version "1.3.6"
} }
group = "com.willfp" group = "com.willfp"

View File

@@ -0,0 +1,53 @@
package com.willfp.eco.internal.spigot.proxy.v1_17_R1
import com.willfp.eco.core.items.TestableItem
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.SnbtPrinterTagVisitor
import net.minecraft.nbt.TagParser
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack
import org.bukkit.inventory.ItemStack
class SNBTConverter : SNBTConverterProxy {
override fun fromSNBT(snbt: String): ItemStack? {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return null
val nms = net.minecraft.world.item.ItemStack.of(nbt)
return CraftItemStack.asBukkitCopy(nms)
}
override fun toSNBT(itemStack: ItemStack): String {
val nms = CraftItemStack.asNMSCopy(itemStack)
return SnbtPrinterTagVisitor().visit(nms.save(CompoundTag()))
}
override fun makeSNBTTestable(snbt: String): TestableItem {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return EmptyTestableItem()
val nms = net.minecraft.world.item.ItemStack.of(nbt)
if (nms == net.minecraft.world.item.ItemStack.EMPTY) {
return EmptyTestableItem()
}
nbt.remove("Count")
return SNBTTestableItem(CraftItemStack.asBukkitCopy(nms), nbt)
}
class SNBTTestableItem(
private val item: ItemStack,
private val tag: CompoundTag
) : TestableItem {
override fun matches(itemStack: ItemStack?): Boolean {
if (itemStack == null) {
return false
}
val nms = CraftItemStack.asNMSCopy(itemStack)
val nmsTag = nms.save(CompoundTag())
nmsTag.remove("Count")
return tag.copy().merge(nmsTag) == nmsTag
}
override fun getItem(): ItemStack = item
}
}

View File

@@ -20,6 +20,10 @@ class Skull : SkullProxy {
setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java) setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java)
setProfile.isAccessible = true setProfile.isAccessible = true
} }
if (base64.length < 20) {
return
}
val uuid = UUID( val uuid = UUID(
base64.substring(base64.length - 20).hashCode().toLong(), base64.substring(base64.length - 20).hashCode().toLong(),
base64.substring(base64.length - 10).hashCode().toLong() base64.substring(base64.length - 10).hashCode().toLong()
@@ -39,6 +43,6 @@ class Skull : SkullProxy {
val profile = profile[meta] as GameProfile? ?: return null val profile = profile[meta] as GameProfile? ?: return null
val properties = profile.properties ?: return null val properties = profile.properties ?: return null
val prop = properties["textures"] ?: return null val prop = properties["textures"] ?: return null
return prop.toMutableList().firstOrNull()?.value return prop.toMutableList().firstOrNull()?.name
} }
} }

View File

@@ -2,7 +2,10 @@ package com.willfp.eco.internal.spigot.proxy.v1_17_R1
import com.willfp.eco.core.display.Display import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.trading.MerchantOffer import net.minecraft.world.item.trading.MerchantOffer
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftMerchantRecipe import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftMerchantRecipe
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.MerchantRecipe import org.bukkit.inventory.MerchantRecipe
@@ -15,20 +18,17 @@ class VillagerTrade : VillagerTradeProxy {
recipe: MerchantRecipe, recipe: MerchantRecipe,
player: Player player: Player
): MerchantRecipe { ): MerchantRecipe {
val oldRecipe = recipe as CraftMerchantRecipe recipe as CraftMerchantRecipe
val newRecipe = CraftMerchantRecipe(
Display.display(recipe.getResult().clone(), player), val nbt = getHandle(recipe).createTag()
recipe.getUses(), for (tag in arrayOf("buy", "buyB", "sell")) {
recipe.getMaxUses(), val nms = ItemStack.of(nbt.getCompound(tag))
recipe.hasExperienceReward(), val displayed = Display.display(CraftItemStack.asBukkitCopy(nms), player)
recipe.getVillagerExperience(), val itemNBT = CraftItemStack.asNMSCopy(displayed).save(CompoundTag())
recipe.getPriceMultiplier() nbt.put(tag, itemNBT)
)
for (ingredient in recipe.getIngredients()) {
newRecipe.addIngredient(Display.display(ingredient.clone(), player))
} }
getHandle(newRecipe).specialPriceDiff = getHandle(oldRecipe).specialPriceDiff
return newRecipe return CraftMerchantRecipe(MerchantOffer(nbt))
} }
private fun getHandle(recipe: CraftMerchantRecipe): MerchantOffer { private fun getHandle(recipe: CraftMerchantRecipe): MerchantOffer {

View File

@@ -1,5 +1,5 @@
plugins { plugins {
id("io.papermc.paperweight.userdev") version "1.3.5" id("io.papermc.paperweight.userdev") version "1.3.6"
} }
group = "com.willfp" group = "com.willfp"

View File

@@ -0,0 +1,53 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.core.items.TestableItem
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.SnbtPrinterTagVisitor
import net.minecraft.nbt.TagParser
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
import org.bukkit.inventory.ItemStack
class SNBTConverter : SNBTConverterProxy {
override fun fromSNBT(snbt: String): ItemStack? {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return null
val nms = net.minecraft.world.item.ItemStack.of(nbt)
return CraftItemStack.asBukkitCopy(nms)
}
override fun toSNBT(itemStack: ItemStack): String {
val nms = CraftItemStack.asNMSCopy(itemStack)
return SnbtPrinterTagVisitor().visit(nms.save(CompoundTag()))
}
override fun makeSNBTTestable(snbt: String): TestableItem {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return EmptyTestableItem()
val nms = net.minecraft.world.item.ItemStack.of(nbt)
if (nms == net.minecraft.world.item.ItemStack.EMPTY) {
return EmptyTestableItem()
}
nbt.remove("Count")
return SNBTTestableItem(CraftItemStack.asBukkitCopy(nms), nbt)
}
class SNBTTestableItem(
private val item: ItemStack,
private val tag: CompoundTag
) : TestableItem {
override fun matches(itemStack: ItemStack?): Boolean {
if (itemStack == null) {
return false
}
val nms = CraftItemStack.asNMSCopy(itemStack)
val nmsTag = nms.save(CompoundTag())
nmsTag.remove("Count")
return tag.copy().merge(nmsTag) == nmsTag
}
override fun getItem(): ItemStack = item
}
}

View File

@@ -20,6 +20,10 @@ class Skull : SkullProxy {
setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java) setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java)
setProfile.isAccessible = true setProfile.isAccessible = true
} }
if (base64.length < 20) {
return
}
val uuid = UUID( val uuid = UUID(
base64.substring(base64.length - 20).hashCode().toLong(), base64.substring(base64.length - 20).hashCode().toLong(),
base64.substring(base64.length - 10).hashCode().toLong() base64.substring(base64.length - 10).hashCode().toLong()
@@ -39,6 +43,6 @@ class Skull : SkullProxy {
val profile = profile[meta] as GameProfile? ?: return null val profile = profile[meta] as GameProfile? ?: return null
val properties = profile.properties ?: return null val properties = profile.properties ?: return null
val prop = properties["textures"] ?: return null val prop = properties["textures"] ?: return null
return prop.toMutableList().firstOrNull()?.value return prop.toMutableList().firstOrNull()?.name
} }
} }

View File

@@ -2,7 +2,10 @@ package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.core.display.Display import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.trading.MerchantOffer import net.minecraft.world.item.trading.MerchantOffer
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftMerchantRecipe import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftMerchantRecipe
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.MerchantRecipe import org.bukkit.inventory.MerchantRecipe
@@ -15,20 +18,17 @@ class VillagerTrade : VillagerTradeProxy {
recipe: MerchantRecipe, recipe: MerchantRecipe,
player: Player player: Player
): MerchantRecipe { ): MerchantRecipe {
val oldRecipe = recipe as CraftMerchantRecipe recipe as CraftMerchantRecipe
val newRecipe = CraftMerchantRecipe(
Display.display(recipe.getResult().clone(), player), val nbt = getHandle(recipe).createTag()
recipe.getUses(), for (tag in arrayOf("buy", "buyB", "sell")) {
recipe.getMaxUses(), val nms = ItemStack.of(nbt.getCompound(tag))
recipe.hasExperienceReward(), val displayed = Display.display(CraftItemStack.asBukkitCopy(nms), player)
recipe.getVillagerExperience(), val itemNBT = CraftItemStack.asNMSCopy(displayed).save(CompoundTag())
recipe.getPriceMultiplier() nbt.put(tag, itemNBT)
)
for (ingredient in recipe.getIngredients()) {
newRecipe.addIngredient(Display.display(ingredient.clone(), player))
} }
getHandle(newRecipe).setSpecialPriceDiff(getHandle(oldRecipe).getSpecialPriceDiff())
return newRecipe return CraftMerchantRecipe(MerchantOffer(nbt))
} }
private fun getHandle(recipe: CraftMerchantRecipe): MerchantOffer { private fun getHandle(recipe: CraftMerchantRecipe): MerchantOffer {

View File

@@ -1,5 +1,5 @@
plugins { plugins {
id("io.papermc.paperweight.userdev") version "1.3.5" id("io.papermc.paperweight.userdev") version "1.3.6"
} }
group = "com.willfp" group = "com.willfp"

View File

@@ -0,0 +1,53 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R2
import com.willfp.eco.core.items.TestableItem
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.SnbtPrinterTagVisitor
import net.minecraft.nbt.TagParser
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack
import org.bukkit.inventory.ItemStack
class SNBTConverter : SNBTConverterProxy {
override fun fromSNBT(snbt: String): ItemStack? {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return null
val nms = net.minecraft.world.item.ItemStack.of(nbt)
return CraftItemStack.asBukkitCopy(nms)
}
override fun toSNBT(itemStack: ItemStack): String {
val nms = CraftItemStack.asNMSCopy(itemStack)
return SnbtPrinterTagVisitor().visit(nms.save(CompoundTag()))
}
override fun makeSNBTTestable(snbt: String): TestableItem {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return EmptyTestableItem()
val nms = net.minecraft.world.item.ItemStack.of(nbt)
if (nms == net.minecraft.world.item.ItemStack.EMPTY) {
return EmptyTestableItem()
}
nbt.remove("Count")
return SNBTTestableItem(CraftItemStack.asBukkitCopy(nms), nbt)
}
class SNBTTestableItem(
private val item: ItemStack,
private val tag: CompoundTag
) : TestableItem {
override fun matches(itemStack: ItemStack?): Boolean {
if (itemStack == null) {
return false
}
val nms = CraftItemStack.asNMSCopy(itemStack)
val nmsTag = nms.save(CompoundTag())
nmsTag.remove("Count")
return tag.copy().merge(nmsTag) == nmsTag
}
override fun getItem(): ItemStack = item
}
}

View File

@@ -20,6 +20,10 @@ class Skull : SkullProxy {
setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java) setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java)
setProfile.isAccessible = true setProfile.isAccessible = true
} }
if (base64.length < 20) {
return
}
val uuid = UUID( val uuid = UUID(
base64.substring(base64.length - 20).hashCode().toLong(), base64.substring(base64.length - 20).hashCode().toLong(),
base64.substring(base64.length - 10).hashCode().toLong() base64.substring(base64.length - 10).hashCode().toLong()
@@ -39,6 +43,6 @@ class Skull : SkullProxy {
val profile = profile[meta] as GameProfile? ?: return null val profile = profile[meta] as GameProfile? ?: return null
val properties = profile.properties ?: return null val properties = profile.properties ?: return null
val prop = properties["textures"] ?: return null val prop = properties["textures"] ?: return null
return prop.toMutableList().firstOrNull()?.value return prop.toMutableList().firstOrNull()?.name
} }
} }

View File

@@ -2,7 +2,10 @@ package com.willfp.eco.internal.spigot.proxy.v1_18_R2
import com.willfp.eco.core.display.Display import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.trading.MerchantOffer import net.minecraft.world.item.trading.MerchantOffer
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftMerchantRecipe import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftMerchantRecipe
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.MerchantRecipe import org.bukkit.inventory.MerchantRecipe
@@ -15,20 +18,17 @@ class VillagerTrade : VillagerTradeProxy {
recipe: MerchantRecipe, recipe: MerchantRecipe,
player: Player player: Player
): MerchantRecipe { ): MerchantRecipe {
val oldRecipe = recipe as CraftMerchantRecipe recipe as CraftMerchantRecipe
val newRecipe = CraftMerchantRecipe(
Display.display(recipe.getResult().clone(), player), val nbt = getHandle(recipe).createTag()
recipe.getUses(), for (tag in arrayOf("buy", "buyB", "sell")) {
recipe.getMaxUses(), val nms = ItemStack.of(nbt.getCompound(tag))
recipe.hasExperienceReward(), val displayed = Display.display(CraftItemStack.asBukkitCopy(nms), player)
recipe.getVillagerExperience(), val itemNBT = CraftItemStack.asNMSCopy(displayed).save(CompoundTag())
recipe.getPriceMultiplier() nbt.put(tag, itemNBT)
)
for (ingredient in recipe.getIngredients()) {
newRecipe.addIngredient(Display.display(ingredient.clone(), player))
} }
getHandle(newRecipe).setSpecialPriceDiff(getHandle(oldRecipe).getSpecialPriceDiff())
return newRecipe return CraftMerchantRecipe(MerchantOffer(nbt))
} }
private fun getHandle(recipe: CraftMerchantRecipe): MerchantOffer { private fun getHandle(recipe: CraftMerchantRecipe): MerchantOffer {

View File

@@ -0,0 +1,39 @@
plugins {
id("io.papermc.paperweight.userdev") version "1.3.6"
}
group = "com.willfp"
version = rootProject.version
dependencies {
implementation(project(":eco-core:core-nms:nms-common"))
paperDevBundle("1.19-R0.1-SNAPSHOT")
implementation("net.kyori:adventure-text-minimessage:4.11.0") {
version {
strictly("4.11.0")
}
exclude(group = "net.kyori", module = "adventure-api")
}
}
tasks {
build {
dependsOn(reobfJar)
}
reobfJar {
mustRunAfter(shadowJar)
}
shadowJar {
relocate(
"com.willfp.eco.internal.spigot.proxy.common",
"com.willfp.eco.internal.spigot.proxy.v1_19_R1.common"
)
relocate(
"net.kyori.adventure.text.minimessage",
"com.willfp.eco.internal.spigot.proxy.v1_19_R1.minimessage"
)
}
}

View File

@@ -0,0 +1,15 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.internal.spigot.proxy.AutoCraftProxy
import net.minecraft.network.protocol.game.ClientboundPlaceGhostRecipePacket
import net.minecraft.resources.ResourceLocation
class AutoCraft : AutoCraftProxy {
override fun modifyPacket(packet: Any) {
val recipePacket = packet as ClientboundPlaceGhostRecipePacket
val fKey = recipePacket.javaClass.getDeclaredField("b")
fKey.isAccessible = true
val key = fKey[recipePacket] as ResourceLocation
fKey[recipePacket] = ResourceLocation(key.namespace, key.path + "_displayed")
}
}

View File

@@ -0,0 +1,93 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.ChatComponentProxy
import net.kyori.adventure.nbt.api.BinaryTagHolder
import net.kyori.adventure.text.BuildableComponent
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.TranslatableComponent
import net.kyori.adventure.text.event.HoverEvent
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
import net.minecraft.nbt.TagParser
import org.bukkit.Material
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
@Suppress("UNCHECKED_CAST")
class ChatComponent : ChatComponentProxy {
private val gsonComponentSerializer = GsonComponentSerializer.gson()
override fun modifyComponent(obj: Any, player: Player): Any {
if (obj !is net.minecraft.network.chat.Component) {
return obj
}
val component = gsonComponentSerializer.deserialize(
net.minecraft.network.chat.Component.Serializer.toJson(
obj
)
).asComponent() as BuildableComponent<*, *>
val newComponent = modifyBaseComponent(component, player)
return net.minecraft.network.chat.Component.Serializer.fromJson(
gsonComponentSerializer.serialize(newComponent.asComponent())
) ?: obj
}
private fun modifyBaseComponent(baseComponent: Component, player: Player): Component {
var component = baseComponent
if (component is TranslatableComponent) {
val args = mutableListOf<Component>()
for (arg in component.args()) {
args.add(modifyBaseComponent(arg, player))
}
component = component.args(args)
}
val children = mutableListOf<Component>()
for (child in component.children()) {
children.add(modifyBaseComponent(child, player))
}
component = component.children(children)
val hoverEvent: HoverEvent<Any> = component.style().hoverEvent() as HoverEvent<Any>? ?: return component
val showItem = hoverEvent.value()
if (showItem !is HoverEvent.ShowItem) {
return component
}
val newShowItem = showItem.nbt(
BinaryTagHolder.binaryTagHolder(
CraftItemStack.asNMSCopy(
Display.display(
CraftItemStack.asBukkitCopy(
CraftItemStack.asNMSCopy(
ItemStack(
Material.matchMaterial(
showItem.item()
.toString()
) ?: return component,
showItem.count()
)
).apply {
this.tag = TagParser.parseTag(
showItem.nbt()?.string() ?: return component
) ?: return component
}
),
player
)
).orCreateTag.toString()
)
)
val newHover = hoverEvent.value(newShowItem)
val style = component.style().hoverEvent(newHover)
return component.style(style)
}
}

View File

@@ -0,0 +1,135 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.PathfinderMob
import org.bukkit.Bukkit
import org.bukkit.NamespacedKey
import org.bukkit.craftbukkit.v1_19_R1.CraftServer
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftMob
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_19_R1.persistence.CraftPersistentDataContainer
import org.bukkit.craftbukkit.v1_19_R1.persistence.CraftPersistentDataTypeRegistry
import org.bukkit.craftbukkit.v1_19_R1.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_19_R1.util.CraftNamespacedKey
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Mob
import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataContainer
import java.lang.reflect.Field
class CommonsInitializer : CommonsInitializerProxy {
override fun init() {
CommonsProvider.setIfNeeded(CommonsProviderImpl)
}
object CommonsProviderImpl : CommonsProvider {
private val cisHandle: Field = CraftItemStack::class.java.getDeclaredField("handle").apply {
isAccessible = true
}
private val pdcRegsitry = Class.forName("org.bukkit.craftbukkit.v1_19_R1.inventory.CraftMetaItem")
.getDeclaredField("DATA_TYPE_REGISTRY")
.apply { isAccessible = true }
.get(null) as CraftPersistentDataTypeRegistry
override val nbtTagString = CraftMagicNumbers.NBT.TAG_STRING
override fun toPathfinderMob(mob: Mob): PathfinderMob? {
val craft = mob as? CraftMob ?: return null
return craft.handle as? PathfinderMob
}
override fun toResourceLocation(namespacedKey: NamespacedKey): ResourceLocation =
CraftNamespacedKey.toMinecraft(namespacedKey)
override fun asNMSStack(itemStack: ItemStack): net.minecraft.world.item.ItemStack {
return if (itemStack !is CraftItemStack) {
CraftItemStack.asNMSCopy(itemStack)
} else {
cisHandle[itemStack] as net.minecraft.world.item.ItemStack? ?: CraftItemStack.asNMSCopy(itemStack)
}
}
override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack {
return CraftItemStack.asBukkitCopy(itemStack)
}
override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) {
if (itemStack !is CraftItemStack) {
itemStack.itemMeta = CraftItemStack.asCraftMirror(nmsStack).itemMeta
}
}
override fun toBukkitEntity(entity: net.minecraft.world.entity.LivingEntity): LivingEntity? =
CraftEntity.getEntity(Bukkit.getServer() as CraftServer, entity) as? LivingEntity
override fun makePdc(tag: CompoundTag, base: Boolean): PersistentDataContainer {
fun emptyPdc(): CraftPersistentDataContainer = CraftPersistentDataContainer(pdcRegsitry)
fun CompoundTag?.toPdc(): PersistentDataContainer {
val pdc = emptyPdc()
this ?: return pdc
val keys = this.allKeys
for (key in keys) {
pdc.put(key, this[key])
}
return pdc
}
return if (base) {
tag.toPdc()
} else {
if (tag.contains("PublicBukkitValues")) {
tag.getCompound("PublicBukkitValues").toPdc()
} else {
emptyPdc()
}
}
}
override fun setPdc(
tag: CompoundTag,
pdc: PersistentDataContainer?,
item: net.minecraft.world.item.ItemStack?
) {
fun CraftPersistentDataContainer.toTag(): CompoundTag {
val compound = CompoundTag()
val rawPublicMap: Map<String, Tag> = this.raw
for ((key, value) in rawPublicMap) {
compound.put(key, value)
}
return compound
}
val container = when (pdc) {
is CraftPersistentDataContainer? -> pdc
else -> null
}
if (item != null) {
if (container != null && !container.isEmpty) {
for (key in tag.allKeys.toSet()) {
tag.remove(key)
}
tag.merge(container.toTag())
} else {
item.setTag(null)
}
} else {
if (container != null && !container.isEmpty) {
tag.put("PublicBukkitValues", container.toTag())
} else {
tag.remove("PublicBukkitValues")
}
}
}
}
}

View File

@@ -0,0 +1,16 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.internal.entities.EcoDummyEntity
import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy
import org.bukkit.Location
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld
import org.bukkit.entity.Entity
import org.bukkit.entity.EntityType
class DummyEntityFactory : DummyEntityFactoryProxy {
override fun createDummyEntity(location: Location): Entity {
val world = location.world as CraftWorld
@Suppress("UsePropertyAccessSyntax")
return EcoDummyEntity(world.createEntity(location, EntityType.ZOMBIE.entityClass).getBukkitEntity())
}
}

View File

@@ -0,0 +1,12 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.entities.ai.EntityController
import com.willfp.eco.internal.spigot.proxy.EntityControllerFactoryProxy
import com.willfp.eco.internal.spigot.proxy.common.ai.EcoEntityController
import org.bukkit.entity.Mob
class EntityControllerFactory : EntityControllerFactoryProxy {
override fun <T : Mob> createEntityController(entity: T): EntityController<T> {
return EcoEntityController(entity)
}
}

View File

@@ -0,0 +1,70 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.data.ExtendedPersistentDataContainer
import com.willfp.eco.internal.spigot.proxy.ExtendedPersistentDataContainerFactoryProxy
import net.minecraft.nbt.Tag
import org.bukkit.craftbukkit.v1_19_R1.persistence.CraftPersistentDataContainer
import org.bukkit.craftbukkit.v1_19_R1.persistence.CraftPersistentDataTypeRegistry
import org.bukkit.persistence.PersistentDataContainer
import org.bukkit.persistence.PersistentDataType
class ExtendedPersistentDataContainerFactory: ExtendedPersistentDataContainerFactoryProxy {
@Suppress("UNCHECKED_CAST")
private val registry: CraftPersistentDataTypeRegistry =
CraftPersistentDataContainer::class.java.getDeclaredField("registry")
.apply { isAccessible = true }.get(null) as CraftPersistentDataTypeRegistry
override fun adapt(pdc: PersistentDataContainer): ExtendedPersistentDataContainer {
return when (pdc) {
is CraftPersistentDataContainer -> EcoPersistentDataContainer(pdc)
else -> throw IllegalArgumentException("Custom PDC instance is not supported!")
}
}
override fun newPdc(): PersistentDataContainer {
return CraftPersistentDataContainer(registry)
}
inner class EcoPersistentDataContainer(
val handle: CraftPersistentDataContainer
) : ExtendedPersistentDataContainer {
@Suppress("UNCHECKED_CAST")
private val customDataTags: MutableMap<String, Tag> =
CraftPersistentDataContainer::class.java.getDeclaredField("customDataTags")
.apply { isAccessible = true }.get(handle) as MutableMap<String, Tag>
override fun <T : Any, Z : Any> set(key: String, dataType: PersistentDataType<T, Z>, value: Z) {
customDataTags[key] = registry.wrap(dataType.primitiveType, dataType.toPrimitive(value, handle.adapterContext))
}
override fun <T : Any, Z : Any> has(key: String, dataType: PersistentDataType<T, Z>): Boolean {
val value = customDataTags[key] ?: return false
return registry.isInstanceOf(dataType.primitiveType, value)
}
override fun <T : Any, Z : Any> get(key: String, dataType: PersistentDataType<T, Z>): Z? {
val value = customDataTags[key] ?: return null
return dataType.fromPrimitive(registry.extract(dataType.primitiveType, value), handle.adapterContext)
}
override fun <T : Any, Z : Any> getOrDefault(
key: String,
dataType: PersistentDataType<T, Z>,
defaultValue: Z
): Z {
return get(key, dataType) ?: defaultValue
}
override fun remove(key: String) {
customDataTags.remove(key)
}
override fun getAllKeys(): MutableSet<String> {
return customDataTags.keys
}
override fun getBase(): PersistentDataContainer {
return handle
}
}
}

View File

@@ -0,0 +1,12 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.fast.FastItemStack
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
import com.willfp.eco.internal.spigot.proxy.common.item.EcoFastItemStack
import org.bukkit.inventory.ItemStack
class FastItemStackFactory : FastItemStackFactoryProxy {
override fun create(itemStack: ItemStack): FastItemStack {
return EcoFastItemStack(itemStack)
}
}

View File

@@ -0,0 +1,33 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.MiniMessageTranslatorProxy
import com.willfp.eco.util.toLegacy
import net.kyori.adventure.text.minimessage.MiniMessage
class MiniMessageTranslator : MiniMessageTranslatorProxy {
override fun format(message: String): String {
var mut = message
val startsWithPrefix = mut.startsWith(Display.PREFIX)
if (startsWithPrefix) {
mut = mut.substring(2)
}
mut = mut.replace('§', '&')
val miniMessage = runCatching {
MiniMessage.miniMessage().deserialize(
mut
).toLegacy()
}.getOrNull() ?: mut
mut = if (startsWithPrefix) {
Display.PREFIX + miniMessage
} else {
miniMessage
}
return mut
}
}

View File

@@ -0,0 +1,52 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.items.TestableItem
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.SnbtPrinterTagVisitor
import net.minecraft.nbt.TagParser
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack
import org.bukkit.inventory.ItemStack
class SNBTConverter : SNBTConverterProxy {
override fun fromSNBT(snbt: String): ItemStack? {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return null
val nms = net.minecraft.world.item.ItemStack.of(nbt)
return CraftItemStack.asBukkitCopy(nms)
}
override fun toSNBT(itemStack: ItemStack): String {
val nms = CraftItemStack.asNMSCopy(itemStack)
return SnbtPrinterTagVisitor().visit(nms.save(CompoundTag()))
}
override fun makeSNBTTestable(snbt: String): TestableItem {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return EmptyTestableItem()
val nms = net.minecraft.world.item.ItemStack.of(nbt)
if (nms == net.minecraft.world.item.ItemStack.EMPTY) {
return EmptyTestableItem()
}
nbt.remove("Count")
return SNBTTestableItem(CraftItemStack.asBukkitCopy(nms), nbt)
}
class SNBTTestableItem(
private val item: ItemStack,
private val tag: CompoundTag
) : TestableItem {
override fun matches(itemStack: ItemStack?): Boolean {
if (itemStack == null) {
return false
}
val nms = CraftItemStack.asNMSCopy(itemStack)
val nmsTag = nms.save(CompoundTag())
nmsTag.remove("Count")
return tag.copy().merge(nmsTag) == nmsTag
}
override fun getItem(): ItemStack = item
}
}

View File

@@ -0,0 +1,48 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.mojang.authlib.GameProfile
import com.mojang.authlib.properties.Property
import com.willfp.eco.internal.spigot.proxy.SkullProxy
import org.bukkit.inventory.meta.SkullMeta
import java.lang.reflect.Field
import java.lang.reflect.Method
import java.util.UUID
class Skull : SkullProxy {
private lateinit var setProfile: Method
private lateinit var profile: Field
override fun setSkullTexture(
meta: SkullMeta,
base64: String
) {
if (!this::setProfile.isInitialized) {
setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java)
setProfile.isAccessible = true
}
if (base64.length < 20) {
return
}
val uuid = UUID(
base64.substring(base64.length - 20).hashCode().toLong(),
base64.substring(base64.length - 10).hashCode().toLong()
)
val profile = GameProfile(uuid, "eco")
profile.properties.put("textures", Property("textures", base64))
setProfile.invoke(meta, profile)
}
override fun getSkullTexture(
meta: SkullMeta
): String? {
if (!this::profile.isInitialized) {
profile = meta.javaClass.getDeclaredField("profile")
profile.isAccessible = true
}
val profile = profile[meta] as GameProfile? ?: return null
val properties = profile.properties ?: return null
val prop = properties["textures"] ?: return null
return prop.toMutableList().firstOrNull()?.name
}
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.internal.spigot.proxy.TPSProxy
import org.bukkit.Bukkit
import org.bukkit.craftbukkit.v1_19_R1.CraftServer
class TPS : TPSProxy {
override fun getTPS(): Double {
return (Bukkit.getServer() as CraftServer).handle.server.recentTps[0]
}
}

View File

@@ -0,0 +1,41 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.trading.MerchantOffer
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftMerchantRecipe
import org.bukkit.entity.Player
import org.bukkit.inventory.MerchantRecipe
import java.lang.reflect.Field
class VillagerTrade : VillagerTradeProxy {
private val handle: Field = CraftMerchantRecipe::class.java.getDeclaredField("handle")
override fun displayTrade(
recipe: MerchantRecipe,
player: Player
): MerchantRecipe {
recipe as CraftMerchantRecipe
val nbt = getHandle(recipe).createTag()
for (tag in arrayOf("buy", "buyB", "sell")) {
val nms = ItemStack.of(nbt.getCompound(tag))
val displayed = Display.display(CraftItemStack.asBukkitCopy(nms), player)
val itemNBT = CraftItemStack.asNMSCopy(displayed).save(CompoundTag())
nbt.put(tag, itemNBT)
}
return CraftMerchantRecipe(MerchantOffer(nbt))
}
private fun getHandle(recipe: CraftMerchantRecipe): MerchantOffer {
return handle[recipe] as MerchantOffer
}
init {
handle.isAccessible = true
}
}

View File

@@ -6,7 +6,7 @@ dependencies {
compileOnly project(":eco-core:core-backend") compileOnly project(":eco-core:core-backend")
// Libraries // Libraries
implementation 'com.github.Redempt:Crunch:1.1.2' implementation 'com.github.Redempt:Crunch:master-SNAPSHOT'
implementation 'mysql:mysql-connector-java:8.0.25' implementation 'mysql:mysql-connector-java:8.0.25'
implementation 'org.jetbrains.exposed:exposed-core:0.37.3' implementation 'org.jetbrains.exposed:exposed-core:0.37.3'
implementation 'org.jetbrains.exposed:exposed-dao:0.37.3' implementation 'org.jetbrains.exposed:exposed-dao:0.37.3'
@@ -14,16 +14,17 @@ dependencies {
implementation 'com.zaxxer:HikariCP:5.0.0' implementation 'com.zaxxer:HikariCP:5.0.0'
implementation 'net.kyori:adventure-platform-bukkit:4.1.0' implementation 'net.kyori:adventure-platform-bukkit:4.1.0'
implementation 'org.javassist:javassist:3.28.0-GA' implementation 'org.javassist:javassist:3.28.0-GA'
implementation 'org.mongodb:mongodb-driver-sync:4.6.0'
implementation 'org.litote.kmongo:kmongo-coroutine:4.6.0'
// Included in spigot jar // Included in spigot jar
compileOnly 'com.google.code.gson:gson:2.8.8' compileOnly 'com.google.code.gson:gson:2.8.8'
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT' compileOnly 'io.papermc.paper:paper-api:1.17.1-R0.1-SNAPSHOT'
// Plugin dependencies // Plugin dependencies
compileOnly 'com.comphenix.protocol:ProtocolLib:4.6.1-SNAPSHOT' compileOnly 'com.comphenix.protocol:ProtocolLib:5.0.0-SNAPSHOT'
compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.0.7-SNAPSHOT' compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.0.7-SNAPSHOT'
compileOnly 'com.github.TechFortress:GriefPrevention:16.17.1' compileOnly 'com.github.TechFortress:GriefPrevention:16.17.1'
compileOnly 'com.massivecraft:Factions:1.6.9.5-U0.5.10'
compileOnly 'com.github.cryptomorin:kingdoms:1.12.3' compileOnly 'com.github.cryptomorin:kingdoms:1.12.3'
compileOnly('com.github.TownyAdvanced:Towny:0.97.2.6') { compileOnly('com.github.TownyAdvanced:Towny:0.97.2.6') {
exclude group: 'com.zaxxer', module: 'HikariCP' exclude group: 'com.zaxxer', module: 'HikariCP'
@@ -34,7 +35,7 @@ dependencies {
compileOnly 'com.gmail.nossr50.mcMMO:mcMMO:2.1.202' compileOnly 'com.gmail.nossr50.mcMMO:mcMMO:2.1.202'
compileOnly 'me.clip:placeholderapi:2.10.10' compileOnly 'me.clip:placeholderapi:2.10.10'
compileOnly 'com.github.oraxen:oraxen:bd81ace154' compileOnly 'com.github.oraxen:oraxen:bd81ace154'
compileOnly 'com.github.brcdev-minecraft:shopgui-api:2.2.0' compileOnly 'com.github.brcdev-minecraft:shopgui-api:3.0.0'
compileOnly 'com.github.LoneDev6:API-ItemsAdder:2.4.7' compileOnly 'com.github.LoneDev6:API-ItemsAdder:2.4.7'
compileOnly 'com.arcaniax:HeadDatabase-API:1.3.0' compileOnly 'com.arcaniax:HeadDatabase-API:1.3.0'
compileOnly 'com.gmail.filoghost.holographicdisplays:holographicdisplays-api:2.4.0' compileOnly 'com.gmail.filoghost.holographicdisplays:holographicdisplays-api:2.4.0'
@@ -45,6 +46,7 @@ dependencies {
compileOnly 'com.wolfyscript.wolfyutilities:wolfyutilities:3.16.0.0' compileOnly 'com.wolfyscript.wolfyutilities:wolfyutilities:3.16.0.0'
compileOnly 'com.github.decentsoftware-eu:decentholograms:2.1.2' compileOnly 'com.github.decentsoftware-eu:decentholograms:2.1.2'
compileOnly 'com.github.Gypopo:EconomyShopGUI-API:1.1.0' compileOnly 'com.github.Gypopo:EconomyShopGUI-API:1.1.0'
compileOnly 'com.github.N0RSKA:ScytherAPI:55a'
// MythicMobs // MythicMobs
compileOnly 'io.lumine:Mythic:5.0.1' compileOnly 'io.lumine:Mythic:5.0.1'
@@ -63,6 +65,13 @@ dependencies {
compileOnly fileTree(dir: '../../lib', include: ['*.jar']) compileOnly fileTree(dir: '../../lib', include: ['*.jar'])
} }
shadowJar {
minimize {
exclude(dependency('org.litote.kmongo:kmongo-coroutine:.*'))
exclude(dependency('org.jetbrains.exposed:.*:.*'))
}
}
processResources { processResources {
filesNotMatching(["**/*.png", "**/models/**", "**/textures/**"]) { filesNotMatching(["**/*.png", "**/models/**", "**/textures/**"]) {
expand projectVersion: project.version expand projectVersion: project.version

View File

@@ -0,0 +1,20 @@
package com.mongodb.diagnostics.logging
/*
This is a terrible fix for mongo logging.
I've tried every 'solution' on the internet - setting the level with java native logging,
with Log4j / Slf4j, reflectively changing the logger delegate in the Log4J impl, every
single method under the sun - but I just couldn't get any of them to work.
So, I've 'fixed' the problem at the source - the class in the jar now always returns a useless
logger that can't do anything. At least there's no console spam anymore.
*/
@Suppress("UNUSED")
object Loggers {
private const val PREFIX = "org.mongodb.driver"
@JvmStatic
fun getLogger(suffix: String): Logger = NoOpLogger("$PREFIX.$suffix")
}

View File

@@ -0,0 +1,69 @@
package com.willfp.eco.internal.spigot
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.util.containsIgnoreCase
import org.bukkit.Bukkit
import org.bukkit.plugin.Plugin
import java.io.File
import java.util.zip.ZipFile
object ConflictFinder {
fun searchForConflicts(eco: EcoPlugin): List<Conflict> {
val conflicts = mutableListOf<Conflict>()
for (plugin in Bukkit.getPluginManager().plugins) {
if (eco.configYml.getStrings("conflicts.whitelist").containsIgnoreCase(plugin.name)) {
continue
}
val conflict = try {
plugin.getConflict()
} catch (e: Exception) {
continue
} // Really can't be fucked to do this properly.
if (conflict != null) {
conflicts.add(conflict)
}
}
return conflicts
}
}
data class Conflict(
val plugin: Plugin,
val conflictType: ConflictType
) {
val conflictMessage: String
get() = "${plugin.name} will likely conflict with eco! Reason: ${conflictType.friendlyMessage}"
}
enum class ConflictType(
val friendlyMessage: String
) {
LIB_LOADER("Kotlin found in libraries (lib-loader)"),
KOTLIN_SHADE("Kotlin shaded into jar");
}
private fun Plugin.getConflict(): Conflict? {
if (this.description.libraries.any { it.contains("kotlin-stdlib") }) {
return Conflict(this, ConflictType.LIB_LOADER)
}
val file = File(this::class.java.protectionDomain.codeSource.location.toURI())
if (!file.exists() || file.name.contains("PolymartHelper")) {
return null
}
val zip = ZipFile(file)
for (entry in zip.entries()) {
if (entry.name.startsWith("kotlin/") || entry.name.startsWith("kotlinx/")) {
return Conflict(this, ConflictType.KOTLIN_SHADE)
}
}
return null
}

View File

@@ -7,6 +7,7 @@ import com.willfp.eco.core.data.ExtendedPersistentDataContainer
import com.willfp.eco.core.entities.ai.EntityController import com.willfp.eco.core.entities.ai.EntityController
import com.willfp.eco.core.fast.FastItemStack import com.willfp.eco.core.fast.FastItemStack
import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration
import com.willfp.eco.core.items.SNBTHandler
import com.willfp.eco.internal.EcoCleaner import com.willfp.eco.internal.EcoCleaner
import com.willfp.eco.internal.EcoPropsParser import com.willfp.eco.internal.EcoPropsParser
import com.willfp.eco.internal.Plugins import com.willfp.eco.internal.Plugins
@@ -29,7 +30,9 @@ import com.willfp.eco.internal.scheduling.EcoScheduler
import com.willfp.eco.internal.spigot.data.DataYml import com.willfp.eco.internal.spigot.data.DataYml
import com.willfp.eco.internal.spigot.data.EcoKeyRegistry import com.willfp.eco.internal.spigot.data.EcoKeyRegistry
import com.willfp.eco.internal.spigot.data.EcoProfileHandler import com.willfp.eco.internal.spigot.data.EcoProfileHandler
import com.willfp.eco.internal.spigot.data.storage.HandlerType
import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler
import com.willfp.eco.internal.spigot.items.EcoSNBTHandler
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy
import com.willfp.eco.internal.spigot.proxy.EntityControllerFactoryProxy import com.willfp.eco.internal.spigot.proxy.EntityControllerFactoryProxy
@@ -56,8 +59,15 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
private val cleaner = EcoCleaner() private val cleaner = EcoCleaner()
private var adventure: BukkitAudiences? = null private var adventure: BukkitAudiences? = null
private val keyRegistry = EcoKeyRegistry() private val keyRegistry = EcoKeyRegistry()
private val playerProfileHandler = EcoProfileHandler(this.configYml.getBool("mysql.enabled"), this)
private val playerProfileHandler = EcoProfileHandler(
HandlerType.valueOf(this.configYml.getString("data-handler").uppercase()),
this
)
private val snbtHandler = EcoSNBTHandler(this)
@Suppress("RedundantNullableReturnType") @Suppress("RedundantNullableReturnType")
private val keyFactory: InternalNamespacedKeyFactory? = private val keyFactory: InternalNamespacedKeyFactory? =
@@ -159,4 +169,7 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
override fun newPdc(): PersistentDataContainer = override fun newPdc(): PersistentDataContainer =
getProxy(ExtendedPersistentDataContainerFactoryProxy::class.java).newPdc() getProxy(ExtendedPersistentDataContainerFactoryProxy::class.java).newPdc()
override fun getSNBTHandler(): SNBTHandler =
snbtHandler
} }

View File

@@ -38,6 +38,7 @@ import com.willfp.eco.internal.entities.EntityArgParserSilent
import com.willfp.eco.internal.entities.EntityArgParserSize import com.willfp.eco.internal.entities.EntityArgParserSize
import com.willfp.eco.internal.entities.EntityArgParserSpawnReinforcements import com.willfp.eco.internal.entities.EntityArgParserSpawnReinforcements
import com.willfp.eco.internal.entities.EntityArgParserSpeed import com.willfp.eco.internal.entities.EntityArgParserSpeed
import com.willfp.eco.internal.gui.menu.getMenu
import com.willfp.eco.internal.items.ArgParserColor import com.willfp.eco.internal.items.ArgParserColor
import com.willfp.eco.internal.items.ArgParserCustomModelData import com.willfp.eco.internal.items.ArgParserCustomModelData
import com.willfp.eco.internal.items.ArgParserEnchantment import com.willfp.eco.internal.items.ArgParserEnchantment
@@ -63,7 +64,8 @@ import com.willfp.eco.internal.spigot.display.PacketWindowItems
import com.willfp.eco.internal.spigot.display.frame.clearFrames import com.willfp.eco.internal.spigot.display.frame.clearFrames
import com.willfp.eco.internal.spigot.drops.CollatedRunnable import com.willfp.eco.internal.spigot.drops.CollatedRunnable
import com.willfp.eco.internal.spigot.eventlisteners.EntityDeathByEntityListeners import com.willfp.eco.internal.spigot.eventlisteners.EntityDeathByEntityListeners
import com.willfp.eco.internal.spigot.eventlisteners.NaturalExpGainListeners import com.willfp.eco.internal.spigot.eventlisteners.NaturalExpGainListenersPaper
import com.willfp.eco.internal.spigot.eventlisteners.NaturalExpGainListenersSpigot
import com.willfp.eco.internal.spigot.eventlisteners.PlayerJumpListenersPaper import com.willfp.eco.internal.spigot.eventlisteners.PlayerJumpListenersPaper
import com.willfp.eco.internal.spigot.eventlisteners.PlayerJumpListenersSpigot import com.willfp.eco.internal.spigot.eventlisteners.PlayerJumpListenersSpigot
import com.willfp.eco.internal.spigot.eventlisteners.armor.ArmorChangeEventListeners import com.willfp.eco.internal.spigot.eventlisteners.armor.ArmorChangeEventListeners
@@ -82,6 +84,7 @@ import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogX
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV11 import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV11
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCrashClaim import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCrashClaim
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefDeluxeCombat import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefDeluxeCombat
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefFabledSkyBlock
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefFactionsUUID import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefFactionsUUID
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefGriefPrevention import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefGriefPrevention
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefIridiumSkyblock import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefIridiumSkyblock
@@ -98,6 +101,7 @@ import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsHeadDa
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsItemsAdder import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsItemsAdder
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsMythicMobs import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsMythicMobs
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsOraxen import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsOraxen
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsScyther
import com.willfp.eco.internal.spigot.integrations.customrecipes.CustomRecipeCustomCrafting import com.willfp.eco.internal.spigot.integrations.customrecipes.CustomRecipeCustomCrafting
import com.willfp.eco.internal.spigot.integrations.economy.EconomyVault import com.willfp.eco.internal.spigot.integrations.economy.EconomyVault
import com.willfp.eco.internal.spigot.integrations.hologram.HologramCMI import com.willfp.eco.internal.spigot.integrations.hologram.HologramCMI
@@ -110,6 +114,7 @@ import com.willfp.eco.internal.spigot.integrations.shop.ShopEconomyShopGUI
import com.willfp.eco.internal.spigot.integrations.shop.ShopShopGuiPlus import com.willfp.eco.internal.spigot.integrations.shop.ShopShopGuiPlus
import com.willfp.eco.internal.spigot.integrations.shop.ShopZShop import com.willfp.eco.internal.spigot.integrations.shop.ShopZShop
import com.willfp.eco.internal.spigot.math.evaluateExpression import com.willfp.eco.internal.spigot.math.evaluateExpression
import com.willfp.eco.internal.spigot.player.PlayerHealthFixer
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
import com.willfp.eco.internal.spigot.proxy.SkullProxy import com.willfp.eco.internal.spigot.proxy.SkullProxy
import com.willfp.eco.internal.spigot.proxy.TPSProxy import com.willfp.eco.internal.spigot.proxy.TPSProxy
@@ -119,6 +124,7 @@ import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInComplex
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInVanilla import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInVanilla
import com.willfp.eco.internal.spigot.recipes.stackhandlers.ShapedCraftingRecipeStackHandler import com.willfp.eco.internal.spigot.recipes.stackhandlers.ShapedCraftingRecipeStackHandler
import com.willfp.eco.internal.spigot.recipes.stackhandlers.ShapelessCraftingRecipeStackHandler import com.willfp.eco.internal.spigot.recipes.stackhandlers.ShapelessCraftingRecipeStackHandler
import com.willfp.eco.util.MenuUtils
import com.willfp.eco.util.NumberUtils import com.willfp.eco.util.NumberUtils
import com.willfp.eco.util.ServerUtils import com.willfp.eco.util.ServerUtils
import com.willfp.eco.util.SkullUtils import com.willfp.eco.util.SkullUtils
@@ -179,7 +185,9 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
val tpsProxy = getProxy(TPSProxy::class.java) val tpsProxy = getProxy(TPSProxy::class.java)
ServerUtils.initialize { tpsProxy.getTPS() } ServerUtils.initialize { tpsProxy.getTPS() }
NumberUtils.initCrunch { expression, player, context -> evaluateExpression(expression, player, context) } NumberUtils.initCrunch(::evaluateExpression)
MenuUtils.initialize { it.openInventory.topInventory.getMenu() }
CustomItemsManager.registerProviders() CustomItemsManager.registerProviders()
@@ -191,7 +199,27 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
} }
override fun handleEnable() { override fun handleEnable() {
this.logger.info("Scanning for conflicts...")
val conflicts = ConflictFinder.searchForConflicts(this)
for (conflict in conflicts) {
this.logger.warning(conflict.conflictMessage)
}
if (conflicts.isNotEmpty()) {
this.logger.warning(
"You can fix the conflicts by either removing the conflicting plugins, " +
"or by asking on the support discord to have them patched!"
)
this.logger.warning(
"Only remove potentially conflicting plugins if you see " +
"Loader Constraint Violation / LinkageError anywhere"
)
} else {
this.logger.info("No conflicts found!")
}
CollatedRunnable(this) CollatedRunnable(this)
CustomItemsManager.registerProviders() // Do it again here
// Register events for ShopSellEvent // Register events for ShopSellEvent
ShopManager.registerEvents(this) ShopManager.registerEvents(this)
@@ -218,7 +246,12 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
override fun handleReload() { override fun handleReload() {
CollatedRunnable(this) CollatedRunnable(this)
DropManager.update(this) DropManager.update(this)
ProfileSaver(this)
this.scheduler.runLater(3) {
(Eco.getHandler().profileHandler as EcoProfileHandler).migrateIfNeeded()
}
ProfileSaver(this, Eco.getHandler().profileHandler)
this.scheduler.runTimer( this.scheduler.runTimer(
{ clearFrames() }, { clearFrames() },
this.configYml.getInt("display-frame-ttl").toLong(), this.configYml.getInt("display-frame-ttl").toLong(),
@@ -238,6 +271,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
IntegrationLoader("IridiumSkyblock") { AntigriefManager.register(AntigriefIridiumSkyblock()) }, IntegrationLoader("IridiumSkyblock") { AntigriefManager.register(AntigriefIridiumSkyblock()) },
IntegrationLoader("DeluxeCombat") { AntigriefManager.register(AntigriefDeluxeCombat()) }, IntegrationLoader("DeluxeCombat") { AntigriefManager.register(AntigriefDeluxeCombat()) },
IntegrationLoader("SuperiorSkyblock2") { AntigriefManager.register(AntigriefSuperiorSkyblock2()) }, IntegrationLoader("SuperiorSkyblock2") { AntigriefManager.register(AntigriefSuperiorSkyblock2()) },
IntegrationLoader("FabledSkyBlock") { AntigriefManager.register(AntigriefFabledSkyBlock()) },
IntegrationLoader("BentoBox") { AntigriefManager.register(AntigriefBentoBox()) }, IntegrationLoader("BentoBox") { AntigriefManager.register(AntigriefBentoBox()) },
IntegrationLoader("WorldGuard") { AntigriefManager.register(AntigriefWorldGuard()) }, IntegrationLoader("WorldGuard") { AntigriefManager.register(AntigriefWorldGuard()) },
IntegrationLoader("GriefPrevention") { AntigriefManager.register(AntigriefGriefPrevention()) }, IntegrationLoader("GriefPrevention") { AntigriefManager.register(AntigriefGriefPrevention()) },
@@ -280,6 +314,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
CraftingRecipeListener.registerValidator(CustomRecipeCustomCrafting()) CraftingRecipeListener.registerValidator(CustomRecipeCustomCrafting())
}, },
IntegrationLoader("MythicMobs") { CustomItemsManager.register(CustomItemsMythicMobs(this)) }, IntegrationLoader("MythicMobs") { CustomItemsManager.register(CustomItemsMythicMobs(this)) },
IntegrationLoader("Scyther") { CustomItemsManager.register(CustomItemsScyther()) },
// Shop // Shop
IntegrationLoader("ShopGUIPlus") { ShopManager.register(ShopShopGuiPlus()) }, IntegrationLoader("ShopGUIPlus") { ShopManager.register(ShopShopGuiPlus()) },
@@ -329,7 +364,6 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
override fun loadListeners(): List<Listener> { override fun loadListeners(): List<Listener> {
val listeners = mutableListOf( val listeners = mutableListOf(
NaturalExpGainListeners(),
ArmorListener(), ArmorListener(),
EntityDeathByEntityListeners(this), EntityDeathByEntityListeners(this),
CraftingRecipeListener(), CraftingRecipeListener(),
@@ -338,13 +372,17 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
ArrowDataListener(this), ArrowDataListener(this),
ArmorChangeEventListeners(this), ArmorChangeEventListeners(this),
DataListener(this), DataListener(this),
PlayerBlockListener(this) PlayerBlockListener(this),
PlayerHealthFixer(this),
ServerLocking
) )
if (Prerequisite.HAS_PAPER.isMet) { if (Prerequisite.HAS_PAPER.isMet) {
listeners.add(PlayerJumpListenersPaper()) listeners.add(PlayerJumpListenersPaper())
listeners.add(NaturalExpGainListenersPaper())
} else { } else {
listeners.add(PlayerJumpListenersSpigot()) listeners.add(PlayerJumpListenersSpigot())
listeners.add(NaturalExpGainListenersSpigot())
} }
return listeners return listeners

View File

@@ -0,0 +1,28 @@
package com.willfp.eco.internal.spigot
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerLoginEvent
object ServerLocking : Listener {
private var lockReason: String? = null
@Suppress("DEPRECATION")
@EventHandler
fun handle(event: PlayerLoginEvent) {
if (lockReason != null) {
event.disallow(
PlayerLoginEvent.Result.KICK_OTHER,
lockReason!!
)
}
}
fun lock(reason: String) {
lockReason = reason
}
fun unlock() {
lockReason = null
}
}

View File

@@ -1,6 +1,5 @@
package com.willfp.eco.internal.spigot.data package com.willfp.eco.internal.spigot.data
import com.willfp.eco.core.Eco
import com.willfp.eco.core.data.keys.KeyRegistry import com.willfp.eco.core.data.keys.KeyRegistry
import com.willfp.eco.core.data.keys.PersistentDataKey import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.core.data.keys.PersistentDataKeyType import com.willfp.eco.core.data.keys.PersistentDataKeyType
@@ -8,7 +7,6 @@ import org.bukkit.NamespacedKey
class EcoKeyRegistry : KeyRegistry { class EcoKeyRegistry : KeyRegistry {
private val registry = mutableMapOf<NamespacedKey, PersistentDataKey<*>>() private val registry = mutableMapOf<NamespacedKey, PersistentDataKey<*>>()
private val categories = mutableMapOf<NamespacedKey, KeyRegistry.KeyCategory>()
override fun registerKey(key: PersistentDataKey<*>) { override fun registerKey(key: PersistentDataKey<*>) {
if (this.registry.containsKey(key.key)) { if (this.registry.containsKey(key.key)) {
@@ -25,29 +23,29 @@ class EcoKeyRegistry : KeyRegistry {
} }
private fun <T> validateKey(key: PersistentDataKey<T>) { private fun <T> validateKey(key: PersistentDataKey<T>) {
val default = key.defaultValue
when (key.type) { when (key.type) {
PersistentDataKeyType.INT -> if (key.defaultValue !is Int) { PersistentDataKeyType.INT -> if (default !is Int) {
throw IllegalArgumentException("Invalid Data Type! Should be Int") throw IllegalArgumentException("Invalid Data Type! Should be Int")
} }
PersistentDataKeyType.DOUBLE -> if (key.defaultValue !is Double) { PersistentDataKeyType.DOUBLE -> if (default !is Double) {
throw IllegalArgumentException("Invalid Data Type! Should be Double") throw IllegalArgumentException("Invalid Data Type! Should be Double")
} }
PersistentDataKeyType.BOOLEAN -> if (key.defaultValue !is Boolean) { PersistentDataKeyType.BOOLEAN -> if (default !is Boolean) {
throw IllegalArgumentException("Invalid Data Type! Should be Boolean") throw IllegalArgumentException("Invalid Data Type! Should be Boolean")
} }
PersistentDataKeyType.STRING -> if (key.defaultValue !is String) { PersistentDataKeyType.STRING -> if (default !is String) {
throw IllegalArgumentException("Invalid Data Type! Should be String") throw IllegalArgumentException("Invalid Data Type! Should be String")
} }
PersistentDataKeyType.STRING_LIST -> if (default !is List<*> || default.firstOrNull() !is String?) {
throw IllegalArgumentException("Invalid Data Type! Should be String List")
}
else -> throw NullPointerException("Null value found!") else -> throw NullPointerException("Null value found!")
} }
} }
override fun markKeyAs(key: PersistentDataKey<*>, category: KeyRegistry.KeyCategory) {
categories[key.key] = category
(Eco.getHandler().profileHandler as EcoProfileHandler).handler.categorize(key, category) // ew
}
override fun getKeyFrom(namespacedKey: NamespacedKey): PersistentDataKey<*>? { override fun getKeyFrom(namespacedKey: NamespacedKey): PersistentDataKey<*>? {
return registry[namespacedKey] return registry[namespacedKey]
} }

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