Compare commits
722
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
981d368058 | ||
|
|
7507099a4e | ||
|
|
29b58b1655 | ||
|
|
a1081c1b6b | ||
|
|
3152b62668 | ||
|
|
0082cc9852 | ||
|
|
f60b656bed | ||
|
|
da5f5de5cd | ||
|
|
e9aacecc2f | ||
|
|
fa3adbe605 | ||
|
|
e33b2f7025 | ||
|
|
a9cc577754 | ||
|
|
02344a31cf | ||
|
|
2f4871ef71 | ||
|
|
9750fad4b7 | ||
|
|
df77372d96 | ||
|
|
039af3c219 | ||
|
|
09ec4f87ef | ||
|
|
f996f22f4b | ||
|
|
b230c5ae9c | ||
|
|
2561107697 | ||
|
|
70babc8656 | ||
|
|
bd09d6c950 | ||
|
|
b94de763ca | ||
|
|
22ca57543f | ||
|
|
25c70170d9 | ||
|
|
9926041c2f | ||
|
|
1c99898d0d | ||
|
|
41e0261eee | ||
|
|
642f3ab1b8 | ||
|
|
57d1844756 | ||
|
|
73e1650fc3 | ||
|
|
800709ca95 | ||
|
|
935cbad21c | ||
|
|
0e2a27b298 | ||
|
|
baaa175423 | ||
|
|
e2b7a31191 | ||
|
|
afa2825bc7 | ||
|
|
21b4f6b087 | ||
|
|
a771652c8f | ||
|
|
e89b4f19ee | ||
|
|
eb8ef32a94 | ||
|
|
f9d783bc5c | ||
|
|
87dd4168cd | ||
|
|
2da6ece606 | ||
|
|
cbb3a7a518 | ||
|
|
57796d295b | ||
|
|
09314e8bce | ||
|
|
907a6dd5c0 | ||
|
|
a50bd807b6 | ||
|
|
02081b4654 | ||
|
|
156ec7911d | ||
|
|
2b95c62a84 | ||
|
|
539d5c43d1 | ||
|
|
1664690472 | ||
|
|
455396713e | ||
|
|
8bc3a593d0 | ||
|
|
5177f290ae | ||
|
|
5118864bb8 | ||
|
|
654da03add | ||
|
|
61229356ad | ||
|
|
fa5aa41547 | ||
|
|
04f07657eb | ||
|
|
eea2af169f | ||
|
|
6d393723ff | ||
|
|
9137ef04d2 | ||
|
|
878c4bea3d | ||
|
|
021d86e21c | ||
|
|
3e9425c8f1 | ||
|
|
cc60b9c938 | ||
|
|
d3cc950a97 | ||
|
|
5e97b1169b | ||
|
|
c3f4f117e5 | ||
|
|
814901b1c1 | ||
|
|
7c6b1d07b0 | ||
|
|
c389a41cdc | ||
|
|
2db9ae7c66 | ||
|
|
b80aea4c38 | ||
|
|
35b129701f | ||
|
|
d92fe17c4f | ||
|
|
488e258e3f | ||
|
|
d096d1a941 | ||
|
|
3ef4271e63 | ||
|
|
0a33d35b2b | ||
|
|
b4fedea1db | ||
|
|
4d92964dda | ||
|
|
3443b175ff | ||
|
|
ad3fe9e114 | ||
|
|
d1660d7e81 | ||
|
|
7750b61103 | ||
|
|
eeb1019bbb | ||
|
|
6bbaad8bdb | ||
|
|
1ef4470979 | ||
|
|
3110f462ac | ||
|
|
170e1ac347 | ||
|
|
86b95034cc | ||
|
|
8f6d4d5960 | ||
|
|
a34d2f810b | ||
|
|
db002ab2b1 | ||
|
|
c9c8a1a9c6 | ||
|
|
cdc22bc533 | ||
|
|
1efe98ab46 | ||
|
|
989242810d | ||
|
|
29d3c0c8c1 | ||
|
|
97cc7e53f0 | ||
|
|
4c4544340a | ||
|
|
755fab05ba | ||
|
|
5f295fd57b | ||
|
|
86b888a68e | ||
|
|
4fd8350a96 | ||
|
|
5702426ddd | ||
|
|
9c562d09ea | ||
|
|
59d1c44c23 | ||
|
|
1082f73be7 | ||
|
|
1372626b50 | ||
|
|
c09dacb8ec | ||
|
|
518d64882c | ||
|
|
4f08b9a446 | ||
|
|
a3b7dd542d | ||
|
|
c68936f06d | ||
|
|
b91214f958 | ||
|
|
ff26ffd9c5 | ||
|
|
058a7c97cb | ||
|
|
a50965509d | ||
|
|
3356724481 | ||
|
|
8dcdf68b9f | ||
|
|
ae0f25a0f8 | ||
|
|
148f513bc2 | ||
|
|
29f60bcde5 | ||
|
|
e9ddb24706 | ||
|
|
71e815a9bd | ||
|
|
a55ce680df | ||
|
|
3e47460c3b | ||
|
|
abd6983eee | ||
|
|
ce263b5b1f | ||
|
|
7f15a28a69 | ||
|
|
4ddcb3f0bf | ||
|
|
d76a6a6ca6 | ||
|
|
e9a20254b0 | ||
|
|
42a8d33824 | ||
|
|
d89f00a607 | ||
|
|
41c8c17bc9 | ||
|
|
a3a621945a | ||
|
|
71eedd392d | ||
|
|
ccfcae9dd0 | ||
|
|
f50849422b | ||
|
|
8786a09b8f | ||
|
|
07b750f11c | ||
|
|
ba78b7da3a | ||
|
|
38231ef0d4 | ||
|
|
232d18f8da | ||
|
|
530a8a9c2c | ||
|
|
38bbe8103c | ||
|
|
d2af009d9f | ||
|
|
8a96c7b610 | ||
|
|
bb2da157da | ||
|
|
1c521e0f79 | ||
|
|
aab13c1ec6 | ||
|
|
fd72d6a9b8 | ||
|
|
d73e90e46e | ||
|
|
913f131b3b | ||
|
|
795aeab7a3 | ||
|
|
2ee01adb6b | ||
|
|
b4e246ffb3 | ||
|
|
64995a0bfd | ||
|
|
3173b5fc18 | ||
|
|
ae4d33d7b1 | ||
|
|
d5b2cc884b | ||
|
|
50f6152a71 | ||
|
|
c84ae0493c | ||
|
|
e1dadc045f | ||
|
|
15812081e0 | ||
|
|
5365ebd939 | ||
|
|
e06770a55f | ||
|
|
a931c63ba9 | ||
|
|
47fae91a29 | ||
|
|
df010c4978 | ||
|
|
8060e12d57 | ||
|
|
dd8a74c19e | ||
|
|
f0992dae25 | ||
|
|
2935d13cd0 | ||
|
|
d484c539a9 | ||
|
|
3c511417a5 | ||
|
|
ad6c44bec3 | ||
|
|
dd155507e6 | ||
|
|
866a7415b6 | ||
|
|
230ffd59d4 | ||
|
|
ca4e3e11d2 | ||
|
|
395c3098c4 | ||
|
|
b0219fbb5b | ||
|
|
dbeba59561 | ||
|
|
4104a2db59 | ||
|
|
1f97a8960a | ||
|
|
8597dd63ca | ||
|
|
3fcfb4d11e | ||
|
|
72e3ba99c6 | ||
|
|
27417c53d7 | ||
|
|
db97b6e678 | ||
|
|
ac050bfb37 | ||
|
|
5e75b1cd17 | ||
|
|
565ed9f1fc | ||
|
|
41ab66b704 | ||
|
|
a9d81bd5a2 | ||
|
|
98095927a9 | ||
|
|
2e1e8685e9 | ||
|
|
087fdbbb2c | ||
|
|
42cd9ec18d | ||
|
|
f63861b1d4 | ||
|
|
3233ae556c | ||
|
|
d1e1ea56d1 | ||
|
|
7eede2daeb | ||
|
|
468399ad84 | ||
|
|
200e8cbc30 | ||
|
|
69ab331a6f | ||
|
|
dcb8a354cf | ||
|
|
e625e4750f | ||
|
|
dbcbcad6d1 | ||
|
|
84916fe25b | ||
|
|
535da5e39b | ||
|
|
cd2869863f | ||
|
|
b9766f87c9 | ||
|
|
32829531d3 | ||
|
|
aa82743c25 | ||
|
|
47e9076c9e | ||
|
|
841ad8f55d | ||
|
|
407e778841 | ||
|
|
5b85e2f119 | ||
|
|
49bdb568cc | ||
|
|
a4e7282a0b | ||
|
|
1cfd9e6905 | ||
|
|
064e4a0ed8 | ||
|
|
65d199c65a | ||
|
|
cb61c81836 | ||
|
|
25e1751283 | ||
|
|
e417e0479c | ||
|
|
fe4cada82d | ||
|
|
c92d04376c | ||
|
|
a24a3a54f4 | ||
|
|
8b4e339665 | ||
|
|
6c96f506c8 | ||
|
|
28475e442d | ||
|
|
59e6fdbfa5 | ||
|
|
2848889395 | ||
|
|
3df1e5a547 | ||
|
|
0739ac3a70 | ||
|
|
c4a692ad70 | ||
|
|
1535238770 | ||
|
|
efd8b4b34e | ||
|
|
88125ecf9c | ||
|
|
675e590ccf | ||
|
|
afd89dbb51 | ||
|
|
c961c9ff57 | ||
|
|
2d02658730 | ||
|
|
dfd4b88031 | ||
|
|
52e0b1288a | ||
|
|
d1dd8d7493 | ||
|
|
ca73265f88 | ||
|
|
5bdec28099 | ||
|
|
bd0a3dd3fb | ||
|
|
7a9994004c | ||
|
|
45b9dd3622 | ||
|
|
269bbf8783 | ||
|
|
fa5bbec9e3 | ||
|
|
ee3a1f3a79 | ||
|
|
b9e29fddea | ||
|
|
c9a0dd368d | ||
|
|
2db3589f05 | ||
|
|
702ef3c569 | ||
|
|
0f21b61529 | ||
|
|
a568ab66dd | ||
|
|
15dfc164e6 | ||
|
|
bbb5ecba1d | ||
|
|
63b5393dea | ||
|
|
1b8abc2ddd | ||
|
|
8ee4e00181 | ||
|
|
757057de39 | ||
|
|
5ce2eedbfd | ||
|
|
fca6951d36 | ||
|
|
dc83349537 | ||
|
|
c159b16860 | ||
|
|
4fba35b68f | ||
|
|
4ca8cfcaa1 | ||
|
|
58de984524 | ||
|
|
b615213907 | ||
|
|
807f7c1b66 | ||
|
|
77994b991f | ||
|
|
677dd475f7 | ||
|
|
0e6a63d60e | ||
|
|
4fc4d7613a | ||
|
|
3cf1a9f33b | ||
|
|
c1b60c148e | ||
|
|
9a3b28f5f5 | ||
|
|
6aebd2904f | ||
|
|
d0671a25d6 | ||
|
|
8e17d2a6bd | ||
|
|
af7a71753f | ||
|
|
c0dd1518e1 | ||
|
|
3b5a1c1988 | ||
|
|
774c2b2327 | ||
|
|
71b1662b55 | ||
|
|
9317f4cd6b | ||
|
|
00b4a9bab4 | ||
|
|
48a091842a | ||
|
|
7e9ca7cc79 | ||
|
|
d333cf55d1 | ||
|
|
cb45ae1590 | ||
|
|
3c85f1324d | ||
|
|
ee3f26b2f3 | ||
|
|
67f5e47dc9 | ||
|
|
8b530854f6 | ||
|
|
91e503e904 | ||
|
|
cf287ab9bf | ||
|
|
ad51e92d90 | ||
|
|
40f80e8040 | ||
|
|
5efbeaba92 | ||
|
|
e5eb9a7eba | ||
|
|
0ea7375fe9 | ||
|
|
7db9e99fd7 | ||
|
|
da3248894e | ||
|
|
8934133874 | ||
|
|
0ec184ce4d | ||
|
|
57ff66ab27 | ||
|
|
8bfa604584 | ||
|
|
c541c27485 | ||
|
|
fd02e00da6 | ||
|
|
729ee19585 | ||
|
|
e14853dc11 | ||
|
|
c439412a3c | ||
|
|
035728e37f | ||
|
|
4728449137 | ||
|
|
e94cc41ca8 | ||
|
|
ab4856c81e | ||
|
|
7861ac7d63 | ||
|
|
cf37956784 | ||
|
|
0b39e94047 | ||
|
|
0dce6293d5 | ||
|
|
8b181cbe43 | ||
|
|
290a12ce02 | ||
|
|
8eab3c13ef | ||
|
|
bf3fba58e2 | ||
|
|
34991a722a | ||
|
|
cca6c16928 | ||
|
|
1b379bb426 | ||
|
|
294c69524f | ||
|
|
441e6da0ca | ||
|
|
09da352175 | ||
|
|
552533f82e | ||
|
|
8ddbadf6fc | ||
|
|
92297ceba9 | ||
|
|
766496459d | ||
|
|
510c4b287c | ||
|
|
bc9122cf7e | ||
|
|
8cb3500690 | ||
|
|
1a8c2c3045 | ||
|
|
9295318794 | ||
|
|
81ea96019a | ||
|
|
818c416d81 | ||
|
|
c020a298ef | ||
|
|
d960ec048c | ||
|
|
f4bca52712 | ||
|
|
2f73856d17 | ||
|
|
2608a12cf3 | ||
|
|
dc3acc8e08 | ||
|
|
f5aa3f3de5 | ||
|
|
e43f7de881 | ||
|
|
96f17784ec | ||
|
|
02b3fa60c6 | ||
|
|
caa35ed6e3 | ||
|
|
dc9a386af1 | ||
|
|
120b51e9e6 | ||
|
|
626e6d01ee | ||
|
|
ac2ca92d33 | ||
|
|
781dc35e52 | ||
|
|
ac8896ed6d | ||
|
|
ca7ac564da | ||
|
|
4551eae74f | ||
|
|
dd279910bd | ||
|
|
ef47a70089 | ||
|
|
a2d7bbc58c | ||
|
|
0ed41e3776 | ||
|
|
babcec1f5d | ||
|
|
9e25e1d00b | ||
|
|
e9e0407dbc | ||
|
|
cfd7be25af | ||
|
|
74e595b236 | ||
|
|
f46449fb99 | ||
|
|
54ebdcb38b | ||
|
|
1a3baf2a98 | ||
|
|
02127fa123 | ||
|
|
16f8f3cd00 | ||
|
|
a9fd4db245 | ||
|
|
f966266bdc | ||
|
|
c5b4b88647 | ||
|
|
fe0be3e6ec | ||
|
|
733a561cf8 | ||
|
|
61e2d008fe | ||
|
|
95bd8492d2 | ||
|
|
5db01b860d | ||
|
|
e3409be81b | ||
|
|
bb9591ce10 | ||
|
|
ab65c01408 | ||
|
|
a47125d29b | ||
|
|
3160ac32b4 | ||
|
|
2de0c32d32 | ||
|
|
fb7e496e4e | ||
|
|
9956142bba | ||
|
|
188a60ade7 | ||
|
|
b701da15ff | ||
|
|
eb20386bac | ||
|
|
757ea6038f | ||
|
|
288a87d551 | ||
|
|
e6313ceeb9 | ||
|
|
74c311be96 | ||
|
|
0ffb55c4b9 | ||
|
|
f76c3e106a | ||
|
|
e83f9093f5 | ||
|
|
40cafbd743 | ||
|
|
13d75b1645 | ||
|
|
95ca397072 | ||
|
|
cdfea86283 | ||
|
|
06e7b30963 | ||
|
|
761455aeb9 | ||
|
|
c6797363f5 | ||
|
|
a7ca4499c3 | ||
|
|
e910e88b35 | ||
|
|
92548a3617 | ||
|
|
92b13a5057 | ||
|
|
4cad57f749 | ||
|
|
5cb7fc87c9 | ||
|
|
1eaa76cb3a | ||
|
|
72a7b2b511 | ||
|
|
35c4392033 | ||
|
|
df11141d17 | ||
|
|
f8b41cea91 | ||
|
|
c4f5ae366c | ||
|
|
d6ea37777f | ||
|
|
547c123075 | ||
|
|
5d09bce8f4 | ||
|
|
18fd97410e | ||
|
|
1ffdc4ad75 | ||
|
|
0fceff073c | ||
|
|
dee05cb21f | ||
|
|
2b70c8bfa5 | ||
|
|
3861737918 | ||
|
|
ee15740d75 | ||
|
|
164e0ffd09 | ||
|
|
878d1d86f3 | ||
|
|
548dc7dae7 | ||
|
|
367b9096c5 | ||
|
|
12c9911434 | ||
|
|
d6f63ee2e9 | ||
|
|
580e876009 | ||
|
|
7aacd73460 | ||
|
|
c692632b7f | ||
|
|
68595d4acf | ||
|
|
78d0e14ffd | ||
|
|
28f609858f | ||
|
|
9d72c7b22d | ||
|
|
d6f4bca6d1 | ||
|
|
1397d14c4e | ||
|
|
0002582991 | ||
|
|
21b8008297 | ||
|
|
906fac1e62 | ||
|
|
8096a4e185 | ||
|
|
d3274cced7 | ||
|
|
949c4704f4 | ||
|
|
6d32393145 | ||
|
|
54f03256f7 | ||
|
|
715d1cb59b | ||
|
|
abe9ddd638 | ||
|
|
fb75953468 | ||
|
|
417090489c | ||
|
|
f6e91fbc03 | ||
|
|
d7c1954a39 | ||
|
|
ddc4785fed | ||
|
|
402fa87e32 | ||
|
|
525171a69a | ||
|
|
c5a8134bce | ||
|
|
d9cf3f50ee | ||
|
|
9a55e35055 | ||
|
|
9660b0c689 | ||
|
|
96b174c78a | ||
|
|
a269c0292f | ||
|
|
365b871cf1 | ||
|
|
31524f9d0e | ||
|
|
b646937d23 | ||
|
|
d6a70bbb9b | ||
|
|
55cd6b7c59 | ||
|
|
4362453f90 | ||
|
|
36aa144121 | ||
|
|
bb91a74308 | ||
|
|
b8db6e2645 | ||
|
|
449f85ee5c | ||
|
|
c1e6614423 | ||
|
|
b17afbd8e0 | ||
|
|
b3e633b119 | ||
|
|
4eb9ff6dae | ||
|
|
e3fded9373 | ||
|
|
53c9cbe81c | ||
|
|
b68e8a2cef | ||
|
|
5742670a90 | ||
|
|
b66498545a | ||
|
|
7a6d328d5a | ||
|
|
2cfcdad4de | ||
|
|
4dc61634bd | ||
|
|
51731cd178 | ||
|
|
14a541cc49 | ||
|
|
9d54cc48dd | ||
|
|
ed5a13b269 | ||
|
|
971a159eae | ||
|
|
83e197aacd | ||
|
|
9884ec2e82 | ||
|
|
52a4059f98 | ||
|
|
c49653ebc8 | ||
|
|
9be7c75dcc | ||
|
|
5b97c3fd1c | ||
|
|
3a9eb88197 | ||
|
|
d83d6c6483 | ||
|
|
6fb620cac6 | ||
|
|
cb2ab3e437 | ||
|
|
03dc8e4245 | ||
|
|
2df1f39ef9 | ||
|
|
3b9a91c010 | ||
|
|
64e7baec3c | ||
|
|
06feb84ba9 | ||
|
|
b5f1b32a3d | ||
|
|
647e116bc5 | ||
|
|
874b604294 | ||
|
|
1f8a7975ce | ||
|
|
293417125a | ||
|
|
5b09097fd2 | ||
|
|
c03679d20e | ||
|
|
ef21d83c35 | ||
|
|
89871cd418 | ||
|
|
7d90a11d9c | ||
|
|
ec19f3e786 | ||
|
|
de879c7af2 | ||
|
|
f707f29249 | ||
|
|
4798ddda63 | ||
|
|
4f28d38dc1 | ||
|
|
2356bfa7fc | ||
|
|
643fa604d1 | ||
|
|
a982875558 | ||
|
|
803345d09d | ||
|
|
f1d98a68c5 | ||
|
|
2c82c279e2 | ||
|
|
1e33689d7b | ||
|
|
8793aa506b | ||
|
|
6d08d1551b | ||
|
|
2949b96a46 | ||
|
|
cdb5fc0560 | ||
|
|
f37ee00030 | ||
|
|
df7b9a3e5b | ||
|
|
bb6d236495 | ||
|
|
7c2b7e5a47 | ||
|
|
5f15cce3f3 | ||
|
|
199da71be0 | ||
|
|
303ac039e0 | ||
|
|
067a88eec1 | ||
|
|
34ea244e82 | ||
|
|
68717d592c | ||
|
|
c0c9814c10 | ||
|
|
0f1a9eb8f7 | ||
|
|
d9aae1ade7 | ||
|
|
3e69dd4877 | ||
|
|
918d54f466 | ||
|
|
25e704d6ce | ||
|
|
d8d8607592 | ||
|
|
2e309cab0d | ||
|
|
97b6d240fc | ||
|
|
9e38142c4f | ||
|
|
5dddfbebc9 | ||
|
|
ddedf2cbdd | ||
|
|
71e47d22ef | ||
|
|
08ac65e372 | ||
|
|
50ed9e29d8 | ||
|
|
e492c2801e | ||
|
|
5259f6a503 | ||
|
|
17bb856242 | ||
|
|
df1cb2ccc2 | ||
|
|
5a90d51e36 | ||
|
|
b8f2ebdab7 | ||
|
|
78b9ad532b | ||
|
|
88bb593b84 | ||
|
|
f67777b9a7 | ||
|
|
a5ba42285f | ||
|
|
33e440ffec | ||
|
|
8fdb13765e | ||
|
|
88171da0ab | ||
|
|
7db5f8c30c | ||
|
|
69ab1d3953 | ||
|
|
92f3225144 | ||
|
|
1885298222 | ||
|
|
7ae9d2671e | ||
|
|
c6ceba8ea5 | ||
|
|
22e18545ed | ||
|
|
f20b4f285f | ||
|
|
d06407fcde | ||
|
|
8410175f60 | ||
|
|
3bdc7f428b | ||
|
|
a5009bf8a5 | ||
|
|
018e15483d | ||
|
|
d8b56b9feb | ||
|
|
63b6ab225f | ||
|
|
0700d481d1 | ||
|
|
80ad788028 | ||
|
|
f55bacc83d | ||
|
|
12ed1885d8 | ||
|
|
8e64b18102 | ||
|
|
32f609e9ad | ||
|
|
ea87f2a30b | ||
|
|
75a98f9c67 | ||
|
|
974887d13f | ||
|
|
c6983a5f44 | ||
|
|
0d6daa1cd6 | ||
|
|
6a351fd38a | ||
|
|
6c6553bf85 | ||
|
|
7e8ba18ba1 | ||
|
|
aac076f19a | ||
|
|
ecf0260a9f | ||
|
|
470e657e3e | ||
|
|
d0774614c8 | ||
|
|
8d852c5269 | ||
|
|
e93e2aa5f4 | ||
|
|
07ed9fbc48 | ||
|
|
c0ceb4f993 | ||
|
|
9781e8350c | ||
|
|
b1afd8f786 | ||
|
|
668856dccc | ||
|
|
e59089f706 | ||
|
|
295259a456 | ||
|
|
8ebb5cff5a | ||
|
|
8a28bcafec | ||
|
|
0cc1676e6c | ||
|
|
b434903739 | ||
|
|
5b3477af3e | ||
|
|
e2050c825e | ||
|
|
faf8d1a7d0 | ||
|
|
e15dd7e69b | ||
|
|
cee6a4879a | ||
|
|
f5b5148f82 | ||
|
|
d3f6b11fe5 | ||
|
|
1eeb265f4e | ||
|
|
2f8d23390a | ||
|
|
c4d01b65b7 | ||
|
|
d415a7fc5c | ||
|
|
0b89738ec0 | ||
|
|
e33fc93a1d | ||
|
|
656b318be3 | ||
|
|
562dece6f9 | ||
|
|
fa30b432a9 | ||
|
|
20af0350aa | ||
|
|
30e8b93786 | ||
|
|
b7d067123c | ||
|
|
38dd0018e7 | ||
|
|
e889e406ae | ||
|
|
83b6236ed7 | ||
|
|
41cab5b290 | ||
|
|
99a716ccaa | ||
|
|
ecca904aef | ||
|
|
a2a740f371 | ||
|
|
c66b1a2b96 | ||
|
|
52b2170f8f | ||
|
|
4264c0c9d2 | ||
|
|
061b90ce90 | ||
|
|
38aa534cf5 | ||
|
|
234d42f1f1 | ||
|
|
a226ae5d4a | ||
|
|
1ba0505c4b | ||
|
|
bc27f0548a | ||
|
|
17d376d4d4 | ||
|
|
1547ea84c6 | ||
|
|
c8e50ff7fc | ||
|
|
5a9b9771bc | ||
|
|
7def05e112 | ||
|
|
42cfd9dcc4 | ||
|
|
7868a1971e | ||
|
|
9c929fccca | ||
|
|
18f4600ca4 | ||
|
|
1ea3531d26 | ||
|
|
11e2deaa23 | ||
|
|
a68b78e5a4 | ||
|
|
c3674e0a2f | ||
|
|
64584cc6cf | ||
|
|
7368ff257c | ||
|
|
54736baf33 | ||
|
|
1528fdfed1 | ||
|
|
c05d1401ea | ||
|
|
4be2034588 | ||
|
|
7bde4c1033 | ||
|
|
f00e2964f3 | ||
|
|
1ec4e4b8f0 | ||
|
|
330d4fbe39 | ||
|
|
8cbf2bc050 | ||
|
|
77350539a7 | ||
|
|
d530c2aa4d | ||
|
|
d83ecd3b94 | ||
|
|
fe79580e86 | ||
|
|
e0d0ee0ad0 | ||
|
|
1d1f5940d7 | ||
|
|
ad3a6fc8fc | ||
|
|
533e843cdb | ||
|
|
833c33e26e | ||
|
|
949ba46a16 | ||
|
|
62c9497365 | ||
|
|
fef9ba44cd | ||
|
|
38f97a81c8 | ||
|
|
e13349949a | ||
|
|
2d059eabc3 | ||
|
|
006fe56d18 | ||
|
|
2cf8b6961c | ||
|
|
9c519e1ea4 | ||
|
|
f1db561262 | ||
|
|
f0cf1b7d4c | ||
|
|
7b20cd6443 | ||
|
|
278c51d056 | ||
|
|
caed081f82 | ||
|
|
7276da7665 | ||
|
|
90b8729129 | ||
|
|
c24f198ed0 | ||
|
|
c640a251b6 | ||
|
|
a6f4f2d2d5 |
No files matched your search
@@ -0,0 +1,2 @@
|
||||
github: Multiverse
|
||||
open_collective: multiverse-plugins
|
||||
@@ -18,10 +18,10 @@ body:
|
||||
|
||||
When completing the report, please ensure all fields are filled with the correct details requested. Failure to do so will result in your issue being closed.
|
||||
- type: input
|
||||
id: mutliverse-version-info
|
||||
id: multiverse-version-info
|
||||
attributes:
|
||||
label: '`/mv version -p` output'
|
||||
description: Run `/mv version -p` in the console, then copy and paste the link from the output of the command into this box.
|
||||
label: '`/mv dumps` output'
|
||||
description: Run `/mv dumps` in the console, then copy and paste the link from the output of the command into this box. If `/mv dumps` command is not available, update multiverse to v5.
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
@@ -29,7 +29,7 @@ body:
|
||||
attributes:
|
||||
label: Server logs
|
||||
description: >
|
||||
Include full startup log and console error (if any). upload all relevant logs to either https://paste.gg
|
||||
Include full startup log and console error (if any). upload all relevant logs to either https://pastes.dev
|
||||
or https://gist.github.com, save and the paste the link in this box.
|
||||
validations:
|
||||
required: true
|
||||
@@ -54,7 +54,7 @@ body:
|
||||
id: reproduce-steps
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Provide detailed intructions to trigger the bug.
|
||||
description: Provide detailed instructions to trigger the bug.
|
||||
placeholder: |
|
||||
Example:
|
||||
1. Start a server with only multiverse installed.
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
name: 'Dispatch: Create Release'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_type:
|
||||
description: 'Stable or pre-release'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- prerelease
|
||||
- release
|
||||
version_bump:
|
||||
description: 'Version bump type'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- major
|
||||
- minor
|
||||
- patch
|
||||
|
||||
jobs:
|
||||
github_release:
|
||||
uses: ./.github/workflows/call.github_release.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
release_mode: ${{ inputs.release_type }}
|
||||
version_bump: ${{ inputs.version_bump }}
|
||||
|
||||
platform_uploads:
|
||||
needs: github_release
|
||||
if: needs.github_release.outputs.release_created == 'true'
|
||||
uses: ./.github/workflows/call.platform_uploads.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
target_tag: ${{ needs.github_release.outputs.tag_name }}
|
||||
upload_modrinth: 'true'
|
||||
upload_dbo: 'false'
|
||||
upload_hangar: 'false'
|
||||
@@ -0,0 +1,55 @@
|
||||
name: 'Dispatch: Deploy Javadoc'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
target_tag:
|
||||
description: 'Version to generate javadoc'
|
||||
required: true
|
||||
replace_latest:
|
||||
description: 'Replace the latest folder'
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
javadocs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.target_tag }}
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'adopt'
|
||||
cache: gradle
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: build javadoc
|
||||
run: ./gradlew javadoc
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_VERSION: ${{ inputs.target_tag }}
|
||||
|
||||
- name: Copy javadoc to deploy folder
|
||||
run: |
|
||||
mkdir -p build/docs/javadoc-deploy/${{ inputs.target_tag }}
|
||||
cp -r build/docs/javadoc/* build/docs/javadoc-deploy/${{ inputs.target_tag }}
|
||||
|
||||
- name: Copy javadoc to latest folder
|
||||
if: inputs.replace_latest
|
||||
run: |
|
||||
mkdir -p build/docs/javadoc-deploy/latest
|
||||
cp -r build/docs/javadoc/* build/docs/javadoc-deploy/latest
|
||||
|
||||
- name: Deploy javadoc to gh pages
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
folder: build/docs/javadoc-deploy
|
||||
branch: javadoc
|
||||
target-folder: javadoc
|
||||
clean: false
|
||||
commit-message: Deploy javadoc for ${{ inputs.target_tag }}
|
||||
@@ -43,28 +43,28 @@ jobs:
|
||||
echo "version_bump: ${{ inputs.version_bump }}"
|
||||
echo "promote_from: ${{ inputs.promote_from }}"
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.promote_from }}
|
||||
|
||||
- uses: actions/setup-java@v3
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '11'
|
||||
java-version: '21'
|
||||
distribution: 'adopt'
|
||||
cache: gradle
|
||||
|
||||
- name: Validate Gradle wrapper
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Build and test
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
arguments: clean build -x assemble -x shadowJar
|
||||
- name: Build to test
|
||||
id: test
|
||||
run: ./gradlew clean build -x assemble -x shadowJar
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create release
|
||||
id: release
|
||||
if: steps.test.outcome == 'success'
|
||||
uses: benwoo1110/semantic-release-action@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -74,18 +74,58 @@ jobs:
|
||||
|
||||
- name: Publish package
|
||||
if: steps.release.outputs.release_created == 'true'
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
arguments: publish -x test
|
||||
run: >
|
||||
./gradlew publish -x test
|
||||
-PmultiverseUsername=${{ secrets.REPOSILITE_REPO_USERNAME }}
|
||||
-PmultiversePassword=${{ secrets.REPOSILITE_REPO_PASSWORD }}
|
||||
env:
|
||||
GITHUB_VERSION: ${{ steps.release.outputs.publish_version }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload release artifact
|
||||
- name: Build for upload
|
||||
id: build
|
||||
if: steps.release.outputs.release_created == 'true'
|
||||
run: ./gradlew build -x test
|
||||
env:
|
||||
GITHUB_VERSION: ${{ steps.release.outputs.tag_name }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload release artifact
|
||||
if: steps.build.outcome == 'success'
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: build/libs/${{ inputs.plugin_name }}-${{ steps.release.outputs.publish_version }}.jar
|
||||
file: build/libs/${{ inputs.plugin_name }}-${{ steps.release.outputs.tag_name }}.jar
|
||||
asset_name: ${{ inputs.plugin_name }}-${{ steps.release.outputs.tag_name }}.jar
|
||||
tag: ${{ steps.release.outputs.tag_name }}
|
||||
|
||||
- name: Generate javadoc
|
||||
id: javadoc
|
||||
if: steps.build.outcome == 'success'
|
||||
run: ./gradlew javadoc -x test
|
||||
env:
|
||||
GITHUB_VERSION: ${{ steps.release.outputs.publish_version }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload javadoc
|
||||
if: steps.javadoc.outcome == 'success'
|
||||
run: |
|
||||
mkdir -p build/docs/javadoc-deploy/${{ steps.release.outputs.publish_version }}
|
||||
cp -r build/docs/javadoc/* build/docs/javadoc-deploy/${{ steps.release.outputs.publish_version }}
|
||||
|
||||
- name: Override latest javadoc for stable release
|
||||
if: steps.javadoc.outcome == 'success' && steps.release.outputs.release_type == 'release'
|
||||
run: |
|
||||
mkdir -p build/docs/javadoc-deploy/latest
|
||||
cp -r build/docs/javadoc/* build/docs/javadoc-deploy/latest
|
||||
|
||||
- name: Deploy javadoc to gh pages
|
||||
if: steps.javadoc.outcome == 'success'
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
folder: build/docs/javadoc-deploy
|
||||
branch: javadoc
|
||||
target-folder: javadoc
|
||||
clean: false
|
||||
commit-message: Deploy javadoc for ${{ steps.release.outputs.tag_name }}
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
files: '["${{ github.workspace }}/${{ inputs.plugin_name }}-${{ steps.release-info.outputs.tag_name }}.jar"]'
|
||||
name: ${{ steps.release-info.outputs.tag_name }}
|
||||
changelog: ${{ steps.release-artifact.outputs.body }}
|
||||
game_versions: 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2, 1.18.1, 1.18, 1.17.1, 1.17, 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16, 1.15.2, 1.15.1, 1.15, 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14, 1.13.2, 1.13.1, 1.13
|
||||
game_versions: 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2
|
||||
version_type: ${{ steps.parse-release-type.outputs.release_type }}
|
||||
loaders: bukkit, spigot, paper
|
||||
dependencies: ${{ inputs.modrinth_dependencies }}
|
||||
@@ -121,7 +121,7 @@ jobs:
|
||||
changelog: ${{ steps.release-artifact.outputs.body }}
|
||||
changelog_type: markdown
|
||||
display_name: ${{ steps.release-info.outputs.tag_name }}
|
||||
game_versions: 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2, 1.18.1, 1.18, 1.17, 1.16, 1.15, 1.14, 1.13
|
||||
game_versions: 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2
|
||||
release_type: ${{ steps.parse-release-type.outputs.release_type }}
|
||||
project_relations: ${{ inputs.dbo_project_relations }}
|
||||
file_path: ${{ github.workspace }}/${{ inputs.plugin_name }}-${{ steps.release-info.outputs.tag_name }}.jar
|
||||
@@ -136,5 +136,5 @@ jobs:
|
||||
channel: ${{ steps.parse-release-type.outputs.release_type }}
|
||||
files: '[{"path": "${{ github.workspace }}/${{ inputs.plugin_name }}-${{ steps.release-info.outputs.tag_name }}.jar", "platforms": ["PAPER"]}]'
|
||||
description: ${{ steps.release-artifact.outputs.body }}
|
||||
platform_dependencies: '{"PAPER": ["1.13-1.20.1"]}'
|
||||
platform_dependencies: '{"PAPER": ["1.18.2-1.21.8"]}'
|
||||
plugin_dependencies: ${{ inputs.hangar_plugin_dependencies }}
|
||||
@@ -9,32 +9,40 @@ on:
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
test:
|
||||
test-and-artifact:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-java@v3
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'adopt'
|
||||
cache: gradle
|
||||
|
||||
- name: Validate Gradle wrapper
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Run unit tests
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
arguments: build
|
||||
run: ./gradlew build
|
||||
env:
|
||||
GITHUB_VERSION: pr${{ github.event.pull_request.number }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Artifact output
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ inputs.plugin_name }}-pr${{ github.event.pull_request.number }}
|
||||
path: build/libs/${{ inputs.plugin_name }}-pr${{ github.event.pull_request.number }}.jar
|
||||
|
||||
comment-artifact:
|
||||
needs: test-and-artifact
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: benwoo1110/artifact-comment-action@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -1,22 +1,21 @@
|
||||
<p align="center">
|
||||
<img src="config/multiverse2-long.png" alt="Multiverse Logo">
|
||||
<img src="config/multiverse-banner.png" alt="Multiverse Logo">
|
||||
</p>
|
||||
|
||||
[](https://modrinth.com/plugin/multiverse-core)
|
||||
[](https://hangar.papermc.io/Multiverse/Multiverse-Core)
|
||||
[](https://dev.bukkit.org/projects/multiverse-core)
|
||||
[](https://www.spigotmc.org/resources/multiverse-core.390/)
|
||||
|
||||
[](https://dev.bukkit.org/projects/multiverse-core)
|
||||
[](https://ci.onarandombox.com/job/Multiverse-Core/)
|
||||
[](https://discord.gg/NZtfKky)
|
||||
[](https://patreon.com/dumptruckman)
|
||||
[](LICENSE.md)
|
||||
[](https://hangar.papermc.io/Multiverse/Multiverse-Core)
|
||||
[](https://dev.bukkit.org/projects/multiverse-core)
|
||||
[](https://www.spigotmc.org/resources/multiverse-core.390/)
|
||||
|
||||
[](https://github.com/Multiverse/Multiverse-Core/releases/latest)
|
||||
[](https://github.com/Multiverse/Multiverse-Core/releases)
|
||||
[](https://discord.gg/NZtfKky)
|
||||
[](https://github.com/sponsors/Multiverse)
|
||||
[](https://opencollective.com/multiverse-plugins)
|
||||
|
||||
# About
|
||||
|
||||
[Multiverse](https://dev.bukkit.org/projects/multiverse-core) was created at the dawn of Bukkit multiworld support. It has since then grown into a **complete world management solution!** Multiverse provides the easiest to use world management solution for your Minecraft server, big or small, and with great addons like [Portals](https://dev.bukkit.org/projects/multiverse-portals) and [NetherPortals](https://dev.bukkit.org/projects/multiverse-netherportals/), what's not to love!
|
||||
[Multiverse](https://modrinth.com/plugin/multiverse-core) was created at the dawn of Bukkit multiworld support. It has since then grown into a **complete world management solution!** Multiverse provides the easiest to use world management solution for your Minecraft server, big or small, and with great addons like [Portals](https://dev.bukkit.org/projects/multiverse-portals) and [NetherPortals](https://dev.bukkit.org/projects/multiverse-netherportals/), what's not to love!
|
||||
|
||||
Now it's time to create your very own Multiverse server, do check out our [Wiki](https://github.com/Multiverse/Multiverse-Core/wiki) and [Usage Guide](https://github.com/Multiverse/Multiverse-Core/wiki/Basics) to get started. Feel free to hop onto our [Discord](https://discord.gg/NZtfKky) if you have any question or just want to have a chat with us!
|
||||
|
||||
@@ -27,22 +26,24 @@ Now it's time to create your very own Multiverse server, do check out our [Wiki]
|
||||
* [Multiverse-Inventories](https://github.com/Multiverse/Multiverse-Inventories) -> Have separated players stats and inventories per world or per group of worlds.
|
||||
* [Multiverse-SignPortals](https://github.com/Multiverse/Multiverse-SignPortals) -> Signs as teleporters!
|
||||
|
||||
## Usage Guide
|
||||
|
||||
We have a cool new website hosting our Wiki: https://mvplugins.org
|
||||
|
||||
## Building
|
||||
Simply build the source with Gradle:
|
||||
```
|
||||
./gradlew build
|
||||
```
|
||||
More details are available on the [build instructions wiki page](https://github.com/Multiverse/Multiverse-Core/wiki/Building).
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
**Want to help improve Multiverse?** There are several ways you can support and contribute to the project.
|
||||
* Take a look at our "Bug: Unconfirmed" issues, where you can find issues that need extra testing and investigation.
|
||||
* Want others to love Multiverse too? You can join the [Multiverse Discord community](https://discord.gg/NZtfKky) and help others with issues and setup!
|
||||
* A Multiverse guru? You can update our [Wiki](https://github.com/Multiverse/Multiverse-Core/wiki) with your latest tip, tricks and guides! The wiki open for all to edit and improve.
|
||||
* A Multiverse guru? You can update our [Wiki](https://github.com/Multiverse/multiverse-web) with your latest tip, tricks and guides! The wiki open for all to edit and improve.
|
||||
* Love coding? You could look at ["State: Open to PR"](https://github.com/Multiverse/Multiverse-Core/labels/State%3A%20Open%20to%20PR) and ["Resolution: Accepted"](https://github.com/Multiverse/Multiverse-Core/labels/Resolution%3A%20Accepted) issues. We're always happy to receive bug fixes and feature additions as [pull requests](https://www.freecodecamp.org/news/how-to-make-your-first-pull-request-on-github-3/).
|
||||
* If you'd like to make a financial contribution to the project, do consider joining our [Patreon](https://www.patreon.com/dumptruckman) or make a one-time donation [here](https://paypal.me/dumptruckman)!
|
||||
* If you'd like to make a financial contribution to the project, do consider donating to our [Github Sponsors](https://github.com/sponsors/Multiverse) or [Open Collective](https://opencollective.com/multiverse-plugins)!
|
||||
|
||||
Additionally, we would like to give a big thanks to everyone that has supported Multiverse over the years, as well as those in the years to come. Thank you!
|
||||
|
||||
|
||||
+31
-235
@@ -1,50 +1,13 @@
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'maven-publish'
|
||||
id 'com.github.johnrengelman.shadow' version '7.1.2'
|
||||
id "org.jetbrains.kotlin.jvm" version "1.8.10"
|
||||
id 'org.mvplugins.multiverse-plugin' version '1.2.1'
|
||||
}
|
||||
|
||||
version = System.getenv('GITHUB_VERSION') ?: 'local'
|
||||
group = 'com.onarandombox.multiversecore'
|
||||
group = 'org.mvplugins.multiverse.core'
|
||||
description = 'Multiverse-Core'
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(17))
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
|
||||
maven {
|
||||
url = uri('https://hub.spigotmc.org/nexus/content/repositories/snapshots/')
|
||||
}
|
||||
|
||||
maven {
|
||||
url = uri('https://repo.onarandombox.com/content/groups/public')
|
||||
}
|
||||
|
||||
maven {
|
||||
url = uri('https://hub.spigotmc.org/nexus/content/groups/public/')
|
||||
}
|
||||
|
||||
maven {
|
||||
url = uri('https://jitpack.io')
|
||||
}
|
||||
|
||||
maven {
|
||||
url = uri('https://repo.minebench.de/')
|
||||
}
|
||||
|
||||
maven {
|
||||
url = uri('https://repo.maven.apache.org/maven2/')
|
||||
}
|
||||
|
||||
maven {
|
||||
name = 'aikar repo'
|
||||
url = uri('https://repo.aikar.co/content/groups/aikar/')
|
||||
@@ -56,179 +19,61 @@ repositories {
|
||||
}
|
||||
|
||||
maven {
|
||||
name = 'PlaceholderAPI'
|
||||
url = 'https://repo.extendedclip.com/content/repositories/placeholderapi/'
|
||||
}
|
||||
|
||||
maven {
|
||||
name = 'papermc repo'
|
||||
url = 'https://repo.papermc.io/repository/maven-public/'
|
||||
name = "helpchatRepoReleases"
|
||||
url = uri("https://repo.helpch.at/releases/")
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
// Add configuration for server API
|
||||
compileOnly.extendsFrom serverApi
|
||||
runtimeClasspath.extendsFrom serverApi
|
||||
|
||||
// Add configuration for external plugins
|
||||
implementation.extendsFrom externalPlugin
|
||||
|
||||
// Add configuration for dependencies that will be included in fat jar
|
||||
compileClasspath.extendsFrom shadowed
|
||||
testCompileClasspath.extendsFrom shadowed
|
||||
testRuntimeClasspath.extendsFrom shadowed
|
||||
oldTestCompileClasspath.extendsFrom shadowed
|
||||
oldTestRuntimeClasspath.extendsFrom shadowed
|
||||
|
||||
// Add configuration for old tests
|
||||
oldTestImplementation.extendsFrom implementation
|
||||
oldTestRuntime.extendsFrom runtime
|
||||
configure(apiDependencies) {
|
||||
serverApiVersion = '1.21.8-R0.1-SNAPSHOT'
|
||||
mockBukkitServerApiVersion = '1.21'
|
||||
mockBukkitVersion = '4.69.2'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
serverApi 'org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT'
|
||||
|
||||
// Economy
|
||||
externalPlugin('com.github.MilkBowl:VaultAPI:1.7.1') {
|
||||
exclude group: 'org.bukkit', module: 'bukkit'
|
||||
}
|
||||
|
||||
// PlaceholderAPI
|
||||
externalPlugin 'me.clip:placeholderapi:2.11.3'
|
||||
externalPlugin 'me.clip:placeholderapi:2.11.6'
|
||||
|
||||
// Command Framework
|
||||
shadowed 'co.aikar:acf-paper:0.5.1-SNAPSHOT'
|
||||
|
||||
// Config
|
||||
shadowed('me.main__.util:SerializationConfig:1.7') {
|
||||
exclude group: 'org.bukkit', module: 'bukkit'
|
||||
}
|
||||
shadowed('io.github.townyadvanced.commentedconfiguration:CommentedConfiguration:1.0.1') {
|
||||
exclude group: 'org.spigotmc', module: 'spigot-api'
|
||||
}
|
||||
|
||||
// Utils
|
||||
shadowed 'io.vavr:vavr:0.10.4'
|
||||
shadowed 'org.glassfish.hk2:hk2-locator:3.0.3'
|
||||
shadowed 'io.vavr:vavr:0.10.7'
|
||||
shadowed 'org.glassfish.hk2:hk2-locator:3.1.1'
|
||||
shadowed('org.glassfish.hk2:hk2-inhabitant-generator:3.1.1') {
|
||||
exclude group: 'org.apache.maven', module: 'maven-core'
|
||||
}
|
||||
shadowed('com.dumptruckman.minecraft:Logging:1.1.1') {
|
||||
exclude group: 'junit', module: 'junit'
|
||||
}
|
||||
shadowed 'de.themoep.idconverter:mappings:1.2-SNAPSHOT'
|
||||
shadowed 'org.bstats:bstats-bukkit:2.2.1'
|
||||
shadowed 'net.minidev:json-smart:2.4.9'
|
||||
shadowed 'org.jetbrains:annotations:22.0.0'
|
||||
shadowed('org.bstats:bstats-bukkit:3.1.0') {
|
||||
exclude group: 'org.bukkit', module: 'bukkit'
|
||||
}
|
||||
shadowed 'net.minidev:json-smart:2.5.2'
|
||||
shadowed 'org.jetbrains:annotations:26.0.2'
|
||||
shadowed 'io.papermc:paperlib:1.0.8'
|
||||
|
||||
// Tests
|
||||
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.10'
|
||||
testImplementation 'com.github.seeseemelk:MockBukkit-v1.20:3.20.2'
|
||||
testImplementation('com.googlecode.json-simple:json-simple:1.1.1') {
|
||||
exclude group: 'junit', module: 'junit'
|
||||
}
|
||||
testImplementation 'org.jetbrains.kotlin:kotlin-test'
|
||||
testImplementation 'com.natpryce:hamkrest:1.8.0.1'
|
||||
testImplementation 'org.mockito.kotlin:mockito-kotlin:4.1.0'
|
||||
|
||||
// Old Tests
|
||||
oldTestImplementation 'org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT'
|
||||
oldTestImplementation('com.googlecode.json-simple:json-simple:1.1.1') {
|
||||
exclude group: 'junit', module: 'junit'
|
||||
}
|
||||
oldTestImplementation 'junit:junit:4.13.1'
|
||||
oldTestImplementation 'org.mockito:mockito-core:3.11.2'
|
||||
oldTestImplementation 'commons-io:commons-io:2.7'
|
||||
|
||||
// Annotation Processors
|
||||
annotationProcessor 'org.glassfish.hk2:hk2-metadata-generator:3.0.3'
|
||||
testAnnotationProcessor 'org.glassfish.hk2:hk2-metadata-generator:3.0.3'
|
||||
testImplementation("org.hamcrest:hamcrest:3.0")
|
||||
}
|
||||
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
||||
|
||||
tasks.withType(Javadoc) {
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
||||
|
||||
|
||||
configurations {
|
||||
[apiElements, runtimeElements].each {
|
||||
it.outgoing.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(jar) }
|
||||
it.outgoing.artifact(shadowJar)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sourceSets {
|
||||
oldTest {
|
||||
java {
|
||||
compileClasspath += main.output
|
||||
runtimeClasspath += main.output
|
||||
srcDir file('src/old-test/java')
|
||||
}
|
||||
resources.srcDir file('src/old-test/resources')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
maven(MavenPublication) {
|
||||
from components.java
|
||||
|
||||
pom.withXml {
|
||||
Node pomNode = asNode()
|
||||
|
||||
// Remove Kotlin dependency
|
||||
pomNode.dependencies.'*'.findAll() {
|
||||
it.groupId.text() == 'org.jetbrains.kotlin'
|
||||
}.each() {
|
||||
it.parent().remove(it)
|
||||
}
|
||||
|
||||
// Switch runtime deps to provided
|
||||
pomNode.dependencies.'*'.findAll() {
|
||||
it.scope.text() == 'runtime'
|
||||
}.each() {
|
||||
it.scope*.value = 'provided'
|
||||
}
|
||||
|
||||
// Add spigot api to pom
|
||||
project.configurations.serverApi.allDependencies.each { dependency ->
|
||||
pomNode.dependencies[0].appendNode("dependency").with {
|
||||
it.appendNode("groupId", dependency.group)
|
||||
it.appendNode("artifactId", dependency.name)
|
||||
it.appendNode("version", dependency.version)
|
||||
it.appendNode("scope", "provided")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
name = "GitHubPackages"
|
||||
url = "https://maven.pkg.github.com/Multiverse/Multiverse-Core"
|
||||
credentials {
|
||||
username = System.getenv("GITHUB_ACTOR")
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ext.bitlyAccessToken = System.getenv('BITLY_ACCESS_TOKEN') ?: 'bitly-access-token'
|
||||
|
||||
task prepareSource(type: Sync) {
|
||||
tasks.register('prepareSource', Sync) {
|
||||
inputs.property 'bitlyAccessToken', bitlyAccessToken
|
||||
from sourceSets.main.java
|
||||
into "$buildDir/src"
|
||||
@@ -237,52 +82,12 @@ task prepareSource(type: Sync) {
|
||||
])
|
||||
}
|
||||
|
||||
compileJava {
|
||||
source = prepareSource.outputs
|
||||
}
|
||||
tasks.withType(JavaCompile) {
|
||||
configure(options) {
|
||||
options.compilerArgs << '-Aorg.glassfish.hk2.metadata.location=META-INF/hk2-locator/Multiverse-Core'
|
||||
}
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
// We're not using Kotlin in the plugin itself, just tests!
|
||||
enabled = false
|
||||
}
|
||||
configurations.findAll { !it.name.startsWith('test') }.each {
|
||||
it.exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
|
||||
}
|
||||
|
||||
processResources {
|
||||
def props = [version: "${project.version}"]
|
||||
inputs.properties props
|
||||
filteringCharset 'UTF-8'
|
||||
filesMatching('plugin.yml') {
|
||||
expand props
|
||||
}
|
||||
|
||||
// This task should never be skipped. The tests depend on this having been run but we want the new version number
|
||||
// that is created after tests are run and before we run again to publish.
|
||||
outputs.upToDateWhen { false }
|
||||
}
|
||||
|
||||
|
||||
javadoc {
|
||||
source = sourceSets.main.allJava
|
||||
classpath = configurations.compileClasspath
|
||||
}
|
||||
|
||||
|
||||
project.configurations.api.canBeResolved = true
|
||||
|
||||
shadowJar {
|
||||
relocate 'co.aikar', 'org.mvplugins.multiverse.external.acf'
|
||||
relocate 'com.dumptruckman.minecraft.util.Logging', 'org.mvplugins.multiverse.core.utils.CoreLogging'
|
||||
relocate 'com.dumptruckman.minecraft.util.DebugLog', 'org.mvplugins.multiverse.core.utils.DebugFileLogger'
|
||||
relocate 'de.themoep.idconverter', 'org.mvplugins.multiverse.external.idconverter'
|
||||
relocate 'io.github.townyadvanced.commentedconfiguration', 'org.mvplugins.multiverse.external.commentedconfiguration'
|
||||
relocate 'me.main__.util', 'org.mvplugins.multiverse.external.serializationconfig'
|
||||
relocate 'org.bstats', 'org.mvplugins.multiverse.external.bstats'
|
||||
relocate 'com.sun', 'org.mvplugins.multiverse.external.sun'
|
||||
relocate 'net.minidev', 'org.mvplugins.multiverse.external.minidev'
|
||||
@@ -296,26 +101,17 @@ shadowJar {
|
||||
relocate 'org.intellij', 'org.mvplugins.multiverse.external.intellij'
|
||||
relocate 'org.jetbrains', 'org.mvplugins.multiverse.external.jetbrains'
|
||||
relocate 'io.papermc.lib', 'org.mvplugins.multiverse.external.paperlib'
|
||||
|
||||
configurations = [project.configurations.shadowed]
|
||||
|
||||
archiveFileName = "$baseName-$version.$extension"
|
||||
|
||||
dependencies {
|
||||
exclude(dependency {
|
||||
it.moduleGroup == 'org.jetbrains.kotlin'
|
||||
})
|
||||
}
|
||||
//classifier = ''
|
||||
}
|
||||
|
||||
build.dependsOn shadowJar
|
||||
jar.enabled = false
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
|
||||
testLogging {
|
||||
exceptionFormat = 'full'
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name = "GitHubPackages"
|
||||
url = "https://maven.pkg.github.com/Multiverse/Multiverse-Core"
|
||||
credentials {
|
||||
username = System.getenv("GITHUB_ACTOR")
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
out.txt
|
||||
@@ -0,0 +1,20 @@
|
||||
filepath = "../src/main/resources/multiverse-core_en.properties"
|
||||
|
||||
enumList = []
|
||||
|
||||
with open(filepath) as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if len(line) == 0:
|
||||
enumList.append("")
|
||||
elif line.startswith("#"):
|
||||
enumList.append(line.replace("#", "//"))
|
||||
else:
|
||||
parts = line.split("=")
|
||||
if (len(parts) < 2):
|
||||
continue
|
||||
parts = parts[0].split(".")[1:]
|
||||
enumList.append("_".join([p.upper() for p in parts]) + ",")
|
||||
|
||||
with open("out.txt", "w") as f:
|
||||
f.write("\n".join(enumList))
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 166 KiB |
@@ -134,7 +134,7 @@
|
||||
<module name="MutableException"/>
|
||||
<module name="OneTopLevelClass"/>
|
||||
<module name="ThrowsCount">
|
||||
<property name="max" value="0"/>
|
||||
<property name="max" value="2"/>
|
||||
</module>
|
||||
<module name="VisibilityModifier">
|
||||
<property name="protectedAllowed" value="true"/>
|
||||
@@ -380,7 +380,7 @@
|
||||
<property name="throwsIndent" value="8"/>
|
||||
<property name="arrayInitIndent" value="4"/>
|
||||
<property name="lineWrappingIndentation" value="8"/>
|
||||
<property name="forceStrictCondition" value="true"/>
|
||||
<property name="forceStrictCondition" value="false"/>
|
||||
</module>
|
||||
<module name="NoCodeInFile"/>
|
||||
<module name="OuterTypeFilename"/>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -5,6 +5,9 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
maven {
|
||||
url = uri('https://repo.onarandombox.com/multiverse-releases')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package co.aikar.commands;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
/**
|
||||
* Exists just so we can extend BukkitCommandIssuer since it has a package-private constructor.
|
||||
*/
|
||||
public abstract class OpenBukkitCommandIssuer extends BukkitCommandIssuer {
|
||||
|
||||
protected OpenBukkitCommandIssuer(BukkitCommandManager manager, CommandSender sender) {
|
||||
super(manager, sender);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package org.mvplugins.multiverse.core;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.inject.Inject;
|
||||
import org.apache.commons.lang3.text.WordUtils;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bstats.charts.AdvancedPie;
|
||||
import org.bstats.charts.SingleLineChart;
|
||||
import org.bukkit.World;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.utils.REPatterns;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
|
||||
/**
|
||||
* Helper class that registers and sends metrics to <a href="https://bstats.org">bstats website</a>.
|
||||
*/
|
||||
@Service
|
||||
final class BstatsMetricsConfigurator {
|
||||
|
||||
private static final int PLUGIN_ID = 7765;
|
||||
private static final String NO_GENERATOR_NAME = "N/A";
|
||||
|
||||
private final WorldManager worldManager;
|
||||
private final Metrics metrics;
|
||||
|
||||
@Inject
|
||||
private BstatsMetricsConfigurator(MultiverseCore plugin, WorldManager worldManager) {
|
||||
this.worldManager = worldManager;
|
||||
this.metrics = new Metrics(plugin, PLUGIN_ID);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
private void initMetrics() {
|
||||
try {
|
||||
addCustomGeneratorsMetric();
|
||||
addEnvironmentsMetric();
|
||||
addWorldCountMetric();
|
||||
|
||||
Logging.fine("Metrics enabled.");
|
||||
} catch (Exception e) {
|
||||
Logging.warning("There was an issue while enabling metrics:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void addCustomGeneratorsMetric() {
|
||||
addAdvancedPieMetric("custom_generators", map -> {
|
||||
for (MultiverseWorld w : worldManager.getLoadedWorlds()) {
|
||||
incrementCount(map, getGeneratorName(w));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String getGeneratorName(MultiverseWorld world) {
|
||||
String gen = world.getGenerator();
|
||||
return (gen != null && !gen.equalsIgnoreCase("null"))
|
||||
? REPatterns.COLON.split(gen)[0]
|
||||
: NO_GENERATOR_NAME;
|
||||
}
|
||||
|
||||
private void addEnvironmentsMetric() {
|
||||
addAdvancedPieMetric("environments", map -> {
|
||||
for (MultiverseWorld w : worldManager.getLoadedWorlds()) {
|
||||
incrementCount(map, titleCaseEnv(w.getEnvironment()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String titleCaseEnv(World.Environment env) {
|
||||
String envName = env.name().replaceAll("_+", " ");
|
||||
return WordUtils.capitalizeFully(envName);
|
||||
}
|
||||
|
||||
private void addWorldCountMetric() {
|
||||
addLineMetric("worlds", () -> worldManager.getWorlds().size());
|
||||
}
|
||||
|
||||
private void addAdvancedPieMetric(String chartId, Consumer<Map<String, Integer>> metricsFunc) {
|
||||
metrics.addCustomChart(createAdvancedPieChart(chartId, metricsFunc));
|
||||
}
|
||||
|
||||
private void addLineMetric(String chartId, Callable<Integer> metricsFunc) {
|
||||
metrics.addCustomChart(createLineChart(chartId, metricsFunc));
|
||||
}
|
||||
|
||||
private void incrementCount(Map<String, Integer> map, String key) {
|
||||
Integer count = map.getOrDefault(key, 0);
|
||||
map.put(key, count + 1);
|
||||
}
|
||||
|
||||
private AdvancedPie createAdvancedPieChart(String chartId, Consumer<Map<String, Integer>> metricsFunc) {
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
metricsFunc.accept(map);
|
||||
return new AdvancedPie(chartId, () -> map);
|
||||
}
|
||||
|
||||
private SingleLineChart createLineChart(String chartId, Callable<Integer> metricsFunc) {
|
||||
return new SingleLineChart(chartId, metricsFunc);
|
||||
}
|
||||
}
|
||||
@@ -7,73 +7,51 @@
|
||||
|
||||
package org.mvplugins.multiverse.core;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import io.vavr.control.Try;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Provider;
|
||||
import me.main__.util.SerializationConfig.SerializationConfig;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
import org.glassfish.hk2.api.MultiException;
|
||||
import org.glassfish.hk2.api.ServiceHandle;
|
||||
import org.glassfish.hk2.api.ServiceLocator;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.api.Destination;
|
||||
import org.mvplugins.multiverse.core.api.MVCore;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.commandtools.PluginLocales;
|
||||
import org.mvplugins.multiverse.core.config.MVCoreConfig;
|
||||
import org.mvplugins.multiverse.core.destination.Destination;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
|
||||
import org.mvplugins.multiverse.core.commands.CoreCommand;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.economy.MVEconomist;
|
||||
import org.mvplugins.multiverse.core.inject.InjectableListener;
|
||||
import org.mvplugins.multiverse.core.inject.PluginInjection;
|
||||
import org.mvplugins.multiverse.core.placeholders.MultiverseCorePlaceholders;
|
||||
import org.mvplugins.multiverse.core.utils.TestingMode;
|
||||
import org.mvplugins.multiverse.core.utils.metrics.MetricsConfigurator;
|
||||
import org.mvplugins.multiverse.core.listeners.CoreListener;
|
||||
import org.mvplugins.multiverse.core.inject.PluginServiceLocatorFactory;
|
||||
import org.mvplugins.multiverse.core.module.MultiverseModule;
|
||||
import org.mvplugins.multiverse.core.utils.StringFormatter;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.config.NullLocation;
|
||||
import org.mvplugins.multiverse.core.world.config.SpawnLocation;
|
||||
import org.mvplugins.multiverse.core.world.location.NullSpawnLocation;
|
||||
import org.mvplugins.multiverse.core.world.location.SpawnLocation;
|
||||
import org.mvplugins.multiverse.core.world.location.UnloadedWorldLocation;
|
||||
|
||||
/**
|
||||
* The implementation of the Multiverse-{@link MVCore}.
|
||||
* The start of the Multiverse-Core plugin
|
||||
*/
|
||||
@Service
|
||||
public class MultiverseCore extends JavaPlugin implements MVCore {
|
||||
private static final int PROTOCOL = 50;
|
||||
public class MultiverseCore extends MultiverseModule {
|
||||
|
||||
private ServiceLocator serviceLocator;
|
||||
@Inject
|
||||
private Provider<MVCoreConfig> configProvider;
|
||||
private Provider<CoreConfig> configProvider;
|
||||
@Inject
|
||||
private Provider<WorldManager> worldManagerProvider;
|
||||
@Inject
|
||||
private Provider<AnchorManager> anchorManagerProvider;
|
||||
@Inject
|
||||
private Provider<MVCommandManager> commandManagerProvider;
|
||||
@Inject
|
||||
private Provider<DestinationsProvider> destinationsProviderProvider;
|
||||
@Inject
|
||||
private Provider<MetricsConfigurator> metricsConfiguratorProvider;
|
||||
private Provider<BstatsMetricsConfigurator> metricsConfiguratorProvider;
|
||||
@Inject
|
||||
private Provider<MVEconomist> economistProvider;
|
||||
@Inject
|
||||
private Provider<PluginLocales> pluginLocalesProvider;
|
||||
|
||||
// Counter for the number of plugins that have registered with us
|
||||
private int pluginCount;
|
||||
|
||||
/**
|
||||
* This is the constructor for the MultiverseCore.
|
||||
@@ -95,9 +73,9 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
|
||||
}
|
||||
|
||||
// Register our config classes
|
||||
SerializationConfig.initLogging(Logging.getLogger());
|
||||
ConfigurationSerialization.registerClass(NullLocation.class);
|
||||
ConfigurationSerialization.registerClass(NullSpawnLocation.class);
|
||||
ConfigurationSerialization.registerClass(SpawnLocation.class);
|
||||
ConfigurationSerialization.registerClass(UnloadedWorldLocation.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,11 +83,13 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
|
||||
*/
|
||||
@Override
|
||||
public void onEnable() {
|
||||
initializeDependencyInjection();
|
||||
super.onEnable();
|
||||
initializeDependencyInjection(new MultiverseCorePluginBinder(this));
|
||||
|
||||
// Load our configs first as we need them for everything else.
|
||||
var config = configProvider.get();
|
||||
if (!config.isLoaded()) {
|
||||
var loadSuccess = config.load().andThenTry(config::save).isSuccess();
|
||||
if (!loadSuccess || !config.isLoaded()) {
|
||||
Logging.severe("Your configs were not loaded.");
|
||||
Logging.severe("Please check your configs and restart the server.");
|
||||
this.getServer().getPluginManager().disablePlugin(this);
|
||||
@@ -119,17 +99,15 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
|
||||
|
||||
// Initialize the worlds
|
||||
worldManagerProvider.get().initAllWorlds().andThenTry(() -> {
|
||||
// Setup economy here so vault is loaded
|
||||
loadEconomist();
|
||||
|
||||
// Init all the other stuff
|
||||
loadEconomist(); // Setup economy here so vault is loaded
|
||||
loadAnchors();
|
||||
registerEvents();
|
||||
registerDynamicListeners(CoreListener.class);
|
||||
setUpLocales();
|
||||
registerCommands();
|
||||
registerCommands(CoreCommand.class);
|
||||
registerDestinations();
|
||||
setupMetrics();
|
||||
loadPlaceholderApiIntegration();
|
||||
loadApiService();
|
||||
saveAllConfigs();
|
||||
logEnableMessage();
|
||||
}).onFailure(e -> {
|
||||
@@ -144,30 +122,14 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
|
||||
*/
|
||||
@Override
|
||||
public void onDisable() {
|
||||
super.onDisable();
|
||||
MultiverseCoreApi.shutdown();
|
||||
saveAllConfigs();
|
||||
shutdownDependencyInjection();
|
||||
PluginServiceLocatorFactory.get().shutdown();
|
||||
Logging.shutdown();
|
||||
}
|
||||
|
||||
private void initializeDependencyInjection() {
|
||||
serviceLocator = PluginInjection.createServiceLocator(new MultiverseCorePluginBinder(this))
|
||||
.andThenTry(locator -> {
|
||||
PluginInjection.enable(this, locator);
|
||||
})
|
||||
.getOrElseThrow(exception -> {
|
||||
Logging.severe("Failed to initialize dependency injection");
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
return new RuntimeException(exception);
|
||||
});
|
||||
}
|
||||
|
||||
private void shutdownDependencyInjection() {
|
||||
if (serviceLocator != null) {
|
||||
PluginInjection.disable(this, serviceLocator);
|
||||
serviceLocator = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldShowConfig() {
|
||||
return !configProvider.get().getSilentStart();
|
||||
}
|
||||
@@ -182,60 +144,13 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
|
||||
|
||||
private void loadAnchors() {
|
||||
Try.of(() -> anchorManagerProvider.get())
|
||||
.onSuccess(AnchorManager::loadAnchors)
|
||||
.flatMap(AnchorManager::loadAnchors)
|
||||
.onFailure(e -> {
|
||||
Logging.severe("Failed to load anchors");
|
||||
e.printStackTrace();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to Register all the Events needed.
|
||||
*/
|
||||
private void registerEvents() {
|
||||
var pluginManager = getServer().getPluginManager();
|
||||
|
||||
Try.run(() -> serviceLocator.getAllServices(InjectableListener.class).forEach(
|
||||
listener -> pluginManager.registerEvents(listener, this)))
|
||||
.onFailure(e -> {
|
||||
throw new RuntimeException("Failed to register listeners. Terminating...", e);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Multiverse-Core commands to Command Manager.
|
||||
*/
|
||||
private void registerCommands() {
|
||||
Try.of(() -> commandManagerProvider.get())
|
||||
.andThenTry(commandManager -> {
|
||||
serviceLocator.getAllServices(MultiverseCommand.class)
|
||||
.forEach(commandManager::registerCommand);
|
||||
})
|
||||
.onFailure(e -> {
|
||||
Logging.severe("Failed to register commands");
|
||||
e.printStackTrace();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register locales.
|
||||
*/
|
||||
private void setUpLocales() {
|
||||
Try.of(() -> commandManagerProvider.get())
|
||||
.andThen(commandManager -> {
|
||||
commandManager.usePerIssuerLocale(true, true);
|
||||
})
|
||||
.mapTry(commandManager -> pluginLocalesProvider.get())
|
||||
.andThen(pluginLocales -> {
|
||||
pluginLocales.addFileResClassLoader(this);
|
||||
pluginLocales.addMessageBundles("multiverse-core");
|
||||
})
|
||||
.onFailure(e -> {
|
||||
Logging.severe("Failed to register locales");
|
||||
e.printStackTrace();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all the destinations.
|
||||
*/
|
||||
@@ -268,21 +183,12 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the enable message.
|
||||
* Setup placeholder api hook
|
||||
*/
|
||||
private void logEnableMessage() {
|
||||
Logging.config("Version %s (API v%s) Enabled - By %s", this.getDescription().getVersion(), PROTOCOL, getAuthors());
|
||||
|
||||
if (configProvider.get().isShowingDonateMessage()) {
|
||||
Logging.config("Help dumptruckman keep this project alive. Become a patron! https://www.patreon.com/dumptruckman");
|
||||
Logging.config("One time donations are also appreciated: https://www.paypal.me/dumptruckman");
|
||||
}
|
||||
}
|
||||
|
||||
private void loadPlaceholderApiIntegration() {
|
||||
if (configProvider.get().isRegisterPapiHook()
|
||||
&& getServer().getPluginManager().getPlugin("PlaceholderAPI") != null) {
|
||||
Try.run(() -> serviceLocator.createAndInitialize(MultiverseCorePlaceholders.class))
|
||||
Try.run(() -> serviceLocator.getService(PlaceholderExpansionHook.class))
|
||||
.onFailure(e -> {
|
||||
Logging.severe("Failed to load PlaceholderAPI integration.");
|
||||
e.printStackTrace();
|
||||
@@ -291,53 +197,67 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* Setup the api service for {@link MultiverseCoreApi}
|
||||
*/
|
||||
@Override
|
||||
public MVCore getCore() {
|
||||
return this;
|
||||
private void loadApiService() {
|
||||
Try.run(() -> MultiverseCoreApi.init(this))
|
||||
.onSuccess(ignore -> Logging.info("API service loaded!"))
|
||||
.onFailure(e -> {
|
||||
Logging.severe("Failed to load API service!");
|
||||
e.printStackTrace();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* Save config.yml, worlds.yml, and anchors.yml.
|
||||
*
|
||||
* @return {@link Try#isSuccess()} true if all configs were successfully saved
|
||||
*/
|
||||
@Override
|
||||
public int getProtocolVersion() {
|
||||
return PROTOCOL;
|
||||
private Try<Void> saveAllConfigs() {
|
||||
return configProvider.get().save()
|
||||
.flatMap(ignore -> worldManagerProvider.get().saveWorldsConfig())
|
||||
.flatMap(ignore ->anchorManagerProvider.get().saveAllAnchors())
|
||||
.onFailure(e -> {
|
||||
Logging.severe("Failed to save configs, things may not work as expected.");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* Logs the enable message.
|
||||
*/
|
||||
@Override
|
||||
public String getAuthors() {
|
||||
List<String> authorsList = this.getDescription().getAuthors();
|
||||
if (authorsList.isEmpty()) {
|
||||
return "";
|
||||
private void logEnableMessage() {
|
||||
Logging.config("\u001B[32mVersion %s (API v%s) Enabled - By %s\u001B[39m",
|
||||
this.getDescription().getVersion(), getVersionAsNumber(), StringFormatter.joinAnd(getDescription().getAuthors()));
|
||||
|
||||
if (configProvider.get().isShowingDonateMessage()) {
|
||||
Logging.config("\u001B[32mLoving Multiverse-Core? Please consider supporting the project with a small donation: https://github.com/sponsors/Multiverse\u001B[39m");
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder authors = new StringBuilder();
|
||||
authors.append(authorsList.get(0));
|
||||
|
||||
for (int i = 1; i < authorsList.size(); i++) {
|
||||
if (i == authorsList.size() - 1) {
|
||||
authors.append(" and ").append(authorsList.get(i));
|
||||
} else {
|
||||
authors.append(", ").append(authorsList.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
return authors.toString();
|
||||
/**
|
||||
* Gets the MultiverseCoreApi
|
||||
*
|
||||
* @return The MultiverseCoreApi
|
||||
*
|
||||
* @deprecated Use {@link MultiverseCoreApi#get()} directly.
|
||||
*/
|
||||
@Deprecated(since = "5.1", forRemoval = true)
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "6.0")
|
||||
public MultiverseCoreApi getApi() {
|
||||
return MultiverseCoreApi.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int getPluginCount() {
|
||||
return this.pluginCount;
|
||||
public double getTargetCoreVersion() {
|
||||
return getVersionAsNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
@@ -348,78 +268,33 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void incrementPluginCount() {
|
||||
this.pluginCount += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void decrementPluginCount() {
|
||||
this.pluginCount -= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean saveAllConfigs() {
|
||||
// TODO: Make this all Try<Void>
|
||||
return configProvider.get().save().isSuccess()
|
||||
&& worldManagerProvider.get().saveWorldsConfig()
|
||||
&& anchorManagerProvider.get().saveAnchors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the best service from this plugin that implements the given contract or has the given implementation.
|
||||
*
|
||||
* @param contractOrImpl The contract or concrete implementation to get the best instance of
|
||||
* @param qualifiers The set of qualifiers that must match this service definition
|
||||
* @param <T> The type of the contract to get
|
||||
* @return An instance of the contract or impl if it is a service and is already instantiated, null otherwise
|
||||
* @throws MultiException if there was an error during service lookup
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T getService(@NotNull Class<T> contractOrImpl, Annotation... qualifiers) throws MultiException {
|
||||
var handle = serviceLocator.getServiceHandle(contractOrImpl, qualifiers);
|
||||
if (handle != null && handle.isActive()) {
|
||||
return handle.getService();
|
||||
public @NotNull FileConfiguration getConfig() {
|
||||
CoreConfig coreConfig = this.configProvider.get();
|
||||
var config = coreConfig.getConfig();
|
||||
if (config != null && coreConfig.isLoaded()) {
|
||||
return config;
|
||||
}
|
||||
return null;
|
||||
|
||||
var loadSuccess = coreConfig.load().isSuccess();
|
||||
if (!loadSuccess || !coreConfig.isLoaded()) {
|
||||
throw new RuntimeException("Failed to load configs");
|
||||
}
|
||||
return coreConfig.getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all services from this plugin that implement the given contract or have the given implementation and have
|
||||
* the provided qualifiers.
|
||||
*
|
||||
* @param contractOrImpl The contract or concrete implementation to get the best instance of
|
||||
* @param qualifiers The set of qualifiers that must match this service definition
|
||||
* @param <T> The type of the contract to get
|
||||
* @return A list of services implementing this contract or concrete implementation. May not return null, but may
|
||||
* return an empty list.
|
||||
* @throws MultiException if there was an error during service lookup
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@NotNull
|
||||
public <T> List<T> getAllServices(
|
||||
@NotNull Class<T> contractOrImpl,
|
||||
Annotation... qualifiers) throws MultiException {
|
||||
var handles = serviceLocator.getAllServiceHandles(contractOrImpl, qualifiers);
|
||||
return handles.stream()
|
||||
.filter(ServiceHandle::isActive)
|
||||
.map(ServiceHandle::getService)
|
||||
.collect(Collectors.toList());
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
this.configProvider.get().load();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is for unit testing ONLY. Do not use this constructor.
|
||||
*
|
||||
* @param loader The PluginLoader to use.
|
||||
* @param description The Description file to use.
|
||||
* @param dataFolder The folder that other datafiles can be found in.
|
||||
* @param file The location of the plugin.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public MultiverseCore(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) {
|
||||
super(loader, description, dataFolder, file);
|
||||
@Override
|
||||
public void saveConfig() {
|
||||
this.configProvider.get().save();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package org.mvplugins.multiverse.core;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
|
||||
import org.mvplugins.multiverse.core.economy.MVEconomist;
|
||||
import org.mvplugins.multiverse.core.inject.PluginServiceLocator;
|
||||
import org.mvplugins.multiverse.core.teleportation.AsyncSafetyTeleporter;
|
||||
import org.mvplugins.multiverse.core.teleportation.BlockSafety;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.biomeprovider.BiomeProviderFactory;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Provides access to the MultiverseCore API.
|
||||
*/
|
||||
public class MultiverseCoreApi {
|
||||
|
||||
private static MultiverseCoreApi instance;
|
||||
private static final List<Consumer<MultiverseCoreApi>> whenLoadedCallbacks = new ArrayList<>();
|
||||
|
||||
static void init(@NotNull MultiverseCore multiverseCore) {
|
||||
if (instance != null) {
|
||||
throw new IllegalStateException("MultiverseCoreApi has already been initialized!");
|
||||
}
|
||||
instance = new MultiverseCoreApi(multiverseCore.getServiceLocator());
|
||||
Bukkit.getServicesManager().register(MultiverseCoreApi.class, instance, multiverseCore, ServicePriority.Normal);
|
||||
|
||||
whenLoadedCallbacks.forEach(c -> c.accept(instance));
|
||||
whenLoadedCallbacks.clear();
|
||||
}
|
||||
|
||||
static void shutdown() {
|
||||
Bukkit.getServicesManager().unregister(instance);
|
||||
instance = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook your plugin into the MultiverseCoreApi here to ensure you only start using the API after it has been initialized.
|
||||
* Use this if you know your plugin may load before Multiverse-Core is fully initialized.
|
||||
* <br/>
|
||||
* This handy method removes the need for you to check with plugin manager or listen to plugin enable event.
|
||||
* <br/>
|
||||
* Callback will be called immediately if the MultiverseCoreApi has already been initialized.
|
||||
*
|
||||
* @param consumer The callback to execute when the MultiverseCoreApi has been initialized.
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public static void whenLoaded(@NotNull Consumer<MultiverseCoreApi> consumer) {
|
||||
if (instance != null) {
|
||||
consumer.accept(instance);
|
||||
} else {
|
||||
whenLoadedCallbacks.add(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the MultiverseCoreApi has been initialized.
|
||||
*
|
||||
* @return True if the MultiverseCoreApi has been initialized, false otherwise
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public static boolean isLoaded() {
|
||||
return instance != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MultiverseCoreApi. This will throw an exception if the Multiverse-Core has not been initialized.
|
||||
* <br/>
|
||||
* You can check if the MultiverseCoreApi has been initialized with {@link #isLoaded()} before using this method.
|
||||
* <br/>
|
||||
* Alternatively, you can use {@link #whenLoaded(Consumer)} to hook into the MultiverseCoreApi if your plugin may
|
||||
* load before Multiverse-Core is fully initialized.
|
||||
*
|
||||
* @return The MultiverseCoreApi
|
||||
* @throws IllegalStateException if the MultiverseCoreApi has not been initialized
|
||||
*/
|
||||
public static @NotNull MultiverseCoreApi get() {
|
||||
if (instance == null) {
|
||||
throw new IllegalStateException("MultiverseCoreApi has not been initialized!");
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private final PluginServiceLocator serviceLocator;
|
||||
|
||||
private MultiverseCoreApi(@NotNull PluginServiceLocator serviceProvider) {
|
||||
this.serviceLocator = serviceProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of AnchorManager.
|
||||
*
|
||||
* @return The AnchorManager instance
|
||||
*/
|
||||
public @NotNull AnchorManager getAnchorManager() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(AnchorManager.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of BiomeProviderFactory.
|
||||
*
|
||||
* @return The BiomeProviderFactory instance
|
||||
*/
|
||||
public @NotNull BiomeProviderFactory getBiomeProviderFactory() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(BiomeProviderFactory.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of BlockSafety.
|
||||
*
|
||||
* @return The BlockSafety instance
|
||||
*/
|
||||
public @NotNull BlockSafety getBlockSafety() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(BlockSafety.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of CoreConfig.
|
||||
*
|
||||
* @return The CoreConfig instance
|
||||
*/
|
||||
public @NotNull CoreConfig getCoreConfig() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(CoreConfig.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of DestinationsProvider.
|
||||
*
|
||||
* @return The DestinationsProvider instance
|
||||
*/
|
||||
public @NotNull DestinationsProvider getDestinationsProvider() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(DestinationsProvider.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of GeneratorProvider.
|
||||
*
|
||||
* @return The GeneratorProvider instance
|
||||
*/
|
||||
public @NotNull GeneratorProvider getGeneratorProvider() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(GeneratorProvider.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of LocationManipulation.
|
||||
*
|
||||
* @return The LocationManipulation instance
|
||||
*/
|
||||
public @NotNull LocationManipulation getLocationManipulation() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(LocationManipulation.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of MVEconomist.
|
||||
*
|
||||
* @return The MVEconomist instance
|
||||
*/
|
||||
public @NotNull MVEconomist getMVEconomist() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(MVEconomist.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of SafetyTeleporter.
|
||||
*
|
||||
* @return The SafetyTeleporter instance
|
||||
*/
|
||||
public @NotNull AsyncSafetyTeleporter getSafetyTeleporter() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(AsyncSafetyTeleporter.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of WorldManager.
|
||||
*
|
||||
* @return The WorldManager instance
|
||||
*/
|
||||
public @NotNull WorldManager getWorldManager() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(WorldManager.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of Multiverse-Core's PluginServiceLocator.
|
||||
* <br/>
|
||||
* You can use this to hook into the hk2 dependency injection system used by Multiverse-Core.
|
||||
*
|
||||
* @return The Multiverse-Core's PluginServiceLocator
|
||||
*/
|
||||
public @NotNull PluginServiceLocator getServiceLocator() {
|
||||
return serviceLocator;
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,17 @@ package org.mvplugins.multiverse.core;
|
||||
import org.glassfish.hk2.utilities.binding.ScopedBindingBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.mvplugins.multiverse.core.api.MVCore;
|
||||
import org.mvplugins.multiverse.core.inject.binder.JavaPluginBinder;
|
||||
import org.mvplugins.multiverse.core.module.MultiverseModuleBinder;
|
||||
|
||||
class MultiverseCorePluginBinder extends JavaPluginBinder<MultiverseCore> {
|
||||
final class MultiverseCorePluginBinder extends MultiverseModuleBinder<MultiverseCore> {
|
||||
|
||||
protected MultiverseCorePluginBinder(@NotNull MultiverseCore plugin) {
|
||||
MultiverseCorePluginBinder(@NotNull MultiverseCore plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScopedBindingBuilder<MultiverseCore> bindPluginClass(
|
||||
ScopedBindingBuilder<MultiverseCore> bindingBuilder) {
|
||||
return super.bindPluginClass(bindingBuilder).to(MVCore.class).to(MultiverseCore.class);
|
||||
return super.bindPluginClass(bindingBuilder).to(MultiverseCore.class);
|
||||
}
|
||||
}
|
||||
+76
-32
@@ -1,5 +1,6 @@
|
||||
package org.mvplugins.multiverse.core.placeholders;
|
||||
package org.mvplugins.multiverse.core;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import io.vavr.control.Option;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.inject.Inject;
|
||||
@@ -7,24 +8,31 @@ import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.SpawnCategory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.MultiverseCore;
|
||||
import org.mvplugins.multiverse.core.economy.MVEconomist;
|
||||
import org.mvplugins.multiverse.core.utils.MinecraftTimeFormatter;
|
||||
import org.mvplugins.multiverse.core.utils.REPatterns;
|
||||
import org.mvplugins.multiverse.core.utils.StringFormatter;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class MultiverseCorePlaceholders extends PlaceholderExpansion {
|
||||
final class PlaceholderExpansionHook extends PlaceholderExpansion {
|
||||
|
||||
private final MultiverseCore plugin;
|
||||
private final WorldManager worldManager;
|
||||
private final MVEconomist economist;
|
||||
|
||||
@Inject
|
||||
public MultiverseCorePlaceholders(MultiverseCore plugin, WorldManager worldManager, MVEconomist economist) {
|
||||
public PlaceholderExpansionHook(MultiverseCore plugin, WorldManager worldManager, MVEconomist economist) {
|
||||
this.plugin = plugin;
|
||||
this.worldManager = worldManager;
|
||||
this.economist = economist;
|
||||
@@ -43,7 +51,7 @@ public class MultiverseCorePlaceholders extends PlaceholderExpansion {
|
||||
|
||||
@Override
|
||||
public @NotNull String getAuthor() {
|
||||
return plugin.getAuthors();
|
||||
return StringFormatter.joinAnd(plugin.getDescription().getAuthors());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,39 +74,61 @@ public class MultiverseCorePlaceholders extends PlaceholderExpansion {
|
||||
@Override
|
||||
public @Nullable String onRequest(OfflinePlayer offlinePlayer, @NotNull String params) {
|
||||
// Split string in to an Array with underscores
|
||||
String[] paramsArray = params.split("_", 2);
|
||||
List<String> paramsArray = Lists.newArrayList(REPatterns.UNDERSCORE.split(params));
|
||||
|
||||
// No placeholder defined
|
||||
if (paramsArray.length < 1) {
|
||||
warning("No placeholder defined");
|
||||
if (paramsArray.isEmpty()) {
|
||||
warning("No placeholder key defined");
|
||||
return null;
|
||||
}
|
||||
|
||||
final var placeholder = paramsArray[0];
|
||||
Option<LoadedMultiverseWorld> targetWorld;
|
||||
final var placeholder = paramsArray.removeFirst();
|
||||
|
||||
// If no world is defined, use the player's world
|
||||
if (paramsArray.length == 1) {
|
||||
if (!offlinePlayer.isOnline()) {
|
||||
return null;
|
||||
}
|
||||
targetWorld = worldManager.getLoadedWorld(((Player)offlinePlayer).getWorld());
|
||||
} else {
|
||||
targetWorld = worldManager.getLoadedWorld(paramsArray[1]);
|
||||
}
|
||||
String worldName = parseWorldName(offlinePlayer, paramsArray);
|
||||
if (worldName == null) return null;
|
||||
|
||||
// Fail if world is null
|
||||
return targetWorld.map(world -> getWorldPlaceHolderValue(placeholder, world)).getOrNull();
|
||||
return worldManager.getLoadedWorld(worldName)
|
||||
.onEmpty(() -> warning("Multiverse World not found: " + worldName))
|
||||
.map(world -> getWorldPlaceHolderValue(placeholder, paramsArray, world))
|
||||
.getOrNull();
|
||||
}
|
||||
|
||||
private @Nullable String getWorldPlaceHolderValue(@NotNull String placeholder, @NotNull LoadedMultiverseWorld world) {
|
||||
private @Nullable String parseWorldName(OfflinePlayer offlinePlayer, List<String> paramsArray) {
|
||||
// No world defined, get from player
|
||||
if (paramsArray.isEmpty()) {
|
||||
if (offlinePlayer instanceof Player player) {
|
||||
return player.getWorld().getName();
|
||||
} else {
|
||||
warning("You must specify a world name for non-player placeholders");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Try get from params
|
||||
String paramWorldName = paramsArray.getLast();
|
||||
if (worldManager.isLoadedWorld(paramWorldName)) {
|
||||
paramsArray.removeLast();
|
||||
return paramWorldName;
|
||||
}
|
||||
|
||||
// Param not a world, fallback to player
|
||||
if (offlinePlayer instanceof Player player) {
|
||||
return player.getWorld().getName();
|
||||
}
|
||||
warning("Multiverse World not found: " + paramWorldName);
|
||||
return null;
|
||||
}
|
||||
|
||||
private @Nullable String getWorldPlaceHolderValue(@NotNull String placeholder,
|
||||
@NotNull List<String> placeholderParams,
|
||||
@NotNull LoadedMultiverseWorld world) {
|
||||
// Switch to find what specific placeholder we want
|
||||
switch (placeholder.toLowerCase()) {
|
||||
case "alias" -> {
|
||||
return world.getAlias();
|
||||
return world.getAliasOrName();
|
||||
}
|
||||
case "animalspawn" -> {
|
||||
return String.valueOf(world.getSpawningAnimals());
|
||||
return String.valueOf(world.getEntitySpawnConfig().getSpawnCategoryConfig(SpawnCategory.ANIMAL).isSpawn());
|
||||
}
|
||||
case "autoheal" -> {
|
||||
return String.valueOf(world.getAutoHeal());
|
||||
@@ -119,7 +149,7 @@ public class MultiverseCorePlaceholders extends PlaceholderExpansion {
|
||||
return world.getEnvironment().toString().toLowerCase();
|
||||
}
|
||||
case "flight" -> {
|
||||
return String.valueOf(world.getAllowFlight());
|
||||
return String.valueOf(world.isAllowFlight());
|
||||
}
|
||||
case "gamemode" -> {
|
||||
return world.getGameMode().toString().toLowerCase();
|
||||
@@ -128,10 +158,10 @@ public class MultiverseCorePlaceholders extends PlaceholderExpansion {
|
||||
return world.getGenerator();
|
||||
}
|
||||
case "hunger" -> {
|
||||
return String.valueOf(world.getHunger());
|
||||
return String.valueOf(world.isHunger());
|
||||
}
|
||||
case "monstersspawn" -> {
|
||||
return String.valueOf(world.getSpawningMonsters());
|
||||
return String.valueOf(world.getEntitySpawnConfig().getSpawnCategoryConfig(SpawnCategory.MONSTER).isSpawn());
|
||||
}
|
||||
case "name" -> {
|
||||
return world.getName();
|
||||
@@ -148,15 +178,29 @@ public class MultiverseCorePlaceholders extends PlaceholderExpansion {
|
||||
case "seed" -> {
|
||||
return String.valueOf(world.getSeed());
|
||||
}
|
||||
// TODO: Time is removed, not sure if it's worth adding back
|
||||
// case "time" -> {
|
||||
// return world.getTime();
|
||||
// }
|
||||
case "time" -> {
|
||||
String timeFormat = !placeholderParams.isEmpty() ? placeholderParams.getFirst() : "";
|
||||
long time = world.getBukkitWorld().map(World::getTime).getOrElse(0L);
|
||||
switch (timeFormat) {
|
||||
case "" -> {
|
||||
return String.valueOf(time);
|
||||
}
|
||||
case "12h" -> {
|
||||
return MinecraftTimeFormatter.format12h(time);
|
||||
}
|
||||
case "24h" -> {
|
||||
return MinecraftTimeFormatter.format24h(time);
|
||||
}
|
||||
default -> {
|
||||
return MinecraftTimeFormatter.formatTime(time, timeFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
case "type" -> {
|
||||
return world.getBukkitWorld().map(World::getWorldType).map(Enum::name).getOrElse("null");
|
||||
}
|
||||
case "weather" -> {
|
||||
return String.valueOf(world.getAllowWeather());
|
||||
return String.valueOf(world.isAllowWeather());
|
||||
}
|
||||
default -> {
|
||||
warning("Unknown placeholder: " + placeholder);
|
||||
+8
-4
@@ -1,18 +1,22 @@
|
||||
package org.mvplugins.multiverse.core.utils;
|
||||
package org.mvplugins.multiverse.core;
|
||||
|
||||
/**
|
||||
* A utility class that enables automated tests to flag Multiverse for testing. This allows Multiverse to not perform
|
||||
* certain behaviors such as enabled stats uploads.
|
||||
*/
|
||||
public class TestingMode {
|
||||
final class TestingMode {
|
||||
|
||||
private static boolean enabled = false;
|
||||
|
||||
public static void enable() {
|
||||
private TestingMode() {
|
||||
// No instantiation
|
||||
}
|
||||
|
||||
static void enable() {
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
public static boolean isDisabled() {
|
||||
static boolean isDisabled() {
|
||||
return !enabled;
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,14 @@
|
||||
package org.mvplugins.multiverse.core.anchor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import io.vavr.control.Option;
|
||||
import io.vavr.control.Try;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
@@ -23,167 +23,183 @@ import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.MultiverseCore;
|
||||
import org.mvplugins.multiverse.core.api.LocationManipulation;
|
||||
import org.mvplugins.multiverse.core.config.MVCoreConfig;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
import org.mvplugins.multiverse.core.utils.result.Result;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.entrycheck.WorldEntryCheckerProvider;
|
||||
import org.mvplugins.multiverse.core.world.location.UnloadedWorldLocation;
|
||||
|
||||
/**
|
||||
* Manages anchors.
|
||||
* Manages anchors and it's location.
|
||||
*/
|
||||
@Service
|
||||
public class AnchorManager {
|
||||
private Map<String, Location> anchors;
|
||||
public final class AnchorManager {
|
||||
|
||||
private static final String ANCHORS_FILE = "anchors.yml";
|
||||
private static final String ANCHORS_CONFIG_SECTION = "anchors";
|
||||
|
||||
private final Map<String, MultiverseAnchor> anchors;
|
||||
private FileConfiguration anchorConfig;
|
||||
|
||||
private final Plugin plugin;
|
||||
private final LocationManipulation locationManipulation;
|
||||
private final MVCoreConfig config;
|
||||
private final WorldEntryCheckerProvider entryCheckerProvider;
|
||||
private final WorldManager worldManager;
|
||||
|
||||
@Inject
|
||||
public AnchorManager(
|
||||
AnchorManager(
|
||||
MultiverseCore plugin,
|
||||
LocationManipulation locationManipulation,
|
||||
MVCoreConfig config
|
||||
WorldEntryCheckerProvider entryCheckerProvider,
|
||||
WorldManager worldManager
|
||||
) {
|
||||
this.plugin = plugin;
|
||||
this.locationManipulation = locationManipulation;
|
||||
this.config = config;
|
||||
this.entryCheckerProvider = entryCheckerProvider;
|
||||
this.worldManager = worldManager;
|
||||
|
||||
this.anchors = new HashMap<String, Location>();
|
||||
this.anchors = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all anchors.
|
||||
*/
|
||||
public void loadAnchors() {
|
||||
this.anchors = new HashMap<String, Location>();
|
||||
this.anchorConfig = YamlConfiguration.loadConfiguration(new File(this.plugin.getDataFolder(), "anchors.yml"));
|
||||
this.ensureConfigIsPrepared();
|
||||
ConfigurationSection anchorsSection = this.anchorConfig.getConfigurationSection("anchors");
|
||||
public Try<Void> loadAnchors() {
|
||||
anchors.clear();
|
||||
return Try.run(() -> {
|
||||
anchorConfig = YamlConfiguration.loadConfiguration(new File(plugin.getDataFolder(), ANCHORS_FILE));
|
||||
parseAnchorsFromConfig();
|
||||
});
|
||||
}
|
||||
|
||||
private void parseAnchorsFromConfig() {
|
||||
var anchorsSection = getAnchorsConfigSection();
|
||||
Set<String> anchorKeys = anchorsSection.getKeys(false);
|
||||
for (String key : anchorKeys) {
|
||||
//world:x,y,z:pitch:yaw
|
||||
Location anchorLocation = this.locationManipulation.stringToLocation(anchorsSection.getString(key, ""));
|
||||
Location anchorLocation = locationManipulation.stringToLocation(anchorsSection.getString(key, ""));
|
||||
if (anchorLocation != null) {
|
||||
Logging.config("Loading anchor: '%s'...", key);
|
||||
this.anchors.put(key, anchorLocation);
|
||||
anchors.put(key, new MultiverseAnchor(key, UnloadedWorldLocation.fromLocation(anchorLocation)));
|
||||
} else {
|
||||
Logging.warning("The location for anchor '%s' is INVALID.", key);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureConfigIsPrepared() {
|
||||
if (this.anchorConfig.getConfigurationSection("anchors") == null) {
|
||||
this.anchorConfig.createSection("anchors");
|
||||
private ConfigurationSection getAnchorsConfigSection() {
|
||||
var anchorsConfigSection = anchorConfig.getConfigurationSection(ANCHORS_CONFIG_SECTION);
|
||||
if (anchorsConfigSection == null) {
|
||||
anchorsConfigSection = anchorConfig.createSection(ANCHORS_CONFIG_SECTION);
|
||||
}
|
||||
return anchorsConfigSection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves all anchors.
|
||||
*
|
||||
* @return True if all anchors were successfully saved.
|
||||
*/
|
||||
public boolean saveAnchors() {
|
||||
try {
|
||||
this.anchorConfig.save(new File(this.plugin.getDataFolder(), "anchors.yml"));
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
Logging.severe("Failed to save anchors.yml. Please check your file permissions.");
|
||||
return false;
|
||||
}
|
||||
public Try<Void> saveAllAnchors() {
|
||||
return Try.run(() -> anchorConfig.save(new File(plugin.getDataFolder(), ANCHORS_FILE)))
|
||||
.onFailure(failure ->
|
||||
Logging.severe("Failed to save anchors.yml. Please check your file permissions."));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Location} associated with an anchor.
|
||||
* @param anchor The name of the anchor.
|
||||
*
|
||||
* @param anchorName The name of the anchor.
|
||||
* @return The {@link Location}.
|
||||
*/
|
||||
public Location getAnchorLocation(String anchor) {
|
||||
if (this.anchors.containsKey(anchor)) {
|
||||
return this.anchors.get(anchor);
|
||||
}
|
||||
return null;
|
||||
public Option<MultiverseAnchor> getAnchor(String anchorName) {
|
||||
return Option.of(anchors.get(anchorName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves an anchor.
|
||||
* @param anchor The name of the anchor.
|
||||
* @param location The location of the anchor as string.
|
||||
* Sets a new location for an anchor. Creates a new anchor if it doesn't exist.
|
||||
*
|
||||
* @param anchorName The name of the anchor.
|
||||
* @param location The location of the anchor as string (world:x,y,z:pitch:yaw).
|
||||
* @return True if the anchor was successfully saved.
|
||||
*/
|
||||
public boolean saveAnchorLocation(String anchor, String location) {
|
||||
Location parsed = this.locationManipulation.stringToLocation(location);
|
||||
return parsed != null && this.saveAnchorLocation(anchor, parsed);
|
||||
public Try<Void> setAnchor(@NotNull String anchorName, @NotNull String location) {
|
||||
Location parsed = locationManipulation.stringToLocation(location);
|
||||
if (parsed == null) {
|
||||
return Try.failure(new IllegalArgumentException("The location for anchor '" + anchorName + "' is INVALID."));
|
||||
}
|
||||
return setAnchor(anchorName, parsed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves an anchor.
|
||||
* @param anchor The name of the anchor.
|
||||
* @param l The {@link Location} of the anchor.
|
||||
* Sets a new location for an anchor. Creates a new anchor if it doesn't exist.
|
||||
*
|
||||
* @param anchorName The name of the anchor.
|
||||
* @param location The {@link Location} of the anchor.
|
||||
* @return True if the anchor was successfully saved.
|
||||
*/
|
||||
public boolean saveAnchorLocation(String anchor, Location l) {
|
||||
if (l == null) {
|
||||
return false;
|
||||
}
|
||||
this.anchorConfig.set("anchors." + anchor, this.locationManipulation.locationToString(l));
|
||||
this.anchors.put(anchor, l);
|
||||
return this.saveAnchors();
|
||||
public Try<Void> setAnchor(@NotNull String anchorName, @NotNull Location location) {
|
||||
Option.of(anchors.get(anchorName))
|
||||
.peek(anchor -> anchor.setLocation(UnloadedWorldLocation.fromLocation(location)))
|
||||
.onEmpty(() -> anchors.put(anchorName, new MultiverseAnchor(anchorName, UnloadedWorldLocation.fromLocation(location))));
|
||||
getAnchorsConfigSection().set(anchorName, locationManipulation.locationToString(location));
|
||||
return saveAllAnchors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all anchors.
|
||||
* @return An unmodifiable {@link Set} containing all anchors.
|
||||
*
|
||||
* @return An unmodifiable {@link List} containing all anchors.
|
||||
*/
|
||||
public Set<String> getAllAnchors() {
|
||||
return Collections.unmodifiableSet(this.anchors.keySet());
|
||||
public List<MultiverseAnchor> getAllAnchors() {
|
||||
return anchors.values().stream().toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all anchors that the specified {@link Player} can access.
|
||||
* @param p The {@link Player}.
|
||||
* @return An unmodifiable {@link Set} containing all anchors the specified {@link Player} can access.
|
||||
*
|
||||
* @param player The {@link Player}.
|
||||
* @return An unmodifiable {@link List} containing all anchors the specified {@link Player} can access.
|
||||
*/
|
||||
public Set<String> getAnchors(Player p) {
|
||||
if (p == null) {
|
||||
return this.anchors.keySet();
|
||||
public List<MultiverseAnchor> getAnchors(@Nullable Player player) {
|
||||
if (player == null) {
|
||||
return getAllAnchors();
|
||||
} else {
|
||||
return getAnchorsForPlayer(player);
|
||||
}
|
||||
Set<String> myAnchors = new HashSet<String>();
|
||||
for (String anchor : this.anchors.keySet()) {
|
||||
Location ancLoc = this.anchors.get(anchor);
|
||||
if (ancLoc == null) {
|
||||
continue;
|
||||
}
|
||||
String worldPerm = "multiverse.access." + ancLoc.getWorld().getName();
|
||||
// Add to the list if we're not enforcing access
|
||||
// OR
|
||||
// We are enforcing access and the user has the permission.
|
||||
if (!config.getEnforceAccess() ||
|
||||
(config.getEnforceAccess() && p.hasPermission(worldPerm))) {
|
||||
myAnchors.add(anchor);
|
||||
} else {
|
||||
Logging.finer(String.format("Not adding anchor %s to the list, user %s doesn't have the %s " +
|
||||
"permission and 'enforceaccess' is enabled!",
|
||||
anchor, p.getName(), worldPerm));
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableSet(myAnchors);
|
||||
}
|
||||
|
||||
private List<MultiverseAnchor> getAnchorsForPlayer(@NotNull Player player) {
|
||||
return anchors.values().stream()
|
||||
.filter(anchor -> shouldIncludeAnchorForPlayer(anchor, player))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private boolean shouldIncludeAnchorForPlayer(MultiverseAnchor anchor, Player player) {
|
||||
return worldManager.getWorld(anchor.getLocationWorld())
|
||||
.map(mvWorld -> entryCheckerProvider.forSender(player).canAccessWorld(mvWorld))
|
||||
.peek(result -> Logging.finer("Result for %s can access anchor %s: %s", player.getName(), anchor.getName(), result))
|
||||
.map(Result::isSuccess)
|
||||
.getOrElse(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the specified anchor.
|
||||
* @param s The name of the anchor.
|
||||
*
|
||||
* @param anchor The anchor to delete.
|
||||
* @return True if the anchor was successfully deleted.
|
||||
*/
|
||||
public boolean deleteAnchor(String s) {
|
||||
if (this.anchors.containsKey(s)) {
|
||||
this.anchors.remove(s);
|
||||
this.anchorConfig.set("anchors." + s, null);
|
||||
return this.saveAnchors();
|
||||
public Try<Void> deleteAnchor(@NotNull MultiverseAnchor anchor) {
|
||||
if (anchors.containsKey(anchor.getName())) {
|
||||
anchors.remove(anchor.getName());
|
||||
getAnchorsConfigSection().set(anchor.getName(), null);
|
||||
return saveAllAnchors();
|
||||
}
|
||||
return false;
|
||||
return Try.failure(new IllegalArgumentException("Anchor does not exist"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.mvplugins.multiverse.core.anchor;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.mvplugins.multiverse.core.world.location.UnloadedWorldLocation;
|
||||
|
||||
/**
|
||||
* Represents a single anchor location.
|
||||
*/
|
||||
public final class MultiverseAnchor {
|
||||
|
||||
private final String name;
|
||||
private UnloadedWorldLocation location;
|
||||
|
||||
MultiverseAnchor(String name, UnloadedWorldLocation location) {
|
||||
this.name = name;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the anchor.
|
||||
*
|
||||
* @return The name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of the anchor's location.
|
||||
*
|
||||
* @return The location.
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return location.toBukkitLocation();
|
||||
}
|
||||
|
||||
void setLocation(Location location) {
|
||||
this.location = new UnloadedWorldLocation(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world of the anchor's location.
|
||||
*
|
||||
* @return The world.
|
||||
*/
|
||||
@Nullable World getLocationWorld() {
|
||||
if (location == null) {
|
||||
return null;
|
||||
}
|
||||
return location.getWorld();
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.api;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Minecart;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Contract;
|
||||
|
||||
/**
|
||||
* Used to get block/location-related information.
|
||||
*/
|
||||
@Contract
|
||||
public interface BlockSafety {
|
||||
/**
|
||||
* This function checks whether the block at the given coordinates are above air or not.
|
||||
* @param l The {@link Location} of the block.
|
||||
* @return True if the block at that {@link Location} is above air.
|
||||
*/
|
||||
boolean isBlockAboveAir(Location l);
|
||||
|
||||
/**
|
||||
* Checks if a player can spawn safely at the given coordinates.
|
||||
* @param world The {@link World}.
|
||||
* @param x The x-coordinate.
|
||||
* @param y The y-coordinate.
|
||||
* @param z The z-coordinate.
|
||||
* @return True if a player can spawn safely at the given coordinates.
|
||||
*/
|
||||
boolean playerCanSpawnHereSafely(World world, double x, double y, double z);
|
||||
|
||||
/**
|
||||
* This function checks whether the block at the coordinates given is safe or not by checking for Lava/Fire/Air
|
||||
* etc. This also ensures there is enough space for a player to spawn!
|
||||
*
|
||||
* @param l The {@link Location}
|
||||
* @return Whether the player can spawn safely at the given {@link Location}
|
||||
*/
|
||||
boolean playerCanSpawnHereSafely(Location l);
|
||||
|
||||
/**
|
||||
* Finds a portal-block next to the specified {@link Location}.
|
||||
*
|
||||
* @param location The {@link Location}
|
||||
* @return The next portal-block's {@link Location}.
|
||||
*/
|
||||
Location findPortalBlockNextTo(Location location);
|
||||
|
||||
/**
|
||||
* Gets the next safe location around the given location.
|
||||
*
|
||||
* @param location A {@link Location}.
|
||||
* @return A safe {@link Location}.
|
||||
*/
|
||||
@Nullable Location getSafeLocation(Location location);
|
||||
|
||||
/**
|
||||
* Gets the next safe location around the given location.
|
||||
*
|
||||
* @param location A {@link Location}.
|
||||
* @param tolerance The tolerance of how far up and down to search.
|
||||
* @param radius The radius around given location to search.
|
||||
* @return A safe {@link Location}.
|
||||
*/
|
||||
@Nullable Location getSafeLocation(Location location, int tolerance, int radius);
|
||||
|
||||
/**
|
||||
* Gets a safe bed spawn location OR null if the bed is invalid.
|
||||
*
|
||||
* @param l The location of the bead head (block with the pillow on it).
|
||||
* @return Safe location around the bed or null if no location was found.
|
||||
*/
|
||||
Location getSafeBedSpawn(Location l);
|
||||
|
||||
/**
|
||||
* Gets the location of the top block at the specified {@link Location}.
|
||||
*
|
||||
* @param l Any {@link Location}.
|
||||
* @return The {@link Location} of the top-block.
|
||||
*/
|
||||
Location getTopBlock(Location l);
|
||||
|
||||
/**
|
||||
* Gets the location of the top block at the specified {@link Location}.
|
||||
*
|
||||
* @param l Any {@link Location}.
|
||||
* @return The {@link Location} of the top-block.
|
||||
*/
|
||||
Location getBottomBlock(Location l);
|
||||
|
||||
/**
|
||||
* Checks if an entity would be on track at the specified {@link Location}.
|
||||
*
|
||||
* @param l The {@link Location}.
|
||||
* @return True if an entity would be on tracks at the specified {@link Location}.
|
||||
*/
|
||||
boolean isEntitiyOnTrack(Location l);
|
||||
|
||||
/**
|
||||
* Checks if the specified {@link Minecart} can spawn safely.
|
||||
*
|
||||
* @param cart The {@link Minecart}.
|
||||
* @return True if the minecart can spawn safely.
|
||||
*/
|
||||
boolean canSpawnCartSafely(Minecart cart);
|
||||
|
||||
/**
|
||||
* Checks if the specified {@link Vehicle} can spawn safely.
|
||||
*
|
||||
* @param vehicle The {@link Vehicle}.
|
||||
* @return True if the vehicle can spawn safely.
|
||||
*/
|
||||
boolean canSpawnVehicleSafely(Vehicle vehicle);
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.api;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import co.aikar.commands.BukkitCommandIssuer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Contract;
|
||||
|
||||
@Contract
|
||||
public interface Destination<T extends DestinationInstance> {
|
||||
/**
|
||||
* Returns the identifier or prefix that is required for this destination.
|
||||
*
|
||||
* <p>Portals have a prefix of "p" for example and OpenWarp (third party plugin) uses "ow". This is derived from a
|
||||
* hash and cannot have duplicate values. Read that as your plugin cannot use 'p' because it's already used.
|
||||
* Please check the wiki when adding a custom destination!</p>
|
||||
*
|
||||
* @return The identifier or prefix that is required for this destination.
|
||||
*/
|
||||
@NotNull String getIdentifier();
|
||||
|
||||
/**
|
||||
* Returns the destination instance for the given destination parameters.
|
||||
*
|
||||
* @param destinationParams The destination parameters. ex: p:MyPortal:nw
|
||||
* @return The destination instance, or null if the destination parameters are invalid.
|
||||
*/
|
||||
@Nullable T getDestinationInstance(@Nullable String destinationParams);
|
||||
|
||||
/**
|
||||
* Returns a list of possible destinations for the given destination parameters.
|
||||
*
|
||||
* @param issuer The command issuer.
|
||||
* @param destinationParams The destination parameters. ex: p:MyPortal:nw
|
||||
* @return A list of possible destinations.
|
||||
*/
|
||||
@NotNull Collection<String> suggestDestinations(@NotNull BukkitCommandIssuer issuer, @Nullable String destinationParams);
|
||||
|
||||
/**
|
||||
* Should the Multiverse SafeTeleporter be used?
|
||||
*
|
||||
* <p>If not, MV will blindly take people to the location specified.</p>
|
||||
*
|
||||
* @return True if the SafeTeleporter will be used, false if not.
|
||||
*/
|
||||
boolean checkTeleportSafety();
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.api;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface DestinationInstance {
|
||||
/**
|
||||
* Gets the exact location to teleport an entity to.
|
||||
*
|
||||
* @param teleportee The entity to teleport.
|
||||
* @return The location to teleport to.
|
||||
*/
|
||||
@Nullable Location getLocation(@NotNull Entity teleportee);
|
||||
|
||||
/**
|
||||
* Gets the velocity to apply to an entity after teleporting.
|
||||
*
|
||||
* @param teleportee The entity to teleport.
|
||||
* @return A vector representing the speed/direction the player should travel when arriving at the destination.
|
||||
*/
|
||||
@Nullable Vector getVelocity(@NotNull Entity teleportee);
|
||||
|
||||
/**
|
||||
* Gets the permission suffix to check for when teleporting to this destination.
|
||||
* This is used for finer per world/player permissions, such as "multiverse.teleport.self.worldname".
|
||||
*
|
||||
* <p>For example, if the destination is "w:world", the permission suffix is "world".</p>
|
||||
*
|
||||
* @return The permission suffix.
|
||||
*/
|
||||
@Nullable String getFinerPermissionSuffix();
|
||||
|
||||
/**
|
||||
* Serialises the destination instance to a savable string.
|
||||
*
|
||||
* <p>This is used when plugins save destinations to configuration,
|
||||
* and when the destination is displayed to the user.</p>
|
||||
*
|
||||
* @return The serialised destination instance.
|
||||
*/
|
||||
@NotNull String serialise();
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.api;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jvnet.hk2.annotations.Contract;
|
||||
|
||||
/**
|
||||
* Used to manipulate locations.
|
||||
*/
|
||||
@Contract
|
||||
public interface LocationManipulation {
|
||||
/**
|
||||
* Convert a Location into a Colon separated string to allow us to store it in text.
|
||||
* <p>
|
||||
* WORLD:X,Y,Z:yaw:pitch
|
||||
* <p>
|
||||
* The corresponding String2Loc function is {@link #stringToLocation}
|
||||
*
|
||||
* @param location The Location to save.
|
||||
* @return The location as a string in this format: WORLD:x,y,z:yaw:pitch
|
||||
*/
|
||||
String locationToString(Location location);
|
||||
|
||||
/**
|
||||
* This method simply does some rounding, rather than forcing a call to the server to get the blockdata.
|
||||
*
|
||||
* @param l The location to round to the block location
|
||||
* @return A rounded location.
|
||||
*/
|
||||
Location getBlockLocation(Location l);
|
||||
|
||||
/**
|
||||
* Returns a new location from a given string. The format is as follows:
|
||||
* <p>
|
||||
* WORLD:X,Y,Z:yaw:pitch
|
||||
* <p>
|
||||
* The corresponding Location2String function is {@link #stringToLocation}
|
||||
*
|
||||
* @param locationString The location represented as a string (WORLD:X,Y,Z:yaw:pitch)
|
||||
* @return A new location defined by the string or null if the string was invalid.
|
||||
*/
|
||||
Location stringToLocation(String locationString);
|
||||
|
||||
/**
|
||||
* Returns a colored string with the coords.
|
||||
*
|
||||
* @param l The {@link Location}
|
||||
* @return The {@link String}
|
||||
*/
|
||||
String strCoords(Location l);
|
||||
|
||||
/**
|
||||
* Converts a location to a printable readable formatted string including pitch/yaw.
|
||||
*
|
||||
* @param l The {@link Location}
|
||||
* @return The {@link String}
|
||||
*/
|
||||
String strCoordsRaw(Location l);
|
||||
|
||||
/**
|
||||
* Return the NESW Direction a Location is facing.
|
||||
*
|
||||
* @param location The {@link Location}
|
||||
* @return The NESW Direction
|
||||
*/
|
||||
String getDirection(Location location);
|
||||
|
||||
/**
|
||||
* Returns the float yaw position for the given cardinal direction.
|
||||
*
|
||||
* @param orientation The cardinal direction
|
||||
* @return The yaw
|
||||
*/
|
||||
float getYaw(String orientation);
|
||||
|
||||
/**
|
||||
* Returns a speed float from a given vector.
|
||||
*
|
||||
* @param v The {@link Vector}
|
||||
* @return The speed
|
||||
*/
|
||||
float getSpeed(Vector v);
|
||||
|
||||
/**
|
||||
* Returns a translated vector from the given direction.
|
||||
*
|
||||
* @param v The old {@link Vector}
|
||||
* @param direction The new direction
|
||||
* @return The translated {@link Vector}
|
||||
*/
|
||||
Vector getTranslatedVector(Vector v, String direction);
|
||||
|
||||
/**
|
||||
* Returns the next Location that a {@link Vehicle} is traveling at.
|
||||
*
|
||||
* @param v The {@link Vehicle}
|
||||
* @return The {@link Location}
|
||||
*/
|
||||
Location getNextBlock(Vehicle v);
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.api;
|
||||
|
||||
import io.vavr.control.Try;
|
||||
import org.jvnet.hk2.annotations.Contract;
|
||||
|
||||
import org.mvplugins.multiverse.core.configuration.handle.StringPropertyHandle;
|
||||
import org.mvplugins.multiverse.core.placeholders.MultiverseCorePlaceholders;
|
||||
|
||||
@Contract
|
||||
public interface MVConfig {
|
||||
|
||||
/**
|
||||
* Loads the config from disk.
|
||||
* @return True if the config was loaded successfully.
|
||||
*/
|
||||
Try<Void> load();
|
||||
|
||||
/**
|
||||
* Whether the config has been loaded.
|
||||
* @return True if the config has been loaded.
|
||||
*/
|
||||
boolean isLoaded();
|
||||
|
||||
/**
|
||||
* Saves the config to disk.
|
||||
*/
|
||||
Try<Void> save();
|
||||
|
||||
/**
|
||||
* Gets the handler for managing config with string names and values.
|
||||
*
|
||||
* @return The config handle for string properties.
|
||||
*/
|
||||
StringPropertyHandle getStringPropertyHandle();
|
||||
|
||||
/**
|
||||
* Sets world access permissions should be enforced.
|
||||
* @param enforceAccess The new value.
|
||||
*/
|
||||
void setEnforceAccess(boolean enforceAccess);
|
||||
|
||||
/**
|
||||
* Gets enforceAccess.
|
||||
* @return enforceAccess.
|
||||
*/
|
||||
boolean getEnforceAccess();
|
||||
|
||||
/**
|
||||
* Sets whether the game mode should be enforced.
|
||||
* @param enforceGameMode The new value.
|
||||
*/
|
||||
void setEnforceGameMode(boolean enforceGameMode);
|
||||
|
||||
/**
|
||||
* Gets enforceGameMode value.
|
||||
* @return True if game mode should be enforced.
|
||||
*/
|
||||
boolean getEnforceGameMode();
|
||||
|
||||
/**
|
||||
* Sets whether or not the automatic purge of entities is enabled.
|
||||
*
|
||||
* @param autopurge True if automatic purge should be enabled.
|
||||
*/
|
||||
void setAutoPurgeEntities(boolean autopurge);
|
||||
|
||||
/**
|
||||
* Gets whether or not the automatic purge of entities is enabled.
|
||||
*
|
||||
* @return True if automatic purge is enabled.
|
||||
*/
|
||||
boolean isAutoPurgeEntities();
|
||||
|
||||
/**
|
||||
* Sets teleportIntercept.
|
||||
* @param teleportIntercept The new value.
|
||||
*/
|
||||
void setTeleportIntercept(boolean teleportIntercept);
|
||||
|
||||
/**
|
||||
* Gets teleportIntercept.
|
||||
* @return teleportIntercept.
|
||||
*/
|
||||
boolean getTeleportIntercept();
|
||||
|
||||
/**
|
||||
* Sets firstSpawnOverride.
|
||||
* @param firstSpawnOverride The new value.
|
||||
*/
|
||||
void setFirstSpawnOverride(boolean firstSpawnOverride);
|
||||
|
||||
/**
|
||||
* Gets firstSpawnOverride.
|
||||
* @return firstSpawnOverride.
|
||||
*/
|
||||
boolean getFirstSpawnOverride();
|
||||
|
||||
/**
|
||||
* Sets firstSpawnWorld.
|
||||
* @param firstSpawnWorld The new value.
|
||||
*/
|
||||
void setFirstSpawnLocation(String firstSpawnWorld);
|
||||
|
||||
/**
|
||||
* Gets firstSpawnWorld.
|
||||
* @return firstSpawnWorld.
|
||||
*/
|
||||
String getFirstSpawnLocation();
|
||||
|
||||
/**
|
||||
* Sets whether join destination should be enabled.
|
||||
* @param enableJoinDestination The new value
|
||||
*/
|
||||
void setEnableJoinDestination(boolean enableJoinDestination);
|
||||
|
||||
/**
|
||||
* Gets enableJoinDestination.
|
||||
* @return enableJoinDestination
|
||||
*/
|
||||
boolean getEnableJoinDestination();
|
||||
|
||||
/**
|
||||
* Sets alwaysSpawnDestination.
|
||||
* @param alwaysSpawnDestination The new value
|
||||
*/
|
||||
void setJoinDestination(String alwaysSpawnDestination);
|
||||
|
||||
/**
|
||||
* Gets alwaysSpawnDestination.
|
||||
* @return alwaysSpawnLocation
|
||||
*/
|
||||
String getJoinDestination();
|
||||
|
||||
/**
|
||||
* Sets whether or not to let Bukkit determine portal search radius on its own or if Multiverse should give input.
|
||||
*
|
||||
* @param useDefaultPortalSearch True to let Bukkit determine portal search radius on its own.
|
||||
*/
|
||||
void setUseCustomPortalSearch(boolean useDefaultPortalSearch);
|
||||
|
||||
/**
|
||||
* Gets whether or not Bukkit will be determining portal search radius on its own or if Multiverse should help.
|
||||
*
|
||||
* @return True means Bukkit will use its own default values.
|
||||
*/
|
||||
boolean isUsingCustomPortalSearch();
|
||||
|
||||
/**
|
||||
* Sets the radius at which vanilla style portals will be searched for to connect to worlds together.
|
||||
*
|
||||
* @param searchRadius The portal search radius.
|
||||
*/
|
||||
void setCustomPortalSearchRadius(int searchRadius);
|
||||
|
||||
/**
|
||||
* Gets the radius at which vanilla style portals will be searched for to connect to worlds together.
|
||||
*
|
||||
* @return The portal search radius.
|
||||
*/
|
||||
int getCustomPortalSearchRadius();
|
||||
|
||||
/**
|
||||
* Sets prefixChat.
|
||||
* @param prefixChat The new value.
|
||||
*/
|
||||
void setEnablePrefixChat(boolean prefixChat);
|
||||
|
||||
/**
|
||||
* Gets prefixChat.
|
||||
* @return prefixChat.
|
||||
*/
|
||||
boolean isEnablePrefixChat();
|
||||
|
||||
/**
|
||||
* Sets prefixChatFormat.
|
||||
* @param prefixChatFormat The new value.
|
||||
*/
|
||||
void setPrefixChatFormat(String prefixChatFormat);
|
||||
|
||||
/**
|
||||
* Gets prefixChatFormat.
|
||||
* @return prefixChatFormat.
|
||||
*/
|
||||
String getPrefixChatFormat();
|
||||
|
||||
/**
|
||||
* Sets whether to register the {@link MultiverseCorePlaceholders} class with PlaceholderAPI plugin.
|
||||
* @param registerPapiHook The new value.
|
||||
*/
|
||||
void setRegisterPapiHook(boolean registerPapiHook);
|
||||
|
||||
/**
|
||||
* Gets whether to register the {@link MultiverseCorePlaceholders} class with PlaceholderAPI plugin.
|
||||
* @return registerPapiHook.
|
||||
*/
|
||||
boolean isRegisterPapiHook();
|
||||
|
||||
/**
|
||||
* Sets globalDebug.
|
||||
* @param globalDebug The new value.
|
||||
*/
|
||||
void setGlobalDebug(int globalDebug);
|
||||
|
||||
/**
|
||||
* Gets globalDebug.
|
||||
* @return globalDebug.
|
||||
*/
|
||||
int getGlobalDebug();
|
||||
|
||||
/**
|
||||
* Sets whether to suppress startup messages.
|
||||
*
|
||||
* @param silentStart true to suppress messages.
|
||||
*/
|
||||
void setSilentStart(boolean silentStart);
|
||||
|
||||
/**
|
||||
* Whether we are suppressing startup messages.
|
||||
*
|
||||
* @return true if we are suppressing startup messages.
|
||||
*/
|
||||
boolean getSilentStart();
|
||||
|
||||
/**
|
||||
* Sets whether or not the donation/patreon messages are shown.
|
||||
*
|
||||
* @param idonotwanttodonate True if donation/patreon messages should be shown.
|
||||
*/
|
||||
void setShowDonateMessage(boolean idonotwanttodonate);
|
||||
|
||||
/**
|
||||
* Gets whether or not the donation/patreon messages are shown.
|
||||
*
|
||||
* @return True if donation/patreon messages should be shown.
|
||||
*/
|
||||
boolean isShowingDonateMessage();
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Multiverse 2 Copyright (c) the Multiverse Team 2011. *
|
||||
* Multiverse 2 is licensed under the BSD License. *
|
||||
* For more information please check the README.md file included *
|
||||
* with this project. *
|
||||
******************************************************************************/
|
||||
|
||||
package org.mvplugins.multiverse.core.api;
|
||||
|
||||
/**
|
||||
* Multiverse 2 Core API
|
||||
* <p>
|
||||
* This API contains a bunch of useful things you can get out of Multiverse in general!
|
||||
*/
|
||||
public interface MVCore extends MVPlugin {
|
||||
|
||||
/**
|
||||
* Saves all configs.
|
||||
*
|
||||
* @return Whether the config was successfully saved
|
||||
*/
|
||||
boolean saveAllConfigs();
|
||||
|
||||
/**
|
||||
* Decrements the number of plugins that have specifically hooked into core.
|
||||
*/
|
||||
void decrementPluginCount();
|
||||
|
||||
/**
|
||||
* Increments the number of plugins that have specifically hooked into core.
|
||||
*/
|
||||
void incrementPluginCount();
|
||||
|
||||
/**
|
||||
* Returns the number of plugins that have specifically hooked into core.
|
||||
*
|
||||
* @return The number if plugins that have hooked into core.
|
||||
*/
|
||||
int getPluginCount();
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Multiverse 2 Copyright (c) the Multiverse Team 2011. *
|
||||
* Multiverse 2 is licensed under the BSD License. *
|
||||
* For more information please check the README.md file included *
|
||||
* with this project. *
|
||||
******************************************************************************/
|
||||
|
||||
package org.mvplugins.multiverse.core.api;
|
||||
|
||||
/**
|
||||
* This interface is implemented by every official Multiverse-plugin.
|
||||
*/
|
||||
public interface MVPlugin {
|
||||
/**
|
||||
* Gets the reference to MultiverseCore.
|
||||
*
|
||||
* @return A valid {@link org.mvplugins.multiverse.core.MultiverseCore}.
|
||||
*/
|
||||
MVCore getCore();
|
||||
|
||||
/**
|
||||
* Allows Multiverse or a plugin to query another Multiverse plugin to see what version its protocol is. This
|
||||
* number
|
||||
* should change when something will break the code.
|
||||
*
|
||||
* @return The Integer protocol version.
|
||||
*/
|
||||
int getProtocolVersion();
|
||||
|
||||
/**
|
||||
* Parse the Authors Array into a readable String with ',' and 'and'.
|
||||
*
|
||||
* @return The readable authors-{@link String}
|
||||
*/
|
||||
String getAuthors();
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
/**
|
||||
* The Multiverse-API, containing lots of interfaces that can be quite useful for other
|
||||
* plugins when interacting with Multiverse.
|
||||
*/
|
||||
package org.mvplugins.multiverse.core.api;
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
/**
|
||||
* Extends a command class to add legacy alias annotations.
|
||||
*/
|
||||
public interface LegacyAliasCommand {
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import co.aikar.commands.BukkitCommandCompletionContext;
|
||||
import co.aikar.commands.CommandIssuer;
|
||||
import co.aikar.commands.PaperCommandCompletions;
|
||||
import co.aikar.commands.RegisteredCommand;
|
||||
import co.aikar.commands.RootCommand;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import io.vavr.control.Option;
|
||||
import io.vavr.control.Try;
|
||||
import jakarta.inject.Inject;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Difficulty;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.SpawnCategory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.anchor.MultiverseAnchor;
|
||||
import org.mvplugins.multiverse.core.command.context.issueraware.IssuerAwareValue;
|
||||
import org.mvplugins.multiverse.core.command.context.issueraware.MultiverseWorldValue;
|
||||
import org.mvplugins.multiverse.core.command.context.issueraware.PlayerArrayValue;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.config.node.functions.DefaultSuggesterProvider;
|
||||
import org.mvplugins.multiverse.core.config.handle.PropertyModifyAction;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationInstance;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationSuggestionPacket;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
|
||||
import org.mvplugins.multiverse.core.permissions.CorePermissionsChecker;
|
||||
import org.mvplugins.multiverse.core.utils.REPatterns;
|
||||
import org.mvplugins.multiverse.core.utils.StringFormatter;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorPlugin;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
|
||||
|
||||
import static org.mvplugins.multiverse.core.utils.StringFormatter.addonToCommaSeperated;
|
||||
|
||||
@Service
|
||||
public class MVCommandCompletions extends PaperCommandCompletions {
|
||||
|
||||
private final MVCommandManager commandManager;
|
||||
private final WorldManager worldManager;
|
||||
private final DestinationsProvider destinationsProvider;
|
||||
private final CoreConfig config;
|
||||
private final CorePermissionsChecker corePermissionsChecker;
|
||||
private final AnchorManager anchorManager;
|
||||
private final GeneratorProvider generatorProvider;
|
||||
|
||||
@Inject
|
||||
MVCommandCompletions(
|
||||
@NotNull MVCommandManager mvCommandManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull DestinationsProvider destinationsProvider,
|
||||
@NotNull CoreConfig config,
|
||||
@NotNull CorePermissionsChecker corePermissionsChecker,
|
||||
@NotNull AnchorManager anchorManager,
|
||||
@NotNull GeneratorProvider generatorProvider
|
||||
) {
|
||||
super(mvCommandManager);
|
||||
this.commandManager = mvCommandManager;
|
||||
this.worldManager = worldManager;
|
||||
this.destinationsProvider = destinationsProvider;
|
||||
this.config = config;
|
||||
this.corePermissionsChecker = corePermissionsChecker;
|
||||
this.anchorManager = anchorManager;
|
||||
this.generatorProvider = generatorProvider;
|
||||
|
||||
registerAsyncCompletion("anchornames", this::suggestAnchorNames);
|
||||
registerAsyncCompletion("commands", this::suggestCommands);
|
||||
registerAsyncCompletion("destinations", this::suggestDestinations);
|
||||
registerStaticCompletion("difficulties", suggestEnums(Difficulty.class));
|
||||
registerStaticCompletion("environments", suggestEnums(World.Environment.class));
|
||||
registerAsyncCompletion("flags", this::suggestFlags);
|
||||
registerStaticCompletion("gamemodes", suggestEnums(GameMode.class));
|
||||
registerStaticCompletion("gamerules", this::suggestGamerules);
|
||||
registerAsyncCompletion("gamerulesvalues", this::suggestGamerulesValues);
|
||||
registerAsyncCompletion("generatorplugins", this::suggestGeneratorPlugins);
|
||||
registerStaticCompletion("materials", suggestEnums(Material.class));
|
||||
registerStaticCompletion("mvconfigs", config.getStringPropertyHandle().getAllPropertyNames());
|
||||
registerAsyncCompletion("mvconfigvalues", this::suggestMVConfigValues);
|
||||
registerAsyncCompletion("mvworlds", this::suggestMVWorlds);
|
||||
registerAsyncCompletion("mvworldpropsname", this::suggestMVWorldPropsName);
|
||||
registerAsyncCompletion("mvworldpropsvalue", this::suggestMVWorldPropsValue);
|
||||
registerAsyncCompletion("playersarray", this::suggestPlayersArray);
|
||||
registerStaticCompletion("propsmodifyaction", suggestEnums(PropertyModifyAction.class));
|
||||
registerStaticCompletion("spawncategories", suggestEnums(SpawnCategory.class));
|
||||
registerAsyncCompletion("spawncategorypropsname", this::suggestSpawnCategoryPropsName);
|
||||
registerAsyncCompletion("spawncategorypropsvalue", this::suggestSpawnCategoryPropsValue);
|
||||
|
||||
setDefaultCompletion("destinations", DestinationInstance.class);
|
||||
setDefaultCompletion("difficulties", Difficulty.class);
|
||||
setDefaultCompletion("environments", World.Environment.class);
|
||||
setDefaultCompletion("flags", String[].class);
|
||||
setDefaultCompletion("gamemodes", GameMode.class);
|
||||
setDefaultCompletion("gamerules", GameRule.class);
|
||||
setDefaultCompletion("mvworlds", LoadedMultiverseWorld.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<BukkitCommandCompletionContext> handler) {
|
||||
return super.registerCompletion(id, context ->
|
||||
completeWithPreconditions(context, handler));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<BukkitCommandCompletionContext> handler) {
|
||||
return super.registerAsyncCompletion(id, context ->
|
||||
completeWithPreconditions(context, handler));
|
||||
}
|
||||
|
||||
private Collection<String> completeWithPreconditions(
|
||||
BukkitCommandCompletionContext context,
|
||||
CommandCompletionHandler<BukkitCommandCompletionContext> handler) {
|
||||
if (context.hasConfig("playerOnly") && !context.getIssuer().isPlayer()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (context.hasConfig("byIssuerForArg")) {
|
||||
Boolean byIssuerForArg = Try.of(() -> context.getContextValueByName(IssuerAwareValue.class, context.getConfig("byIssuerForArg")))
|
||||
.map(IssuerAwareValue::isByIssuer)
|
||||
.getOrElse(false);
|
||||
if (!byIssuerForArg) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
if (context.hasConfig("notByIssuerForArg")) {
|
||||
Boolean byIssuerForArg = Try.of(() -> context.getContextValueByName(IssuerAwareValue.class, context.getConfig("notByIssuerForArg")))
|
||||
.map(IssuerAwareValue::isByIssuer)
|
||||
.getOrElse(false);
|
||||
if (byIssuerForArg) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
if (context.hasConfig("resolveUntil")) {
|
||||
if (!Try.run(() -> context.getContextValueByName(Object.class, context.getConfig("resolveUntil"))).isSuccess()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
if (context.hasConfig("checkPermissions")) {
|
||||
for (String permission : REPatterns.SEMICOLON.split(context.getConfig("checkPermissions"))) {
|
||||
if (!commandManager.getCommandPermissions().hasPermission(context.getIssuer(), permission)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (context.hasConfig("multiple")) {
|
||||
return addonToCommaSeperated(context.getInput(), handler.getCompletions(context));
|
||||
}
|
||||
return handler.getCompletions(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to suggest enums values
|
||||
*
|
||||
* @param enumClass The enum class with values
|
||||
* @return A collection of possible string values
|
||||
* @param <T> The enum type
|
||||
*/
|
||||
public <T extends Enum<T>> Collection<String> suggestEnums(Class<T> enumClass) {
|
||||
return EnumSet.allOf(enumClass).stream()
|
||||
.map(Enum::name)
|
||||
.map(String::toLowerCase)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private Collection<String> suggestAnchorNames(BukkitCommandCompletionContext context) {
|
||||
return anchorManager.getAnchors(context.getPlayer()).stream()
|
||||
.map(MultiverseAnchor::getName)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private Collection<String> suggestCommands(BukkitCommandCompletionContext context) {
|
||||
String rootCmdName = context.getConfig();
|
||||
if (rootCmdName == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
RootCommand rootCommand = this.commandManager.getRegisteredRootCommands().stream()
|
||||
.unordered()
|
||||
.filter(c -> c.getCommandName().equals(rootCmdName))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (rootCommand == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return rootCommand.getSubCommands().entries().stream()
|
||||
.filter(entry -> checkPerms(context.getIssuer(), entry.getValue()))
|
||||
.map(Map.Entry::getKey)
|
||||
.filter(cmdName -> !cmdName.startsWith("__"))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private boolean checkPerms(CommandIssuer issuer, RegisteredCommand<?> command) {
|
||||
return this.commandManager.hasPermission(issuer, command.getRequiredPermissions());
|
||||
}
|
||||
|
||||
private Collection<String> suggestDestinations(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> context.getContextValue(PlayerArrayValue.class))
|
||||
.map(PlayerArrayValue::value)
|
||||
.recover(IllegalStateException.class, e -> context.getContextValue(Player[].class))
|
||||
.recover(IllegalStateException.class, e -> new Player[]{context.getContextValue(Player.class)})
|
||||
.map(players -> {
|
||||
if (players.length == 0) {
|
||||
// Most likely console did not specify a player
|
||||
return Collections.<String>emptyList();
|
||||
}
|
||||
if (context.hasConfig("othersOnly") && (players.length == 1 && players[0].equals(context.getIssuer().getIssuer()))) {
|
||||
return Collections.<String>emptyList();
|
||||
}
|
||||
return suggestDestinationsWithPerms(context.getIssuer().getIssuer(), players, context.getInput());
|
||||
})
|
||||
.getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestDestinationsWithPerms(CommandSender teleporter, Player[] players, String deststring) {
|
||||
return destinationsProvider.suggestDestinations(teleporter, deststring).stream()
|
||||
.filter(packet -> corePermissionsChecker
|
||||
.checkDestinationPacketPermission(teleporter, Arrays.asList(players), packet))
|
||||
.map(DestinationSuggestionPacket::parsableString)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private Collection<String> suggestFlags(@NotNull BukkitCommandCompletionContext context) {
|
||||
String groupName = context.getConfig("groupName", "");
|
||||
|
||||
return Try.of(() -> context.getContextValue(String[].class))
|
||||
.map(flags -> commandManager.getFlagsManager().suggest(groupName, flags))
|
||||
.getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestGamerules() {
|
||||
return Arrays.stream(GameRule.values()).map(GameRule::getName).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestGamerulesValues(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> context.getContextValue(GameRule.class))
|
||||
// Just use our suggester from configuration lib since gamerules are only boolean or int
|
||||
.mapTry(gamerule -> Option.of(DefaultSuggesterProvider.getDefaultSuggester(gamerule.getType()))
|
||||
.map(s -> s.suggest(context.getInput())).getOrElse(Collections.emptyList()))
|
||||
.getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestGeneratorPlugins(BukkitCommandCompletionContext context) {
|
||||
return generatorProvider.getRegisteredGeneratorPlugins().stream()
|
||||
.map(GeneratorPlugin::getPluginName)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private Collection<String> suggestMVConfigValues(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> context.getContextValue(String.class))
|
||||
.map(propertyName -> config.getStringPropertyHandle()
|
||||
.getSuggestedPropertyValue(propertyName, context.getInput(), PropertyModifyAction.SET, context.getSender()))
|
||||
.getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestMVWorlds(BukkitCommandCompletionContext context) {
|
||||
String scope = context.getConfig("scope", "loaded");
|
||||
switch (scope) {
|
||||
case "both" -> {
|
||||
return worldManager.getWorlds().stream()
|
||||
.map(MultiverseWorld::getTabCompleteName)
|
||||
.map(StringFormatter::quoteMultiWordString)
|
||||
.toList();
|
||||
}
|
||||
case "loaded" -> {
|
||||
return worldManager.getLoadedWorlds().stream()
|
||||
.map(MultiverseWorld::getTabCompleteName)
|
||||
.map(StringFormatter::quoteMultiWordString)
|
||||
.toList();
|
||||
}
|
||||
case "unloaded" -> {
|
||||
return worldManager.getUnloadedWorlds().stream()
|
||||
.map(MultiverseWorld::getTabCompleteName)
|
||||
.map(StringFormatter::quoteMultiWordString)
|
||||
.toList();
|
||||
}
|
||||
case "potential" -> {
|
||||
return worldManager.getPotentialWorlds();
|
||||
}
|
||||
}
|
||||
Logging.severe("Invalid MVWorld scope: " + scope);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private Collection<String> suggestMVWorldPropsName(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> {
|
||||
MultiverseWorld world = context.getContextValue(MultiverseWorldValue.class).value();
|
||||
PropertyModifyAction action = context.getContextValue(PropertyModifyAction.class);
|
||||
return world.getStringPropertyHandle().getModifiablePropertyNames(action);
|
||||
}).getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestMVWorldPropsValue(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> {
|
||||
MultiverseWorld world = context.getContextValue(MultiverseWorldValue.class).value();
|
||||
PropertyModifyAction action = context.getContextValue(PropertyModifyAction.class);
|
||||
String propertyName = context.getContextValue(String.class);
|
||||
return world.getStringPropertyHandle().getSuggestedPropertyValue(propertyName, context.getInput(), action, context.getSender());
|
||||
}).getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestPlayersArray(BukkitCommandCompletionContext context) {
|
||||
CommandSender sender = context.getSender();
|
||||
Validate.notNull(sender, "Sender cannot be null");
|
||||
Player senderPlayer = sender instanceof Player ? (Player)sender : null;
|
||||
List<String> matchedPlayers = new ArrayList<>();
|
||||
|
||||
for(Player player : Bukkit.getOnlinePlayers()) {
|
||||
String name = player.getName();
|
||||
if ((senderPlayer == null || senderPlayer.canSee(player))
|
||||
&& (!context.hasConfig("excludeSelf") || !player.equals(senderPlayer))) {
|
||||
matchedPlayers.add(name);
|
||||
}
|
||||
}
|
||||
return addonToCommaSeperated(context.getInput(), matchedPlayers);
|
||||
}
|
||||
|
||||
private Collection<String> suggestSpawnCategoryPropsName(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> {
|
||||
MultiverseWorld world = context.getContextValue(MultiverseWorld.class);
|
||||
SpawnCategory spawnCategory = context.getContextValue(SpawnCategory.class);
|
||||
PropertyModifyAction action = context.getContextValue(PropertyModifyAction.class);
|
||||
return world.getEntitySpawnConfig()
|
||||
.getSpawnCategoryConfig(spawnCategory)
|
||||
.getStringPropertyHandle()
|
||||
.getModifiablePropertyNames(action);
|
||||
}).getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestSpawnCategoryPropsValue(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> {
|
||||
MultiverseWorld world = context.getContextValue(MultiverseWorld.class);
|
||||
SpawnCategory spawnCategory = context.getContextValue(SpawnCategory.class);
|
||||
PropertyModifyAction action = context.getContextValue(PropertyModifyAction.class);
|
||||
String propertyName = context.getContextValue(String.class);
|
||||
return world.getEntitySpawnConfig()
|
||||
.getSpawnCategoryConfig(spawnCategory)
|
||||
.getStringPropertyHandle()
|
||||
.getSuggestedPropertyValue(propertyName, context.getInput(), action, context.getSender());
|
||||
}).getOrElse(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
+8
-5
@@ -1,4 +1,4 @@
|
||||
package org.mvplugins.multiverse.core.commandtools;
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import co.aikar.commands.BukkitCommandExecutionContext;
|
||||
import co.aikar.commands.BukkitCommandIssuer;
|
||||
@@ -8,12 +8,16 @@ import co.aikar.commands.ConditionContext;
|
||||
import co.aikar.commands.ConditionFailedException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.mvplugins.multiverse.core.world.WorldNameChecker;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.helpers.WorldNameChecker;
|
||||
|
||||
public class MVCommandConditions {
|
||||
static void load(MVCommandManager commandManager, WorldManager worldManager, WorldNameChecker worldNameChecker) {
|
||||
new MVCommandConditions(commandManager, worldManager, worldNameChecker);
|
||||
static void load(
|
||||
@NotNull MVCommandManager commandManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull WorldNameChecker worldNameChecker) {
|
||||
MVCommandConditions mvCommandConditions = new MVCommandConditions(commandManager, worldManager, worldNameChecker);
|
||||
mvCommandConditions.registerConditions();
|
||||
}
|
||||
|
||||
private final WorldManager worldManager;
|
||||
@@ -27,7 +31,6 @@ public class MVCommandConditions {
|
||||
this.worldManager = worldManager;
|
||||
this.commandManager = commandManager;
|
||||
this.worldNameChecker = worldNameChecker;
|
||||
registerConditions();
|
||||
}
|
||||
|
||||
private void registerConditions() {
|
||||
@@ -0,0 +1,383 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import co.aikar.commands.ACFUtil;
|
||||
import co.aikar.commands.BukkitCommandExecutionContext;
|
||||
import co.aikar.commands.BukkitCommandIssuer;
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import co.aikar.commands.MinecraftMessageKeys;
|
||||
import co.aikar.commands.PaperCommandContexts;
|
||||
import co.aikar.commands.contexts.ContextResolver;
|
||||
import com.google.common.base.Strings;
|
||||
import io.vavr.control.Try;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.BlockCommandSender;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.SpawnCategory;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.anchor.MultiverseAnchor;
|
||||
import org.mvplugins.multiverse.core.command.context.GameRuleValue;
|
||||
import org.mvplugins.multiverse.core.command.context.issueraware.IssuerAwareContextBuilder;
|
||||
import org.mvplugins.multiverse.core.command.context.PlayerLocation;
|
||||
import org.mvplugins.multiverse.core.command.context.issueraware.MultiverseWorldValue;
|
||||
import org.mvplugins.multiverse.core.command.context.issueraware.PlayerArrayValue;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationInstance;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
|
||||
import org.mvplugins.multiverse.core.display.filters.ContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.DefaultContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.RegexContentFilter;
|
||||
import org.mvplugins.multiverse.core.exceptions.command.MVInvalidCommandArgument;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.utils.PlayerFinder;
|
||||
import org.mvplugins.multiverse.core.utils.REPatterns;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorPlugin;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
|
||||
|
||||
@Service
|
||||
public class MVCommandContexts extends PaperCommandContexts {
|
||||
|
||||
private final MVCommandManager mvCommandManager;
|
||||
private final DestinationsProvider destinationsProvider;
|
||||
private final WorldManager worldManager;
|
||||
private final CoreConfig config;
|
||||
private final AnchorManager anchorManager;
|
||||
private final GeneratorProvider generatorProvider;
|
||||
|
||||
@Inject
|
||||
MVCommandContexts(
|
||||
MVCommandManager mvCommandManager,
|
||||
DestinationsProvider destinationsProvider,
|
||||
WorldManager worldManager,
|
||||
CoreConfig config,
|
||||
AnchorManager anchorManager,
|
||||
GeneratorProvider generatorProvider
|
||||
) {
|
||||
super(mvCommandManager);
|
||||
this.mvCommandManager = mvCommandManager;
|
||||
this.destinationsProvider = destinationsProvider;
|
||||
this.worldManager = worldManager;
|
||||
this.config = config;
|
||||
this.anchorManager = anchorManager;
|
||||
this.generatorProvider = generatorProvider;
|
||||
|
||||
registerIssuerOnlyContext(BukkitCommandIssuer.class, BukkitCommandExecutionContext::getIssuer);
|
||||
registerIssuerOnlyContext(MVCommandIssuer.class, this::parseMVCommandIssuer);
|
||||
registerOptionalContext(ContentFilter.class, this::parseContentFilter);
|
||||
registerContext(DestinationInstance.class, this::parseDestination);
|
||||
registerContext(GameRule.class, this::parseGameRule);
|
||||
registerContext(GameRuleValue.class, this::parseGameRuleValue);
|
||||
registerContext(GeneratorPlugin.class, this::parseGeneratorPlugin);
|
||||
registerIssuerAwareContext(LoadedMultiverseWorld.class, loadedMultiverseWorldContextBuilder().generateContext());
|
||||
registerIssuerAwareContext(LoadedMultiverseWorld[].class, loadedMultiverseWorldArrayContextBuilder().generateContext());
|
||||
registerIssuerAwareContext(MultiverseWorld.class, multiverseWorldContextBuilder().generateContext());
|
||||
registerIssuerAwareContext(MultiverseWorldValue.class, multiverseWorldContextBuilder().generateContext(MultiverseWorldValue::new));
|
||||
registerIssuerAwareContext(MultiverseWorld[].class, multiverseWorldArrayContextBuilder().generateContext());
|
||||
registerContext(MultiverseAnchor.class, this::parseMultiverseAnchor);
|
||||
registerIssuerAwareContext(Player.class, playerContextBuilder().generateContext());
|
||||
registerIssuerAwareContext(Player[].class, playerArrayContextBuilder().generateContext());
|
||||
registerIssuerAwareContext(PlayerArrayValue.class, playerArrayContextBuilder().generateContext(PlayerArrayValue::new));
|
||||
registerIssuerAwareContext(PlayerLocation.class, this::parsePlayerLocation);
|
||||
registerContext(SpawnCategory[].class, this::parseSpawnCategories);
|
||||
}
|
||||
|
||||
private MVCommandIssuer parseMVCommandIssuer(BukkitCommandExecutionContext context) {
|
||||
if (context.getIssuer() instanceof MVCommandIssuer) {
|
||||
return (MVCommandIssuer) context.getIssuer();
|
||||
}
|
||||
return mvCommandManager.getCommandIssuer(context.getSender());
|
||||
}
|
||||
|
||||
private ContentFilter parseContentFilter(BukkitCommandExecutionContext context) {
|
||||
if (Strings.isNullOrEmpty(context.getFirstArg())) {
|
||||
return DefaultContentFilter.get();
|
||||
}
|
||||
String filterString = context.popFirstArg();
|
||||
return RegexContentFilter.fromString(filterString);
|
||||
}
|
||||
|
||||
private DestinationInstance<?, ?> parseDestination(BukkitCommandExecutionContext context) {
|
||||
String destination = context.popFirstArg();
|
||||
if (Strings.isNullOrEmpty(destination)) {
|
||||
throw new InvalidCommandArgument("No destination specified.");
|
||||
}
|
||||
|
||||
return destinationsProvider.parseDestination(context.getSender(), destination)
|
||||
.getOrThrow(failure ->
|
||||
new InvalidCommandArgument(failure.getFailureMessage().formatted(context.getIssuer())));
|
||||
}
|
||||
|
||||
private GameRule<?> parseGameRule(BukkitCommandExecutionContext context) {
|
||||
String gameRuleName = context.popFirstArg();
|
||||
if (Strings.isNullOrEmpty(gameRuleName)) {
|
||||
throw new InvalidCommandArgument("No game rule specified.");
|
||||
}
|
||||
|
||||
GameRule<?> gameRule = GameRule.getByName(gameRuleName);
|
||||
if (gameRule == null) {
|
||||
throw new InvalidCommandArgument("The game rule " + gameRuleName + " is not valid.");
|
||||
}
|
||||
|
||||
return gameRule;
|
||||
}
|
||||
|
||||
private GameRuleValue parseGameRuleValue(BukkitCommandExecutionContext context) {
|
||||
GameRule<?> gameRule = (GameRule<?>) context.getResolvedArg(GameRule.class);
|
||||
if (gameRule == null) {
|
||||
throw new InvalidCommandArgument("No game rule specified.");
|
||||
}
|
||||
String valueString = context.getFirstArg();
|
||||
if (Strings.isNullOrEmpty(valueString)) {
|
||||
throw new InvalidCommandArgument("No game rule value specified.");
|
||||
}
|
||||
|
||||
ContextResolver<?, BukkitCommandExecutionContext> resolver = getResolver(gameRule.getType());
|
||||
if (resolver == null) {
|
||||
return new GameRuleValue(valueString);
|
||||
}
|
||||
|
||||
Object resolvedValue = resolver.getContext(context);
|
||||
if (resolvedValue == null) {
|
||||
throw new InvalidCommandArgument("The game rule value " + valueString + " is not valid for game rule " + gameRule.getName() + ".");
|
||||
}
|
||||
|
||||
return new GameRuleValue(resolvedValue);
|
||||
}
|
||||
|
||||
private GeneratorPlugin parseGeneratorPlugin(BukkitCommandExecutionContext context) {
|
||||
GeneratorPlugin generatorPlugin = generatorProvider.getGeneratorPlugin(context.popFirstArg());
|
||||
if (generatorPlugin == null) {
|
||||
throw new InvalidCommandArgument("Invalid generator plugin: " + context.getFirstArg());
|
||||
}
|
||||
return generatorPlugin;
|
||||
}
|
||||
|
||||
|
||||
private IssuerAwareContextBuilder<LoadedMultiverseWorld> loadedMultiverseWorldContextBuilder() {
|
||||
return new IssuerAwareContextBuilder<LoadedMultiverseWorld>()
|
||||
.fromPlayer((context, player) -> worldManager.getLoadedWorld(player.getWorld()).getOrNull())
|
||||
.fromInput((context, input) -> getLoadedMultiverseWorld(input))
|
||||
.issuerOnlyFailMessage((context) -> Message.of("This command can only be used by a player in a loaded Multiverse World."))
|
||||
.issuerAwarePlayerFailMessage((context, player) -> Message.of("You are not in a loaded multiverse world. Either specify a multiverse world name or use this command in a loaded multiverse world."))
|
||||
.issuerAwareInputFailMessage((context, input) -> Message.of("World '" + input + "' is not a loaded multiverse world. Remember to specify the world name when using this command in console."))
|
||||
.inputOnlyFailMessage((context, input) -> Message.of("World " + input + " is not a loaded multiverse world."));
|
||||
}
|
||||
|
||||
private IssuerAwareContextBuilder<LoadedMultiverseWorld[]> loadedMultiverseWorldArrayContextBuilder() {
|
||||
return new IssuerAwareContextBuilder<LoadedMultiverseWorld[]>()
|
||||
.fromPlayer((context, player) -> worldManager.getLoadedWorld(player.getWorld())
|
||||
.map(world -> new LoadedMultiverseWorld[]{world})
|
||||
.getOrNull())
|
||||
.fromInput((context, input) -> {
|
||||
String[] worldNames = input == null ? new String[0] : REPatterns.COMMA.split(input);
|
||||
Set<LoadedMultiverseWorld> worlds = new HashSet<>(worldNames.length);
|
||||
for (String worldName : worldNames) {
|
||||
if ("*".equals(worldName)) {
|
||||
worlds.addAll(worldManager.getLoadedWorlds());
|
||||
break;
|
||||
}
|
||||
LoadedMultiverseWorld world = getLoadedMultiverseWorld(worldName);
|
||||
if (world == null) {
|
||||
throw new InvalidCommandArgument("World " + worldName + " is not a loaded multiverse world.");
|
||||
}
|
||||
worlds.add(world);
|
||||
}
|
||||
return worlds.isEmpty() ? null : worlds.toArray(new LoadedMultiverseWorld[0]);
|
||||
})
|
||||
.issuerOnlyFailMessage((context) -> Message.of("This command can only be used by a player in a loaded Multiverse World."))
|
||||
.issuerAwarePlayerFailMessage((context, player) -> Message.of("You are not in a loaded multiverse world. Either specify a multiverse world name or use this command in a loaded multiverse world."))
|
||||
.issuerAwareInputFailMessage((context, input) -> Message.of("World '" + input + "' is not a loaded multiverse world. Remember to specify the world name when using this command in console."))
|
||||
.inputOnlyFailMessage((context, input) -> Message.of("World " + input + " is not a loaded multiverse world."));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LoadedMultiverseWorld getLoadedMultiverseWorld(String worldName) {
|
||||
return config.getResolveAliasName()
|
||||
? worldManager.getLoadedWorldByNameOrAlias(worldName).getOrNull()
|
||||
: worldManager.getLoadedWorld(worldName).getOrNull();
|
||||
}
|
||||
|
||||
private IssuerAwareContextBuilder<MultiverseWorld> multiverseWorldContextBuilder() {
|
||||
return new IssuerAwareContextBuilder<MultiverseWorld>()
|
||||
.fromPlayer((context, player) -> worldManager.getWorld(player.getWorld()).getOrNull())
|
||||
.fromInput((context, input) -> getMultiverseWorld(input))
|
||||
.issuerOnlyFailMessage((context) -> Message.of("This command can only be used by a player in a Multiverse World."))
|
||||
.issuerAwarePlayerFailMessage((context, player) -> Message.of("You are not in a multiverse world. Either specify a multiverse world name or use this command in a multiverse world."))
|
||||
.issuerAwareInputFailMessage((context, input) -> Message.of("World '" + input + "' is not a multiverse world. Remember to specify the world name when using this command in console."))
|
||||
.inputOnlyFailMessage((context, input) -> Message.of("World " + input + " is not a multiverse world."));
|
||||
}
|
||||
|
||||
private IssuerAwareContextBuilder<MultiverseWorld[]> multiverseWorldArrayContextBuilder() {
|
||||
return new IssuerAwareContextBuilder<MultiverseWorld[]>()
|
||||
.fromPlayer((context, player) -> worldManager.getWorld(player.getWorld())
|
||||
.map(world -> new MultiverseWorld[]{world})
|
||||
.getOrNull())
|
||||
.fromInput((context, input) -> {
|
||||
String[] worldNames = input == null ? new String[0] : REPatterns.COMMA.split(input);
|
||||
Set<MultiverseWorld> worlds = new HashSet<>(worldNames.length);
|
||||
for (String worldName : worldNames) {
|
||||
if ("*".equals(worldName)) {
|
||||
worlds.addAll(worldManager.getWorlds());
|
||||
break;
|
||||
}
|
||||
MultiverseWorld world = getMultiverseWorld(worldName);
|
||||
if (world == null) {
|
||||
throw new InvalidCommandArgument("World " + worldName + " is not a multiverse world.");
|
||||
}
|
||||
worlds.add(world);
|
||||
}
|
||||
return worlds.isEmpty() ? null : worlds.toArray(new MultiverseWorld[0]);
|
||||
})
|
||||
.issuerOnlyFailMessage((context) -> Message.of("This command can only be used by a player in a Multiverse World."))
|
||||
.issuerAwarePlayerFailMessage((context, player) -> Message.of("You are not in a multiverse world. Either specify a multiverse world name or use this command in a multiverse world."))
|
||||
.issuerAwareInputFailMessage((context, input) -> Message.of("World '" + input + "' is not a multiverse world. Remember to specify the world name when using this command in console."))
|
||||
.inputOnlyFailMessage((context, input) -> Message.of("World " + input + " is not a multiverse world."));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private MultiverseWorld getMultiverseWorld(String worldName) {
|
||||
return config.getResolveAliasName()
|
||||
? worldManager.getWorldByNameOrAlias(worldName).getOrNull()
|
||||
: worldManager.getWorld(worldName).getOrNull();
|
||||
}
|
||||
|
||||
private MultiverseAnchor parseMultiverseAnchor(BukkitCommandExecutionContext context) {
|
||||
String anchorName = context.popFirstArg();
|
||||
return anchorManager.getAnchor(anchorName)
|
||||
.getOrElseThrow(() -> new InvalidCommandArgument("The anchor '" +anchorName + "' does not exist."));
|
||||
}
|
||||
|
||||
private IssuerAwareContextBuilder<Player> playerContextBuilder() {
|
||||
return new IssuerAwareContextBuilder<Player>()
|
||||
.fromPlayer((context, player) -> player)
|
||||
.fromInput((context, input) -> PlayerFinder.get(input, context.getSender()))
|
||||
.issuerOnlyFailMessage((context) -> Message.of("This command can only be used by a player."))
|
||||
.issuerAwareInputFailMessage((context, input) -> Message.of("Invalid player: " + input + ". Either specify an online player or use this command as a player."))
|
||||
.inputOnlyFailMessage((context, input) -> Message.of("Player " + input + " not found."));
|
||||
}
|
||||
|
||||
private IssuerAwareContextBuilder<Player[]> playerArrayContextBuilder() {
|
||||
return new IssuerAwareContextBuilder<Player[]>()
|
||||
.fromPlayer((context, player) -> new Player[]{player})
|
||||
.fromInput((context, input) -> {
|
||||
Player[] players = PlayerFinder.getMulti(input, context.getSender()).toArray(new Player[0]);
|
||||
return (players.length == 0) ? null : players;
|
||||
})
|
||||
.issuerOnlyFailMessage((context) -> Message.of("This command can only be used by a player."))
|
||||
.issuerAwareInputFailMessage((context, input) -> Message.of("Invalid player: " + input + ". Either specify an online player or use this command as a player."))
|
||||
.inputOnlyFailMessage((context, input) -> Message.of("Player " + input + " not found."));
|
||||
}
|
||||
|
||||
private PlayerLocation parsePlayerLocation(BukkitCommandExecutionContext context) {
|
||||
Try<Location> location = Try.of(() -> parseLocationFromInput(context.getFirstArg(), context.getSender()));
|
||||
|
||||
if (location.isSuccess()) {
|
||||
context.popFirstArg();
|
||||
return new PlayerLocation(location.get());
|
||||
}
|
||||
if (context.getPlayer() != null) {
|
||||
return new PlayerLocation(context.getPlayer().getLocation());
|
||||
}
|
||||
if (context.getFirstArg() == null) {
|
||||
throw new InvalidCommandArgument("You must specify a world location when using this command in console.");
|
||||
}
|
||||
if (location.getCause() instanceof InvalidCommandArgument) {
|
||||
throw (InvalidCommandArgument)location.getCause();
|
||||
}
|
||||
throw new RuntimeException(location.getCause());
|
||||
}
|
||||
|
||||
// copied from ACF
|
||||
private Location parseLocationFromInput(String input, CommandSender sender) {
|
||||
String[] split = REPatterns.COLON.split(input, 2);
|
||||
if (split.length == 0) {
|
||||
throw new InvalidCommandArgument(true);
|
||||
} else if (split.length < 2 && !(sender instanceof Player) && !(sender instanceof BlockCommandSender)) {
|
||||
throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_PLEASE_SPECIFY_WORLD, new String[0]);
|
||||
} else {
|
||||
Location sourceLoc = null;
|
||||
String world;
|
||||
String rest;
|
||||
if (split.length == 2) {
|
||||
world = split[0];
|
||||
rest = split[1];
|
||||
} else if (sender instanceof Player) {
|
||||
sourceLoc = ((Player)sender).getLocation();
|
||||
world = sourceLoc.getWorld().getName();
|
||||
rest = split[0];
|
||||
} else {
|
||||
if (!(sender instanceof BlockCommandSender)) {
|
||||
throw new InvalidCommandArgument(true);
|
||||
}
|
||||
|
||||
sourceLoc = ((BlockCommandSender)sender).getBlock().getLocation();
|
||||
world = sourceLoc.getWorld().getName();
|
||||
rest = split[0];
|
||||
}
|
||||
|
||||
boolean rel = rest.startsWith("~");
|
||||
split = REPatterns.COMMA.split(rel ? rest.substring(1) : rest);
|
||||
if (split.length < 3) {
|
||||
throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_PLEASE_SPECIFY_XYZ, new String[0]);
|
||||
} else {
|
||||
Double x = ACFUtil.parseDouble(split[0], rel ? (double)0.0F : null);
|
||||
Double y = ACFUtil.parseDouble(split[1], rel ? (double)0.0F : null);
|
||||
Double z = ACFUtil.parseDouble(split[2], rel ? (double)0.0F : null);
|
||||
if (sourceLoc != null && rel) {
|
||||
x = x + sourceLoc.getX();
|
||||
y = y + sourceLoc.getY();
|
||||
z = z + sourceLoc.getZ();
|
||||
} else if (rel) {
|
||||
throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_CONSOLE_NOT_RELATIVE, new String[0]);
|
||||
}
|
||||
|
||||
if (x != null && y != null && z != null) {
|
||||
World worldObj = Bukkit.getWorld(world);
|
||||
if (worldObj == null) {
|
||||
throw new InvalidCommandArgument(MinecraftMessageKeys.INVALID_WORLD, new String[0]);
|
||||
} else if (split.length >= 5) {
|
||||
Float yaw = ACFUtil.parseFloat(split[3]);
|
||||
Float pitch = ACFUtil.parseFloat(split[4]);
|
||||
if (pitch != null && yaw != null) {
|
||||
return new Location(worldObj, x, y, z, yaw, pitch);
|
||||
} else {
|
||||
throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_PLEASE_SPECIFY_XYZ, new String[0]);
|
||||
}
|
||||
} else {
|
||||
return new Location(worldObj, x, y, z);
|
||||
}
|
||||
} else {
|
||||
throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_PLEASE_SPECIFY_XYZ, new String[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SpawnCategory[] parseSpawnCategories(BukkitCommandExecutionContext context) {
|
||||
if (context.isOptional() && context.getArgs().isEmpty()) {
|
||||
return new SpawnCategory[0];
|
||||
}
|
||||
Set<SpawnCategory> categories = new HashSet<>();
|
||||
String[] split = REPatterns.COMMA.split(context.popFirstArg());
|
||||
for (String category : split) {
|
||||
SpawnCategory spawnCategory = ACFUtil.simpleMatch(SpawnCategory.class, category);
|
||||
if (spawnCategory != null) {
|
||||
categories.add(spawnCategory);
|
||||
}
|
||||
}
|
||||
return categories.toArray(new SpawnCategory[0]);
|
||||
}
|
||||
}
|
||||
+34
-17
@@ -1,16 +1,16 @@
|
||||
package org.mvplugins.multiverse.core.commandtools;
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import co.aikar.commands.MessageKeys;
|
||||
import co.aikar.commands.BukkitCommandIssuer;
|
||||
import co.aikar.commands.MessageType;
|
||||
import co.aikar.commands.OpenBukkitCommandIssuer;
|
||||
import co.aikar.locales.MessageKeyProvider;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.mvplugins.multiverse.core.utils.message.Message;
|
||||
import org.mvplugins.multiverse.core.utils.message.MessageReplacement;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement;
|
||||
import org.mvplugins.multiverse.core.utils.text.ChatTextFormatter;
|
||||
|
||||
public class MVCommandIssuer extends OpenBukkitCommandIssuer {
|
||||
public class MVCommandIssuer extends BukkitCommandIssuer {
|
||||
|
||||
private final MVCommandManager commandManager;
|
||||
|
||||
@@ -24,16 +24,29 @@ public class MVCommandIssuer extends OpenBukkitCommandIssuer {
|
||||
return commandManager;
|
||||
}
|
||||
|
||||
public void sendError(String message) {
|
||||
sendMessage(MessageType.INFO, MessageKeys.INFO_MESSAGE, "{message}", message);
|
||||
@Override
|
||||
public void sendMessageInternal(String message) {
|
||||
ChatTextFormatter.sendFormattedMessage(getIssuer(), message);
|
||||
}
|
||||
|
||||
public void sendSyntax(String message) {
|
||||
sendMessage(MessageType.SYNTAX, MessageKeys.INFO_MESSAGE, "{message}", message);
|
||||
public void sendError(String message, MessageReplacement... replacements) {
|
||||
sendMessage(MessageType.ERROR, message, replacements);
|
||||
}
|
||||
|
||||
public void sendInfo(String message) {
|
||||
sendMessage(MessageType.INFO, MessageKeys.INFO_MESSAGE, "{message}", message);
|
||||
public void sendSyntax(String message, MessageReplacement... replacements) {
|
||||
sendMessage(MessageType.SYNTAX, message, replacements);
|
||||
}
|
||||
|
||||
public void sendInfo(String message, MessageReplacement... replacements) {
|
||||
sendMessage(MessageType.INFO, message, replacements);
|
||||
}
|
||||
|
||||
public void sendMessage(String message, MessageReplacement... replacements) {
|
||||
sendMessage(null, Message.of(message, replacements));
|
||||
}
|
||||
|
||||
public void sendMessage(MessageType type, String message, MessageReplacement... replacements) {
|
||||
sendMessage(type, Message.of(message, replacements));
|
||||
}
|
||||
|
||||
public void sendMessage(MessageType messageType, String message) {
|
||||
@@ -68,12 +81,12 @@ public class MVCommandIssuer extends OpenBukkitCommandIssuer {
|
||||
public void sendInfo(MessageKeyProvider key, MessageReplacement... replacements) {
|
||||
sendMessage(MessageType.INFO, key, replacements);
|
||||
}
|
||||
public void sendMessage(MessageKeyProvider key, MessageReplacement... replacements) {
|
||||
sendMessage(null, Message.of(key, replacements));
|
||||
}
|
||||
|
||||
private void sendMessage(MessageType messageType, MessageKeyProvider key, MessageReplacement... replacements) {
|
||||
sendMessage(messageType, Message.of(
|
||||
key,
|
||||
"{error_key: %s}".formatted(key.getMessageKey().getKey()),
|
||||
replacements));
|
||||
public void sendMessage(MessageType messageType, MessageKeyProvider key, MessageReplacement... replacements) {
|
||||
sendMessage(messageType, Message.of(key, replacements));
|
||||
}
|
||||
|
||||
public void sendError(Message message) {
|
||||
@@ -88,6 +101,10 @@ public class MVCommandIssuer extends OpenBukkitCommandIssuer {
|
||||
sendMessage(MessageType.INFO, message);
|
||||
}
|
||||
|
||||
public void sendMessage(Message message) {
|
||||
sendMessage(null, message);
|
||||
}
|
||||
|
||||
public void sendMessage(MessageType messageType, Message message) {
|
||||
if (message instanceof MessageKeyProvider) {
|
||||
sendMessage(messageType, (MessageKeyProvider) message,
|
||||
+78
-16
@@ -1,14 +1,17 @@
|
||||
package org.mvplugins.multiverse.core.commandtools;
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import co.aikar.commands.BukkitCommandCompletionContext;
|
||||
import co.aikar.commands.BukkitCommandExecutionContext;
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.CommandCompletions;
|
||||
import co.aikar.commands.CommandContexts;
|
||||
import co.aikar.commands.CommandHelp;
|
||||
import co.aikar.commands.CommandIssuer;
|
||||
import co.aikar.commands.HelpEntry;
|
||||
import co.aikar.commands.LogLevel;
|
||||
import co.aikar.commands.PaperCommandManager;
|
||||
import co.aikar.commands.RootCommand;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Provider;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -17,10 +20,12 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.MultiverseCore;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.queue.CommandQueueManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.queue.CommandQueueManager;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.locale.PluginLocales;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.WorldNameChecker;
|
||||
import org.mvplugins.multiverse.core.world.helpers.WorldNameChecker;
|
||||
|
||||
/**
|
||||
* Main class to manage permissions.
|
||||
@@ -32,6 +37,9 @@ public class MVCommandManager extends PaperCommandManager {
|
||||
private final CommandQueueManager commandQueueManager;
|
||||
private final Provider<MVCommandContexts> commandContextsProvider;
|
||||
private final Provider<MVCommandCompletions> commandCompletionsProvider;
|
||||
private final MVCommandPermissions commandPermissions;
|
||||
private final CoreConfig config;
|
||||
private final PluginLocales pluginLocales;
|
||||
|
||||
@Inject
|
||||
MVCommandManager(
|
||||
@@ -41,22 +49,54 @@ public class MVCommandManager extends PaperCommandManager {
|
||||
@NotNull Provider<MVCommandContexts> commandContextsProvider,
|
||||
@NotNull Provider<MVCommandCompletions> commandCompletionsProvider,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull WorldNameChecker worldNameChecker) {
|
||||
@NotNull WorldNameChecker worldNameChecker,
|
||||
@NotNull MVCommandPermissions commandPermissions,
|
||||
@NotNull CoreConfig config
|
||||
) {
|
||||
super(plugin);
|
||||
this.flagsManager = flagsManager;
|
||||
this.commandQueueManager = commandQueueManager;
|
||||
this.commandContextsProvider = commandContextsProvider;
|
||||
this.commandCompletionsProvider = commandCompletionsProvider;
|
||||
this.commandPermissions = commandPermissions;
|
||||
this.config = config;
|
||||
this.pluginLocales = new PluginLocales(this);
|
||||
this.locales = this.pluginLocales;
|
||||
this.pluginLocales.loadLanguages();
|
||||
|
||||
MVCommandConditions.load(this, worldManager, worldNameChecker);
|
||||
this.enableUnstableAPI("help");
|
||||
this.setDefaultExceptionHandler(new MVDefaultExceptionHandler());
|
||||
}
|
||||
|
||||
void loadLanguages(PluginLocales locales) {
|
||||
if (this.locales == null) {
|
||||
this.locales = locales;
|
||||
this.locales.loadLanguages();
|
||||
/**
|
||||
* Registers a list of commands and handles {@link LegacyAliasCommand} based on config option.
|
||||
* @param commands The commands to register
|
||||
* @param <T> The type of the commands
|
||||
*/
|
||||
public <T extends BaseCommand> void registerAllCommands(List<T> commands) {
|
||||
List<T> noLegacy = commands.stream().filter(command -> !(command instanceof LegacyAliasCommand)).toList();
|
||||
if (!config.getShowLegacyAliases()) {
|
||||
noLegacy.forEach(this::registerCommand);
|
||||
return;
|
||||
}
|
||||
|
||||
List<T> legacy = commands.stream().filter(command -> command instanceof LegacyAliasCommand).toList();
|
||||
List<T> noLegacyInheritance = noLegacy.stream()
|
||||
.filter(command -> legacy.stream().noneMatch(
|
||||
legacyAliasCommand -> command.getClass().isAssignableFrom(legacyAliasCommand.getClass())))
|
||||
.toList();
|
||||
|
||||
legacy.forEach(this::registerCommand);
|
||||
noLegacyInheritance.forEach(this::registerCommand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommand(BaseCommand command, boolean force) {
|
||||
if (command instanceof LegacyAliasCommand && !config.getShowLegacyAliases()) {
|
||||
return;
|
||||
}
|
||||
super.registerCommand(command, force);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +104,7 @@ public class MVCommandManager extends PaperCommandManager {
|
||||
*/
|
||||
@Override
|
||||
public PluginLocales getLocales() {
|
||||
return (PluginLocales) this.locales;
|
||||
return this.pluginLocales;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,17 +125,21 @@ public class MVCommandManager extends PaperCommandManager {
|
||||
return commandQueueManager;
|
||||
}
|
||||
|
||||
public synchronized @NotNull MVCommandPermissions getCommandPermissions() {
|
||||
return commandPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets class responsible for parsing string args into objects.
|
||||
*
|
||||
* @return A not-null {@link CommandContexts}.
|
||||
*/
|
||||
@Override
|
||||
public synchronized @NotNull CommandContexts<BukkitCommandExecutionContext> getCommandContexts() {
|
||||
public synchronized @NotNull MVCommandContexts getCommandContexts() {
|
||||
if (this.contexts == null) {
|
||||
this.contexts = commandContextsProvider.get();
|
||||
}
|
||||
return this.contexts;
|
||||
return (MVCommandContexts) this.contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,11 +148,16 @@ public class MVCommandManager extends PaperCommandManager {
|
||||
* @return A not-null {@link CommandCompletions}.
|
||||
*/
|
||||
@Override
|
||||
public synchronized @NotNull CommandCompletions<BukkitCommandCompletionContext> getCommandCompletions() {
|
||||
public synchronized @NotNull MVCommandCompletions getCommandCompletions() {
|
||||
if (this.completions == null) {
|
||||
this.completions = commandCompletionsProvider.get();
|
||||
}
|
||||
return this.completions;
|
||||
return (MVCommandCompletions) this.completions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandIssuer issuer, String permission) {
|
||||
return commandPermissions.hasPermission(issuer, permission);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,4 +186,17 @@ public class MVCommandManager extends PaperCommandManager {
|
||||
return new MVCommandIssuer(this, (CommandSender)issuer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RootCommand createRootCommand(String cmd) {
|
||||
return new MVRootCommand(this, cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(LogLevel level, String message, Throwable throwable) {
|
||||
Logging.finer("[%s] %s", level, message);
|
||||
if (throwable != null) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import co.aikar.commands.CommandIssuer;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import io.vavr.control.Option;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.permissions.CorePermissionsChecker;
|
||||
import org.mvplugins.multiverse.core.permissions.PermissionUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static org.mvplugins.multiverse.core.permissions.CorePermissionsChecker.*;
|
||||
|
||||
/**
|
||||
* Maps permission checking to custom logic for commands, to allow more complex permission checking.
|
||||
*/
|
||||
@Service
|
||||
public class MVCommandPermissions {
|
||||
private final Map<String, Predicate<CommandIssuer>> permissionsCheckMap;
|
||||
|
||||
@Inject
|
||||
MVCommandPermissions(@NotNull CorePermissionsChecker permissionsChecker) {
|
||||
this.permissionsCheckMap = new HashMap<>();
|
||||
|
||||
registerPermissionChecker("mvteleport", issuer -> permissionsChecker.hasAnyTeleportPermission(issuer.getIssuer()));
|
||||
registerPermissionChecker("mvteleportother", issuer -> permissionsChecker.hasAnyTeleportPermission(issuer.getIssuer(), Scope.OTHER));
|
||||
registerPermissionChecker("mvspawn", issuer -> permissionsChecker.hasAnySpawnPermission(issuer.getIssuer()));
|
||||
registerPermissionChecker("mvspawnother", issuer -> permissionsChecker.hasAnySpawnPermission(issuer.getIssuer(), Scope.OTHER));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a custom permission checker callback. Use `@id-name` in {@link CommandPermission} decorator to use
|
||||
* the callback instead of the default permission string checking.
|
||||
*
|
||||
* @param id The permission id
|
||||
* @param checker The permission checker callback
|
||||
*/
|
||||
public void registerPermissionChecker(String id, Predicate<CommandIssuer> checker) {
|
||||
permissionsCheckMap.put(prepareId(id), checker);
|
||||
}
|
||||
|
||||
private static @NotNull String prepareId(String id) {
|
||||
return (id.startsWith("@") ? "" : "@") + id.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the issuer has the given permission.
|
||||
* @param issuer The issuer
|
||||
* @param permission The permission to check
|
||||
* @return True if the issuer has the permission
|
||||
*/
|
||||
boolean hasPermission(CommandIssuer issuer, String permission) {
|
||||
return Option.of(permissionsCheckMap.get(permission))
|
||||
.map(checker -> checker.test(issuer))
|
||||
.getOrElse(() -> PermissionUtils.hasPermission(issuer.getIssuer(), permission));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.CommandIssuer;
|
||||
import co.aikar.commands.ExceptionHandler;
|
||||
import co.aikar.commands.RegisteredCommand;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Default handler that will print the stack trace when the command throws an exception.
|
||||
*/
|
||||
public class MVDefaultExceptionHandler implements ExceptionHandler {
|
||||
@Override
|
||||
public boolean execute(BaseCommand command, RegisteredCommand registeredCommand, CommandIssuer sender, List<String> args, Throwable t) {
|
||||
Logging.severe("Failed to execute command /%s %s %s",
|
||||
registeredCommand.getCommand(), registeredCommand.getPrefSubCommand(), String.join(" ", args));
|
||||
t.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.BukkitCommandManager;
|
||||
import co.aikar.commands.BukkitRootCommand;
|
||||
import co.aikar.commands.CommandIssuer;
|
||||
import org.mvplugins.multiverse.core.utils.StringFormatter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MVRootCommand extends BukkitRootCommand {
|
||||
protected MVRootCommand(BukkitCommandManager manager, String name) {
|
||||
super(manager, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseCommand execute(CommandIssuer sender, String commandLabel, String[] args) {
|
||||
String[] quoteFormatedArgs = StringFormatter.parseQuotesInArgs(args).toArray(String[]::new);
|
||||
return super.execute(sender, commandLabel, quoteFormatedArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getTabCompletions(CommandIssuer sender, String alias, String[] args, boolean commandsOnly, boolean isAsync) {
|
||||
String[] quoteFormatedArgs = StringFormatter.parseQuotesInArgs(args).toArray(String[]::new);
|
||||
return super.getTabCompletions(sender, alias, quoteFormatedArgs, commandsOnly, isAsync);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Contract;
|
||||
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagGroup;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
|
||||
/**
|
||||
* Base class for all Multiverse commands.
|
||||
*/
|
||||
@Contract
|
||||
public abstract class MultiverseCommand extends BaseCommand {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.mvplugins.multiverse.core.command.context;
|
||||
|
||||
/**
|
||||
* Simple wrapper for game rule value, as they may be different types.
|
||||
*/
|
||||
public record GameRuleValue(Object value) {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.mvplugins.multiverse.core.command.context;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Wrapper for context that get location from player if executed by player,
|
||||
* else requires user input of location coordinates.
|
||||
*
|
||||
* @param value The location
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public record PlayerLocation(Location value) {
|
||||
}
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
package org.mvplugins.multiverse.core.command.context.issueraware;
|
||||
|
||||
import co.aikar.commands.BukkitCommandExecutionContext;
|
||||
import co.aikar.commands.BukkitCommandIssuer;
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import co.aikar.commands.contexts.IssuerAwareContextResolver;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Reusable logic of issuer only and issuer aware context resolvers
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public final class IssuerAwareContextBuilder<T> {
|
||||
|
||||
private BiFunction<BukkitCommandExecutionContext, Player, T> fromPlayer;
|
||||
private BiFunction<BukkitCommandExecutionContext, String, T> fromInput;
|
||||
private Function<BukkitCommandExecutionContext, Message> issuerOnlyFailMessage = context -> Message.of("This command can only be used by a player.");
|
||||
private BiFunction<BukkitCommandExecutionContext, Player, Message> issuerAwarePlayerFailMessage = (context, player) -> Message.of("Unable to resolve context for player '" + player.getName() + "'.");
|
||||
private BiFunction<BukkitCommandExecutionContext, String, Message> issuerAwareInputFailMessage = (context, input) -> Message.of("Unable to resolve context for input '" + input + "'.");
|
||||
private BiFunction<BukkitCommandExecutionContext, String, Message> inputOnlyFailMessage = (context, input) -> Message.of("Unable to resolve context for input '" + input + "'.");
|
||||
|
||||
public IssuerAwareContextBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse value from player itself.
|
||||
*
|
||||
* @param fromInput the parsing function
|
||||
* @return The same builder for chaining
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextBuilder<T> fromPlayer(BiFunction<BukkitCommandExecutionContext, Player, T> fromInput) {
|
||||
this.fromPlayer = fromInput;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse value from command input string.
|
||||
*
|
||||
* @param fromInput the parsing function
|
||||
* @return The same builder for chaining
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextBuilder<T> fromInput(BiFunction<BukkitCommandExecutionContext, String, T> fromInput) {
|
||||
this.fromInput = fromInput;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When getting value fails as issuer is not a player.
|
||||
*
|
||||
* @param issuerOnlyFailMessage The message
|
||||
* @return The same builder for chaining
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextBuilder<T> issuerOnlyFailMessage(Function<BukkitCommandExecutionContext, Message> issuerOnlyFailMessage) {
|
||||
this.issuerOnlyFailMessage = issuerOnlyFailMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When getting value fails as player cannot parse the value.
|
||||
*
|
||||
* @param issuerAwarePlayerFailMessage The message
|
||||
* @return The same builder for chaining
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextBuilder<T> issuerAwarePlayerFailMessage(BiFunction<BukkitCommandExecutionContext, Player, Message> issuerAwarePlayerFailMessage) {
|
||||
this.issuerAwarePlayerFailMessage = issuerAwarePlayerFailMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When getting value fails as input cannot parse the value.
|
||||
*
|
||||
* @param issuerAwareInputFailMessage The message
|
||||
* @return The same builder for chaining
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextBuilder<T> issuerAwareInputFailMessage(BiFunction<BukkitCommandExecutionContext, String, Message> issuerAwareInputFailMessage) {
|
||||
this.issuerAwareInputFailMessage = issuerAwareInputFailMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When getting value fails as input cannot parse the value.
|
||||
*
|
||||
* @param inputOnlyFailMessage The message
|
||||
* @return The same builder for chaining
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextBuilder<T> inputOnlyFailMessage(BiFunction<BukkitCommandExecutionContext, String, Message> inputOnlyFailMessage) {
|
||||
this.inputOnlyFailMessage = inputOnlyFailMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the issuer aware context resolver logic.
|
||||
*
|
||||
* @return The generated context resolver
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextResolver<T, BukkitCommandExecutionContext> generateContext() {
|
||||
Objects.requireNonNull(fromPlayer);
|
||||
Objects.requireNonNull(fromInput);
|
||||
Objects.requireNonNull(issuerOnlyFailMessage);
|
||||
Objects.requireNonNull(issuerAwarePlayerFailMessage);
|
||||
Objects.requireNonNull(issuerAwareInputFailMessage);
|
||||
Objects.requireNonNull(inputOnlyFailMessage);
|
||||
|
||||
return context -> {
|
||||
BukkitCommandIssuer issuer = context.getIssuer();
|
||||
String resolve = context.getFlagValue("resolve", "");
|
||||
|
||||
if (resolve.equals("issuerOnly")) {
|
||||
if (issuer.isPlayer()) {
|
||||
T result = fromPlayer.apply(context, issuer.getPlayer());
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
throw new InvalidCommandArgument(issuerOnlyFailMessage.apply(context).formatted(issuer));
|
||||
}
|
||||
|
||||
String input = context.getFirstArg();
|
||||
T result = fromInput.apply(context, input);
|
||||
if (result != null) {
|
||||
context.popFirstArg();
|
||||
return result;
|
||||
}
|
||||
|
||||
if (resolve.equals("issuerAware")) {
|
||||
if (issuer.isPlayer()) {
|
||||
Player player = issuer.getPlayer();
|
||||
result = fromPlayer.apply(context, player);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
throw new InvalidCommandArgument(issuerAwarePlayerFailMessage.apply(context, player).formatted(issuer));
|
||||
}
|
||||
throw new InvalidCommandArgument(issuerAwareInputFailMessage.apply(context, input).formatted(issuer));
|
||||
}
|
||||
|
||||
throw new InvalidCommandArgument(inputOnlyFailMessage.apply(context, input).formatted(issuer));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the issuer aware context resolver logic, with marking of whether the value was resolved from player or input.
|
||||
*
|
||||
* @param createValue The function to create the {@link IssuerAwareValue} value
|
||||
* @param <I> The type of the value
|
||||
* @return The generated context resolver
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public <I extends IssuerAwareValue> IssuerAwareContextResolver<I, BukkitCommandExecutionContext> generateContext(BiFunction<Boolean, T, I> createValue) {
|
||||
// todo: This is a copy and paste from above
|
||||
|
||||
Objects.requireNonNull(fromPlayer);
|
||||
Objects.requireNonNull(fromInput);
|
||||
Objects.requireNonNull(issuerOnlyFailMessage);
|
||||
Objects.requireNonNull(issuerAwarePlayerFailMessage);
|
||||
Objects.requireNonNull(issuerAwareInputFailMessage);
|
||||
Objects.requireNonNull(inputOnlyFailMessage);
|
||||
|
||||
return context -> {
|
||||
BukkitCommandIssuer issuer = context.getIssuer();
|
||||
String resolve = context.getFlagValue("resolve", "");
|
||||
|
||||
if (resolve.equals("issuerOnly")) {
|
||||
if (issuer.isPlayer()) {
|
||||
T result = fromPlayer.apply(context, issuer.getPlayer());
|
||||
if (result != null) {
|
||||
return createValue.apply(true, result);
|
||||
}
|
||||
}
|
||||
throw new InvalidCommandArgument(issuerOnlyFailMessage.apply(context).formatted(issuer));
|
||||
}
|
||||
|
||||
String input = context.getFirstArg();
|
||||
T result = fromInput.apply(context, input);
|
||||
if (result != null) {
|
||||
context.popFirstArg();
|
||||
return createValue.apply(false, result);
|
||||
}
|
||||
|
||||
if (resolve.equals("issuerAware")) {
|
||||
if (issuer.isPlayer()) {
|
||||
Player player = issuer.getPlayer();
|
||||
result = fromPlayer.apply(context, player);
|
||||
if (result != null) {
|
||||
return createValue.apply(true, result);
|
||||
}
|
||||
throw new InvalidCommandArgument(issuerAwarePlayerFailMessage.apply(context, player).formatted(issuer));
|
||||
}
|
||||
throw new InvalidCommandArgument(issuerAwareInputFailMessage.apply(context, input).formatted(issuer));
|
||||
}
|
||||
|
||||
throw new InvalidCommandArgument(inputOnlyFailMessage.apply(context, input).formatted(issuer));
|
||||
};
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package org.mvplugins.multiverse.core.command.context.issueraware;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Base class for issuer aware values
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public abstract class IssuerAwareValue {
|
||||
protected final boolean byIssuer;
|
||||
|
||||
/**
|
||||
* Constructor to create an issuer aware value
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
protected IssuerAwareValue(boolean byIssuer) {
|
||||
this.byIssuer = byIssuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the value is by issuer or input
|
||||
*
|
||||
* @return true if by issuer, false if by input
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public boolean isByIssuer() {
|
||||
return byIssuer;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package org.mvplugins.multiverse.core.command.context.issueraware;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
|
||||
/**
|
||||
* Issuer aware value wrapper for {@link MultiverseWorld}
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public final class MultiverseWorldValue extends IssuerAwareValue {
|
||||
|
||||
private final MultiverseWorld world;
|
||||
|
||||
/**
|
||||
* Constructor for issuer aware value
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public MultiverseWorldValue(boolean byIssuer, MultiverseWorld world) {
|
||||
super(byIssuer);
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
/**
|
||||
* The containing world wrapped
|
||||
*
|
||||
* @return wrapped world
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public MultiverseWorld value() {
|
||||
return world;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package org.mvplugins.multiverse.core.command.context.issueraware;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Issuer aware value wrapper for {@link Player} array
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public final class PlayerArrayValue extends IssuerAwareValue {
|
||||
|
||||
private final Player[] players;
|
||||
|
||||
/**
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public PlayerArrayValue(boolean byIssuer, Player[] players) {
|
||||
super(byIssuer);
|
||||
this.players = players;
|
||||
}
|
||||
|
||||
/**
|
||||
* The containing player array wrapped
|
||||
*
|
||||
* @return wrapped player array
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public Player[] value() {
|
||||
return players;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package org.mvplugins.multiverse.core.command.context;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.mvplugins.multiverse.core.commandtools.flags;
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.mvplugins.multiverse.core.commandtools.flags;
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
+3
-1
@@ -1,4 +1,4 @@
|
||||
package org.mvplugins.multiverse.core.commandtools.flags;
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -7,6 +7,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
@@ -54,6 +55,7 @@ public class CommandFlagsManager {
|
||||
public @NotNull Collection<String> suggest(@Nullable String groupName, @NotNull String[] flags) {
|
||||
CommandFlagGroup flagGroup = this.getFlagGroup(groupName);
|
||||
if (flagGroup == null) {
|
||||
Logging.warning("Unknown flag group: " + groupName);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
+3
-5
@@ -1,4 +1,4 @@
|
||||
package org.mvplugins.multiverse.core.commandtools.flags;
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
|
||||
@@ -68,9 +68,7 @@ public class CommandFlagsParser {
|
||||
|
||||
this.currentFlag = potentialFlag;
|
||||
|
||||
if (this.currentFlag instanceof CommandValueFlag) {
|
||||
CommandValueFlag<?> valueFlag = (CommandValueFlag<?>) this.currentFlag;
|
||||
|
||||
if (this.currentFlag instanceof CommandValueFlag<?> valueFlag) {
|
||||
if (valueFlag.isOptional()) {
|
||||
parsedFlags.addFlagResult(valueFlag.getKey(), valueFlag.getDefaultValue());
|
||||
this.nextArgMayBeKey = true;
|
||||
@@ -98,7 +96,7 @@ public class CommandFlagsParser {
|
||||
*/
|
||||
private boolean parseValue(String flag) {
|
||||
if (this.currentFlag == null) {
|
||||
throw new InvalidCommandArgument("Some flag logic error occurred at " + flag + "");
|
||||
throw new InvalidCommandArgument("Some flag logic error occurred at '" + flag + "'!");
|
||||
}
|
||||
if (flagGroup.hasKey(flag)) {
|
||||
throw new InvalidCommandArgument(currentFlag.getKey() + " requires a value!");
|
||||
+4
-5
@@ -1,10 +1,9 @@
|
||||
package org.mvplugins.multiverse.core.commandtools.flags;
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -192,7 +191,7 @@ public class CommandValueFlag<T> extends CommandFlag {
|
||||
@Override
|
||||
public @NotNull CommandValueFlag<T> build() {
|
||||
if (context == null && !String.class.equals(type)) {
|
||||
throw new IllegalStateException("Context is required for none-string value flags");
|
||||
throw new IllegalStateException("Context is required for non-string value flags");
|
||||
}
|
||||
return new CommandValueFlag<>(key, aliases, type, optional, defaultValue, context, completion);
|
||||
}
|
||||
@@ -230,8 +229,8 @@ public class CommandValueFlag<T> extends CommandFlag {
|
||||
|
||||
private void setEnumCompletion() {
|
||||
List<String> types = Arrays.stream(type.getEnumConstants())
|
||||
.map(type -> type.name().toLowerCase())
|
||||
.collect(Collectors.toList());
|
||||
.map(typeClass -> typeClass.name().toLowerCase())
|
||||
.toList();
|
||||
|
||||
this.completion = (input) -> types;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Contract;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Builds and registers a flag group on initialization. Flags should be final fields that calls {@link #flag(CommandFlag)}.
|
||||
*/
|
||||
@Contract
|
||||
public abstract class FlagBuilder {
|
||||
|
||||
private final String name;
|
||||
private final CommandFlagsManager flagsManager;
|
||||
private final List<CommandFlag> flags;
|
||||
|
||||
protected FlagBuilder(@NotNull String name, @NotNull CommandFlagsManager flagsManager) {
|
||||
this.name = name;
|
||||
this.flagsManager = flagsManager;
|
||||
this.flags = new ArrayList<>();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
private void postConstruct() {
|
||||
CommandFlagGroup.Builder flagGroupBuilder = CommandFlagGroup.builder(name);
|
||||
flags.forEach(flagGroupBuilder::add);
|
||||
registerFlagGroup(flagGroupBuilder.build());
|
||||
}
|
||||
|
||||
private void registerFlagGroup(@NotNull CommandFlagGroup flagGroup) {
|
||||
flagsManager.registerFlagGroup(flagGroup);
|
||||
Logging.finer("Registered flag group: " + flagGroup.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new flag to the flag builder.
|
||||
*
|
||||
* @param flag The flag to add.
|
||||
* @param <T> The type of the flag.
|
||||
* @return The flag.
|
||||
*/
|
||||
protected <T extends CommandFlag> T flag(T flag) {
|
||||
flags.add(flag);
|
||||
Logging.finer("Added flag: " + flag);
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses flags.
|
||||
*
|
||||
* @param flags The raw string array to parse into flags.
|
||||
* @return The parsed flags.
|
||||
*/
|
||||
public @NotNull ParsedCommandFlags parse(@NotNull String[] flags) {
|
||||
return flagsManager.parse(name, flags);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.mvplugins.multiverse.core.commandtools.flags;
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* This package contains classes related to parsing command flags.
|
||||
*/
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.mvplugins.multiverse.core.command.flags;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.display.filters.ContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.RegexContentFilter;
|
||||
|
||||
/**
|
||||
* A command flag for regex filtering.
|
||||
* <br/>
|
||||
* Parses the value of the --filter (or -f) flag as a {@link ContentFilter}.
|
||||
*/
|
||||
public final class FilterCommandFlag extends CommandValueFlag<ContentFilter> {
|
||||
|
||||
private static final Function<String, ContentFilter> VALUE_PARSER = value -> {
|
||||
try {
|
||||
return RegexContentFilter.fromString(value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new InvalidCommandArgument("Invalid filter: " + value);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new instance of this flag.
|
||||
*
|
||||
* @return The new instance.
|
||||
*/
|
||||
@NotNull
|
||||
public static FilterCommandFlag create() {
|
||||
return new FilterCommandFlag();
|
||||
}
|
||||
|
||||
private FilterCommandFlag() {
|
||||
super("--filter", List.of("-f"), ContentFilter.class, false, null, VALUE_PARSER, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.mvplugins.multiverse.core.command.flags;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandValueFlag;
|
||||
|
||||
/**
|
||||
* A command flag for page number.
|
||||
* <br/>
|
||||
* Parses the value of the --page (or -p) flag as an integer.
|
||||
*/
|
||||
public final class PageCommandFlag extends CommandValueFlag<Integer> {
|
||||
|
||||
private static final Function<String, Integer> VALUE_PARSER = value -> {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("Invalid page number: " + value);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new instance of this flag.
|
||||
*
|
||||
* @return The new instance.
|
||||
*/
|
||||
@NotNull
|
||||
public static PageCommandFlag create() {
|
||||
return new PageCommandFlag();
|
||||
}
|
||||
|
||||
private PageCommandFlag() {
|
||||
super("--page", List.of("-p"), Integer.class, false, null, VALUE_PARSER, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.mvplugins.multiverse.core.command.flags;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
|
||||
import org.mvplugins.multiverse.core.display.filters.ContentFilter;
|
||||
|
||||
@Service
|
||||
public class PageFilterFlags extends FlagBuilder {
|
||||
|
||||
public static final String NAME = "pagefilter";
|
||||
|
||||
protected PageFilterFlags(@NotNull String name, @NotNull CommandFlagsManager flagsManager) {
|
||||
super(name, flagsManager);
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected PageFilterFlags(@NotNull CommandFlagsManager flagsManager) {
|
||||
super(NAME, flagsManager);
|
||||
}
|
||||
|
||||
public final CommandValueFlag<Integer> page = flag(PageCommandFlag.create());
|
||||
|
||||
public final CommandValueFlag<ContentFilter> filter = flag(FilterCommandFlag.create());
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.mvplugins.multiverse.core.command.flags;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
|
||||
|
||||
@Service
|
||||
public class RemovePlayerFlags extends FlagBuilder {
|
||||
|
||||
public static final String NAME = "removeplayer";
|
||||
|
||||
protected RemovePlayerFlags(@NotNull String name, @NotNull CommandFlagsManager flagsManager) {
|
||||
super(name, flagsManager);
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected RemovePlayerFlags(@NotNull CommandFlagsManager flagsManager) {
|
||||
super(NAME, flagsManager);
|
||||
}
|
||||
|
||||
public final CommandFlag removePlayers = flag(CommandFlag.builder("--remove-players")
|
||||
.addAlias("-r")
|
||||
.build());
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.mvplugins.multiverse.core.command.flags;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
|
||||
|
||||
@Service
|
||||
public class UnsafeFlags extends FlagBuilder {
|
||||
|
||||
public static final String NAME = "unsafe";
|
||||
|
||||
protected UnsafeFlags(@NotNull String name, @NotNull CommandFlagsManager flagsManager) {
|
||||
super(name, flagsManager);
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected UnsafeFlags(@NotNull CommandFlagsManager flagsManager) {
|
||||
super(NAME, flagsManager);
|
||||
}
|
||||
|
||||
public final CommandFlag unsafe = flag(CommandFlag.builder("--unsafe")
|
||||
.addAlias("-u")
|
||||
.build());
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* This package contains predefined flags for commands.
|
||||
*/
|
||||
package org.mvplugins.multiverse.core.command.flags;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* This package contains the classes that manages command handling.
|
||||
*/
|
||||
package org.mvplugins.multiverse.core.commandtools;
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
@@ -0,0 +1,192 @@
|
||||
/******************************************************************************
|
||||
* Multiverse 2 Copyright (c) the Multiverse Team 2020. *
|
||||
* Multiverse 2 is licensed under the BSD License. *
|
||||
* For more information please check the README.md file included *
|
||||
* with this project. *
|
||||
******************************************************************************/
|
||||
|
||||
package org.mvplugins.multiverse.core.command.queue;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import io.vavr.control.Option;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.block.data.type.CommandBlock;
|
||||
import org.bukkit.command.BlockCommandSender;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.MultiverseCore;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.utils.result.Attempt;
|
||||
|
||||
import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.*;
|
||||
|
||||
/**
|
||||
* <p>Manages the queuing of dangerous commands that require {@code /mv confirm} before executing.</p>
|
||||
*
|
||||
* <p>Each sender can only have one command in queue at any given time. When a queued command is added
|
||||
* for a sender that already has a command in queue, it will replace the old queued command.</p>
|
||||
*/
|
||||
@Service
|
||||
public class CommandQueueManager {
|
||||
|
||||
private static final String CONSOLE_NAME = "@console";
|
||||
private static final String COMMAND_BLOCK_NAME = "@commandblock";
|
||||
private static final long TICKS_PER_SECOND = 20;
|
||||
|
||||
private final Plugin plugin;
|
||||
private final CoreConfig config;
|
||||
private final Map<String, CommandQueuePayload> queuedCommandMap;
|
||||
|
||||
@Inject
|
||||
CommandQueueManager(@NotNull MultiverseCore plugin, @NotNull CoreConfig config) {
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.queuedCommandMap = new WeakHashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link CommandQueuePayload} into queue.
|
||||
*
|
||||
* @param payload The command queue payload to add.
|
||||
*/
|
||||
public void addToQueue(CommandQueuePayload payload) {
|
||||
String senderName = parseSenderName(payload.issuer());
|
||||
if (canRunImmediately(senderName)) {
|
||||
payload.action().run();
|
||||
return;
|
||||
}
|
||||
|
||||
this.removeFromQueue(senderName);
|
||||
|
||||
Logging.finer("Add new command to queue for sender %s.", senderName);
|
||||
this.queuedCommandMap.put(senderName, payload);
|
||||
payload.expireTask(runExpireLater(senderName, config.getConfirmTimeout()));
|
||||
|
||||
payload.issuer().sendInfo(payload.prompt());
|
||||
var confirmCommand = "/mv confirm";
|
||||
if (config.getUseConfirmOtp()) {
|
||||
confirmCommand += " " + payload.otp();
|
||||
}
|
||||
payload.issuer().sendMessage(String.format("Run %s%s %sto continue. This will expire in %s seconds.",
|
||||
ChatColor.GREEN, confirmCommand, ChatColor.WHITE, config.getConfirmTimeout()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if sender does not need to queue before running.
|
||||
*
|
||||
* @param senderName The name of sender.
|
||||
* @return True if sender does not need to queue before running.
|
||||
*/
|
||||
private boolean canRunImmediately(@NotNull String senderName) {
|
||||
return switch (config.getConfirmMode()) {
|
||||
case ENABLE -> false;
|
||||
case PLAYER_ONLY -> senderName.equals(CONSOLE_NAME) || senderName.equals(COMMAND_BLOCK_NAME);
|
||||
case DISABLE_COMMAND_BLOCKS -> senderName.equals(COMMAND_BLOCK_NAME);
|
||||
case DISABLE_CONSOLE -> senderName.equals(CONSOLE_NAME);
|
||||
case DISABLE -> true;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Expire task that removes a {@link CommandQueuePayload} from queue after valid duration defined.
|
||||
*
|
||||
* @param senderName The name of the sender.
|
||||
* @return The expire {@link BukkitTask}.
|
||||
*/
|
||||
@NotNull
|
||||
private BukkitTask runExpireLater(@NotNull String senderName, int validDuration) {
|
||||
return Bukkit.getScheduler().runTaskLater(
|
||||
this.plugin,
|
||||
expireRunnable(senderName),
|
||||
validDuration * TICKS_PER_SECOND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runnable responsible for expiring the queued command.
|
||||
*
|
||||
* @param senderName The name of the sender.
|
||||
* @return The expire runnable.
|
||||
*/
|
||||
@NotNull
|
||||
private Runnable expireRunnable(@NotNull String senderName) {
|
||||
return () -> {
|
||||
CommandQueuePayload payload = this.queuedCommandMap.remove(senderName);
|
||||
if (payload == null) {
|
||||
// Payload already removed
|
||||
return;
|
||||
}
|
||||
payload.issuer().sendMessage("Your queued command has expired.");
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the command in queue for the given sender, if any.
|
||||
*
|
||||
* @param issuer Sender that confirmed the command.
|
||||
* @return True if queued command ran successfully, else false.
|
||||
*/
|
||||
public Attempt<Void, RunQueuedFailedReason> runQueuedCommand(@NotNull MVCommandIssuer issuer, String otpInput) {
|
||||
String senderName = parseSenderName(issuer);
|
||||
return Option.of(this.queuedCommandMap.get(senderName)).fold(
|
||||
() -> Attempt.failure(RunQueuedFailedReason.NO_COMMAND_IN_QUEUE),
|
||||
payload -> runPayload(senderName, otpInput, payload));
|
||||
}
|
||||
|
||||
private Attempt<Void, RunQueuedFailedReason> runPayload(String senderName, String otpInput, CommandQueuePayload payload) {
|
||||
if (config.getUseConfirmOtp() && !Objects.equals(payload.otp(), otpInput)) {
|
||||
return Attempt.failure(RunQueuedFailedReason.INVALID_OTP, replace("{otp}").with(otpInput));
|
||||
}
|
||||
this.removeFromQueue(senderName);
|
||||
Logging.finer("Running queued command...");
|
||||
payload.action().run();
|
||||
return Attempt.success(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Since only one command is stored in queue per sender, we remove the old one.
|
||||
*
|
||||
* @param senderName The sender that executed the command.
|
||||
*/
|
||||
public void removeFromQueue(@NotNull String senderName) {
|
||||
CommandQueuePayload payload = this.queuedCommandMap.remove(senderName);
|
||||
if (payload == null) {
|
||||
Logging.finer("No queue command to remove for sender %s.", senderName);
|
||||
return;
|
||||
}
|
||||
Option.of(payload.expireTask()).peek(BukkitTask::cancel);
|
||||
Logging.finer("Removed queue command for sender %s.", senderName);
|
||||
}
|
||||
|
||||
private String parseSenderName(MVCommandIssuer issuer) {
|
||||
CommandSender sender = issuer.getIssuer();
|
||||
if (isCommandBlock(sender)) {
|
||||
return COMMAND_BLOCK_NAME;
|
||||
} else if (sender instanceof ConsoleCommandSender) {
|
||||
return CONSOLE_NAME;
|
||||
}
|
||||
return sender.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the sender is a command block.
|
||||
*
|
||||
* @param sender The sender to check.
|
||||
* @return True if sender is a command block, else false.
|
||||
*/
|
||||
private boolean isCommandBlock(@NotNull CommandSender sender) {
|
||||
return sender instanceof BlockCommandSender
|
||||
&& ((BlockCommandSender) sender).getBlock().getBlockData() instanceof CommandBlock;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package org.mvplugins.multiverse.core.command.queue;
|
||||
|
||||
import co.aikar.commands.ACFUtil;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
|
||||
/**
|
||||
* Represents a single command used in {@link CommandQueueManager} for confirming before running potentially
|
||||
* dangerous action.
|
||||
*/
|
||||
public class CommandQueuePayload {
|
||||
|
||||
/**
|
||||
* Creates a new {@link CommandQueuePayload}
|
||||
*
|
||||
* @param issuer The issuer of the command
|
||||
* @return The new {@link CommandQueuePayload}
|
||||
*/
|
||||
public static CommandQueuePayload issuer(@NotNull MVCommandIssuer issuer) {
|
||||
return new CommandQueuePayload(issuer);
|
||||
}
|
||||
|
||||
private static final String DEFAULT_PROMPT_MESSAGE = "The command you are trying to run is deemed dangerous."; // todo: localize
|
||||
|
||||
private final MVCommandIssuer issuer;
|
||||
private String otp;
|
||||
private Runnable action = () -> {};
|
||||
private Message prompt = Message.of(DEFAULT_PROMPT_MESSAGE);
|
||||
private BukkitTask expireTask;
|
||||
|
||||
protected CommandQueuePayload(@NotNull MVCommandIssuer issuer) {
|
||||
this.otp = String.valueOf(ACFUtil.rand(100, 999));
|
||||
this.issuer = issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the issuer of the command.
|
||||
* @return The issuer
|
||||
*/
|
||||
@NotNull
|
||||
public MVCommandIssuer issuer() {
|
||||
return issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the logic to execute upon confirming.
|
||||
* @param action The logic to execute
|
||||
* @return The same {@link CommandQueuePayload} for method chaining
|
||||
*/
|
||||
public CommandQueuePayload action(@NotNull Runnable action) {
|
||||
this.action = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the logic to execute upon confirming.
|
||||
*
|
||||
* @return The logic to execute
|
||||
*/
|
||||
@NotNull
|
||||
public Runnable action() {
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OTP number for validation.
|
||||
*
|
||||
* @param otp The OTP number
|
||||
* @return The same {@link CommandQueuePayload} for method chaining
|
||||
*/
|
||||
public CommandQueuePayload otp(String otp) {
|
||||
this.otp = otp;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OTP number for validation.
|
||||
*
|
||||
* @return The OTP number
|
||||
*/
|
||||
public String otp() {
|
||||
return otp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the question to ask sender to confirm.
|
||||
*
|
||||
* @param prompt The prompt message.
|
||||
* @return The same {@link CommandQueuePayload} for method chaining.
|
||||
*/
|
||||
public CommandQueuePayload prompt(Message prompt) {
|
||||
this.prompt = prompt;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the question to ask sender to confirm.
|
||||
*
|
||||
* @return The prompt message.
|
||||
*/
|
||||
public Message prompt() {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
void expireTask(BukkitTask expireTask) {
|
||||
this.expireTask = expireTask;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
BukkitTask expireTask() {
|
||||
return expireTask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.mvplugins.multiverse.core.command.queue;
|
||||
|
||||
/**
|
||||
* Sets whether the command executor needs to confirm before executing a command.
|
||||
*/
|
||||
public enum ConfirmMode {
|
||||
/**
|
||||
* Every command executor needs to confirm before executing a command.
|
||||
*/
|
||||
ENABLE,
|
||||
|
||||
/**
|
||||
* Only players need to confirm before executing a command. Command blocks and console will not need to confirm.
|
||||
*/
|
||||
PLAYER_ONLY,
|
||||
|
||||
/**
|
||||
* Everyone except command blocks will not need to confirm before executing a command.
|
||||
*/
|
||||
DISABLE_COMMAND_BLOCKS,
|
||||
|
||||
/**
|
||||
* Everyone except console will not need to confirm before executing a command.
|
||||
*/
|
||||
DISABLE_CONSOLE,
|
||||
|
||||
/**
|
||||
* Everyone will not need to confirm before executing a command.
|
||||
*/
|
||||
DISABLE,
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.mvplugins.multiverse.core.command.queue;
|
||||
|
||||
import co.aikar.locales.MessageKey;
|
||||
import co.aikar.locales.MessageKeyProvider;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.utils.result.FailureReason;
|
||||
|
||||
public enum RunQueuedFailedReason implements FailureReason {
|
||||
NO_COMMAND_IN_QUEUE(MVCorei18n.QUEUECOMMAND_NOCOMMANDINQUEUE),
|
||||
INVALID_OTP(MVCorei18n.QUEUECOMMAND_INVALIDOTP),
|
||||
COMMAND_EXECUTION_ERROR(MVCorei18n.QUEUECOMMAND_COMMANDEXECUTIONERROR),
|
||||
;
|
||||
|
||||
private final MessageKeyProvider message;
|
||||
|
||||
RunQueuedFailedReason(MessageKeyProvider message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public MessageKey getMessageKey() {
|
||||
return message.getMessageKey();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* Manager queuing of dangerous commands in need of confirmation.
|
||||
*/
|
||||
package org.mvplugins.multiverse.core.commandtools.queue;
|
||||
package org.mvplugins.multiverse.core.command.queue;
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.anchor.MultiverseAnchor;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
|
||||
@Service
|
||||
final class AnchorDeleteCommand extends CoreCommand {
|
||||
|
||||
private final AnchorManager anchorManager;
|
||||
|
||||
@Inject
|
||||
AnchorDeleteCommand(@NotNull AnchorManager anchorManager) {
|
||||
this.anchorManager = anchorManager;
|
||||
}
|
||||
|
||||
@Subcommand("anchor delete")
|
||||
@CommandPermission("multiverse.core.anchor.delete")
|
||||
@CommandCompletion("@anchornames")
|
||||
@Syntax("<name>")
|
||||
@Description("")
|
||||
void onAnchorDeleteCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Syntax("<name>")
|
||||
@Description("")
|
||||
MultiverseAnchor anchor) {
|
||||
if (anchorManager.deleteAnchor(anchor).isSuccess()) {
|
||||
issuer.sendMessage("&aAnchor &f" + anchor.getName() + "&a deleted.");
|
||||
} else {
|
||||
issuer.sendMessage("&cFailed to delete anchor.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.flags.PageFilterFlags;
|
||||
import org.mvplugins.multiverse.core.display.ContentDisplay;
|
||||
import org.mvplugins.multiverse.core.display.filters.DefaultContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.handlers.PagedSendHandler;
|
||||
import org.mvplugins.multiverse.core.display.parsers.ListContentProvider;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
|
||||
@Service
|
||||
final class AnchorListCommand extends CoreCommand {
|
||||
|
||||
private final AnchorManager anchorManager;
|
||||
private final LocationManipulation locationManipulation;
|
||||
private final PageFilterFlags flags;
|
||||
|
||||
@Inject
|
||||
AnchorListCommand(
|
||||
@NotNull AnchorManager anchorManager,
|
||||
@NotNull LocationManipulation locationManipulation,
|
||||
@NotNull PageFilterFlags flags
|
||||
) {
|
||||
this.anchorManager = anchorManager;
|
||||
this.locationManipulation = locationManipulation;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("anchor list")
|
||||
@CommandPermission("multiverse.core.anchor.list")
|
||||
@CommandCompletion("@flags:groupName=" + PageFilterFlags.NAME)
|
||||
@Syntax("[--page <page>] [--filter <filter>]")
|
||||
@Description("")
|
||||
void onAnchorListCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Optional
|
||||
@Syntax("[--page <page>] [--filter <filter>]")
|
||||
@Description("")
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
ContentDisplay.create()
|
||||
.addContent(ListContentProvider.forContent(getAnchors(issuer.getPlayer())))
|
||||
.withSendHandler(PagedSendHandler.create()
|
||||
.withHeader("&3==== [ Multiverse Anchors ] ====")
|
||||
.doPagination(true)
|
||||
.withTargetPage(parsedFlags.flagValue(flags.page, 1))
|
||||
.withFilter(parsedFlags.flagValue(flags.filter, DefaultContentFilter.get())))
|
||||
.send(issuer);
|
||||
}
|
||||
|
||||
private List<String> getAnchors(Player player) {
|
||||
return anchorManager.getAnchors(player).stream()
|
||||
.map(anchor ->
|
||||
"&a%s&7 - &f%s".formatted(
|
||||
anchor.getName(), locationManipulation.locationToString(anchor.getLocation())))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Flags;
|
||||
import co.aikar.commands.annotation.Single;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
|
||||
@Service
|
||||
final class AnchorSetCommand extends CoreCommand {
|
||||
|
||||
private final AnchorManager anchorManager;
|
||||
private final LocationManipulation locationManipulation;
|
||||
|
||||
@Inject
|
||||
AnchorSetCommand(
|
||||
@NotNull AnchorManager anchorManager,
|
||||
@NotNull LocationManipulation locationManipulation
|
||||
) {
|
||||
this.anchorManager = anchorManager;
|
||||
this.locationManipulation = locationManipulation;
|
||||
}
|
||||
|
||||
@Subcommand("anchor set")
|
||||
@CommandPermission("multiverse.core.anchor.create")
|
||||
@CommandCompletion("@empty @locations")
|
||||
@Syntax("<name> [location]")
|
||||
@Description("")
|
||||
void onAnchorSetCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Flags("resolve=issuerOnly")
|
||||
Player player,
|
||||
|
||||
@Single
|
||||
@Syntax("<name>")
|
||||
@Description("")
|
||||
//TODO: Check if anchor name is valid or exists already.
|
||||
String anchorName) {
|
||||
Location anchorLocation = player.getLocation();
|
||||
if (anchorManager.setAnchor(anchorName, anchorLocation).isSuccess()) {
|
||||
sendAnchorSetSuccessMessage(issuer, anchorName, locationManipulation.locationToString(anchorLocation));
|
||||
} else {
|
||||
sendAnchorSetFailedMessage(issuer, anchorName);
|
||||
}
|
||||
}
|
||||
|
||||
@Subcommand("anchor set")
|
||||
@CommandPermission("multiverse.core.anchor.create")
|
||||
@CommandCompletion("@anchornames @locations")
|
||||
@Syntax("<name> [location]")
|
||||
@Description("")
|
||||
void onAnchorSetCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Syntax("<name>")
|
||||
@Description("")
|
||||
String anchorName,
|
||||
|
||||
@Single
|
||||
@Syntax("[location]")
|
||||
@Description("")
|
||||
String locationString) {
|
||||
if (anchorManager.setAnchor(anchorName, locationString).isSuccess()) {
|
||||
sendAnchorSetSuccessMessage(issuer, anchorName, locationString);
|
||||
} else {
|
||||
sendAnchorSetFailedMessage(issuer, anchorName);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendAnchorSetSuccessMessage(MVCommandIssuer issuer, String anchorName, String locationString) {
|
||||
issuer.sendMessage("&aAnchor &f" + anchorName + "&a set to &f" + locationString);
|
||||
}
|
||||
|
||||
private void sendAnchorSetFailedMessage(MVCommandIssuer issuer, String anchorName) {
|
||||
issuer.sendMessage("&cFailed to set anchor &f" + anchorName + ".");
|
||||
}
|
||||
}
|
||||
@@ -11,28 +11,35 @@ import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
|
||||
import org.mvplugins.multiverse.core.destination.ParsedDestination;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationInstance;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.permissions.CorePermissionsChecker;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
|
||||
import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class CheckCommand extends MultiverseCommand {
|
||||
class CheckCommand extends CoreCommand {
|
||||
|
||||
private final DestinationsProvider destinationsProvider;
|
||||
private final CorePermissionsChecker corePermissionsChecker;
|
||||
private final LocationManipulation locationManipulation;
|
||||
|
||||
@Inject
|
||||
CheckCommand(@NotNull MVCommandManager commandManager, @NotNull DestinationsProvider destinationsProvider) {
|
||||
super(commandManager);
|
||||
this.destinationsProvider = destinationsProvider;
|
||||
CheckCommand(
|
||||
@NotNull CorePermissionsChecker corePermissionsChecker,
|
||||
@NotNull LocationManipulation locationManipulation
|
||||
) {
|
||||
this.corePermissionsChecker = corePermissionsChecker;
|
||||
this.locationManipulation = locationManipulation;
|
||||
}
|
||||
|
||||
@Subcommand("check")
|
||||
@CommandPermission("multiverse.core.check")
|
||||
@CommandCompletion("@players @destinations|@mvworlds")
|
||||
@CommandCompletion("@players @destinations")
|
||||
@Syntax("<player> <destination>")
|
||||
@Description("{@@mv-core.check.description}")
|
||||
void onCheckCommand(
|
||||
@@ -44,11 +51,32 @@ class CheckCommand extends MultiverseCommand {
|
||||
|
||||
@Syntax("<destination>")
|
||||
@Description("{@@mv-core.check.destination.description}")
|
||||
ParsedDestination<?> destination) {
|
||||
issuer.sendInfo(MVCorei18n.CHECK_CHECKING,
|
||||
"{player}", player.getName(),
|
||||
"{destination}", destination.toString());
|
||||
// TODO: More detailed output on permissions required.
|
||||
// this.destinationsProvider.checkTeleportPermissions(issuer, player, destination);
|
||||
DestinationInstance<?, ?> destination) {
|
||||
issuer.sendInfo(this.corePermissionsChecker.checkTeleportPermission(player, player, destination)
|
||||
? MVCorei18n.CHECK_HASPERMISSION
|
||||
: MVCorei18n.CHECK_NOPERMISSION,
|
||||
Replace.PLAYER.with(player.getName()),
|
||||
Replace.DESTINATION.with(destination));
|
||||
issuer.sendInfo(MVCorei18n.CHECK_LOCATION,
|
||||
replace("{location}").with(destination.getLocation(player)
|
||||
.map(locationManipulation::locationToString)
|
||||
.map(Message::of)
|
||||
.getOrElse(() -> Message.of(MVCorei18n.GENERIC_NULL, "Null!"))));
|
||||
|
||||
// TODO: Show permission required for this particular destination
|
||||
}
|
||||
|
||||
@Service
|
||||
private final static class LegacyAlias extends CheckCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull CorePermissionsChecker corePermissionsChecker, @NotNull LocationManipulation locationManipulation) {
|
||||
super(corePermissionsChecker, locationManipulation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvcheck")
|
||||
void onCheckCommand(MVCommandIssuer issuer, Player player, DestinationInstance<?, ?> destination) {
|
||||
super.onCheckCommand(issuer, player, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,44 +12,36 @@ import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.options.CloneWorldOptions;
|
||||
|
||||
import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class CloneCommand extends MultiverseCommand {
|
||||
class CloneCommand extends CoreCommand {
|
||||
|
||||
private final WorldManager worldManager;
|
||||
|
||||
private final CommandFlag RESET_WORLD_CONFIG_FLAG = flag(CommandFlag.builder("--reset-world-config")
|
||||
.addAlias("-wc")
|
||||
.build());
|
||||
|
||||
private final CommandFlag RESET_GAMERULES_FLAG = flag(CommandFlag.builder("--reset-gamerules")
|
||||
.addAlias("-gm")
|
||||
.build());
|
||||
|
||||
private final CommandFlag RESET_WORLD_BORDER_FLAG = flag(CommandFlag.builder("--reset-world-border")
|
||||
.addAlias("-wb")
|
||||
.build());
|
||||
private final CloneCommand.Flags flags;
|
||||
|
||||
@Inject
|
||||
CloneCommand(@NotNull MVCommandManager commandManager, @NotNull WorldManager worldManager) {
|
||||
super(commandManager);
|
||||
CloneCommand(@NotNull WorldManager worldManager, @NotNull Flags flags) {
|
||||
this.worldManager = worldManager;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("clone")
|
||||
@CommandPermission("multiverse.core.clone")
|
||||
@CommandCompletion("@mvworlds:scope=loaded @empty @flags:groupName=mvclonecommand")
|
||||
@Syntax("<world> <new world name>")
|
||||
@CommandCompletion("@mvworlds:scope=loaded @empty @flags:groupName=" + Flags.NAME)
|
||||
@Syntax("<world> <new-world-name> [--reset-world-config --reset-gamerules --reset-world-border]")
|
||||
@Description("{@@mv-core.clone.description}")
|
||||
void onCloneCommand(
|
||||
MVCommandIssuer issuer,
|
||||
@@ -58,28 +50,72 @@ class CloneCommand extends MultiverseCommand {
|
||||
@Description("{@@mv-core.clone.world.description}")
|
||||
LoadedMultiverseWorld world,
|
||||
|
||||
@Syntax("<new world name>")
|
||||
@Syntax("<new-world-name>")
|
||||
@Description("{@@mv-core.clone.newWorld.description}")
|
||||
String newWorldName,
|
||||
|
||||
@Optional
|
||||
@Syntax(/* TODO */ "")
|
||||
@Syntax("[--reset-world-config --reset-gamerules --reset-world-border]")
|
||||
@Description("{@@mv-core.regen.other.description}")
|
||||
String[] flags) {
|
||||
ParsedCommandFlags parsedFlags = parseFlags(flags);
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
|
||||
issuer.sendInfo(MVCorei18n.CLONE_CLONING, "{world}", world.getName(), "{newworld}", newWorldName);
|
||||
issuer.sendInfo(MVCorei18n.CLONE_CLONING,
|
||||
Replace.WORLD.with(world.getName()),
|
||||
replace("{newworld}").with(newWorldName));
|
||||
CloneWorldOptions cloneWorldOptions = CloneWorldOptions.fromTo(world, newWorldName)
|
||||
.keepWorldConfig(!parsedFlags.hasFlag(RESET_WORLD_CONFIG_FLAG))
|
||||
.keepGameRule(!parsedFlags.hasFlag(RESET_GAMERULES_FLAG))
|
||||
.keepWorldBorder(!parsedFlags.hasFlag(RESET_WORLD_BORDER_FLAG));
|
||||
.keepWorldConfig(!parsedFlags.hasFlag(flags.resetWorldConfig))
|
||||
.keepGameRule(!parsedFlags.hasFlag(flags.resetGamerules))
|
||||
.keepWorldBorder(!parsedFlags.hasFlag(flags.resetWorldBorder))
|
||||
.saveBukkitWorld(!parsedFlags.hasFlag(flags.noSave));
|
||||
worldManager.cloneWorld(cloneWorldOptions)
|
||||
.onSuccess(newWorld -> {
|
||||
Logging.fine("World clone success: " + newWorld);
|
||||
issuer.sendInfo(MVCorei18n.CLONE_SUCCESS, "{world}", newWorld.getName());
|
||||
issuer.sendInfo(MVCorei18n.CLONE_SUCCESS, Replace.WORLD.with(newWorld.getName()));
|
||||
}).onFailure(failure -> {
|
||||
Logging.fine("World clone failure: " + failure);
|
||||
issuer.sendError(failure.getFailureMessage());
|
||||
});
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class Flags extends FlagBuilder {
|
||||
|
||||
private static final String NAME = "mvclone";
|
||||
|
||||
@Inject
|
||||
private Flags(@NotNull CommandFlagsManager flagsManager) {
|
||||
super(NAME, flagsManager);
|
||||
}
|
||||
|
||||
private final CommandFlag resetWorldConfig = flag(CommandFlag.builder("--reset-world-config")
|
||||
.addAlias("-wc")
|
||||
.build());
|
||||
|
||||
private final CommandFlag resetGamerules = flag(CommandFlag.builder("--reset-gamerules")
|
||||
.addAlias("-gm")
|
||||
.build());
|
||||
|
||||
private final CommandFlag resetWorldBorder = flag(CommandFlag.builder("--reset-world-border")
|
||||
.addAlias("-wb")
|
||||
.build());
|
||||
|
||||
private final CommandFlag noSave = flag(CommandFlag.builder("--no-save")
|
||||
.addAlias("-s")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Service
|
||||
private final static class LegacyAlias extends CloneCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull WorldManager worldManager, @NotNull Flags flags) {
|
||||
super(worldManager, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvcl|mvclone")
|
||||
void onCloneCommand(MVCommandIssuer issuer, LoadedMultiverseWorld world, String newWorldName, String[] flags) {
|
||||
super.onCloneCommand(issuer, world, newWorldName, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,21 +12,22 @@ import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.config.MVCoreConfig;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.exceptions.MultiverseException;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class ConfigCommand extends MultiverseCommand {
|
||||
class ConfigCommand extends CoreCommand {
|
||||
|
||||
private final MVCoreConfig config;
|
||||
private final CoreConfig config;
|
||||
|
||||
@Inject
|
||||
ConfigCommand(@NotNull MVCommandManager commandManager, @NotNull MVCoreConfig config) {
|
||||
super(commandManager);
|
||||
ConfigCommand(@NotNull CoreConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@@ -34,17 +35,17 @@ class ConfigCommand extends MultiverseCommand {
|
||||
@CommandPermission("multiverse.core.config")
|
||||
@CommandCompletion("@mvconfigs @mvconfigvalues")
|
||||
@Syntax("<name> [value]")
|
||||
@Description("Show or set a config value.")
|
||||
@Description("{@@mv-core.config.description}")
|
||||
void onConfigCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Syntax("<name>")
|
||||
@Description("The name of the config to set or show.")
|
||||
@Description("{@@mv-core.config.name.description}")
|
||||
String name,
|
||||
|
||||
@Optional
|
||||
@Syntax("[value]")
|
||||
@Description("The value to set the config to. If not specified, the current value will be shown.")
|
||||
@Description("{@@mv-core.config.value.description}")
|
||||
String value) {
|
||||
if (value == null) {
|
||||
showConfigValue(issuer, name);
|
||||
@@ -55,17 +56,40 @@ class ConfigCommand extends MultiverseCommand {
|
||||
|
||||
private void showConfigValue(MVCommandIssuer issuer, String name) {
|
||||
config.getStringPropertyHandle().getProperty(name)
|
||||
.onSuccess(value -> issuer.sendMessage(name + "is currently set to " + value))
|
||||
.onFailure(e -> issuer.sendMessage(e.getMessage()));
|
||||
.onSuccess(value -> issuer.sendMessage(MVCorei18n.CONFIG_SHOW_SUCCESS,
|
||||
Replace.NAME.with(name),
|
||||
Replace.VALUE.with(value)))
|
||||
.onFailure(e -> issuer.sendMessage(MVCorei18n.CONFIG_SHOW_ERROR,
|
||||
Replace.NAME.with(name),
|
||||
Replace.ERROR.with(e)));
|
||||
}
|
||||
|
||||
private void updateConfigValue(MVCommandIssuer issuer, String name, String value) {
|
||||
config.getStringPropertyHandle().setPropertyString(name, value)
|
||||
var stringPropertyHandle = config.getStringPropertyHandle();
|
||||
stringPropertyHandle.setPropertyString(issuer.getIssuer(), name, value)
|
||||
.onSuccess(ignore -> {
|
||||
config.save();
|
||||
issuer.sendMessage("Successfully set " + name + " to " + value);
|
||||
issuer.sendMessage(MVCorei18n.CONFIG_SET_SUCCESS,
|
||||
Replace.NAME.with(name),
|
||||
Replace.VALUE.with(stringPropertyHandle.getProperty(name).getOrNull()));
|
||||
})
|
||||
.onFailure(ignore -> issuer.sendMessage("Unable to set " + name + " to " + value + "."))
|
||||
.onFailure(MultiverseException.class, e -> Option.of(e.getMVMessage()).peek(issuer::sendError));
|
||||
.onFailure(e -> issuer.sendMessage(MVCorei18n.CONFIG_SET_ERROR,
|
||||
Replace.NAME.with(name),
|
||||
Replace.VALUE.with(value),
|
||||
Replace.ERROR.with(e)));
|
||||
}
|
||||
|
||||
@Service
|
||||
private final static class LegacyAlias extends ConfigCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull CoreConfig config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvconfig|mvconf")
|
||||
void onConfigCommand(MVCommandIssuer issuer, String name, String value) {
|
||||
super.onConfigCommand(issuer, name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,54 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import co.aikar.commands.BukkitCommandIssuer;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Default;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.queue.CommandQueueManager;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class ConfirmCommand extends MultiverseCommand {
|
||||
class ConfirmCommand extends CoreCommand {
|
||||
|
||||
@NotNull
|
||||
private final CommandQueueManager commandQueueManager;
|
||||
|
||||
@Inject
|
||||
ConfirmCommand(@NotNull MVCommandManager commandManager) {
|
||||
super(commandManager);
|
||||
ConfirmCommand(@NotNull CommandQueueManager commandQueueManager) {
|
||||
this.commandQueueManager = commandQueueManager;
|
||||
}
|
||||
|
||||
@Subcommand("confirm")
|
||||
@CommandPermission("multiverse.core.confirm")
|
||||
@Syntax("[otp]")
|
||||
@Description("{@@mv-core.confirm.description}")
|
||||
void onConfirmCommand(@NotNull BukkitCommandIssuer issuer) {
|
||||
this.commandManager.getCommandQueueManager().runQueuedCommand(issuer.getIssuer());
|
||||
void onConfirmCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Default("0")
|
||||
String otp) {
|
||||
this.commandQueueManager.runQueuedCommand(issuer, otp)
|
||||
.onFailure(failure -> issuer.sendError(failure.getFailureMessage()));
|
||||
}
|
||||
|
||||
@Service
|
||||
private final static class LegacyAlias extends ConfirmCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull CommandQueueManager commandQueueCommand) {
|
||||
super(commandQueueCommand);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvconfirm")
|
||||
void onConfirmCommand(MVCommandIssuer issuer, String otp) {
|
||||
super.onConfirmCommand(issuer, otp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import co.aikar.commands.BukkitCommandIssuer;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
@@ -11,42 +10,60 @@ import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.api.LocationManipulation;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
|
||||
import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class CoordinatesCommand extends MultiverseCommand {
|
||||
class CoordinatesCommand extends CoreCommand {
|
||||
|
||||
private final LocationManipulation locationManipulation;
|
||||
|
||||
@Inject
|
||||
CoordinatesCommand(
|
||||
@NotNull MVCommandManager commandManager,
|
||||
@NotNull LocationManipulation locationManipulation) {
|
||||
super(commandManager);
|
||||
CoordinatesCommand(@NotNull LocationManipulation locationManipulation) {
|
||||
this.locationManipulation = locationManipulation;
|
||||
}
|
||||
|
||||
@Subcommand("coordinates|coords|coord|co")
|
||||
@Subcommand("coordinates")
|
||||
@CommandPermission("multiverse.core.coord")
|
||||
@Description("{@@mv-core.coordinates.description}")
|
||||
void onCoordinatesCommand(
|
||||
BukkitCommandIssuer issuer,
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Flags("resolve=issuerOnly")
|
||||
Player player,
|
||||
|
||||
@Flags("resolve=issuerOnly")
|
||||
LoadedMultiverseWorld world) {
|
||||
MultiverseWorld world) {
|
||||
issuer.sendInfo(MVCorei18n.COORDINATES_INFO_TITLE);
|
||||
issuer.sendInfo(MVCorei18n.COORDINATES_INFO_WORLD, "{world}", world.getName());
|
||||
issuer.sendInfo(MVCorei18n.COORDINATES_INFO_ALIAS, "{alias}", world.getAlias());
|
||||
issuer.sendInfo(MVCorei18n.COORDINATES_INFO_WORLDSCALE, "{scale}", String.valueOf(world.getScale()));
|
||||
issuer.sendInfo(MVCorei18n.COORDINATES_INFO_COORDINATES, "{coordinates}", locationManipulation.strCoords(player.getLocation()));
|
||||
issuer.sendInfo(MVCorei18n.COORDINATES_INFO_DIRECTION, "{direction}", locationManipulation.getDirection(player.getLocation()));
|
||||
issuer.sendInfo(MVCorei18n.COORDINATES_INFO_WORLD, Replace.WORLD.with(world.getName()));
|
||||
issuer.sendInfo(MVCorei18n.COORDINATES_INFO_ALIAS, replace("{alias}").with(world.getAliasOrName()));
|
||||
issuer.sendInfo(MVCorei18n.COORDINATES_INFO_WORLDSCALE,
|
||||
replace("{scale}").with(String.valueOf(world.getScale())));
|
||||
issuer.sendInfo(MVCorei18n.COORDINATES_INFO_COORDINATES,
|
||||
replace("{coordinates}").with(locationManipulation.strCoords(player.getLocation())));
|
||||
issuer.sendInfo(MVCorei18n.COORDINATES_INFO_DIRECTION,
|
||||
replace("{direction}").with(locationManipulation.getDirection(player.getLocation())));
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends CoordinatesCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull LocationManipulation locationManipulation) {
|
||||
super(locationManipulation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvcoord|mvco")
|
||||
@Subcommand("coords|coord|co")
|
||||
void onCoordinatesCommand(MVCommandIssuer issuer, Player player, MultiverseWorld world) {
|
||||
super.onCoordinatesCommand(issuer, player, world);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Contract;
|
||||
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.command.MultiverseCommand;
|
||||
|
||||
/**
|
||||
* Represents a command that is part of the Multiverse-Core plugin.
|
||||
*/
|
||||
@Contract
|
||||
@CommandAlias("mv")
|
||||
public abstract class CoreCommand extends MultiverseCommand {
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Random;
|
||||
|
||||
import co.aikar.commands.ACFUtil;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
@@ -17,62 +17,43 @@ import org.bukkit.WorldType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.utils.result.Attempt.Failure;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.biomeprovider.BiomeProviderFactory;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
|
||||
import org.mvplugins.multiverse.core.world.options.CreateWorldOptions;
|
||||
import org.mvplugins.multiverse.core.world.reasons.CreateFailureReason;
|
||||
|
||||
import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class CreateCommand extends MultiverseCommand {
|
||||
class CreateCommand extends CoreCommand {
|
||||
|
||||
private final WorldManager worldManager;
|
||||
private GeneratorProvider generatorProvider;
|
||||
|
||||
private final CommandValueFlag<String> SEED_FLAG = flag(CommandValueFlag.builder("--seed", String.class)
|
||||
.addAlias("-s")
|
||||
.completion(input -> Collections.singleton(String.valueOf(new Random().nextLong())))
|
||||
.build());
|
||||
|
||||
private final CommandValueFlag<String> GENERATOR_FLAG = flag(CommandValueFlag
|
||||
.builder("--generator", String.class)
|
||||
.addAlias("-g")
|
||||
.completion(input -> generatorProvider.suggestGeneratorString(input))
|
||||
.build());
|
||||
|
||||
private final CommandValueFlag<WorldType> WORLD_TYPE_FLAG = flag(CommandValueFlag
|
||||
.enumBuilder("--world-type", WorldType.class)
|
||||
.addAlias("-t")
|
||||
.build());
|
||||
|
||||
private final CommandFlag NO_ADJUST_SPAWN_FLAG = flag(CommandFlag.builder("--no-adjust-spawn")
|
||||
.addAlias("-n")
|
||||
.build());
|
||||
|
||||
private final CommandFlag NO_STRUCTURES_FLAG = flag(CommandFlag.builder("--no-structures")
|
||||
.addAlias("-a")
|
||||
.build());
|
||||
private final CreateCommand.Flags flags;
|
||||
|
||||
@Inject
|
||||
CreateCommand(
|
||||
@NotNull MVCommandManager commandManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull GeneratorProvider generatorProvider) {
|
||||
super(commandManager);
|
||||
CreateCommand(@NotNull WorldManager worldManager, @NotNull Flags flags) {
|
||||
this.worldManager = worldManager;
|
||||
this.generatorProvider = generatorProvider;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("create")
|
||||
@CommandPermission("multiverse.core.create")
|
||||
@CommandCompletion("@empty @environments @flags:groupName=mvcreatecommand")
|
||||
@Syntax("<name> <environment> --seed [seed] --generator [generator[:id]] --world-type [worldtype] --adjust-spawn --no-structures")
|
||||
@CommandCompletion("@empty @environments @flags:groupName=" + Flags.NAME)
|
||||
@Syntax("<name> <environment> [--seed <seed> --generator <generator[:id]> --world-type <worldtype> --adjust-spawn "
|
||||
+ "--no-structures --biome <biome>]")
|
||||
@Description("{@@mv-core.create.description}")
|
||||
void onCreateCommand(
|
||||
MVCommandIssuer issuer,
|
||||
@@ -86,41 +67,132 @@ class CreateCommand extends MultiverseCommand {
|
||||
World.Environment environment,
|
||||
|
||||
@Optional
|
||||
@Syntax("--seed [seed] --generator [generator[:id]] --world-type [worldtype] --adjust-spawn --no-structures")
|
||||
@Syntax("[--seed <seed> --generator <generator[:id]> --world-type <worldtype> --adjust-spawn "
|
||||
+ "--no-structures --biome <biome>]")
|
||||
@Description("{@@mv-core.create.flags.description}")
|
||||
String[] flags) {
|
||||
ParsedCommandFlags parsedFlags = parseFlags(flags);
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES,
|
||||
"{worldName}", worldName);
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_ENVIRONMENT,
|
||||
"{environment}", environment.name());
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_SEED,
|
||||
"{seed}", parsedFlags.flagValue(SEED_FLAG, "RANDOM"));
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_WORLDTYPE,
|
||||
"{worldType}", parsedFlags.flagValue(WORLD_TYPE_FLAG, WorldType.NORMAL).name());
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_ADJUSTSPAWN,
|
||||
"{adjustSpawn}", String.valueOf(!parsedFlags.hasFlag(NO_ADJUST_SPAWN_FLAG)));
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_GENERATOR,
|
||||
"{generator}", parsedFlags.flagValue(GENERATOR_FLAG, ""));
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_STRUCTURES,
|
||||
"{structures}", String.valueOf(!parsedFlags.hasFlag(NO_STRUCTURES_FLAG)));
|
||||
messageWorldDetails(issuer, worldName, environment, parsedFlags);
|
||||
|
||||
issuer.sendInfo(MVCorei18n.CREATE_LOADING);
|
||||
|
||||
worldManager.createWorld(CreateWorldOptions.worldName(worldName)
|
||||
.biome(parsedFlags.flagValue(flags.biome, ""))
|
||||
.environment(environment)
|
||||
.seed(parsedFlags.flagValue(SEED_FLAG))
|
||||
.worldType(parsedFlags.flagValue(WORLD_TYPE_FLAG, WorldType.NORMAL))
|
||||
.useSpawnAdjust(!parsedFlags.hasFlag(NO_ADJUST_SPAWN_FLAG))
|
||||
.generator(parsedFlags.flagValue(GENERATOR_FLAG, ""))
|
||||
.generateStructures(!parsedFlags.hasFlag(NO_STRUCTURES_FLAG)))
|
||||
.onSuccess(newWorld -> {
|
||||
Logging.fine("World create success: " + newWorld);
|
||||
issuer.sendInfo(MVCorei18n.CREATE_SUCCESS, "{world}", newWorld.getName());
|
||||
}).onFailure(failure -> {
|
||||
Logging.fine("World create failure: " + failure);
|
||||
issuer.sendError(failure.getFailureMessage());
|
||||
});
|
||||
.seed(parsedFlags.flagValue(flags.seed))
|
||||
.worldType(parsedFlags.flagValue(flags.worldType, WorldType.NORMAL))
|
||||
.useSpawnAdjust(!parsedFlags.hasFlag(flags.noAdjustSpawn))
|
||||
.generator(parsedFlags.flagValue(flags.generator, ""))
|
||||
.generatorSettings(parsedFlags.flagValue(flags.generatorSettings, ""))
|
||||
.generateStructures(!parsedFlags.hasFlag(flags.noStructures)))
|
||||
.onSuccess(newWorld -> messageSuccess(issuer, newWorld))
|
||||
.onFailure(failure -> messageFailure(issuer, failure));
|
||||
}
|
||||
|
||||
private void messageWorldDetails(MVCommandIssuer issuer, String worldName,
|
||||
World.Environment environment, ParsedCommandFlags parsedFlags) {
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES,
|
||||
replace("{worldName}").with(worldName));
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_ENVIRONMENT,
|
||||
replace("{environment}").with(environment.name()));
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_SEED,
|
||||
replace("{seed}").with(parsedFlags.flagValue(flags.seed, "RANDOM")));
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_WORLDTYPE,
|
||||
replace("{worldType}").with(parsedFlags.flagValue(flags.worldType, WorldType.NORMAL).name()));
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_ADJUSTSPAWN,
|
||||
replace("{adjustSpawn}").with(String.valueOf(!parsedFlags.hasFlag(flags.noAdjustSpawn))));
|
||||
if (parsedFlags.hasFlag(flags.biome)) {
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_BIOME,
|
||||
replace("{biome}").with(parsedFlags.flagValue(flags.biome)));
|
||||
}
|
||||
if (parsedFlags.hasFlag(flags.generator)) {
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_GENERATOR,
|
||||
replace("{generator}").with(parsedFlags.flagValue(flags.generator)));
|
||||
}
|
||||
if (parsedFlags.hasFlag(flags.generatorSettings)) {
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_GENERATORSETTINGS,
|
||||
replace("{generatorSettings}").with(parsedFlags.flagValue(flags.generatorSettings)));
|
||||
}
|
||||
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_STRUCTURES,
|
||||
replace("{structures}").with(String.valueOf(!parsedFlags.hasFlag(flags.noStructures))));
|
||||
}
|
||||
|
||||
private void messageSuccess(MVCommandIssuer issuer, LoadedMultiverseWorld newWorld) {
|
||||
Logging.fine("World create success: " + newWorld);
|
||||
issuer.sendInfo(MVCorei18n.CREATE_SUCCESS, Replace.WORLD.with(newWorld.getName()));
|
||||
}
|
||||
|
||||
private void messageFailure(MVCommandIssuer issuer, Failure<LoadedMultiverseWorld, CreateFailureReason> failure) {
|
||||
Logging.fine("World create failure: " + failure);
|
||||
issuer.sendError(failure.getFailureMessage());
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class Flags extends FlagBuilder {
|
||||
|
||||
private static final String NAME = "mvcreate";
|
||||
|
||||
private GeneratorProvider generatorProvider;
|
||||
private BiomeProviderFactory biomeProviderFactory;
|
||||
|
||||
@Inject
|
||||
private Flags(
|
||||
@NotNull CommandFlagsManager flagsManager,
|
||||
@NotNull GeneratorProvider generatorProvider,
|
||||
@NotNull BiomeProviderFactory biomeProviderFactory
|
||||
) {
|
||||
super(NAME, flagsManager);
|
||||
this.generatorProvider = generatorProvider;
|
||||
this.biomeProviderFactory = biomeProviderFactory;
|
||||
}
|
||||
|
||||
private final CommandValueFlag<String> seed = flag(CommandValueFlag.builder("--seed", String.class)
|
||||
.addAlias("-s")
|
||||
.completion(input -> Collections.singleton(String.valueOf(ACFUtil.RANDOM.nextLong())))
|
||||
.build());
|
||||
|
||||
private final CommandValueFlag<String> generator = flag(CommandValueFlag
|
||||
.builder("--generator", String.class)
|
||||
.addAlias("-g")
|
||||
.completion(input -> generatorProvider.suggestGeneratorString(input))
|
||||
.build());
|
||||
|
||||
private final CommandValueFlag<String> generatorSettings = flag(CommandValueFlag
|
||||
.builder("--generator-settings", String.class)
|
||||
.addAlias("-gs")
|
||||
.build());
|
||||
|
||||
private final CommandValueFlag<WorldType> worldType = flag(CommandValueFlag
|
||||
.enumBuilder("--world-type", WorldType.class)
|
||||
.addAlias("-t")
|
||||
.build());
|
||||
|
||||
private final CommandFlag noAdjustSpawn = flag(CommandFlag.builder("--no-adjust-spawn")
|
||||
.addAlias("-n")
|
||||
.build());
|
||||
|
||||
private final CommandFlag noStructures = flag(CommandFlag.builder("--no-structures")
|
||||
.addAlias("-a")
|
||||
.build());
|
||||
|
||||
private final CommandValueFlag<String> biome = flag(CommandValueFlag.builder("--biome", String.class)
|
||||
.addAlias("-b")
|
||||
.completion(input -> biomeProviderFactory.suggestBiomeString(input))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends CreateCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull WorldManager worldManager, @NotNull Flags flags) {
|
||||
super(worldManager, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvcreate|mvc")
|
||||
void onCreateCommand(MVCommandIssuer issuer, String worldName, World.Environment environment, String[] flags) {
|
||||
super.onCreateCommand(issuer, worldName, environment, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,20 +12,18 @@ import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.config.MVCoreConfig;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class DebugCommand extends MultiverseCommand {
|
||||
class DebugCommand extends CoreCommand {
|
||||
|
||||
private final MVCoreConfig config;
|
||||
private final CoreConfig config;
|
||||
|
||||
@Inject
|
||||
DebugCommand(@NotNull MVCommandManager commandManager, @NotNull MVCoreConfig config) {
|
||||
super(commandManager);
|
||||
DebugCommand(@NotNull CoreConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@@ -62,4 +60,18 @@ class DebugCommand extends MultiverseCommand {
|
||||
issuer.sendInfo(MVCorei18n.DEBUG_INFO_ON, "{level}", String.valueOf(debugLevel));
|
||||
Logging.fine("Multiverse Debug ENABLED.");
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends DebugCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
public LegacyAlias(@NotNull CoreConfig config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvdebug")
|
||||
void onChangeDebugCommand(BukkitCommandIssuer issuer, int level) {
|
||||
super.onChangeDebugCommand(issuer, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,8 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import co.aikar.commands.MessageType;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Conditions;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Single;
|
||||
@@ -17,85 +13,114 @@ import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.commandtools.queue.QueuedCommand;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.utils.result.Async;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.flags.RemovePlayerFlags;
|
||||
import org.mvplugins.multiverse.core.command.queue.CommandQueueManager;
|
||||
import org.mvplugins.multiverse.core.command.queue.CommandQueuePayload;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.utils.WorldTickDeferrer;
|
||||
import org.mvplugins.multiverse.core.utils.result.AsyncAttemptsAggregate;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.helpers.PlayerWorldTeleporter;
|
||||
import org.mvplugins.multiverse.core.world.options.DeleteWorldOptions;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class DeleteCommand extends MultiverseCommand {
|
||||
class DeleteCommand extends CoreCommand {
|
||||
|
||||
private final CommandQueueManager commandQueueManager;
|
||||
private final WorldManager worldManager;
|
||||
private final PlayerWorldTeleporter playerWorldTeleporter;
|
||||
|
||||
private final CommandFlag REMOVE_PLAYERS_FLAG = flag(CommandFlag.builder("--remove-players")
|
||||
.addAlias("-r")
|
||||
.build());
|
||||
private final WorldTickDeferrer worldTickDeferrer;
|
||||
private final RemovePlayerFlags flags;
|
||||
|
||||
@Inject
|
||||
DeleteCommand(
|
||||
@NotNull MVCommandManager commandManager,
|
||||
@NotNull CommandQueueManager commandQueueManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull PlayerWorldTeleporter playerWorldTeleporter) {
|
||||
super(commandManager);
|
||||
@NotNull PlayerWorldTeleporter playerWorldTeleporter,
|
||||
@NotNull WorldTickDeferrer worldTickDeferrer,
|
||||
@NotNull RemovePlayerFlags flags
|
||||
) {
|
||||
this.commandQueueManager = commandQueueManager;
|
||||
this.worldManager = worldManager;
|
||||
this.playerWorldTeleporter = playerWorldTeleporter;
|
||||
this.worldTickDeferrer = worldTickDeferrer;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("delete")
|
||||
@CommandPermission("multiverse.core.delete")
|
||||
@CommandCompletion("@mvworlds:scope=loaded @flags:groupName=mvdeletecommand")
|
||||
@CommandCompletion("@mvworlds:scope=both @flags:groupName=" + RemovePlayerFlags.NAME)
|
||||
@Syntax("<world>")
|
||||
@Description("{@@mv-core.delete.description}")
|
||||
void onDeleteCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Single
|
||||
@Conditions("worldname:scope=loaded")
|
||||
@Syntax("<world>")
|
||||
@Description("The world you want to delete.")
|
||||
LoadedMultiverseWorld world,
|
||||
MultiverseWorld world,
|
||||
|
||||
@Optional
|
||||
@Syntax("[--remove-players]")
|
||||
@Description("")
|
||||
String[] flags) {
|
||||
ParsedCommandFlags parsedFlags = parseFlags(flags);
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
|
||||
this.commandManager.getCommandQueueManager().addToQueue(new QueuedCommand(
|
||||
issuer.getIssuer(),
|
||||
() -> {
|
||||
runDeleteCommand(issuer, world, parsedFlags);
|
||||
}, this.commandManager.formatMessage(issuer, MessageType.INFO, MVCorei18n.DELETE_PROMPT,
|
||||
"{world}", world.getName())));
|
||||
commandQueueManager.addToQueue(CommandQueuePayload
|
||||
.issuer(issuer)
|
||||
.action(() -> runDeleteCommand(issuer, world, parsedFlags))
|
||||
.prompt(Message.of(MVCorei18n.DELETE_PROMPT, "",
|
||||
Replace.WORLD.with(world.getName()))));
|
||||
}
|
||||
|
||||
private void runDeleteCommand(MVCommandIssuer issuer, LoadedMultiverseWorld world, ParsedCommandFlags parsedFlags) {
|
||||
issuer.sendInfo(MVCorei18n.DELETE_DELETING, "{world}", world.getName());
|
||||
private void runDeleteCommand(MVCommandIssuer issuer, MultiverseWorld world, ParsedCommandFlags parsedFlags) {
|
||||
issuer.sendInfo(MVCorei18n.DELETE_DELETING, Replace.WORLD.with(world.getName()));
|
||||
|
||||
var future = parsedFlags.hasFlag(REMOVE_PLAYERS_FLAG)
|
||||
? playerWorldTeleporter.removeFromWorld(world)
|
||||
: Async.completedFuture(Collections.emptyList());
|
||||
var future = parsedFlags.hasFlag(flags.removePlayers)
|
||||
&& world.isLoaded()
|
||||
&& world instanceof LoadedMultiverseWorld loadedWorld
|
||||
? playerWorldTeleporter.removeFromWorld(loadedWorld)
|
||||
: AsyncAttemptsAggregate.emptySuccess();
|
||||
|
||||
future.thenRun(() -> doWorldDeleting(issuer, world));
|
||||
future.onSuccess(() -> worldTickDeferrer.deferWorldTick(() -> doWorldDeleting(issuer, world)))
|
||||
.onFailure(() -> issuer.sendError("Failed to teleport one or more players out of the world!"));
|
||||
}
|
||||
|
||||
private void doWorldDeleting(MVCommandIssuer issuer, LoadedMultiverseWorld world) {
|
||||
worldManager.deleteWorld(world)
|
||||
private void doWorldDeleting(MVCommandIssuer issuer, MultiverseWorld world) {
|
||||
worldManager.deleteWorld(DeleteWorldOptions.world(world))
|
||||
.onSuccess(deletedWorldName -> {
|
||||
Logging.fine("World delete success: " + deletedWorldName);
|
||||
issuer.sendInfo(MVCorei18n.DELETE_SUCCESS, "{world}", deletedWorldName);
|
||||
issuer.sendInfo(MVCorei18n.DELETE_SUCCESS, Replace.WORLD.with(deletedWorldName));
|
||||
}).onFailure(failure -> {
|
||||
Logging.fine("World delete failure: " + failure);
|
||||
issuer.sendError(failure.getFailureMessage());
|
||||
});
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends DeleteCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(
|
||||
@NotNull CommandQueueManager commandQueueManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull PlayerWorldTeleporter playerWorldTeleporter,
|
||||
@NotNull WorldTickDeferrer worldTickDeferrer,
|
||||
@NotNull RemovePlayerFlags flags) {
|
||||
super(commandQueueManager, worldManager, playerWorldTeleporter, worldTickDeferrer, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvdelete")
|
||||
void onDeleteCommand(MVCommandIssuer issuer, MultiverseWorld world, String[] flags) {
|
||||
super.onDeleteCommand(issuer, world, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,282 +1,81 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
import co.aikar.commands.CommandIssuer;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import jakarta.inject.Inject;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.MultiverseCore;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.event.MVVersionEvent;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.utils.webpaste.PasteFailedException;
|
||||
import org.mvplugins.multiverse.core.utils.webpaste.PasteService;
|
||||
import org.mvplugins.multiverse.core.utils.webpaste.PasteServiceFactory;
|
||||
import org.mvplugins.multiverse.core.utils.webpaste.PasteServiceType;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
|
||||
import static org.mvplugins.multiverse.core.utils.file.FileUtils.getBukkitConfig;
|
||||
import static org.mvplugins.multiverse.core.utils.file.FileUtils.getServerProperties;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
|
||||
import org.mvplugins.multiverse.core.commands.DumpsLogPoster.LogsType;
|
||||
import org.mvplugins.multiverse.core.commands.DumpsLogPoster.UploadType;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class DumpsCommand extends MultiverseCommand {
|
||||
final class DumpsCommand extends CoreCommand {
|
||||
|
||||
private final MultiverseCore plugin;
|
||||
private final WorldManager worldManager;
|
||||
|
||||
private final CommandValueFlag<LogsTypeOption> LOGS_FLAG = flag(CommandValueFlag
|
||||
.enumBuilder("--logs", LogsTypeOption.class)
|
||||
.addAlias("-l")
|
||||
.build());
|
||||
|
||||
private final CommandValueFlag<ServiceTypeOption> UPLOAD_FLAG = flag(CommandValueFlag
|
||||
.enumBuilder("--upload", ServiceTypeOption.class)
|
||||
.addAlias("-u")
|
||||
.build());
|
||||
|
||||
// Does not upload logs or plugin list (except if --logs mclogs is there)
|
||||
private final CommandFlag PARANOID_FLAG = flag(CommandFlag.builder("--paranoid")
|
||||
.addAlias("-p")
|
||||
.build());
|
||||
private final DumpsService dumpsService;
|
||||
private final DumpsCommand.Flags flags;
|
||||
|
||||
@Inject
|
||||
DumpsCommand(@NotNull MVCommandManager commandManager,
|
||||
@NotNull MultiverseCore plugin,
|
||||
@NotNull WorldManager worldManager) {
|
||||
super(commandManager);
|
||||
this.plugin = plugin;
|
||||
this.worldManager = worldManager;
|
||||
}
|
||||
|
||||
private enum ServiceTypeOption {
|
||||
PASTEGG,
|
||||
PASTESDEV
|
||||
}
|
||||
|
||||
private enum LogsTypeOption {
|
||||
APPEND,
|
||||
MCLOGS
|
||||
DumpsCommand(@NotNull DumpsService dumpsService, @NotNull Flags flags) {
|
||||
this.dumpsService = dumpsService;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("dumps")
|
||||
@CommandPermission("multiverse.core.dumps")
|
||||
@CommandCompletion("@flags:groupName=mvdumpscommand")
|
||||
@CommandCompletion("@flags:groupName=" + Flags.NAME)
|
||||
@Syntax("[--logs <mclogs | append>] [--upload <pastesdev | pastegg>] [--paranoid]")
|
||||
@Description("{@@mv-core.dumps.description}")
|
||||
void onDumpsCommand(
|
||||
CommandIssuer issuer,
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Optional
|
||||
@Syntax("[--logs <mclogs | append>] [--upload <pastesdev | pastegg>] [--paranoid]")
|
||||
String[] flags) {
|
||||
final ParsedCommandFlags parsedFlags = parseFlags(flags);
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
|
||||
// Grab all our flags
|
||||
final boolean paranoid = parsedFlags.hasFlag(PARANOID_FLAG);
|
||||
final LogsTypeOption logsType = parsedFlags.flagValue(LOGS_FLAG, LogsTypeOption.MCLOGS);
|
||||
final ServiceTypeOption servicesType = parsedFlags.flagValue(UPLOAD_FLAG, ServiceTypeOption.PASTEGG);
|
||||
boolean paranoid = parsedFlags.hasFlag(flags.paranoid);
|
||||
LogsType logsType = parsedFlags.flagValue(flags.logs, LogsType.MCLOGS);
|
||||
UploadType servicesType = parsedFlags.flagValue(flags.upload, UploadType.PASTESDEV);
|
||||
|
||||
// Initialise and add info to the debug event
|
||||
MVVersionEvent versionEvent = new MVVersionEvent();
|
||||
this.addDebugInfoToEvent(versionEvent);
|
||||
plugin.getServer().getPluginManager().callEvent(versionEvent);
|
||||
|
||||
// Add plugin list if user isn't paranoid
|
||||
if (!paranoid) {
|
||||
versionEvent.putDetailedVersionInfo("plugins.md", "# Plugins\n\n" + getPluginList());
|
||||
}
|
||||
|
||||
BukkitRunnable logPoster = new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// TODO: Refactor into smaller methods
|
||||
Logging.finer("Logs type is: " + logsType);
|
||||
Logging.finer("Services is: " + servicesType);
|
||||
|
||||
// Deal with logs flag
|
||||
if (!paranoid) {
|
||||
switch (logsType) {
|
||||
case MCLOGS -> issuer.sendInfo(MVCorei18n.DUMPS_URL_LIST,
|
||||
"{service}", "Logs",
|
||||
"{link}", postToService(PasteServiceType.MCLOGS, true, getLogs(), null));
|
||||
case APPEND -> versionEvent.putDetailedVersionInfo("latest.log", getLogs());
|
||||
}
|
||||
}
|
||||
|
||||
// Get the files from the event
|
||||
final Map<String, String> files = versionEvent.getDetailedVersionInfo();
|
||||
|
||||
// Deal with uploading debug info
|
||||
switch (servicesType) {
|
||||
case PASTEGG -> issuer.sendInfo(MVCorei18n.DUMPS_URL_LIST,
|
||||
"{service}", "paste.gg",
|
||||
"{link}", postToService(PasteServiceType.PASTEGG, true, null, files));
|
||||
case PASTESDEV -> issuer.sendInfo(MVCorei18n.DUMPS_URL_LIST,
|
||||
"{service}", "pastes.dev",
|
||||
"{link}", postToService(PasteServiceType.PASTESDEV, true, null, files));
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Run the uploader async as it could take some time to upload the debug info
|
||||
logPoster.runTaskAsynchronously(plugin);
|
||||
dumpsService.postLogs(issuer, logsType, servicesType, paranoid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of the latest.log file
|
||||
*
|
||||
* @return A string containing the latest.log file
|
||||
*/
|
||||
private String getLogs() {
|
||||
// Get the Path of latest.log
|
||||
Path logsPath = plugin.getServer().getWorldContainer().toPath().resolve("logs").resolve("latest.log");
|
||||
File logsFile = logsPath.toFile();
|
||||
@Service
|
||||
private static final class Flags extends FlagBuilder {
|
||||
|
||||
if (!logsFile.exists()) {
|
||||
Logging.warning("Could not read logs/latest.log");
|
||||
return "Could not find log";
|
||||
private static final String NAME = "mvdumps";
|
||||
|
||||
@Inject
|
||||
private Flags(@NotNull CommandFlagsManager flagsManager) {
|
||||
super(NAME, flagsManager);
|
||||
}
|
||||
|
||||
// Try reading as ANSI encoded
|
||||
try {
|
||||
return Files.readString(logsPath, StandardCharsets.ISO_8859_1);
|
||||
} catch (IOException e) {
|
||||
Logging.finer("Log is not ANSI encoded. Trying UTF-8");
|
||||
// Must be a UTF-8 encoded log then
|
||||
}
|
||||
private final CommandValueFlag<LogsType> logs = flag(CommandValueFlag
|
||||
.enumBuilder("--logs", LogsType.class)
|
||||
.addAlias("-l")
|
||||
.build());
|
||||
|
||||
// Try reading as UTF-8 encoded
|
||||
try {
|
||||
return Files.readString(logsPath, StandardCharsets.UTF_8);
|
||||
} catch (IOException ex) {
|
||||
// It is some other strange encoding
|
||||
Logging.severe("Could not read ./logs/latest.log. See below for stack trace");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return "Could not read log";
|
||||
}
|
||||
private final CommandValueFlag<UploadType> upload = flag(CommandValueFlag
|
||||
.enumBuilder("--upload", UploadType.class)
|
||||
.addAlias("-u")
|
||||
.build());
|
||||
|
||||
private String getVersionString() {
|
||||
return "# Multiverse-Core Version info" + "\n\n"
|
||||
+ " - Multiverse-Core Version: " + this.plugin.getDescription().getVersion() + '\n'
|
||||
+ " - Bukkit Version: " + this.plugin.getServer().getVersion() + '\n'
|
||||
+ " - Loaded Worlds: " + worldManager.getLoadedWorlds() + '\n'
|
||||
+ " - Multiverse Plugins Loaded: " + this.plugin.getPluginCount() + '\n';
|
||||
}
|
||||
|
||||
private void addDebugInfoToEvent(MVVersionEvent event) {
|
||||
// Add the legacy file, but as markdown, so it's readable
|
||||
event.putDetailedVersionInfo("version.md", this.getVersionString());
|
||||
|
||||
// add config.yml
|
||||
File configFile = new File(plugin.getDataFolder(), "config.yml");
|
||||
event.putDetailedVersionInfo("multiverse-core/config.yml", configFile);
|
||||
|
||||
// add worlds.yml
|
||||
File worldsFile = new File(plugin.getDataFolder(), "worlds.yml");
|
||||
event.putDetailedVersionInfo("multiverse-core/worlds.yml", worldsFile);
|
||||
|
||||
// Add bukkit.yml if we found it
|
||||
if (getBukkitConfig() != null) {
|
||||
event.putDetailedVersionInfo(getBukkitConfig().getPath(), getBukkitConfig());
|
||||
} else {
|
||||
Logging.warning("/mv version could not find bukkit.yml. Not including file");
|
||||
}
|
||||
|
||||
// Add server.properties if we found it
|
||||
if (getServerProperties() != null) {
|
||||
event.putDetailedVersionInfo(getServerProperties().getPath(), getServerProperties());
|
||||
} else {
|
||||
Logging.warning("/mv version could not find server.properties. Not including file");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String getPluginList() {
|
||||
return " - " + StringUtils.join(plugin.getServer().getPluginManager().getPlugins(), "\n - ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a list of files in to a string containing askii art.
|
||||
*
|
||||
* @param files Map of filenames/contents
|
||||
* @return The askii art
|
||||
*/
|
||||
private String encodeAsString(Map<String, String> files) {
|
||||
StringBuilder uploadData = new StringBuilder();
|
||||
for (String file : files.keySet()) {
|
||||
String data = files.get(file);
|
||||
uploadData.append("# ---------- ")
|
||||
.append(file)
|
||||
.append(" ----------\n\n")
|
||||
.append(data)
|
||||
.append("\n\n");
|
||||
}
|
||||
|
||||
return uploadData.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the current contents of this.pasteBinBuffer to a web service.
|
||||
*
|
||||
* @param type Service type to send paste data to.
|
||||
* @param isPrivate Should the paste be marked as private.
|
||||
* @param rawPasteData Legacy string containing only data to post to a service.
|
||||
* @param pasteFiles Map of filenames/contents of debug info.
|
||||
* @return URL of visible paste
|
||||
*/
|
||||
private String postToService(@NotNull PasteServiceType type, boolean isPrivate, @Nullable String rawPasteData, @Nullable Map<String, String> pasteFiles) {
|
||||
PasteService pasteService = PasteServiceFactory.getService(type, isPrivate);
|
||||
|
||||
try {
|
||||
// Upload normally when multi file is supported
|
||||
if (pasteService.supportsMultiFile()) {
|
||||
return pasteService.postData(pasteFiles);
|
||||
}
|
||||
|
||||
// When there is raw paste data, use that
|
||||
if (rawPasteData != null) { // For the logs
|
||||
return pasteService.postData(rawPasteData);
|
||||
}
|
||||
|
||||
// If all we have are files and the paste service does not support multi file then encode them
|
||||
if (pasteFiles != null) {
|
||||
return pasteService.postData(this.encodeAsString(pasteFiles));
|
||||
}
|
||||
|
||||
// Should never get here
|
||||
return "No data specified in code";
|
||||
|
||||
} catch (PasteFailedException e) {
|
||||
e.printStackTrace();
|
||||
return "Error posting to service.";
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
return "That service isn't supported yet.";
|
||||
}
|
||||
// Does not upload logs or plugin list (except if --logs mclogs is there)
|
||||
private final CommandFlag paranoid = flag(CommandFlag.builder("--paranoid")
|
||||
.addAlias("-p")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.event.MVDumpsDebugInfoEvent;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.utils.webpaste.PasteFailedException;
|
||||
import org.mvplugins.multiverse.core.utils.webpaste.PasteService;
|
||||
import org.mvplugins.multiverse.core.utils.webpaste.PasteServiceFactory;
|
||||
import org.mvplugins.multiverse.core.utils.webpaste.PasteServiceType;
|
||||
|
||||
final class DumpsLogPoster extends BukkitRunnable {
|
||||
|
||||
enum UploadType {
|
||||
// BEGIN CHECKSTYLE-SUPPRESSION: JavadocVariable
|
||||
PASTEGG(PasteServiceType.PASTEGG, "paste.gg"),
|
||||
PASTESDEV(PasteServiceType.PASTESDEV, "pastes.dev");
|
||||
// END CHECKSTYLE-SUPPRESSION: JavadocVariable
|
||||
|
||||
private final PasteServiceType pasteServiceType;
|
||||
private final String serviceName;
|
||||
|
||||
UploadType(PasteServiceType pasteServiceType, String serviceName) {
|
||||
this.pasteServiceType = pasteServiceType;
|
||||
this.serviceName = serviceName;
|
||||
}
|
||||
}
|
||||
|
||||
enum LogsType {
|
||||
/**
|
||||
* Appends the log file to the debug info.
|
||||
*/
|
||||
APPEND,
|
||||
/**
|
||||
* Uploads the log file to a paste service.
|
||||
*/
|
||||
MCLOGS
|
||||
}
|
||||
|
||||
private final MVCommandIssuer issuer;
|
||||
private final LogsType logsType;
|
||||
private final UploadType uploadType;
|
||||
private final boolean paranoid;
|
||||
private final String logs;
|
||||
private final MVDumpsDebugInfoEvent versionEvent;
|
||||
|
||||
DumpsLogPoster(@NotNull MVCommandIssuer issuer,
|
||||
@NotNull DumpsLogPoster.LogsType logsType,
|
||||
@NotNull DumpsLogPoster.UploadType uploadType,
|
||||
boolean paranoid,
|
||||
@NotNull String logs,
|
||||
@NotNull MVDumpsDebugInfoEvent versionEvent) {
|
||||
this.issuer = issuer;
|
||||
this.logsType = logsType;
|
||||
this.uploadType = uploadType;
|
||||
this.paranoid = paranoid;
|
||||
this.logs = logs;
|
||||
this.versionEvent = versionEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
handleLogs();
|
||||
handleVersionEvent();
|
||||
}
|
||||
|
||||
@SuppressWarnings("checkstyle:MissingSwitchDefault")
|
||||
private void handleLogs() {
|
||||
Logging.finer("Logs type is: " + logsType);
|
||||
|
||||
if (!paranoid) {
|
||||
switch (logsType) {
|
||||
case MCLOGS -> sendDumpsUrl("Logs", postRawDataToMcLogs(logs));
|
||||
case APPEND -> versionEvent.putDetailedDebugInfo("latest.log", logs);
|
||||
default -> Logging.finer("Not uploading logs.");
|
||||
}
|
||||
} else {
|
||||
Logging.finer("Paranoid mode is on, not uploading logs.");
|
||||
}
|
||||
}
|
||||
|
||||
private void handleVersionEvent() {
|
||||
Logging.finer("Upload service is: " + uploadType);
|
||||
|
||||
final Map<String, String> files = versionEvent.getDetailedDebugInfo();
|
||||
sendDumpsUrl(uploadType.serviceName, postFilesToService(files));
|
||||
}
|
||||
|
||||
private void sendDumpsUrl(String service, String url) {
|
||||
issuer.sendInfo(MVCorei18n.DUMPS_URL_LIST, "{service}", service, "{link}", url);
|
||||
}
|
||||
|
||||
private String postRawDataToMcLogs(@NotNull String rawPasteData) {
|
||||
PasteService pasteService = PasteServiceFactory.getService(PasteServiceType.MCLOGS, true);
|
||||
|
||||
return pasteToService(() -> pasteService.postData(rawPasteData));
|
||||
}
|
||||
|
||||
private String postFilesToService(@NotNull Map<String, String> pasteFiles) {
|
||||
PasteService pasteService = PasteServiceFactory.getService(uploadType.pasteServiceType, true);
|
||||
|
||||
return pasteToService(() -> {
|
||||
if (pasteService.supportsMultiFile()) {
|
||||
return pasteService.postData(pasteFiles);
|
||||
} else {
|
||||
return pasteService.postData(this.encodeAsString(pasteFiles));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String encodeAsString(Map<String, String> files) {
|
||||
StringBuilder uploadData = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : files.entrySet()) {
|
||||
String file = entry.getKey();
|
||||
String data = entry.getValue();
|
||||
uploadData.append("# ---------- ")
|
||||
.append(file)
|
||||
.append(" ----------\n\n")
|
||||
.append(data)
|
||||
.append("\n\n");
|
||||
}
|
||||
|
||||
return uploadData.toString();
|
||||
}
|
||||
|
||||
private String pasteToService(LogPaster paster) {
|
||||
try {
|
||||
return paster.postLogs();
|
||||
} catch (PasteFailedException e) {
|
||||
e.printStackTrace();
|
||||
return "Error posting to service.";
|
||||
}
|
||||
}
|
||||
|
||||
private interface LogPaster {
|
||||
String postLogs() throws PasteFailedException;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import jakarta.inject.Inject;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.MultiverseCore;
|
||||
import org.mvplugins.multiverse.core.module.MultiverseModulesRegistry;
|
||||
import org.mvplugins.multiverse.core.commands.DumpsLogPoster.LogsType;
|
||||
import org.mvplugins.multiverse.core.commands.DumpsLogPoster.UploadType;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.event.MVDumpsDebugInfoEvent;
|
||||
import org.mvplugins.multiverse.core.utils.FileUtils;
|
||||
import org.mvplugins.multiverse.core.utils.StringFormatter;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
|
||||
@Service
|
||||
final class DumpsService {
|
||||
|
||||
private final MultiverseCore plugin;
|
||||
private final WorldManager worldManager;
|
||||
private final FileUtils fileUtils;
|
||||
|
||||
@Inject
|
||||
DumpsService(@NotNull MultiverseCore plugin,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull FileUtils fileUtils) {
|
||||
this.plugin = plugin;
|
||||
this.worldManager = worldManager;
|
||||
this.fileUtils = fileUtils;
|
||||
}
|
||||
|
||||
void postLogs(MVCommandIssuer issuer, LogsType logsType, UploadType servicesType, boolean paranoid) {
|
||||
// Initialise and add info to the debug event
|
||||
MVDumpsDebugInfoEvent versionEvent = createAndCallDebugInfoEvent();
|
||||
|
||||
// Add plugin list if user isn't paranoid
|
||||
if (!paranoid) {
|
||||
versionEvent.putDetailedDebugInfo("plugins.md", "# Plugins\n\n" + getPluginList());
|
||||
}
|
||||
|
||||
new DumpsLogPoster(issuer, logsType, servicesType, paranoid, getLogs(), versionEvent)
|
||||
.runTaskAsynchronously(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of the latest.log file.
|
||||
*
|
||||
* @return A string containing the latest.log file
|
||||
*/
|
||||
private @NotNull String getLogs() {
|
||||
// Get the Path of latest.log
|
||||
Path logsPath = fileUtils.getServerFolder().toPath().resolve("logs/latest.log");
|
||||
File logsFile = logsPath.toFile();
|
||||
|
||||
if (!logsFile.exists()) {
|
||||
Logging.warning("Could not read logs/latest.log");
|
||||
return "Could not find log";
|
||||
}
|
||||
|
||||
return readLogsFromFile(logsPath);
|
||||
}
|
||||
|
||||
private @NotNull String readLogsFromFile(Path logsPath) {
|
||||
String logs = "Could not read log";
|
||||
|
||||
// Try reading as ANSI encoded
|
||||
try {
|
||||
logs = Files.readString(logsPath, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
Logging.severe("Could not read logs/latest.log. See below for stack trace");
|
||||
e.printStackTrace();
|
||||
|
||||
try {
|
||||
logs = Files.readString(logsPath, StandardCharsets.UTF_8);
|
||||
} catch (IOException ex) {
|
||||
// It is some other strange encoding
|
||||
Logging.severe("Could not read ./logs/latest.log. See below for stack trace");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return logs;
|
||||
}
|
||||
|
||||
private String getDebugInfoString() {
|
||||
return "# Multiverse-Core Version info" + "\n\n"
|
||||
+ " - Multiverse-Core Version: " + this.plugin.getDescription().getVersion() + '\n'
|
||||
+ " - Bukkit Version: " + this.plugin.getServer().getVersion() + '\n'
|
||||
+ " - Loaded Worlds: " + worldManager.getLoadedWorlds() + '\n'
|
||||
+ " - Multiverse Plugins Loaded: " + StringFormatter.joinAnd(MultiverseModulesRegistry.get().getRegisteredPlugins()) + '\n'
|
||||
+ " - Multiverse Plugins Count: " + MultiverseModulesRegistry.get().getPluginCount() + '\n';
|
||||
}
|
||||
|
||||
private MVDumpsDebugInfoEvent createAndCallDebugInfoEvent() {
|
||||
MVDumpsDebugInfoEvent event = new MVDumpsDebugInfoEvent();
|
||||
addDebugInfoToEvent(event);
|
||||
plugin.getServer().getPluginManager().callEvent(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
private void addDebugInfoToEvent(MVDumpsDebugInfoEvent event) {
|
||||
// Add the legacy file, but as markdown, so it's readable
|
||||
event.putDetailedDebugInfo("version.md", this.getDebugInfoString());
|
||||
|
||||
// add config.yml
|
||||
File configFile = new File(plugin.getDataFolder(), "config.yml");
|
||||
event.putDetailedDebugInfo("Multiverse-Core/config.yml", configFile);
|
||||
|
||||
// add worlds.yml
|
||||
File worldsFile = new File(plugin.getDataFolder(), "worlds.yml");
|
||||
event.putDetailedDebugInfo("Multiverse-Core/worlds.yml", worldsFile);
|
||||
|
||||
// Add bukkit.yml if we found it
|
||||
if (fileUtils.getBukkitConfig() != null) {
|
||||
event.putDetailedDebugInfo(fileUtils.getBukkitConfig().getPath(), fileUtils.getBukkitConfig());
|
||||
} else {
|
||||
Logging.warning("/mv dumps could not find bukkit.yml. Not including file");
|
||||
}
|
||||
|
||||
// Add server.properties if we found it
|
||||
if (fileUtils.getServerProperties() != null) {
|
||||
event.putDetailedDebugInfo(fileUtils.getServerProperties().getPath(), fileUtils.getServerProperties());
|
||||
} else {
|
||||
Logging.warning("/mv dumps could not find server.properties. Not including file");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String getPluginList() {
|
||||
return " - " + StringUtils.join(plugin.getServer().getPluginManager().getPlugins(), "\n - ");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Flags;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Single;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.entity.SpawnCategory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.flags.PageFilterFlags;
|
||||
import org.mvplugins.multiverse.core.config.handle.PropertyModifyAction;
|
||||
import org.mvplugins.multiverse.core.display.ContentDisplay;
|
||||
import org.mvplugins.multiverse.core.display.filters.DefaultContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.handlers.PagedSendHandler;
|
||||
import org.mvplugins.multiverse.core.display.parsers.ListContentProvider;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.utils.StringFormatter;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.entity.SpawnCategoryConfig;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Subcommand("entity-spawn-config")
|
||||
final class EntitySpawnConfigCommand extends CoreCommand {
|
||||
|
||||
private final WorldManager worldManager;
|
||||
private final PageFilterFlags flags;
|
||||
|
||||
@Inject
|
||||
EntitySpawnConfigCommand(@NotNull WorldManager worldManager, @NotNull PageFilterFlags flags) {
|
||||
this.worldManager = worldManager;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("info")
|
||||
@CommandPermission("multiverse.core.entityspawnconfig.info")
|
||||
@CommandCompletion("@mvworlds:scope=both|@flags:resolveUntil=arg1,groupName=" + PageFilterFlags.NAME + " @flags:groupName=" + PageFilterFlags.NAME)
|
||||
@Syntax("[world] [--page <page>] [--filter <filter>]")
|
||||
@Description("")
|
||||
void onInfoCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Flags("resolve=issuerAware")
|
||||
@Syntax("[world]")
|
||||
MultiverseWorld world,
|
||||
|
||||
@Optional
|
||||
@Syntax("[--page <page>] [--filter <filter>]")
|
||||
String[] flagArray
|
||||
) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
ContentDisplay.create()
|
||||
.addContent(ListContentProvider.forContent(getEntitySpawnConfigList(world)))
|
||||
.withSendHandler(PagedSendHandler.create()
|
||||
.withHeader(Message.of("==== [ Entity Spawn Config '" + world.getName() + "' ] ===="))
|
||||
.withLinesPerPage(8)
|
||||
.withTargetPage(parsedFlags.flagValue(flags.page, 1))
|
||||
.withFilter(parsedFlags.flagValue(flags.filter, DefaultContentFilter.get())))
|
||||
.send(issuer);
|
||||
}
|
||||
|
||||
private List<String> getEntitySpawnConfigList(MultiverseWorld world) {
|
||||
List<String> list = new ArrayList<>();
|
||||
Arrays.stream(SpawnCategory.values()).forEach(spawnCategory -> {
|
||||
list.add(spawnCategory.name() + ": ");
|
||||
SpawnCategoryConfig spawnCategoryConfig = world.getEntitySpawnConfig().getSpawnCategoryConfig(spawnCategory);
|
||||
list.add(" spawn: " + spawnCategoryConfig.isSpawn());
|
||||
list.add(" tick-rate: " + spawnCategoryConfig.getTickRate());
|
||||
list.add(" exceptions: " + StringFormatter.join(spawnCategoryConfig.getExceptions(), ", "));
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
@Subcommand("modify")
|
||||
@CommandPermission("multiverse.core.entityspawnconfig.modify")
|
||||
@CommandCompletion("@mvworlds:scope=both @spawncategories @propsmodifyaction @spawncategorypropsname @spawncategorypropsvalue")
|
||||
@Syntax("[world] <spawn-category> <set|add|reset|remove> <property> [value]")
|
||||
@Description("")
|
||||
void onModifyCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Flags("resolve=issuerAware")
|
||||
@Syntax("[world]")
|
||||
MultiverseWorld world,
|
||||
|
||||
@Syntax("<spawn-category>")
|
||||
SpawnCategory spawnCategory,
|
||||
|
||||
@Syntax("<set|add|reset|remove>")
|
||||
PropertyModifyAction action,
|
||||
|
||||
@Syntax("<property>")
|
||||
String property,
|
||||
|
||||
@Optional
|
||||
@Single
|
||||
@Syntax("[value]")
|
||||
@Nullable String value
|
||||
) {
|
||||
world.getEntitySpawnConfig()
|
||||
.getSpawnCategoryConfig(spawnCategory)
|
||||
.getStringPropertyHandle()
|
||||
.modifyPropertyString(property, value, action)
|
||||
.onSuccess(ignore -> issuer.sendMessage("Successfully set " + property + " to " + value
|
||||
+ " for " + spawnCategory.name() + " in " + world.getName()))
|
||||
.onFailure(e -> issuer.sendMessage("Unable to set " + property + " to " + value
|
||||
+ " for " + spawnCategory.name() + " in " + world.getName() + ": " + e.getMessage()));
|
||||
|
||||
worldManager.saveWorldsConfig();
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import co.aikar.commands.CommandIssuer;
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import co.aikar.commands.MessageType;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
@@ -16,65 +15,45 @@ import co.aikar.commands.annotation.Flags;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import io.vavr.control.Option;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.World;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.commandtools.context.GameRuleValue;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.command.context.GameRuleValue;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.flags.PageFilterFlags;
|
||||
import org.mvplugins.multiverse.core.display.ContentDisplay;
|
||||
import org.mvplugins.multiverse.core.display.filters.ContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.DefaultContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.RegexContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.handlers.PagedSendHandler;
|
||||
import org.mvplugins.multiverse.core.display.parsers.MapContentProvider;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
|
||||
import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
@Subcommand("gamerule|rule|gamerules|rules")
|
||||
class GameruleCommand extends MultiverseCommand {
|
||||
class GameruleCommand extends CoreCommand {
|
||||
|
||||
private final CommandValueFlag<Integer> PAGE_FLAG = flag(CommandValueFlag
|
||||
.builder("--page", Integer.class)
|
||||
.addAlias("-p")
|
||||
.context(value -> {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new InvalidCommandArgument("Invalid page number: " + value);
|
||||
}
|
||||
})
|
||||
.build());
|
||||
|
||||
private final CommandValueFlag<ContentFilter> FILTER_FLAG = flag(CommandValueFlag
|
||||
.builder("--filter", ContentFilter.class)
|
||||
.addAlias("-f")
|
||||
.context(value -> {
|
||||
try {
|
||||
return RegexContentFilter.fromString(value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new InvalidCommandArgument("Invalid filter: " + value);
|
||||
}
|
||||
})
|
||||
.build());
|
||||
private final PageFilterFlags flags;
|
||||
|
||||
@Inject
|
||||
GameruleCommand(@NotNull MVCommandManager commandManager) {
|
||||
super(commandManager);
|
||||
GameruleCommand(@NotNull PageFilterFlags flags) {
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("set")
|
||||
@Subcommand("gamerule|rule set")
|
||||
@CommandPermission("multiverse.core.gamerule.set")
|
||||
@CommandCompletion("@gamerules true|false|@range:1-10 @mvworlds:multiple|*")
|
||||
@CommandCompletion("@gamerules @gamerulesvalues @mvworlds:multiple|*")
|
||||
@Syntax("<Gamerule> <Gamerule value> [World or *]")
|
||||
@Description("{@@mv-core.gamerule.set.description}")
|
||||
void onGameruleSetCommand(
|
||||
@@ -92,17 +71,17 @@ class GameruleCommand extends MultiverseCommand {
|
||||
@Syntax("[World or *]")
|
||||
@Description("{@@mv-core.gamerule.set.world.description}")
|
||||
LoadedMultiverseWorld[] worlds) {
|
||||
Object value = gameRuleValue.getValue();
|
||||
Object value = gameRuleValue.value();
|
||||
boolean success = true;
|
||||
for (LoadedMultiverseWorld world : worlds) {
|
||||
// Set gamerules and add false to list if it fails
|
||||
World bukkitWorld = world.getBukkitWorld().getOrNull();
|
||||
if (bukkitWorld == null || !bukkitWorld.setGameRule(gamerule, value)) {
|
||||
issuer.sendError(MVCorei18n.GAMERULE_SET_FAILED,
|
||||
"{gamerule}", gamerule.getName(),
|
||||
"{value}", value.toString(),
|
||||
"{world}", world.getName(),
|
||||
"{type}", gamerule.getType().getName());
|
||||
Replace.GAMERULE.with(gamerule.getName()),
|
||||
Replace.VALUE.with(value.toString()),
|
||||
Replace.WORLD.with(world.getName()),
|
||||
replace("{type}").with(gamerule.getType().getName()));
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
@@ -110,24 +89,25 @@ class GameruleCommand extends MultiverseCommand {
|
||||
if (success) {
|
||||
if (worlds.length == 1) {
|
||||
issuer.sendInfo(MVCorei18n.GAMERULE_SET_SUCCESS_SINGLE,
|
||||
"{gamerule}", gamerule.getName(),
|
||||
"{value}", value.toString(),
|
||||
"{world}", worlds[0].getName());
|
||||
Replace.GAMERULE.with(gamerule.getName()),
|
||||
Replace.VALUE.with(value.toString()),
|
||||
Replace.WORLD.with(worlds[0].getName()));
|
||||
} else if (worlds.length > 1) {
|
||||
issuer.sendInfo(MVCorei18n.GAMERULE_SET_SUCCESS_MULTIPLE,
|
||||
"{gamerule}", gamerule.getName(),
|
||||
"{value}", value.toString(),
|
||||
"{count}", String.valueOf(worlds.length));
|
||||
Replace.GAMERULE.with(gamerule.getName()),
|
||||
Replace.VALUE.with(value.toString()),
|
||||
Replace.COUNT.with(String.valueOf(worlds.length)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subcommand("reset")
|
||||
@SuppressWarnings("rawtypes,unchecked")
|
||||
@Subcommand("gamerule|rule reset")
|
||||
@CommandPermission("multiverse.core.gamerule.set")
|
||||
@CommandCompletion("@gamerules @mvworlds:multiple|*")
|
||||
@Syntax("<Gamerule> [World or *]")
|
||||
@Description("{@@mv-core.gamerule.reset.description}")
|
||||
void onGameruleSetCommand(
|
||||
void onGameruleResetCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Syntax("<Gamerule>")
|
||||
@@ -139,32 +119,34 @@ class GameruleCommand extends MultiverseCommand {
|
||||
@Description("{@@mv-core.gamerule.reset.world.description}")
|
||||
LoadedMultiverseWorld[] worlds) {
|
||||
AtomicBoolean success = new AtomicBoolean(true);
|
||||
Arrays.stream(worlds).forEach(world -> world.getBukkitWorld().peek(bukkitWorld -> {
|
||||
bukkitWorld.setGameRule(gamerule, bukkitWorld.getGameRuleDefault(gamerule));
|
||||
}).onEmpty(() -> {
|
||||
success.set(false);
|
||||
issuer.sendError(MVCorei18n.GAMERULE_RESET_FAILED,
|
||||
"{gamerule}", gamerule.getName(),
|
||||
"{world}", world.getName());
|
||||
}));
|
||||
Arrays.stream(worlds)
|
||||
.forEach(world -> world.getBukkitWorld()
|
||||
.flatMap(bukkitWorld -> Option.of(bukkitWorld.getGameRuleDefault(gamerule))
|
||||
.map(value -> bukkitWorld.setGameRule(gamerule, value)))
|
||||
.onEmpty(() -> {
|
||||
success.set(false);
|
||||
issuer.sendError(MVCorei18n.GAMERULE_RESET_FAILED,
|
||||
Replace.GAMERULE.with(gamerule.getName()),
|
||||
Replace.WORLD.with(world.getName()));
|
||||
}));
|
||||
|
||||
// Tell user if it was successful
|
||||
if (success.get()) {
|
||||
if (worlds.length == 1) {
|
||||
issuer.sendInfo(MVCorei18n.GAMERULE_RESET_SUCCESS_SINGLE,
|
||||
"{gamerule}", gamerule.getName(),
|
||||
"{world}", worlds[0].getName());
|
||||
Replace.GAMERULE.with(gamerule.getName()),
|
||||
Replace.WORLD.with(worlds[0].getName()));
|
||||
} else if (worlds.length > 1) {
|
||||
issuer.sendInfo(MVCorei18n.GAMERULE_RESET_SUCCESS_MULTIPLE,
|
||||
"{gamerule}", gamerule.getName(),
|
||||
"{count}", String.valueOf(worlds.length));
|
||||
Replace.GAMERULE.with(gamerule.getName()),
|
||||
Replace.COUNT.with(String.valueOf(worlds.length)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subcommand("list")
|
||||
@Subcommand("gamerule|rule list")
|
||||
@CommandPermission("multiverse.core.gamerule.list")
|
||||
@CommandCompletion("@mvworlds|@flags:groupName=mvgamerulecommand @flags:groupName=mvgamerulecommand")
|
||||
@CommandCompletion("@mvworlds|@flags:groupName=" + PageFilterFlags.NAME + " @flags:groupName=" + PageFilterFlags.NAME)
|
||||
@Syntax("[world] [--page <page>] [--filter <filter>]")
|
||||
@Description("{@@mv-core.gamerule.list.description}")
|
||||
void onGameruleListCommand(
|
||||
@@ -178,18 +160,18 @@ class GameruleCommand extends MultiverseCommand {
|
||||
@Optional
|
||||
@Syntax("[--page <page>] [--filter <filter>]")
|
||||
@Description("{@@mv-core.gamerule.list.description.page}")
|
||||
String[] flags) {
|
||||
ParsedCommandFlags parsedFlags = parseFlags(flags);
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
|
||||
ContentDisplay.create()
|
||||
.addContent(MapContentProvider.forContent(getGameRuleMap(world.getBukkitWorld().getOrNull())) // TODO: Handle null
|
||||
.addContent(MapContentProvider.forContent(getGameRuleMap(world.getBukkitWorld().getOrNull()))
|
||||
.withKeyColor(ChatColor.AQUA)
|
||||
.withValueColor(ChatColor.WHITE))
|
||||
.withSendHandler(PagedSendHandler.create()
|
||||
.withHeader(this.getListTitle(issuer, world.getBukkitWorld().getOrNull()))
|
||||
.withHeader(this.getListTitle(world.getBukkitWorld().getOrNull()))
|
||||
.doPagination(true)
|
||||
.withTargetPage(parsedFlags.flagValue(PAGE_FLAG, 1))
|
||||
.withFilter(parsedFlags.flagValue(FILTER_FLAG, DefaultContentFilter.get())))
|
||||
.withTargetPage(parsedFlags.flagValue(flags.page, 1))
|
||||
.withFilter(parsedFlags.flagValue(flags.filter, DefaultContentFilter.get())))
|
||||
.send(issuer);
|
||||
}
|
||||
|
||||
@@ -201,23 +183,51 @@ class GameruleCommand extends MultiverseCommand {
|
||||
*/
|
||||
private Map<String, String> getGameRuleMap(World world) {
|
||||
Map<String, String> gameRuleMap = new HashMap<>();
|
||||
if (world == null) {
|
||||
return gameRuleMap;
|
||||
}
|
||||
|
||||
for (GameRule<?> gamerule : GameRule.values()) {
|
||||
Object gameruleValue = world.getGameRuleValue(gamerule);
|
||||
if (gameruleValue == null) {
|
||||
gameRuleMap.put(gamerule.getName(), "null");
|
||||
for (String gamerule : world.getGameRules()) {
|
||||
GameRule<?> gameruleEnum = GameRule.getByName(gamerule);
|
||||
if (gameruleEnum == null) {
|
||||
continue;
|
||||
}
|
||||
gameRuleMap.put(gamerule.getName(), gameruleValue.toString());
|
||||
Object gameruleValue = world.getGameRuleValue(gameruleEnum);
|
||||
if (gameruleValue == null) {
|
||||
gameRuleMap.put(gameruleEnum.getName(), "null");
|
||||
continue;
|
||||
}
|
||||
gameRuleMap.put(gameruleEnum.getName(), gameruleValue.toString());
|
||||
}
|
||||
return gameRuleMap;
|
||||
}
|
||||
|
||||
private String getListTitle(CommandIssuer issuer, World world) {
|
||||
return this.commandManager.formatMessage(
|
||||
issuer,
|
||||
MessageType.INFO,
|
||||
MVCorei18n.GAMERULE_LIST_TITLE,
|
||||
"{world}", world.getName());
|
||||
private Message getListTitle(@Nullable World world) {
|
||||
return Message.of(MVCorei18n.GAMERULE_LIST_TITLE, Replace.WORLD.with(world == null ? "null" : world.getName()));
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends GameruleCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull PageFilterFlags flags) {
|
||||
super(flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvrule|mvgamerule")
|
||||
void onGameruleSetCommand(MVCommandIssuer issuer, GameRule gamerule, GameRuleValue gameRuleValue, LoadedMultiverseWorld[] worlds) {
|
||||
super.onGameruleSetCommand(issuer, gamerule, gameRuleValue, worlds);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onGameruleResetCommand(MVCommandIssuer issuer, GameRule gamerule, LoadedMultiverseWorld[] worlds) {
|
||||
super.onGameruleResetCommand(issuer, gamerule, worlds);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvrules|mvgamerules")
|
||||
void onGameruleListCommand(MVCommandIssuer issuer, LoadedMultiverseWorld world, String[] flags) {
|
||||
super.onGameruleListCommand(issuer, world, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@ package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import co.aikar.commands.MessageType;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
@@ -16,79 +14,54 @@ import org.bukkit.ChatColor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.flags.PageFilterFlags;
|
||||
import org.mvplugins.multiverse.core.display.ContentDisplay;
|
||||
import org.mvplugins.multiverse.core.display.filters.ContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.DefaultContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.RegexContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.handlers.PagedSendHandler;
|
||||
import org.mvplugins.multiverse.core.display.parsers.ListContentProvider;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.utils.StringFormatter;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorPlugin;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
|
||||
|
||||
/**
|
||||
* List all gamerules in your current or specified world.
|
||||
*/
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class GeneratorsCommand extends MultiverseCommand {
|
||||
class GeneratorsCommand extends CoreCommand {
|
||||
|
||||
private final GeneratorProvider generatorProvider;
|
||||
|
||||
private final CommandValueFlag<Integer> PAGE_FLAG = flag(CommandValueFlag
|
||||
.builder("--page", Integer.class)
|
||||
.addAlias("-p")
|
||||
.context(value -> {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new InvalidCommandArgument("Invalid page number: " + value);
|
||||
}
|
||||
})
|
||||
.build());
|
||||
|
||||
private final CommandValueFlag<ContentFilter> FILTER_FLAG = flag(CommandValueFlag
|
||||
.builder("--filter", ContentFilter.class)
|
||||
.addAlias("-f")
|
||||
.context(value -> {
|
||||
try {
|
||||
return RegexContentFilter.fromString(value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new InvalidCommandArgument("Invalid filter: " + value);
|
||||
}
|
||||
})
|
||||
.build());
|
||||
private final PageFilterFlags flags;
|
||||
|
||||
@Inject
|
||||
GeneratorsCommand(@NotNull MVCommandManager commandManager, @NotNull GeneratorProvider generatorProvider) {
|
||||
super(commandManager);
|
||||
GeneratorsCommand(@NotNull GeneratorProvider generatorProvider, @NotNull PageFilterFlags flags) {
|
||||
this.generatorProvider = generatorProvider;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("generators|gens")
|
||||
@Subcommand("generators list")
|
||||
@CommandPermission("multiverse.core.generator")
|
||||
@CommandCompletion("@flags:groupName=mvgeneratorscommand @flags:groupName=mvgeneratorscommand")
|
||||
@Syntax("")
|
||||
@CommandCompletion("@flags:groupName=" + PageFilterFlags.NAME)
|
||||
@Syntax("[--page <page>] [--filter <filter>]")
|
||||
@Description("{@@mv-core.generators.description}")
|
||||
void onGamerulesCommand(
|
||||
void onGeneratorsListCommand(
|
||||
@NotNull MVCommandIssuer issuer,
|
||||
|
||||
@Optional
|
||||
@Syntax("[--page <page>] [--filter <filter>]")
|
||||
@Description("{@@mv-core.generators.description.flags}")
|
||||
String[] flags) {
|
||||
ParsedCommandFlags parsedFlags = parseFlags(flags);
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
|
||||
// Get the generators loaded using the command suggestions
|
||||
List<String> generators = (List<String>) generatorProvider.suggestGeneratorString("");
|
||||
|
||||
// Tell the user if we cannot find any generator plugins, then abort
|
||||
if (generators.isEmpty()) {
|
||||
issuer.sendMessage(commandManager.formatMessage(issuer, MessageType.INFO, MVCorei18n.GENERATORS_EMPTY));
|
||||
issuer.sendMessage(MVCorei18n.GENERATORS_EMPTY);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -97,8 +70,38 @@ class GeneratorsCommand extends MultiverseCommand {
|
||||
.withSendHandler(PagedSendHandler.create()
|
||||
.withHeader("%s====[ Multiverse Generator List ]====", ChatColor.AQUA)
|
||||
.doPagination(true)
|
||||
.withTargetPage(parsedFlags.flagValue(PAGE_FLAG, 1))
|
||||
.withFilter(parsedFlags.flagValue(FILTER_FLAG, DefaultContentFilter.get())))
|
||||
.withTargetPage(parsedFlags.flagValue(flags.page, 1))
|
||||
.withFilter(parsedFlags.flagValue(flags.filter, DefaultContentFilter.get())))
|
||||
.send(issuer);
|
||||
}
|
||||
|
||||
@Subcommand("generators info")
|
||||
@CommandPermission("multiverse.core.generator")
|
||||
@CommandCompletion("@generatorplugins")
|
||||
@Syntax("<generator>")
|
||||
void onGeneratorsInfoCommand(
|
||||
@NotNull MVCommandIssuer issuer,
|
||||
|
||||
@Syntax("<generator>")
|
||||
GeneratorPlugin generatorPlugin
|
||||
) {
|
||||
issuer.sendMessage(ChatColor.RESET + "Generator Plugin: " + generatorPlugin.getPluginName());
|
||||
issuer.sendMessage(ChatColor.RESET + "Example usages: ");
|
||||
issuer.sendMessage(ChatColor.RESET + StringFormatter.join(generatorPlugin.getExampleUsages(), "\n"));
|
||||
issuer.sendMessage(ChatColor.RESET + "Link to more info: " + generatorPlugin.getInfoLink());
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends GeneratorsCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull GeneratorProvider generatorProvider, @NotNull PageFilterFlags flags) {
|
||||
super(generatorProvider, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvgenerators|mvgens")
|
||||
void onGeneratorsListCommand(@NotNull MVCommandIssuer issuer, String[] flags) {
|
||||
super.onGeneratorsListCommand(issuer, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
-9
@@ -5,36 +5,51 @@ import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.HelpCommand;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class UsageCommand extends MultiverseCommand {
|
||||
class HelpCommand extends CoreCommand {
|
||||
|
||||
private final MVCommandManager commandManager;
|
||||
|
||||
@Inject
|
||||
UsageCommand(@NotNull MVCommandManager commandManager) {
|
||||
super(commandManager);
|
||||
HelpCommand(@NotNull MVCommandManager commandManager) {
|
||||
this.commandManager = commandManager;
|
||||
}
|
||||
|
||||
@HelpCommand
|
||||
@co.aikar.commands.annotation.HelpCommand
|
||||
@Subcommand("help")
|
||||
@CommandPermission("multiverse.core.help")
|
||||
@CommandCompletion("@commands:mv")
|
||||
@Syntax("[filter] [page]")
|
||||
@Description("{@@mv-core.usage.description}")
|
||||
void onUsageCommand(CommandHelp help) {
|
||||
void onHelpCommand(CommandHelp help) {
|
||||
if (help.getIssuer().isPlayer()) {
|
||||
// Prevent flooding the chat
|
||||
help.setPerPage(4);
|
||||
}
|
||||
this.commandManager.showUsage(help);
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends HelpCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull MVCommandManager commandManager) {
|
||||
super(commandManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvhelp")
|
||||
public void onHelpCommand(CommandHelp help) {
|
||||
super.onHelpCommand(help);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,49 +14,37 @@ import org.bukkit.World;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
|
||||
import org.mvplugins.multiverse.core.world.options.ImportWorldOptions;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class ImportCommand extends MultiverseCommand {
|
||||
class ImportCommand extends CoreCommand {
|
||||
|
||||
private final WorldManager worldManager;
|
||||
|
||||
private GeneratorProvider generatorProvider;
|
||||
private final CommandValueFlag<String> GENERATOR_FLAG = flag(CommandValueFlag
|
||||
.builder("--generator", String.class)
|
||||
.addAlias("-g")
|
||||
.completion(input -> generatorProvider.suggestGeneratorString(input))
|
||||
.build());
|
||||
|
||||
private final CommandFlag NO_ADJUST_SPAWN_FLAG = flag(CommandFlag.builder("--no-adjust-spawn")
|
||||
.addAlias("-n")
|
||||
.build());
|
||||
private final ImportCommand.Flags flags;
|
||||
|
||||
@Inject
|
||||
ImportCommand(
|
||||
@NotNull MVCommandManager commandManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull GeneratorProvider generatorProvider) {
|
||||
super(commandManager);
|
||||
ImportCommand(@NotNull WorldManager worldManager, @NotNull Flags flags) {
|
||||
this.worldManager = worldManager;
|
||||
this.generatorProvider = generatorProvider;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("import")
|
||||
@CommandPermission("multiverse.core.import")
|
||||
@CommandCompletion("@mvworlds:scope=potential @environments @flags:groupName=mvimportcommand")
|
||||
@Syntax("<name> <env> --generator [generator[:id]] --adjust-spawn")
|
||||
@Description("{@@mv-core.import.description")
|
||||
@CommandCompletion("@mvworlds:scope=potential @environments @flags:groupName=" + Flags.NAME)
|
||||
@Syntax("<name> <environment> [--generator <generator[:id]> --adjust-spawn --biome <biome>]")
|
||||
@Description("{@@mv-core.import.description}")
|
||||
void onImportCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@@ -70,23 +58,71 @@ class ImportCommand extends MultiverseCommand {
|
||||
World.Environment environment,
|
||||
|
||||
@Optional
|
||||
@Syntax("--generator [generator[:id]] --adjust-spawn")
|
||||
@Syntax("[--generator <generator[:id]> --adjust-spawn --biome <biome>]")
|
||||
@Description("{@@mv-core.import.other.description}")
|
||||
String[] flags) {
|
||||
ParsedCommandFlags parsedFlags = parseFlags(flags);
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
|
||||
issuer.sendInfo(MVCorei18n.IMPORT_IMPORTING, "{world}", worldName);
|
||||
issuer.sendInfo(MVCorei18n.IMPORT_IMPORTING, Replace.WORLD.with(worldName));
|
||||
worldManager.importWorld(ImportWorldOptions.worldName(worldName)
|
||||
.environment(environment)
|
||||
.generator(parsedFlags.flagValue(GENERATOR_FLAG, String.class))
|
||||
.useSpawnAdjust(!parsedFlags.hasFlag(NO_ADJUST_SPAWN_FLAG)))
|
||||
.biome(parsedFlags.flagValue(flags.biome, ""))
|
||||
.environment(environment)
|
||||
.generator(parsedFlags.flagValue(flags.generator, String.class))
|
||||
.useSpawnAdjust(!parsedFlags.hasFlag(flags.noAdjustSpawn))
|
||||
.doFolderCheck(!parsedFlags.hasFlag(flags.skipFolderCheck)))
|
||||
.onSuccess(newWorld -> {
|
||||
Logging.fine("World import success: " + newWorld);
|
||||
issuer.sendInfo(MVCorei18n.IMPORT_SUCCESS, "{world}", newWorld.getName());
|
||||
issuer.sendInfo(MVCorei18n.IMPORT_SUCCESS, Replace.WORLD.with(newWorld.getName()));
|
||||
})
|
||||
.onFailure(failure -> {
|
||||
Logging.fine("World import failure: " + failure);
|
||||
issuer.sendError(failure.getFailureMessage());
|
||||
});
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class Flags extends FlagBuilder {
|
||||
|
||||
private static final String NAME = "mvimport";
|
||||
|
||||
private GeneratorProvider generatorProvider;
|
||||
|
||||
@Inject
|
||||
private Flags(@NotNull CommandFlagsManager flagsManager, @NotNull GeneratorProvider generatorProvider) {
|
||||
super(NAME, flagsManager);
|
||||
this.generatorProvider = generatorProvider;
|
||||
}
|
||||
|
||||
private final CommandValueFlag<String> generator = flag(CommandValueFlag
|
||||
.builder("--generator", String.class)
|
||||
.addAlias("-g")
|
||||
.completion(input -> generatorProvider.suggestGeneratorString(input))
|
||||
.build());
|
||||
|
||||
private final CommandFlag noAdjustSpawn = flag(CommandFlag.builder("--no-adjust-spawn")
|
||||
.addAlias("-n")
|
||||
.build());
|
||||
|
||||
private final CommandValueFlag<String> biome = flag(CommandValueFlag.builder("--biome", String.class)
|
||||
.addAlias("-b")
|
||||
.build());
|
||||
|
||||
private final CommandFlag skipFolderCheck = flag(CommandFlag.builder("--skip-folder-check")
|
||||
.addAlias("-f")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends ImportCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull WorldManager worldManager, @NotNull Flags flags) {
|
||||
super(worldManager, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvimport|mvim")
|
||||
void onImportCommand(MVCommandIssuer issuer, String worldName, World.Environment environment, String[] flags) {
|
||||
super.onImportCommand(issuer, worldName, environment, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package org.mvplugins.multiverse.core.commands;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
@@ -14,72 +13,51 @@ import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.WorldType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.api.LocationManipulation;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.flags.PageFilterFlags;
|
||||
import org.mvplugins.multiverse.core.display.ContentDisplay;
|
||||
import org.mvplugins.multiverse.core.display.filters.ContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.DefaultContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.RegexContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.handlers.PagedSendHandler;
|
||||
import org.mvplugins.multiverse.core.display.parsers.MapContentProvider;
|
||||
import org.mvplugins.multiverse.core.economy.MVEconomist;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
|
||||
import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class InfoCommand extends MultiverseCommand {
|
||||
|
||||
private final CommandValueFlag<Integer> PAGE_FLAG = flag(CommandValueFlag
|
||||
.builder("--page", Integer.class)
|
||||
.addAlias("-p")
|
||||
.context(value -> {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new InvalidCommandArgument("Invalid page number: " + value);
|
||||
}
|
||||
})
|
||||
.build());
|
||||
|
||||
private final CommandValueFlag<ContentFilter> FILTER_FLAG = flag(CommandValueFlag
|
||||
.builder("--filter", ContentFilter.class)
|
||||
.addAlias("-f")
|
||||
.context(value -> {
|
||||
try {
|
||||
return RegexContentFilter.fromString(value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new InvalidCommandArgument("Invalid filter: " + value);
|
||||
}
|
||||
})
|
||||
.build());
|
||||
class InfoCommand extends CoreCommand {
|
||||
|
||||
private final LocationManipulation locationManipulation;
|
||||
private final MVEconomist economist;
|
||||
private final PageFilterFlags flags;
|
||||
|
||||
@Inject
|
||||
InfoCommand(
|
||||
@NotNull MVCommandManager commandManager,
|
||||
@NotNull LocationManipulation locationManipulation,
|
||||
@NotNull MVEconomist economist) {
|
||||
super(commandManager);
|
||||
@NotNull MVEconomist economist,
|
||||
@NotNull PageFilterFlags flags
|
||||
) {
|
||||
this.locationManipulation = locationManipulation;
|
||||
this.economist = economist;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
// TODO: support info for unloaded worlds
|
||||
@Subcommand("info")
|
||||
@CommandPermission("multiverse.core.info")
|
||||
@CommandCompletion("@mvworlds:scope=both|@flags:groupName=mvinfocommand @flags:groupName=mvinfocommand")
|
||||
@CommandCompletion("@mvworlds:scope=both|@flags:resolveUntil=arg1,groupName=" + PageFilterFlags.NAME + " @flags:groupName=" + PageFilterFlags.NAME)
|
||||
@Syntax("[world] [--page <page>] [--filter <filter>]")
|
||||
@Description("{@@mv-core.info.description")
|
||||
@Description("{@@mv-core.info.description}")
|
||||
public void onInfoCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@@ -89,85 +67,113 @@ class InfoCommand extends MultiverseCommand {
|
||||
LoadedMultiverseWorld world,
|
||||
|
||||
@Optional
|
||||
@Syntax("[--page <page>]")
|
||||
@Description("{@@mv-core.info.description.page}")
|
||||
String[] flags) {
|
||||
ParsedCommandFlags parsedFlags = parseFlags(flags);
|
||||
@Syntax("[--page <page>] [--filter <filter>]")
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
|
||||
ContentDisplay.create()
|
||||
.addContent(MapContentProvider.forContent(getInfo(world))
|
||||
.withKeyColor(ChatColor.AQUA)
|
||||
.withValueColor(ChatColor.WHITE))
|
||||
.withSendHandler(PagedSendHandler.create()
|
||||
.withHeader(getTitle(world))
|
||||
.withHeader(Message.of(MVCorei18n.INFO_HEADER, replace("{world}").with(world.getName())))
|
||||
.noContentMessage(Message.of(MVCorei18n.INFO_NOCONTENT))
|
||||
.doPagination(true)
|
||||
.withTargetPage(parsedFlags.flagValue(PAGE_FLAG, 1))
|
||||
.withFilter(parsedFlags.flagValue(FILTER_FLAG, DefaultContentFilter.get())))
|
||||
.withTargetPage(parsedFlags.flagValue(flags.page, 1))
|
||||
.withFilter(parsedFlags.flagValue(flags.filter, DefaultContentFilter.get())))
|
||||
.send(issuer);
|
||||
}
|
||||
|
||||
private String getTitle(MultiverseWorld world) {
|
||||
return "&a&l---- World Info: &f&l%s&a&l ----".formatted(world.getName());
|
||||
}
|
||||
|
||||
private Map<String, String> getInfo(LoadedMultiverseWorld world) {
|
||||
Map<String, String> outMap = new LinkedHashMap<>();
|
||||
|
||||
outMap.put("World Name", world.getName());
|
||||
outMap.put("World Alias", world.getAlias());
|
||||
outMap.put("World UID", world.getUID().toString());
|
||||
outMap.put("Game Mode: ", world.getGameMode().toString());
|
||||
outMap.put("Game Mode", world.getGameMode().toString());
|
||||
outMap.put("Difficulty", world.getDifficulty().toString());
|
||||
|
||||
outMap.put("Spawn Location", locationManipulation.strCoords(world.getSpawnLocation()));
|
||||
outMap.put("Seed", String.valueOf(world.getSeed()));
|
||||
getEntryFeeInfo(outMap, world); // Entry fee/reward
|
||||
outMap.put("Respawn World", world.getRespawnWorldName());
|
||||
outMap.put("World Type", world.getWorldType().get().toString());
|
||||
outMap.put("Bed Respawn", String.valueOf(world.getBedRespawn()));
|
||||
outMap.put("Anchor Respawn", String.valueOf(world.getAnchorRespawn()));
|
||||
|
||||
outMap.put("Seed", String.valueOf(world.getSeed()));
|
||||
outMap.put("Environment", String.valueOf(world.getEnvironment()));
|
||||
outMap.put("World Type", world.getWorldType().map(WorldType::getName).getOrNull());
|
||||
outMap.put("Biome", world.getBiome());
|
||||
outMap.put("Generator", world.getGenerator());
|
||||
outMap.put("Generate Structures", world.canGenerateStructures().get().toString());
|
||||
outMap.put("Generate Structures", world.canGenerateStructures().map(String::valueOf).getOrNull());
|
||||
|
||||
outMap.put("Auto Load", String.valueOf(world.isAutoLoad()));
|
||||
outMap.put("Keep Spawn In Memory", String.valueOf(world.isKeepSpawnInMemory()));
|
||||
|
||||
getEntryFeeInfo(outMap, world);
|
||||
outMap.put("World Scale", String.valueOf(world.getScale()));
|
||||
outMap.put("Weather Enabled", String.valueOf(world.getAllowWeather()));
|
||||
outMap.put("Hunger Depletes", String.valueOf(world.getHunger()));
|
||||
outMap.put("Keep Spawn In Memory", String.valueOf(world.getKeepSpawnInMemory()));
|
||||
outMap.put("Weather Enabled", String.valueOf(world.isAllowWeather()));
|
||||
outMap.put("Allow Flight", String.valueOf(world.isAllowFlight()));
|
||||
outMap.put("Hunger Depletes", String.valueOf(world.isHunger()));
|
||||
outMap.put("Keep Spawn In Memory", String.valueOf(world.isKeepSpawnInMemory()));
|
||||
outMap.put("PVP Enabled", String.valueOf(world.getPvp()));
|
||||
getAnimalSpawningInfo(outMap, world); // Animals that can spawn
|
||||
getMonsterSpawningInfo(outMap, world); // Monsters that can spawn
|
||||
outMap.put("Portal Form", String.valueOf(world.getPortalForm()));
|
||||
outMap.put("Player Limit", String.valueOf(world.getPlayerLimit()));
|
||||
// getAnimalSpawningInfo(outMap, world);
|
||||
// getMonsterSpawningInfo(outMap, world);
|
||||
outMap.put("World Blacklist", String.join(", ", world.getWorldBlacklist()));
|
||||
|
||||
return outMap;
|
||||
}
|
||||
|
||||
private void getEntryFeeInfo(Map<String, String> outMap, LoadedMultiverseWorld world) {
|
||||
private void getEntryFeeInfo(Map<String, String> outMap, MultiverseWorld world) {
|
||||
double price = world.getPrice();
|
||||
if (price == 0) {
|
||||
outMap.put("Entry Fee", "FREE!");
|
||||
} else if (price > 0) {
|
||||
outMap.put("Entry Fee", economist.formatPrice(-price, world.getCurrency()));
|
||||
outMap.put("Entry Fee", economist.formatPrice(price, world.getCurrency()));
|
||||
} else if (price < 0) {
|
||||
outMap.put("Entry Reward", economist.formatPrice(price, world.getCurrency()));
|
||||
outMap.put("Entry Reward", economist.formatPrice(-price, world.getCurrency()));
|
||||
}
|
||||
}
|
||||
|
||||
private void getAnimalSpawningInfo(Map<String, String> outMap, LoadedMultiverseWorld world) {
|
||||
if (world.getSpawningAnimals()) {
|
||||
outMap.put("Spawning Animals", "ALL");
|
||||
} else {
|
||||
if (!world.getSpawningAnimalsExceptions().isEmpty()) {
|
||||
outMap.put("Spawning Animals", world.getSpawningAnimalsExceptions().toString());
|
||||
} else {
|
||||
outMap.put("Spawning Animals", "NONE");
|
||||
}
|
||||
}
|
||||
}
|
||||
// private void getAnimalSpawningInfo(Map<String, String> outMap, MultiverseWorld world) {
|
||||
// if (world.isSpawningAnimals()) {
|
||||
// outMap.put("Spawning Animals", "ALL");
|
||||
// } else {
|
||||
// if (!world.getSpawningAnimalsExceptions().isEmpty()) {
|
||||
// outMap.put("Spawning Animals", world.getSpawningAnimalsExceptions().toString());
|
||||
// } else {
|
||||
// outMap.put("Spawning Animals", "NONE");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void getMonsterSpawningInfo(Map<String, String> outMap, MultiverseWorld world) {
|
||||
// if (world.isSpawningMonsters()) {
|
||||
// outMap.put("Spawning Monsters", "ALL");
|
||||
// } else {
|
||||
// if (!world.getSpawningMonstersExceptions().isEmpty()) {
|
||||
// outMap.put("Spawning Monsters", world.getSpawningMonstersExceptions().toString());
|
||||
// } else {
|
||||
// outMap.put("Spawning Monsters", "NONE");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
private void getMonsterSpawningInfo(Map<String, String> outMap, LoadedMultiverseWorld world) {
|
||||
if (world.getSpawningMonsters()) {
|
||||
outMap.put("Spawning Monsters", "ALL");
|
||||
} else {
|
||||
if (!world.getSpawningMonstersExceptions().isEmpty()) {
|
||||
outMap.put("Spawning Monsters", world.getSpawningMonstersExceptions().toString());
|
||||
} else {
|
||||
outMap.put("Spawning Monsters", "NONE");
|
||||
}
|
||||
@Service
|
||||
private static final class LegacyAlias extends InfoCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(
|
||||
@NotNull LocationManipulation locationManipulation,
|
||||
@NotNull MVEconomist economist,
|
||||
@NotNull PageFilterFlags flags
|
||||
) {
|
||||
super(locationManipulation, economist, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvinfo|mvi")
|
||||
public void onInfoCommand(MVCommandIssuer issuer, LoadedMultiverseWorld world, String[] flags) {
|
||||
super.onInfoCommand(issuer, world, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package org.mvplugins.multiverse.core.commands;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
@@ -16,110 +15,107 @@ import org.bukkit.World;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.flags.PageFilterFlags;
|
||||
import org.mvplugins.multiverse.core.display.ContentDisplay;
|
||||
import org.mvplugins.multiverse.core.display.filters.ContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.DefaultContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.RegexContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.handlers.PagedSendHandler;
|
||||
import org.mvplugins.multiverse.core.display.parsers.ListContentProvider;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.entrycheck.WorldEntryChecker;
|
||||
import org.mvplugins.multiverse.core.world.entrycheck.WorldEntryCheckerProvider;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class ListCommand extends MultiverseCommand {
|
||||
class ListCommand extends CoreCommand {
|
||||
|
||||
private final WorldManager worldManager;
|
||||
private final WorldEntryCheckerProvider worldEntryCheckerProvider;
|
||||
|
||||
private final CommandValueFlag<Integer> PAGE_FLAG = flag(CommandValueFlag
|
||||
.builder("--page", Integer.class)
|
||||
.addAlias("-p")
|
||||
.context(value -> {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new InvalidCommandArgument("Invalid page number: " + value);
|
||||
}
|
||||
})
|
||||
.build());
|
||||
|
||||
private final CommandValueFlag<ContentFilter> FILTER_FLAG = flag(CommandValueFlag
|
||||
.builder("--filter", ContentFilter.class)
|
||||
.addAlias("-f")
|
||||
.context(value -> {
|
||||
try {
|
||||
return RegexContentFilter.fromString(value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new InvalidCommandArgument("Invalid filter: " + value);
|
||||
}
|
||||
})
|
||||
.build());
|
||||
private final ListCommand.Flags flags;
|
||||
|
||||
@Inject
|
||||
ListCommand(
|
||||
@NotNull MVCommandManager commandManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull WorldEntryCheckerProvider worldEntryCheckerProvider) {
|
||||
super(commandManager);
|
||||
@NotNull WorldEntryCheckerProvider worldEntryCheckerProvider,
|
||||
@NotNull Flags flags
|
||||
) {
|
||||
this.worldManager = worldManager;
|
||||
this.worldEntryCheckerProvider = worldEntryCheckerProvider;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("list")
|
||||
@CommandPermission("multiverse.core.list.worlds")
|
||||
@CommandCompletion("@flags:groupName=mvlistcommand")
|
||||
@Syntax("--filter [filter] --page [page]")
|
||||
@Description("Displays a listing of all worlds that you can enter.")
|
||||
@CommandCompletion("@flags:groupName=" + Flags.NAME)
|
||||
@Syntax("--filter [filter] --page [page] --raw")
|
||||
@Description("{{@mv-core.list.description}}")
|
||||
public void onListCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Syntax("[--filter <filter>] [--page <page>]")
|
||||
@Description("Filters the list of worlds by the given regex and displays the given page.")
|
||||
String[] flags) {
|
||||
ParsedCommandFlags parsedFlags = parseFlags(flags);
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
ContentDisplay.create()
|
||||
.addContent(ListContentProvider.forContent(getListContents(issuer)))
|
||||
.addContent(ListContentProvider.forContent(getListContents(issuer, parsedFlags.hasFlag(flags.raw))))
|
||||
.withSendHandler(PagedSendHandler.create()
|
||||
.withHeader("%s====[ Multiverse World List ]====", ChatColor.GOLD)
|
||||
.withTargetPage(parsedFlags.flagValue(PAGE_FLAG, 1))
|
||||
.withFilter(parsedFlags.flagValue(FILTER_FLAG, DefaultContentFilter.get())))
|
||||
.noContentMessage(Message.of(MVCorei18n.LIST_NOCONTENT))
|
||||
.withHeader(Message.of(MVCorei18n.LIST_HEADER))
|
||||
.withTargetPage(parsedFlags.flagValue(flags.page, 1))
|
||||
.withFilter(parsedFlags.flagValue(flags.filter, DefaultContentFilter.get())))
|
||||
.send(issuer);
|
||||
}
|
||||
|
||||
private List<String> getListContents(MVCommandIssuer issuer) {
|
||||
private List<String> getListContents(MVCommandIssuer issuer, boolean useRawNames) {
|
||||
List<String> worldList = new ArrayList<>();
|
||||
WorldEntryChecker worldEntryChecker = worldEntryCheckerProvider.forSender(issuer.getIssuer());
|
||||
|
||||
worldManager.getLoadedWorlds().stream()
|
||||
.filter(world -> worldEntryChecker.canAccessWorld(world).isSuccess())
|
||||
.filter(world -> canSeeWorld(issuer, world))
|
||||
.map(world -> hiddenText(world) + world.getAlias() + " - " + parseColouredEnvironment(world.getEnvironment()))
|
||||
.map(world -> hiddenText(world) + getWorldName(world, useRawNames) + " - "
|
||||
+ parseColouredEnvironment(world.getEnvironment()))
|
||||
.sorted()
|
||||
.forEach(worldList::add);
|
||||
|
||||
worldManager.getUnloadedWorlds().stream()
|
||||
.filter(world -> worldEntryChecker.canAccessWorld(world).isSuccess())
|
||||
.map(world -> ChatColor.GRAY + world.getAlias() + " - UNLOADED")
|
||||
.map(world -> ChatColor.GRAY + getWorldName(world, useRawNames) + " - UNLOADED")
|
||||
.sorted()
|
||||
.forEach(worldList::add);
|
||||
|
||||
return worldList;
|
||||
}
|
||||
|
||||
private boolean canSeeWorld(MVCommandIssuer issuer, LoadedMultiverseWorld world) {
|
||||
return !world.isHidden()
|
||||
|| issuer.hasPermission("multiverse.core.modify"); // TODO: Refactor stray permission check
|
||||
/**
|
||||
* Gets a world's name or alias.
|
||||
*
|
||||
* @param world The world to retrieve the name of
|
||||
* @param useRawNames True to return the name, false to return the alias
|
||||
* @return The name
|
||||
*/
|
||||
private String getWorldName(MultiverseWorld world, boolean useRawNames) {
|
||||
if (useRawNames) {
|
||||
return world.getName();
|
||||
}
|
||||
|
||||
return world.getAliasOrName();
|
||||
}
|
||||
|
||||
private String hiddenText(LoadedMultiverseWorld world) {
|
||||
private boolean canSeeWorld(MVCommandIssuer issuer, MultiverseWorld world) {
|
||||
return !world.isHidden()
|
||||
// TODO: Refactor stray permission check
|
||||
|| issuer.hasPermission("multiverse.core.modify");
|
||||
}
|
||||
|
||||
private String hiddenText(MultiverseWorld world) {
|
||||
return (world.isHidden()) ? String.format("%s[H] ", ChatColor.GRAY) : "";
|
||||
}
|
||||
|
||||
@@ -132,4 +128,37 @@ class ListCommand extends MultiverseCommand {
|
||||
};
|
||||
return color + env.toString();
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class Flags extends PageFilterFlags {
|
||||
|
||||
private static final String NAME = "mvlist";
|
||||
|
||||
@Inject
|
||||
private Flags(@NotNull CommandFlagsManager flagsManager) {
|
||||
super(NAME, flagsManager);
|
||||
}
|
||||
|
||||
private final CommandFlag raw = flag(CommandFlag.builder("--raw")
|
||||
.addAlias("-r")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends ListCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull WorldEntryCheckerProvider worldEntryCheckerProvider,
|
||||
@NotNull Flags flags
|
||||
) {
|
||||
super(worldManager, worldEntryCheckerProvider, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvlist|mvl")
|
||||
public void onListCommand(MVCommandIssuer issuer, String[] flags) {
|
||||
super.onListCommand(issuer, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,8 @@ package org.mvplugins.multiverse.core.commands;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Conditions;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Single;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
@@ -13,22 +12,28 @@ import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.flags.RemovePlayerFlags;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.options.LoadWorldOptions;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class LoadCommand extends MultiverseCommand {
|
||||
class LoadCommand extends CoreCommand {
|
||||
|
||||
private final WorldManager worldManager;
|
||||
private final LoadCommand.Flags flags;
|
||||
|
||||
@Inject
|
||||
LoadCommand(@NotNull MVCommandManager commandManager, @NotNull WorldManager worldManager) {
|
||||
super(commandManager);
|
||||
LoadCommand(@NotNull WorldManager worldManager, @NotNull Flags flags) {
|
||||
this.worldManager = worldManager;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("load")
|
||||
@@ -39,19 +44,54 @@ class LoadCommand extends MultiverseCommand {
|
||||
void onLoadCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Single
|
||||
@Conditions("worldname:scope=unloaded")
|
||||
@Syntax("<world>")
|
||||
@Description("{@@mv-core.load.world.description}")
|
||||
String worldName) {
|
||||
issuer.sendInfo(MVCorei18n.LOAD_LOADING, "{world}", worldName);
|
||||
worldManager.loadWorld(worldName)
|
||||
MultiverseWorld world,
|
||||
|
||||
@Optional
|
||||
@Syntax("[--remove-players]")
|
||||
@Description("")
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
|
||||
issuer.sendInfo(MVCorei18n.LOAD_LOADING, Replace.WORLD.with(world.getName()));
|
||||
worldManager.loadWorld(LoadWorldOptions.world(world)
|
||||
.doFolderCheck(!parsedFlags.hasFlag(flags.skipFolderCheck)))
|
||||
.onSuccess(newWorld -> {
|
||||
Logging.fine("World load success: " + newWorld);
|
||||
issuer.sendInfo(MVCorei18n.LOAD_SUCCESS, "{world}", newWorld.getName());
|
||||
issuer.sendInfo(MVCorei18n.LOAD_SUCCESS, Replace.WORLD.with(newWorld.getName()));
|
||||
}).onFailure(failure -> {
|
||||
Logging.fine("World load failure: " + failure);
|
||||
issuer.sendError(failure.getFailureMessage());
|
||||
});
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class Flags extends RemovePlayerFlags {
|
||||
|
||||
private static final String NAME = "mvunload";
|
||||
|
||||
@Inject
|
||||
private Flags(@NotNull CommandFlagsManager flagsManager) {
|
||||
super(NAME, flagsManager);
|
||||
}
|
||||
|
||||
private final CommandFlag skipFolderCheck = flag(CommandFlag.builder("--skip-folder-check")
|
||||
.addAlias("-f")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends LoadCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull WorldManager worldManager, @NotNull Flags flags) {
|
||||
super(worldManager, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvload")
|
||||
void onLoadCommand(MVCommandIssuer issuer, MultiverseWorld world, String[] flagArray) {
|
||||
super.onLoadCommand(issuer, world, flagArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,72 +6,130 @@ import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Flags;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Single;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.configuration.handle.PropertyModifyAction;
|
||||
import org.mvplugins.multiverse.core.configuration.handle.StringPropertyHandle;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.context.issueraware.MultiverseWorldValue;
|
||||
import org.mvplugins.multiverse.core.config.handle.PropertyModifyAction;
|
||||
import org.mvplugins.multiverse.core.config.handle.StringPropertyHandle;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.*;
|
||||
import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class ModifyCommand extends MultiverseCommand {
|
||||
class ModifyCommand extends CoreCommand {
|
||||
|
||||
private static final Map<String, String> REMOVED_PROPERTIES = Map.of(
|
||||
"animals", "/mv entity-spawn-config modify [world] animal set spawn <true|false>",
|
||||
"monsters", "/mv entity-spawn-config modify [world] monster set spawn <true|false>"
|
||||
);
|
||||
|
||||
private final WorldManager worldManager;
|
||||
|
||||
@Inject
|
||||
ModifyCommand(@NotNull MVCommandManager commandManager, WorldManager worldManager) {
|
||||
super(commandManager);
|
||||
ModifyCommand(WorldManager worldManager) {
|
||||
this.worldManager = worldManager;
|
||||
}
|
||||
|
||||
@Subcommand("modify")
|
||||
@CommandPermission("multiverse.core.modify")
|
||||
@CommandCompletion("@mvworlds:scope=both @propsmodifyaction @mvworldpropsname @mvworldpropsvalue")
|
||||
@CommandCompletion("@mvworlds:scope=both|@propsmodifyaction:byIssuerForArg=arg1 " +
|
||||
"@propsmodifyaction:notByIssuerForArg=arg1|@mvworldpropsname:byIssuerForArg=arg1 " +
|
||||
"@mvworldpropsname:notByIssuerForArg=arg1|@mvworldpropsvalue:byIssuerForArg=arg1 " +
|
||||
"@mvworldpropsvalue:notByIssuerForArg=arg1")
|
||||
@Syntax("[world] <set|add|remove|reset> <property> <value>")
|
||||
@Description("")
|
||||
void onModifyCommand(
|
||||
@Description("{@@mv-core.modify.description}")
|
||||
void onModifyCommand(// SUPPRESS CHECKSTYLE: ParameterNumber
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Flags("resolve=issuerAware")
|
||||
@Syntax("[world]")
|
||||
@Description("")
|
||||
MultiverseWorld world,
|
||||
@Description("{@@mv-core.modify.world.description}")
|
||||
@NotNull MultiverseWorldValue worldValue,
|
||||
|
||||
@Syntax("<set|add|remove|reset>")
|
||||
@Description("")
|
||||
PropertyModifyAction action,
|
||||
@NotNull PropertyModifyAction action,
|
||||
|
||||
@Syntax("<property>")
|
||||
@Description("")
|
||||
String propertyName,
|
||||
@Description("{@@mv-core.modify.property.description}")
|
||||
@NotNull String propertyName,
|
||||
|
||||
@Optional
|
||||
@Single
|
||||
@Syntax("[value]")
|
||||
@Description("")
|
||||
String propertyValue) {
|
||||
@Description("{@@mv-core.modify.value.description}")
|
||||
@Nullable String propertyValue) {
|
||||
if (REMOVED_PROPERTIES.containsKey(propertyName)) {
|
||||
issuer.sendMessage(MVCorei18n.MODIFY_PROPERTYREMOVED,
|
||||
replace("{property}").with(propertyName),
|
||||
replace("{replacement}").with(REMOVED_PROPERTIES.get(propertyName)));
|
||||
return;
|
||||
}
|
||||
|
||||
MultiverseWorld world = worldValue.value();
|
||||
|
||||
if (action.isRequireValue() && propertyValue == null) {
|
||||
issuer.sendMessage(MVCorei18n.MODIFY_SPECIFYVALUE,
|
||||
replace("{action}").with(action.name().toLowerCase()),
|
||||
replace("{property}").with(propertyName));
|
||||
return;
|
||||
} else if (!action.isRequireValue() && propertyValue != null) {
|
||||
issuer.sendMessage(MVCorei18n.MODIFY_CANNOTHAVEVALUE,
|
||||
replace("{action}").with(action.name().toLowerCase()),
|
||||
replace("{property}").with(propertyName));
|
||||
return;
|
||||
}
|
||||
|
||||
StringPropertyHandle worldPropertyHandle = world.getStringPropertyHandle();
|
||||
worldPropertyHandle.modifyProperty(propertyName, propertyValue, action).onSuccess(ignore -> {
|
||||
issuer.sendMessage("Property %s set to %s for world %s.".formatted(
|
||||
propertyName,
|
||||
worldPropertyHandle.getProperty(propertyName).getOrNull(),
|
||||
world.getName()));
|
||||
worldPropertyHandle.modifyPropertyString(issuer.getIssuer(), propertyName, propertyValue, action).onSuccess(ignore -> {
|
||||
issuer.sendMessage(MVCorei18n.MODIFY_SUCCESS,
|
||||
replace("{action}").with(action.name().toLowerCase()),
|
||||
replace("{property}").with(propertyName),
|
||||
Replace.VALUE.with(worldPropertyHandle.getProperty(propertyName).getOrNull()),
|
||||
Replace.WORLD.with(world.getName()));
|
||||
worldManager.saveWorldsConfig();
|
||||
}).onFailure(exception -> {
|
||||
issuer.sendMessage("Failed to %s property %s to %s for world %s.".formatted(
|
||||
action.name().toLowerCase(),
|
||||
propertyName,
|
||||
propertyValue,
|
||||
world.getName()));
|
||||
issuer.sendMessage(exception.getMessage());
|
||||
if (propertyValue == null) {
|
||||
issuer.sendMessage(MVCorei18n.MODIFY_FAILURE_NOVALUE,
|
||||
replace("{action}").with(action.name().toLowerCase()),
|
||||
replace("{property}").with(propertyName),
|
||||
Replace.WORLD.with(world.getName()),
|
||||
Replace.ERROR.with(exception.getMessage()));
|
||||
} else {
|
||||
issuer.sendMessage(MVCorei18n.MODIFY_FAILURE,
|
||||
replace("{action}").with(action.name().toLowerCase()),
|
||||
replace("{property}").with(propertyName),
|
||||
Replace.VALUE.with(propertyValue),
|
||||
Replace.WORLD.with(world.getName()),
|
||||
Replace.ERROR.with(exception.getMessage()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends ModifyCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(WorldManager worldManager) {
|
||||
super(worldManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvmodify|mvm")
|
||||
void onModifyCommand(MVCommandIssuer issuer, @NotNull MultiverseWorldValue world, @NotNull PropertyModifyAction action, @NotNull String propertyName, @Nullable String propertyValue) {
|
||||
super.onModifyCommand(issuer, world, action, propertyName, propertyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Flags;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.entity.SpawnCategory;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.utils.StringFormatter;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.entity.EntityPurger;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
final class PurgeAllEntitiesCommand extends CoreCommand {
|
||||
|
||||
private final EntityPurger entityPurger;
|
||||
|
||||
@Inject
|
||||
PurgeAllEntitiesCommand(EntityPurger entityPurger) {
|
||||
this.entityPurger = entityPurger;
|
||||
}
|
||||
|
||||
@Subcommand("purge-all-entities")
|
||||
@CommandPermission("multiverse.core.purgeall")
|
||||
@CommandCompletion("@mvworlds:scope=loaded|@spawncategories:multiple,resolveUntil=arg1 @spawncategories:multiple")
|
||||
@Syntax("[world] [spawn-categories]")
|
||||
void onPurgeAllEntitiesCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Flags("resolve=issuerAware")
|
||||
@Syntax("[world]")
|
||||
LoadedMultiverseWorld world,
|
||||
|
||||
@Optional
|
||||
@Syntax("[spawn-categories]")
|
||||
SpawnCategory[] spawnCategories
|
||||
) {
|
||||
if (spawnCategories == null || spawnCategories.length == 0) {
|
||||
int purgeCount = entityPurger.purgeAllEntities(world);
|
||||
issuer.sendMessage("Successfully purged " + purgeCount + " entities in world " + world.getName() + ".");
|
||||
return;
|
||||
}
|
||||
|
||||
int purgeCount = entityPurger.purgeEntities(world, spawnCategories);
|
||||
issuer.sendMessage("Successfully purged " + purgeCount + " entities in world " + world.getName() +
|
||||
" for spawn categories " + StringFormatter.join(List.of(spawnCategories), ", ") + ".");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Flags;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.entity.EntityPurger;
|
||||
|
||||
@Service
|
||||
final class PurgeEntitiesCommand extends CoreCommand {
|
||||
|
||||
private final EntityPurger entityPurger;
|
||||
|
||||
@Inject
|
||||
PurgeEntitiesCommand(EntityPurger entityPurger) {
|
||||
this.entityPurger = entityPurger;
|
||||
}
|
||||
|
||||
@Subcommand("purge-entities")
|
||||
@CommandPermission("multiverse.core.purge")
|
||||
@CommandCompletion("@mvworlds:scope=loaded")
|
||||
@Syntax("[world]")
|
||||
void onPurgeEntityCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Flags("resolve=issuerAware")
|
||||
@Syntax("[world]")
|
||||
LoadedMultiverseWorld world
|
||||
) {
|
||||
int purgeCount = entityPurger.purgeEntities(world);
|
||||
issuer.sendMessage("Successfully purged " + purgeCount + " entities in world " + world.getName() + ".");
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,8 @@ package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import co.aikar.commands.MessageType;
|
||||
import co.aikar.commands.ACFUtil;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
@@ -18,62 +17,55 @@ import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.commandtools.queue.QueuedCommand;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.utils.result.Async;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.flags.RemovePlayerFlags;
|
||||
import org.mvplugins.multiverse.core.command.queue.CommandQueueManager;
|
||||
import org.mvplugins.multiverse.core.command.queue.CommandQueuePayload;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.utils.REPatterns;
|
||||
import org.mvplugins.multiverse.core.utils.WorldTickDeferrer;
|
||||
import org.mvplugins.multiverse.core.utils.result.AsyncAttemptsAggregate;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.helpers.PlayerWorldTeleporter;
|
||||
import org.mvplugins.multiverse.core.world.options.RegenWorldOptions;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class RegenCommand extends MultiverseCommand {
|
||||
class RegenCommand extends CoreCommand {
|
||||
|
||||
@NotNull
|
||||
private final CommandQueueManager commandQueueManager;
|
||||
private final WorldManager worldManager;
|
||||
private final PlayerWorldTeleporter playerWorldTeleporter;
|
||||
|
||||
private final CommandValueFlag<String> SEED_FLAG = flag(CommandValueFlag.builder("--seed", String.class)
|
||||
.addAlias("-s")
|
||||
.completion(input -> Collections.singleton(String.valueOf(new Random().nextLong())))
|
||||
.build());
|
||||
|
||||
private final CommandFlag RESET_WORLD_CONFIG_FLAG = flag(CommandFlag.builder("--reset-world-config")
|
||||
.addAlias("-wc")
|
||||
.build());
|
||||
|
||||
private final CommandFlag RESET_GAMERULES_FLAG = flag(CommandFlag.builder("--reset-gamerules")
|
||||
.addAlias("-gm")
|
||||
.build());
|
||||
|
||||
private final CommandFlag RESET_WORLD_BORDER_FLAG = flag(CommandFlag.builder("--reset-world-border")
|
||||
.addAlias("-wb")
|
||||
.build());
|
||||
|
||||
private final CommandFlag REMOVE_PLAYERS_FLAG = flag(CommandFlag.builder("--remove-players")
|
||||
.addAlias("-r")
|
||||
.build());
|
||||
private final WorldTickDeferrer worldTickDeferrer;
|
||||
private final RegenCommand.Flags flags;
|
||||
|
||||
@Inject
|
||||
RegenCommand(
|
||||
@NotNull MVCommandManager commandManager,
|
||||
@NotNull CommandQueueManager commandQueueManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull PlayerWorldTeleporter playerWorldTeleporter) {
|
||||
super(commandManager);
|
||||
@NotNull PlayerWorldTeleporter playerWorldTeleporter,
|
||||
@NotNull WorldTickDeferrer worldTickDeferrer,
|
||||
@NotNull Flags flags
|
||||
) {
|
||||
this.commandQueueManager = commandQueueManager;
|
||||
this.worldManager = worldManager;
|
||||
this.playerWorldTeleporter = playerWorldTeleporter;
|
||||
this.worldTickDeferrer = worldTickDeferrer;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("regen")
|
||||
@CommandPermission("multiverse.core.regen")
|
||||
@CommandCompletion("@mvworlds:scope=loaded @flags:groupName=mvregencommand")
|
||||
@Syntax("<world> --seed [seed] --keep-gamerules")
|
||||
@CommandCompletion("@mvworlds:scope=loaded @flags:groupName=" + Flags.NAME)
|
||||
@Syntax("<world> [--seed [seed] --reset-world-config --reset-gamerules --reset-world-border --remove-players]")
|
||||
@Description("{@@mv-core.regen.description}")
|
||||
void onRegenCommand(
|
||||
MVCommandIssuer issuer,
|
||||
@@ -83,27 +75,30 @@ class RegenCommand extends MultiverseCommand {
|
||||
LoadedMultiverseWorld world,
|
||||
|
||||
@Optional
|
||||
@Syntax("--seed [seed] --reset-gamerules")
|
||||
@Syntax("[--seed [seed] --reset-world-config --reset-gamerules --reset-world-border --remove-players]")
|
||||
@Description("{@@mv-core.regen.other.description}")
|
||||
String[] flags) {
|
||||
ParsedCommandFlags parsedFlags = parseFlags(flags);
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
|
||||
this.commandManager.getCommandQueueManager().addToQueue(new QueuedCommand(
|
||||
issuer.getIssuer(),
|
||||
() -> runRegenCommand(issuer, world, parsedFlags),
|
||||
this.commandManager.formatMessage(
|
||||
issuer, MessageType.INFO, MVCorei18n.REGEN_PROMPT, "{world}", world.getName())));
|
||||
commandQueueManager.addToQueue(CommandQueuePayload
|
||||
.issuer(issuer)
|
||||
.action(() -> runRegenCommand(issuer, world, parsedFlags))
|
||||
.prompt(Message.of(MVCorei18n.REGEN_PROMPT, "",
|
||||
Replace.WORLD.with(world.getName()))));
|
||||
}
|
||||
|
||||
private void runRegenCommand(MVCommandIssuer issuer, LoadedMultiverseWorld world, ParsedCommandFlags parsedFlags) {
|
||||
issuer.sendInfo(MVCorei18n.REGEN_REGENERATING, "{world}", world.getName());
|
||||
issuer.sendInfo(MVCorei18n.REGEN_REGENERATING, Replace.WORLD.with(world.getName()));
|
||||
List<Player> worldPlayers = world.getPlayers().getOrElse(Collections.emptyList());
|
||||
|
||||
var future = parsedFlags.hasFlag(REMOVE_PLAYERS_FLAG)
|
||||
var future = parsedFlags.hasFlag(flags.removePlayers)
|
||||
? playerWorldTeleporter.removeFromWorld(world)
|
||||
: Async.completedFuture(Collections.emptyList());
|
||||
: AsyncAttemptsAggregate.emptySuccess();
|
||||
|
||||
future.thenRun(() -> doWorldRegening(issuer, world, parsedFlags, worldPlayers));
|
||||
// todo: using future will hide stacktrace
|
||||
future.onSuccess(() -> worldTickDeferrer
|
||||
.deferWorldTick(() -> doWorldRegening(issuer, world, parsedFlags, worldPlayers)))
|
||||
.onFailure(() -> issuer.sendError("Failed to teleport one or more players out of the world!"));
|
||||
}
|
||||
|
||||
private void doWorldRegening(
|
||||
@@ -111,22 +106,80 @@ class RegenCommand extends MultiverseCommand {
|
||||
LoadedMultiverseWorld world,
|
||||
ParsedCommandFlags parsedFlags,
|
||||
List<Player> worldPlayers) {
|
||||
//todo: Change biome on regen
|
||||
RegenWorldOptions regenWorldOptions = RegenWorldOptions.world(world)
|
||||
.randomSeed(parsedFlags.hasFlag(SEED_FLAG))
|
||||
.seed(parsedFlags.flagValue(SEED_FLAG))
|
||||
.keepWorldConfig(!parsedFlags.hasFlag(RESET_WORLD_CONFIG_FLAG))
|
||||
.keepGameRule(!parsedFlags.hasFlag(RESET_GAMERULES_FLAG))
|
||||
.keepWorldBorder(!parsedFlags.hasFlag(RESET_WORLD_BORDER_FLAG));
|
||||
.randomSeed(parsedFlags.hasFlag(flags.seed))
|
||||
.seed(parsedFlags.flagValue(flags.seed))
|
||||
.keepWorldConfig(!parsedFlags.hasFlag(flags.resetWorldConfig))
|
||||
.keepGameRule(!parsedFlags.hasFlag(flags.resetGamerules))
|
||||
.keepWorldBorder(!parsedFlags.hasFlag(flags.resetWorldBorder))
|
||||
.keepFiles(parsedFlags.flagValue(flags.keepFiles));
|
||||
|
||||
worldManager.regenWorld(regenWorldOptions).onSuccess(newWorld -> {
|
||||
Logging.fine("World regen success: " + newWorld);
|
||||
issuer.sendInfo(MVCorei18n.REGEN_SUCCESS, "{world}", newWorld.getName());
|
||||
if (parsedFlags.hasFlag(REMOVE_PLAYERS_FLAG)) {
|
||||
issuer.sendInfo(MVCorei18n.REGEN_SUCCESS, Replace.WORLD.with(newWorld.getName()));
|
||||
if (parsedFlags.hasFlag(flags.removePlayers)) {
|
||||
playerWorldTeleporter.teleportPlayersToWorld(worldPlayers, newWorld);
|
||||
}
|
||||
}).onFailure(failure -> {
|
||||
Logging.fine("World regen failure: " + failure);
|
||||
Logging.warning("World regen failure: " + failure);
|
||||
issuer.sendError(failure.getFailureMessage());
|
||||
});
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class Flags extends RemovePlayerFlags {
|
||||
|
||||
private static final String NAME = "mvregen";
|
||||
|
||||
@Inject
|
||||
private Flags(@NotNull CommandFlagsManager flagsManager) {
|
||||
super(NAME, flagsManager);
|
||||
}
|
||||
|
||||
private final CommandValueFlag<String> seed = flag(CommandValueFlag.builder("--seed", String.class)
|
||||
.addAlias("-s")
|
||||
.completion(input -> Collections.singleton(String.valueOf(ACFUtil.RANDOM.nextLong())))
|
||||
.optional()
|
||||
.build());
|
||||
|
||||
private final CommandFlag resetWorldConfig = flag(CommandFlag.builder("--reset-world-config")
|
||||
.addAlias("-wc")
|
||||
.build());
|
||||
|
||||
private final CommandFlag resetGamerules = flag(CommandFlag.builder("--reset-gamerules")
|
||||
.addAlias("-gm")
|
||||
.build());
|
||||
|
||||
private final CommandFlag resetWorldBorder = flag(CommandFlag.builder("--reset-world-border")
|
||||
.addAlias("-wb")
|
||||
.build());
|
||||
|
||||
private final CommandValueFlag<List> keepFiles = flag(CommandValueFlag.builder("--keep-files", List.class)
|
||||
.addAlias("-f")
|
||||
.completion(input -> List.of("paper-world.yml"))
|
||||
.defaultValue(Collections.emptyList())
|
||||
.context(input -> List.of(REPatterns.COMMA.split(input)))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends RegenCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(
|
||||
@NotNull CommandQueueManager commandQueueManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull PlayerWorldTeleporter playerWorldTeleporter,
|
||||
@NotNull WorldTickDeferrer worldTickDeferrer,
|
||||
@NotNull Flags flags
|
||||
) {
|
||||
super(commandQueueManager, worldManager, playerWorldTeleporter, worldTickDeferrer, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvregen")
|
||||
void onRegenCommand(MVCommandIssuer issuer, LoadedMultiverseWorld world, String[] flags) {
|
||||
super.onRegenCommand(issuer, world, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,30 +14,28 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.config.MVCoreConfig;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.event.MVConfigReloadEvent;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class ReloadCommand extends MultiverseCommand {
|
||||
class ReloadCommand extends CoreCommand {
|
||||
|
||||
private final MVCoreConfig config;
|
||||
private final CoreConfig config;
|
||||
private final AnchorManager anchorManager;
|
||||
private final WorldManager worldManager;
|
||||
private final PluginManager pluginManager;
|
||||
|
||||
@Inject
|
||||
ReloadCommand(
|
||||
@NotNull MVCommandManager commandManager,
|
||||
@NotNull MVCoreConfig config,
|
||||
@NotNull CoreConfig config,
|
||||
@NotNull AnchorManager anchorManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull PluginManager pluginManager) {
|
||||
super(commandManager);
|
||||
@NotNull PluginManager pluginManager
|
||||
) {
|
||||
this.config = config;
|
||||
this.anchorManager = anchorManager;
|
||||
this.worldManager = worldManager;
|
||||
@@ -50,24 +48,36 @@ class ReloadCommand extends MultiverseCommand {
|
||||
void onReloadCommand(@NotNull BukkitCommandIssuer issuer) {
|
||||
issuer.sendInfo(MVCorei18n.RELOAD_RELOADING);
|
||||
try {
|
||||
// TODO: Make this all Try<Void>
|
||||
this.config.load().getOrElseThrow(e -> new RuntimeException("Failed to load config", e));
|
||||
this.worldManager.initAllWorlds().getOrElseThrow(e -> new RuntimeException("Failed to init worlds", e));
|
||||
this.anchorManager.loadAnchors();
|
||||
this.anchorManager.loadAnchors().getOrElseThrow(e -> new RuntimeException("Failed to load anchors", e));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
List<String> configsLoaded = new ArrayList<>();
|
||||
configsLoaded.add("Multiverse-Core - config.yml");
|
||||
configsLoaded.add("Multiverse-Core - worlds2.yml");
|
||||
configsLoaded.add("Multiverse-Core - worlds.yml");
|
||||
configsLoaded.add("Multiverse-Core - anchors.yml");
|
||||
|
||||
MVConfigReloadEvent configReload = new MVConfigReloadEvent(configsLoaded);
|
||||
this.pluginManager.callEvent(configReload);
|
||||
|
||||
// TODO: replace this sendMessage and format the configsLoaded above, maybe?
|
||||
configReload.getAllConfigsLoaded().forEach(issuer::sendMessage);
|
||||
issuer.sendInfo(MVCorei18n.RELOAD_SUCCESS);
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends ReloadCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull CoreConfig config, @NotNull AnchorManager anchorManager, @NotNull WorldManager worldManager, @NotNull PluginManager pluginManager) {
|
||||
super(config, anchorManager, worldManager, pluginManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvreload|mvr")
|
||||
void onReloadCommand(@NotNull BukkitCommandIssuer issuer) {
|
||||
super.onReloadCommand(issuer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Conditions;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Single;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
@@ -16,75 +12,112 @@ import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.utils.result.Async;
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.flags.RemovePlayerFlags;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.utils.result.AsyncAttemptsAggregate;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.helpers.PlayerWorldTeleporter;
|
||||
import org.mvplugins.multiverse.core.world.options.RemoveWorldOptions;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
class RemoveCommand extends MultiverseCommand {
|
||||
class RemoveCommand extends CoreCommand {
|
||||
|
||||
private final WorldManager worldManager;
|
||||
private final PlayerWorldTeleporter playerWorldTeleporter;
|
||||
|
||||
private final CommandFlag REMOVE_PLAYERS_FLAG = flag(CommandFlag.builder("--remove-players")
|
||||
.addAlias("-r")
|
||||
.build());
|
||||
private final Flags flags;
|
||||
|
||||
@Inject
|
||||
RemoveCommand(
|
||||
@NotNull MVCommandManager commandManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull PlayerWorldTeleporter playerWorldTeleporter) {
|
||||
super(commandManager);
|
||||
@NotNull PlayerWorldTeleporter playerWorldTeleporter,
|
||||
@NotNull Flags flags
|
||||
) {
|
||||
this.worldManager = worldManager;
|
||||
this.playerWorldTeleporter = playerWorldTeleporter;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("remove")
|
||||
@CommandPermission("multiverse.core.remove")
|
||||
@CommandCompletion("@mvworlds:scope=both")
|
||||
@CommandCompletion("@mvworlds:scope=both @flags:groupName=" + Flags.NAME)
|
||||
@Syntax("<world>")
|
||||
@Description("{@@mv-core.remove.description}")
|
||||
void onRemoveCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Single
|
||||
@Conditions("mvworlds:scope=both @flags:groupName=mvremovecommand")
|
||||
@Syntax("<world>")
|
||||
@Description("{@@mv-core.remove.world.description}")
|
||||
MultiverseWorld world,
|
||||
|
||||
@Optional
|
||||
@Syntax("[--remove-players]")
|
||||
@Description(/* TODO */"")
|
||||
String[] flags) {
|
||||
ParsedCommandFlags parsedFlags = parseFlags(flags);
|
||||
@Description("")
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
|
||||
var future = parsedFlags.hasFlag(REMOVE_PLAYERS_FLAG)
|
||||
? worldManager.getLoadedWorld(world)
|
||||
.map(playerWorldTeleporter::removeFromWorld)
|
||||
.getOrElse(Async.completedFuture(Collections.emptyList()))
|
||||
: Async.completedFuture(Collections.emptyList());
|
||||
var future = parsedFlags.hasFlag(flags.removePlayers)
|
||||
? worldManager.getLoadedWorld(world).map(playerWorldTeleporter::removeFromWorld).getOrElse(AsyncAttemptsAggregate::emptySuccess)
|
||||
: AsyncAttemptsAggregate.emptySuccess();
|
||||
|
||||
future.thenRun(() -> doWorldRemoving(issuer, world));
|
||||
future.onSuccess(() -> doWorldRemoving(issuer, world, parsedFlags))
|
||||
.onFailure(() -> issuer.sendError("Failed to teleport one or more players out of the world!"));
|
||||
}
|
||||
|
||||
private void doWorldRemoving(MVCommandIssuer issuer, MultiverseWorld world) {
|
||||
worldManager.removeWorld(world)
|
||||
private void doWorldRemoving(MVCommandIssuer issuer, MultiverseWorld world, ParsedCommandFlags parsedFlags) {
|
||||
worldManager.removeWorld(RemoveWorldOptions.world(world)
|
||||
.saveBukkitWorld(!parsedFlags.hasFlag(flags.noSave))
|
||||
.unloadBukkitWorld(!parsedFlags.hasFlag(flags.noUnloadBukkitWorld)))
|
||||
.onSuccess(removedWorldName -> {
|
||||
Logging.fine("World remove success: " + removedWorldName);
|
||||
issuer.sendInfo(MVCorei18n.REMOVE_SUCCESS, "{world}", removedWorldName);
|
||||
issuer.sendInfo(MVCorei18n.REMOVE_SUCCESS, Replace.WORLD.with(removedWorldName));
|
||||
}).onFailure(failure -> {
|
||||
Logging.fine("World remove failure: " + failure);
|
||||
issuer.sendError(failure.getFailureMessage());
|
||||
});
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class Flags extends RemovePlayerFlags {
|
||||
|
||||
private static final String NAME = "mvremove";
|
||||
|
||||
@Inject
|
||||
private Flags(@NotNull CommandFlagsManager flagsManager) {
|
||||
super(NAME, flagsManager);
|
||||
}
|
||||
|
||||
private final CommandFlag noUnloadBukkitWorld = flag(CommandFlag.builder("--no-unload-bukkit-world")
|
||||
.addAlias("-b")
|
||||
.build());
|
||||
|
||||
private final CommandFlag noSave = flag(CommandFlag.builder("--no-save")
|
||||
.addAlias("-n")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends RemoveCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull PlayerWorldTeleporter playerWorldTeleporter,
|
||||
@NotNull Flags flags
|
||||
) {
|
||||
super(worldManager, playerWorldTeleporter, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvremove")
|
||||
void onRemoveCommand(MVCommandIssuer issuer, MultiverseWorld world, String[] flags) {
|
||||
super.onRemoveCommand(issuer, world, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,18 +9,16 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.MultiverseCore;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.utils.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
|
||||
@Service
|
||||
class RootCommand extends MultiverseCommand {
|
||||
final class RootCommand extends CoreCommand {
|
||||
|
||||
private final Plugin plugin;
|
||||
|
||||
@Inject
|
||||
RootCommand(@NotNull MVCommandManager commandManager, @NotNull MultiverseCore plugin) {
|
||||
super(commandManager);
|
||||
RootCommand(@NotNull MultiverseCore plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import co.aikar.commands.BukkitCommandIssuer;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Flags;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
@@ -13,59 +11,85 @@ import jakarta.inject.Inject;
|
||||
import org.bukkit.Location;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.api.BlockSafety;
|
||||
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.commandtools.MultiverseCommand;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.context.PlayerLocation;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.flags.UnsafeFlags;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.teleportation.BlockSafety;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
|
||||
@Service
|
||||
@CommandAlias("mv")
|
||||
public class SetSpawnCommand extends MultiverseCommand {
|
||||
class SetSpawnCommand extends CoreCommand {
|
||||
|
||||
private final WorldManager worldManager;
|
||||
private final BlockSafety blockSafety;
|
||||
private final UnsafeFlags flags;
|
||||
|
||||
@Inject
|
||||
SetSpawnCommand(@NotNull MVCommandManager commandManager) {
|
||||
super(commandManager);
|
||||
SetSpawnCommand(@NotNull WorldManager worldManager, @NotNull BlockSafety blockSafety, @NotNull UnsafeFlags flags) {
|
||||
this.worldManager = worldManager;
|
||||
this.blockSafety = blockSafety;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@CommandAlias("mvsetspawn")
|
||||
@Subcommand("setspawn")
|
||||
@CommandPermission("multiverse.core.setspawn")
|
||||
@CommandCompletion("@nothing @mvworlds:scope=loaded ") // TODO: Use Brigadier to show <position> above in chat like the vanilla TP command
|
||||
@Syntax("[location] [world]")
|
||||
@CommandPermission("multiverse.core.spawn.set")
|
||||
@CommandCompletion("@flags:groupName=" + UnsafeFlags.NAME + " @flags:resolveUntil=arg1,groupName=" + UnsafeFlags.NAME)
|
||||
@Syntax("[worldname:x,y,z[,pitch,yaw]] [--unsafe]")
|
||||
@Description("{@@mv-core.setspawn.description}")
|
||||
void onSetSpawnCommand(
|
||||
BukkitCommandIssuer issuer,
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Optional
|
||||
@Flags("resolve=issuerAware")
|
||||
@Syntax("<location>")
|
||||
@Syntax("[worldname:x,y,z[,pitch,yaw]]")
|
||||
@Description("{@@mv-core.setspawn.location.description}")
|
||||
Location location,
|
||||
PlayerLocation playerLocation,
|
||||
|
||||
@Optional
|
||||
@Flags("resolve=issuerAware")
|
||||
@Syntax("<world>")
|
||||
@Description("{@@mv-core.setspawn.world.description}")
|
||||
LoadedMultiverseWorld world
|
||||
) {
|
||||
@Syntax("[--unsafe]")
|
||||
@Description("")
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
Location location = playerLocation.value();
|
||||
|
||||
// TODO: Use a flag to do this, no clue how to edit an inbuilt ACF flag though
|
||||
// Get the Location
|
||||
if (location == null) {
|
||||
if (issuer.isPlayer()) {
|
||||
location = issuer.getPlayer().getLocation();
|
||||
} else {
|
||||
issuer.sendMessage("The console must specify a location");
|
||||
return;
|
||||
}
|
||||
if (!parsedFlags.hasFlag(flags.unsafe) && !blockSafety.canSpawnAtLocationSafely(location)) {
|
||||
issuer.sendMessage(MVCorei18n.SETSPAWN_UNSAFE);
|
||||
return;
|
||||
}
|
||||
|
||||
issuer.sendMessage("Setting spawn in " + world.getName() + " to " + prettyLocation(location));
|
||||
|
||||
world.setSpawnLocation(location);
|
||||
worldManager.getLoadedWorld(location.getWorld())
|
||||
.peek(mvWorld -> mvWorld.setSpawnLocation(location)
|
||||
.flatMap(ignore -> worldManager.saveWorldsConfig())
|
||||
.onSuccess(ignore -> issuer.sendMessage(MVCorei18n.SETSPAWN_SUCCESS,
|
||||
Replace.WORLD.with(mvWorld.getName()),
|
||||
Replace.LOCATION.with(prettyLocation(location))))
|
||||
.onFailure(e -> issuer.sendMessage(MVCorei18n.SETSPAWN_FAILED,
|
||||
Replace.WORLD.with(mvWorld.getName()),
|
||||
Replace.ERROR.with(e))))
|
||||
.onEmpty(() -> issuer.sendMessage(MVCorei18n.SETSPAWN_NOTMVWORLD,
|
||||
Replace.WORLD.with(location.getWorld().getName())));
|
||||
}
|
||||
|
||||
private String prettyLocation(Location location) {
|
||||
return location.getX() + ", " + location.getY() + ", " + location.getZ();
|
||||
return "%.2f, %.2f, %.2f, pitch:%.2f, yaw:%.2f"
|
||||
.formatted(location.getX(), location.getY(), location.getZ(), location.getPitch(), location.getYaw());
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class LegacyAlias extends SetSpawnCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull WorldManager worldManager, @NotNull BlockSafety blockSafety, @NotNull UnsafeFlags flags) {
|
||||
super(worldManager, blockSafety, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvss")
|
||||
void onSetSpawnCommand(MVCommandIssuer issuer, PlayerLocation location, String[] flagArray) {
|
||||
super.onSetSpawnCommand(issuer, location, flagArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 439 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user