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

Compare commits

..

581 Commits

Author SHA1 Message Date
Auxilor
e82cd59d72 libreforge-updater 2023-12-20 15:56:34 +00:00
Will FP
6e384c248d libreforge-updater 2023-12-14 16:13:22 +00:00
Will FP
e83cafb752 libreforge-updater 2023-12-11 12:12:40 +00:00
Will FP
a4aa97006a libreforge-updater 2023-12-07 17:25:29 +00:00
Will FP
3d1dce4567 Switched to ModelEngineBridge 2023-12-03 16:04:46 +00:00
Will FP
45ef970521 libreforge-updater 2023-12-03 15:58:59 +00:00
Will FP
16c9640163 libreforge-updater 2023-11-30 14:27:19 +00:00
Will FP
8ed4dbc9d3 libreforge-updater 2023-11-26 23:24:25 +00:00
Will FP
3805f8e2dd libreforge-updater 2023-11-23 13:21:18 +00:00
Auxilor
97e0832f7a libreforge-updater 2023-11-21 22:41:27 +00:00
Auxilor
99a3a1f4a9 libreforge-updater 2023-11-19 14:14:11 +00:00
Auxilor
87989ef899 libreforge-updater 2023-11-17 19:02:19 +00:00
Auxilor
754ab3b6fe libreforge-updater 2023-11-11 17:58:46 +00:00
Auxilor
8b0dfd4d8c libreforge-updater 2023-11-10 13:59:16 +00:00
Auxilor
bb73e2e8f7 libreforge-updater 2023-11-05 13:41:54 +00:00
Auxilor
4ab79995b3 libreforge-updater 2023-10-30 13:30:55 +00:00
Auxilor
4e3ba7321a libreforge-updater 2023-10-28 14:15:22 +01:00
Auxilor
0dbee3cead libreforge-updater 2023-10-24 15:39:20 +01:00
Auxilor
5c8cb3baf3 libreforge-updater 2023-10-19 12:52:24 +01:00
Auxilor
314d977a8b libreforge-updater 2023-10-14 14:20:21 +01:00
Auxilor
93c435be9e libreforge-updater 2023-10-14 14:18:59 +01:00
Auxilor
5293dd2095 libreforge-updater 2023-10-02 11:54:11 +01:00
Auxilor
1a9a9afab3 libreforge-updater 2023-09-26 14:45:45 +01:00
Auxilor
934de35447 libreforge-updater 2023-09-20 15:33:42 +01:00
Auxilor
909eaab967 libreforge-updater 2023-09-17 11:20:07 +01:00
Auxilor
27ddb0b97f libreforge-updater 2023-09-13 15:08:42 +01:00
Auxilor
6b0708cb5d libreforge-updater 2023-09-07 16:01:22 +01:00
Auxilor
c8bd1b379d libreforge-updater 2023-09-02 17:34:12 +01:00
Auxilor
683b3fe082 libreforge-updater 2023-08-31 16:59:07 +01:00
Auxilor
0b95669a35 libreforge-updater 2023-08-30 11:31:06 +01:00
Auxilor
f6a9493645 libreforge-updater 2023-08-26 18:11:12 +01:00
Auxilor
fb3aae24e0 libreforge-updater 2023-08-23 15:31:26 +01:00
Auxilor
9c05965b76 libreforge-updater 2023-08-19 15:32:18 +01:00
Auxilor
fdc12dda3d libreforge-updater 2023-08-15 18:52:11 +01:00
Auxilor
f79aad596f libreforge-updater 2023-08-13 14:42:18 +01:00
Auxilor
b29de7effb libreforge-updater 2023-08-10 19:59:11 +01:00
Auxilor
45725b95fe libreforge-updater 2023-08-10 19:57:00 +01:00
Auxilor
a350769ff2 libreforge-updater 2023-08-09 15:58:19 +01:00
Auxilor
9028db8309 libreforge-updater 2023-08-09 14:40:13 +01:00
Auxilor
1535ab476e libreforge-updater 2023-08-09 14:36:57 +01:00
Auxilor
908d929718 libreforge-updater 2023-08-08 17:58:57 +01:00
Auxilor
f410216ab8 libreforge-updater 2023-08-05 21:06:36 +01:00
Auxilor
26cc3be8a7 libreforge-updater 2023-07-27 15:21:12 +01:00
Auxilor
91b85fea88 libreforge-updater 2023-07-27 15:18:31 +01:00
Auxilor
b16e427da6 libreforge-updater 2023-07-25 14:37:47 +01:00
Auxilor
16df926b84 libreforge-updater 2023-07-23 11:40:00 +01:00
Auxilor
16336c5716 libreforge-updater 2023-07-22 14:59:25 +01:00
Auxilor
776b8718b2 libreforge-updater 2023-07-21 12:32:38 +01:00
Auxilor
2dec97e473 libreforge-updater 2023-07-20 13:06:36 +01:00
Auxilor
c177543653 libreforge-updater 2023-07-19 14:14:25 +01:00
Auxilor
aeae0d3737 libreforge-updater 2023-07-17 18:32:06 +01:00
Auxilor
710fb6d2e4 libreforge-updater 2023-07-16 13:32:53 +01:00
Auxilor
9a903e285e libreforge-updater 2023-07-12 13:07:51 +01:00
Auxilor
a033751019 libreforge-updater 2023-07-09 17:24:14 +01:00
Auxilor
d9ab454ca8 libreforge-updater 2023-07-06 18:46:37 +01:00
Auxilor
2ead72ad15 libreforge-updater 2023-07-04 14:49:22 +01:00
Auxilor
365f99a49b libreforge-updater 2023-06-27 10:41:16 +01:00
Auxilor
b8fbfe24b6 libreforge-updater 2023-06-21 10:23:13 +01:00
Auxilor
f545a6c010 libreforge-updater 2023-06-19 11:12:22 +02:00
Will FP
1c6f1c037e Create CODEOWNERS 2023-06-17 21:22:31 +02:00
Auxilor
fc35c2b7a9 libreforge-updater 2023-06-10 13:32:10 +01:00
Auxilor
632f43fe80 libreforge-updater 2023-06-05 16:26:37 +01:00
Auxilor
e5b43cce98 Fixed Publications 2023-06-03 18:01:25 +01:00
Auxilor
372b74ef69 libreforge-updater 2023-06-03 15:45:21 +01:00
Auxilor
03a1f3af28 libreforge-updater 2023-06-01 12:33:21 +01:00
Auxilor
ed0c7ae238 Added location_to_boss mutator 2023-05-30 19:46:22 +01:00
Auxilor
5de65f086e libreforge-updater 2023-05-30 16:10:35 +01:00
Auxilor
bf81feea40 libreforge-updater 2023-05-24 14:57:58 +01:00
Auxilor
9229bdee7b libreforge-updater 2023-05-23 16:12:13 +01:00
Auxilor
bd2637d709 libreforge-updater 2023-05-20 17:40:57 +01:00
Auxilor
4264892c5f fuck you, modelengine. i hate youh 2023-05-18 16:27:43 +01:00
Auxilor
9e07b39c10 libreforge-updater 2023-05-18 16:25:30 +01:00
Auxilor
08d984794e Fixes 2023-05-17 16:36:45 +01:00
Auxilor
1c770e07e7 libreforge-updater 2023-05-17 15:57:13 +01:00
Auxilor
9a48077c9e libreforge-updater 2023-05-16 20:30:07 +01:00
Auxilor
553e006da3 libreforge-updater 2023-05-15 10:52:32 +01:00
Auxilor
c658decff0 libreforge-updater 2023-05-14 13:08:30 +01:00
Auxilor
3af948b712 libreforge-updater 2023-05-09 17:45:30 +01:00
Auxilor
81eeabef5e libreforge-updater 2023-05-05 18:54:37 +01:00
Auxilor
2efa705760 libreforge-updater 2023-05-03 14:47:57 +01:00
Auxilor
040c43f072 libreforge-updater 2023-04-30 19:57:11 +01:00
Auxilor
a3fc8569f9 libreforge-updater 2023-04-29 17:19:28 +01:00
Auxilor
a2eb10c1f2 libreforge-updater 2023-04-25 16:06:07 +01:00
Auxilor
a1fe7ffdc0 libreforge-updater 2023-04-25 13:13:13 +01:00
Auxilor
ebf26ae8ca Fuck mvn.lumine.io 2023-04-24 22:52:19 +01:00
Auxilor
10ce71bb08 libreforge-updater 2023-04-24 22:49:24 +01:00
Auxilor
5432d066b3 libreforge-updater 2023-04-20 20:20:44 +01:00
Auxilor
0a0d1d8764 Updated to 9.3.1 2023-04-20 18:04:55 +01:00
Auxilor
5619859b42 Moved libreforge integration loading to load 2023-04-20 18:04:47 +01:00
Auxilor
c6a6fc4201 libreforge-updater 2023-04-19 12:21:36 +01:00
Auxilor
b4c81d7874 libreforge-updater 2023-04-13 12:48:51 -04:00
Auxilor
fb78e87bd0 libreforge-updater 2023-04-09 18:19:30 -04:00
Auxilor
fd4b3bcc76 libreforge-updater 2023-04-06 20:09:30 +02:00
Auxilor
f1d02cc3ba libreforge-updater 2023-04-05 13:13:45 +01:00
Auxilor
78135d7e72 libreforge-updater 2023-04-03 17:49:46 +01:00
Auxilor
ed0fd90df8 libreforge-updater 2023-04-02 17:44:13 +01:00
Auxilor
42af89c79a libreforge-updater 2023-03-30 15:30:24 +01:00
Auxilor
d453461eeb why is model engine like this 2023-03-29 19:31:03 +01:00
Auxilor
e4093a0fd5 libreforge-updater 2023-03-29 19:21:02 +01:00
Auxilor
7e950ea508 libreforge-updater 2023-03-29 15:47:17 +01:00
Auxilor
ac79baa2d3 Fixed workflows 2023-03-29 13:44:06 +01:00
Auxilor
50adfae567 Moved to repo.auxilor.io 2023-03-29 13:39:57 +01:00
Auxilor
153022c3bf Fixed permissions on paper 2023-03-28 21:42:33 +01:00
Auxilor
8d37635381 Cleanup 2023-03-28 21:19:12 +01:00
Auxilor
299d3ee1d6 Updated to reflect libreforge change 2023-03-28 19:28:06 +01:00
Auxilor
f0a2d32b95 Moved integration 2023-03-28 18:58:58 +01:00
Auxilor
4e86750c7d Fixed duplicated messages for lifespan 2023-03-28 17:23:24 +01:00
Auxilor
b3b7695218 Fixed several bugs 2023-03-28 16:04:59 +01:00
Auxilor
1aa0a27c65 Fixed publications 2023-03-28 14:55:23 +01:00
Auxilor
392a76bad8 Updated to libreforge 4 2023-03-28 14:32:53 +01:00
Auxilor
95afe96860 Changed load order 2023-03-22 22:10:03 +00:00
Auxilor
21d24a5198 libreforge-updater 2023-03-13 13:40:30 +00:00
Auxilor
af9766a391 libreforge-updater 2023-03-02 12:56:01 +00:00
Auxilor
df70871bad libreforge-updater 2023-02-22 15:02:39 +00:00
Auxilor
b030af609a libreforge-updater 2023-02-15 20:59:05 +00:00
Auxilor
344e71cd9a libreforge-updater 2023-02-12 16:55:42 +00:00
Auxilor
7b7a16f9c6 libreforge-updater 2023-02-09 14:12:44 +00:00
Auxilor
ba1c348f8e libreforge-updater 2023-02-07 14:46:53 +00:00
Auxilor
c81f7174e2 libreforge-updater 2023-02-04 15:36:59 +00:00
Auxilor
53b037816d libreforge-updater 2023-01-24 10:09:30 +00:00
Auxilor
d7e07c1a62 libreforge-updater 2023-01-17 16:48:42 +00:00
Auxilor
d939296d96 libreforge-updater 2023-01-13 18:08:48 +00:00
Auxilor
2505ddd845 libreforge-updater 2023-01-07 12:17:46 +00:00
Auxilor
ea7371db9e libreforge-updater 2023-01-02 15:58:40 +00:00
Auxilor
b53ab306ed libreforge-updater 2022-12-26 14:01:48 +01:00
Auxilor
33f82117e4 Updated modelengine 2022-12-20 15:20:45 +00:00
Auxilor
a80e060a7e libreforge-updater 2022-12-20 15:15:33 +00:00
Auxilor
a915752922 libreforge-updater 2022-12-12 14:01:34 +00:00
Auxilor
06eb724bd8 libreforge-updater 2022-12-09 17:01:53 +00:00
Auxilor
18c66ef10c libreforge-updater 2022-12-05 10:51:14 +00:00
Auxilor
ae0c8531b0 libreforge-updater 2022-11-30 17:38:55 +00:00
Auxilor
705eafb9af libreforge-updater 2022-11-27 21:45:04 +00:00
Auxilor
e83ede56f0 libreforge-updater 2022-11-26 19:20:59 +00:00
Auxilor
6bddf72111 libreforge-updater 2022-11-24 14:30:48 +00:00
Auxilor
d32d07f4e2 libreforge-updater 2022-11-23 17:25:42 +00:00
Auxilor
8c40d9861d libreforge-updater 2022-11-21 16:03:34 +00:00
Auxilor
03272f794e libreforge-updater 2022-11-17 08:39:07 +00:00
Auxilor
8ff42da43c libreforge-updater 2022-11-12 17:35:11 +00:00
Auxilor
7f61f6a66a libreforge-updater 2022-11-06 19:52:34 +00:00
Auxilor
c1dde026b7 Updated chains 2022-11-06 17:00:48 +00:00
Auxilor
983246a7c4 Added illusioner 2022-11-06 16:56:39 +00:00
Auxilor
ee32897b1c libreforge-updater 2022-11-01 16:23:35 +00:00
Auxilor
67b38896ca libreforge-updater 2022-10-28 11:35:44 +01:00
Auxilor
39b91bc828 libreforge-updater 2022-10-26 22:12:03 +01:00
Auxilor
e2e7b44a75 Fix 2022-10-24 17:11:42 +01:00
Auxilor
3c1e5ee192 libreforge-updater 2022-10-24 17:05:27 +01:00
Auxilor
56789f331b libreforge-updater 2022-10-21 19:26:42 +01:00
Auxilor
e99b96132f libreforge-updater 2022-10-19 20:44:41 +01:00
Auxilor
c0297cd3db libreforge-updater 2022-10-18 14:14:41 +01:00
Auxilor
3b798a8ed7 libreforge-updater 2022-10-16 23:27:19 +01:00
Auxilor
bc73201ec5 libreforge-updater 2022-10-13 20:13:11 +01:00
Auxilor
b1365855af libreforge-updater 2022-10-10 21:04:32 +01:00
Auxilor
1ce50cb0b9 libreforge-updater 2022-10-09 15:03:11 +01:00
Auxilor
2a50868624 libreforge-updater 2022-10-07 19:51:54 +01:00
Auxilor
0a0e7a9661 libreforge-updater 2022-10-06 12:04:55 +01:00
Auxilor
8cd4ccdbd7 libreforge-updater 2022-10-04 15:53:28 +01:00
Auxilor
429bc6a61f libreforge-updater 2022-10-03 18:30:03 +01:00
Auxilor
b92ea06667 Fixed _example.yml 2022-10-02 17:01:40 +01:00
Auxilor
1e332bf845 libreforge-updater 2022-10-02 14:58:47 +01:00
Auxilor
7cec9f3e30 Added separator ambivalence to boss configs and Model Engine animation support 2022-09-29 08:40:30 +01:00
Auxilor
7db3af5dca oops 2022-09-28 17:55:29 +01:00
Auxilor
137f4e3732 libreforge-updater 2022-09-28 17:53:14 +01:00
Auxilor
7338a24b81 Fix 2022-09-28 16:12:42 +01:00
Auxilor
bde5de1d77 Fixed plugin.yml 2022-09-28 16:12:23 +01:00
Auxilor
b48cc66383 Updated to 8.91.1 2022-09-28 16:12:00 +01:00
Auxilor
bf59ba4d4a Improved _example.yml 2022-09-28 16:11:48 +01:00
Auxilor
127a43e032 PR Improvements 2022-09-28 16:10:21 +01:00
Will FP
383893c8f6 Merge pull request #50
fix: boss transformations
2022-09-28 16:01:24 +01:00
Will FP
37926bd016 Merge pull request #52
Feature/modelengine
2022-09-28 16:01:08 +01:00
Will FP
6778058150 Merge pull request #53
fix: handle spawning of bosses from droppers and dispensers
2022-09-28 15:59:45 +01:00
Auxilor
8addad09d2 fix 2022-09-26 18:54:34 +01:00
DaRacci
7fe0eece16 fix: handle spawning of bosses from droppers and dispensers 2022-09-27 01:13:42 +10:00
DaRacci
eca8726323 fix: check if the model exists 2022-09-27 00:10:20 +10:00
DaRacci
16ba41f39a feat: ModelEngine support 2022-09-27 00:07:28 +10:00
Auxilor
685f40a71b Merge branch 'fix/publishing'
# Conflicts:
#	build.gradle
2022-09-26 13:54:00 +01:00
Auxilor
76c6d22a00 libreforge-updater 2022-09-26 10:52:49 +01:00
DaRacci
38629407bc fix: Use component from subproject 2022-09-26 14:44:12 +10:00
DaRacci
1eee00b88e fix: Publishing
Also converted gradle build to kotlin.
Also updated gradle to 7.5.1

Closes: https://github.com/Auxilor/EcoBosses/issues/49, https://github.com/Auxilor/EcoBosses/issues/41
2022-09-25 23:39:05 +10:00
DaRacci
de47ccf159 fix: boss transformations
Closes: https://github.com/Auxilor/EcoBosses/issues/36
2022-09-25 22:27:08 +10:00
Auxilor
b81e7af836 libreforge-updater 2022-09-22 17:31:03 +01:00
Auxilor
fcde21c21a libreforge-updater 2022-09-21 15:29:05 +01:00
Auxilor
405659f293 libreforge-updater 2022-09-20 10:57:39 +01:00
Auxilor
2d6154d11f libreforge-updater 2022-09-17 15:46:02 +01:00
Auxilor
9fad76ffad libreforge-updater 2022-09-15 12:15:47 +01:00
Auxilor
e4a40470b8 libreforge-updater 2022-09-15 12:09:44 +01:00
Auxilor
f966629e21 libreforge-updater 2022-09-14 18:53:14 +01:00
Auxilor
93d09c1f3d libreforge-updater 2022-09-14 15:12:30 +01:00
Auxilor
56763be02d libreforge-updater 2022-09-14 15:09:33 +01:00
Auxilor
bd05d4474f libreforge-updater 2022-09-14 12:59:22 +01:00
Auxilor
aa0f9c195d libreforge-updater 2022-09-13 19:15:06 +01:00
Auxilor
e9e0214d1e libreforge-updater 2022-09-12 21:20:54 +01:00
Auxilor
744e3a943d libreforge-updater 2022-09-12 17:14:59 +01:00
Auxilor
fcaea262e8 libreforge-updater 2022-09-11 19:27:24 +01:00
Auxilor
062d2eea77 libreforge-updater 2022-09-10 12:58:21 +01:00
Auxilor
25844170eb libreforge-updater 2022-09-10 10:51:17 +01:00
Auxilor
00cc509b40 libreforge-updater 2022-09-06 15:43:31 +01:00
Auxilor
77e46ffb55 libreforge-updater 2022-09-06 13:46:10 +01:00
Auxilor
1f72e3b9b3 libreforge-updater 2022-09-06 11:25:17 +01:00
Auxilor
a94a5cc04d libreforge-updater 2022-09-05 18:00:28 +01:00
Auxilor
2b8d8eb20a libreforge-updater 2022-09-04 17:22:44 +01:00
Auxilor
1b4851fb9c libreforge-updater 2022-09-04 16:22:01 +01:00
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
137 changed files with 3407 additions and 4114 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1 @@
* @WillFP

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

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Discord
url: https://discord.gg/ZcwpSsE/
about: Issues have moved to Discord, please join the server to get help!

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

@@ -0,0 +1,11 @@
---
name: Report a Bug
about: Report an issue with the plugin
title: ''
labels: bug
assignees: ''
---
# Please report bugs on the discord!
[Join by clicking here](https://discord.gg/ZcwpSsE/)

33
.github/workflows/publish-release.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: Publish Packages
on:
workflow_dispatch:
release:
types: [ created ]
push:
tags:
- '*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout latest code
uses: actions/checkout@v2
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: 17
- name: Change wrapper permissions
run: chmod +x ./gradlew
- name: Publish package
uses: gradle/gradle-build-action@v2
with:
arguments: publish
env:
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}

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,107 +0,0 @@
plugins {
id 'java-library'
id 'com.github.johnrengelman.shadow' version '5.2.0'
id 'maven-publish'
id 'java'
}
dependencies {
implementation project(":eco-core").getSubprojects()
}
allprojects {
apply plugin: 'java'
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/' }
maven { url 'https://repo.codemc.org/repository/nms/' }
maven { url 'https://repo.codemc.org/repository/maven-public' }
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
maven { url 'https://oss.sonatype.org/content/groups/public/' }
maven { url 'https://maven.enginehub.org/repo/' }
maven { url 'https://ci.ender.zone/plugin/repository/project/' }
maven { url 'https://ci.ender.zone/plugin/repository/everything/' }
maven { url 'https://repo.md-5.net/content/repositories/snapshots/' }
maven { url 'https://repo.dmulloy2.net/nexus/repository/public/' }
maven { url 'https://papermc.io/repo/repository/maven-public/' }
maven { url 'https://repo.maven.apache.org/maven2/' }
maven { url 'https://repo.dustplanet.de/artifactory/ext-release-local/' }
maven { url 'https://maven.seyfahni.de/repository/snapshots/' }
maven { url 'https://libraries.minecraft.net/' }
maven { url 'https://repo.spongepowered.org/maven/' }
maven { url 'https://org.kitteh.pastegg' }
maven { url 'https://repo.mikeprimm.com/' }
maven { url 'https://maven.sk89q.com/repo/' }
maven { url 'https://github.com/factions-site/repo/raw/public/' }
maven { url 'https://repo.extendedclip.com/content/repositories/placeholderapi/' }
}
jar {
onlyIf { !sourceSets.main.allSource.files.isEmpty() }
}
dependencies {
compileOnly 'com.willfp:eco:5.0.0'
compileOnly 'org.jetbrains:annotations:19.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'
}
tasks.withType(JavaCompile) {
options.deprecation = true
options.encoding = 'UTF-8'
}
processResources {
filesNotMatching(["**/*.png", "**/models/**", "**/textures/**"]) {
expand projectVersion: project.version
}
}
compileJava.options.encoding = 'UTF-8'
compileJava.dependsOn clean
}
tasks.withType(Jar) {
destinationDirectory = file("$rootDir/bin/")
}
clean.doLast {
file("${rootDir}/bin").deleteDir()
}
shadowJar {
archiveFileName = findProperty("plugin-name") + " v" + findProperty("version") + ".jar"
}
jar {
archiveFileName = findProperty("plugin-name") + " v" + findProperty("version") + " " + "unshaded" + ".jar"
}
group = 'com.willfp'
archivesBaseName = project.name
version = findProperty("version")
java.sourceCompatibility = JavaVersion.VERSION_1_8
compileJava.options.encoding = 'UTF-8'
build.dependsOn shadowJar
publishing {
publications {
maven(MavenPublication) {
from(components.java)
}
}
}

84
build.gradle.kts Normal file
View File

@@ -0,0 +1,84 @@
plugins {
java
`java-library`
`maven-publish`
kotlin("jvm") version "1.9.20"
id("com.github.johnrengelman.shadow") version "8.0.0"
id("com.willfp.libreforge-gradle-plugin") version "1.0.0"
}
group = "com.willfp"
version = findProperty("version")!!
val libreforgeVersion = findProperty("libreforge-version")
base {
archivesName.set(project.name)
}
dependencies {
project(":eco-core").dependencyProject.subprojects {
implementation(this)
}
}
allprojects {
apply(plugin = "java")
apply(plugin = "kotlin")
apply(plugin = "maven-publish")
apply(plugin = "com.github.johnrengelman.shadow")
repositories {
mavenLocal()
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.auxilor.io/repository/maven-public/")
maven("https://jitpack.io")
maven("https://mvn.lumine.io/repository/maven-public/")
}
dependencies {
compileOnly("com.willfp:eco:6.56.0")
compileOnly("org.jetbrains:annotations:23.0.0")
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.20")
}
java {
withSourcesJar()
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
}
tasks {
shadowJar {
relocate("com.willfp.libreforge.loader", "com.willfp.ecobosses.libreforge.loader")
relocate("com.willfp.modelenginebridge", "com.willfp.ecobosses.modelenginebridge")
}
compileKotlin {
kotlinOptions {
jvmTarget = "17"
}
}
compileJava {
options.isDeprecation = true
options.encoding = "UTF-8"
dependsOn(clean)
}
processResources {
filesMatching(listOf("**plugin.yml", "**eco.yml")) {
expand(
"version" to project.version,
"libreforgeVersion" to libreforgeVersion,
"pluginName" to rootProject.name
)
}
}
build {
dependsOn(shadowJar)
}
}
}

View File

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

View File

@@ -0,0 +1,2 @@
group = "com.willfp"
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

@@ -1,9 +0,0 @@
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'
}

View File

@@ -0,0 +1,37 @@
group = "com.willfp"
version = rootProject.version
dependencies {
compileOnly("io.papermc.paper:paper-api:1.19.3-R0.1-SNAPSHOT")
compileOnly("com.github.lokka30:LevelledMobs:3.1.4")
implementation("com.willfp:ModelEngineBridge:1.2.0")
}
publishing {
publications {
register<MavenPublication>("maven") {
groupId = project.group.toString()
version = project.version.toString()
artifactId = rootProject.name
artifact(rootProject.tasks.shadowJar.get().archiveFile)
}
}
repositories {
maven {
name = "auxilor"
url = uri("https://repo.auxilor.io/repository/maven-releases/")
credentials {
username = System.getenv("MAVEN_USERNAME")
password = System.getenv("MAVEN_PASSWORD")
}
}
}
}
tasks {
build {
dependsOn(publishToMavenLocal)
}
}

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,109 @@
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.libreforge.EffectBossDropChanceMultiplier
import com.willfp.ecobosses.libreforge.MutatorLocationToBoss
import com.willfp.ecobosses.libreforge.TriggerKillBoss
import com.willfp.ecobosses.libreforge.TriggerSpawnBoss
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.effects.Effects
import com.willfp.libreforge.loader.LibreforgePlugin
import com.willfp.libreforge.loader.configs.ConfigCategory
import com.willfp.libreforge.mutators.Mutators
import com.willfp.libreforge.registerHolderProvider
import com.willfp.libreforge.registerSpecificHolderProvider
import com.willfp.libreforge.triggers.Triggers
import org.bukkit.entity.Player
import org.bukkit.event.Listener
class EcoBossesPlugin : LibreforgePlugin() {
init {
instance = this
}
override fun loadConfigCategories(): List<ConfigCategory> {
return listOf(
Bosses
)
}
override fun handleLoad() {
Effects.register(EffectBossDropChanceMultiplier)
Triggers.register(TriggerKillBoss)
Triggers.register(TriggerSpawnBoss)
Mutators.register(MutatorLocationToBoss)
}
override fun handleEnable() {
registerSpecificHolderProvider<Player> {
it.bossHolders
}
}
override fun handleReload() {
Bosses.getAllAlive().forEach { it.remove() }
AutospawnHandler.startSpawning(this)
}
override fun handleDisable() {
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(this),
DamageMultiplierHandler(),
MountHandler(),
PickupHandler(),
ImmunitiesHandler(),
CompatibilityListeners(),
SpawnTotemHandler(),
DeathListeners(),
ConsoleLoggers(this)
)
}
override fun loadIntegrationLoaders(): List<IntegrationLoader> {
return listOf(
IntegrationLoader("LevelledMobs") { this.eventManager.registerListener(IntegrationLevelledMobs()) }
)
}
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.ecobosses.util.EntityProvidedHolder
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataType
import kotlin.math.pow
val Player.bossHolders: Collection<EntityProvidedHolder>
get() {
val holders = mutableListOf<EntityProvidedHolder>()
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(EntityProvidedHolder(boss, entity))
}
}
}
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.key)
}
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,108 @@
package com.willfp.ecobosses.bosses
import com.google.common.collect.ImmutableList
import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.config.readConfig
import com.willfp.eco.core.config.updating.ConfigUpdater
import com.willfp.eco.core.registry.Registry
import com.willfp.ecobosses.EcoBossesPlugin
import com.willfp.libreforge.loader.LibreforgePlugin
import com.willfp.libreforge.loader.configs.ConfigCategory
import com.willfp.libreforge.loader.configs.LegacyLocation
import com.willfp.libreforge.separatorAmbivalent
import org.bukkit.entity.Entity
import org.bukkit.entity.LivingEntity
import java.io.File
import java.util.UUID
object Bosses : ConfigCategory("boss", "bosses") {
/** Registered bosses. */
private val registry = Registry<EcoBoss>()
override val legacyLocation = LegacyLocation(
"ecobosses.yml",
"bosses"
)
/**
* Get all registered [EcoBoss]s.
*
* @return A list of all [EcoBoss]s.
*/
@JvmStatic
fun values(): List<EcoBoss> {
return ImmutableList.copyOf(registry.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 registry[name]
}
override fun clear(plugin: LibreforgePlugin) {
registry.clear()
}
override fun acceptConfig(plugin: LibreforgePlugin, id: String, config: Config) {
registry.register(EcoBoss(id, config, plugin as EcoBossesPlugin))
}
/**
* 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)
}
/** If an entity is a boss. */
val Entity?.isBoss: Boolean
get() {
if (this !is LivingEntity) {
return false
}
return Bosses[this] != null
}
}

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,482 @@
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.core.registry.Registrable
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.ViolationContext
import com.willfp.libreforge.conditions.Conditions
import com.willfp.libreforge.effects.Effects
import com.willfp.modelenginebridge.ModelEngineBridge
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.Objects
import java.util.UUID
class EcoBoss(
id: String,
val config: Config,
private val plugin: EcoPlugin
) : Holder, Registrable {
override val id = plugin.createNamespacedKey(id)
val displayName: String = config.getString("display-name")
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("boss-bar.enabled")
val bossBarRadius = config.getDouble("boss-bar.radius")
val isPreventingMounts = config.getBool("defence.prevent-mounts")
val isImmuneToExplosions = config.getBool("defence.explosion-immune")
val isImmuneToFire = config.getBool("defence.fire-immune")
val isImmuneToDrowning = config.getBool("defence.drowning-immune")
val isImmuneToSuffocation = config.getBool("defence.suffocation-immune")
val meleeDamageMultiplier = config.getDouble("defence.melee-damage-multiplier")
val projectileDamageMultiplier = config.getDouble("defence.projectile-damage-multiplier")
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.key}_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.not-in-worlds")
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("custom-ai.enabled")
val targetGoals = config.getSubsections("custom-ai.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("custom-ai.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 = Conditions.compile(
config.getSubsections("spawn.conditions"),
ViolationContext(plugin, "$id Spawn Conditions")
)
private val bossBarColor = BossBar.Color.valueOf(config.getString("boss-bar.color").uppercase())
private val bossBarStyle = BossBar.Overlay.valueOf(config.getString("boss-bar.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.top-damager-commands").getKeys(false)) {
val rankRewards = mutableListOf<CommandReward>()
for (config in config.getSubsections("rewards.top-damager-commands.$rank")) {
rankRewards.add(
CommandReward(
config.getDouble("chance"),
config.getStrings("commands")
)
)
}
map[rank.toInt()] = rankRewards
}
map
}
private val nearbyCommandRewardRadius = config.getDouble("rewards.nearby-player-commands.radius")
private val nearbyCommands: Iterable<CommandReward> = run {
val list = mutableListOf<CommandReward>()
for (config in config.getSubsections("rewards.nearby-player-commands.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 modelEngineID = config.getStringOrNull("model-engine-id")
private val currentlyAlive = mutableMapOf<UUID, LivingEcoBoss>()
override val conditions = Conditions.compile(
config.getSubsections("conditions"),
ViolationContext(plugin, "Boss ID $id")
)
override val effects = Effects.compile(
config.getSubsections("effects"),
ViolationContext(plugin, "Boss ID $id")
)
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.key
)
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>) }
}
if (modelEngineID != null && Bukkit.getPluginManager().isPluginEnabled("ModelEngine")) {
val model = ModelEngineBridge.instance.createActiveModel(modelEngineID)
if (model == null) {
plugin.logger.warning("Invalid Model Engine ID for boss $id")
} else {
val modelled = ModelEngineBridge.instance.createModeledEntity(mob)
modelled.addModel(model)
modelled.isBaseEntityVisible = false
}
}
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 getID(): String {
return this.id.key
}
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,43 @@
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 com.willfp.libreforge.SimpleProvidedHolder
import com.willfp.libreforge.toDispatcher
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.toDispatcher(), SimpleProvidedHolder(egg)) }
.map { 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.key).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.key }
/**
* 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.key }
/**
* 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,22 @@
package com.willfp.ecobosses.events
import com.willfp.ecobosses.bosses.LivingEcoBoss
import org.bukkit.event.Event
import org.bukkit.event.HandlerList
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,21 @@
package com.willfp.ecobosses.events
import com.willfp.ecobosses.bosses.LivingEcoBoss
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,25 @@
package com.willfp.ecobosses.events
import com.willfp.ecobosses.bosses.LivingEcoBoss
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,29 @@
package com.willfp.ecobosses.events
import com.willfp.ecobosses.bosses.EcoBoss
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,29 @@
package com.willfp.ecobosses.libreforge
import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.bosses.EcoBoss
import com.willfp.ecobosses.events.BossTryDropItemEvent
import com.willfp.libreforge.effects.templates.MultiMultiplierEffect
import com.willfp.libreforge.toDispatcher
import org.bukkit.event.EventHandler
object EffectBossDropChanceMultiplier : MultiMultiplierEffect<EcoBoss>("boss_drop_chance_multiplier") {
override val key = "bosses"
override fun getElement(key: String): EcoBoss? {
return Bosses.getByID(key)
}
override fun getAllElements(): Collection<EcoBoss> {
return Bosses.values()
}
@EventHandler(ignoreCancelled = true)
fun handle(event: BossTryDropItemEvent) {
val player = event.player ?: return
val multiplier = getMultiplier(player.toDispatcher(), event.boss)
event.chance *= multiplier
}
}

View File

@@ -0,0 +1,24 @@
package com.willfp.ecobosses.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.ecobosses.events.BossSpawnEvent
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.getProvider
import com.willfp.libreforge.mutators.Mutator
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
import org.bukkit.entity.Entity
import org.bukkit.entity.LivingEntity
import org.bukkit.event.EventHandler
object MutatorLocationToBoss : Mutator<NoCompileData>("location_to_boss") {
override fun mutate(data: TriggerData, config: Config, compileData: NoCompileData): TriggerData {
val entity = data.holder.getProvider<LivingEntity>() ?: return data
val location = entity.location
return data.copy(
location = location
)
}
}

View File

@@ -0,0 +1,33 @@
package com.willfp.ecobosses.libreforge
import com.willfp.ecobosses.events.BossKillEvent
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
import org.bukkit.attribute.Attribute
import org.bukkit.event.EventHandler
object TriggerKillBoss : Trigger("kill_boss") {
override val parameters = setOf(
TriggerParameter.PLAYER,
TriggerParameter.VICTIM,
TriggerParameter.LOCATION
)
@EventHandler(ignoreCancelled = true)
fun handle(event: BossKillEvent) {
val killer = event.killer ?: return
val entity = event.boss.entity
this.dispatch(
killer.toDispatcher(),
TriggerData(
player = killer,
victim = entity,
location = entity.location,
value = entity.getAttribute(Attribute.GENERIC_MAX_HEALTH)!!.value
)
)
}
}

View File

@@ -0,0 +1,29 @@
package com.willfp.ecobosses.libreforge
import com.willfp.ecobosses.events.BossSpawnEvent
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
import org.bukkit.event.EventHandler
object TriggerSpawnBoss : Trigger("spawn_boss") {
override val parameters = setOf(
TriggerParameter.PLAYER,
TriggerParameter.LOCATION
)
@EventHandler(ignoreCancelled = true)
fun handle(event: BossSpawnEvent) {
val player = event.spawner ?: return
val location = event.location
this.dispatch(
player.toDispatcher(),
TriggerData(
player = player,
location = location
)
)
}
}

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,25 @@
package com.willfp.ecobosses.lifecycle
import com.willfp.ecobosses.bosses.Bosses.isBoss
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityTransformEvent
import org.bukkit.event.entity.SlimeSplitEvent
class CompatibilityListeners : Listener {
@EventHandler
fun handle(event: SlimeSplitEvent) {
if (!event.entity.isBoss) {
return
}
event.isCancelled = true
}
@EventHandler
fun handle(event: EntityTransformEvent) {
if (!event.entity.isBoss) {
return
}
event.isCancelled = true
}
}

View File

@@ -0,0 +1,56 @@
package com.willfp.ecobosses.lifecycle
import com.willfp.eco.core.EcoPlugin
import com.willfp.ecobosses.events.BossDespawnEvent
import com.willfp.ecobosses.events.BossKillEvent
import com.willfp.ecobosses.events.BossSpawnEvent
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
class ConsoleLoggers(
private val plugin: EcoPlugin
) : 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,52 @@
package com.willfp.ecobosses.lifecycle
import com.willfp.ecobosses.bosses.Bosses
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().map { 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,99 @@
package com.willfp.ecobosses.spawn
import com.willfp.ecobosses.EcoBossesPlugin
import com.willfp.ecobosses.bosses.bossEgg
import com.willfp.ecobosses.events.BossSpawnEvent
import com.willfp.libreforge.SimpleProvidedHolder
import com.willfp.libreforge.toDispatcher
import org.bukkit.Bukkit
import org.bukkit.Location
import org.bukkit.block.Container
import org.bukkit.block.data.Directional
import org.bukkit.entity.Player
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.block.BlockDispenseEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.EquipmentSlot
import org.bukkit.inventory.ItemStack
class SpawnEggHandler(
private val plugin: EcoBossesPlugin
) : Listener {
@EventHandler(
ignoreCancelled = true
)
fun handle(event: PlayerInteractEvent) {
if (event.action != Action.RIGHT_CLICK_BLOCK) {
return
}
if (!this.handleSpawnEgg(event.item, event.clickedBlock?.location?.add(0.0, 1.5, 0.0), event.player)) {
return
}
event.isCancelled = true
event.setUseItemInHand(Event.Result.DENY)
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
}
}
@EventHandler(
ignoreCancelled = true
)
fun handle(event: BlockDispenseEvent) {
val facing = (event.block.blockData as Directional).facing
val location = event.block.location.add(facing.direction.multiply(1.7))
if (!this.handleSpawnEgg(event.item, location, null)) return
event.isCancelled = true
val dispenser = event.block.state as? Container ?: return
// This is needed as the event must finish first,
// Otherwise the dispenser/dropper thinks the item is already removed from this event.
plugin.scheduler.run {
val item = dispenser.inventory.find { it?.isSimilar(event.item) == true } ?: return@run
item.amount--
dispenser.update()
}
}
private fun handleSpawnEgg(
item: ItemStack?,
location: Location?,
player: Player?
): Boolean {
val boss = item?.bossEgg ?: return false
if (location == null) {
return false
}
if (player != null) {
if (!boss.spawnConditions.areMet(player.toDispatcher(), SimpleProvidedHolder(boss))) {
return false
}
}
val spawnEvent = BossSpawnEvent(boss, location, BossSpawnEvent.SpawnReason.EGG, player)
Bukkit.getPluginManager().callEvent(spawnEvent)
if (spawnEvent.isCancelled) {
return false
}
boss.spawn(location)
return true
}
}

View File

@@ -0,0 +1,77 @@
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 com.willfp.libreforge.SimpleProvidedHolder
import com.willfp.libreforge.toDispatcher
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.areMet(player.toDispatcher(), SimpleProvidedHolder(boss))) {
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,46 @@
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
@Suppress("DEPRECATION")
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()
}
}

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