9
0
mirror of https://github.com/Auxilor/EcoMobs.git synced 2025-12-19 15:09:17 +00:00

Compare commits

...

380 Commits

Author SHA1 Message Date
Auxilor
80181bb66e libreforge-updater 2022-09-03 14:20:18 +01:00
Auxilor
d2d6355003 libreforge-updater 2022-09-01 13:05:26 +01:00
Auxilor
b44016d4fe libreforge-updater 2022-08-31 12:45:30 +01:00
Auxilor
74f1953074 libreforge-updater 2022-08-30 20:29:05 +01:00
Auxilor
041e8e070e libreforge-updater 2022-08-30 19:21:42 +01:00
Auxilor
d69b205de5 libreforge-updater 2022-08-29 10:58:32 +01:00
Auxilor
ad827f2b65 libreforge-updater 2022-08-28 15:40:32 +01:00
Auxilor
e8b8dcd2c4 libreforge-updater 2022-08-27 11:22:55 +01:00
Auxilor
e54660cf5e libreforge-updater 2022-08-24 12:52:49 +02:00
Auxilor
7a21d1897d libreforge-updater 2022-08-24 12:50:14 +02:00
Auxilor
64726f665f libreforge-updater 2022-08-24 11:57:32 +02:00
Auxilor
e4fdaeec1d libreforge-updater 2022-08-23 11:07:42 +02:00
Auxilor
3c5fbd6151 libreforge-updater 2022-08-22 12:46:27 +02:00
Auxilor
4329431994 libreforge-updater 2022-08-20 10:00:02 +02:00
Auxilor
c55692e89f libreforge-updater 2022-08-17 14:21:54 +02:00
Auxilor
03466f7892 libreforge-updater 2022-08-17 12:09:45 +02:00
Auxilor
1a6ebd4455 libreforge-updater 2022-08-16 18:45:53 +02:00
Auxilor
486f071dea libreforge-updater 2022-08-14 17:30:33 +02:00
Auxilor
fb4eac5e5e Updated to 8.67.1 2022-08-13 12:12:27 +02:00
Will FP
49d1d3f054 Merge pull request #47 from grzybeek/chunkticker
small chunkticker code cleanup
2022-08-13 12:00:09 +02:00
Auxilor
6dc7426146 libreforge-updater 2022-08-13 11:58:15 +02:00
Auxilor
00c5ead347 libreforge-updater 2022-08-05 18:41:40 +01:00
Auxilor
9bd501dfbe libreforge-updater 2022-08-05 18:39:49 +01:00
Auxilor
67d55bbdc2 libreforge-updater 2022-08-04 13:03:36 +01:00
Auxilor
46aa086366 lang 2022-08-04 12:38:01 +01:00
Auxilor
9f00334ea4 lang 2022-08-04 12:31:24 +01:00
Auxilor
e6db159bfb libreforge-updater 2022-08-04 12:26:42 +01:00
Auxilor
3df7b75737 libreforge-updater 2022-08-04 12:24:14 +01:00
Auxilor
c243a425b3 libreforge-updater 2022-08-02 16:26:52 +01:00
Auxilor
e57fe61d22 libreforge-updater 2022-08-02 16:21:24 +01:00
Auxilor
9830aed484 libreforge-updater 2022-08-02 16:16:46 +01:00
Auxilor
999b89bcb0 libreforge-updater 2022-08-01 11:19:06 +01:00
Auxilor
e7f326efbb libreforge-updater 2022-07-29 17:50:41 +01:00
Auxilor
0cb5b0b7b7 libreforge-updater 2022-07-27 20:17:09 +01:00
Auxilor
8e2d901e9b Updated to 8.63.2 2022-07-26 14:41:50 +01:00
Auxilor
724eede36e Fixed boss death tracking 2022-07-26 14:41:22 +01:00
Auxilor
01a2cc7118 libreforge-updater 2022-07-25 17:53:55 +01:00
Auxilor
20aace3727 libreforge-updater 2022-07-25 17:02:32 +01:00
Auxilor
ec9d4c0dd6 libreforge-updater 2022-07-24 22:49:25 +01:00
Auxilor
b3a0c1fa67 libreforge-updater 2022-07-24 21:50:54 +01:00
Auxilor
88294a17cd libreforge-updater 2022-07-23 17:42:53 +01:00
Auxilor
1ac6a350ec libreforge-updater 2022-07-22 14:20:45 +01:00
Auxilor
a9333cb8b5 libreforge-updater 2022-07-21 20:14:10 +01:00
grzybeek
05cf399e77 remove useless mob getter 2022-07-21 17:07:37 +02:00
grzybeek
de2b8f7526 small chunkticker code cleanup 2022-07-21 17:02:42 +02:00
Auxilor
23085e74e2 Codestyle 2022-07-21 15:48:46 +01:00
Auxilor
80f02a07a4 Updated to 8.60.1 2022-07-21 15:48:22 +01:00
Will FP
a63625593d Merge pull request #45 from grzybeek/chunkticker
Fix spawning bosses on unloaded chunks
2022-07-21 15:26:05 +01:00
Auxilor
1dfd7bac1f libreforge-updater 2022-07-20 00:10:12 +01:00
Auxilor
34b983b185 libreforge-updater 2022-07-13 21:22:38 +01:00
Auxilor
33b2fd9e13 libreforge-updater 2022-07-12 14:58:43 +01:00
Auxilor
85cfb542dc libreforge-updater 2022-07-11 16:16:12 +01:00
Auxilor
197f9e91aa libreforge-updater 2022-07-09 12:10:35 +01:00
grzybeek
9d4a91805a Fix spawning bosses on unloaded chunks, keep them loaded and remove afterwards
Entity is no longer null, change not needed "?: return"
2022-07-06 02:06:46 +02:00
Auxilor
87b91c46d1 libreforge-updater 2022-07-05 18:32:14 +01:00
Auxilor
4a7e6e9ff1 libreforge-updater 2022-07-04 18:45:14 +01:00
Auxilor
b59e54be01 libreforge-updater 2022-06-30 22:54:36 +01:00
Auxilor
d26f0294cc libreforge-updater 2022-06-30 22:34:13 +01:00
Auxilor
150433d46b libreforge-updater 2022-06-26 13:03:03 +01:00
Auxilor
7de4d75c93 libreforge-updater 2022-06-25 22:22:48 +01:00
Auxilor
9790459a26 libreforge-updater 2022-06-24 13:57:52 +01:00
Auxilor
666a80b401 libreforge-updater 2022-06-22 22:24:46 +01:00
Auxilor
59810059aa libreforge-updater 2022-06-22 12:42:49 +01:00
Auxilor
7b604c7812 libreforge-updater 2022-06-21 08:29:23 +01:00
Auxilor
81eab18e42 libreforge-updater 2022-06-20 21:37:23 +01:00
Auxilor
fa54c7022b libreforge-updater 2022-06-20 14:16:54 +01:00
Auxilor
26f976a7ca libreforge-updater 2022-06-19 12:17:53 +01:00
Auxilor
4fa070dabe libreforge-updater 2022-06-18 12:19:23 +01:00
Auxilor
f73327b204 libreforge-updater 2022-06-17 21:34:43 +01:00
Auxilor
d9b702f2f1 libreforge-updater 2022-06-17 15:26:14 +01:00
Auxilor
7692e84a60 libreforge-updater 2022-06-16 16:42:42 +01:00
Auxilor
ffd6037e73 libreforge-updater 2022-06-15 15:12:17 +01:00
Auxilor
7c959d7221 libreforge-updater 2022-06-15 15:10:33 +01:00
Auxilor
91ad33334d libreforge-updater 2022-06-14 16:43:25 +01:00
Auxilor
c1b8ed5b48 libreforge-updater 2022-06-14 09:10:39 +01:00
Auxilor
2f3c5f60a4 libreforge-updater 2022-06-13 11:46:17 +01:00
Auxilor
f3387668e6 Fixed softdepends 2022-06-12 19:12:02 +01:00
Auxilor
b62e79d904 libreforge-updater 2022-06-11 11:14:57 +01:00
Auxilor
d7afeecc27 libreforge-updater 2022-06-08 21:05:47 +01:00
Auxilor
72e61940c5 libreforge-updater 2022-06-06 13:29:09 +01:00
Auxilor
245445473b libreforge-updater 2022-06-04 13:43:57 +01:00
Auxilor
46772ac97a libreforge-updater 2022-06-03 11:35:24 +01:00
Auxilor
29a1e541a2 libreforge-updater 2022-05-31 19:44:47 +01:00
Auxilor
89a6bc97b7 libreforge-updater 2022-05-30 17:04:30 +01:00
Auxilor
c59707e6ac libreforge-updater 2022-05-30 11:10:33 +01:00
Auxilor
99bc2a04ab Updated libreforge 2022-05-28 18:18:27 +01:00
Auxilor
b4e90d9bda libreforge-updater 2022-05-27 19:24:47 +01:00
Auxilor
72c3722429 libreforge-updater 2022-05-25 10:56:28 +01:00
Auxilor
c14b2f0a80 libreforge-updater 2022-05-23 16:02:39 +01:00
Auxilor
0b6c7152e8 libreforge-updater 2022-05-22 20:42:16 +01:00
Auxilor
6e551eeaeb libreforge-updater 2022-05-22 15:26:56 +01:00
Auxilor
d5610ae804 libreforge-updater 2022-05-21 17:33:43 +01:00
Auxilor
79c8ed4992 libreforge-updater 2022-05-20 18:37:00 +01:00
Auxilor
947a0f3c6d libreforge-updater 2022-05-20 18:35:57 +01:00
Auxilor
ce8b0af155 libreforge-updater 2022-05-20 18:27:10 +01:00
Auxilor
a41e5b702d libreforge-updater 2022-05-20 14:20:17 +01:00
Auxilor
f04bf3aeea libreforge-updater 2022-05-19 20:40:35 +01:00
Auxilor
08941461c9 Fixed egg display 2022-05-18 18:06:46 +01:00
Auxilor
743dbac656 Fixed egg display 2022-05-18 18:04:37 +01:00
Auxilor
2e8d1ea4cc Updated to 8.31.1 2022-05-18 17:21:43 +01:00
Auxilor
d31a98fd99 Boss eggs now display not met lore 2022-05-18 17:21:35 +01:00
Auxilor
f7244a7d7f libreforge-updater 2022-05-18 15:31:12 +01:00
Auxilor
268ed76951 libreforge-updater 2022-05-17 18:52:57 +01:00
Auxilor
d0ccb78c17 libreforge-updater 2022-05-16 21:44:52 +01:00
Auxilor
34de040849 libreforge-updater 2022-05-15 14:27:53 +01:00
Auxilor
6b01f8e64a libreforge-updater 2022-05-15 13:59:09 +01:00
Auxilor
2a4d5a8fd2 "libreforge-updater" 2022-05-15 13:33:50 +01:00
Auxilor
f9d7315fd3 Updated libreforge 2022-05-14 21:24:56 +01:00
Auxilor
497f42ccc6 Updated libreforge 2022-05-14 12:22:43 +01:00
Auxilor
d149eb7907 Updated libreforge 2022-05-13 16:02:22 +01:00
Auxilor
47277d0dd8 Updated libreforge 2022-05-12 17:24:02 +01:00
Auxilor
f307f13d1e Updated libreforge 2022-05-11 15:28:48 +01:00
Auxilor
ac3370c0be Updated libreforge 2022-05-05 21:29:00 +01:00
Auxilor
4f616ac8c8 Updated libreforge 2022-05-03 18:46:03 +01:00
Auxilor
24256e9789 Updated libreforge 2022-05-01 17:39:49 +01:00
Auxilor
bbf20e77d0 Updated libreforge 2022-04-30 11:33:18 +01:00
Auxilor
8a506c015b Updated libreforge 2022-04-29 10:20:15 +01:00
Auxilor
744883630d Updated libreforge 2022-04-27 19:00:00 +01:00
Auxilor
8519f4fc23 Updated libreforge 2022-04-27 18:58:32 +01:00
Auxilor
d1cb11ef79 Updated libreforge 2022-04-27 10:38:05 +01:00
Auxilor
edcc185b58 Updated to 8.20.4 2022-04-24 19:08:24 +01:00
Auxilor
ab6d297222 Updated eco/kotlin/libreforge 2022-04-20 11:46:01 +01:00
Auxilor
9626588c66 Updated libreforge 2022-04-16 15:45:37 +01:00
Auxilor
c4eda19d78 Updated to 8.20.4 2022-04-12 11:35:01 +01:00
Auxilor
691326577a Updated to 8.20.4 2022-04-11 14:51:47 +01:00
Auxilor
e2086387e7 Fixed custom AI not working 2022-04-11 14:51:36 +01:00
Auxilor
13a72f849d Updated to 8.20.2 2022-04-09 14:42:29 +01:00
Auxilor
6346975e77 Updated to 8.20.2 2022-04-08 18:03:48 +01:00
Auxilor
0d846d9dff Added autospawn.one-boss-per-world option 2022-04-08 18:03:39 +01:00
Auxilor
31610383c4 Updated libreforge 2022-04-06 14:18:41 +01:00
Auxilor
d7c16ad3cc Updated libreforge 2022-04-04 10:23:34 +01:00
Auxilor
afe9095276 Updated libreforge 2022-04-02 14:04:56 +01:00
Auxilor
31a782581f Updated libreforge 2022-03-31 20:20:00 +01:00
Auxilor
8aad221450 Updated libreforge 2022-03-30 20:38:08 +01:00
Auxilor
b0bff24263 Updated libreforge 2022-03-28 19:05:19 +01:00
Auxilor
04b00fa01b Merge remote-tracking branch 'origin/master'
# Conflicts:
#	build.gradle
#	gradle.properties
2022-03-28 19:05:11 +01:00
Auxilor
276ba4616a Updated libreforge 2022-03-25 09:31:29 +00:00
Auxilor
d8e5fb9cd0 Updated to 8.14.0 2022-03-21 12:40:12 +00:00
Auxilor
9f05a6504a Added support for custom entity AI 2022-03-21 12:39:09 +00:00
Auxilor
322a6bb41b Updated libreforge 2022-03-21 12:24:06 +00:00
Auxilor
4dbc8afdf4 Updated libreforge 2022-03-19 16:42:59 +00:00
Auxilor
7ffa6ff4f4 Updated libreforge 2022-03-17 08:57:55 +00:00
Auxilor
3769684bb0 Updated libreforge 2022-03-16 09:05:56 +00:00
Auxilor
7bb931e027 Updated libreforge 2022-03-13 11:59:46 +00:00
Auxilor
879d6dd72d Updated libreforge 2022-03-12 12:22:54 +00:00
Auxilor
0a4aff45ad Updated libreforge 2022-03-10 15:13:28 +00:00
Auxilor
5929da1f48 Updated libreforge 2022-03-09 12:50:07 +00:00
Will FP
6db5de581b Update README.md 2022-03-09 12:47:33 +00:00
Auxilor
9ce1bb7ddf Updated libreforge 2022-03-08 20:20:01 +00:00
Auxilor
351d34de9f Updated libreforge 2022-03-07 14:01:18 +00:00
Auxilor
4d2b726aa0 Updated to 8.7.1 2022-03-04 16:59:39 +00:00
Auxilor
ff20b70784 Improved PDC storage 2022-03-04 16:59:31 +00:00
Auxilor
f31cd20200 Updated to 8.7.0 2022-03-03 17:02:43 +00:00
Auxilor
0ad2d3cfc7 Adapted pull request 2022-03-03 17:01:19 +00:00
Will FP
ccc7c5797a Merge pull request #28
Add commands ran for lifecycle
2022-03-03 16:54:00 +00:00
Auxilor
a218fa96c0 Updated libreforge 2022-03-01 16:26:17 +00:00
Auxilor
13c0a4d83a Updated to 8.5.2 2022-02-28 10:16:04 +00:00
Auxilor
62e7177b1b Fixed autospawn 2022-02-28 10:15:52 +00:00
Auxilor
752b30b4a2 Fixed spawn event not being called with totems 2022-02-28 10:14:11 +00:00
Auxilor
be4d6156e3 Fixed spawn totems some more 2022-02-28 10:12:12 +00:00
Auxilor
fed6dcafd7 Fixed spawn totems 2022-02-28 10:09:31 +00:00
Auxilor
36f944c58c Updated libreforge 2022-02-28 10:04:53 +00:00
Auxilor
1bc35656fe Fixed bosses attacking creative and spectator mode players 2022-02-28 10:04:38 +00:00
casper
1216e83a39 Add commands ran for lifecycle 2022-02-26 15:31:52 -05:00
Auxilor
4723c7982c Updated libreforge 2022-02-25 11:24:50 +00:00
Auxilor
8ba3c7834c Updated libreforge 2022-02-20 17:25:32 +00:00
Auxilor
76530a1617 Updated libreforge 2022-02-19 15:58:02 +00:00
Auxilor
bf41554846 build.gradle messages 2022-02-18 15:10:11 +00:00
Auxilor
a741c78b6b Fixed compatibility with other plugins 2022-02-18 14:37:01 +00:00
Auxilor
0f8dce74da Updated libreforge 2022-02-18 14:36:11 +00:00
Auxilor
0d31556b84 Updated libreforge 2022-02-15 16:49:03 +00:00
Auxilor
f8544c284e Updated libreforge 2022-02-14 17:18:16 +00:00
Auxilor
512a477fc6 Updated libreforge 2022-02-13 15:41:22 +00:00
Auxilor
8a1b473837 Updated libreforge 2022-02-12 10:51:41 +00:00
Auxilor
7464133c74 Updated to 8.3.0 2022-02-10 12:07:23 +00:00
Auxilor
1e00b28a8b Added BossTryDropItemEvent 2022-02-10 12:07:09 +00:00
Auxilor
b152313f87 Updated to 8.2.1 2022-02-10 11:57:40 +00:00
Auxilor
ec6d7175b9 Updated loggers 2022-02-10 11:57:32 +00:00
Auxilor
804a0e88b9 Updated libreforge 2022-02-10 10:57:25 +00:00
Auxilor
ff2de5aebe Updated to 8.1.8 2022-02-09 21:10:18 +00:00
Auxilor
990ad363eb Improved logging readability 2022-02-09 21:10:07 +00:00
Auxilor
d958b94fb0 Updated libreforge 2022-02-09 20:21:57 +00:00
Auxilor
e4f2a91968 Updated to 8.1.6 2022-02-09 13:10:57 +00:00
Auxilor
f1d50d6222 Added logging 2022-02-09 13:10:50 +00:00
Auxilor
035550db06 Added player to boss spawn event 2022-02-09 13:07:47 +00:00
Auxilor
f4bd64c192 Removed empty drops 2022-02-08 20:21:32 +00:00
Auxilor
4b8e1c0579 Updated to 8.1.5 2022-02-08 20:19:11 +00:00
Auxilor
d8cf08eb25 Fixed mob properties not being set 2022-02-08 20:19:05 +00:00
Auxilor
a94c96e5d4 Updated libreforge 2022-02-08 20:12:30 +00:00
Auxilor
dddf2d8a20 Added support for names without lookup string 2022-02-08 20:07:04 +00:00
Auxilor
7e67620c8c Updated libreforge 2022-02-08 20:03:01 +00:00
Auxilor
8c44303cdc Updated libreforge 2022-02-08 13:53:48 +00:00
Auxilor
97c1045243 Updated to 8.1.2 2022-02-08 13:53:31 +00:00
Auxilor
c47019f3c5 Updated to 8.1.1 2022-02-07 16:04:34 +00:00
Auxilor
1ffedfcb2e Fixed spawn totems 2022-02-07 16:04:25 +00:00
Auxilor
17705e9fdb Updated libreforge 2022-02-07 11:29:13 +00:00
Auxilor
7087feefbc Updated libreforge 2022-02-06 17:40:31 +00:00
Auxilor
31504975ce Added example effect to config 2022-02-06 14:47:04 +00:00
Auxilor
142894c0f4 Removed old configs 2022-02-06 14:32:51 +00:00
Auxilor
1babbcb377 Filled config with comments, registered boss with entity lookup system 2022-02-06 14:31:22 +00:00
Auxilor
87ca7e3718 Removed all bosses on reload and disable 2022-02-06 14:06:53 +00:00
Auxilor
aee2b376c4 Fixed autospawn world checks 2022-02-06 14:06:13 +00:00
Auxilor
6ca3441f3b Fixed top damager commands 2022-02-06 14:00:50 +00:00
Auxilor
af1eb8d27c Fixed boss dropping default mob drops 2022-02-06 13:50:16 +00:00
Auxilor
db3bc38e9c Updated libreforge 2022-02-06 13:46:22 +00:00
Auxilor
f7961ba7f3 Various fixes and improvements 2022-02-06 13:41:17 +00:00
Auxilor
4765b20d20 Fixed stupidity (part 2) 2022-02-06 13:35:00 +00:00
Auxilor
64b22a17d6 Fixed lifespan 2022-02-06 13:30:30 +00:00
Auxilor
b1ad28eee4 Fixed lifecycles 2022-02-06 13:29:40 +00:00
Auxilor
f6f9fb3c1d Fixed spawn broadcast placeholders 2022-02-06 13:27:25 +00:00
Auxilor
4093fa92bd Fixed spawn egg lore 2022-02-06 13:25:32 +00:00
Auxilor
96a6c3d700 Fixed loading bugs 2022-02-06 13:24:10 +00:00
Auxilor
61de345aec Fixed stupidity (part 1) 2022-02-06 13:15:11 +00:00
Auxilor
68b5886505 Added safety checks 2022-02-06 13:14:38 +00:00
Auxilor
f768890e46 More codestyle 2022-02-06 13:11:20 +00:00
Auxilor
8f12af5d49 Fixed migration issues 2022-02-06 13:09:31 +00:00
Auxilor
28c0162a5e Codestyle 2022-02-06 13:06:31 +00:00
Auxilor
3360ceddca Completed rewrite 2022-02-06 13:05:56 +00:00
Auxilor
e575df9f37 Nearing completion 2022-02-06 12:51:33 +00:00
Auxilor
474b9bcffd More work 2022-02-05 22:25:41 +00:00
Auxilor
d583167dbb Continued rewrite some more 2022-02-05 22:14:17 +00:00
Auxilor
baa2b6718e Continued rewrite 2022-02-05 18:57:56 +00:00
Auxilor
03efa137f4 Began complete rewrite 2022-02-05 18:20:16 +00:00
Auxilor
765b65343a Added issue templates 2022-01-26 11:22:18 +00:00
Auxilor
172a345b87 Updated gradle 2022-01-20 12:02:37 +00:00
Auxilor
b1a3c03181 Updated to 7.0.1 2022-01-20 12:02:07 +00:00
Auxilor
e39c01a4a2 Fixed item registration 2022-01-20 12:01:58 +00:00
Will FP
24e5b6d2f4 Merge pull request #15
Added Items lookup system support to egg material, registered egg items in the Items lookup system
2022-01-20 11:58:46 +00:00
_OfTeN_
4ff099ab45 Added Items lookup system support to egg material, registered egg items in the Items lookup system 2022-01-20 12:20:12 +03:00
Auxilor
055d792168 Fixed base-mob 2022-01-10 11:55:53 +00:00
Auxilor
a355b55ff2 Fixed plugin.yml 2022-01-10 11:07:19 +00:00
Auxilor
6ac3001e52 Switched from BossType to Entities system 2022-01-10 11:07:03 +00:00
Auxilor
0f04ca86d9 Updated to 7.0.0 2022-01-10 11:01:49 +00:00
Auxilor
f7422b012d Updated eco 2022-01-10 11:01:31 +00:00
Auxilor
d95de6926e Fixed string getter 2022-01-06 18:56:36 +00:00
Auxilor
ab13053987 Updated to 6.8.6 2022-01-06 18:53:54 +00:00
Auxilor
ab23e19804 Updated eco 2022-01-06 18:53:42 +00:00
Auxilor
c4a04ed048 Updated to 6.85. 2022-01-02 18:05:50 +00:00
Auxilor
b6941baa50 Added EcoItems softdepend 2022-01-02 18:05:40 +00:00
Auxilor
0a1cc72afc Updated to 6.8.4 2021-12-10 15:30:31 +00:00
Will FP
086f50b0b6 Merge pull request #14
Fixed another NPE on boss death
2021-12-10 15:30:09 +00:00
_OfTeN_
bd51eb9d7d Fixed another NPE on boss death 2021-12-10 13:38:51 +03:00
Auxilor
95462086d2 Updated to 6.8.3 2021-11-30 19:07:18 +00:00
Auxilor
39df2c9c6d Updated to Java 17 2021-11-30 19:07:08 +00:00
Auxilor
a6713661a2 Updated to 6.8.2 2021-11-27 13:25:52 +00:00
Will FP
a995568485 Merge pull request #13
Fixed double egg consuming, added null check for all attributes
2021-11-27 13:25:23 +00:00
_OfTeN_
470f39da09 Merge remote-tracking branch 'origin/master' 2021-11-27 13:46:20 +03:00
_OfTeN_
b13bcdd14c Fixed consuming 2 eggs instead of 1 2021-11-27 13:45:57 +03:00
_OfTeN_
97a07f31bf Added null check for all attributes (now ghast as base mob will work), started removing all modifiers from the entity (to avoid random bosses with other modifiers being OP) 2021-11-27 12:43:05 +03:00
_OfTeN_
d4134b4443 Added null check for all attributes (now ghast as base mob will work), started removing all modifiers from the entity (to avoid random bosses with other modifiers being OP) 2021-11-16 20:08:32 +03:00
Auxilor
770ee369e5 Merge remote-tracking branch 'origin/master' 2021-11-08 19:20:17 +00:00
Auxilor
978022df6e Updated to 6.8.1 2021-11-08 19:20:05 +00:00
Will FP
58a05b41c6 Merge pull request #11
Fixed NPE if one of top damagers leave from server before rewards are given
2021-11-08 19:19:55 +00:00
_OfTeN_
ec2bed91c4 Fixed NPE if one of top damagers leave from server before rewards are given 2021-11-08 17:21:05 +03:00
Auxilor
041ec1c79e Updated to 6.8.0 2021-11-07 15:37:18 +00:00
Auxilor
f0b09c035e PR Codestyle 2021-11-07 15:37:07 +00:00
Will FP
4c6ac852aa Merge pull request #10
Implemented spawn events for all types of boss spawns (egg, totem, timer)
2021-11-07 15:36:00 +00:00
_OfTeN_
9772081d7b Implemented spawn events for all types of boss spawns (egg, totem, timer) 2021-11-07 14:06:20 +03:00
Will FP
cea2d96819 Update README.md 2021-10-12 20:12:46 +01:00
Auxilor
9dbba3f751 Fixed the fix 2021-10-01 19:05:08 +01:00
Auxilor
9cecb33b04 Updated to 6.7.1 2021-10-01 19:04:25 +01:00
Auxilor
7b60749b88 Fixed BarStyle 2021-10-01 19:04:15 +01:00
Auxilor
e0d03cc8ed Updated to 6.7.0 2021-10-01 18:22:35 +01:00
Auxilor
80109fc061 Added getMinimumEcoVersion 2021-10-01 18:21:53 +01:00
Auxilor
c1fc918757 Updated boss bar to use Adventure 2021-10-01 18:21:17 +01:00
Auxilor
955a378b98 Updated to 6.6.3 2021-09-26 13:57:37 +01:00
Auxilor
a1875933c8 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	gradle.properties
2021-09-26 13:57:30 +01:00
Auxilor
cf3c302513 Updated to 6.5.5 2021-09-26 13:57:21 +01:00
Will FP
2acdc4a74e Merge pull request #9
Fixed mythicmobs:mob_level not working in summon effect.
2021-09-26 13:57:06 +01:00
_OfTeN_
0e2cdb71cb Fixed mythicmobs:mob_level not working in summon effect. 2021-09-26 03:20:09 +03:00
Auxilor
f1c26763e0 Updated to 6.6.2 2021-09-21 08:44:47 +01:00
Auxilor
b75b83aebf Updated PR to use ChargedCreeperBossType 2021-09-21 08:44:37 +01:00
Will FP
ea2b14fbec Merge pull request #8
Charged creepers support
2021-09-21 08:42:07 +01:00
_OfTeN_
0747a0a3d4 Added ability to use "charged_creeper" as 'base-mob:' or in 'summon:' effect to spawn charged creepers 2021-09-20 22:00:01 +03:00
Auxilor
260aec8ba4 Updated to 6.6.1 2021-09-20 16:46:13 +01:00
Auxilor
77985e5a23 Improved mythicmobs pr 2021-09-20 16:46:07 +01:00
Will FP
201ec4161b Merge pull request #7
MythicMobs support
2021-09-20 16:43:40 +01:00
_OfTeN_
468b0b4292 Added 'baby: true/false' option for boss config to control the mob age. 2021-09-20 11:16:44 +03:00
_OfTeN_
203bec560e Updated how mythic mob fetcher works 2021-09-19 23:01:40 +03:00
_OfTeN_
a2c8b73dbc Added MythicMobs mobs support. Usage: 'base-mob: mythicmobs_<MythicMobName>_<level>' 2021-09-19 22:49:49 +03:00
Auxilor
31ccdf2589 Updated to 6.6.0 2021-09-19 13:33:32 +01:00
Auxilor
7ea1f8938b Added option to set boss gear (armor / weapon) 2021-09-19 13:33:23 +01:00
Auxilor
436e833213 Updated to 6.5.5 2021-09-19 11:31:03 +01:00
Auxilor
60b4c1c246 Updated to eco 6.8.1 polymart resource checker 2021-09-19 11:30:51 +01:00
Auxilor
c5f5032e17 Updated README.md 2021-09-19 11:30:25 +01:00
Auxilor
310ace62b3 Updated to eco 6.8.0 2021-09-17 20:07:49 +01:00
Auxilor
0af79cfc27 Updated to 6.5.4 2021-09-17 20:06:12 +01:00
Will FP
a107d78937 Merge pull request #6
Added glowing: true/false option for boss config
2021-09-17 20:05:44 +01:00
_OfTeN_
d8c229d4fa Added glowing: true/false option for boss config 2021-09-17 21:17:27 +03:00
Auxilor
406601a193 Merge remote-tracking branch 'origin/master' 2021-09-16 18:13:24 +01:00
Auxilor
fb9fdacb9f Updated to 6.5.3 2021-09-16 18:13:19 +01:00
Will FP
45bbc668dc Merge pull request #5
Added %ecobosses_timeunlilspawn_<boss>% placeholder
2021-09-16 18:13:07 +01:00
_OfTeN_
b5f222976b Added %ecobosses_timeunlilspawn_<boss>% placeholder 2021-09-14 15:34:15 +03:00
Auxilor
10d297e0da Updated to 6.5.2 2021-09-12 18:57:37 +01:00
Auxilor
76df0fd2ef Fixed spawn egg bug 2021-09-12 18:57:31 +01:00
Auxilor
56b76f70c6 Updated to 6.5.1 2021-09-12 16:57:22 +01:00
Auxilor
30e0ed02a4 Improved drops for multiple identical items 2021-09-12 16:57:14 +01:00
Auxilor
2795fa8220 Updated to 6.5.0 2021-09-12 16:31:50 +01:00
Auxilor
cbeff28dbf Added spawn requirements 2021-09-12 16:31:03 +01:00
Auxilor
38dd7ea604 Updated to 6.4.0 2021-09-02 10:24:48 +01:00
Auxilor
af72bfbbb6 Legacy base64 system has been removed in favour of the eco items system 2021-09-02 10:24:30 +01:00
Auxilor
de675b49be Updated to 6.3.4 2021-08-28 18:04:40 +01:00
Auxilor
3df4cfaae7 Added LevelledMobs integration 2021-08-28 18:04:30 +01:00
Auxilor
32ac455720 Merge remote-tracking branch 'origin/master' 2021-08-28 15:53:25 +01:00
Auxilor
89a7d37d37 Updated to 6.3.3 2021-08-28 15:53:19 +01:00
Auxilor
04eff9d3f3 Fixed 2 effects with same name not being registered 2021-08-28 15:53:10 +01:00
Will FP
c3c96a6892 Update README.md 2021-08-21 01:23:06 +01:00
Auxilor
d135922dc1 Updated to 6.3.2 2021-08-15 16:25:31 +01:00
Auxilor
1569d12b44 Added lava immunity to fire imunity 2021-08-15 16:25:17 +01:00
Auxilor
aea6e5c2f1 Updated to 6.3.1 2021-08-14 13:37:12 +01:00
Auxilor
d837311ae2 Added discover-recipes 2021-08-14 13:37:05 +01:00
Auxilor
c66b914104 Fixed spawn egg 2021-08-14 13:28:04 +01:00
Auxilor
1f73b9acf7 Fixed lang.yml 2021-08-14 13:24:33 +01:00
Auxilor
cafb41567f Added /ecobosses give 2021-08-14 13:19:28 +01:00
Auxilor
8f912abf31 Updated to 6.3.0 2021-08-14 13:13:32 +01:00
Auxilor
2fe8c9197d Added spawn eggs 2021-08-14 13:13:24 +01:00
Auxilor
46eccfc345 Updated to 6.2.0 2021-08-13 15:38:24 +01:00
Auxilor
7804cebd53 Removed NMS, replaced illusioner with Dark Guardian 2021-08-13 15:38:12 +01:00
Auxilor
1918a46678 Added despawn sounds and messages 2021-08-13 14:33:58 +01:00
Auxilor
99de824b04 Added death time ticker 2021-08-13 14:12:47 +01:00
Auxilor
b18eb3942a Updated to 6.1.0 2021-08-13 14:02:32 +01:00
Auxilor
7434bbb38e Updated to 6.0.4 2021-08-11 20:42:09 +01:00
Auxilor
7bf88ed09a Updated to 6.0.3 2021-08-09 17:45:44 +01:00
Auxilor
d8f54cb9f6 Prevented slime bosses from splitting 2021-08-09 17:45:35 +01:00
Auxilor
3bc5ed6f6a Fixed 1.17 illusioner 2021-08-09 17:43:42 +01:00
Auxilor
ab759afe56 Updated to 6.0.2 2021-08-07 13:59:37 +01:00
Auxilor
3ae961c9c5 Fixed bosses picking up items 2021-08-07 13:59:29 +01:00
Auxilor
b6754c6d5c Updated to 6.0.1 2021-07-27 16:22:40 +01:00
Auxilor
846b03d8bc Removed null traces 2021-07-27 16:22:32 +01:00
Auxilor
746ab5d2b5 jitpack.yml 2021-07-21 19:09:49 +01:00
Auxilor
3f6f13a61f Updated to eco 6 2021-07-21 18:49:15 +01:00
Auxilor
fd82811d2c Updated to eco 6 2021-07-21 18:29:15 +01:00
Auxilor
950bfab5f3 Updated to eco 6 2021-07-21 18:28:42 +01:00
Auxilor
3e4d3af215 Updated to eco 6 2021-07-21 18:28:17 +01:00
Auxilor
9486903895 Updated to 5.3.0 2021-07-20 15:27:57 +01:00
Auxilor
da7ee14787 Removed legacy code 2021-07-20 15:25:49 +01:00
Auxilor
36fa2e5138 Removed UUID tracking 2021-07-20 15:22:53 +01:00
Auxilor
31e3cb993e Removed 10tick delay on timer 2021-07-20 14:43:01 +01:00
Auxilor
c7ea383115 Updated to 5.2.1 2021-07-15 23:31:12 +02:00
Auxilor
1d800a52de Fixed /ecobosses only being able to be ran as a player 2021-07-15 23:31:04 +02:00
Auxilor
1a78db6b07 Fixed permissions 2021-07-12 14:00:57 +02:00
Auxilor
9ab765edb6 Fixed type paramets 2021-07-12 13:57:34 +02:00
Auxilor
c8054c209a Updated to new eco command system and 5.2.0 2021-07-12 13:57:07 +02:00
Auxilor
8db8cca1c9 Updated to 5.1.4 2021-07-09 22:38:32 +02:00
Auxilor
413d86c2d3 Updated to eco 5.7.1x 2021-07-09 22:38:24 +02:00
Auxilor
a335b5b52e Fixed %player% bug 2021-07-09 22:37:28 +02:00
Auxilor
d5dced49b3 Updated to 5.1.3 2021-06-30 19:43:05 +01:00
Auxilor
4ac870f5c3 Chunks with bosses in them should not unload 2021-06-30 19:42:31 +01:00
Auxilor
1a364615a3 Updated to 5.1.2 2021-06-29 18:29:18 +01:00
Auxilor
890b034d4a Bosses should now load the chunk they're in on autospawn 2021-06-29 18:29:08 +01:00
Auxilor
22f59c7c5c Fixed record migration 2021-06-24 08:58:24 +01:00
Auxilor
8bc296f2f8 Updated to 5.1.1 2021-06-24 08:57:19 +01:00
Auxilor
5fe7eb1318 Java 16 migration, more null checks, record conversion 2021-06-24 08:57:11 +01:00
Auxilor
36a3c7f70d Updated to 5.1.0 2021-06-11 12:29:46 +01:00
Auxilor
6b3ff0c88d Updated to 1.17 and Java 16 2021-06-11 12:29:35 +01:00
Auxilor
3e384dbeea Updated to 5.0.7 2021-06-10 11:05:18 +01:00
Auxilor
b16444799a Updated to 5.0.8 2021-06-10 11:04:41 +01:00
Auxilor
98faf823ba Fixed 2 NPE errors 2021-06-10 11:04:28 +01:00
Auxilor
87095166d0 Updated to 5.0.7 2021-05-20 11:40:40 +01:00
Auxilor
b4510233aa Fixed potential NPE 2021-05-20 11:40:08 +01:00
Auxilor
a31b0210ab Updated to use UUID's on backend and update entity object on tick 2021-05-20 11:39:35 +01:00
Auxilor
3a480da078 Updated to 5.0.6 2021-05-20 09:02:15 +01:00
Auxilor
efc56e1763 Fixed several bugs 2021-05-20 09:02:06 +01:00
Auxilor
64f35b6338 Updated to 5.0.5 2021-05-19 11:31:48 +01:00
Auxilor
ab6e990f0b More fixes 2021-05-19 11:31:03 +01:00
Auxilor
fa8c5da31a Fixed 2 effects of the same type not working 2021-05-19 11:30:03 +01:00
Auxilor
730c259d19 Moved autospawn checks to by world 2021-05-02 10:29:04 +01:00
Auxilor
7fbc39d4d1 Updated to 5.0.4 2021-05-02 10:24:46 +01:00
Auxilor
5d69d0faee Added check for living bosses 2021-05-02 10:24:33 +01:00
Auxilor
21ed4b09fd Added extra check to boss bars 2021-04-24 17:55:57 +01:00
Auxilor
9eb3619c35 Fixed lingering boss bars 2021-04-24 17:54:40 +01:00
Auxilor
9abbfbf363 Updated to 5.0.3 2021-04-24 17:49:46 +01:00
Auxilor
12abdcbf5e Fixed Autospawn 2021-04-24 17:49:35 +01:00
Auxilor
11d8d8d13f Updated to 5.0.2 2021-04-18 21:06:43 +01:00
Auxilor
0932e68461 Merge remote-tracking branch 'origin/master' 2021-04-18 21:06:31 +01:00
Auxilor
6975daaeaf Fixed potential issues in boss ticking 2021-04-18 21:06:19 +01:00
Auxilor
663104bda0 Cleaned up /killall leaving lingering boss bars 2021-04-18 21:05:51 +01:00
Auxilor
83805215e9 Updated to 5.0.1 2021-04-17 15:12:24 +01:00
Auxilor
0b1f4d4f6d Removed unused 1.15 code 2021-04-17 15:12:09 +01:00
Auxilor
86e414e108 Updated to eco 5.2.0 2021-04-17 15:11:53 +01:00
127 changed files with 2801 additions and 3924 deletions

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

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

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

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

View File

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

View File

@@ -1,14 +1,14 @@
<h1 align="center">
<br>
<img src="https://i.imgur.com/I74yjwu.png" alt="EcoBosses logo" width="256">
<img src="https://i.imgur.com/3n3ssb4.png" alt="EcoBosses logo" width="256">
<br>
</h1>
<h4 align="center">Source code for EcoBosses, a premium spigot plugin.</h4>
<p align="center">
<a href="https://www.spigotmc.org/resources/ecobosses.79573/">
<img alt="spigot" src="https://img.shields.io/badge/spigot-ecobosses-blue?style=for-the-badge"/>
<a href="https://polymart.org/resource/1-16-1-17-ecobosses.525">
<img alt="spigot" src="https://img.shields.io/badge/polymart-ecobosses-blue?style=for-the-badge"/>
</a>
<a href="https://bstats.org/plugin/bukkit/EcoBosses" alt="bstats servers">
<img src="https://img.shields.io/bstats/servers/10635?color=blue&style=for-the-badge"/>
@@ -29,3 +29,14 @@
## License
*Click here to read [the entire license](https://github.com/Auxilor/EcoBosses/blob/master/LICENSE.md).*
<h1 align="center">
<br>
<a href="http://gamersupps.gg/discount/Auxilor?afmc=Auxilor" target="_blank">
<img src="https://i.imgur.com/uFDpBAC.png" alt="supps banner">
</a>
<a href="https://dedimc.promo/Auxilor" target="_blank">
<img src="https://i.imgur.com/zdDLhFA.png" alt="dedimc banner">
</a>
<br>
</h1>

View File

@@ -1,6 +1,16 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10"
}
}
plugins {
id 'java-library'
id 'com.github.johnrengelman.shadow' version '5.2.0'
id 'com.github.johnrengelman.shadow' version '7.0.0'
id 'maven-publish'
id 'java'
}
@@ -11,12 +21,12 @@ dependencies {
allprojects {
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'maven-publish'
apply plugin: 'com.github.johnrengelman.shadow'
repositories {
mavenCentral()
jcenter()
mavenLocal()
maven { url 'https://jitpack.io' }
maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
@@ -46,16 +56,19 @@ allprojects {
onlyIf { !sourceSets.main.allSource.files.isEmpty() }
}
shadowJar {
relocate('com.willfp.libreforge', 'com.willfp.ecobosses.libreforge')
relocate('org.joml', 'com.willfp.ecobosses.libreforge.joml')
}
dependencies {
compileOnly 'com.willfp:eco:5.0.0'
compileOnly 'com.willfp:eco:6.35.1'
implementation 'com.willfp:libreforge:3.92.1'
implementation 'org.joml:joml:1.10.4'
compileOnly 'org.jetbrains:annotations:19.0.0'
compileOnly 'org.jetbrains:annotations:23.0.0'
compileOnly 'org.projectlombok:lombok:1.18.16'
annotationProcessor 'org.projectlombok:lombok:1.18.16'
testCompileOnly 'org.projectlombok:lombok:1.18.16'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.16'
compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.7.10'
}
tasks.withType(JavaCompile) {
@@ -64,13 +77,25 @@ allprojects {
}
processResources {
filesNotMatching(["**/*.png", "**/models/**", "**/textures/**"]) {
filesNotMatching(["**/*.png", "**/models/**", "**/textures/**", "**lang.yml"]) {
expand projectVersion: project.version
}
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
kotlinOptions {
jvmTarget = "17"
freeCompilerArgs += ["-Xjvm-default=all"]
}
}
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17
compileJava.options.encoding = 'UTF-8'
compileJava.dependsOn clean
build.dependsOn shadowJar
}
tasks.withType(Jar) {
@@ -92,16 +117,20 @@ jar {
group = 'com.willfp'
archivesBaseName = project.name
version = findProperty("version")
java.sourceCompatibility = JavaVersion.VERSION_1_8
compileJava.options.encoding = 'UTF-8'
build.dependsOn shadowJar
build.dependsOn publishToMavenLocal
publishing {
publications {
maven(MavenPublication) {
from(components.java)
}
task buyThePlugins {
dependsOn subprojects.build
doLast {
println 'If you like the plugin, please consider buying it on Spigot or Polymart!'
println 'Spigot: https://www.spigotmc.org/resources/authors/auxilor.507394/'
println 'Polymart: https://polymart.org/user/auxilor.1107/'
println 'Buying gives you access to support and the plugin auto-updater, and it allows me to keep developing plugins.'
}
}
}
build.finalizedBy buyThePlugins

View File

@@ -1,2 +1,2 @@
group 'com.willfp'
version rootProject.version
version rootProject.version

View File

@@ -1,9 +0,0 @@
group 'com.willfp'
version rootProject.version
subprojects {
dependencies {
compileOnly project(':eco-core:core-proxy')
compileOnly project(':eco-core:core-plugin')
}
}

View File

@@ -1,6 +0,0 @@
group 'com.willfp'
version rootProject.version
dependencies {
compileOnly 'org.spigotmc:spigot:1.16.1-R0.1-SNAPSHOT'
}

View File

@@ -1,22 +0,0 @@
package com.willfp.ecobosses.proxy.v1_16_R1;
import com.willfp.ecobosses.proxy.proxies.CustomEntitySpawnerProxy;
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
import com.willfp.ecobosses.proxy.util.CustomEntity;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@SuppressWarnings("unchecked")
public class CustomEntitySpawner implements CustomEntitySpawnerProxy {
@Override
public <T extends LivingEntity> @Nullable T spawnCustomEntity(final Class<? extends CustomEntity<? extends LivingEntity>> entityClass,
@NotNull final Location location) {
if (entityClass.equals(CustomIllusionerProxy.class)) {
return (T) CustomIllusioner.spawn(location);
}
return null;
}
}

View File

@@ -1,62 +0,0 @@
package com.willfp.ecobosses.proxy.v1_16_R1;
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
import net.minecraft.server.v1_16_R1.EntityHuman;
import net.minecraft.server.v1_16_R1.EntityIllagerIllusioner;
import net.minecraft.server.v1_16_R1.EntityIllagerWizard;
import net.minecraft.server.v1_16_R1.EntityInsentient;
import net.minecraft.server.v1_16_R1.EntityIronGolem;
import net.minecraft.server.v1_16_R1.EntityRaider;
import net.minecraft.server.v1_16_R1.EntityTypes;
import net.minecraft.server.v1_16_R1.EntityVillagerAbstract;
import net.minecraft.server.v1_16_R1.PathfinderGoalBowShoot;
import net.minecraft.server.v1_16_R1.PathfinderGoalFloat;
import net.minecraft.server.v1_16_R1.PathfinderGoalHurtByTarget;
import net.minecraft.server.v1_16_R1.PathfinderGoalLookAtPlayer;
import net.minecraft.server.v1_16_R1.PathfinderGoalMeleeAttack;
import net.minecraft.server.v1_16_R1.PathfinderGoalNearestAttackableTarget;
import net.minecraft.server.v1_16_R1.PathfinderGoalRandomStroll;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
import org.bukkit.entity.Illusioner;
import org.jetbrains.annotations.NotNull;
public class CustomIllusioner extends EntityIllagerIllusioner implements CustomIllusionerProxy {
/**
* Instantiate a new custom illusioner entity.
*
* @param location The location to spawn it at.
*/
public CustomIllusioner(@NotNull final Location location) {
super(EntityTypes.ILLUSIONER, ((CraftWorld) location.getWorld()).getHandle());
this.setPosition(location.getX(), location.getY(), location.getZ());
this.goalSelector.a(0, new PathfinderGoalFloat(this));
this.goalSelector.a(1, new EntityIllagerWizard.b());
this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.0D, false));
this.goalSelector.a(2, new PathfinderGoalBowShoot<>(this, 1.0D, 20, 15.0F));
this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
this.goalSelector.a(0, new PathfinderGoalFloat(this));
this.goalSelector.a(6, new PathfinderGoalBowShoot<>(this, 0.5D, 20, 15.0F));
this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
this.goalSelector.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 3.0F, 1.0F));
this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F));
this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0]));
this.targetSelector.a(2, (new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)).a(300));
this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false)).a(300));
this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)).a(300));
}
/**
* Spawn illusioner.
*
* @param location The location.
* @return The illusioner.
*/
public static Illusioner spawn(@NotNull final Location location) {
CustomIllusioner illusioner = new CustomIllusioner(location);
((CraftWorld) location.getWorld()).getHandle().addEntity(illusioner);
return (Illusioner) illusioner.getBukkitEntity();
}
}

View File

@@ -1,6 +0,0 @@
group 'com.willfp'
version rootProject.version
dependencies {
compileOnly 'org.spigotmc:spigot:1.16.3-R0.1-SNAPSHOT'
}

View File

@@ -1,22 +0,0 @@
package com.willfp.ecobosses.proxy.v1_16_R2;
import com.willfp.ecobosses.proxy.proxies.CustomEntitySpawnerProxy;
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
import com.willfp.ecobosses.proxy.util.CustomEntity;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@SuppressWarnings("unchecked")
public class CustomEntitySpawner implements CustomEntitySpawnerProxy {
@Override
public <T extends LivingEntity> @Nullable T spawnCustomEntity(final Class<? extends CustomEntity<? extends LivingEntity>> entityClass,
@NotNull final Location location) {
if (entityClass.equals(CustomIllusionerProxy.class)) {
return (T) CustomIllusioner.spawn(location);
}
return null;
}
}

View File

@@ -1,62 +0,0 @@
package com.willfp.ecobosses.proxy.v1_16_R2;
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
import net.minecraft.server.v1_16_R2.EntityHuman;
import net.minecraft.server.v1_16_R2.EntityIllagerIllusioner;
import net.minecraft.server.v1_16_R2.EntityIllagerWizard;
import net.minecraft.server.v1_16_R2.EntityInsentient;
import net.minecraft.server.v1_16_R2.EntityIronGolem;
import net.minecraft.server.v1_16_R2.EntityRaider;
import net.minecraft.server.v1_16_R2.EntityTypes;
import net.minecraft.server.v1_16_R2.EntityVillagerAbstract;
import net.minecraft.server.v1_16_R2.PathfinderGoalBowShoot;
import net.minecraft.server.v1_16_R2.PathfinderGoalFloat;
import net.minecraft.server.v1_16_R2.PathfinderGoalHurtByTarget;
import net.minecraft.server.v1_16_R2.PathfinderGoalLookAtPlayer;
import net.minecraft.server.v1_16_R2.PathfinderGoalMeleeAttack;
import net.minecraft.server.v1_16_R2.PathfinderGoalNearestAttackableTarget;
import net.minecraft.server.v1_16_R2.PathfinderGoalRandomStroll;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
import org.bukkit.entity.Illusioner;
import org.jetbrains.annotations.NotNull;
public class CustomIllusioner extends EntityIllagerIllusioner implements CustomIllusionerProxy {
/**
* Instantiate a new custom illusioner entity.
*
* @param location The location to spawn it at.
*/
public CustomIllusioner(@NotNull final Location location) {
super(EntityTypes.ILLUSIONER, ((CraftWorld) location.getWorld()).getHandle());
this.setPosition(location.getX(), location.getY(), location.getZ());
this.goalSelector.a(0, new PathfinderGoalFloat(this));
this.goalSelector.a(1, new EntityIllagerWizard.b());
this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.0D, false));
this.goalSelector.a(2, new PathfinderGoalBowShoot<>(this, 1.0D, 20, 15.0F));
this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
this.goalSelector.a(0, new PathfinderGoalFloat(this));
this.goalSelector.a(6, new PathfinderGoalBowShoot<>(this, 0.5D, 20, 15.0F));
this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
this.goalSelector.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 3.0F, 1.0F));
this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F));
this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0]));
this.targetSelector.a(2, (new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)).a(300));
this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false)).a(300));
this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)).a(300));
}
/**
* Spawn illusioner.
*
* @param location The location.
* @return The illusioner.
*/
public static Illusioner spawn(@NotNull final Location location) {
CustomIllusioner illusioner = new CustomIllusioner(location);
((CraftWorld) location.getWorld()).getHandle().addEntity(illusioner);
return (Illusioner) illusioner.getBukkitEntity();
}
}

View File

@@ -1,6 +0,0 @@
group 'com.willfp'
version rootProject.version
dependencies {
compileOnly 'org.spigotmc:spigot:1.16.4-R0.1-SNAPSHOT'
}

View File

@@ -1,22 +0,0 @@
package com.willfp.ecobosses.proxy.v1_16_R3;
import com.willfp.ecobosses.proxy.proxies.CustomEntitySpawnerProxy;
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
import com.willfp.ecobosses.proxy.util.CustomEntity;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@SuppressWarnings("unchecked")
public class CustomEntitySpawner implements CustomEntitySpawnerProxy {
@Override
public <T extends LivingEntity> @Nullable T spawnCustomEntity(final Class<? extends CustomEntity<? extends LivingEntity>> entityClass,
@NotNull final Location location) {
if (entityClass.equals(CustomIllusionerProxy.class)) {
return (T) CustomIllusioner.spawn(location);
}
return null;
}
}

View File

@@ -1,62 +0,0 @@
package com.willfp.ecobosses.proxy.v1_16_R3;
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
import net.minecraft.server.v1_16_R3.EntityHuman;
import net.minecraft.server.v1_16_R3.EntityIllagerIllusioner;
import net.minecraft.server.v1_16_R3.EntityIllagerWizard;
import net.minecraft.server.v1_16_R3.EntityInsentient;
import net.minecraft.server.v1_16_R3.EntityIronGolem;
import net.minecraft.server.v1_16_R3.EntityRaider;
import net.minecraft.server.v1_16_R3.EntityTypes;
import net.minecraft.server.v1_16_R3.EntityVillagerAbstract;
import net.minecraft.server.v1_16_R3.PathfinderGoalBowShoot;
import net.minecraft.server.v1_16_R3.PathfinderGoalFloat;
import net.minecraft.server.v1_16_R3.PathfinderGoalHurtByTarget;
import net.minecraft.server.v1_16_R3.PathfinderGoalLookAtPlayer;
import net.minecraft.server.v1_16_R3.PathfinderGoalMeleeAttack;
import net.minecraft.server.v1_16_R3.PathfinderGoalNearestAttackableTarget;
import net.minecraft.server.v1_16_R3.PathfinderGoalRandomStroll;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
import org.bukkit.entity.Illusioner;
import org.jetbrains.annotations.NotNull;
public class CustomIllusioner extends EntityIllagerIllusioner implements CustomIllusionerProxy {
/**
* Instantiate a new custom illusioner entity.
*
* @param location The location to spawn it at.
*/
public CustomIllusioner(@NotNull final Location location) {
super(EntityTypes.ILLUSIONER, ((CraftWorld) location.getWorld()).getHandle());
this.setPosition(location.getX(), location.getY(), location.getZ());
this.goalSelector.a(0, new PathfinderGoalFloat(this));
this.goalSelector.a(1, new EntityIllagerWizard.b());
this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.0D, false));
this.goalSelector.a(2, new PathfinderGoalBowShoot<>(this, 1.0D, 20, 15.0F));
this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
this.goalSelector.a(0, new PathfinderGoalFloat(this));
this.goalSelector.a(6, new PathfinderGoalBowShoot<>(this, 0.5D, 20, 15.0F));
this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
this.goalSelector.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 3.0F, 1.0F));
this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F));
this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0]));
this.targetSelector.a(2, (new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)).a(300));
this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false)).a(300));
this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)).a(300));
}
/**
* Spawn illusioner.
*
* @param location The location.
* @return The illusioner.
*/
public static Illusioner spawn(@NotNull final Location location) {
CustomIllusioner illusioner = new CustomIllusioner(location);
((CraftWorld) location.getWorld()).getHandle().addEntity(illusioner);
return (Illusioner) illusioner.getBukkitEntity();
}
}

View File

@@ -2,8 +2,7 @@ group 'com.willfp'
version rootProject.version
dependencies {
compileOnly project(":eco-core:core-proxy")
compileOnly 'org.spigotmc:spigot-api:1.16.4-R0.1-SNAPSHOT'
compileOnly 'commons-io:commons-io:2.8.0'
compileOnly 'com.destroystokyo.paper:paper-api:1.16.3-R0.1-SNAPSHOT'
}
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
compileOnly 'com.github.lokka30:LevelledMobs:3.1.4'
compileOnly 'net.kyori:adventure-api:4.9.3'
}

View File

@@ -1,155 +0,0 @@
package com.willfp.ecobosses;
import com.willfp.eco.core.AbstractPacketAdapter;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.command.AbstractCommand;
import com.willfp.eco.core.integrations.IntegrationLoader;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.EcoBosses;
import com.willfp.ecobosses.bosses.listeners.*;
import com.willfp.ecobosses.commands.CommandEbdrop;
import com.willfp.ecobosses.commands.CommandEbkillall;
import com.willfp.ecobosses.commands.CommandEbreload;
import com.willfp.ecobosses.commands.CommandEbspawn;
import com.willfp.ecobosses.commands.TabCompleterEbspawn;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.Listener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@SuppressWarnings("unused")
public class EcoBossesPlugin extends EcoPlugin {
/**
* Instance of the plugin.
*/
@Getter
private static EcoBossesPlugin instance;
/**
* Internal constructor called by bukkit on plugin load.
*/
public EcoBossesPlugin() {
super("EcoBosses", 86576, 10635, "com.willfp.ecobosses.proxy", "&9");
instance = this;
}
/**
* Code executed on plugin enable.
*/
@Override
public void enable() {
this.getExtensionLoader().loadExtensions();
if (this.getExtensionLoader().getLoadedExtensions().isEmpty()) {
this.getLogger().info("&cNo extensions found");
} else {
this.getLogger().info("Extensions Loaded:");
this.getExtensionLoader().getLoadedExtensions().forEach(extension -> this.getLogger().info("- " + extension.getName() + " v" + extension.getVersion()));
}
this.getScheduler().runTimer(new AutoSpawnTimer(), 5, 1);
}
/**
* Code executed on plugin disable.
*/
@Override
public void disable() {
this.getExtensionLoader().unloadExtensions();
for (EcoBoss boss : EcoBosses.values()) {
for (UUID uuid : boss.getLivingBosses().keySet()) {
LivingEntity entity = (LivingEntity) Bukkit.getEntity(uuid);
assert entity != null;
entity.damage(10000000);
}
}
}
/**
* Nothing is called on plugin load.
*/
@Override
public void load() {
// Nothing needs to be called on load
}
/**
* Code executed on reload.
*/
@Override
public void onReload() {
}
/**
* Code executed after server is up.
*/
@Override
public void postLoad() {
// Nothing is executed post-load.
}
/**
* EcoEnchants-specific integrations.
*
* @return A list of all integrations.
*/
@Override
public List<IntegrationLoader> getIntegrationLoaders() {
return new ArrayList<>();
}
/**
* EcoEnchants-specific commands.
*
* @return A list of all commands.
*/
@Override
public List<AbstractCommand> getCommands() {
return Arrays.asList(
new CommandEbreload(this),
new CommandEbdrop(this),
new CommandEbspawn(this),
new CommandEbkillall(this)
);
}
/**
* Packet Adapters for enchant display.
*
* @return A list of packet adapters.
*/
@Override
public List<AbstractPacketAdapter> getPacketAdapters() {
return new ArrayList<>();
}
/**
* EcoEnchants-specific listeners.
*
* @return A list of all listeners.
*/
@Override
public List<Listener> getListeners() {
return Arrays.asList(
new AttackListeners(this),
new DeathListeners(this),
new SpawnListeners(this),
new PassiveListeners(this)
);
}
@Override
public List<Class<?>> getUpdatableClasses() {
return Arrays.asList(
EcoBosses.class,
TabCompleterEbspawn.class
);
}
}

View File

@@ -1,522 +0,0 @@
package com.willfp.ecobosses.bosses;
import com.google.common.collect.ImmutableMap;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.config.Config;
import com.willfp.eco.core.tuples.Pair;
import com.willfp.eco.util.StringUtils;
import com.willfp.ecobosses.bosses.effects.Effect;
import com.willfp.ecobosses.bosses.effects.Effects;
import com.willfp.ecobosses.bosses.util.bosstype.BossEntityUtils;
import com.willfp.ecobosses.bosses.util.bosstype.BossType;
import com.willfp.ecobosses.bosses.util.obj.*;
import lombok.AccessLevel;
import lombok.Getter;
import org.bukkit.*;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.stream.Collectors;
public class EcoBoss extends PluginDependent {
/**
* The name of the boss.
*/
@Getter
private final String name;
/**
* The config of the set.
*/
@Getter(AccessLevel.PRIVATE)
private final Config config;
/**
* The display name of the boss.
*/
@Getter
private final String displayName;
/**
* The base entity spawner.
*/
private final BossType bossType;
/**
* If the boss bar is enabled.
*/
@Getter
private final boolean bossbarEnabled;
/**
* The BossBar properties.
*/
@Getter
private final BossbarProperties bossbarProperties;
/**
* If spawn totem is enabled.
*/
@Getter
private final boolean spawnTotemEnabled;
/**
* The spawn totem.
*/
@Getter
private final SpawnTotem spawnTotem;
/**
* Disabled world names for spawn totem.
*/
@Getter
private final List<String> spawnTotemDisabledWorldNames;
/**
* The max health.
*/
@Getter
private final int maxHealth;
/**
* The attack damage.
*/
@Getter
private final int attackDamage;
/**
* The follow range.
*/
@Getter
private final double followRange;
/**
* The movement speed multiplier.
*/
@Getter
private final double movementSpeedMultiplier;
/**
* The immunity options.
*/
@Getter
private final ImmunityOptions immunityOptions;
/**
* The drops.
*/
@Getter
private final Map<ItemStack, Double> drops;
/**
* The exp to drop.
*/
@Getter
private final ExperienceOptions experienceOptions;
/**
* If attacks should be called on injury.
*/
@Getter
private final boolean attackOnInjure;
/**
* Sounds played on injure.
*/
@Getter
private final List<OptionedSound> injureSounds;
/**
* Spawn sounds.
*/
@Getter
private final List<OptionedSound> spawnSounds;
/**
* Death sounds.
*/
@Getter
private final List<OptionedSound> deathSounds;
/**
* Summon sounds.
*/
@Getter
private final List<OptionedSound> summonSounds;
/**
* Spawn messages.
*/
@Getter
private final List<String> spawnMessages;
/**
* Death messages.
*/
@Getter
private final List<String> deathMessages;
/**
* Nearby players radius.
*/
@Getter
private final double nearbyRadius;
/**
* Nearby players commands.
*/
@Getter
private final Map<String, Double> nearbyPlayersCommands;
/**
* Top damager commands.
*/
@Getter
private final Map<Integer, List<Pair<Double, String>>> topDamagerCommands;
/**
* Incoming damage multipliers.
*/
@Getter
private final Map<EntityDamageEvent.DamageCause, Double> incomingMultipliers;
/**
* The currently living bosses of this type.
*/
private final Map<UUID, LivingEcoBoss> livingBosses;
/**
* The effect names and arguments.
*/
private final Map<String, List<String>> effectNames;
/**
* The target distance.
*/
@Getter
private final double targetDistance;
/**
* The targeting mode.
*/
@Getter
private final TargetMode targetMode;
/**
* If the boss shouldn't get into boats and minecarts.
*/
@Getter
private final boolean disableBoats;
/**
* The time between auto spawns.
*/
@Getter
private final int autoSpawnInterval;
/**
* Locations that the boss can auto spawn at.
*/
@Getter
private final List<Location> autoSpawnLocations;
/**
* Create a new Boss.
*
* @param name The name of the set.
* @param config The set's config.
* @param plugin Instance of EcoBosses.
*/
public EcoBoss(@NotNull final String name,
@NotNull final Config config,
@NotNull final EcoPlugin plugin) {
super(plugin);
this.config = config;
this.name = name;
this.livingBosses = new HashMap<>();
this.displayName = this.getConfig().getString("name");
// Boss Type
this.bossType = BossEntityUtils.getBossType(this.getConfig().getString("base-mob"));
// Boss Bar
this.bossbarEnabled = this.getConfig().getBool("bossbar.enabled");
this.bossbarProperties = new BossbarProperties(
BarColor.valueOf(this.getConfig().getString("bossbar.color").toUpperCase()),
BarStyle.valueOf(this.getConfig().getString("bossbar.style").toUpperCase())
);
// Attributes
this.attackDamage = this.getConfig().getInt("attack-damage");
this.maxHealth = this.getConfig().getInt("max-health");
this.followRange = this.getConfig().getInt("follow-range");
this.movementSpeedMultiplier = this.getConfig().getInt("movement-speed");
// Spawn Totem
this.spawnTotemEnabled = this.getConfig().getBool("spawn-totem.enabled");
this.spawnTotem = new SpawnTotem(
Material.getMaterial(this.getConfig().getString("spawn-totem.bottom").toUpperCase()),
Material.getMaterial(this.getConfig().getString("spawn-totem.middle").toUpperCase()),
Material.getMaterial(this.getConfig().getString("spawn-totem.top").toUpperCase())
);
this.spawnTotemDisabledWorldNames = this.getConfig().getStrings("spawn-totem.world-blacklist").stream().map(String::toLowerCase).collect(Collectors.toList());
// Rewards
this.drops = new HashMap<>();
for (String string : this.getConfig().getStrings("rewards.drops")) {
YamlConfiguration tempConfig = new YamlConfiguration();
double chance = 100;
if (string.contains("::")) {
String[] split = string.split("::");
chance = Double.parseDouble(split[0]);
string = split[1];
}
String tempConfigString = new String(Base64.getDecoder().decode(string));
try {
tempConfig.loadFromString(tempConfigString);
} catch (InvalidConfigurationException e) {
e.printStackTrace();
}
ItemStack itemStack = tempConfig.getItemStack("drop-key");
this.drops.put(itemStack, chance);
}
this.experienceOptions = new ExperienceOptions(
this.getConfig().getInt("rewards.xp.minimum"),
this.getConfig().getInt("rewards.xp.maximum")
);
// Immunities
this.immunityOptions = new ImmunityOptions(
this.getConfig().getBool("defence.immunities.fire"),
this.getConfig().getBool("defence.immunities.suffocation"),
this.getConfig().getBool("defence.immunities.drowning"),
this.getConfig().getBool("defence.immunities.projectiles"),
this.getConfig().getBool("defence.immunities.explosion")
);
// Multipliers
this.incomingMultipliers = new HashMap<>();
double melee = this.getConfig().getDouble("defence.incoming-multipliers.melee");
this.incomingMultipliers.put(EntityDamageEvent.DamageCause.ENTITY_ATTACK, melee);
this.incomingMultipliers.put(EntityDamageEvent.DamageCause.ENTITY_SWEEP_ATTACK, melee);
double projectile = this.getConfig().getDouble("defence.incoming-multipliers.projectile");
this.incomingMultipliers.put(EntityDamageEvent.DamageCause.PROJECTILE, projectile);
// Attack on injure
this.attackOnInjure = this.getConfig().getBool("attacks.on-injure");
// Sounds
this.injureSounds = new ArrayList<>();
for (String string : this.getConfig().getStrings("sounds.injure")) {
String[] split = string.split(":");
this.injureSounds.add(new OptionedSound(
Sound.valueOf(split[0].toUpperCase()),
Float.parseFloat(split[1]) / 16,
Float.parseFloat(split[2])
));
}
this.deathSounds = new ArrayList<>();
for (String string : this.getConfig().getStrings("sounds.death")) {
String[] split = string.split(":");
this.deathSounds.add(new OptionedSound(
Sound.valueOf(split[0].toUpperCase()),
Float.parseFloat(split[1]) / 16,
Float.parseFloat(split[2])
));
}
this.summonSounds = new ArrayList<>();
for (String string : this.getConfig().getStrings("sounds.summon")) {
String[] split = string.split(":");
this.summonSounds.add(new OptionedSound(
Sound.valueOf(split[0].toUpperCase()),
Float.parseFloat(split[1]) / 16,
Float.parseFloat(split[2])
));
}
this.spawnSounds = new ArrayList<>();
for (String string : this.getConfig().getStrings("sounds.spawn")) {
String[] split = string.split(":");
this.spawnSounds.add(new OptionedSound(
Sound.valueOf(split[0].toUpperCase()),
Float.parseFloat(split[1]) / 16,
Float.parseFloat(split[2])
));
}
// Messages
this.spawnMessages = new ArrayList<>();
for (String string : this.getConfig().getStrings("broadcast.spawn")) {
this.spawnMessages.add(StringUtils.translate(string));
}
this.deathMessages = new ArrayList<>();
for (String string : this.getConfig().getStrings("broadcast.death")) {
this.deathMessages.add(StringUtils.translate(string));
}
// Top Damager Commands
this.topDamagerCommands = new HashMap<>();
for (int i = 1; i <= 3; i++) {
this.topDamagerCommands.put(i, new ArrayList<>());
for (String string : this.getConfig().getStrings("rewards.top-damager-commands." + i)) {
double chance = 100;
if (string.contains("::")) {
String[] split = string.split("::");
chance = Double.parseDouble(split[0]);
string = split[1];
}
List<Pair<Double, String>> commands = this.topDamagerCommands.get(i) == null ? new ArrayList<>() : this.topDamagerCommands.get(i);
commands.add(new Pair<>(chance, string));
this.topDamagerCommands.put(i, commands);
}
}
// Nearby Rewards
this.nearbyRadius = this.getConfig().getDouble("rewards.nearby-player-commands.radius");
this.nearbyPlayersCommands = new HashMap<>();
for (String string : this.getConfig().getStrings("rewards.nearby-player-commands.commands")) {
double chance = 100;
if (string.contains("::")) {
String[] split = string.split("::");
chance = Double.parseDouble(split[0]);
string = split[1];
}
this.nearbyPlayersCommands.put(string, chance);
}
// Effects
this.effectNames = new HashMap<>();
for (String string : this.getConfig().getStrings("effects")) {
String effectName = string.split(":")[0];
List<String> args = Arrays.asList(string.replace(effectName + ":", "").split(":"));
this.effectNames.put(effectName, args);
}
new HashMap<>(this.effectNames).forEach((string, args) -> {
if (Effects.getEffect(string, args) == null) {
this.effectNames.remove(string);
Bukkit.getLogger().warning("Invalid effect specified in " + this.name);
}
});
// Targeting
this.targetDistance = this.getConfig().getDouble("attacks.target.range");
this.targetMode = TargetMode.getByName(this.getConfig().getString("attacks.target.mode"));
// Boat + Minecarts
this.disableBoats = this.getConfig().getBool("defence.no-boats");
// Auto Spawn
this.autoSpawnInterval = this.getConfig().getInt("auto-spawn-interval");
this.autoSpawnLocations = new ArrayList<>();
for (String string : this.getConfig().getStrings("auto-spawn-locations")) {
String[] split = string.split(":");
World world = Bukkit.getWorld(split[0]);
double x = Double.parseDouble(split[1]);
double y = Double.parseDouble(split[2]);
double z = Double.parseDouble(split[3]);
autoSpawnLocations.add(new Location(world, x, y, z));
}
if (this.getConfig().getBool("enabled")) {
EcoBosses.addBoss(this);
}
}
/**
* Create effect tickers for Living Boss.
*
* @return The effects.
*/
public Set<Effect> createEffects() {
Set<Effect> effects = new HashSet<>();
this.effectNames.forEach((string, args) -> {
effects.add(Effects.getEffect(string, args));
});
return effects;
}
/**
* Spawn the boss.
*
* @param location The location.
*/
public void spawn(@NotNull final Location location) {
LivingEntity entity = bossType.spawnBossEntity(location);
this.livingBosses.put(entity.getUniqueId(), new LivingEcoBoss(
this.getPlugin(),
entity,
this
)
);
}
/**
* Get {@link LivingEcoBoss} from an entity.
*
* @param entity The entity.
* @return The living boss, or null if not a boss.
*/
public LivingEcoBoss getLivingBoss(@NotNull final LivingEntity entity) {
return this.livingBosses.get(entity.getUniqueId());
}
/**
* Remove living boss.
*
* @param uuid The entity UUID.
*/
public void removeLivingBoss(@NotNull final UUID uuid) {
this.livingBosses.remove(uuid);
}
/**
* Get all living bosses.
*
* @return The living bosses.
*/
public Map<UUID, LivingEcoBoss> getLivingBosses() {
return ImmutableMap.copyOf(this.livingBosses);
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof EcoBoss)) {
return false;
}
EcoBoss boss = (EcoBoss) o;
return this.getName().equals(boss.getName());
}
@Override
public int hashCode() {
return Objects.hash(this.getName());
}
@Override
public String toString() {
return "EcoBoss{"
+ this.getName()
+ "}";
}
}

View File

@@ -1,104 +0,0 @@
package com.willfp.ecobosses.bosses;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.willfp.eco.core.config.ConfigUpdater;
import com.willfp.ecobosses.EcoBossesPlugin;
import com.willfp.ecobosses.config.BaseBossConfig;
import com.willfp.ecobosses.config.CustomConfig;
import lombok.experimental.UtilityClass;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
@UtilityClass
public class EcoBosses {
/**
* Registered armor sets.
*/
private static final BiMap<String, EcoBoss> BY_NAME = HashBiMap.create();
/**
* Sets that exist by default.
*/
private static final List<String> DEFAULT_BOSSES = Arrays.asList(
"illusioner",
"tarantula",
"steel_golem",
"alpha_wolf"
);
/**
* Get all registered {@link EcoBoss}es.
*
* @return A list of all {@link EcoBoss}es.
*/
public static List<EcoBoss> values() {
return ImmutableList.copyOf(BY_NAME.values());
}
/**
* Get {@link EcoBoss} matching name.
*
* @param name The name to search for.
* @return The matching {@link EcoBoss}, or null if not found.
*/
public static EcoBoss getByName(@NotNull final String name) {
return BY_NAME.get(name);
}
/**
* Update all {@link EcoBoss}s.
*/
@ConfigUpdater
public static void update() {
for (EcoBoss boss : values()) {
removeBoss(boss);
}
for (String defaultSetName : DEFAULT_BOSSES) {
new EcoBoss(defaultSetName, new BaseBossConfig(defaultSetName), EcoBossesPlugin.getInstance());
}
try {
Files.walk(Paths.get(new File(EcoBossesPlugin.getInstance().getDataFolder(), "bosses/").toURI()))
.filter(Files::isRegularFile)
.forEach(path -> {
String name = path.getFileName().toString().replace(".yml", "");
new EcoBoss(
name,
new CustomConfig(name, YamlConfiguration.loadConfiguration(path.toFile())),
EcoBossesPlugin.getInstance()
);
});
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Add new {@link EcoBoss} to EcoBosses.
*
* @param set The {@link EcoBoss} to add.
*/
public static void addBoss(@NotNull final EcoBoss set) {
BY_NAME.remove(set.getName());
BY_NAME.put(set.getName(), set);
}
/**
* Remove {@link EcoBoss} from EcoBosses.
*
* @param set The {@link EcoBoss} to remove.
*/
public static void removeBoss(@NotNull final EcoBoss set) {
BY_NAME.remove(set.getName());
}
}

View File

@@ -1,164 +0,0 @@
package com.willfp.ecobosses.bosses;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.scheduling.RunnableTask;
import com.willfp.eco.util.NumberUtils;
import com.willfp.eco.util.StringUtils;
import com.willfp.ecobosses.bosses.effects.Effect;
import com.willfp.ecobosses.bosses.tick.BossTicker;
import com.willfp.ecobosses.bosses.tick.tickers.BossBarTicker;
import com.willfp.ecobosses.bosses.tick.tickers.HealthPlaceholderTicker;
import com.willfp.ecobosses.bosses.tick.tickers.TargetTicker;
import com.willfp.ecobosses.bosses.util.obj.OptionedSound;
import org.bukkit.Bukkit;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.boss.BarFlag;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
public class LivingEcoBoss extends PluginDependent {
/**
* The entity.
*/
private final LivingEntity entity;
/**
* The boss.
*/
private final EcoBoss boss;
/**
* The boss tickers.
*/
private final Set<BossTicker> tickers;
/**
* The effects.
*/
private final Set<Effect> effects;
/**
* Create new living EcoBoss.
*
* @param plugin Instance of EcoBosses.
* @param entity The entity.
* @param boss The boss.
*/
public LivingEcoBoss(@NotNull final EcoPlugin plugin,
@NotNull final LivingEntity entity,
@NotNull final EcoBoss boss) {
super(plugin);
this.entity = entity;
this.boss = boss;
this.onSpawn();
// Tickers
this.tickers = new HashSet<>();
this.tickers.add(new HealthPlaceholderTicker());
this.tickers.add(new TargetTicker(boss.getTargetMode(), boss.getTargetDistance()));
if (boss.isBossbarEnabled()) {
this.tickers.add(
new BossBarTicker(
Bukkit.getServer().createBossBar(
plugin.getNamespacedKeyFactory().create("boss_" + NumberUtils.randInt(0, 1000000)),
entity.getCustomName(),
boss.getBossbarProperties().getColor(),
boss.getBossbarProperties().getStyle(),
(BarFlag) null
),
this.getPlugin().getConfigYml().getInt("bossbar-radius")
)
);
}
// Effects
this.effects = new HashSet<>();
this.effects.addAll(boss.createEffects());
AtomicLong currentTick = new AtomicLong(0);
this.getPlugin().getRunnableFactory().create(runnable -> this.tick(currentTick.getAndAdd(1), runnable)).runTaskTimer(0, 1);
}
private void onSpawn() {
entity.getPersistentDataContainer().set(this.getPlugin().getNamespacedKeyFactory().create("boss"), PersistentDataType.STRING, boss.getName());
entity.setPersistent(true);
entity.setCustomName(boss.getDisplayName());
entity.setCustomNameVisible(true);
AttributeInstance movementSpeed = entity.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED);
assert movementSpeed != null;
movementSpeed.addModifier(new AttributeModifier(entity.getUniqueId(), "ecobosses-movement-multiplier", boss.getMovementSpeedMultiplier() - 1, AttributeModifier.Operation.MULTIPLY_SCALAR_1));
AttributeInstance maxHealth = entity.getAttribute(Attribute.GENERIC_MAX_HEALTH);
assert maxHealth != null;
maxHealth.setBaseValue(boss.getMaxHealth());
entity.setHealth(maxHealth.getValue());
AttributeInstance followRange = entity.getAttribute(Attribute.GENERIC_FOLLOW_RANGE);
assert followRange != null;
followRange.setBaseValue(boss.getFollowRange());
AttributeInstance attackDamage = entity.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE);
assert attackDamage != null;
attackDamage.setBaseValue(boss.getAttackDamage());
for (OptionedSound sound : boss.getSpawnSounds()) {
entity.getWorld().playSound(entity.getLocation(), sound.getSound(), sound.getVolume(), sound.getPitch());
}
for (String spawnMessage : boss.getSpawnMessages()) {
Bukkit.broadcastMessage(spawnMessage
.replace("%x%", StringUtils.internalToString(entity.getLocation().getBlockX()))
.replace("%y%", StringUtils.internalToString(entity.getLocation().getBlockY()))
.replace("%z%", StringUtils.internalToString(entity.getLocation().getBlockZ()))
);
}
}
private void tick(final long tick,
@NotNull final RunnableTask runnable) {
for (BossTicker ticker : tickers) {
ticker.tick(boss, entity, tick);
}
for (Effect effect : effects) {
effect.tick(boss, entity, tick);
}
if (entity.isDead()) {
for (BossTicker ticker : tickers) {
ticker.onDeath(boss, entity, tick);
}
for (Effect effect : effects) {
effect.onDeath(boss, entity, tick);
}
boss.removeLivingBoss(entity.getUniqueId());
runnable.cancel();
}
}
/**
* Handle an attack to the player.
*
* @param player The player.
*/
public void handleAttack(@NotNull final Player player) {
for (OptionedSound sound : boss.getInjureSounds()) {
player.getWorld().playSound(entity.getLocation(), sound.getSound(), sound.getVolume(), sound.getPitch());
}
for (Effect effect : effects) {
effect.onAttack(boss, entity, player);
}
}
}

View File

@@ -1,86 +0,0 @@
package com.willfp.ecobosses.bosses.effects;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.tick.BossTicker;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public abstract class Effect implements BossTicker {
/**
* The effect args.
*/
@Getter
private final List<String> args;
/**
* Create a new effect.
*
* @param args The args.
*/
protected Effect(@NotNull final List<String> args) {
this.args = args;
}
/**
* Show a config error.
*
* @param message The error message.
*/
public void showConfigError(@NotNull final String message) {
Bukkit.getLogger().warning("An effect is configured incorrectly!");
Bukkit.getLogger().warning(message);
Bukkit.getLogger().warning("Usage: " + getUsage());
}
/**
* Get effect usage.
*
* @return The usage.
*/
public abstract String getUsage();
/**
* Handle the boss attacking a player.
*
* @param boss The boss.
* @param entity The boss entity.
* @param player The player.
*/
public void onAttack(@NotNull final EcoBoss boss,
@NotNull final LivingEntity entity,
@NotNull final Player player) {
// Override when needed.
}
/**
* Tick the effect.
*
* @param boss The boss.
* @param entity The boss entity.
* @param tick The current tick: counts up from zero.
*/
public void tick(@NotNull final EcoBoss boss,
@NotNull final LivingEntity entity,
final long tick) {
// Override when needed.
}
/**
* On boss death.
*
* @param boss The boss.
* @param entity The boss entity.
* @param tick The current tick: counts up from zero.
*/
@Override
public void onDeath(@NotNull final EcoBoss boss,
@NotNull final LivingEntity entity,
final long tick) {
// Override when needed.
}
}

View File

@@ -1,53 +0,0 @@
package com.willfp.ecobosses.bosses.effects;
import com.willfp.ecobosses.bosses.effects.effects.*;
import lombok.experimental.UtilityClass;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@UtilityClass
public class Effects {
/**
* Registered effects.
*/
private static final Map<String, Function<List<String>, Effect>> EFFECTS = new HashMap<>();
static {
register("damage-nearby-players", EffectDamageNearbyPlayers::new);
register("lightning-nearby-entities", EffectLightningNearbyEntities::new);
register("summon", EffectSummon::new);
register("give-potion-effect", EffectGivePotionEffect::new);
register("shuffle-hotbar", EffectShuffleHotbar::new);
register("teleport", EffectTeleport::new);
}
/**
* Register new effect.
*
* @param name The effect name.
* @param creator Function to create an instance of the effect given args.
*/
public void register(@NotNull final String name,
@NotNull final Function<List<String>, Effect> creator) {
EFFECTS.put(name, creator);
}
/**
* Get effect matching name.
*
* @param name The effect name.
* @param args The args.
* @return The found effect, or null.
*/
@Nullable
public Effect getEffect(@NotNull final String name,
@NotNull final List<String> args) {
Function<List<String>, Effect> found = EFFECTS.get(name.toLowerCase());
return found == null ? null : found.apply(args);
}
}

View File

@@ -1,46 +0,0 @@
package com.willfp.ecobosses.bosses.effects.effects;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.effects.Effect;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class EffectDamageNearbyPlayers extends Effect {
private final int frequency;
private final double damage;
private final double radius;
public EffectDamageNearbyPlayers(@NotNull final List<String> args) {
super(args);
if (args.size() < 3) {
showConfigError("Incorrect amount of arguments!");
}
frequency = Integer.parseInt(args.get(0));
radius = Double.parseDouble(args.get(1));
damage = Double.parseDouble(args.get(2));
}
@Override
public String getUsage() {
return "damage-nearby-players:<frequency>:<damage>:<radius>";
}
@Override
public void tick(@NotNull final EcoBoss boss,
@NotNull final LivingEntity entity,
final long tick) {
if (tick % frequency == 0) {
for (Entity nearbyEntity : entity.getNearbyEntities(radius, radius, radius)) {
if (nearbyEntity instanceof Player) {
((Player) nearbyEntity).damage(damage, entity);
}
}
}
}
}

View File

@@ -1,48 +0,0 @@
package com.willfp.ecobosses.bosses.effects.effects;
import com.willfp.eco.util.NumberUtils;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.effects.Effect;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class EffectGivePotionEffect extends Effect {
private final PotionEffectType type;
private final double chance;
private final int duration;
private final int strength;
public EffectGivePotionEffect(@NotNull final List<String> args) {
super(args);
if (args.size() < 4) {
showConfigError("Incorrect amount of arguments!");
}
type = PotionEffectType.getByName(args.get(0).toUpperCase());
chance = Double.parseDouble(args.get(1));
duration = Integer.parseInt(args.get(2));
strength = Integer.parseInt(args.get(3));
}
@Override
public String getUsage() {
return "give-potion-effect:<effect>:<chance>:<duration>:<strength>";
}
@Override
public void onAttack(@NotNull final EcoBoss boss,
@NotNull final LivingEntity entity,
@NotNull final Player player) {
if (NumberUtils.randFloat(0, 100) > this.chance) {
return;
}
player.addPotionEffect(new PotionEffect(type, duration, strength - 1));
}
}

View File

@@ -1,51 +0,0 @@
package com.willfp.ecobosses.bosses.effects.effects;
import com.willfp.eco.util.LightningUtils;
import com.willfp.eco.util.NumberUtils;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.effects.Effect;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class EffectLightningNearbyEntities extends Effect {
private final int frequency;
private final double chance;
private final double damage;
private final double radius;
public EffectLightningNearbyEntities(@NotNull final List<String> args) {
super(args);
if (args.size() < 4) {
showConfigError("Incorrect amount of arguments!");
}
frequency = Integer.parseInt(args.get(0));
chance = Double.parseDouble(args.get(1));
radius = Double.parseDouble(args.get(2));
damage = Double.parseDouble(args.get(3));
}
@Override
public String getUsage() {
return "lightning-nearby-entities:<frequency>:<chance>:<damage>:<radius>";
}
@Override
public void tick(@NotNull final EcoBoss boss,
@NotNull final LivingEntity entity,
final long tick) {
if (tick % frequency == 0) {
for (Entity nearbyEntity : entity.getNearbyEntities(radius, radius, radius)) {
if (NumberUtils.randFloat(0, 100) < chance) {
if (nearbyEntity instanceof LivingEntity) {
LightningUtils.strike((LivingEntity) nearbyEntity, damage);
}
}
}
}
}
}

View File

@@ -1,54 +0,0 @@
package com.willfp.ecobosses.bosses.effects.effects;
import com.willfp.eco.util.NumberUtils;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.effects.Effect;
import org.bukkit.Sound;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class EffectShuffleHotbar extends Effect {
private final double chance;
public EffectShuffleHotbar(@NotNull final List<String> args) {
super(args);
if (args.size() < 1) {
showConfigError("Incorrect amount of arguments!");
}
chance = Double.parseDouble(args.get(0));
}
@Override
public String getUsage() {
return "shuffle-hotbar:<chance>";
}
@Override
public void onAttack(@NotNull final EcoBoss boss,
@NotNull final LivingEntity entity,
@NotNull final Player player) {
if (NumberUtils.randFloat(0, 100) > this.chance) {
return;
}
List<ItemStack> hotbar = new ArrayList<>();
for (int i = 0; i < 9; i++) {
hotbar.add(player.getInventory().getItem(i));
}
Collections.shuffle(hotbar);
int i2 = 0;
for (ItemStack item : hotbar) {
player.getInventory().setItem(i2, item);
i2++;
}
player.playSound(player.getLocation(), Sound.ENTITY_ENDER_PEARL_THROW, 1, 0.5f);
}
}

View File

@@ -1,65 +0,0 @@
package com.willfp.ecobosses.bosses.effects.effects;
import com.willfp.eco.util.NumberUtils;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.effects.Effect;
import com.willfp.ecobosses.bosses.util.bosstype.BossEntityUtils;
import com.willfp.ecobosses.bosses.util.bosstype.BossType;
import com.willfp.ecobosses.bosses.util.obj.OptionedSound;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Mob;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class EffectSummon extends Effect {
private final BossType type;
private final double chance;
public EffectSummon(@NotNull final List<String> args) {
super(args);
if (args.size() < 2) {
showConfigError("Incorrect amount of arguments!");
}
type = BossEntityUtils.getBossType(args.get(0));
chance = Double.parseDouble(args.get(1));
}
@Override
public String getUsage() {
return "summon:<entity>:<chance>";
}
@Override
public void onAttack(@NotNull final EcoBoss boss,
@NotNull final LivingEntity entity,
@NotNull final Player player) {
if (NumberUtils.randFloat(0, 100) > this.chance) {
return;
}
Location loc = player.getLocation().add(NumberUtils.randInt(2, 6), 0, NumberUtils.randInt(2, 6));
for (int i = 0; i < 15; i++) {
if (loc.getBlock().getType() == Material.AIR) {
break;
}
loc.add(0, 1, 0);
}
Entity summonedEntity = type.spawnBossEntity(loc);
if (summonedEntity instanceof Mob) {
((Mob) summonedEntity).setTarget(player);
}
for (OptionedSound sound : boss.getSummonSounds()) {
player.getWorld().playSound(entity.getLocation(), sound.getSound(), sound.getVolume(), sound.getPitch());
}
}
}

View File

@@ -1,75 +0,0 @@
package com.willfp.ecobosses.bosses.effects.effects;
import com.willfp.eco.util.NumberUtils;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.effects.Effect;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class EffectTeleport extends Effect {
private final int range;
private final double chance;
public EffectTeleport(@NotNull final List<String> args) {
super(args);
if (args.size() < 2) {
showConfigError("Incorrect amount of arguments!");
}
range = Integer.parseInt(args.get(0));
chance = Double.parseDouble(args.get(1));
}
@Override
public String getUsage() {
return "teleport:<range>:<chance>";
}
@Override
public void onAttack(@NotNull final EcoBoss boss,
@NotNull final LivingEntity entity,
@NotNull final Player player) {
if (NumberUtils.randFloat(0, 100) > this.chance) {
return;
}
List<Location> valid = new ArrayList<>();
for (int x = -range; x <= range; x++) {
for (int y = -range; y <= range; y++) {
for (int z = -range; z <= range; z++) {
Location location = entity.getLocation().clone();
location.setX(location.getX() + x);
location.setY(location.getY() + y);
location.setZ(location.getZ() + z);
Block block = location.getBlock();
if (block.getType() == Material.AIR
&& block.getRelative(BlockFace.UP).getType() == Material.AIR
&& !(block.getRelative(BlockFace.DOWN).isLiquid() || block.getRelative(BlockFace.DOWN).getType() == Material.AIR)) {
valid.add(location);
}
}
}
}
if (valid.isEmpty()) {
return;
}
Collections.shuffle(valid);
Location location = valid.get(0);
entity.teleport(location);
}
}

View File

@@ -1,200 +0,0 @@
package com.willfp.ecobosses.bosses.listeners;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.LivingEcoBoss;
import com.willfp.ecobosses.bosses.util.BossUtils;
import com.willfp.ecobosses.bosses.util.obj.DamagerProperty;
import com.willfp.ecobosses.bosses.util.obj.ImmunityOptions;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class AttackListeners extends PluginDependent implements Listener {
/**
* Create new attack listeners.
*
* @param plugin Instance of EcoBosses.
*/
public AttackListeners(@NotNull final EcoPlugin plugin) {
super(plugin);
}
/**
* Called when a player attacks a boss.
*
* @param event The event to listen for.
*/
@EventHandler(ignoreCancelled = true)
public void onAttackBoss(@NotNull final EntityDamageByEntityEvent event) {
if (!(event.getEntity() instanceof LivingEntity)) {
return;
}
LivingEntity entity = (LivingEntity) event.getEntity();
Player player = null;
if (event.getDamager() instanceof Player) {
player = (Player) event.getDamager();
} else if (event.getDamager() instanceof Projectile) {
if (((Projectile) event.getDamager()).getShooter() instanceof Player) {
player = (Player) ((Projectile) event.getDamager()).getShooter();
}
}
if (player == null) {
return;
}
EcoBoss boss = BossUtils.getBoss(entity);
if (boss == null) {
return;
}
LivingEcoBoss livingEcoBoss = boss.getLivingBoss(entity);
if (boss.isAttackOnInjure()) {
livingEcoBoss.handleAttack(player);
}
}
/**
* Track top damage players.
*
* @param event The event to listen for.
*/
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void topDamageTracker(@NotNull final EntityDamageByEntityEvent event) {
if (!(event.getEntity() instanceof LivingEntity)) {
return;
}
LivingEntity entity = (LivingEntity) event.getEntity();
Player temp = null;
if (event.getDamager() instanceof Player) {
temp = (Player) event.getDamager();
} else if (event.getDamager() instanceof Projectile) {
if (((Projectile) event.getDamager()).getShooter() instanceof Player) {
temp = (Player) ((Projectile) event.getDamager()).getShooter();
}
}
if (temp == null) {
return;
}
Player player = temp;
EcoBoss boss = BossUtils.getBoss(entity);
if (boss == null) {
return;
}
List<DamagerProperty> topDamagers = BossUtils.getTopDamagers(entity);
double playerDamage;
Optional<DamagerProperty> damager = topDamagers.stream().filter(damagerProperty -> damagerProperty.getPlayerUUID().equals(player.getUniqueId())).findFirst();
playerDamage = damager.map(DamagerProperty::getDamage).orElse(0.0);
playerDamage += event.getFinalDamage();
topDamagers.removeIf(damagerProperty -> damagerProperty.getPlayerUUID().equals(player.getUniqueId()));
topDamagers.add(new DamagerProperty(player.getUniqueId(), playerDamage));
entity.removeMetadata("ecobosses-top-damagers", this.getPlugin());
entity.setMetadata("ecobosses-top-damagers", this.getPlugin().getMetadataValueFactory().create(topDamagers));
}
/**
* Called when a boss attacks a player.
*
* @param event The event to listen for.
*/
@EventHandler(ignoreCancelled = true)
public void onAttackPlayer(@NotNull final EntityDamageByEntityEvent event) {
if (!(event.getEntity() instanceof Player)) {
return;
}
if (!(event.getDamager() instanceof LivingEntity)) {
return;
}
LivingEntity entity = (LivingEntity) event.getDamager();
Player player = (Player) event.getEntity();
EcoBoss boss = BossUtils.getBoss(entity);
if (boss == null) {
return;
}
LivingEcoBoss livingEcoBoss = boss.getLivingBoss(entity);
livingEcoBoss.handleAttack(player);
}
/**
* Called when a boss is damaged.
*
* @param event The event to listen for.
*/
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
public void defenceListener(@NotNull final EntityDamageEvent event) {
if (!(event.getEntity() instanceof LivingEntity)) {
return;
}
LivingEntity entity = (LivingEntity) event.getEntity();
EcoBoss boss = BossUtils.getBoss(entity);
if (boss == null) {
return;
}
ImmunityOptions immunities = boss.getImmunityOptions();
if (immunities.isImmuneToFire()
&& (event.getCause() == EntityDamageEvent.DamageCause.FIRE
|| event.getCause() == EntityDamageEvent.DamageCause.FIRE_TICK
|| event.getCause() == EntityDamageEvent.DamageCause.HOT_FLOOR)) {
event.setCancelled(true);
}
if (immunities.isImmuneToSuffocation()&& event.getCause() == EntityDamageEvent.DamageCause.SUFFOCATION) {
event.setCancelled(true);
}
if (immunities.isImmuneToDrowning() && event.getCause() == EntityDamageEvent.DamageCause.DROWNING) {
event.setCancelled(true);
}
if (immunities.isImmuneToExplosions() && (event.getCause() == EntityDamageEvent.DamageCause.ENTITY_EXPLOSION || event.getCause() == EntityDamageEvent.DamageCause.BLOCK_EXPLOSION)) {
event.setCancelled(true);
}
if (immunities.isImmuneToProjectiles() && (event.getCause() == EntityDamageEvent.DamageCause.PROJECTILE)) {
event.setCancelled(true);
}
for (Map.Entry<EntityDamageEvent.DamageCause, Double> entry : boss.getIncomingMultipliers().entrySet()) {
if (event.getCause() == entry.getKey()) {
event.setDamage(event.getDamage() * entry.getValue());
}
}
}
}

View File

@@ -1,30 +0,0 @@
package com.willfp.ecobosses.bosses.listeners;
import com.willfp.eco.util.NumberUtils;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.EcoBosses;
import org.bukkit.Location;
public class AutoSpawnTimer implements Runnable {
private int tick = 0;
@Override
public void run() {
tick++;
for (EcoBoss boss : EcoBosses.values()) {
if (boss.getAutoSpawnInterval() < 0) {
continue;
}
if (boss.getAutoSpawnLocations().isEmpty()) {
continue;
}
if (tick % boss.getAutoSpawnInterval() == 0) {
Location location = boss.getAutoSpawnLocations().get(NumberUtils.randInt(0, boss.getAutoSpawnLocations().size() - 1));
boss.spawn(location);
}
}
}
}

View File

@@ -1,154 +0,0 @@
package com.willfp.ecobosses.bosses.listeners;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.events.EntityDeathByEntityEvent;
import com.willfp.eco.core.tuples.Pair;
import com.willfp.eco.util.NumberUtils;
import com.willfp.eco.util.StringUtils;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.util.BossUtils;
import com.willfp.ecobosses.bosses.util.obj.DamagerProperty;
import com.willfp.ecobosses.bosses.util.obj.OptionedSound;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class DeathListeners extends PluginDependent implements Listener {
/**
* Create new death listeners.
*
* @param plugin Instance of EcoBosses.
*/
public DeathListeners(@NotNull final EcoPlugin plugin) {
super(plugin);
}
/**
* Called when a boss dies.
*
* @param event The event to listen for.
*/
@EventHandler
public void onBossDeath(@NotNull final EntityDeathByEntityEvent event) {
LivingEntity entity = event.getVictim();
EcoBoss boss = BossUtils.getBoss(entity);
if (boss == null) {
return;
}
for (OptionedSound sound : boss.getDeathSounds()) {
entity.getWorld().playSound(entity.getLocation(), sound.getSound(), sound.getVolume(), sound.getPitch());
}
}
/**
* Handle drops and experience.
*
* @param event The event.
*/
@EventHandler(priority = EventPriority.LOW)
public void onOtherDeath(@NotNull final EntityDeathEvent event) {
LivingEntity entity = event.getEntity();
EcoBoss boss = BossUtils.getBoss(entity);
if (boss == null) {
return;
}
List<DamagerProperty> topDamagers = BossUtils.getTopDamagers(entity);
DamagerProperty top = null;
DamagerProperty second = null;
DamagerProperty third = null;
if (topDamagers.size() >= 1) {
top = topDamagers.get(0);
}
if (topDamagers.size() >= 2) {
second = topDamagers.get(1);
}
if (topDamagers.size() >= 3) {
third = topDamagers.get(2);
}
String na = this.getPlugin().getLangYml().getString("na");
String topDamager = top == null ? na : Bukkit.getPlayer(top.getPlayerUUID()).getDisplayName();
String topDamage = top == null ? na : StringUtils.internalToString(top.getDamage());
String secondDamager = second == null ? na : Bukkit.getPlayer(second.getPlayerUUID()).getDisplayName();
String secondDamage = second == null ? na : StringUtils.internalToString(second.getDamage());
String thirdDamager = third == null ? na : Bukkit.getPlayer(third.getPlayerUUID()).getDisplayName();
String thirdDamage = third == null ? na : StringUtils.internalToString(third.getDamage());
for (String spawnMessage : boss.getDeathMessages()) {
Bukkit.broadcastMessage(spawnMessage
.replace("%top%", topDamager)
.replace("%top_damage%", topDamage)
.replace("%second%", secondDamager)
.replace("%second_damage%", secondDamage)
.replace("%third%", thirdDamager)
.replace("%third_damage%", thirdDamage)
);
}
for (int i = 1; i <= 3; i++) {
List<Pair<Double, String>> topDamagerCommands = boss.getTopDamagerCommands().get(i);
for (Pair<Double, String> pair : topDamagerCommands) {
if (top != null && i == 1) {
if (NumberUtils.randFloat(0, 100) < pair.getFirst()) {
Bukkit.dispatchCommand(Bukkit.getServer().getConsoleSender(), pair.getSecond().replace("%player%", Bukkit.getOfflinePlayer(top.getPlayerUUID()).getName()));
}
}
if (second != null && i == 2) {
if (NumberUtils.randFloat(0, 100) < pair.getFirst()) {
Bukkit.dispatchCommand(Bukkit.getServer().getConsoleSender(), pair.getSecond().replace("%player%", Bukkit.getOfflinePlayer(second.getPlayerUUID()).getName()));
}
}
if (third != null && i == 3) {
if (NumberUtils.randFloat(0, 100) < pair.getFirst()) {
Bukkit.dispatchCommand(Bukkit.getServer().getConsoleSender(), pair.getSecond().replace("%player%", Bukkit.getOfflinePlayer(third.getPlayerUUID()).getName()));
}
}
}
}
List<ItemStack> drops = new ArrayList<>();
for (Map.Entry<ItemStack, Double> entry : boss.getDrops().entrySet()) {
if (NumberUtils.randFloat(0, 100) < entry.getValue()) {
drops.add(entry.getKey().clone());
}
}
for (Entity nearby : entity.getNearbyEntities(boss.getNearbyRadius(), boss.getNearbyRadius(), boss.getNearbyRadius())) {
if (nearby instanceof Player) {
String playerName = nearby.getName();
for (Map.Entry<String, Double> entry : boss.getNearbyPlayersCommands().entrySet()) {
if (NumberUtils.randFloat(0, 100) < entry.getValue()) {
Bukkit.dispatchCommand(Bukkit.getServer().getConsoleSender(), entry.getKey().replace("%player%", playerName));
}
}
}
}
event.getDrops().addAll(drops);
event.setDroppedExp(boss.getExperienceOptions().generateXp());
}
}

View File

@@ -1,52 +0,0 @@
package com.willfp.ecobosses.bosses.listeners;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.util.BossUtils;
import org.bukkit.entity.Boat;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Minecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
import org.spigotmc.event.entity.EntityMountEvent;
public class PassiveListeners extends PluginDependent implements Listener {
/**
* Create new attack listeners.
*
* @param plugin Instance of EcoBosses.
*/
public PassiveListeners(@NotNull final EcoPlugin plugin) {
super(plugin);
}
/**
* Called when a player attacks a boss.
*
* @param event The event to listen for.
*/
@EventHandler(ignoreCancelled = true)
public void onAttackBoss(@NotNull final EntityMountEvent event) {
if (!(event.getEntity() instanceof LivingEntity)) {
return;
}
if (!(event.getMount() instanceof Boat || event.getMount() instanceof Minecart)) {
return;
}
LivingEntity entity = (LivingEntity) event.getEntity();
EcoBoss boss = BossUtils.getBoss(entity);
if (boss == null) {
return;
}
if (boss.isDisableBoats()) {
event.setCancelled(true);
}
}
}

View File

@@ -1,68 +0,0 @@
package com.willfp.ecobosses.bosses.listeners;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.EcoBosses;
import com.willfp.ecobosses.bosses.util.obj.SpawnTotem;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.jetbrains.annotations.NotNull;
public class SpawnListeners extends PluginDependent implements Listener {
/**
* Create new spawn listeners and link them to a plugin.
*
* @param plugin The plugin to link to.
*/
public SpawnListeners(@NotNull final EcoPlugin plugin) {
super(plugin);
}
/**
* Called on block place.
*
* @param event The event to listen for.
*/
@EventHandler
public void spawnTotem(@NotNull final BlockPlaceEvent event) {
for (int i = 0; i < 3; i++) {
Block block1;
Block block2;
Block block3;
if (i == 0) {
block3 = event.getBlock();
block2 = event.getBlock().getRelative(0, -1, 0);
block1 = event.getBlock().getRelative(0, -2, 0);
} else if (i == 1) {
block1 = event.getBlock();
block2 = event.getBlock().getRelative(0, 1, 0);
block3 = event.getBlock().getRelative(0, 2, 0);
} else {
block2 = event.getBlock();
block1 = event.getBlock().getRelative(0, -1, 0);
block3 = event.getBlock().getRelative(0, 1, 0);
}
SpawnTotem placedTotem = new SpawnTotem(block1.getType(), block2.getType(), block3.getType());
for (EcoBoss boss : EcoBosses.values()) {
if (boss.isSpawnTotemEnabled()) {
if (!boss.getSpawnTotemDisabledWorldNames().contains(event.getBlock().getWorld().getName().toLowerCase())) {
if (boss.getSpawnTotem().equals(placedTotem)) {
block1.setType(Material.AIR);
block2.setType(Material.AIR);
block3.setType(Material.AIR);
boss.spawn(event.getBlock().getLocation());
}
}
}
}
}
}
}

View File

@@ -1,31 +0,0 @@
package com.willfp.ecobosses.bosses.tick;
import com.willfp.ecobosses.bosses.EcoBoss;
import org.bukkit.entity.LivingEntity;
import org.jetbrains.annotations.NotNull;
public interface BossTicker {
/**
* Run on boss tick.
*
* @param boss The boss.
* @param entity The boss entity.
* @param tick The current tick: counts up from zero.
*/
void tick(@NotNull EcoBoss boss,
@NotNull LivingEntity entity,
long tick);
/**
* Run on boss death.
*
* @param boss The boss.
* @param entity The boss entity.
* @param tick The current tick: counts up from zero.
*/
default void onDeath(@NotNull EcoBoss boss,
@NotNull LivingEntity entity,
long tick) {
// Can be overridden when needed.
}
}

View File

@@ -1,57 +0,0 @@
package com.willfp.ecobosses.bosses.tick.tickers;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.tick.BossTicker;
import org.bukkit.attribute.Attribute;
import org.bukkit.boss.BossBar;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class BossBarTicker implements BossTicker {
/**
* The boss bar.
*/
private final BossBar bossBar;
/**
* The radius that the boss bar should be visible in.
*/
private final double radius;
/**
* Create new boss bar ticker.
* @param bossBar The boss bar.
* @param radius The radius.
*/
public BossBarTicker(@NotNull final BossBar bossBar,
final double radius) {
this.bossBar = bossBar;
this.radius = radius;
}
@Override
public void tick(@NotNull final EcoBoss boss,
@NotNull final LivingEntity entity,
final long tick) {
bossBar.setTitle(entity.getCustomName());
bossBar.setProgress(entity.getHealth() / entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
if (tick % 40 == 0) {
bossBar.getPlayers().forEach(bossBar::removePlayer);
entity.getNearbyEntities(radius, radius, radius).forEach(entity1 -> {
if (entity1 instanceof Player) {
bossBar.addPlayer((Player) entity1);
}
});
}
}
@Override
public void onDeath(@NotNull final EcoBoss boss,
@NotNull final LivingEntity entity,
final long tick) {
bossBar.getPlayers().forEach(bossBar::removePlayer);
bossBar.setVisible(false);
}
}

View File

@@ -1,16 +0,0 @@
package com.willfp.ecobosses.bosses.tick.tickers;
import com.willfp.eco.util.StringUtils;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.tick.BossTicker;
import org.bukkit.entity.LivingEntity;
import org.jetbrains.annotations.NotNull;
public class HealthPlaceholderTicker implements BossTicker {
@Override
public void tick(@NotNull final EcoBoss boss,
@NotNull final LivingEntity entity,
final long tick) {
entity.setCustomName(boss.getDisplayName().replace("%health%", StringUtils.internalToString(entity.getHealth())));
}
}

View File

@@ -1,58 +0,0 @@
package com.willfp.ecobosses.bosses.tick.tickers;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.tick.BossTicker;
import com.willfp.ecobosses.bosses.util.obj.TargetMode;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Mob;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class TargetTicker implements BossTicker {
/**
* The targeting mode.
*/
private final TargetMode mode;
/**
* The maximum range.
*/
private final double range;
/**
* Create new target ticker.
*
* @param mode The targeting mode.
* @param range The range.
*/
public TargetTicker(@NotNull final TargetMode mode,
final double range) {
this.mode = mode;
this.range = range;
}
@Override
public void tick(@NotNull final EcoBoss boss,
@NotNull final LivingEntity entity,
final long tick) {
Mob mob = (Mob) entity;
if (tick % 10 == 0) {
List<Player> nearbyPlayers = new ArrayList<>();
for (Entity nearbyEntity : entity.getNearbyEntities(range, range, range)) {
if (nearbyEntity instanceof Player) {
nearbyPlayers.add((Player) nearbyEntity);
}
}
if (nearbyPlayers.isEmpty()) {
return;
}
mob.setTarget(mode.getTarget(nearbyPlayers, entity));
}
}
}

View File

@@ -1,71 +0,0 @@
package com.willfp.ecobosses.bosses.util;
import com.willfp.ecobosses.EcoBossesPlugin;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.EcoBosses;
import com.willfp.ecobosses.bosses.util.obj.DamagerProperty;
import lombok.experimental.UtilityClass;
import org.bukkit.entity.LivingEntity;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@UtilityClass
@SuppressWarnings("unchecked")
public class BossUtils {
/**
* Instance of EcoBosses.
*/
private static final EcoBossesPlugin PLUGIN = EcoBossesPlugin.getInstance();
/**
* Get {@link EcoBoss} from an entity.
*
* @param entity The entity.
* @return The boss, or null if not a boss.
*/
@Nullable
public EcoBoss getBoss(@NotNull final LivingEntity entity) {
if (!entity.getPersistentDataContainer().has(PLUGIN.getNamespacedKeyFactory().create("boss"), PersistentDataType.STRING)) {
return null;
}
String bossName = entity.getPersistentDataContainer().get(PLUGIN.getNamespacedKeyFactory().create("boss"), PersistentDataType.STRING);
if (bossName == null) {
return null;
}
return EcoBosses.getByName(bossName);
}
/**
* Get top damagers for a boss.
*
* @param entity The boss entity.
* @return A list of the top damagers, sorted.
*/
public List<DamagerProperty> getTopDamagers(@NotNull final LivingEntity entity) {
if (getBoss(entity) == null) {
return new ArrayList<>();
}
List<DamagerProperty> topDamagers;
if (entity.hasMetadata("ecobosses-top-damagers")) {
topDamagers = (List<DamagerProperty>) entity.getMetadata("ecobosses-top-damagers").get(0).value();
} else {
topDamagers = new ArrayList<>();
}
assert topDamagers != null;
topDamagers.sort(Comparator.comparingDouble(DamagerProperty::getDamage));
Collections.reverse(topDamagers);
return topDamagers;
}
}

View File

@@ -1,33 +0,0 @@
package com.willfp.ecobosses.bosses.util.bosstype;
import com.willfp.ecobosses.proxy.util.CustomEntities;
import com.willfp.ecobosses.proxy.util.CustomEntity;
import lombok.experimental.UtilityClass;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.jetbrains.annotations.NotNull;
@UtilityClass
@SuppressWarnings("unchecked")
public class BossEntityUtils {
/**
* Get boss type.
*
* @param id The name.
* @return The boss type.
*/
public static BossType getBossType(@NotNull final String id) {
try {
Class<? extends LivingEntity> type = (Class<? extends LivingEntity>) EntityType.valueOf(id.toUpperCase()).getEntityClass();
assert type != null;
return new VanillaBossType(type);
} catch (IllegalArgumentException e) {
Class<? extends CustomEntity<? extends LivingEntity>> proxy = CustomEntities.getEntityClass(id.toLowerCase());
if (proxy != null) {
return new CustomBossType(proxy);
}
}
return null;
}
}

View File

@@ -1,15 +0,0 @@
package com.willfp.ecobosses.bosses.util.bosstype;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import org.jetbrains.annotations.NotNull;
public abstract class BossType {
/**
* Spawn boss entity.
*
* @param location The location.
* @return The entity.
*/
public abstract LivingEntity spawnBossEntity(@NotNull Location location);
}

View File

@@ -1,29 +0,0 @@
package com.willfp.ecobosses.bosses.util.bosstype;
import com.willfp.ecobosses.proxy.proxies.CustomEntitySpawnerProxy;
import com.willfp.ecobosses.proxy.util.CustomEntity;
import com.willfp.ecobosses.util.ProxyUtils;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import org.jetbrains.annotations.NotNull;
class CustomBossType extends BossType {
/**
* The entity type.
*/
private final Class<? extends CustomEntity<? extends LivingEntity>> entityClass;
/**
* Create new vanilla boss type.
*
* @param entityClass The entity class.
*/
CustomBossType(@NotNull final Class<? extends CustomEntity<? extends LivingEntity>> entityClass) {
this.entityClass = entityClass;
}
@Override
public LivingEntity spawnBossEntity(@NotNull final Location location) {
return ProxyUtils.getProxy(CustomEntitySpawnerProxy.class).spawnCustomEntity(entityClass, location);
}
}

View File

@@ -1,28 +0,0 @@
package com.willfp.ecobosses.bosses.util.bosstype;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
class VanillaBossType extends BossType {
/**
* The entity type.
*/
private final Class<? extends LivingEntity> entityClass;
/**
* Create new vanilla boss type.
*
* @param entityClass The entity class.
*/
VanillaBossType(@NotNull final Class<? extends LivingEntity> entityClass) {
this.entityClass = entityClass;
}
@Override
public LivingEntity spawnBossEntity(@NotNull final Location location) {
return Objects.requireNonNull(location.getWorld()).spawn(location, entityClass);
}
}

View File

@@ -1,18 +0,0 @@
package com.willfp.ecobosses.bosses.util.obj;
import lombok.Data;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle;
@Data
public class BossbarProperties {
/**
* The BossBar color.
*/
private final BarColor color;
/**
* The BossBar style.
*/
private final BarStyle style;
}

View File

@@ -1,18 +0,0 @@
package com.willfp.ecobosses.bosses.util.obj;
import lombok.Data;
import java.util.UUID;
@Data
public class DamagerProperty {
/**
* The player.
*/
private final UUID playerUUID;
/**
* The damage.
*/
private final double damage;
}

View File

@@ -1,36 +0,0 @@
package com.willfp.ecobosses.bosses.util.obj;
import com.willfp.eco.util.NumberUtils;
public class ExperienceOptions {
/**
* The minimum xp to drop.
*/
private final int minimum;
/**
* The maximum xp to drop.
*/
private final int maximum;
/**
* Create new experience options.
*
* @param minimum Minimum xp.
* @param maximum Maximum xp.
*/
public ExperienceOptions(final int minimum,
final int maximum) {
this.minimum = minimum;
this.maximum = maximum;
}
/**
* Generate an exp amount.
*
* @return The amount.
*/
public int generateXp() {
return NumberUtils.randInt(minimum, maximum);
}
}

View File

@@ -1,31 +0,0 @@
package com.willfp.ecobosses.bosses.util.obj;
import lombok.Data;
@Data
public class ImmunityOptions {
/**
* If is immune to fire.
*/
private final boolean immuneToFire;
/**
* If is immune to suffocation.
*/
private final boolean immuneToSuffocation;
/**
* If is immune to drowning.
*/
private final boolean immuneToDrowning;
/**
* If is immune to projectiles.
*/
private final boolean immuneToProjectiles;
/**
* If is immune to explosions.
*/
private final boolean immuneToExplosions;
}

View File

@@ -1,40 +0,0 @@
package com.willfp.ecobosses.bosses.util.obj;
import lombok.Getter;
import org.bukkit.Sound;
import org.jetbrains.annotations.NotNull;
public class OptionedSound {
/**
* The sound.
*/
@Getter
private final Sound sound;
/**
* The volume.
*/
@Getter
private final float volume;
/**
* The pitch, from 0.5 to 2.
*/
@Getter
private final float pitch;
/**
* Create a new optioned sound.
*
* @param sound The sound.
* @param volume The volume.
* @param pitch The pitch, from 0.5 to 2.
*/
public OptionedSound(@NotNull final Sound sound,
final float volume,
final float pitch) {
this.sound = sound;
this.volume = volume;
this.pitch = pitch;
}
}

View File

@@ -1,22 +0,0 @@
package com.willfp.ecobosses.bosses.util.obj;
import lombok.Data;
import org.bukkit.Material;
@Data
public class SpawnTotem {
/**
* The bottom block.
*/
private final Material bottom;
/**
* The middle block.
*/
private final Material middle;
/**
* The top block.
*/
private final Material top;
}

View File

@@ -1,114 +0,0 @@
package com.willfp.ecobosses.bosses.util.obj;
import com.willfp.eco.util.NumberUtils;
import lombok.Getter;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
public class TargetMode {
/**
* All registered target modes.
*/
private static final Map<String, TargetMode> VALUES = new HashMap<>();
/**
* Random nearby player.
*/
public static final TargetMode RANDOM = new TargetMode("random", (list, entity) -> {
return list.get(NumberUtils.randInt(0, list.size() - 1));
});
/**
* Closest player.
*/
public static final TargetMode CLOSEST = new TargetMode("closest", (list, entity) -> {
Player player = null;
double nearestD2 = 10000;
for (Player nearbyPlayer : list) {
double d2 = nearbyPlayer.getLocation().distanceSquared(entity.getLocation());
if (d2 < nearestD2) {
player = nearbyPlayer;
}
}
return player;
});
/**
* Player with lowest health.
*/
public static final TargetMode LOWEST_HEALTH = new TargetMode("lowest-health", (list, entity) -> {
Player player = null;
double lowest = 100;
for (Player nearbyPlayer : list) {
double health = nearbyPlayer.getHealth();
if (health < lowest) {
player = nearbyPlayer;
}
}
return player;
});
/**
* Player with highest health.
*/
public static final TargetMode HIGHEST_HEALTH = new TargetMode("highest-health", (list, entity) -> {
Player player = null;
double highest = 0;
for (Player nearbyPlayer : list) {
double health = nearbyPlayer.getHealth();
if (health > highest) {
player = nearbyPlayer;
}
}
return player;
});
/**
* The name of the target mode.
*/
@Getter
private final String name;
/**
* The function to find a player out of a list.
*/
private final BiFunction<List<Player>, LivingEntity, Player> function;
protected TargetMode(@NotNull final String name,
@NotNull final BiFunction<List<Player>, LivingEntity, Player> function) {
this.name = name;
this.function = function;
VALUES.put(name, this);
}
/**
* Get target from list of players.
*
* @param list The list.
* @param entity The boss.
* @return The target.
*/
public Player getTarget(@NotNull final List<Player> list,
@NotNull final LivingEntity entity) {
return function.apply(list, entity);
}
/**
* Get target mode by name.
*
* @param name The name.
* @return The target mode, or null if not found.
*/
@Nullable
public static TargetMode getByName(@NotNull final String name) {
return VALUES.get(name);
}
}

View File

@@ -1,42 +0,0 @@
package com.willfp.ecobosses.commands;
import com.willfp.eco.core.command.AbstractCommand;
import com.willfp.ecobosses.EcoBossesPlugin;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
public class CommandEbdrop extends AbstractCommand {
/**
* Instantiate a new executor for /ebdrop.
*
* @param plugin The plugin to manage the execution for.
*/
public CommandEbdrop(@NotNull final EcoBossesPlugin plugin) {
super(plugin, "ebdrop", "ecobosses.ebdrop", true);
}
@Override
public void onExecute(@NotNull final CommandSender sender,
@NotNull final List<String> args) {
Player player = (Player) sender;
ItemStack itemStack = player.getInventory().getItemInMainHand();
String key = "drop-key";
YamlConfiguration jank = new YamlConfiguration();
jank.set(key, itemStack);
String configString = jank.saveToString();
String dropString = Base64.getEncoder().encodeToString(configString.getBytes(StandardCharsets.UTF_8));
Bukkit.getLogger().info("Copy this into the drops section of your boss yml!");
Bukkit.getLogger().info("\n" + dropString);
player.sendMessage(this.getPlugin().getLangYml().getMessage("sent-drop"));
}
}

View File

@@ -1,40 +0,0 @@
package com.willfp.ecobosses.commands;
import com.willfp.eco.core.command.AbstractCommand;
import com.willfp.ecobosses.EcoBossesPlugin;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.EcoBosses;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.LivingEntity;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.UUID;
public class CommandEbkillall extends AbstractCommand {
/**
* Instantiate a new executor for /ebspawn.
*
* @param plugin The plugin to manage the execution for.
*/
public CommandEbkillall(@NotNull final EcoBossesPlugin plugin) {
super(plugin, "ebkillall", "ecobosses.killall", false);
}
@Override
public void onExecute(@NotNull final CommandSender sender,
@NotNull final List<String> args) {
int amount = 0;
for (EcoBoss boss : EcoBosses.values()) {
for (UUID uuid : boss.getLivingBosses().keySet()) {
LivingEntity entity = (LivingEntity) Bukkit.getEntity(uuid);
assert entity != null;
entity.damage(10000000);
amount++;
}
}
sender.sendMessage(this.getPlugin().getLangYml().getMessage("killall").replace("%amount%", String.valueOf(amount)));
}
}

View File

@@ -1,27 +0,0 @@
package com.willfp.ecobosses.commands;
import com.willfp.eco.core.command.AbstractCommand;
import com.willfp.ecobosses.EcoBossesPlugin;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class CommandEbreload extends AbstractCommand {
/**
* Instantiate a new executor for /ebreload.
*
* @param plugin The plugin to manage the execution for.
*/
public CommandEbreload(@NotNull final EcoBossesPlugin plugin) {
super(plugin, "ebreload", "ecobosses.reload", false);
}
@Override
public void onExecute(@NotNull final CommandSender sender,
@NotNull final List<String> args) {
this.getPlugin().reload();
this.getPlugin().reload();
sender.sendMessage(this.getPlugin().getLangYml().getMessage("reloaded"));
}
}

View File

@@ -1,138 +0,0 @@
package com.willfp.ecobosses.commands;
import com.willfp.eco.core.command.AbstractCommand;
import com.willfp.eco.core.command.AbstractTabCompleter;
import com.willfp.ecobosses.EcoBossesPlugin;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.EcoBosses;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class CommandEbspawn extends AbstractCommand {
/**
* Instantiate a new executor for /ebspawn.
*
* @param plugin The plugin to manage the execution for.
*/
public CommandEbspawn(@NotNull final EcoBossesPlugin plugin) {
super(plugin, "ebspawn", "ecobosses.ebspawn", false);
}
@Override
@Nullable
public AbstractTabCompleter getTab() {
return new TabCompleterEbspawn(this);
}
@Override
public void onExecute(@NotNull final CommandSender sender,
@NotNull final List<String> args) {
if (args.isEmpty()) {
sender.sendMessage(this.getPlugin().getLangYml().getMessage("specify-boss"));
return;
}
String bossName = args.get(0);
EcoBoss boss = EcoBosses.getByName(bossName.toLowerCase());
if (boss == null) {
sender.sendMessage(this.getPlugin().getLangYml().getMessage("specify-boss"));
return;
}
Location location = null;
if (sender instanceof Player) {
location = ((Player) sender).getLocation();
}
if (args.size() >= 4) {
String xString = args.get(1);
String yString = args.get(2);
String zString = args.get(3);
double xPos;
double yPos;
double zPos;
if (xString.startsWith("~") && sender instanceof Player) {
String xDiff = xString.replace("~", "");
String yDiff = yString.replace("~", "");
String zDiff = zString.replace("~", "");
if (xDiff.isEmpty()) {
xPos = ((Player) sender).getLocation().getX();
} else {
try {
xPos = ((Player) sender).getLocation().getX() + Double.parseDouble(xDiff);
} catch (NumberFormatException e) {
xPos = ((Player) sender).getLocation().getX();
}
}
if (yDiff.isEmpty()) {
yPos = ((Player) sender).getLocation().getY();
} else {
try {
yPos = ((Player) sender).getLocation().getY() + Double.parseDouble(yDiff);
} catch (NumberFormatException e) {
yPos = ((Player) sender).getLocation().getY();
}
}
if (zDiff.isEmpty()) {
zPos = ((Player) sender).getLocation().getZ();
} else {
try {
zPos = ((Player) sender).getLocation().getZ() + Double.parseDouble(yDiff);
} catch (NumberFormatException e) {
zPos = ((Player) sender).getLocation().getZ();
}
}
} else {
try {
xPos = Double.parseDouble(xString);
yPos = Double.parseDouble(yString);
zPos = Double.parseDouble(zString);
} catch (NumberFormatException e) {
sender.sendMessage(this.getPlugin().getLangYml().getMessage("invalid-location"));
return;
}
}
location = new Location(null, xPos, yPos, zPos);
}
World world = null;
if (sender instanceof Player) {
world = ((Player) sender).getWorld();
}
if (args.size() >= 5) {
world = Bukkit.getWorld(args.get(4));
}
if (location == null) {
sender.sendMessage(this.getPlugin().getLangYml().getMessage("invalid-location"));
return;
}
location.setWorld(world);
if (world == null) {
sender.sendMessage(this.getPlugin().getLangYml().getMessage("invalid-world"));
return;
}
boss.spawn(location);
sender.sendMessage(this.getPlugin().getLangYml().getMessage("spawned"));
}
}

View File

@@ -1,105 +0,0 @@
package com.willfp.ecobosses.commands;
import com.willfp.eco.core.command.AbstractTabCompleter;
import com.willfp.eco.core.config.ConfigUpdater;
import com.willfp.ecobosses.bosses.EcoBoss;
import com.willfp.ecobosses.bosses.EcoBosses;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class TabCompleterEbspawn extends AbstractTabCompleter {
/**
* The cached names.
*/
private static final List<String> BOSS_NAMES = new ArrayList<>();
/**
* The cached numbers.
*/
private static final List<String> TILDE = Arrays.asList(
"~"
);
/**
* Instantiate a new tab-completer for /ebspawn.
*
* @param command Instance of /ebspawn.
*/
public TabCompleterEbspawn(@NotNull final CommandEbspawn command) {
super(command);
reload();
}
/**
* Called on reload.
*/
@ConfigUpdater
public static void reload() {
BOSS_NAMES.clear();
BOSS_NAMES.addAll(EcoBosses.values().stream().map(EcoBoss::getName).collect(Collectors.toList()));
}
/**
* The execution of the tabcompleter.
*
* @param sender The sender of the command.
* @param args The arguments of the command.
* @return A list of tab-completions.
*/
@Override
public List<String> onTab(@NotNull final CommandSender sender,
@NotNull final List<String> args) {
List<String> completions = new ArrayList<>();
if (args.isEmpty()) {
// Currently, this case is not ever reached
return new ArrayList<>();
}
if (args.size() == 1) {
StringUtil.copyPartialMatches(args.get(0), BOSS_NAMES, completions);
Collections.sort(completions);
return completions;
}
if (args.size() == 2) {
StringUtil.copyPartialMatches(args.get(1), TILDE, completions);
Collections.sort(completions);
return completions;
}
if (args.size() == 3) {
StringUtil.copyPartialMatches(args.get(2), TILDE, completions);
Collections.sort(completions);
return completions;
}
if (args.size() == 4) {
StringUtil.copyPartialMatches(args.get(3), TILDE, completions);
Collections.sort(completions);
return completions;
}
if (args.size() == 5) {
StringUtil.copyPartialMatches(args.get(4), Bukkit.getWorlds().stream().map(World::getName).collect(Collectors.toList()), completions);
Collections.sort(completions);
return completions;
}
return new ArrayList<>(0);
}
}

View File

@@ -1,16 +0,0 @@
package com.willfp.ecobosses.config;
import com.willfp.eco.core.config.ExtendableConfig;
import com.willfp.ecobosses.EcoBossesPlugin;
import org.jetbrains.annotations.NotNull;
public class BaseBossConfig extends ExtendableConfig {
/**
* Create new EcoBoss config.
*
* @param configName The name of the config.
*/
public BaseBossConfig(@NotNull final String configName) {
super(configName, true, EcoBossesPlugin.getInstance(), EcoBossesPlugin.class, "bosses/");
}
}

View File

@@ -1,26 +0,0 @@
package com.willfp.ecobosses.config;
import com.willfp.eco.core.config.YamlConfig;
import lombok.Getter;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
public class CustomConfig extends YamlConfig {
/**
* The name of the config.
*/
@Getter
private final String configName;
/**
* Create new custom config.
*
* @param configName The name of the config.
* @param config The config.
*/
public CustomConfig(@NotNull final String configName,
@NotNull final YamlConfiguration config) {
super(config);
this.configName = configName;
}
}

View File

@@ -1,21 +0,0 @@
package com.willfp.ecobosses.util;
import com.willfp.eco.core.proxy.AbstractProxy;
import com.willfp.ecobosses.EcoBossesPlugin;
import com.willfp.ecobosses.proxy.util.ProxyFactory;
import lombok.experimental.UtilityClass;
import org.jetbrains.annotations.NotNull;
@UtilityClass
public class ProxyUtils {
/**
* Get the implementation of a specified proxy.
*
* @param proxyClass The proxy interface.
* @param <T> The type of the proxy.
* @return The proxy implementation.
*/
public @NotNull <T extends AbstractProxy> T getProxy(@NotNull final Class<T> proxyClass) {
return new ProxyFactory<>(EcoBossesPlugin.getInstance(), proxyClass).getProxy();
}
}

View File

@@ -0,0 +1,90 @@
package com.willfp.ecobosses
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.eco.core.display.DisplayModule
import com.willfp.eco.core.integrations.IntegrationLoader
import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.bosses.EggDisplay
import com.willfp.ecobosses.bosses.bossHolders
import com.willfp.ecobosses.commands.CommandEcobosses
import com.willfp.ecobosses.defence.DamageMultiplierHandler
import com.willfp.ecobosses.defence.ImmunitiesHandler
import com.willfp.ecobosses.defence.MountHandler
import com.willfp.ecobosses.defence.PickupHandler
import com.willfp.ecobosses.integrations.levelledmobs.IntegrationLevelledMobs
import com.willfp.ecobosses.lifecycle.CompatibilityListeners
import com.willfp.ecobosses.lifecycle.ConsoleLoggers
import com.willfp.ecobosses.lifecycle.DeathListeners
import com.willfp.ecobosses.lifecycle.LifecycleHandlers
import com.willfp.ecobosses.spawn.AutospawnHandler
import com.willfp.ecobosses.spawn.SpawnEggHandler
import com.willfp.ecobosses.spawn.SpawnTotemHandler
import com.willfp.ecobosses.util.DiscoverRecipeListener
import com.willfp.ecobosses.util.TopDamagerListener
import com.willfp.libreforge.LibReforgePlugin
import org.bukkit.event.Listener
class EcoBossesPlugin : LibReforgePlugin() {
init {
instance = this
registerHolderProvider { it.bossHolders }
}
override fun handleEnableAdditional() {
this.copyConfigs("bosses")
}
override fun handleReloadAdditional() {
Bosses.getAllAlive().forEach { it.remove() }
logger.info(Bosses.values().size.toString() + " Bosses Loaded")
AutospawnHandler.startSpawning(this)
}
override fun handleDisableAdditional() {
Bosses.getAllAlive().forEach { it.remove() }
}
override fun createDisplayModule(): DisplayModule {
return EggDisplay(this)
}
override fun loadPluginCommands(): List<PluginCommand> {
return listOf(
CommandEcobosses(this)
)
}
override fun loadListeners(): List<Listener> {
return listOf(
DiscoverRecipeListener(this),
TopDamagerListener(),
LifecycleHandlers(),
SpawnEggHandler(),
DamageMultiplierHandler(),
MountHandler(),
PickupHandler(),
ImmunitiesHandler(),
CompatibilityListeners(),
SpawnTotemHandler(),
DeathListeners(),
ConsoleLoggers(this)
)
}
override fun loadAdditionalIntegrations(): List<IntegrationLoader> {
return listOf(
IntegrationLoader("LevelledMobs") { this.eventManager.registerListener(IntegrationLevelledMobs()) }
)
}
override fun getMinimumEcoVersion(): String {
return "6.35.1"
}
companion object {
@JvmStatic
lateinit var instance: EcoBossesPlugin
}
}

View File

@@ -0,0 +1,49 @@
package com.willfp.ecobosses.bosses
import com.willfp.eco.core.fast.fast
import com.willfp.ecobosses.EcoBossesPlugin
import com.willfp.libreforge.Holder
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataType
import kotlin.math.pow
val Player.bossHolders: Iterable<Holder>
get() {
val holders = mutableListOf<Holder>()
for (boss in Bosses.values()) {
for (livingBoss in boss.getAllAlive()) {
val entity = livingBoss.entity
if (entity.world != this.world) {
continue
}
if (entity.location.distanceSquared(this.location) <= boss.influence.pow(2)) {
holders.add(boss)
}
}
}
return holders
}
private val spawnEggKey = EcoBossesPlugin.instance.namespacedKeyFactory.create("spawn_egg")
var ItemStack.bossEgg: EcoBoss?
set(value) {
val meta = this.itemMeta ?: return
val pdc = meta.persistentDataContainer
if (value == null) {
pdc.remove(spawnEggKey)
} else {
pdc.set(spawnEggKey, PersistentDataType.STRING, value.id)
}
this.itemMeta = meta
}
get() {
val pdc = this.fast().persistentDataContainer
val id = pdc.get(spawnEggKey, PersistentDataType.STRING) ?: return null
return Bosses.getByID(id)
}

View File

@@ -0,0 +1,126 @@
package com.willfp.ecobosses.bosses
import com.google.common.collect.BiMap
import com.google.common.collect.HashBiMap
import com.google.common.collect.ImmutableList
import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.TransientConfig
import com.willfp.eco.core.config.updating.ConfigUpdater
import com.willfp.ecobosses.EcoBossesPlugin
import org.bukkit.entity.LivingEntity
import java.io.File
import java.util.*
object Bosses {
/**
* Registered bosses.
*/
private val BY_ID: BiMap<String, EcoBoss> = HashBiMap.create()
/**
* Get all registered [EcoBoss]s.
*
* @return A list of all [EcoBoss]s.
*/
@JvmStatic
fun values(): List<EcoBoss> {
return ImmutableList.copyOf(BY_ID.values)
}
/**
* Get [EcoBoss] matching ID.
*
* @param name The name to search for.
* @return The matching [EcoBoss], or null if not found.
*/
@JvmStatic
fun getByID(name: String): EcoBoss? {
return BY_ID[name]
}
/**
* Update all [EcoBoss]s.
*
* @param plugin Instance of EcoBosses.
*/
@ConfigUpdater
@JvmStatic
fun update(plugin: EcoBossesPlugin) {
for (boss in values()) {
removeBoss(boss)
}
for ((id, config) in plugin.fetchConfigs("bosses")) {
addNewBoss(EcoBoss(id, config, plugin))
}
val ecoBossesYml = TransientConfig(File(plugin.dataFolder, "ecobosses.yml"), ConfigType.YAML)
for (bossConfig in ecoBossesYml.getSubsections("bosses")) {
addNewBoss(EcoBoss(bossConfig.getString("id"), bossConfig, plugin))
}
}
/**
* Add new [EcoBoss] to EcoBosses.
*
* @param set The [EcoBoss] to add.
*/
@JvmStatic
fun addNewBoss(set: EcoBoss) {
BY_ID.remove(set.id)
BY_ID[set.id] = set
}
/**
* Remove [EcoBoss] from EcoBosses.
*
* @param set The [EcoBoss] to remove.
*/
@JvmStatic
fun removeBoss(set: EcoBoss) {
BY_ID.remove(set.id)
}
/**
* Get all currently alive [EcoBoss]es.
*
* @return All living bosses.
*/
@JvmStatic
fun getAllAlive(): Set<LivingEcoBoss> {
val entities = mutableSetOf<LivingEcoBoss>()
for (boss in values()) {
entities.addAll(boss.getAllAlive())
}
return entities
}
/**
* Get [LivingEcoBoss].
*
* @return The boss, or null if not a boss.
*/
operator fun get(uuid: UUID): LivingEcoBoss? {
for (boss in values()) {
val found = boss[uuid]
if (found != null) {
return found
}
}
return null
}
/**
* Get [LivingEcoBoss].
*
* @return The boss, or null if not a boss.
*/
operator fun get(entity: LivingEntity): LivingEcoBoss? {
return get(entity.uniqueId)
}
}

View File

@@ -0,0 +1,8 @@
package com.willfp.ecobosses.bosses
import com.willfp.eco.core.entities.ai.Goal
data class ConfiguredGoal<T : Goal<*>>(
val priority: Int,
val goal: T
)

View File

@@ -0,0 +1,458 @@
package com.willfp.ecobosses.bosses
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.entities.CustomEntity
import com.willfp.eco.core.entities.Entities
import com.willfp.eco.core.entities.TestableEntity
import com.willfp.eco.core.entities.ai.EntityController
import com.willfp.eco.core.entities.ai.EntityGoal
import com.willfp.eco.core.entities.ai.EntityGoals
import com.willfp.eco.core.entities.ai.TargetGoal
import com.willfp.eco.core.entities.ai.TargetGoals
import com.willfp.eco.core.items.CustomItem
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.builder.ItemStackBuilder
import com.willfp.eco.core.recipe.Recipes
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import com.willfp.eco.core.recipe.recipes.CraftingRecipe
import com.willfp.eco.util.NamespacedKeyUtils
import com.willfp.eco.util.toComponent
import com.willfp.ecobosses.events.BossKillEvent
import com.willfp.ecobosses.lifecycle.BossLifecycle
import com.willfp.ecobosses.tick.BossBarTicker
import com.willfp.ecobosses.tick.BossTicker
import com.willfp.ecobosses.tick.ChunkTicker
import com.willfp.ecobosses.tick.DisplayNameTicker
import com.willfp.ecobosses.tick.LifespanTicker
import com.willfp.ecobosses.tick.TargetTicker
import com.willfp.ecobosses.tick.TeleportHandler
import com.willfp.ecobosses.util.BossDrop
import com.willfp.ecobosses.util.CommandReward
import com.willfp.ecobosses.util.ConfiguredSound
import com.willfp.ecobosses.util.LocalBroadcast
import com.willfp.ecobosses.util.LocalCommands
import com.willfp.ecobosses.util.PlayableSound
import com.willfp.ecobosses.util.SpawnTotem
import com.willfp.ecobosses.util.XpReward
import com.willfp.ecobosses.util.topDamagers
import com.willfp.libreforge.Holder
import com.willfp.libreforge.conditions.Conditions
import com.willfp.libreforge.effects.Effects
import net.kyori.adventure.bossbar.BossBar
import org.bukkit.Bukkit
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Mob
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataType
import java.util.*
class EcoBoss(
override val id: String,
val config: Config,
private val plugin: EcoPlugin
) : Holder {
val displayName: String = config.getString("displayName")
val lifespan = config.getInt("lifespan")
val influence = config.getDouble("influence")
val targetRange = config.getDouble("target.range")
val targetMode = TargetMode.getByID(config.getString("target.mode"))!!
val isBossBarEnabled = config.getBool("bossBar.enabled")
val bossBarRadius = config.getDouble("bossBar.radius")
val isPreventingMounts = config.getBool("defence.preventMounts")
val isImmuneToExplosions = config.getBool("defence.explosionImmune")
val isImmuneToFire = config.getBool("defence.fireImmune")
val isImmuneToDrowning = config.getBool("defence.drowningImmune")
val isImmuneToSuffocation = config.getBool("defence.suffocationImmune")
val meleeDamageMultiplier = config.getDouble("defence.meleeDamageMultiplier")
val projectileDamageMultiplier = config.getDouble("defence.projectileDamageMultiplier")
val canTeleport = config.getBool("defence.teleportation.enabled")
val teleportRange = config.getInt("defence.teleportation.range")
val teleportInterval = config.getInt("defence.teleportation.interval")
private val spawnEggBacker: ItemStack? = run {
val enabled = config.getBool("spawn.egg.enabled")
if (!enabled) {
return@run null
}
val lookup = Items.lookup(config.getString("spawn.egg.item"))
if (lookup is EmptyTestableItem) {
return@run null
}
val name = config.getFormattedStringOrNull("spawn.egg.name")
val item = ItemStackBuilder(lookup)
.addLoreLines(config.getFormattedStrings("spawn.egg.lore"))
.apply {
if (name != null) {
setDisplayName(name)
}
}
.build().apply { bossEgg = this@EcoBoss }
val key = plugin.namespacedKeyFactory.create("${this.id}_spawn_egg")
Items.registerCustomItem(
key,
CustomItem(
key,
{ it.bossEgg == this },
item
)
)
item
}
val spawnEgg: ItemStack?
get() = this.spawnEggBacker?.clone()
val recipe: CraftingRecipe? = run {
if (spawnEggBacker == null || !config.getBool("spawn.egg.craftable")) {
return@run null
}
val recipe = Recipes.createAndRegisterRecipe(
this@EcoBoss.plugin,
"${this.id}_spawn_egg",
spawnEggBacker,
config.getStrings("spawn.egg.recipe")
)
recipe
}
val totem: SpawnTotem? = run {
if (!config.getBool("spawn.totem.enabled")) {
return@run null
}
SpawnTotem(
Material.getMaterial(config.getString("spawn.totem.top").uppercase()) ?: return@run null,
Material.getMaterial(config.getString("spawn.totem.middle").uppercase()) ?: return@run null,
Material.getMaterial(config.getString("spawn.totem.bottom").uppercase()) ?: return@run null
)
}
val disabledTotemWorlds: List<String> = config.getStrings("spawn.totem.notInWorlds")
val autoSpawnInterval = config.getInt("spawn.autospawn.interval")
val autoSpawnLocations: List<Location> = run {
val locations = mutableListOf<Location>()
for (config in config.getSubsections("spawn.autospawn.locations")) {
val world = Bukkit.getWorld(config.getString("world")) ?: continue
val x = config.getDouble("x")
val y = config.getDouble("y")
val z = config.getDouble("z")
locations.add(
Location(
world, x, y, z
)
)
}
locations
}
val hasCustomAI = config.getBool("customai.enabled")
val targetGoals = config.getSubsections("customai.target-goals").mapNotNull {
val key = NamespacedKeyUtils.fromStringOrNull(it.getString("key")) ?: return@mapNotNull null
val deserializer = TargetGoals.getByKey(key) ?: return@mapNotNull null
val goal = deserializer.deserialize(it.getSubsection("args")) ?: return@mapNotNull null
ConfiguredGoal(it.getInt("priority"), goal)
}
val entityGoals = config.getSubsections("customai.ai-goals").mapNotNull {
val key = NamespacedKeyUtils.fromStringOrNull(it.getString("key")) ?: return@mapNotNull null
val deserializer = EntityGoals.getByKey(key) ?: return@mapNotNull null
val goal = deserializer.deserialize(it.getSubsection("args")) ?: return@mapNotNull null
ConfiguredGoal(it.getInt("priority"), goal)
}
val spawnConditions = config.getSubsections("spawn.conditions").mapNotNull {
Conditions.compile(it, "$id Spawn Conditions")
}
private val bossBarColor = BossBar.Color.valueOf(config.getString("bossBar.color").uppercase())
private val bossBarStyle = BossBar.Overlay.valueOf(config.getString("bossBar.style").uppercase())
private val sounds: Map<BossLifecycle, PlayableSound> = run {
val map = mutableMapOf<BossLifecycle, PlayableSound>()
for (value in BossLifecycle.values()) {
map[value] = PlayableSound(config.getSubsections("sounds.${value.name.lowercase()}").map {
ConfiguredSound.fromConfig(it)
})
}
map
}
private val messages: Map<BossLifecycle, Iterable<LocalBroadcast>> = run {
val map = mutableMapOf<BossLifecycle, Iterable<LocalBroadcast>>()
for (value in BossLifecycle.values()) {
map[value] = config.getSubsections("messages.${value.name.lowercase()}").map {
LocalBroadcast.fromConfig(it)
}
}
map
}
private val commands: Map<BossLifecycle, LocalCommands> = run {
val map = mutableMapOf<BossLifecycle, LocalCommands>()
for (value in BossLifecycle.values()) {
map[value] = LocalCommands(config.getStrings("commands.${value.name.lowercase()}"))
}
map
}
private val commandRewards: Map<Int, Iterable<CommandReward>> = run {
val map = mutableMapOf<Int, Iterable<CommandReward>>()
for (rank in config.getSubsection("rewards.topDamagerCommands").getKeys(false)) {
val rankRewards = mutableListOf<CommandReward>()
for (config in config.getSubsections("rewards.topDamagerCommands.$rank")) {
rankRewards.add(
CommandReward(
config.getDouble("chance"),
config.getStrings("commands")
)
)
}
map[rank.toInt()] = rankRewards
}
map
}
private val nearbyCommandRewardRadius = config.getDouble("rewards.nearbyPlayerCommands.radius")
private val nearbyCommands: Iterable<CommandReward> = run {
val list = mutableListOf<CommandReward>()
for (config in config.getSubsections("rewards.nearbyPlayerCommands.commands")) {
list.add(
CommandReward(
config.getDouble("chance"),
config.getStrings("commands")
)
)
}
list
}
private val xp = XpReward(
config.getInt("rewards.xp.minimum"),
config.getInt("rewards.xp.maximum")
)
private val drops: Iterable<BossDrop> = run {
val list = mutableListOf<BossDrop>()
for (config in config.getSubsections("rewards.drops")) {
list.add(
BossDrop(
config.getDouble("chance"),
config.getStrings("items")
.map { Items.lookup(it) }
.filter { it !is EmptyTestableItem }
.map { it.item }
)
)
}
list
}
private val mob: TestableEntity = Entities.lookup(config.getString("mob"))
private val currentlyAlive = mutableMapOf<UUID, LivingEcoBoss>()
override val conditions = config.getSubsections("conditions").mapNotNull {
Conditions.compile(it, "Boss ID $id")
}.toSet()
override val effects = config.getSubsections("effects").mapNotNull {
Effects.compile(it, "Boss ID $id")
}.toSet()
fun markDead(uuid: UUID) {
currentlyAlive.remove(uuid)
}
operator fun get(uuid: UUID): LivingEcoBoss? {
return currentlyAlive[uuid]
}
operator fun get(entity: LivingEntity): LivingEcoBoss? {
return currentlyAlive[entity.uniqueId]
}
fun getAllAlive(): Set<LivingEcoBoss> {
return currentlyAlive.values.toSet()
}
fun spawn(location: Location): LivingEcoBoss {
val mob = mob.spawn(location) as Mob
mob.isPersistent = true
mob.isCustomNameVisible = true
mob.removeWhenFarAway = false
mob.persistentDataContainer.set(
plugin.namespacedKeyFactory.create("boss"),
PersistentDataType.STRING,
this.id
)
if (hasCustomAI) {
val controller = EntityController.getFor(mob)
.clearAllGoals()
@Suppress("UNCHECKED_CAST") // What could go wrong?
targetGoals.forEach { controller.addTargetGoal(it.priority, it.goal as TargetGoal<in Mob>) }
@Suppress("UNCHECKED_CAST")
entityGoals.forEach { controller.addEntityGoal(it.priority, it.goal as EntityGoal<in Mob>) }
}
val boss = LivingEcoBoss(
plugin,
mob,
this,
createTickers()
)
currentlyAlive[mob.uniqueId] = boss
return boss
}
private fun createTickers(): Set<BossTicker> {
val tickers = mutableSetOf(
LifespanTicker(),
DisplayNameTicker(),
TargetTicker(),
TeleportHandler(),
ChunkTicker()
)
if (isBossBarEnabled) {
tickers.add(
BossBarTicker(
BossBar.bossBar(
this.displayName.toComponent(),
1.0f,
bossBarColor,
bossBarStyle
)
)
)
}
return tickers
}
fun handleLifecycle(lifecycle: BossLifecycle, location: Location, entity: LivingEntity?) {
sounds[lifecycle]?.play(location)
messages[lifecycle]?.forEach { it.broadcast(location, entity?.topDamagers ?: emptyList()) }
commands[lifecycle]?.dispatch(location, entity?.topDamagers ?: emptyList())
}
fun processRewards(event: BossKillEvent) {
val entity = event.boss.entity
val location = entity.location
val player = event.killer
for (drop in drops) {
drop.drop(this, location, player)
}
xp.modify(event.event)
for ((index, damager) in entity.topDamagers.withIndex()) {
val rewards = commandRewards[index + 1] ?: continue
val damagerPlayer = Bukkit.getPlayer(damager.uuid) ?: continue
for (reward in rewards) {
reward.reward(damagerPlayer)
}
}
for (nearbyPlayer in entity.getNearbyEntities(
nearbyCommandRewardRadius,
nearbyCommandRewardRadius,
nearbyCommandRewardRadius
).filterIsInstance<Player>()) {
for (command in nearbyCommands) {
command.reward(nearbyPlayer)
}
}
}
init {
Entities.registerCustomEntity(
plugin.namespacedKeyFactory.create(id),
CustomEntity(
plugin.namespacedKeyFactory.create(id),
{
if (it !is LivingEntity) {
return@CustomEntity false
}
return@CustomEntity Bosses[it]?.boss == this
},
{
this.spawn(it).entity
}
)
)
}
override fun equals(other: Any?): Boolean {
if (other !is EcoBoss) {
return false
}
return id == other.id
}
override fun hashCode(): Int {
return Objects.hash(id)
}
override fun toString(): String {
return ("EcoBoss{"
+ id
+ "}")
}
}

View File

@@ -0,0 +1,41 @@
package com.willfp.ecobosses.bosses
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.display.Display
import com.willfp.eco.core.display.DisplayModule
import com.willfp.eco.core.display.DisplayPriority
import com.willfp.eco.core.fast.fast
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
class EggDisplay(
plugin: EcoPlugin
) : DisplayModule(
plugin,
DisplayPriority.LOW
) {
override fun display(itemStack: ItemStack, player: Player?, vararg args: Any) {
if (player == null) {
return
}
val fis = itemStack.fast()
val lore = fis.lore.toMutableList()
val egg = itemStack.bossEgg ?: return
val lines = egg.spawnConditions
.filterNot { it.isMet(player) }
.mapNotNull { it.notMetLines?.map { line -> Display.PREFIX + line } }
.flatten()
if (lines.isNotEmpty()) {
lore.add(Display.PREFIX)
lore.addAll(lines)
}
fis.lore = lore
}
}

View File

@@ -0,0 +1,53 @@
package com.willfp.ecobosses.bosses
import com.willfp.eco.core.EcoPlugin
import com.willfp.ecobosses.tick.BossTicker
import org.bukkit.Chunk
import org.bukkit.entity.Mob
class LivingEcoBoss(
plugin: EcoPlugin,
val entity: Mob,
val boss: EcoBoss,
private val tickers: Set<BossTicker>
) {
private val ticker = plugin.runnableFactory.create {
if (tick()) {
it.cancel()
}
}.apply { runTaskTimer(1, 1) }
val chunk: Chunk
get() = entity.location.chunk
val forceLoadedChunks = mutableListOf<Chunk>()
val deathTime = System.currentTimeMillis() + (boss.lifespan * 1000)
private var currentTick = 1 // Start at 1 as 0 is divisible by everything
private fun tick(): Boolean {
if (entity.isDead) {
remove()
return true
}
for (ticker in tickers) {
ticker.tick(this, currentTick)
}
currentTick++
return false
}
fun remove() {
ticker.cancel()
entity.remove()
tickers.forEach { it.onDeath(this, currentTick) }
boss.markDead(entity.uniqueId)
}
override fun toString(): String {
return "LivingEcoBoss{boss=${boss}, uuid=${entity.uniqueId}}"
}
}

View File

@@ -0,0 +1,63 @@
package com.willfp.ecobosses.bosses
import com.google.common.collect.BiMap
import com.google.common.collect.HashBiMap
import com.google.common.collect.ImmutableList
import org.bukkit.GameMode
import org.bukkit.entity.Entity
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Player
class TargetMode(
val id: String,
private val function: (Collection<LivingEntity>, Entity) -> LivingEntity?
) {
init {
BY_ID[this.id] = this
}
fun getTarget(boss: LivingEcoBoss): LivingEntity? {
val entity = boss.entity
return function(
entity.getNearbyEntities(
boss.boss.targetRange,
boss.boss.targetRange,
boss.boss.targetRange
).filterIsInstance<Player>()
.filter { listOf(GameMode.SURVIVAL, GameMode.ADVENTURE).contains(it.gameMode) }
.ifEmpty { return null },
entity
)
}
companion object {
private val BY_ID: BiMap<String, TargetMode> = HashBiMap.create()
val RANDOM = TargetMode("random") { entities, _ ->
entities.random()
}
val CLOSEST = TargetMode("closest") { entities, boss ->
entities.minByOrNull { it.location.distanceSquared(boss.location) }
}
val LOWEST_HEALTH = TargetMode("lowest_health") { entities, _ ->
entities.minByOrNull { it.health }
}
val HIGHEST_HEALTH = TargetMode("highest_health") { entities, _ ->
entities.maxByOrNull { it.health }
}
@JvmStatic
fun values(): List<TargetMode> {
return ImmutableList.copyOf(BY_ID.values)
}
@JvmStatic
fun getByID(id: String): TargetMode? {
return BY_ID[id]
}
}
}

View File

@@ -0,0 +1,26 @@
package com.willfp.ecobosses.commands
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.ecobosses.EcoBossesPlugin
import org.bukkit.command.CommandSender
class CommandEcobosses(plugin: EcoBossesPlugin) : PluginCommand(
plugin,
"ecobosses",
"ecobosses.command.ecobosses",
false
) {
override fun onExecute(
sender: CommandSender,
args: List<String>
) {
sender.sendMessage(plugin.langYml.getMessage("invalid-command"))
}
init {
addSubcommand(CommandReload(plugin))
.addSubcommand(CommandKillall(plugin))
.addSubcommand(CommandSpawn(plugin))
.addSubcommand(CommandGive(plugin))
}
}

View File

@@ -0,0 +1,114 @@
package com.willfp.ecobosses.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.ecobosses.bosses.Bosses
import org.bukkit.Bukkit
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
import java.util.stream.Collectors
class CommandGive(plugin: EcoPlugin) : Subcommand(
plugin,
"give",
"ecobosses.command.give",
false
) {
override fun onExecute(
sender: CommandSender,
args: List<String>
) {
if (args.isEmpty()) {
sender.sendMessage(plugin.langYml.getMessage("needs-player"))
return
}
if (args.size == 1) {
sender.sendMessage(plugin.langYml.getMessage("needs-boss"))
return
}
var amount = 1
if (args.size > 2) {
amount = args[2].toIntOrNull() ?: amount
}
val recieverName = args[0]
val reciever = Bukkit.getPlayer(recieverName)
if (reciever == null) {
sender.sendMessage(plugin.langYml.getMessage("invalid-player"))
return
}
val key = args[1]
val boss = Bosses.getByID(key)
if (boss?.spawnEgg == null) {
sender.sendMessage(plugin.langYml.getMessage("invalid-boss"))
return
}
var message = plugin.langYml.getMessage("give-success")
message = message.replace("%boss%", boss.id).replace("%recipient%", reciever.name)
sender.sendMessage(message)
val itemStack = boss.spawnEgg!!
itemStack.amount = amount
reciever.inventory.addItem(itemStack)
}
override fun tabComplete(
sender: CommandSender,
args: List<String>
): List<String> {
val completions = mutableListOf<String>()
if (args.isEmpty()) {
return BOSS_NAMES
}
if (args.size == 1) {
StringUtil.copyPartialMatches(args[0], Bukkit.getOnlinePlayers().stream().map { obj: Player -> obj.name }
.collect(Collectors.toList()), completions)
return completions
}
if (args.size == 2) {
StringUtil.copyPartialMatches(args[1], BOSS_NAMES, completions)
completions.sort()
return completions
}
if (args.size == 3) {
StringUtil.copyPartialMatches(args[2], NUMBERS, completions)
completions.sortWith { s1: String, s2: String ->
val t1 = s1.toInt()
val t2 = s2.toInt()
t1 - t2
}
return completions
}
return ArrayList(0)
}
companion object {
/**
* The cached names.
*/
private val BOSS_NAMES: List<String>
get() = Bosses.values().map { it.id }
/**
* The cached numbers.
*/
private val NUMBERS = listOf(
"1",
"2",
"3",
"4",
"5",
"10",
"32",
"64"
)
}
}

View File

@@ -0,0 +1,28 @@
package com.willfp.ecobosses.commands
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.ecobosses.EcoBossesPlugin
import com.willfp.ecobosses.bosses.Bosses
import org.bukkit.command.CommandSender
class CommandKillall(plugin: EcoBossesPlugin) : Subcommand(
plugin,
"killall",
"ecobosses.command.killall",
false
) {
override fun onExecute(
sender: CommandSender,
args: List<String>
) {
val alive = Bosses.getAllAlive()
for (boss in alive) {
boss.remove()
}
sender.sendMessage(
plugin.langYml.getMessage("killall").replace("%amount%", alive.size.toString())
)
}
}

View File

@@ -0,0 +1,20 @@
package com.willfp.ecobosses.commands
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.ecobosses.EcoBossesPlugin
import org.bukkit.command.CommandSender
class CommandReload(plugin: EcoBossesPlugin) : Subcommand(
plugin,
"reload",
"ecobosses.command.reload",
false
) {
override fun onExecute(
sender: CommandSender,
args: List<String>
) {
plugin.reload()
sender.sendMessage(plugin.langYml.getMessage("reloaded"))
}
}

View File

@@ -0,0 +1,178 @@
package com.willfp.ecobosses.commands
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.ecobosses.EcoBossesPlugin
import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.events.BossSpawnEvent
import org.bukkit.Bukkit
import org.bukkit.Location
import org.bukkit.World
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
class CommandSpawn(plugin: EcoBossesPlugin) : Subcommand(
plugin,
"spawn",
"ecobosses.command.spawn",
false
) {
override fun onExecute(
sender: CommandSender,
args: List<String>
) {
if (args.isEmpty()) {
sender.sendMessage(plugin.langYml.getMessage("specify-boss"))
return
}
val bossName = args[0]
val boss = Bosses.getByID(bossName.lowercase())
if (boss == null) {
sender.sendMessage(plugin.langYml.getMessage("specify-boss"))
return
}
var location: Location? = null
if (sender is Player) {
location = sender.location
}
if (args.size >= 4) {
val xString = args[1]
val yString = args[2]
val zString = args[3]
val xPos: Double
val yPos: Double
val zPos: Double
if (xString.startsWith("~") && sender is Player) {
val xDiff = xString.replace("~", "")
val yDiff = yString.replace("~", "")
val zDiff = zString.replace("~", "")
xPos = if (xDiff.isEmpty()) {
sender.location.x
} else {
try {
sender.location.x + xDiff.toDouble()
} catch (e: NumberFormatException) {
sender.location.x
}
}
yPos = if (yDiff.isEmpty()) {
sender.location.y
} else {
try {
sender.location.y + yDiff.toDouble()
} catch (e: NumberFormatException) {
sender.location.y
}
}
zPos = if (zDiff.isEmpty()) {
sender.location.z
} else {
try {
sender.location.z + yDiff.toDouble()
} catch (e: NumberFormatException) {
sender.location.z
}
}
} else {
try {
xPos = xString.toDouble()
yPos = yString.toDouble()
zPos = zString.toDouble()
} catch (e: NumberFormatException) {
sender.sendMessage(plugin.langYml.getMessage("invalid-location"))
return
}
}
location = Location(null, xPos, yPos, zPos)
}
var world: World? = null
if (sender is Player) {
world = sender.world
}
if (args.size >= 5) {
world = Bukkit.getWorld(args[4])
}
if (location == null) {
sender.sendMessage(plugin.langYml.getMessage("invalid-location"))
return
}
location.world = world
if (world == null) {
sender.sendMessage(plugin.langYml.getMessage("invalid-world"))
return
}
val event = BossSpawnEvent(
boss,
location,
BossSpawnEvent.SpawnReason.COMMAND,
null
)
Bukkit.getPluginManager().callEvent(event)
if (!event.isCancelled) {
boss.spawn(location)
}
sender.sendMessage(plugin.langYml.getMessage("spawned"))
}
override fun tabComplete(
sender: CommandSender,
args: List<String>
): List<String> {
val completions = mutableListOf<String>()
if (args.isEmpty()) {
return emptyList()
}
if (args.size == 1) {
StringUtil.copyPartialMatches(args[0], BOSS_NAMES, completions)
completions.sort()
return completions
}
if (args.size == 2) {
StringUtil.copyPartialMatches(args[1], TILDE, completions)
completions.sort()
return completions
}
if (args.size == 3) {
StringUtil.copyPartialMatches(args[2], TILDE, completions)
completions.sort()
return completions
}
if (args.size == 4) {
StringUtil.copyPartialMatches(args[3], TILDE, completions)
completions.sort()
return completions
}
if (args.size == 5) {
StringUtil.copyPartialMatches(args[4], Bukkit.getWorlds().map { it.name }, completions)
completions.sort()
return completions
}
return ArrayList(0)
}
companion object {
/**
* The cached names.
*/
private val BOSS_NAMES: List<String>
get() = Bosses.values().map { it.id }
/**
* The cached numbers.
*/
private val TILDE = listOf(
"~"
)
}
}

View File

@@ -0,0 +1,35 @@
package com.willfp.ecobosses.defence
import com.willfp.ecobosses.bosses.Bosses
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Player
import org.bukkit.entity.Projectile
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDamageByEntityEvent
class DamageMultiplierHandler : Listener {
@EventHandler(
ignoreCancelled = true
)
fun handle(event: EntityDamageByEntityEvent) {
val entity = event.entity as? LivingEntity ?: return
val boss = Bosses[entity]?.boss ?: return
if (event.damager is Player) {
event.damage *= boss.meleeDamageMultiplier
if (boss.meleeDamageMultiplier == 0.0) {
event.isCancelled = true
}
}
if (event.damager is Projectile) {
event.damage *= boss.projectileDamageMultiplier
if (boss.projectileDamageMultiplier == 0.0) {
event.isCancelled = true
}
}
}
}

View File

@@ -0,0 +1,46 @@
package com.willfp.ecobosses.defence
import com.willfp.ecobosses.bosses.Bosses
import org.bukkit.entity.LivingEntity
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDamageEvent
class ImmunitiesHandler : Listener {
@EventHandler(
ignoreCancelled = true
)
fun handle(event: EntityDamageEvent) {
val entity = event.entity as? LivingEntity ?: return
val boss = Bosses[entity]?.boss ?: return
when (event.cause) {
EntityDamageEvent.DamageCause.SUFFOCATION -> {
if (boss.isImmuneToSuffocation) {
event.isCancelled = true
}
}
EntityDamageEvent.DamageCause.ENTITY_EXPLOSION, EntityDamageEvent.DamageCause.BLOCK_EXPLOSION -> {
if (boss.isImmuneToExplosions) {
event.isCancelled = true
}
}
EntityDamageEvent.DamageCause.HOT_FLOOR, EntityDamageEvent.DamageCause.FIRE,
EntityDamageEvent.DamageCause.FIRE_TICK, EntityDamageEvent.DamageCause.LAVA -> {
if (boss.isImmuneToFire) {
event.isCancelled = true
}
}
EntityDamageEvent.DamageCause.DROWNING -> {
if (boss.isImmuneToDrowning) {
event.isCancelled = true
}
}
else -> {}
}
}
}

View File

@@ -0,0 +1,21 @@
package com.willfp.ecobosses.defence
import com.willfp.ecobosses.bosses.Bosses
import org.bukkit.entity.LivingEntity
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.spigotmc.event.entity.EntityMountEvent
class MountHandler : Listener {
@EventHandler(
ignoreCancelled = true
)
fun handle(event: EntityMountEvent) {
val entity = event.entity as? LivingEntity ?: return
val boss = Bosses[entity]?.boss ?: return
if (boss.isPreventingMounts) {
event.isCancelled = true
}
}
}

View File

@@ -0,0 +1,19 @@
package com.willfp.ecobosses.defence
import com.willfp.ecobosses.bosses.Bosses
import org.bukkit.entity.LivingEntity
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityPickupItemEvent
class PickupHandler : Listener {
@EventHandler(
ignoreCancelled = true
)
fun handle(event: EntityPickupItemEvent) {
val entity = event.entity as? LivingEntity ?: return
Bosses[entity]?.boss ?: return
event.isCancelled = true
}
}

View File

@@ -0,0 +1,24 @@
package com.willfp.ecobosses.events
import com.willfp.ecobosses.bosses.LivingEcoBoss
import com.willfp.ecobosses.lifecycle.BossLifecycle
import org.bukkit.event.Event
import org.bukkit.event.HandlerList
import org.bukkit.event.entity.EntityDeathEvent
abstract class BossDeathEvent(
val boss: LivingEcoBoss
) : Event() {
override fun getHandlers(): HandlerList {
return HANDLERS
}
companion object {
private val HANDLERS = HandlerList()
@JvmStatic
fun getHandlerList(): HandlerList {
return HANDLERS
}
}
}

View File

@@ -0,0 +1,22 @@
package com.willfp.ecobosses.events
import com.willfp.ecobosses.bosses.LivingEcoBoss
import com.willfp.ecobosses.lifecycle.BossLifecycle
import org.bukkit.event.HandlerList
class BossDespawnEvent(
boss: LivingEcoBoss,
) : BossDeathEvent(boss) {
override fun getHandlers(): HandlerList {
return HANDLERS
}
companion object {
private val HANDLERS = HandlerList()
@JvmStatic
fun getHandlerList(): HandlerList {
return HANDLERS
}
}
}

View File

@@ -0,0 +1,26 @@
package com.willfp.ecobosses.events
import com.willfp.ecobosses.bosses.LivingEcoBoss
import com.willfp.ecobosses.lifecycle.BossLifecycle
import org.bukkit.entity.Player
import org.bukkit.event.HandlerList
import org.bukkit.event.entity.EntityDeathEvent
class BossKillEvent(
boss: LivingEcoBoss,
val killer: Player?,
val event: EntityDeathEvent
) : BossDeathEvent(boss) {
override fun getHandlers(): HandlerList {
return HANDLERS
}
companion object {
private val HANDLERS = HandlerList()
@JvmStatic
fun getHandlerList(): HandlerList {
return HANDLERS
}
}
}

View File

@@ -0,0 +1,46 @@
package com.willfp.ecobosses.events
import com.willfp.ecobosses.bosses.EcoBoss
import org.bukkit.Location
import org.bukkit.entity.Player
import org.bukkit.event.Cancellable
import org.bukkit.event.Event
import org.bukkit.event.HandlerList
class BossSpawnEvent(
val boss: EcoBoss,
val location: Location,
val reason: SpawnReason,
val spawner: Player?
) : Event(), Cancellable {
private var isCancelled: Boolean = false
override fun isCancelled(): Boolean {
return isCancelled
}
override fun setCancelled(cancelled: Boolean) {
isCancelled = cancelled
}
override fun getHandlers(): HandlerList {
return HANDLERS
}
enum class SpawnReason {
TOTEM,
EGG,
COMMAND,
AUTOSPAWN,
UNKNOWN
}
companion object {
private val HANDLERS = HandlerList()
@JvmStatic
fun getHandlerList(): HandlerList {
return HANDLERS
}
}
}

View File

@@ -0,0 +1,30 @@
package com.willfp.ecobosses.events
import com.willfp.ecobosses.bosses.EcoBoss
import com.willfp.ecobosses.bosses.LivingEcoBoss
import org.bukkit.Location
import org.bukkit.entity.Player
import org.bukkit.event.Event
import org.bukkit.event.HandlerList
import org.bukkit.inventory.ItemStack
class BossTryDropItemEvent(
val boss: EcoBoss,
val location: Location,
var items: MutableCollection<ItemStack>,
var chance: Double,
val player: Player?
): Event() {
override fun getHandlers(): HandlerList {
return HANDLERS
}
companion object {
private val HANDLERS = HandlerList()
@JvmStatic
fun getHandlerList(): HandlerList {
return HANDLERS
}
}
}

View File

@@ -0,0 +1,20 @@
package com.willfp.ecobosses.integrations.levelledmobs
import com.willfp.eco.core.integrations.Integration
import com.willfp.ecobosses.bosses.Bosses
import me.lokka30.levelledmobs.events.MobPreLevelEvent
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
class IntegrationLevelledMobs : Listener, Integration {
@EventHandler
fun handle(event: MobPreLevelEvent) {
if (Bosses[event.entity] != null) {
event.isCancelled = true
}
}
override fun getPluginName(): String {
return "LevelledMobs"
}
}

View File

@@ -0,0 +1,10 @@
package com.willfp.ecobosses.lifecycle
enum class BossLifecycle(
val isDeath: Boolean
) {
SPAWN(false),
KILL(true),
DESPAWN(true),
INJURE(false)
}

View File

@@ -0,0 +1,16 @@
package com.willfp.ecobosses.lifecycle
import com.willfp.ecobosses.bosses.Bosses
import org.bukkit.entity.LivingEntity
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.entity.SlimeSplitEvent
class CompatibilityListeners : Listener {
@EventHandler
fun handle(event: SlimeSplitEvent) {
if (Bosses[event.entity as? LivingEntity ?: return] != null) {
event.isCancelled = true
}
}
}

View File

@@ -0,0 +1,56 @@
package com.willfp.ecobosses.lifecycle
import com.willfp.ecobosses.events.BossDespawnEvent
import com.willfp.ecobosses.events.BossKillEvent
import com.willfp.ecobosses.events.BossSpawnEvent
import com.willfp.libreforge.LibReforgePlugin
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
class ConsoleLoggers(
private val plugin: LibReforgePlugin
) : Listener {
@EventHandler(
ignoreCancelled = true,
priority = EventPriority.MONITOR
)
fun handle(event: BossSpawnEvent) {
if (!plugin.configYml.getBool("log-spawn-kill")) {
return
}
val location = "${event.location.world?.name}: ${event.location.x}, ${event.location.y}, ${event.location.z}"
plugin.logger.info("&a${event.boss.id}&r was spawned by &a${event.spawner?.name}&r at &a$location")
}
@EventHandler(
ignoreCancelled = true,
priority = EventPriority.MONITOR
)
fun handle(event: BossKillEvent) {
if (!plugin.configYml.getBool("log-spawn-kill")) {
return
}
val loc = event.boss.entity.location
val location = "${loc.world?.name}: ${loc.x}, ${loc.y}, ${loc.z}"
plugin.logger.info("&a${event.boss.boss.id}&r was killed by &a${event.killer?.name}&r at &a$location")
}
@EventHandler(
ignoreCancelled = true,
priority = EventPriority.MONITOR
)
fun handle(event: BossDespawnEvent) {
if (!plugin.configYml.getBool("log-spawn-kill")) {
return
}
val loc = event.boss.entity.location
val location = "${loc.world?.name}: ${loc.x}, ${loc.y}, ${loc.z}"
plugin.logger.info("&a${event.boss.boss.id}&r despawned at &a$location")
}
}

View File

@@ -0,0 +1,49 @@
package com.willfp.ecobosses.lifecycle
import com.willfp.eco.core.events.EntityDeathByEntityEvent
import com.willfp.eco.util.tryAsPlayer
import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.events.BossKillEvent
import org.bukkit.Bukkit
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDeathEvent
class DeathListeners : Listener {
@EventHandler(
ignoreCancelled = true
)
fun handle(event: EntityDeathByEntityEvent) {
val boss = Bosses[event.victim] ?: return
val deathEvent = BossKillEvent(boss, event.killer.tryAsPlayer(), event.deathEvent)
Bukkit.getPluginManager().callEvent(deathEvent)
boss.remove()
event.drops.clear()
}
@EventHandler(
ignoreCancelled = true,
priority = EventPriority.HIGHEST
)
fun handle(event: EntityDeathEvent) {
val boss = Bosses[event.entity] ?: return
val deathEvent = BossKillEvent(boss, null, event)
Bukkit.getPluginManager().callEvent(deathEvent)
boss.remove()
event.drops.clear()
}
@EventHandler(
ignoreCancelled = true
)
fun handle(event: BossKillEvent) {
event.boss.boss.processRewards(event)
}
}

View File

@@ -0,0 +1,53 @@
package com.willfp.ecobosses.lifecycle
import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.events.BossDeathEvent
import com.willfp.ecobosses.events.BossDespawnEvent
import com.willfp.ecobosses.events.BossKillEvent
import com.willfp.ecobosses.events.BossSpawnEvent
import org.bukkit.entity.LivingEntity
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDamageEvent
class LifecycleHandlers : Listener {
@EventHandler(
ignoreCancelled = true,
priority = EventPriority.MONITOR
)
fun handle(event: EntityDamageEvent) {
val entity = event.entity as? LivingEntity ?: return
val boss = Bosses[entity] ?: return
boss.boss.handleLifecycle(BossLifecycle.INJURE, entity.location, entity)
}
@EventHandler(
ignoreCancelled = true,
priority = EventPriority.MONITOR
)
fun handle(event: BossKillEvent) {
val entity = event.boss.entity
event.boss.boss.handleLifecycle(BossLifecycle.KILL, entity.location, entity)
}
@EventHandler(
ignoreCancelled = true,
priority = EventPriority.MONITOR
)
fun handle(event: BossDespawnEvent) {
val entity = event.boss.entity
event.boss.boss.handleLifecycle(BossLifecycle.DESPAWN, entity.location, entity)
}
@EventHandler(
ignoreCancelled = true,
priority = EventPriority.MONITOR
)
fun handle(event: BossSpawnEvent) {
event.boss.handleLifecycle(BossLifecycle.SPAWN, event.location, null)
}
}

View File

@@ -0,0 +1,43 @@
package com.willfp.ecobosses.spawn
import com.willfp.eco.core.EcoPlugin
import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.events.BossSpawnEvent
import org.bukkit.Bukkit
object AutospawnHandler {
private var tick = 1
fun startSpawning(plugin: EcoPlugin) {
plugin.scheduler.runTimer(1, 1) {
for (boss in Bosses.values()) {
if (boss.autoSpawnInterval < 0) {
continue
}
if (tick % boss.autoSpawnInterval != 0) {
continue
}
val location = boss.autoSpawnLocations.randomOrNull() ?: continue
val world = location.world ?: continue
if (plugin.configYml.getBool("autospawn.one-boss-per-world")) {
if (Bosses.getAllAlive().mapNotNull { it.entity }.any { it.world == world }) {
continue
}
}
val spawnEvent = BossSpawnEvent(boss, location, BossSpawnEvent.SpawnReason.AUTOSPAWN, null)
Bukkit.getPluginManager().callEvent(spawnEvent)
if (!spawnEvent.isCancelled) {
boss.spawn(location)
}
}
tick++
}
}
}

View File

@@ -0,0 +1,54 @@
package com.willfp.ecobosses.spawn
import com.willfp.ecobosses.bosses.bossEgg
import com.willfp.ecobosses.events.BossSpawnEvent
import org.bukkit.Bukkit
import org.bukkit.event.Event
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.block.Action
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.EquipmentSlot
class SpawnEggHandler : Listener {
@EventHandler(
ignoreCancelled = true
)
fun handle(event: PlayerInteractEvent) {
if (event.action != Action.RIGHT_CLICK_BLOCK) {
return
}
val item = event.item ?: return
val boss = item.bossEgg ?: return
event.isCancelled = true
event.setUseItemInHand(Event.Result.DENY)
val location = event.clickedBlock?.location?.add(0.0, 1.5, 0.0) ?: return
val player = event.player
if (!boss.spawnConditions.all { it.condition.isConditionMet(player, it.config) }) {
return
}
val spawnEvent = BossSpawnEvent(boss, location, BossSpawnEvent.SpawnReason.EGG, player)
Bukkit.getPluginManager().callEvent(spawnEvent)
if (spawnEvent.isCancelled) {
return
}
if (event.hand == EquipmentSlot.HAND) {
val hand = event.player.inventory.itemInMainHand
hand.amount = hand.amount - 1
} else {
val hand = event.player.inventory.itemInOffHand
hand.amount = hand.amount - 1
}
boss.spawn(location)
}
}

View File

@@ -0,0 +1,73 @@
package com.willfp.ecobosses.spawn
import com.willfp.eco.util.containsIgnoreCase
import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.events.BossSpawnEvent
import com.willfp.ecobosses.util.SpawnTotem
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.block.Block
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.block.BlockPlaceEvent
class SpawnTotemHandler : Listener {
@EventHandler(
ignoreCancelled = true
)
fun handle(event: BlockPlaceEvent) {
for (i in 0..2) {
lateinit var top: Block
lateinit var middle: Block
lateinit var bottom: Block
// I know this code sucks ass, but I can't be arsed to write it nicely
when (i) {
0 -> {
top = event.block
middle = event.block.getRelative(0, -1, 0)
bottom = event.block.getRelative(0, -2, 0)
}
1 -> {
top = event.block.getRelative(0, 2, 0)
middle = event.block.getRelative(0, 1, 0)
bottom = event.block
}
2 -> {
top = event.block.getRelative(0, 1, 0)
middle = event.block
bottom = event.block.getRelative(0, -1, 0)
}
}
val placedTotem = SpawnTotem(top.type, middle.type, bottom.type)
for (boss in Bosses.values()) {
if (boss.totem == null || boss.disabledTotemWorlds.containsIgnoreCase(event.block.world.name)) {
continue
}
if (!boss.totem.matches(placedTotem)) {
continue
}
val player = event.player
if (!boss.spawnConditions.all { it.condition.isConditionMet(player, it.config) }) {
return
}
val spawnEvent = BossSpawnEvent(boss, event.block.location, BossSpawnEvent.SpawnReason.TOTEM, player)
Bukkit.getPluginManager().callEvent(spawnEvent)
if (!spawnEvent.isCancelled) {
top.type = Material.AIR
middle.type = Material.AIR
bottom.type = Material.AIR
boss.spawn(event.block.location.add(0.0, 1.5, 0.0))
}
}
}
}
}

View File

@@ -0,0 +1,45 @@
package com.willfp.ecobosses.tick
import com.willfp.eco.util.asAudience
import com.willfp.eco.util.toComponent
import com.willfp.ecobosses.bosses.LivingEcoBoss
import net.kyori.adventure.bossbar.BossBar
import org.bukkit.Bukkit
import org.bukkit.attribute.Attribute
import org.bukkit.entity.Player
class BossBarTicker(
private val bar: BossBar
) : BossTicker {
override fun tick(boss: LivingEcoBoss, tick: Int) {
val entity = boss.entity
bar.name(entity.customName!!.toComponent())
bar.progress((entity.health / entity.getAttribute(Attribute.GENERIC_MAX_HEALTH)!!.value).toFloat())
if (tick % 40 == 0) {
for (player in Bukkit.getOnlinePlayers()) {
player.asAudience().hideBossBar(bar)
}
entity.getNearbyEntities(
boss.boss.bossBarRadius,
boss.boss.bossBarRadius,
boss.boss.bossBarRadius
).filterIsInstance<Player>()
.map { it.asAudience() }
.forEach { it.showBossBar(bar) }
}
if (tick % 10 != 0) {
return
}
entity.target = boss.boss.targetMode.getTarget(boss) ?: return
}
override fun onDeath(boss: LivingEcoBoss, tick: Int) {
for (player in Bukkit.getOnlinePlayers()) {
player.asAudience().hideBossBar(bar)
}
}
}

View File

@@ -0,0 +1,19 @@
package com.willfp.ecobosses.tick
import com.willfp.ecobosses.bosses.LivingEcoBoss
interface BossTicker {
fun tick(
boss: LivingEcoBoss,
tick: Int
) {
// Can be overridden when needed.
}
fun onDeath(
boss: LivingEcoBoss,
tick: Int
) {
// Can be overridden when needed.
}
}

View File

@@ -0,0 +1,26 @@
package com.willfp.ecobosses.tick
import com.willfp.ecobosses.bosses.LivingEcoBoss
class ChunkTicker : BossTicker {
override fun tick(boss: LivingEcoBoss, tick: Int) {
val currentChunk = boss.chunk
if (tick % 10 != 0) {
return
}
if (currentChunk.isLoaded && currentChunk.isForceLoaded) {
return;
}
currentChunk.load()
currentChunk.isForceLoaded = true
boss.forceLoadedChunks.add(currentChunk)
}
override fun onDeath(boss: LivingEcoBoss, tick: Int) {
boss.forceLoadedChunks.forEach { it.isForceLoaded = false }
boss.forceLoadedChunks.clear()
}
}

View File

@@ -0,0 +1,23 @@
package com.willfp.ecobosses.tick
import com.willfp.eco.util.NumberUtils
import com.willfp.eco.util.formatEco
import com.willfp.ecobosses.bosses.LivingEcoBoss
import kotlin.math.ceil
class DisplayNameTicker : BossTicker {
override fun tick(boss: LivingEcoBoss, tick: Int) {
val entity = boss.entity
val timeLeft = ceil(
(boss.deathTime - System.currentTimeMillis()) / 1000.0
).toInt()
val formattedTime = String.format("%d:%02d", timeLeft / 60, timeLeft % 60)
entity.customName = boss.boss.displayName
.replace("%health%", NumberUtils.format(entity.health))
.replace("%time%", formattedTime)
.formatEco()
}
}

View File

@@ -0,0 +1,24 @@
package com.willfp.ecobosses.tick
import com.willfp.ecobosses.bosses.LivingEcoBoss
import com.willfp.ecobosses.events.BossDespawnEvent
import com.willfp.ecobosses.lifecycle.BossLifecycle
import org.bukkit.Bukkit
class LifespanTicker : BossTicker {
override fun tick(boss: LivingEcoBoss, tick: Int) {
val timeLeft = (boss.deathTime - System.currentTimeMillis()) / 1000.0
if (timeLeft <= 0) {
val event = BossDespawnEvent(boss)
Bukkit.getPluginManager().callEvent(event)
boss.remove()
boss.boss.handleLifecycle(
BossLifecycle.DESPAWN,
boss.entity.location,
boss.entity
)
}
}
}

View File

@@ -0,0 +1,15 @@
package com.willfp.ecobosses.tick
import com.willfp.ecobosses.bosses.LivingEcoBoss
class TargetTicker : BossTicker {
override fun tick(boss: LivingEcoBoss, tick: Int) {
val entity = boss.entity
if (tick % 10 != 0) {
return
}
entity.target = boss.boss.targetMode.getTarget(boss) ?: return
}
}

View File

@@ -0,0 +1,49 @@
package com.willfp.ecobosses.tick
import com.willfp.ecobosses.bosses.LivingEcoBoss
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.block.BlockFace
class TeleportHandler : BossTicker {
override fun tick(boss: LivingEcoBoss, tick: Int) {
val entity = boss.entity
if (!boss.boss.canTeleport) {
return
}
if (tick % boss.boss.teleportInterval != 0) {
return
}
val range = boss.boss.teleportRange
val validLocations = mutableListOf<Location>()
for (x in -range..range) {
for (y in -range..range) {
for (z in -range..range) {
val location = entity.location.clone().apply {
this.x += x
this.y += y
this.z += z
}
val block = location.block
if (block.type == Material.AIR && block.getRelative(BlockFace.UP).type == Material.AIR && !(block.getRelative(
BlockFace.DOWN
).isLiquid || block.getRelative(BlockFace.DOWN).type == Material.AIR)
) {
validLocations.add(location)
}
}
}
}
if (validLocations.isEmpty()) {
return
}
entity.teleport(validLocations.random())
}
}

View File

@@ -0,0 +1,24 @@
package com.willfp.ecobosses.util
import com.willfp.eco.core.EcoPlugin
import org.bukkit.Bukkit
import org.bukkit.Keyed
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.inventory.Recipe
class DiscoverRecipeListener(private val plugin: EcoPlugin) : Listener {
@EventHandler
fun onJoin(event: PlayerJoinEvent) {
if (!plugin.configYml.getBool("discover-recipes")) {
return
}
mutableListOf<Recipe>()
.apply { Bukkit.getServer().recipeIterator().forEachRemaining(this::add) }
.filterIsInstance<Keyed>().map { it.key }
.filter { it.namespace == plugin.name.lowercase() }
.filter { !it.key.contains("displayed") }
.forEach { event.player.discoverRecipe(it) }
}
}

View File

@@ -0,0 +1,42 @@
package com.willfp.ecobosses.util
import com.willfp.eco.util.tryAsPlayer
import com.willfp.ecobosses.EcoBossesPlugin
import org.bukkit.entity.LivingEntity
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDamageByEntityEvent
import java.util.*
data class Damager(
val uuid: UUID,
var damage: Double
)
private const val metaKey = "TOP_DAMAGERS"
@Suppress("UNCHECKED_CAST")
var LivingEntity.topDamagers: List<Damager>
get() = (this.getMetadata(metaKey).getOrNull(0)?.value() as? List<Damager>) ?: emptyList()
private set(value) {
this.removeMetadata(metaKey, EcoBossesPlugin.instance)
this.setMetadata(metaKey, EcoBossesPlugin.instance.metadataValueFactory.create(value))
}
class TopDamagerListener : Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
fun handle(event: EntityDamageByEntityEvent) {
val uuid = event.damager.tryAsPlayer()?.uniqueId ?: return
val victim = event.entity as? LivingEntity ?: return
val topDamagers = victim.topDamagers.toMutableList()
val damager = topDamagers.firstOrNull { it.uuid == uuid } ?: Damager(uuid, 0.0)
damager.damage += event.damage
topDamagers.removeIf { it.uuid == uuid }
topDamagers.add(damager)
victim.topDamagers = topDamagers.sortedByDescending { it.damage }
}
}

View File

@@ -0,0 +1,59 @@
package com.willfp.ecobosses.util
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.util.NumberUtils
import com.willfp.eco.util.formatEco
import com.willfp.eco.util.savedDisplayName
import com.willfp.ecobosses.EcoBossesPlugin
import org.bukkit.Bukkit
import org.bukkit.Location
import org.bukkit.entity.Player
data class LocalBroadcast(
val messages: Iterable<String>,
val radius: Double
) {
fun broadcast(location: Location, topDamagers: List<Damager>) {
val toBroadcast = messages.toMutableList()
toBroadcast.replaceAll {
var message = it
for (i in 1..20) {
val damager = topDamagers.getOrNull(i - 1)
val damage = if (damager?.damage != null) NumberUtils.format(damager.damage) else
EcoBossesPlugin.instance.langYml.getFormattedString("na")
val player = if (damager?.uuid != null) Bukkit.getOfflinePlayer(damager.uuid).savedDisplayName else
EcoBossesPlugin.instance.langYml.getFormattedString("na")
message = message.replace("%damage_${i}%", damage)
.replace("%damage_${i}_player%", player)
}
message = message.replace("%x%", location.blockX.toString())
.replace("%y%", location.blockY.toString())
.replace("%z%", location.blockZ.toString())
message.formatEco()
}
if (radius < 0) {
for (message in toBroadcast) {
Bukkit.broadcastMessage(message)
}
} else {
val world = location.world ?: return
world.getNearbyEntities(location, radius, radius, radius)
.filterIsInstance<Player>()
.forEach { player -> toBroadcast.forEach { player.sendMessage(it) } }
}
}
companion object {
fun fromConfig(config: Config): LocalBroadcast {
return LocalBroadcast(
config.getStrings("message"),
config.getDouble("radius")
)
}
}
}

View File

@@ -0,0 +1,38 @@
package com.willfp.ecobosses.util
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.util.NumberUtils
import com.willfp.eco.util.savedDisplayName
import com.willfp.ecobosses.EcoBossesPlugin
import org.bukkit.Bukkit
import org.bukkit.Location
data class LocalCommands(
val commands: Iterable<String>,
) {
fun dispatch(location: Location, topDamagers: List<Damager>) {
val toDispatch = commands.toMutableList()
toDispatch.replaceAll {
var command = it
for (i in 1..20) {
val damager = topDamagers.getOrNull(i - 1)
val damage = if (damager?.damage != null) NumberUtils.format(damager.damage) else
EcoBossesPlugin.instance.langYml.getFormattedString("na")
val player = if (damager?.uuid != null) Bukkit.getOfflinePlayer(damager.uuid).savedDisplayName else
EcoBossesPlugin.instance.langYml.getFormattedString("na")
command = command.replace("%damage_${i}%", damage)
.replace("%damage_${i}_player%", player)
}
command.replace("%x%", location.blockX.toString())
.replace("%y%", location.blockY.toString())
.replace("%z%", location.blockZ.toString())
}
for (s in toDispatch) {
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), s);
}
}
}

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