mirror of
https://github.com/EssentialsX/Essentials.git
synced 2026-11-05 01:00:13 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2719a189af | ||
|
|
b4a97ab2a9 | ||
|
|
eab220183e | ||
|
|
43d1e37b8f | ||
|
|
80bdc5269f | ||
|
|
90d766df2b | ||
|
|
5bf158c1d4 | ||
|
|
1531cf4146 | ||
|
|
b5748eb32f | ||
|
|
e49021fffe | ||
|
|
ba5257c8e6 | ||
|
|
fe27182ba8 | ||
|
|
5458241fcd | ||
|
|
bad79b79ac | ||
|
|
1ff24cb634 | ||
|
|
f5efa26300 | ||
|
|
263dab54d0 | ||
|
|
e3e247dd61 | ||
|
|
5a839c47bc | ||
|
|
3025ba5c05 | ||
|
|
8313d522dc | ||
|
|
196a2a19c4 | ||
|
|
69ed07a536 | ||
|
|
cb00783ede | ||
|
|
4e6478224c | ||
|
|
fb6edc04c6 | ||
|
|
d232ce4037 | ||
|
|
1a4d75ced7 | ||
|
|
42121aa4be | ||
|
|
ea3ea202a7 | ||
|
|
62fb6a16d4 | ||
|
|
e2295c1e1f | ||
|
|
eb6e192d8d | ||
|
|
b293f2328a | ||
|
|
22de3d8bab | ||
|
|
fe4e388c42 | ||
|
|
803771e74a | ||
|
|
667b0f7523 | ||
|
|
8e53214b50 | ||
|
|
5515f9f3f6 | ||
|
|
f2af9528b0 | ||
|
|
e1091d887d | ||
|
|
424816ef51 | ||
|
|
baa8258936 | ||
|
|
c37064ff74 | ||
|
|
d58db0dce9 | ||
|
|
bc8aa76690 | ||
|
|
d31ff5553e | ||
|
|
b560bbdec4 | ||
|
|
2a41ea050a | ||
|
|
c7cc1b4f93 | ||
|
|
57c9edcc0c | ||
|
|
3f0a412390 | ||
|
|
9590d4cd75 | ||
|
|
f02eeecee8 | ||
|
|
3203e97a5e | ||
|
|
bea43e8798 | ||
|
|
1af1565059 | ||
|
|
38e42f9f90 | ||
|
|
2418a6fb78 | ||
|
|
1778bf5ada | ||
|
|
a87760d3ce | ||
|
|
2ac37d8dd4 | ||
|
|
0b49421bad | ||
|
|
aa2eca17ef | ||
|
|
fe6b04ed84 | ||
|
|
2b209a4a2f | ||
|
|
a4a09299e7 | ||
|
|
4a68758975 | ||
|
|
cb15b467ab | ||
|
|
f7a8f86850 | ||
|
|
cd06e737e1 | ||
|
|
a8452b4615 | ||
|
|
1bede4ae3f | ||
|
|
c80bef9841 | ||
|
|
9c3e0eb312 | ||
|
|
6157668a63 | ||
|
|
04518dbbb3 | ||
|
|
3e29e04722 | ||
|
|
9dfa8cf3cb | ||
|
|
b54c8c1774 | ||
|
|
f1a5caf98e | ||
|
|
7ae01a03ac | ||
|
|
b763fd3868 | ||
|
|
7b02d22ac7 | ||
|
|
8b08a8f2c8 | ||
|
|
80c3150e44 | ||
|
|
33e086ff05 | ||
|
|
8971798a90 | ||
|
|
fcf6e64732 | ||
|
|
9e57dd6aef | ||
|
|
b392f03ad1 | ||
|
|
64531aa862 | ||
|
|
1ea080effa | ||
|
|
6624e6688c | ||
|
|
022b0049b4 | ||
|
|
cecc00a3b6 | ||
|
|
29a122ea5e | ||
|
|
3a6fdd9bf3 | ||
|
|
434e7a0e70 | ||
|
|
e7a4167111 | ||
|
|
aec5859c2a | ||
|
|
5392169f72 | ||
|
|
d4a3f5a9e6 | ||
|
|
bef1e57712 | ||
|
|
4c5a97bf00 | ||
|
|
b9b3e4430e | ||
|
|
84d3138b21 | ||
|
|
1c8060341f | ||
|
|
c58aae78e7 | ||
|
|
cde7184da3 | ||
|
|
549283a1e5 | ||
|
|
6a2527ccdb | ||
|
|
c60ed56190 | ||
|
|
c85e179718 | ||
|
|
71ca7ffbf6 | ||
|
|
76a513a05c | ||
|
|
8cfe680abc | ||
|
|
2cb0af0ca4 | ||
|
|
570eca2e21 | ||
|
|
3817a11d9d | ||
|
|
c19b20ea3b | ||
|
|
a4ac720057 | ||
|
|
993d7ede56 | ||
|
|
622c8147a9 | ||
|
|
6b521e78a6 | ||
|
|
4219450705 | ||
|
|
bd8c792fa4 | ||
|
|
52a638f18f | ||
|
|
1b1b511b61 | ||
|
|
d4b72c8af6 | ||
|
|
185b4e266b | ||
|
|
7a9a0e6f51 | ||
|
|
9be27ad7ac | ||
|
|
09fa6463a7 | ||
|
|
1929d4110a | ||
|
|
4386713807 | ||
|
|
139db29782 | ||
|
|
d307279b3b | ||
|
|
80e6f96c71 | ||
|
|
77d505bb4a | ||
|
|
14125d9c4c | ||
|
|
dfc5c49f56 | ||
|
|
221a6622f3 | ||
|
|
82606a7ced | ||
|
|
1dccfbfcee | ||
|
|
ac0ba8890f | ||
|
|
0cd47639c2 | ||
|
|
63234d6b1d | ||
|
|
8a57856c96 | ||
|
|
3d9d3a3254 | ||
|
|
544f69aec8 | ||
|
|
596ba6e2f5 | ||
|
|
1e040fa7b5 | ||
|
|
51075adec6 | ||
|
|
4134b5fb99 | ||
|
|
d4ecfd2263 | ||
|
|
0d1462a021 | ||
|
|
16e297269d | ||
|
|
3b61b3ed31 | ||
|
|
23093b68d7 | ||
|
|
746627c4b5 | ||
|
|
04c01655f6 | ||
|
|
388d571da9 | ||
|
|
8234dedb22 | ||
|
|
81a8731330 | ||
|
|
fbfd7e9871 | ||
|
|
0af4436c2f | ||
|
|
84e9051f46 | ||
|
|
bb7b334ace | ||
|
|
c68b277782 | ||
|
|
50c4d04b02 | ||
|
|
3eceec87d3 | ||
|
|
fdf1875e7f | ||
|
|
79449ef663 | ||
|
|
b900444ff0 | ||
|
|
a3a71afcef | ||
|
|
72ba87c509 | ||
|
|
ee1111f6aa | ||
|
|
42071f4ad4 | ||
|
|
cf43e643ed | ||
|
|
bb2df0b0a4 | ||
|
|
e3e52db10e | ||
|
|
ad5f17481c | ||
|
|
0a4cf27342 | ||
|
|
dfa22969c9 | ||
|
|
eb76cf0fbb | ||
|
|
409af5d2aa | ||
|
|
6fb500d9fb | ||
|
|
2b993d58cf | ||
|
|
7eed853294 | ||
|
|
6d2a8ffba4 | ||
|
|
b781c1e924 | ||
|
|
19d6db0b4c | ||
|
|
02ced188c8 | ||
|
|
7f3b62a180 | ||
|
|
908b06570f | ||
|
|
d7e5c10b51 | ||
|
|
b2ae28b450 | ||
|
|
e558e7365a | ||
|
|
c32a0f975e | ||
|
|
ae1f1583c2 | ||
|
|
58eea1724f | ||
|
|
52c9ca8197 | ||
|
|
f26e1b2e29 | ||
|
|
f84a311c2b | ||
|
|
60129594a6 | ||
|
|
563d3fab4e | ||
|
|
1022f7a3ab | ||
|
|
d57094c0bc | ||
|
|
863b9cffc5 | ||
|
|
1921abd310 | ||
|
|
803d800bdd | ||
|
|
5276204cf2 | ||
|
|
697128bcf2 | ||
|
|
a1fa1e38f8 | ||
|
|
ed41790712 | ||
|
|
834ef4ea57 | ||
|
|
03ed9a5b41 | ||
|
|
d67dd46cdc | ||
|
|
694ed6e66f | ||
|
|
8a0526b1e5 | ||
|
|
a116e8630d | ||
|
|
8b2c7d7ad1 | ||
|
|
8d07c4bb0f | ||
|
|
fc3dabf8f5 | ||
|
|
cdd277da92 | ||
|
|
0d322e2c6b | ||
|
|
646b60a90b | ||
|
|
357cd6b246 | ||
|
|
a4fb02f3e6 | ||
|
|
2828901927 | ||
|
|
1e0f7cb984 | ||
|
|
52a4dd2c60 | ||
|
|
8323b47e40 | ||
|
|
14cdde009c | ||
|
|
1883e6adbc | ||
|
|
2f9659e7fc | ||
|
|
1a4f63915f | ||
|
|
dd3f4c2921 | ||
|
|
7ebb6359e5 | ||
|
|
069ebfcd5b | ||
|
|
991bc61b0c | ||
|
|
8194d1f747 | ||
|
|
ee7ea2ae39 | ||
|
|
3d23916ad5 | ||
|
|
e5b0c4c855 | ||
|
|
84fd45bd09 | ||
|
|
01883a6b18 | ||
|
|
fd49b70a69 | ||
|
|
3a737480ec | ||
|
|
384f63bf92 | ||
|
|
77dc87bb8e | ||
|
|
c716fc8236 | ||
|
|
c52c1fea9d | ||
|
|
e7c56b32a4 | ||
|
|
11e6d3ca7b | ||
|
|
75481925f7 | ||
|
|
ecb1850451 | ||
|
|
0f4af9e735 | ||
|
|
bf14b88600 | ||
|
|
43d84de2b2 | ||
|
|
25ad8ac9bd | ||
|
|
17051eab73 | ||
|
|
4dc994df3c | ||
|
|
996285c0e3 | ||
|
|
312d1699a8 | ||
|
|
b3238605cc | ||
|
|
b7a4bea52e | ||
|
|
ca71d93963 | ||
|
|
0936fe80bd | ||
|
|
520e8f991f | ||
|
|
3131cadf65 | ||
|
|
bfae6c5c69 | ||
|
|
52c500ee6d | ||
|
|
ba5a8becfc | ||
|
|
2a1957229f | ||
|
|
e6af246170 | ||
|
|
939e5c5a55 | ||
|
|
80bbf8c55b | ||
|
|
376abc4aab | ||
|
|
a7f4d6b16b | ||
|
|
e0d6040662 | ||
|
|
6ec4c97ddd | ||
|
|
db10678095 | ||
|
|
582a357752 | ||
|
|
8a1e7019a7 | ||
|
|
4414eea513 | ||
|
|
6e931b2b3b | ||
|
|
22a0d53cf2 | ||
|
|
20011b9996 | ||
|
|
879e70fb6b | ||
|
|
f91dfed5b4 | ||
|
|
767185ec32 | ||
|
|
4aa93a43db | ||
|
|
57529c4b7d | ||
|
|
dc7fb91939 | ||
|
|
e91ce0c44c | ||
|
|
f7cbc7b0d3 | ||
|
|
28d7abe642 | ||
|
|
0ca58ce4ba | ||
|
|
d75d3cd001 | ||
|
|
1eb5d8a459 | ||
|
|
b808511efe | ||
|
|
0897ef71f2 | ||
|
|
f176893940 | ||
|
|
af18afad7a | ||
|
|
bdc5f4c830 | ||
|
|
0be056b9c2 | ||
|
|
5f5d65c463 | ||
|
|
ca4077b204 | ||
|
|
4ab3e20a0c | ||
|
|
576866540e | ||
|
|
dfcb9a1c52 | ||
|
|
a7a9cbc034 | ||
|
|
2f4f555923 | ||
|
|
1c22edbb1b | ||
|
|
b71fb520aa | ||
|
|
8f7b7d0a5f | ||
|
|
f379323d7a | ||
|
|
f2dde4154c | ||
|
|
12c2a4f2b5 | ||
|
|
ee7c1b1cf1 | ||
|
|
422f25af8b | ||
|
|
728c746200 | ||
|
|
6dfa18ca53 | ||
|
|
a394760677 | ||
|
|
5f48cdef13 | ||
|
|
c56a9e6741 | ||
|
|
5b20f30350 | ||
|
|
037577162b | ||
|
|
908189a233 | ||
|
|
c938767b2d | ||
|
|
b135fcf086 | ||
|
|
09dc49aacb | ||
|
|
f4b6197a49 | ||
|
|
4a53cfe7ac | ||
|
|
2bba577567 | ||
|
|
6e674c73e0 | ||
|
|
a60f3c067f | ||
|
|
6816eb4e18 | ||
|
|
9c5536b2e6 | ||
|
|
ff80338350 | ||
|
|
8d856dd6db | ||
|
|
96c6c951e8 | ||
|
|
0931b21f6d | ||
|
|
9147d1036d | ||
|
|
a7f602e2ad | ||
|
|
0c81980ead | ||
|
|
2d5794f68d | ||
|
|
6b80e0b113 | ||
|
|
18f9af898e | ||
|
|
d04c933abe | ||
|
|
b916488de2 | ||
|
|
c6066bd2d8 | ||
|
|
3af931740b | ||
|
|
1c5a7e9ffb | ||
|
|
ea5cdc097d | ||
|
|
d891268143 | ||
|
|
4bd1b3c09f | ||
|
|
c4f10d9c1d | ||
|
|
e12f1b5022 | ||
|
|
31732cec95 | ||
|
|
f104b6ec15 | ||
|
|
695546420f | ||
|
|
997fb1800e | ||
|
|
3984bddd9d | ||
|
|
d92ce8bdfe | ||
|
|
3348bd9129 | ||
|
|
1a5526867c | ||
|
|
c5253bc5e2 | ||
|
|
29a2a865c5 | ||
|
|
c3b994808f | ||
|
|
bc2da98703 | ||
|
|
cbb012853c | ||
|
|
4bf4bd432a | ||
|
|
83d0e0d9a0 | ||
|
|
2f5c24d114 | ||
|
|
88c8ccd29b | ||
|
|
94edbcfeb1 | ||
|
|
d5822e9a41 | ||
|
|
debf09437e | ||
|
|
a9e5f079a9 | ||
|
|
f00c2dcf92 | ||
|
|
63cbf7e2da | ||
|
|
19837f9309 | ||
|
|
4b8b770c30 | ||
|
|
ddc258ed11 | ||
|
|
d23796dade | ||
|
|
41f5cc3175 | ||
|
|
c6fe160b47 | ||
|
|
5c46bea2ca | ||
|
|
a9585bb525 | ||
|
|
bb88a6a749 | ||
|
|
739600eb05 | ||
|
|
5f98d3fac5 | ||
|
|
84326cf13e | ||
|
|
685084219e | ||
|
|
c4e62ae22b | ||
|
|
05ce11f657 | ||
|
|
bcb0fb5825 | ||
|
|
91f4493fe0 | ||
|
|
d53ff36a2a | ||
|
|
98917d97c8 | ||
|
|
7e1d18fee4 | ||
|
|
0b7e7801d0 | ||
|
|
840035944a | ||
|
|
20a7d1c7ee | ||
|
|
253185bd0e | ||
|
|
dae519494e | ||
|
|
dc27af78bf | ||
|
|
41861a8551 | ||
|
|
9b629e42d8 | ||
|
|
7794634d37 | ||
|
|
d091d6902c | ||
|
|
c45c741210 | ||
|
|
e35c65b976 | ||
|
|
0983167740 | ||
|
|
1509cf8978 | ||
|
|
c0082ee734 | ||
|
|
db2ec1b436 | ||
|
|
7a1e50d10f | ||
|
|
b6ba1768a1 | ||
|
|
c38dd997d2 | ||
|
|
f8ca1bae5d | ||
|
|
3c60bcf2de | ||
|
|
3f857e3183 | ||
|
|
668c9634ca | ||
|
|
51c49b0de6 | ||
|
|
5723dac6ba | ||
|
|
680d3230ea | ||
|
|
8f679de352 | ||
|
|
86d435eee1 | ||
|
|
e4cf965bae | ||
|
|
78c846a0a8 | ||
|
|
c466c9c370 | ||
|
|
6994005a5f | ||
|
|
e43f06bfa6 | ||
|
|
9601687190 | ||
|
|
2ed94f1048 | ||
|
|
70045c30f3 | ||
|
|
ce88c0e1e4 | ||
|
|
494e82e581 | ||
|
|
edd15132fd | ||
|
|
add664441e | ||
|
|
58b0fb089f | ||
|
|
90e4845627 | ||
|
|
43f4d306be | ||
|
|
cb7d9baf7a | ||
|
|
f3aea5e6ec | ||
|
|
a7a1fcd98c | ||
|
|
ef8bcc8bc4 | ||
|
|
b3692d18b0 | ||
|
|
a7b2b675d5 | ||
|
|
7d7a8e47ac | ||
|
|
f0da17b75c | ||
|
|
d86b471402 | ||
|
|
767508fb87 | ||
|
|
c85d772e1b | ||
|
|
fde6524e46 | ||
|
|
b2886969f0 | ||
|
|
19ca5186e4 | ||
|
|
b86a34c909 | ||
|
|
d145fbc5cc | ||
|
|
3ca960e31b | ||
|
|
8bbaf7da68 | ||
|
|
14c2ab5ddd | ||
|
|
6f20a789f9 | ||
|
|
4bee15956a | ||
|
|
e4c179f5ed | ||
|
|
4811eb1558 | ||
|
|
69850d82c8 | ||
|
|
df88a89c14 | ||
|
|
c746a1ce17 | ||
|
|
ecdaed7d11 | ||
|
|
c062651821 | ||
|
|
3692740762 | ||
|
|
1179caab88 | ||
|
|
35b1a284f3 | ||
|
|
36432c65e9 | ||
|
|
871e718f63 | ||
|
|
42293596f3 | ||
|
|
ac8a13f039 | ||
|
|
d56ecaacdc | ||
|
|
14fbfe360e | ||
|
|
5334a3fd34 | ||
|
|
2fa9c6486e | ||
|
|
c221e96122 | ||
|
|
26c016fea2 | ||
|
|
b6a08ec712 | ||
|
|
9179c6c1e2 | ||
|
|
3f9aceb922 | ||
|
|
3da8efae49 | ||
|
|
b84207f955 | ||
|
|
f57de40668 | ||
|
|
e95df57642 | ||
|
|
aaddb2af1f | ||
|
|
082950cc18 | ||
|
|
90828965df | ||
|
|
17e026f9aa | ||
|
|
f1d7e50dc0 | ||
|
|
e2cb7b2102 | ||
|
|
28578a5d8a | ||
|
|
0d8e90b8da | ||
|
|
1556b911b2 | ||
|
|
eed73e3157 | ||
|
|
c020526b1e | ||
|
|
cca98e817f | ||
|
|
46a8a7d04c | ||
|
|
d4ddc87d81 | ||
|
|
b473460ffc | ||
|
|
db027bced3 | ||
|
|
12cc0b99f9 | ||
|
|
15cac529c5 | ||
|
|
feed2d6a45 | ||
|
|
b516db669c | ||
|
|
3bc58264ea | ||
|
|
0a0416ae38 | ||
|
|
d244956b4b | ||
|
|
37e3730e9d | ||
|
|
48532a0ae6 | ||
|
|
0b6b0f9c61 | ||
|
|
435ac80ff9 | ||
|
|
a098055fc9 | ||
|
|
cba5063b33 | ||
|
|
3787b80286 | ||
|
|
2858bd3784 | ||
|
|
ff58d8e443 | ||
|
|
5e178943a0 | ||
|
|
33ca3b2981 | ||
|
|
8c8c85d753 | ||
|
|
6535edf4e0 | ||
|
|
7e25570344 | ||
|
|
409210ccde | ||
|
|
555a62c582 | ||
|
|
36a070be4c | ||
|
|
d903e40a53 | ||
|
|
d78729f343 | ||
|
|
a55289196b | ||
|
|
3505b47d8f | ||
|
|
11836e6662 | ||
|
|
4ce38bde36 | ||
|
|
711f701d62 | ||
|
|
94c509b1e2 | ||
|
|
5c08a0e72c | ||
|
|
9c451271e0 | ||
|
|
55db6c2476 | ||
|
|
0861427bf3 | ||
|
|
9d3bf337e1 | ||
|
|
4e4eb35240 | ||
|
|
e7e3f58c8f | ||
|
|
c18830ce75 | ||
|
|
3f36a52685 | ||
|
|
64eb39a417 | ||
|
|
736ecae5ff | ||
|
|
6bd4a6a037 | ||
|
|
4271938c3a | ||
|
|
e1441c1d33 | ||
|
|
9bd35a2cd2 | ||
|
|
d4e194fbf7 | ||
|
|
003d556f3d | ||
|
|
1da3b3f08e | ||
|
|
f08c176b68 | ||
|
|
780aadedf2 | ||
|
|
3fe279e229 | ||
|
|
c43af5d3d9 | ||
|
|
65b80200bd | ||
|
|
6e5a41a880 | ||
|
|
fa87c74b56 | ||
|
|
8142da608c | ||
|
|
eacc748b09 | ||
|
|
def41802b8 | ||
|
|
38dcdff659 | ||
|
|
bd9540cea3 | ||
|
|
0d71fe65f6 | ||
|
|
54c70581a2 | ||
|
|
3abddd6f84 | ||
|
|
8e712bc827 | ||
|
|
2018149395 | ||
|
|
ecea17195a | ||
|
|
a28d0823b2 | ||
|
|
6e6561a267 | ||
|
|
8b1db22a53 | ||
|
|
3d09ea386b | ||
|
|
300daea4f9 | ||
|
|
7653da0e4f | ||
|
|
19b4da07b9 | ||
|
|
ff9f93fba4 | ||
|
|
fed26071ac | ||
|
|
a4fbfbef02 | ||
|
|
347751a826 | ||
|
|
fbb3a9a0a4 | ||
|
|
f8f1facf43 | ||
|
|
0d6441d0b6 | ||
|
|
a009b2f9b5 | ||
|
|
7852aedabd | ||
|
|
b2d7d1b4cb | ||
|
|
ec50b28f4b | ||
|
|
4ed36d9bbe | ||
|
|
887772a428 | ||
|
|
e9169b890d | ||
|
|
b716c04d96 | ||
|
|
2d3cbc9783 | ||
|
|
23a497abf6 | ||
|
|
d00b90cd61 | ||
|
|
f4fe8808a4 | ||
|
|
02193b0523 | ||
|
|
c9310ea429 | ||
|
|
c76e4239bb | ||
|
|
8a8d45c91e | ||
|
|
071f99560e | ||
|
|
8b23c2c4cd | ||
|
|
0d640d1215 | ||
|
|
b4d63857ce | ||
|
|
4976484d91 | ||
|
|
16627d10b6 | ||
|
|
83ca7d2574 | ||
|
|
956afc0382 | ||
|
|
312ff110ec | ||
|
|
214d07c468 | ||
|
|
2c68d1b866 | ||
|
|
5171215817 | ||
|
|
195148a2a2 | ||
|
|
edf664e19a | ||
|
|
0668e4c48a | ||
|
|
d75787726c | ||
|
|
1e0d7fb0a3 | ||
|
|
454698bf98 | ||
|
|
bfeb0ef2ad | ||
|
|
1cf2b11f1e | ||
|
|
0ce4029483 | ||
|
|
504e82e9fd | ||
|
|
eca6a9f247 | ||
|
|
94d4385d41 | ||
|
|
c41bb0ec42 | ||
|
|
00b71cafc9 | ||
|
|
3cd69dabe9 | ||
|
|
10fa3b5a31 | ||
|
|
b43790e9d2 | ||
|
|
ee5f4b9b42 | ||
|
|
e5db842dd6 | ||
|
|
657a11b1f4 | ||
|
|
0ef1e23c69 | ||
|
|
141512f2f7 | ||
|
|
671983724a | ||
|
|
81571fc014 | ||
|
|
f806409d80 | ||
|
|
f3c347424b | ||
|
|
8cbd9b7935 | ||
|
|
158d273dbe | ||
|
|
1258d2f0a1 | ||
|
|
36422ab22b | ||
|
|
191cea7fb3 | ||
|
|
f8cc0e41d1 | ||
|
|
f29f9e1aba | ||
|
|
34fdcf8f6f | ||
|
|
adef08af3e | ||
|
|
1301e8fc99 | ||
|
|
eee1c0628b | ||
|
|
9ce839c9d8 | ||
|
|
401fc4d2eb | ||
|
|
4e7f1377bf | ||
|
|
fccf796eeb | ||
|
|
500edb7860 | ||
|
|
cb168b0c8a | ||
|
|
74131f816c | ||
|
|
f1ef21eb0d | ||
|
|
79406613c1 | ||
|
|
89c1e3b60d | ||
|
|
224634d8d2 | ||
|
|
e42d37e86d | ||
|
|
191c9e9302 | ||
|
|
a482ddf0f6 | ||
|
|
7245e84f00 | ||
|
|
e287600c34 | ||
|
|
817585a9a6 | ||
|
|
eae8bc05c9 | ||
|
|
026d279556 | ||
|
|
8177893e28 | ||
|
|
70de83827d | ||
|
|
5af9536db1 | ||
|
|
cb7b2dabf5 | ||
|
|
01987a0374 | ||
|
|
5528b5b92c | ||
|
|
1838354b70 | ||
|
|
1f1edd9b23 | ||
|
|
2b7a4364b1 | ||
|
|
2f45d3edf3 | ||
|
|
a20d20574e | ||
|
|
d78832498e | ||
|
|
e2c6170eba | ||
|
|
6864af762c | ||
|
|
a8daa2160f | ||
|
|
b84aaa1dab | ||
|
|
c6de77130f | ||
|
|
02ba924f33 | ||
|
|
318df64e54 | ||
|
|
cb45867de8 | ||
|
|
c4ca0e51e2 | ||
|
|
7bb12fd33c | ||
|
|
001213ee2c | ||
|
|
f320705216 | ||
|
|
d4ed77fdc6 | ||
|
|
ef1202923e | ||
|
|
e1e98f5048 | ||
|
|
5bb3cc88e5 | ||
|
|
43eff69a2f | ||
|
|
450da59057 | ||
|
|
dda4d58a23 | ||
|
|
f5d5ed9844 | ||
|
|
2342d53dba | ||
|
|
005d83c6fe | ||
|
|
8c4fb3fefb | ||
|
|
b0fa0d1ec8 | ||
|
|
2ce5797d5e | ||
|
|
c2617e5a1d | ||
|
|
3f73e31d9e | ||
|
|
84a48adbdd | ||
|
|
63c29a318e | ||
|
|
69748fd72e | ||
|
|
35278c6e90 | ||
|
|
088fc35435 | ||
|
|
4baad6b89c | ||
|
|
9a23f806fe | ||
|
|
82b466db0b |
No files matched your search
@@ -24,7 +24,7 @@
|
||||
|
||||
<!-- https://checkstyle.org/config_filters.html#SuppressionFilter -->
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${checkstyle.suppressions.file}"/>
|
||||
<property name="file" value="${configDirectory}/suppressions.xml"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_filters.html#SuppressWithPlainTextCommentFilter -->
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
<suppressions>
|
||||
<suppress files=".*[\\/]test[\\/]java[\\/].*" checks="RequireExplicitVisibilityModifier"/>
|
||||
<!-- TODO: don't suppress I-prefixed API interfaces under com.earth2me.essentials -->
|
||||
<suppress files="(com[\\/]earth2me[\\/]essentials[\\/]|net[\\/]ess3[\\/])(?:[^\\/]+$|(?!api)[^\\/]+[\\/])" checks="MissingJavadoc(Method|Type)"/>
|
||||
<suppress files="(com[\\/]earth2me[\\/]essentials[\\/]|net[\\/]ess3[\\/]|net[\\/]essentialsx[\\/])(?:[^\\/]+$|(?!api)[^\\/]+[\\/])" checks="MissingJavadoc(Method|Type)"/>
|
||||
</suppressions>
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
# Currently used
|
||||
patreon: EssentialsX
|
||||
ko_fi: essentialsx
|
||||
github: EssentialsX
|
||||
open_collective: EssentialsX
|
||||
|
||||
# Currently not used
|
||||
#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
#open_collective: # Replace with a single Open Collective username
|
||||
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
#liberapay: # Replace with a single Liberapay username
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: MOSS Discord Server
|
||||
- name: View common issues
|
||||
url: https://github.com/EssentialsX/Essentials/issues/3956
|
||||
about: Check the list of known common issues to see if it solves your problem.
|
||||
- name: Check past help requests
|
||||
url: https://github.com/EssentialsX/Essentials/discussions/categories/q-a
|
||||
about: Visit the Q&A forum to search for previous help requests.
|
||||
- name: Check past feature suggestions
|
||||
url: https://github.com/EssentialsX/Essentials/issues?q=is%3Aissue+label%3A%22type%3A+enhancement%22
|
||||
about: Visit the Feature Suggestions forum to view and discuss existing feature suggestions.
|
||||
- name: Create help request
|
||||
url: https://github.com/EssentialsX/Essentials/discussions/new?category=q-a
|
||||
about: Create a support ticket to get help from developers.
|
||||
- name: Get help from the community on Discord
|
||||
url: https://discord.gg/casfFyh
|
||||
about: Need help with using EssentialsX? Join the MOSS Discord server for help.
|
||||
about: Join the MOSS Discord for community-powered EssentialsX support!
|
||||
@@ -1,86 +0,0 @@
|
||||
---
|
||||
name: Help!
|
||||
about: Encountered a problem with EssentialsX? Not sure how to fix it?
|
||||
labels: 'type: question'
|
||||
|
||||
---
|
||||
|
||||
<!-- EssentialsX help request guide
|
||||
|
||||
NOTE: Failure to fill out this template properly may result in your issue being
|
||||
delayed or ignored.
|
||||
|
||||
Don't type between any arrows in the template, as this text will be hidden.
|
||||
This includes this header block and any other explanatory text blocks.
|
||||
|
||||
Want faster support? Come join our Discord server to get help from both
|
||||
developers and community members: https://discord.gg/F7gexAQ
|
||||
|
||||
If you're happy to wait (or you were sent here from Discord), read on:
|
||||
|
||||
1. Check the Common Issues page.
|
||||
Read through the wiki page to see if you've encountered a regular issue:
|
||||
https://essentialsx.net/wiki/Common-Issues.html
|
||||
|
||||
2. Fill out the template.
|
||||
Run the commands in the console. Don't just put "latest" as a version, or
|
||||
we will ignore it. This will help us understand what problem you've
|
||||
encountered and help us find a solution.
|
||||
|
||||
3. When linking logs or config files, do not attach them to the post!
|
||||
Copy and paste any logs into https://gist.github.com/, then paste a
|
||||
link to them in the relevant parts of the template. Do not use Hastebin
|
||||
or Pastebin, as this can cause issues when trying to solve issues in the
|
||||
future.
|
||||
**DO NOT drag logs into this text box!**
|
||||
|
||||
4. If you are encountering a performance issue, please include a link to a
|
||||
Timings and/or profiler report.
|
||||
|
||||
-->
|
||||
|
||||
### Information
|
||||
|
||||
**Full output of `/ess version`:**
|
||||
<!--
|
||||
Run /ess version in the console, then paste the full output of the command
|
||||
between the ```s.
|
||||
-->
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
**Server startup log:**
|
||||
<!--
|
||||
Restart your server and upload `logs/latest.log` to
|
||||
https://gist.github.com/. You may redact sensitive data (such as IP
|
||||
addresses), but you should make it clear what data was removed. Once
|
||||
uploaded, paste the link below this block.
|
||||
-->
|
||||
|
||||
|
||||
**EssentialsX config:**
|
||||
<!--
|
||||
Upload `plugins/Essentials/config.yml` (and other config files if relevant)
|
||||
to https://gist.github.com/ then paste the link below this block.
|
||||
-->
|
||||
|
||||
|
||||
### Help request
|
||||
|
||||
**Problem:**
|
||||
<!-- What problem did you encounter? Type below this line. -->
|
||||
|
||||
**What I have tried:**
|
||||
<!-- What have you tried so far? Type below this line. -->
|
||||
|
||||
**Console stack trace:**
|
||||
<!--
|
||||
If you are reporting an error in the console, paste it between the ```s.
|
||||
-->
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
**Screenshots:**
|
||||
<!-- If relevant, include any screenshots or a video below this line. -->
|
||||
@@ -1,83 +0,0 @@
|
||||
---
|
||||
name: Report a bug
|
||||
about: Report an EssentialsX bug. Only use this if you're 100% sure there's something wrong with EssentialsX - otherwise, try "Help!".
|
||||
labels: 'bug: unconfirmed'
|
||||
|
||||
---
|
||||
|
||||
<!-- EssentialsX bug reporting guide
|
||||
|
||||
NOTE: Failure to fill out this template properly may result in your issue being
|
||||
delayed or ignored.
|
||||
|
||||
Don't type between any arrows in the template, as this text will be hidden.
|
||||
This includes this header block and any other explanatory text blocks.
|
||||
|
||||
If you are reporting a bug, please follow the following steps:
|
||||
|
||||
1. Fill out the template in full.
|
||||
Run the commands in the console. Don't just put "latest" as a version,
|
||||
or we will ignore it.
|
||||
|
||||
2. When linking files, do not attach them to the post!
|
||||
Copy and paste any logs into https://gist.github.com/, then paste a
|
||||
link to them in the relevant parts of the template. Avoid using
|
||||
Hastebin or Pastebin, as this makes providing support more difficult.
|
||||
**DO NOT drag files into this text box!**
|
||||
|
||||
3. If you are reporting a performance issue, please include a link to a
|
||||
Timings and/or profiler report.
|
||||
|
||||
4. If you are reporting a bug with commands or something else in-game,
|
||||
please include screenshots to help us diagnose the problem.
|
||||
|
||||
-->
|
||||
|
||||
### Information
|
||||
|
||||
**Full output of `/ess version`:**
|
||||
<!--
|
||||
Run /ess version in the console, then paste the full output of the command
|
||||
between the ```s.
|
||||
-->
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
**Server startup log:**
|
||||
<!--
|
||||
Restart your server and upload `logs/latest.log` to
|
||||
https://gist.github.com/. You may redact sensitive data (such as IP
|
||||
addresses), but you should make it clear what data was removed. Once
|
||||
uploaded, paste the link below this block.
|
||||
-->
|
||||
|
||||
|
||||
**EssentialsX config:**
|
||||
<!--
|
||||
Upload `plugins/Essentials/config.yml` (and other config files if relevant)
|
||||
to https://gist.github.com/ then paste the link below this block.
|
||||
-->
|
||||
|
||||
|
||||
### Details
|
||||
|
||||
**Description:**
|
||||
<!-- What is the bug? Type a brief summary below this line. -->
|
||||
|
||||
**Steps to reproduce:**
|
||||
<!-- How did you cause it? Describe what you did to cause the bug below. -->
|
||||
|
||||
**Expected behavior:**
|
||||
<!-- What did you expect to happen? Type below this line. -->
|
||||
|
||||
**Console stack trace:**
|
||||
<!--
|
||||
If you are encountering an error in the console, paste it between the ```s.
|
||||
-->
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
**Screenshots:**
|
||||
<!-- If necessary, include screenshots or a video below this line. -->
|
||||
@@ -0,0 +1,83 @@
|
||||
name: Report bug
|
||||
description: Report a bug in EssentialsX.
|
||||
labels: 'bug: unconfirmed'
|
||||
type: Bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to report an EssentialsX bug! Fill out the form below to provide us with info to help fix the bug.
|
||||
Only use this if you're 100% sure you've found a bug and can reproduce it. If you're looking for general help with EssentialsX, try the Q&A forum or MOSS Discord server.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Type of bug
|
||||
description: What type of bug is this? Choose all that apply.
|
||||
multiple: true
|
||||
options:
|
||||
- Performance issue or memory leak
|
||||
- Data loss
|
||||
- Exploit
|
||||
- Compatibility issue
|
||||
- Error in console
|
||||
- Other unexpected behaviour
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: "`/ess dump all` output"
|
||||
description: Run `/ess dump all` in the console, then copy and paste the link from the output of the command into this box. (If this command doesn't work, you should [update EssentialsX](https://essentialsx.net/downloads.html) and try again.)
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Error log (if applicable)
|
||||
description: If you are reporting a console error, upload any relevant log excerpts to either https://paste.gg or https://gist.github.com, save and the paste the link in this box. If you included those files in the same paste as your startup log, paste the same link here.
|
||||
placeholder: "Example: https://paste.gg/p/anonymous/109dd6a10a734a3aa430d5a351ea5210"
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Bug description
|
||||
description: Describe roughly what the bug is here.
|
||||
placeholder: |
|
||||
Example: "When running /nuke after putting everyone into adventure mode, there aren't any explosions..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Provide an example of how to trigger the bug.
|
||||
placeholder: |
|
||||
Example:
|
||||
1. Have at least 3 people online
|
||||
2. Run `/gma *` to put everyone into adventure mode
|
||||
3. Run `/nuke`
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected behaviour
|
||||
description: Explain what you should expect to happen.
|
||||
placeholder: |
|
||||
Example: "Everything should explode!"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Actual behaviour
|
||||
description: Explain what actually happens.
|
||||
placeholder: |
|
||||
Example: "Everything doesn't explode :("
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional Information
|
||||
description: |
|
||||
In this box, you can attach any relevant screenshots, files and links to Timings/spark profiler reports.
|
||||
You can also include a link to a heapdump if necessary, but please make sure you don't include any private player data in the heapdump.
|
||||
If you suspect this issue is related to a prior issue/PR/commit, please mention it here.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
---
|
||||
name: Request a feature
|
||||
about: Suggest a feature you want to see in EssentialsX!
|
||||
labels: 'type: enhancement'
|
||||
|
||||
---
|
||||
|
||||
<!-- EssentialsX feature request guide
|
||||
|
||||
NOTE: Failure to fill out this template properly may result in your issue being
|
||||
delayed or ignored.
|
||||
|
||||
Don't type between any arrows in the template, as this text will be hidden.
|
||||
This includes this header block and any other explanatory text blocks.
|
||||
|
||||
Not sure if your feature fits in EssentialsX? Feel free to ask on our Discord
|
||||
server: https://discord.gg/F7gexAQ
|
||||
|
||||
If you have a feature suggestion for EssentialsX, read the following tips:
|
||||
|
||||
1. Fill out the template.
|
||||
This will help us understand what you're requesting and why you want us
|
||||
to add it.
|
||||
|
||||
2. Keep it simple.
|
||||
Make sure it's easy to understand what you're requesting. A good way is
|
||||
to keep it to one request per GitHub issue, as we can then easily track
|
||||
feature requests.
|
||||
|
||||
3. Check whether it has already been asked or added.
|
||||
You can search the issue tracker to see if your feature has already been
|
||||
requested at https://github.com/EssentialsX/Essentials/issues. You can
|
||||
also check the changelogs to see if the feature was recently added:
|
||||
https://github.com/EssentialsX/Essentials/releases
|
||||
|
||||
4. Ask yourself: "Does this belong in EssentialsX?"
|
||||
There are lots of features that we reject because most servers won't
|
||||
need or use them. If your feature is very specific or already exists in
|
||||
another plugin, it might not be a good fit for EssentialsX.
|
||||
|
||||
-->
|
||||
|
||||
### Feature request
|
||||
|
||||
**Feature description:**
|
||||
<!-- What feature are you suggesting? Type below this line. -->
|
||||
|
||||
**How the feature is useful:**
|
||||
<!--
|
||||
How is the feature useful to players, server owners and/or developers?
|
||||
Type below this block.
|
||||
-->
|
||||
@@ -0,0 +1,41 @@
|
||||
name: Request a feature
|
||||
description: Suggest a feature you want to see in EssentialsX!
|
||||
labels: 'type: enhancement'
|
||||
type: Feature
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
If you have a feature suggestion for EssentialsX, read the following tips:
|
||||
1. Fill out the template.
|
||||
This will help us understand what you're requesting and why you want us
|
||||
to add it.
|
||||
2. Keep it simple.
|
||||
Make sure it's easy to understand what you're requesting. A good way is
|
||||
to keep it to one request per GitHub issue, as we can then easily track
|
||||
feature requests.
|
||||
3. Check whether it has already been asked or added.
|
||||
You can search the issue tracker to see if your feature has already been
|
||||
requested at https://github.com/EssentialsX/Essentials/issues. You can
|
||||
also check the changelogs to see if the feature was recently added:
|
||||
https://github.com/EssentialsX/Essentials/releases
|
||||
4. Ask yourself: "Does this belong in EssentialsX?"
|
||||
There are lots of features that we reject because most servers won't
|
||||
need or use them. If your feature is very specific or already exists in
|
||||
another plugin, it might not be a good fit for EssentialsX.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Feature description
|
||||
description: Explain what you should expect to happen.
|
||||
placeholder: |
|
||||
What feature are you suggesting?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: How the feature is useful
|
||||
description: Explain what actually happens.
|
||||
placeholder: |
|
||||
How is the feature useful to players, server owners and/or developers?
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,24 +1,30 @@
|
||||
---
|
||||
name: Bug fix
|
||||
about: Use this if your PR fixes a bug in EssentialsX.
|
||||
labels: 'type: bugfix'
|
||||
---
|
||||
<!--
|
||||
|
||||
<!-- EssentialsX bug fix submission guide
|
||||
EssentialsX bug fix submission guide
|
||||
====================================
|
||||
|
||||
NOTE: Failure to fill out this template properly may result in your PR being
|
||||
delayed or ignored without warning.
|
||||
|
||||
Don't type between any arrows in the template, as this text will be hidden.
|
||||
This includes this header block and any other explanatory text blocks.
|
||||
NOTE: Don't type between any arrows in the template, as this text will be
|
||||
hidden. This includes this header block and any other explanation text
|
||||
blocks.
|
||||
|
||||
Want to discuss your PR before submitting it? Join the EssentialsX Development
|
||||
server: https://discord.gg/CUN7qVb
|
||||
|
||||
|
||||
EssentialsX is GPL
|
||||
------------------
|
||||
|
||||
By contributing to EssentialsX, you agree to license your code under the
|
||||
GNU General Public License version 3, which can be found at the link below:
|
||||
https://github.com/EssentialsX/Essentials/blob/2.x/LICENSE
|
||||
|
||||
|
||||
Instructions
|
||||
------------
|
||||
|
||||
If you are submitting a bug fix, please follow the following steps:
|
||||
|
||||
1. Fill out the template in full.
|
||||
@@ -34,14 +40,15 @@ If you are submitting a bug fix, please follow the following steps:
|
||||
Copy and paste any logs into https://gist.github.com/, then paste a
|
||||
link to them in the relevant parts of the template. Do not use Hastebin
|
||||
or Pastebin, as this can cause issues with future reviews.
|
||||
**DO NOT drag logs into this text box!**
|
||||
|
||||
DO NOT drag logs directly into this text box, as we cannot read these!
|
||||
|
||||
3. If you are fixing a performance issue, please include a link to a
|
||||
Timings and/or profiler report, both before and after your PR.
|
||||
|
||||
4. If you are fixing a visual bug, such as in commands, please include
|
||||
screenshots so that we can more easily review the proposed fix.
|
||||
(You may drag screenshots directly into this box.)
|
||||
(You can drag screenshots into the bottom of the editor.)
|
||||
|
||||
-->
|
||||
|
||||
@@ -61,17 +68,21 @@ This PR fixes #nnnn.
|
||||
|
||||
|
||||
**Environments tested:**
|
||||
<!--
|
||||
Below this line, put an "x" inside the box for the environments you have
|
||||
tested this bug fix on, and if relevant alter the OS and Java version
|
||||
accordingly. If this feature does not apply to an environment, strike
|
||||
through the environment using ~~strikethrough~~. If you have tested on
|
||||
other environments, add a new line with relevant details.
|
||||
-->
|
||||
|
||||
- [ ] [Latest](https://papermc.io/downloads) Paper Version (any OS, any Java 8+ version)
|
||||
- [ ] CraftBukkit/Spigot/Paper 1.12.2 (any OS, any Java 8+ version)
|
||||
- [ ] CraftBukkit 1.8.8 (any OS, any Java 8+ version)
|
||||
<!-- Type the OS you have used below. -->
|
||||
OS:
|
||||
|
||||
<!-- Type the JDK version (from java -version) you have used below. -->
|
||||
Java version:
|
||||
|
||||
<!--
|
||||
Put an "x" inside the boxes for the server software you have tested this
|
||||
bug fix on. If this feature does not apply to a server, strike through the server software using ~~strikethrough~~. If you have tested on other
|
||||
environments, add a new line with relevant details.
|
||||
-->
|
||||
- [ ] Most recent Paper version (1.XX.Y, git-Paper-BUILD)
|
||||
- [ ] CraftBukkit/Spigot/Paper 1.12.2
|
||||
- [ ] CraftBukkit 1.8.8
|
||||
|
||||
|
||||
**Demonstration:**
|
||||
@@ -80,3 +91,4 @@ This PR fixes #nnnn.
|
||||
necessary. If you have created or used a test case plugin, please link to a
|
||||
download of the plugin, source code and exact version used where possible.
|
||||
-->
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
---
|
||||
name: Feature addition
|
||||
about: Use this if your PR adds a new feature to EssentialsX.
|
||||
labels: 'type: enhancement'
|
||||
---
|
||||
<!--
|
||||
|
||||
<!-- EssentialsX feature submission guide
|
||||
EssentialsX feature submission guide
|
||||
====================================
|
||||
|
||||
NOTE: Failure to fill out this template properly may result in your PR being
|
||||
delayed or ignored without warning.
|
||||
|
||||
Don't type between any arrows in the template, as this text will be hidden.
|
||||
This includes this header block and any other explanatory text blocks.
|
||||
NOTE: Don't type between any arrows in the template, as this text will be
|
||||
hidden. This includes this header block and any other explanation text
|
||||
blocks.
|
||||
|
||||
Want to discuss your PR before submitting it? Join the EssentialsX Development
|
||||
server: https://discord.gg/CUN7qVb
|
||||
|
||||
|
||||
EssentialsX is GPL
|
||||
------------------
|
||||
|
||||
By contributing to EssentialsX, you agree to license your code under the
|
||||
GNU General Public License version 3, which can be found at the link below:
|
||||
https://github.com/EssentialsX/Essentials/blob/2.x/LICENSE
|
||||
|
||||
|
||||
Instructions
|
||||
------------
|
||||
|
||||
If you are submitting a new feature, please follow the following steps:
|
||||
|
||||
1. Fill out the template in full.
|
||||
@@ -57,26 +63,31 @@ This PR closes #nnnn.
|
||||
|
||||
### Details
|
||||
|
||||
**Proposed feature**
|
||||
**Proposed feature:**
|
||||
<!-- Type a description of your proposed feature below this line. -->
|
||||
|
||||
**Environments tested:**
|
||||
<!--
|
||||
Below this block, put an "x" inside the box for the environments you have
|
||||
tested this bug fix on, and if relevant alter the OS and Java version
|
||||
accordingly. If this feature does not apply to an environment, strike
|
||||
through the environment using ~~strikethrough~~. If you have tested on
|
||||
other environments, add a new line with relevant details.
|
||||
-->
|
||||
|
||||
- [ ] [Latest](https://papermc.io/downloads) Paper Version (any OS, any Java 8+ version)
|
||||
- [ ] CraftBukkit/Spigot/Paper 1.12.2 (any OS, any Java 8+ version)
|
||||
- [ ] CraftBukkit 1.8.8 (any OS, any Java 8+ version)
|
||||
**Environments tested:**
|
||||
|
||||
<!-- Type the OS you have used below. -->
|
||||
OS:
|
||||
|
||||
<!-- Type the JDK version (from java -version) you have used below. -->
|
||||
Java version:
|
||||
|
||||
<!--
|
||||
Put an "x" inside the boxes for the server software you have tested this
|
||||
bug fix on. If this feature does not apply to a server, strike through the server software using ~~strikethrough~~. If you have tested on other
|
||||
environments, add a new line with relevant details.
|
||||
-->
|
||||
- [ ] Most recent Paper version (1.XX.Y, git-Paper-BUILD)
|
||||
- [ ] CraftBukkit/Spigot/Paper 1.12.2
|
||||
- [ ] CraftBukkit 1.8.8
|
||||
|
||||
|
||||
**Demonstration:**
|
||||
<!--
|
||||
Below this block, include screenshots/code snippets from before and after
|
||||
as necessary. If you have created or used a test case plugin, please link
|
||||
to a download of the plugin, source code and exact version used where
|
||||
possible.
|
||||
Below this block, include screenshots/log snippets from before and after as
|
||||
necessary. If you have created or used a test case plugin, please link to a
|
||||
download of the plugin, source code and exact version used where possible.
|
||||
-->
|
||||
@@ -0,0 +1,10 @@
|
||||
You need to select a pull request template!
|
||||
|
||||
If you're adding a new feature, copy and paste the following parameter at the end of the URL:
|
||||
?template=new-feature.md
|
||||
|
||||
If you're fixing a bug, copy and paste the following parameter at the end of the URL:
|
||||
?template=bug-fix.md
|
||||
|
||||
For more information about contributing to EssentialsX, see CONTRIBUTING.md:
|
||||
https://github.com/EssentialsX/Essentials/blob/2.x/CONTRIBUTING.md
|
||||
@@ -0,0 +1,97 @@
|
||||
name: Build EssentialsX
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 2.x
|
||||
- dev/*
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and upload
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Git repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v3
|
||||
|
||||
- name: Build with Gradle
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
./gradlew build --stacktrace
|
||||
|
||||
- name: Publish JUnit report
|
||||
uses: mikepenz/action-junit-report@v4
|
||||
if: success() || failure() # Run even if the previous step fails
|
||||
with:
|
||||
report_paths: '**/build/test-results/test*/TEST-*.xml'
|
||||
|
||||
- name: Archive plugin jars on GitHub
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: EssentialsX plugin jars
|
||||
path: jars/
|
||||
|
||||
- name: Deploy to Maven repo
|
||||
if: ${{ success() && github.event_name == 'push' && github.repository == 'EssentialsX/Essentials' && github.ref == 'refs/heads/2.x' }}
|
||||
env:
|
||||
ORG_GRADLE_PROJECT_essxUsername: ${{ secrets.ESSENTIALSX_DEPLOY_USERNAME }}
|
||||
ORG_GRADLE_PROJECT_essxPassword: ${{ secrets.ESSENTIALSX_DEPLOY_PASSWORD }}
|
||||
run: |
|
||||
./gradlew publish
|
||||
|
||||
- name: Prepare Javadocs
|
||||
run: |
|
||||
mv Essentials/build/docs/javadoc/ javadocs/
|
||||
cp -r EssentialsAntiBuild/build/docs/javadoc/ javadocs/EssentialsAntiBuild/
|
||||
cp -r EssentialsChat/build/docs/javadoc/ javadocs/EssentialsChat/
|
||||
cp -r EssentialsDiscord/build/docs/javadoc/ javadocs/EssentialsDiscord/
|
||||
cp -r EssentialsDiscordLink/build/docs/javadoc/ javadocs/EssentialsDiscordLink/
|
||||
cp -r EssentialsGeoIP/build/docs/javadoc/ javadocs/EssentialsGeoIP/
|
||||
cp -r EssentialsProtect/build/docs/javadoc/ javadocs/EssentialsProtect/
|
||||
cp -r EssentialsSpawn/build/docs/javadoc/ javadocs/EssentialsSpawn/
|
||||
cp -r EssentialsXMPP/build/docs/javadoc/ javadocs/EssentialsXMPP/
|
||||
|
||||
- name: Archive Javadocs
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: javadocs
|
||||
path: javadocs/
|
||||
|
||||
publish-jd:
|
||||
name: Publish Javadocs
|
||||
needs: build
|
||||
if: ${{ github.event_name == 'push' && github.repository == 'EssentialsX/Essentials' && github.ref == 'refs/heads/2.x' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Download Javadocs
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: javadocs
|
||||
path: javadocs/
|
||||
|
||||
- name: Deploy Javadocs
|
||||
run: npx netlify-cli deploy --dir=javadocs/ --prod --message="GitHubActionsDeploy"
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_JD_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_JD_2X_SITE_ID }}
|
||||
@@ -0,0 +1,52 @@
|
||||
name: Build Pull Request
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- mc/* # MC version updates
|
||||
- pr/* # PR rebases
|
||||
pull_request:
|
||||
branches:
|
||||
- 2.x
|
||||
- mc/*
|
||||
- dev/*
|
||||
|
||||
permissions:
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and upload
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Git repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v3
|
||||
|
||||
- name: Build with Gradle
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
./gradlew build --stacktrace
|
||||
|
||||
- name: Publish JUnit report
|
||||
uses: mikepenz/action-junit-report@v4
|
||||
if: success() || failure() # Run even if the previous step fails
|
||||
with:
|
||||
report_paths: '**/build/test-results/test*/TEST-*.xml'
|
||||
|
||||
- name: Archive plugin jars on GitHub
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: EssentialsX plugin jars
|
||||
path: jars/
|
||||
@@ -1,38 +0,0 @@
|
||||
name: Build EssentialsX
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 2.x
|
||||
- mc/*
|
||||
pull_request:
|
||||
branches:
|
||||
- 2.x
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Git repo
|
||||
uses: actions/checkout@v1
|
||||
- name: Restore Maven cache
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maven-
|
||||
- name: Set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
- name: Build with Maven
|
||||
run: mvn package verify --file pom.xml
|
||||
- name: Copy artifacts
|
||||
run: mkdir -p ./out/ && cp -t ./out/ **/target/Essentials*.jar
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: Plugin jars
|
||||
path: out/
|
||||
+10
-2
@@ -15,8 +15,16 @@
|
||||
/Essentials/kits.yml
|
||||
/Essentials/userdata/testplayer1.yml
|
||||
/Essentials/usermap.csv
|
||||
/Essentials/usermap.bin
|
||||
/Essentials/uuids.bin
|
||||
|
||||
# Build files
|
||||
target/
|
||||
jars/
|
||||
.gradle/
|
||||
/jars/
|
||||
out/
|
||||
build/
|
||||
target/
|
||||
*.class
|
||||
|
||||
# Run directory
|
||||
/run/
|
||||
Generated
+23
-15
@@ -1,19 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CheckStyle-IDEA">
|
||||
<option name="configuration">
|
||||
<map>
|
||||
<entry key="active-configuration" value="PROJECT_RELATIVE:$PROJECT_DIR$/.checkstyle/checkstyle.xml:EssentialsX" />
|
||||
<entry key="checkstyle-version" value="8.36.2" />
|
||||
<entry key="copy-libs" value="true" />
|
||||
<entry key="location-0" value="BUNDLED:(bundled):Sun Checks" />
|
||||
<entry key="location-1" value="BUNDLED:(bundled):Google Checks" />
|
||||
<entry key="location-2" value="PROJECT_RELATIVE:$PROJECT_DIR$/.checkstyle/checkstyle.xml:EssentialsX" />
|
||||
<entry key="property-2.checkstyle.suppressions.file" value=".checkstyle/suppressions.xml" />
|
||||
<entry key="scan-before-checkin" value="false" />
|
||||
<entry key="scanscope" value="JavaOnly" />
|
||||
<entry key="suppress-errors" value="false" />
|
||||
</map>
|
||||
<component name="CheckStyle-IDEA" serialisationVersion="2">
|
||||
<checkstyleVersion>8.36.2</checkstyleVersion>
|
||||
<scanScope>JavaOnly</scanScope>
|
||||
<copyLibs>true</copyLibs>
|
||||
<scanBeforeCheckin>true</scanBeforeCheckin>
|
||||
<option name="thirdPartyClasspath" />
|
||||
<option name="activeLocationIds">
|
||||
<option value="321e5753-4201-4d2c-bf31-6232011122fd" />
|
||||
</option>
|
||||
<option name="locations">
|
||||
<list>
|
||||
<ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">(bundled)</ConfigurationLocation>
|
||||
<ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">(bundled)</ConfigurationLocation>
|
||||
<ConfigurationLocation id="321e5753-4201-4d2c-bf31-6232011122fd" type="PROJECT_RELATIVE" scope="All" description="EssentialsX">
|
||||
$PROJECT_DIR$/.checkstyle/checkstyle.xml
|
||||
<option name="properties">
|
||||
<map>
|
||||
<entry key="configDirectory" value=".checkstyle/" />
|
||||
</map>
|
||||
</option>
|
||||
</ConfigurationLocation>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
||||
+93
-22
@@ -1,31 +1,102 @@
|
||||
Contributing to EssentialsX
|
||||
===========================
|
||||
# Contributing to EssentialsX
|
||||
|
||||
Want to help improve EssentialsX? There are several ways you can support and contribute to the project.
|
||||
*By contributing to EssentialsX, you agree to license your changes under the [GNU General Public License version 3](https://github.com/EssentialsX/Essentials/blob/2.x/LICENSE).*
|
||||
|
||||
If you'd like to make a financial contribution to the project, you can join our [Patreon](https://www.patreon.com/essentialsx/),
|
||||
or to make a one-off donation you can visit our [Ko-fi page](https://ko-fi.com/essentialsx). If you can't make a
|
||||
donation, don't worry! There are lots of other ways to contribute:
|
||||
## Submitting code changes to EssentialsX
|
||||
|
||||
* Do you run a server? Take a look at our ["help wanted"](https://github.com/EssentialsX/Essentials/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22help+wanted%22)
|
||||
and ["bug: unconfirmed"](https://github.com/EssentialsX/Essentials/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22bug%3A+unconfirmed%22)
|
||||
issues, where you can find issues that need extra testing and investigation.
|
||||
* Do you speak multiple languages? If so, we always welcome contributions to our [Crowdin project](https://crowdin.com/project/essentialsx-official).
|
||||
* Do you enjoy helping others? If so, why not contribute to the [EssentialsX documentation](https://github.com/EssentialsX/wiki)?
|
||||
You can also join the [MOSS Discord community](https://discord.gg/casfFyh) and provide direct community support to
|
||||
other EssentialsX users.
|
||||
* If you're a developer, you could look through our ["open to PR"](https://github.com/EssentialsX/Essentials/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22status%3A+open+to+PR%22)
|
||||
issues. We're always happy to receive bug fixes and feature additions as pull requests.
|
||||
If you're interested in submitting new code to EssentialsX, we accept changes via GitHub pull requests.
|
||||
|
||||
Submitting a PR
|
||||
---------------
|
||||
### Adding features
|
||||
|
||||
EssentialsX has extensive templates for PRs that detail how to submit your PR. To find out more, see the PR templates for:
|
||||
* [Bug fixes](https://github.com/EssentialsX/Essentials/blob/2.x/.github/PULL_REQUEST_TEMPLATE/bug-fix.md)
|
||||
* [New features](https://github.com/EssentialsX/Essentials/blob/2.x/.github/PULL_REQUEST_TEMPLATE/new-feature.md)
|
||||
In general, we will only consider PRs for features if they have already been discussed with the team through
|
||||
GitHub issues and discussions. Check the list of
|
||||
["open to PR" issues](https://github.com/EssentialsX/Essentials/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22status%3A+open+to+PR%22)
|
||||
and [feature request discussions](https://github.com/EssentialsX/Essentials/discussions/categories/ideas-and-feature-suggestions)
|
||||
before you start working on your changes. If you don't see your desired feature listed,
|
||||
[open a feature request](https://github.com/EssentialsX/Essentials/issues/new/choose) and wait for a response, otherwise
|
||||
you may end up wasting your time on a feature that we aren't in a position to accept.
|
||||
|
||||
Want to discuss a feature before opening a PR? Join the [EssentialsX Development Discord server](https://discord.gg/CUN7qVb). Note that this server is **not for end-users** - if you need support with EssentialsX, you should join [MOSS](https://discord.gg/casfFyh) instead.
|
||||
#### Keep it focused
|
||||
|
||||
By contributing to EssentialsX, you agree to license your code under the [GNU General Public License version 3](https://github.com/EssentialsX/Essentials/blob/2.x/LICENSE).
|
||||
Please try to keep feature PRs focused around one feature. Your PR should ideally contain
|
||||
one feature, or a few closely-linked features. If you submit several unrelated features
|
||||
in one PR, the PR will not be accepted.
|
||||
|
||||
### Fixing bugs
|
||||
|
||||
If you're opening a PR to fix a bug, please ensure a bug report has been filed - search the
|
||||
[issue tracker](https://github.com/EssentialsX/Essentials/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22bug%3A+confirmed%22%2C%22bug%3A+unconfirmed%22%2C%22bug%3A+upstream%22)
|
||||
for an existing report, and if you can't find a bug report,
|
||||
[create one](https://github.com/EssentialsX/Essentials/issues/new/choose) before you submit your PR.
|
||||
|
||||
#### Unconfirmed bugs
|
||||
|
||||
You may find a bug report with the label `bug: unconfirmed`. This means the EssentialsX team hasn't had the time
|
||||
to review the bug report yet or hasn't been able to confirm
|
||||
whether the reported issue is actually a bug in EssentialsX. You can help us by following the steps in the report and
|
||||
posting whether you are able to replicate this issue, ideally on the latest versions of EssentialsX and Paper. This will
|
||||
help us confirm issues and prioritise PRs accordingly.
|
||||
|
||||
#### Upstream bugs
|
||||
|
||||
You may also find bug reports with the `bug: upstream` label. This label means the issue is caused by a bug in *another
|
||||
project*, not EssentialsX. This includes bugs in CraftBukkit/Spigot and bugs in other plugins. It may be appropriate to
|
||||
mitigate an issue in EssentialsX, but please check with us in the [EssentialsX Development Discord server](https://discord.gg/CUN7qVb) before you submit a PR.
|
||||
|
||||
### Making your changes
|
||||
|
||||
You'll need the following to make your changes to EssentialsX:
|
||||
|
||||
* A GitHub account
|
||||
* [`git`](https://git-scm.com/downloads): the Git command-line tool, used to track and save your changes
|
||||
* [`gh`](https://cli.github.com/): the GitHub command-line tool, used to submit your changes to EssentialsX
|
||||
* Your IDE of choice - we recommend [IntelliJ IDEA Community Edition](https://www.jetbrains.com/idea/download)
|
||||
|
||||
If you're already familiar with Git, you can skip this next section.
|
||||
|
||||
You'll need to clone the EssentialsX repository
|
||||
(`gh repo clone EssentialsX/Essentials`), then create a new branch for your work
|
||||
(`cd Essentials` then `git switch -c my-cool-pr`).
|
||||
|
||||
You can then make changes using your IDE of choice. Follow the instructions in `README.md` to build and test your
|
||||
changes.
|
||||
|
||||
Once you've finished, you should commit your changes (`git commit -am "My cool commit name!"`).
|
||||
|
||||
### Submitting your PR
|
||||
|
||||
*Even if you're already familiar with GitHub, you will need to follow these steps in order to submit a PR to
|
||||
EssentialsX. This ensures we have the information we need to test and review your changes.*
|
||||
|
||||
Next, you'll need to fork EssentialsX on GitHub and push your changes to a branch on that fork. We strongly recommend
|
||||
using the `gh` command-line tool for this:
|
||||
|
||||
* In your terminal, run `gh pr create`.
|
||||
* Select either the bug fix or feature template, depending on what your PR is for.
|
||||
* If you get asked `Where should we push the '...' branch?`, select `Create a fork of EssentialsX/Essentials`.
|
||||
* For the title, choose a title that describes what your PR does. For example, `Add more ducks to /spawnmob`.
|
||||
* For the body, press E. You will then need to fill in the PR template in your text editor.
|
||||
- Follow the instructions in the template and fill out the sections as required.
|
||||
- This step is important! Without it, we won't know why you've made your changes or how to test them.
|
||||
* Save the file in your text editor and close it, then return to the terminal.
|
||||
* Select `Submit` to open your PR.
|
||||
|
||||
If you follow these steps correctly, GitHub will create a fork (if necessary) and then open a PR with your changes. You
|
||||
can now sit back while we review your changes. If we need to ask questions or request further changes to your code,
|
||||
we will review your PR and post a comment on GitHub. You can respond to our reviews and comments on the GitHub website,
|
||||
and you can push new changes using `git commit` and `git push`.
|
||||
|
||||
|
||||
## Submitting community translations to EssentialsX
|
||||
|
||||
EssentialsX relies on community translations for its messages in other languages. You can help translate EssentialsX on
|
||||
[Crowdin](https://translate.essentialsx.net/). You'll need a Crowdin account to translate and improve messages.
|
||||
|
||||
If your language isn't listed or doesn't have an active proofreader, please let us know on Discord (see below).
|
||||
|
||||
|
||||
## Discussing EssentialsX contributions
|
||||
|
||||
Want to discuss something before opening a PR or translating messages? Join the
|
||||
[EssentialsX Development Discord server](https://discord.gg/CUN7qVb). Note that this server is **not for end-users** -
|
||||
if you need support with EssentialsX, you should join [MOSS](https://discord.gg/casfFyh) instead.
|
||||
@@ -0,0 +1,87 @@
|
||||
plugins {
|
||||
id("essentials.shadow-module")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly('com.github.milkbowl:VaultAPI:1.7') {
|
||||
exclude group: "org.bukkit", module: "bukkit"
|
||||
}
|
||||
compileOnly 'net.luckperms:api:5.3'
|
||||
|
||||
api 'io.papermc:paperlib:1.0.6'
|
||||
|
||||
implementation 'org.spongepowered:configurate-yaml:4.2.0'
|
||||
implementation 'org.checkerframework:checker-qual:3.49.0'
|
||||
implementation 'nu.studer:java-ordered-properties:1.0.4'
|
||||
|
||||
implementation 'net.kyori:adventure-api:4.19.0'
|
||||
implementation 'net.kyori:adventure-text-minimessage:4.19.0'
|
||||
implementation 'net.kyori:adventure-platform-bukkit:4.3.4'
|
||||
|
||||
// Providers
|
||||
api project(':providers:BaseProviders')
|
||||
api project(path: ':providers:PaperProvider', configuration: 'shadow')
|
||||
api(project(':providers:NMSReflectionProvider')) {
|
||||
exclude group: "org.bukkit", module: "bukkit"
|
||||
}
|
||||
api(project(':providers:1_8Provider')) {
|
||||
exclude group: "org.spigotmc", module: "spigot"
|
||||
}
|
||||
api(project(':providers:1_12Provider')) {
|
||||
exclude group: "org.bukkit", module: "bukkit"
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
testLogging.showStandardStreams = true
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
dependencies {
|
||||
include (dependency('io.papermc:paperlib'))
|
||||
include (dependency('org.bstats:bstats-bukkit'))
|
||||
include (dependency('org.bstats:bstats-base'))
|
||||
include (dependency('org.spongepowered:configurate-yaml'))
|
||||
include (dependency('org.spongepowered:configurate-core'))
|
||||
include (dependency('org.yaml:snakeyaml'))
|
||||
include (dependency('io.leangen.geantyref:geantyref'))
|
||||
include (dependency('org.checkerframework:checker-qual'))
|
||||
include (dependency('nu.studer:java-ordered-properties'))
|
||||
include (dependency('net.kyori:adventure-api'))
|
||||
include (dependency('net.kyori:adventure-key'))
|
||||
include (dependency('net.kyori:examination-api'))
|
||||
include (dependency('net.kyori:examination-string'))
|
||||
include (dependency('net.kyori:option'))
|
||||
include (dependency('net.kyori:adventure-platform-bukkit'))
|
||||
include (dependency('net.kyori:adventure-platform-api'))
|
||||
include (dependency('net.kyori:adventure-platform-facet'))
|
||||
include (dependency('net.kyori:adventure-nbt'))
|
||||
include (dependency('net.kyori:adventure-text-serializer-bungeecord'))
|
||||
include (dependency('net.kyori:adventure-text-serializer-gson'))
|
||||
include (dependency('net.kyori:adventure-text-serializer-gson-legacy-impl'))
|
||||
include (dependency('net.kyori:adventure-text-serializer-json'))
|
||||
include (dependency('net.kyori:adventure-text-serializer-json-legacy-impl'))
|
||||
include (dependency('net.kyori:adventure-text-serializer-legacy'))
|
||||
include (dependency('net.kyori:adventure-text-minimessage'))
|
||||
include (project(':providers:BaseProviders'))
|
||||
include (project(path: ':providers:PaperProvider', configuration: 'shadow'))
|
||||
include (project(':providers:NMSReflectionProvider'))
|
||||
include (project(':providers:1_8Provider'))
|
||||
include (project(':providers:1_12Provider'))
|
||||
}
|
||||
relocate 'io.papermc.lib', 'com.earth2me.essentials.paperlib'
|
||||
relocate 'org.bstats', 'com.earth2me.essentials.libs.bstats'
|
||||
relocate 'org.spongepowered.configurate', 'com.earth2me.essentials.libs.configurate'
|
||||
relocate 'org.yaml.snakeyaml', 'com.earth2me.essentials.libs.snakeyaml'
|
||||
relocate 'io.leangen.geantyref', 'com.earth2me.essentials.libs.geantyref'
|
||||
relocate 'org.checkerframework', 'com.earth2me.essentials.libs.checkerframework'
|
||||
relocate 'net.kyori', 'com.earth2me.essentials.libs.kyori'
|
||||
relocate 'net.essentialsx.temp.adventure', 'net.kyori.adventure'
|
||||
|
||||
minimize {
|
||||
include(dependency('org.checkerframework:checker-qual'))
|
||||
include(dependency('net.kyori:adventure-api'))
|
||||
include(dependency('net.kyori:adventure-platform-bukkit'))
|
||||
include(dependency('net.kyori:adventure-text-minimessage'))
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>EssentialsXParent</artifactId>
|
||||
<version>2.18.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>EssentialsX</artifactId>
|
||||
|
||||
<build>
|
||||
<finalName>EssentialsX-${full.version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<configuration>
|
||||
<showDeprecation>false</showDeprecation>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>io.papermc.lib</pattern>
|
||||
<shadedPattern>com.earth2me.essentials.paperlib</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.milkbowl</groupId>
|
||||
<artifactId>VaultAPI</artifactId>
|
||||
<version>1.7</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.luckperms</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>5.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.papermc</groupId>
|
||||
<artifactId>paperlib</artifactId>
|
||||
<version>1.0.6-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>BaseProviders</artifactId>
|
||||
<version>2.18.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>NMSReflectionProvider</artifactId>
|
||||
<version>2.18.2</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>PaperProvider</artifactId>
|
||||
<version>2.18.2</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.destroystokyo.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>1_8Provider</artifactId>
|
||||
<version>2.18.2</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,108 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.command.PluginCommandYamlParser;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class AlternativeCommandsHandler {
|
||||
private static final Logger LOGGER = Logger.getLogger("Essentials");
|
||||
private final transient Map<String, List<PluginCommand>> altcommands = new HashMap<>();
|
||||
private final transient Map<String, String> disabledList = new HashMap<>();
|
||||
private final transient IEssentials ess;
|
||||
|
||||
public AlternativeCommandsHandler(final IEssentials ess) {
|
||||
this.ess = ess;
|
||||
for (final Plugin plugin : ess.getServer().getPluginManager().getPlugins()) {
|
||||
if (plugin.isEnabled()) {
|
||||
addPlugin(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void addPlugin(final Plugin plugin) {
|
||||
if (plugin.getDescription().getMain().contains("com.earth2me.essentials")) {
|
||||
return;
|
||||
}
|
||||
final List<Command> commands = PluginCommandYamlParser.parse(plugin);
|
||||
final String pluginName = plugin.getDescription().getName().toLowerCase(Locale.ENGLISH);
|
||||
|
||||
for (final Command command : commands) {
|
||||
final PluginCommand pc = (PluginCommand) command;
|
||||
final List<String> labels = new ArrayList<>(pc.getAliases());
|
||||
labels.add(pc.getName());
|
||||
|
||||
PluginCommand reg = ess.getServer().getPluginCommand(pluginName + ":" + pc.getName().toLowerCase(Locale.ENGLISH));
|
||||
if (reg == null) {
|
||||
reg = ess.getServer().getPluginCommand(pc.getName().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
if (reg == null || !reg.getPlugin().equals(plugin)) {
|
||||
continue;
|
||||
}
|
||||
for (final String label : labels) {
|
||||
final List<PluginCommand> plugincommands = altcommands.computeIfAbsent(label.toLowerCase(Locale.ENGLISH), k -> new ArrayList<>());
|
||||
boolean found = false;
|
||||
for (final PluginCommand pc2 : plugincommands) {
|
||||
if (pc2.getPlugin().equals(plugin)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
plugincommands.add(reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removePlugin(final Plugin plugin) {
|
||||
final Iterator<Map.Entry<String, List<PluginCommand>>> iterator = altcommands.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final Map.Entry<String, List<PluginCommand>> entry = iterator.next();
|
||||
entry.getValue().removeIf(pc -> pc.getPlugin() == null || pc.getPlugin().equals(plugin));
|
||||
if (entry.getValue().isEmpty()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PluginCommand getAlternative(final String label) {
|
||||
final List<PluginCommand> commands = altcommands.get(label);
|
||||
if (commands == null || commands.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (commands.size() == 1) {
|
||||
return commands.get(0);
|
||||
}
|
||||
// return the first command that is not an alias
|
||||
for (final PluginCommand command : commands) {
|
||||
if (command.getName().equalsIgnoreCase(label)) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
// return the first alias
|
||||
return commands.get(0);
|
||||
}
|
||||
|
||||
public void executed(final String label, final PluginCommand pc) {
|
||||
final String altString = pc.getPlugin().getName() + ":" + pc.getLabel();
|
||||
if (ess.getSettings().isDebug()) {
|
||||
LOGGER.log(Level.INFO, "Essentials: Alternative command " + label + " found, using " + altString);
|
||||
}
|
||||
disabledList.put(label, altString);
|
||||
}
|
||||
|
||||
public Map<String, String> disabledCommands() {
|
||||
return disabledList;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
public class ChargeException extends Exception {
|
||||
public ChargeException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ChargeException(final String message, final Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class CommandSource {
|
||||
protected CommandSender sender;
|
||||
|
||||
public CommandSource(final CommandSender base) {
|
||||
this.sender = base;
|
||||
}
|
||||
|
||||
public final CommandSender getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public final Player getPlayer() {
|
||||
if (sender instanceof Player) {
|
||||
return (Player) sender;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public final net.ess3.api.IUser getUser(final IEssentials ess) {
|
||||
if (sender instanceof Player) {
|
||||
return ess.getUser((Player) sender);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public final boolean isPlayer() {
|
||||
return sender instanceof Player;
|
||||
}
|
||||
|
||||
public final CommandSender setSender(final CommandSender base) {
|
||||
return this.sender = base;
|
||||
}
|
||||
|
||||
public void sendMessage(final String message) {
|
||||
if (!message.isEmpty()) {
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAuthorized(final String permission, final IEssentials ess) {
|
||||
return !(sender instanceof Player) || getUser(ess).isAuthorized(permission);
|
||||
}
|
||||
|
||||
public String getSelfSelector() {
|
||||
return sender instanceof Player ? getPlayer().getName() : "*";
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return sender instanceof Player ? getPlayer().getDisplayName() : getSender().getName();
|
||||
}
|
||||
}
|
||||
@@ -1,304 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
public final class Enchantments {
|
||||
private static final Map<String, Enchantment> ENCHANTMENTS = new HashMap<>();
|
||||
private static final Map<String, Enchantment> ALIASENCHANTMENTS = new HashMap<>();
|
||||
private static boolean isFlat;
|
||||
|
||||
static {
|
||||
ENCHANTMENTS.put("alldamage", Enchantment.DAMAGE_ALL);
|
||||
ALIASENCHANTMENTS.put("alldmg", Enchantment.DAMAGE_ALL);
|
||||
ENCHANTMENTS.put("sharpness", Enchantment.DAMAGE_ALL);
|
||||
ALIASENCHANTMENTS.put("sharp", Enchantment.DAMAGE_ALL);
|
||||
ALIASENCHANTMENTS.put("dal", Enchantment.DAMAGE_ALL);
|
||||
|
||||
ENCHANTMENTS.put("ardmg", Enchantment.DAMAGE_ARTHROPODS);
|
||||
ENCHANTMENTS.put("baneofarthropods", Enchantment.DAMAGE_ARTHROPODS);
|
||||
ALIASENCHANTMENTS.put("baneofarthropod", Enchantment.DAMAGE_ARTHROPODS);
|
||||
ALIASENCHANTMENTS.put("arthropod", Enchantment.DAMAGE_ARTHROPODS);
|
||||
ALIASENCHANTMENTS.put("dar", Enchantment.DAMAGE_ARTHROPODS);
|
||||
|
||||
ENCHANTMENTS.put("undeaddamage", Enchantment.DAMAGE_UNDEAD);
|
||||
ENCHANTMENTS.put("smite", Enchantment.DAMAGE_UNDEAD);
|
||||
ALIASENCHANTMENTS.put("du", Enchantment.DAMAGE_UNDEAD);
|
||||
|
||||
ENCHANTMENTS.put("digspeed", Enchantment.DIG_SPEED);
|
||||
ENCHANTMENTS.put("efficiency", Enchantment.DIG_SPEED);
|
||||
ALIASENCHANTMENTS.put("minespeed", Enchantment.DIG_SPEED);
|
||||
ALIASENCHANTMENTS.put("cutspeed", Enchantment.DIG_SPEED);
|
||||
ALIASENCHANTMENTS.put("ds", Enchantment.DIG_SPEED);
|
||||
ALIASENCHANTMENTS.put("eff", Enchantment.DIG_SPEED);
|
||||
|
||||
ENCHANTMENTS.put("durability", Enchantment.DURABILITY);
|
||||
ALIASENCHANTMENTS.put("dura", Enchantment.DURABILITY);
|
||||
ENCHANTMENTS.put("unbreaking", Enchantment.DURABILITY);
|
||||
ALIASENCHANTMENTS.put("d", Enchantment.DURABILITY);
|
||||
|
||||
ENCHANTMENTS.put("thorns", Enchantment.THORNS);
|
||||
ENCHANTMENTS.put("highcrit", Enchantment.THORNS);
|
||||
ALIASENCHANTMENTS.put("thorn", Enchantment.THORNS);
|
||||
ALIASENCHANTMENTS.put("highercrit", Enchantment.THORNS);
|
||||
ALIASENCHANTMENTS.put("t", Enchantment.THORNS);
|
||||
|
||||
ENCHANTMENTS.put("fireaspect", Enchantment.FIRE_ASPECT);
|
||||
ENCHANTMENTS.put("fire", Enchantment.FIRE_ASPECT);
|
||||
ALIASENCHANTMENTS.put("meleefire", Enchantment.FIRE_ASPECT);
|
||||
ALIASENCHANTMENTS.put("meleeflame", Enchantment.FIRE_ASPECT);
|
||||
ALIASENCHANTMENTS.put("fa", Enchantment.FIRE_ASPECT);
|
||||
|
||||
ENCHANTMENTS.put("knockback", Enchantment.KNOCKBACK);
|
||||
ALIASENCHANTMENTS.put("kback", Enchantment.KNOCKBACK);
|
||||
ALIASENCHANTMENTS.put("kb", Enchantment.KNOCKBACK);
|
||||
ALIASENCHANTMENTS.put("k", Enchantment.KNOCKBACK);
|
||||
|
||||
ALIASENCHANTMENTS.put("blockslootbonus", Enchantment.LOOT_BONUS_BLOCKS);
|
||||
ENCHANTMENTS.put("fortune", Enchantment.LOOT_BONUS_BLOCKS);
|
||||
ALIASENCHANTMENTS.put("fort", Enchantment.LOOT_BONUS_BLOCKS);
|
||||
ALIASENCHANTMENTS.put("lbb", Enchantment.LOOT_BONUS_BLOCKS);
|
||||
|
||||
ALIASENCHANTMENTS.put("mobslootbonus", Enchantment.LOOT_BONUS_MOBS);
|
||||
ENCHANTMENTS.put("mobloot", Enchantment.LOOT_BONUS_MOBS);
|
||||
ENCHANTMENTS.put("looting", Enchantment.LOOT_BONUS_MOBS);
|
||||
ALIASENCHANTMENTS.put("lbm", Enchantment.LOOT_BONUS_MOBS);
|
||||
|
||||
ALIASENCHANTMENTS.put("oxygen", Enchantment.OXYGEN);
|
||||
ENCHANTMENTS.put("respiration", Enchantment.OXYGEN);
|
||||
ALIASENCHANTMENTS.put("breathing", Enchantment.OXYGEN);
|
||||
ENCHANTMENTS.put("breath", Enchantment.OXYGEN);
|
||||
ALIASENCHANTMENTS.put("o", Enchantment.OXYGEN);
|
||||
|
||||
ENCHANTMENTS.put("protection", Enchantment.PROTECTION_ENVIRONMENTAL);
|
||||
ALIASENCHANTMENTS.put("prot", Enchantment.PROTECTION_ENVIRONMENTAL);
|
||||
ENCHANTMENTS.put("protect", Enchantment.PROTECTION_ENVIRONMENTAL);
|
||||
ALIASENCHANTMENTS.put("p", Enchantment.PROTECTION_ENVIRONMENTAL);
|
||||
|
||||
ALIASENCHANTMENTS.put("explosionsprotection", Enchantment.PROTECTION_EXPLOSIONS);
|
||||
ALIASENCHANTMENTS.put("explosionprotection", Enchantment.PROTECTION_EXPLOSIONS);
|
||||
ALIASENCHANTMENTS.put("expprot", Enchantment.PROTECTION_EXPLOSIONS);
|
||||
ALIASENCHANTMENTS.put("blastprotection", Enchantment.PROTECTION_EXPLOSIONS);
|
||||
ALIASENCHANTMENTS.put("bprotection", Enchantment.PROTECTION_EXPLOSIONS);
|
||||
ALIASENCHANTMENTS.put("bprotect", Enchantment.PROTECTION_EXPLOSIONS);
|
||||
ENCHANTMENTS.put("blastprotect", Enchantment.PROTECTION_EXPLOSIONS);
|
||||
ALIASENCHANTMENTS.put("pe", Enchantment.PROTECTION_EXPLOSIONS);
|
||||
|
||||
ALIASENCHANTMENTS.put("fallprotection", Enchantment.PROTECTION_FALL);
|
||||
ENCHANTMENTS.put("fallprot", Enchantment.PROTECTION_FALL);
|
||||
ENCHANTMENTS.put("featherfall", Enchantment.PROTECTION_FALL);
|
||||
ALIASENCHANTMENTS.put("featherfalling", Enchantment.PROTECTION_FALL);
|
||||
ALIASENCHANTMENTS.put("pfa", Enchantment.PROTECTION_FALL);
|
||||
|
||||
ALIASENCHANTMENTS.put("fireprotection", Enchantment.PROTECTION_FIRE);
|
||||
ALIASENCHANTMENTS.put("flameprotection", Enchantment.PROTECTION_FIRE);
|
||||
ENCHANTMENTS.put("fireprotect", Enchantment.PROTECTION_FIRE);
|
||||
ALIASENCHANTMENTS.put("flameprotect", Enchantment.PROTECTION_FIRE);
|
||||
ENCHANTMENTS.put("fireprot", Enchantment.PROTECTION_FIRE);
|
||||
ALIASENCHANTMENTS.put("flameprot", Enchantment.PROTECTION_FIRE);
|
||||
ALIASENCHANTMENTS.put("pf", Enchantment.PROTECTION_FIRE);
|
||||
|
||||
ENCHANTMENTS.put("projectileprotection", Enchantment.PROTECTION_PROJECTILE);
|
||||
ENCHANTMENTS.put("projprot", Enchantment.PROTECTION_PROJECTILE);
|
||||
ALIASENCHANTMENTS.put("pp", Enchantment.PROTECTION_PROJECTILE);
|
||||
|
||||
ENCHANTMENTS.put("silktouch", Enchantment.SILK_TOUCH);
|
||||
ALIASENCHANTMENTS.put("softtouch", Enchantment.SILK_TOUCH);
|
||||
ALIASENCHANTMENTS.put("st", Enchantment.SILK_TOUCH);
|
||||
|
||||
ENCHANTMENTS.put("waterworker", Enchantment.WATER_WORKER);
|
||||
ENCHANTMENTS.put("aquaaffinity", Enchantment.WATER_WORKER);
|
||||
ALIASENCHANTMENTS.put("watermine", Enchantment.WATER_WORKER);
|
||||
ALIASENCHANTMENTS.put("ww", Enchantment.WATER_WORKER);
|
||||
|
||||
ALIASENCHANTMENTS.put("firearrow", Enchantment.ARROW_FIRE);
|
||||
ENCHANTMENTS.put("flame", Enchantment.ARROW_FIRE);
|
||||
ENCHANTMENTS.put("flamearrow", Enchantment.ARROW_FIRE);
|
||||
ALIASENCHANTMENTS.put("af", Enchantment.ARROW_FIRE);
|
||||
|
||||
ENCHANTMENTS.put("arrowdamage", Enchantment.ARROW_DAMAGE);
|
||||
ENCHANTMENTS.put("power", Enchantment.ARROW_DAMAGE);
|
||||
ALIASENCHANTMENTS.put("arrowpower", Enchantment.ARROW_DAMAGE);
|
||||
ALIASENCHANTMENTS.put("ad", Enchantment.ARROW_DAMAGE);
|
||||
|
||||
ENCHANTMENTS.put("arrowknockback", Enchantment.ARROW_KNOCKBACK);
|
||||
ALIASENCHANTMENTS.put("arrowkb", Enchantment.ARROW_KNOCKBACK);
|
||||
ENCHANTMENTS.put("punch", Enchantment.ARROW_KNOCKBACK);
|
||||
ALIASENCHANTMENTS.put("arrowpunch", Enchantment.ARROW_KNOCKBACK);
|
||||
ALIASENCHANTMENTS.put("ak", Enchantment.ARROW_KNOCKBACK);
|
||||
|
||||
ALIASENCHANTMENTS.put("infinitearrows", Enchantment.ARROW_INFINITE);
|
||||
ENCHANTMENTS.put("infarrows", Enchantment.ARROW_INFINITE);
|
||||
ENCHANTMENTS.put("infinity", Enchantment.ARROW_INFINITE);
|
||||
ALIASENCHANTMENTS.put("infinite", Enchantment.ARROW_INFINITE);
|
||||
ALIASENCHANTMENTS.put("unlimited", Enchantment.ARROW_INFINITE);
|
||||
ALIASENCHANTMENTS.put("unlimitedarrows", Enchantment.ARROW_INFINITE);
|
||||
ALIASENCHANTMENTS.put("ai", Enchantment.ARROW_INFINITE);
|
||||
|
||||
ENCHANTMENTS.put("luck", Enchantment.LUCK);
|
||||
ALIASENCHANTMENTS.put("luckofsea", Enchantment.LUCK);
|
||||
ALIASENCHANTMENTS.put("luckofseas", Enchantment.LUCK);
|
||||
ALIASENCHANTMENTS.put("rodluck", Enchantment.LUCK);
|
||||
|
||||
ENCHANTMENTS.put("lure", Enchantment.LURE);
|
||||
ALIASENCHANTMENTS.put("rodlure", Enchantment.LURE);
|
||||
|
||||
// 1.8
|
||||
try {
|
||||
final Enchantment depthStrider = Enchantment.getByName("DEPTH_STRIDER");
|
||||
if (depthStrider != null) {
|
||||
ENCHANTMENTS.put("depthstrider", depthStrider);
|
||||
ALIASENCHANTMENTS.put("depth", depthStrider);
|
||||
ALIASENCHANTMENTS.put("strider", depthStrider);
|
||||
}
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
// 1.9
|
||||
try {
|
||||
final Enchantment frostWalker = Enchantment.getByName("FROST_WALKER");
|
||||
if (frostWalker != null) {
|
||||
ENCHANTMENTS.put("frostwalker", frostWalker);
|
||||
ALIASENCHANTMENTS.put("frost", frostWalker);
|
||||
ALIASENCHANTMENTS.put("walker", frostWalker);
|
||||
}
|
||||
|
||||
final Enchantment mending = Enchantment.getByName("MENDING");
|
||||
if (mending != null) {
|
||||
ENCHANTMENTS.put("mending", mending);
|
||||
}
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
// 1.11
|
||||
try {
|
||||
final Enchantment bindingCurse = Enchantment.getByName("BINDING_CURSE");
|
||||
if (bindingCurse != null) {
|
||||
ENCHANTMENTS.put("bindingcurse", bindingCurse);
|
||||
ALIASENCHANTMENTS.put("bindcurse", bindingCurse);
|
||||
ALIASENCHANTMENTS.put("binding", bindingCurse);
|
||||
ALIASENCHANTMENTS.put("bind", bindingCurse);
|
||||
}
|
||||
final Enchantment vanishingCurse = Enchantment.getByName("VANISHING_CURSE");
|
||||
if (vanishingCurse != null) {
|
||||
ENCHANTMENTS.put("vanishingcurse", vanishingCurse);
|
||||
ALIASENCHANTMENTS.put("vanishcurse", vanishingCurse);
|
||||
ALIASENCHANTMENTS.put("vanishing", vanishingCurse);
|
||||
ALIASENCHANTMENTS.put("vanish", vanishingCurse);
|
||||
}
|
||||
final Enchantment sweeping = Enchantment.getByName("SWEEPING_EDGE");
|
||||
if (sweeping != null) {
|
||||
ENCHANTMENTS.put("sweepingedge", sweeping);
|
||||
ALIASENCHANTMENTS.put("sweepedge", sweeping);
|
||||
ALIASENCHANTMENTS.put("sweeping", sweeping);
|
||||
}
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
try { // 1.13
|
||||
final Enchantment loyalty = Enchantment.getByName("LOYALTY");
|
||||
if (loyalty != null) {
|
||||
ENCHANTMENTS.put("loyalty", loyalty);
|
||||
ALIASENCHANTMENTS.put("loyal", loyalty);
|
||||
ALIASENCHANTMENTS.put("return", loyalty);
|
||||
}
|
||||
final Enchantment impaling = Enchantment.getByName("IMPALING");
|
||||
if (impaling != null) {
|
||||
ENCHANTMENTS.put("impaling", impaling);
|
||||
ALIASENCHANTMENTS.put("impale", impaling);
|
||||
ALIASENCHANTMENTS.put("oceandamage", impaling);
|
||||
ALIASENCHANTMENTS.put("oceandmg", impaling);
|
||||
}
|
||||
final Enchantment riptide = Enchantment.getByName("RIPTIDE");
|
||||
if (riptide != null) {
|
||||
ENCHANTMENTS.put("riptide", riptide);
|
||||
ALIASENCHANTMENTS.put("rip", riptide);
|
||||
ALIASENCHANTMENTS.put("tide", riptide);
|
||||
ALIASENCHANTMENTS.put("launch", riptide);
|
||||
}
|
||||
final Enchantment channelling = Enchantment.getByName("CHANNELING");
|
||||
if (channelling != null) {
|
||||
ENCHANTMENTS.put("channelling", channelling);
|
||||
ALIASENCHANTMENTS.put("chanelling", channelling);
|
||||
ALIASENCHANTMENTS.put("channeling", channelling);
|
||||
ALIASENCHANTMENTS.put("chaneling", channelling);
|
||||
ALIASENCHANTMENTS.put("channel", channelling);
|
||||
}
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
try { // 1.14
|
||||
final Enchantment multishot = Enchantment.getByName("MULTISHOT");
|
||||
if (multishot != null) {
|
||||
ENCHANTMENTS.put("multishot", multishot);
|
||||
ALIASENCHANTMENTS.put("tripleshot", multishot);
|
||||
}
|
||||
final Enchantment quickCharge = Enchantment.getByName("QUICK_CHARGE");
|
||||
if (quickCharge != null) {
|
||||
ENCHANTMENTS.put("quickcharge", quickCharge);
|
||||
ALIASENCHANTMENTS.put("quickdraw", quickCharge);
|
||||
ALIASENCHANTMENTS.put("fastcharge", quickCharge);
|
||||
ALIASENCHANTMENTS.put("fastdraw", quickCharge);
|
||||
}
|
||||
final Enchantment piercing = Enchantment.getByName("PIERCING");
|
||||
if (piercing != null) {
|
||||
ENCHANTMENTS.put("piercing", piercing);
|
||||
}
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
try { // 1.16
|
||||
final Enchantment soulspeed = Enchantment.getByName("SOUL_SPEED");
|
||||
if (soulspeed != null) {
|
||||
ENCHANTMENTS.put("soulspeed", soulspeed);
|
||||
ALIASENCHANTMENTS.put("soilspeed", soulspeed);
|
||||
ALIASENCHANTMENTS.put("sandspeed", soulspeed);
|
||||
}
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
final Class<?> namespacedKeyClass = Class.forName("org.bukkit.NamespacedKey");
|
||||
final Class<?> enchantmentClass = Class.forName("org.bukkit.enchantments.Enchantment");
|
||||
enchantmentClass.getDeclaredMethod("getByKey", namespacedKeyClass);
|
||||
isFlat = true;
|
||||
} catch (final ClassNotFoundException | NoSuchMethodException e) {
|
||||
isFlat = false;
|
||||
}
|
||||
}
|
||||
|
||||
private Enchantments() {
|
||||
}
|
||||
|
||||
public static Enchantment getByName(final String name) {
|
||||
Enchantment enchantment = null;
|
||||
if (isFlat) { // 1.13+ only
|
||||
enchantment = Enchantment.getByKey(NamespacedKey.minecraft(name.toLowerCase()));
|
||||
}
|
||||
|
||||
if (enchantment == null) {
|
||||
enchantment = Enchantment.getByName(name.toUpperCase());
|
||||
}
|
||||
if (enchantment == null) {
|
||||
enchantment = ENCHANTMENTS.get(name.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
if (enchantment == null) {
|
||||
enchantment = ALIASENCHANTMENTS.get(name.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
return enchantment;
|
||||
}
|
||||
|
||||
public static Set<Entry<String, Enchantment>> entrySet() {
|
||||
return ENCHANTMENTS.entrySet();
|
||||
}
|
||||
|
||||
public static Set<String> keySet() {
|
||||
return ENCHANTMENTS.keySet();
|
||||
}
|
||||
}
|
||||
@@ -1,674 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import net.ess3.api.InvalidWorldException;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class EssentialsConf extends YamlConfiguration {
|
||||
protected static final Logger LOGGER = Logger.getLogger("Essentials");
|
||||
protected static final Charset UTF8 = StandardCharsets.UTF_8;
|
||||
private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
|
||||
protected final File configFile;
|
||||
private final AtomicInteger pendingDiskWrites = new AtomicInteger(0);
|
||||
private final AtomicBoolean transaction = new AtomicBoolean(false);
|
||||
private final byte[] bytebuffer = new byte[1024];
|
||||
protected String templateName = null;
|
||||
private Class<?> resourceClass = EssentialsConf.class;
|
||||
|
||||
public EssentialsConf(final File configFile) {
|
||||
super();
|
||||
this.configFile = configFile.getAbsoluteFile();
|
||||
}
|
||||
|
||||
public static BigDecimal toBigDecimal(final String input, final BigDecimal def) {
|
||||
if (input == null || input.isEmpty()) {
|
||||
return def;
|
||||
} else {
|
||||
try {
|
||||
return new BigDecimal(input, MathContext.DECIMAL128);
|
||||
} catch (final NumberFormatException | ArithmeticException e) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void load() {
|
||||
if (pendingDiskWrites.get() != 0) {
|
||||
LOGGER.log(Level.INFO, "File {0} not read, because it''s not yet written to disk.", configFile);
|
||||
return;
|
||||
}
|
||||
if (!configFile.getParentFile().exists()) {
|
||||
if (!configFile.getParentFile().mkdirs()) {
|
||||
LOGGER.log(Level.SEVERE, tl("failedToCreateConfig", configFile.toString()));
|
||||
}
|
||||
}
|
||||
// This will delete files where the first character is 0. In most cases they are broken.
|
||||
if (configFile.exists() && configFile.length() != 0) {
|
||||
try {
|
||||
final InputStream input = new FileInputStream(configFile);
|
||||
try {
|
||||
if (input.read() == 0) {
|
||||
input.close();
|
||||
configFile.delete();
|
||||
}
|
||||
} catch (final IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, null, ex);
|
||||
} finally {
|
||||
try {
|
||||
input.close();
|
||||
} catch (final IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
} catch (final FileNotFoundException ex) {
|
||||
LOGGER.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!configFile.exists()) {
|
||||
if (legacyFileExists()) {
|
||||
convertLegacyFile();
|
||||
} else if (altFileExists()) {
|
||||
convertAltFile();
|
||||
} else if (templateName != null) {
|
||||
LOGGER.log(Level.INFO, tl("creatingConfigFromTemplate", configFile.toString()));
|
||||
createFromTemplate();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
try (final FileInputStream inputStream = new FileInputStream(configFile)) {
|
||||
final long startSize = configFile.length();
|
||||
if (startSize > Integer.MAX_VALUE) {
|
||||
throw new InvalidConfigurationException("File too big");
|
||||
}
|
||||
ByteBuffer buffer = ByteBuffer.allocate((int) startSize);
|
||||
int length;
|
||||
while ((length = inputStream.read(bytebuffer)) != -1) {
|
||||
if (length > buffer.remaining()) {
|
||||
final ByteBuffer resize = ByteBuffer.allocate(buffer.capacity() + length - buffer.remaining());
|
||||
final int resizePosition = buffer.position();
|
||||
// Fix builds compiled against Java 9+ breaking on Java 8
|
||||
((Buffer) buffer).rewind();
|
||||
resize.put(buffer);
|
||||
resize.position(resizePosition);
|
||||
buffer = resize;
|
||||
}
|
||||
buffer.put(bytebuffer, 0, length);
|
||||
}
|
||||
((Buffer) buffer).rewind();
|
||||
final CharBuffer data = CharBuffer.allocate(buffer.capacity());
|
||||
CharsetDecoder decoder = UTF8.newDecoder();
|
||||
CoderResult result = decoder.decode(buffer, data, true);
|
||||
if (result.isError()) {
|
||||
((Buffer) buffer).rewind();
|
||||
((Buffer) data).clear();
|
||||
LOGGER.log(Level.INFO, "File " + configFile.getAbsolutePath() + " is not utf-8 encoded, trying " + Charset.defaultCharset().displayName());
|
||||
decoder = Charset.defaultCharset().newDecoder();
|
||||
result = decoder.decode(buffer, data, true);
|
||||
if (result.isError()) {
|
||||
throw new InvalidConfigurationException("Invalid Characters in file " + configFile.getAbsolutePath());
|
||||
} else {
|
||||
decoder.flush(data);
|
||||
}
|
||||
} else {
|
||||
decoder.flush(data);
|
||||
}
|
||||
final int end = data.position();
|
||||
((Buffer) data).rewind();
|
||||
super.loadFromString(data.subSequence(0, end).toString());
|
||||
}
|
||||
} catch (final IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
|
||||
} catch (final InvalidConfigurationException ex) {
|
||||
final File broken = new File(configFile.getAbsolutePath() + ".broken." + System.currentTimeMillis());
|
||||
configFile.renameTo(broken);
|
||||
LOGGER.log(Level.SEVERE, "The file " + configFile.toString() + " is broken, it has been renamed to " + broken.toString(), ex.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean legacyFileExists() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void convertLegacyFile() {
|
||||
LOGGER.log(Level.SEVERE, "Unable to import legacy config file.");
|
||||
}
|
||||
|
||||
public boolean altFileExists() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void convertAltFile() {
|
||||
LOGGER.log(Level.SEVERE, "Unable to import alt config file.");
|
||||
}
|
||||
|
||||
private void createFromTemplate() {
|
||||
InputStream istr = null;
|
||||
OutputStream ostr = null;
|
||||
try {
|
||||
istr = resourceClass.getResourceAsStream(templateName);
|
||||
if (istr == null) {
|
||||
LOGGER.log(Level.SEVERE, tl("couldNotFindTemplate", templateName));
|
||||
return;
|
||||
}
|
||||
ostr = new FileOutputStream(configFile);
|
||||
final byte[] buffer = new byte[1024];
|
||||
int length = 0;
|
||||
length = istr.read(buffer);
|
||||
while (length > 0) {
|
||||
ostr.write(buffer, 0, length);
|
||||
length = istr.read(buffer);
|
||||
}
|
||||
} catch (final IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, tl("failedToWriteConfig", configFile.toString()), ex);
|
||||
} finally {
|
||||
try {
|
||||
if (istr != null) {
|
||||
istr.close();
|
||||
}
|
||||
} catch (final IOException ex) {
|
||||
Logger.getLogger(EssentialsConf.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
try {
|
||||
if (ostr != null) {
|
||||
ostr.close();
|
||||
}
|
||||
} catch (final IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, tl("failedToCloseConfig", configFile.toString()), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setTemplateName(final String templateName) {
|
||||
this.templateName = templateName;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return configFile;
|
||||
}
|
||||
|
||||
public void setTemplateName(final String templateName, final Class<?> resClass) {
|
||||
this.templateName = templateName;
|
||||
this.resourceClass = resClass;
|
||||
}
|
||||
|
||||
public void startTransaction() {
|
||||
transaction.set(true);
|
||||
}
|
||||
|
||||
public void stopTransaction() {
|
||||
transaction.set(false);
|
||||
save();
|
||||
}
|
||||
|
||||
public void save() {
|
||||
try {
|
||||
save(configFile);
|
||||
} catch (final IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveWithError() throws IOException {
|
||||
save(configFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void save(final File file) throws IOException {
|
||||
if (!transaction.get()) {
|
||||
delayedSave(file);
|
||||
}
|
||||
}
|
||||
|
||||
//This may be aborted if there are stagnant requests sitting in queue.
|
||||
//This needs fixed to discard outstanding save requests.
|
||||
public synchronized void forceSave() {
|
||||
try {
|
||||
final Future<?> future = delayedSave(configFile);
|
||||
if (future != null) {
|
||||
future.get();
|
||||
}
|
||||
} catch (final InterruptedException | ExecutionException ex) {
|
||||
LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void cleanup() {
|
||||
forceSave();
|
||||
}
|
||||
|
||||
private Future<?> delayedSave(final File file) {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException("File cannot be null");
|
||||
}
|
||||
|
||||
final String data = saveToString();
|
||||
|
||||
if (data.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
pendingDiskWrites.incrementAndGet();
|
||||
|
||||
return EXECUTOR_SERVICE.submit(new WriteRunner(configFile, data, pendingDiskWrites));
|
||||
}
|
||||
|
||||
public boolean hasProperty(final String path) {
|
||||
return isSet(path);
|
||||
}
|
||||
|
||||
public Location getLocation(final String path, final Server server) throws InvalidWorldException {
|
||||
final String worldString = (path == null ? "" : path + ".") + "world";
|
||||
final String worldName = getString(worldString);
|
||||
if (worldName == null || worldName.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final World world = server.getWorld(worldName);
|
||||
if (world == null) {
|
||||
throw new InvalidWorldException(worldName);
|
||||
}
|
||||
return new Location(world, getDouble((path == null ? "" : path + ".") + "x", 0), getDouble((path == null ? "" : path + ".") + "y", 0), getDouble((path == null ? "" : path + ".") + "z", 0), (float) getDouble((path == null ? "" : path + ".") + "yaw", 0), (float) getDouble((path == null ? "" : path + ".") + "pitch", 0));
|
||||
}
|
||||
|
||||
public void setProperty(final String path, final Location loc) {
|
||||
set((path == null ? "" : path + ".") + "world", loc.getWorld().getName());
|
||||
set((path == null ? "" : path + ".") + "x", loc.getX());
|
||||
set((path == null ? "" : path + ".") + "y", loc.getY());
|
||||
set((path == null ? "" : path + ".") + "z", loc.getZ());
|
||||
set((path == null ? "" : path + ".") + "yaw", loc.getYaw());
|
||||
set((path == null ? "" : path + ".") + "pitch", loc.getPitch());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStack(final String path) {
|
||||
final ItemStack stack = new ItemStack(Material.valueOf(getString(path + ".type", "AIR")), getInt(path + ".amount", 1), (short) getInt(path + ".damage", 0));
|
||||
final ConfigurationSection enchants = getConfigurationSection(path + ".enchant");
|
||||
if (enchants != null) {
|
||||
for (final String enchant : enchants.getKeys(false)) {
|
||||
final Enchantment enchantment = Enchantment.getByName(enchant.toUpperCase(Locale.ENGLISH));
|
||||
if (enchantment == null) {
|
||||
continue;
|
||||
}
|
||||
final int level = getInt(path + ".enchant." + enchant, enchantment.getStartLevel());
|
||||
stack.addUnsafeEnchantment(enchantment, level);
|
||||
}
|
||||
}
|
||||
return stack;
|
||||
/*
|
||||
* ,
|
||||
* (byte)getInt(path + ".data", 0)
|
||||
*/
|
||||
}
|
||||
|
||||
public void setProperty(final String path, final ItemStack stack) {
|
||||
final Map<String, Object> map = new HashMap<>();
|
||||
map.put("type", stack.getType().toString());
|
||||
map.put("amount", stack.getAmount());
|
||||
map.put("damage", stack.getDurability());
|
||||
final Map<Enchantment, Integer> enchantments = stack.getEnchantments();
|
||||
if (!enchantments.isEmpty()) {
|
||||
final Map<String, Integer> enchant = new HashMap<>();
|
||||
for (final Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
|
||||
enchant.put(entry.getKey().getName().toLowerCase(Locale.ENGLISH), entry.getValue());
|
||||
}
|
||||
map.put("enchant", enchant);
|
||||
}
|
||||
// getData().getData() is broken
|
||||
//map.put("data", stack.getDurability());
|
||||
set(path, map);
|
||||
}
|
||||
|
||||
public void setProperty(final String path, final List object) {
|
||||
set(path, new ArrayList(object));
|
||||
}
|
||||
|
||||
public void setProperty(final String path, final Map object) {
|
||||
set(path, new LinkedHashMap(object));
|
||||
}
|
||||
|
||||
public Object getProperty(final String path) {
|
||||
return get(path);
|
||||
}
|
||||
|
||||
public void setProperty(final String path, final BigDecimal bigDecimal) {
|
||||
set(path, bigDecimal.toString());
|
||||
}
|
||||
|
||||
public void setProperty(final String path, final Object object) {
|
||||
set(path, object);
|
||||
}
|
||||
|
||||
public void removeProperty(final String path) {
|
||||
set(path, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Object get(final String path) {
|
||||
return super.get(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Object get(final String path, final Object def) {
|
||||
return super.get(path, def);
|
||||
}
|
||||
|
||||
public synchronized BigDecimal getBigDecimal(final String path, final BigDecimal def) {
|
||||
final String input = super.getString(path);
|
||||
return toBigDecimal(input, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean getBoolean(final String path) {
|
||||
return super.getBoolean(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean getBoolean(final String path, final boolean def) {
|
||||
return super.getBoolean(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Boolean> getBooleanList(final String path) {
|
||||
return super.getBooleanList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Byte> getByteList(final String path) {
|
||||
return super.getByteList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Character> getCharacterList(final String path) {
|
||||
return super.getCharacterList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ConfigurationSection getConfigurationSection(final String path) {
|
||||
return super.getConfigurationSection(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized double getDouble(final String path) {
|
||||
return super.getDouble(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized double getDouble(final String path, final double def) {
|
||||
return super.getDouble(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Double> getDoubleList(final String path) {
|
||||
return super.getDoubleList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Float> getFloatList(final String path) {
|
||||
return super.getFloatList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getInt(final String path) {
|
||||
return super.getInt(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getInt(final String path, final int def) {
|
||||
return super.getInt(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Integer> getIntegerList(final String path) {
|
||||
return super.getIntegerList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ItemStack getItemStack(final String path, final ItemStack def) {
|
||||
return super.getItemStack(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Set<String> getKeys(final boolean deep) {
|
||||
return super.getKeys(deep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<?> getList(final String path) {
|
||||
return super.getList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<?> getList(final String path, final List<?> def) {
|
||||
return super.getList(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized long getLong(final String path) {
|
||||
return super.getLong(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized long getLong(final String path, final long def) {
|
||||
return super.getLong(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Long> getLongList(final String path) {
|
||||
return super.getLongList(path);
|
||||
}
|
||||
|
||||
public synchronized Map<String, Object> getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Map<?, ?>> getMapList(final String path) {
|
||||
return super.getMapList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized OfflinePlayer getOfflinePlayer(final String path) {
|
||||
return super.getOfflinePlayer(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized OfflinePlayer getOfflinePlayer(final String path, final OfflinePlayer def) {
|
||||
return super.getOfflinePlayer(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Short> getShortList(final String path) {
|
||||
return super.getShortList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String getString(final String path) {
|
||||
return super.getString(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String getString(final String path, final String def) {
|
||||
return super.getString(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<String> getStringList(final String path) {
|
||||
return super.getStringList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Map<String, Object> getValues(final boolean deep) {
|
||||
return super.getValues(deep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Vector getVector(final String path) {
|
||||
return super.getVector(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Vector getVector(final String path, final Vector def) {
|
||||
return super.getVector(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isBoolean(final String path) {
|
||||
return super.isBoolean(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isConfigurationSection(final String path) {
|
||||
return super.isConfigurationSection(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isDouble(final String path) {
|
||||
return super.isDouble(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isInt(final String path) {
|
||||
return super.isInt(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isItemStack(final String path) {
|
||||
return super.isItemStack(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isList(final String path) {
|
||||
return super.isList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isLong(final String path) {
|
||||
return super.isLong(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isOfflinePlayer(final String path) {
|
||||
return super.isOfflinePlayer(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isSet(final String path) {
|
||||
return super.isSet(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isString(final String path) {
|
||||
return super.isString(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isVector(final String path) {
|
||||
return super.isVector(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void set(final String path, final Object value) {
|
||||
super.set(path, value);
|
||||
}
|
||||
|
||||
private static final class WriteRunner implements Runnable {
|
||||
private final File configFile;
|
||||
private final String data;
|
||||
private final AtomicInteger pendingDiskWrites;
|
||||
|
||||
private WriteRunner(final File configFile, final String data, final AtomicInteger pendingDiskWrites) {
|
||||
this.configFile = configFile;
|
||||
this.data = data;
|
||||
this.pendingDiskWrites = pendingDiskWrites;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
//long startTime = System.nanoTime();
|
||||
synchronized (configFile) {
|
||||
if (pendingDiskWrites.get() > 1) {
|
||||
// Writes can be skipped, because they are stored in a queue (in the executor).
|
||||
// Only the last is actually written.
|
||||
pendingDiskWrites.decrementAndGet();
|
||||
//LOGGER.log(Level.INFO, configFile + " skipped writing in " + (System.nanoTime() - startTime) + " nsec.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Files.createParentDirs(configFile);
|
||||
|
||||
if (!configFile.exists()) {
|
||||
try {
|
||||
LOGGER.log(Level.INFO, tl("creatingEmptyConfig", configFile.toString()));
|
||||
if (!configFile.createNewFile()) {
|
||||
LOGGER.log(Level.SEVERE, tl("failedToCreateConfig", configFile.toString()));
|
||||
return;
|
||||
}
|
||||
} catch (final IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, tl("failedToCreateConfig", configFile.toString()), ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try (final FileOutputStream fos = new FileOutputStream(configFile)) {
|
||||
try (final OutputStreamWriter writer = new OutputStreamWriter(fos, UTF8)) {
|
||||
writer.write(data);
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
LOGGER.log(Level.SEVERE, e.getMessage(), e);
|
||||
} finally {
|
||||
//LOGGER.log(Level.INFO, configFile + " written to disk in " + (System.nanoTime() - startTime) + " nsec.");
|
||||
pendingDiskWrites.decrementAndGet();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,781 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.craftbukkit.BanLookup;
|
||||
import com.earth2me.essentials.craftbukkit.FakeWorld;
|
||||
import com.earth2me.essentials.settings.Spawns;
|
||||
import com.earth2me.essentials.storage.YamlStorageWriter;
|
||||
import com.earth2me.essentials.utils.StringUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.Maps;
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.BanList;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.math.BigInteger;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class EssentialsUpgrade {
|
||||
private final static Logger LOGGER = Logger.getLogger("Essentials");
|
||||
private static final FileFilter YML_FILTER = pathname -> pathname.isFile() && pathname.getName().endsWith(".yml");
|
||||
private static final String PATTERN_CONFIG_UUID_REGEX = "(?mi)^uuid:\\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\s*$";
|
||||
private static final Pattern PATTERN_CONFIG_UUID = Pattern.compile(PATTERN_CONFIG_UUID_REGEX);
|
||||
private static final String PATTERN_CONFIG_NAME_REGEX = "(?mi)^lastAccountName:\\s*[\"\']?(\\w+)[\"\']?\\s*$";
|
||||
private static final Pattern PATTERN_CONFIG_NAME = Pattern.compile(PATTERN_CONFIG_NAME_REGEX);
|
||||
private final transient IEssentials ess;
|
||||
private final transient EssentialsConf doneFile;
|
||||
|
||||
EssentialsUpgrade(final IEssentials essentials) {
|
||||
ess = essentials;
|
||||
if (!ess.getDataFolder().exists()) {
|
||||
ess.getDataFolder().mkdirs();
|
||||
}
|
||||
doneFile = new EssentialsConf(new File(ess.getDataFolder(), "upgrades-done.yml"));
|
||||
doneFile.load();
|
||||
}
|
||||
|
||||
public static void uuidFileConvert(final IEssentials ess, final Boolean ignoreUFCache) {
|
||||
ess.getLogger().info("Starting Essentials UUID userdata conversion");
|
||||
|
||||
final File userdir = new File(ess.getDataFolder(), "userdata");
|
||||
if (!userdir.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int countFiles = 0;
|
||||
int countFails = 0;
|
||||
int countEssCache = 0;
|
||||
int countBukkit = 0;
|
||||
|
||||
ess.getLogger().info("Found " + userdir.list().length + " files to convert...");
|
||||
|
||||
for (final String string : userdir.list()) {
|
||||
if (!string.endsWith(".yml") || string.length() < 5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int showProgress = countFiles % 250;
|
||||
|
||||
if (showProgress == 0) {
|
||||
ess.getUserMap().getUUIDMap().forceWriteUUIDMap();
|
||||
ess.getLogger().info("Converted " + countFiles + "/" + userdir.list().length);
|
||||
}
|
||||
|
||||
countFiles++;
|
||||
|
||||
final String name = string.substring(0, string.length() - 4);
|
||||
final EssentialsUserConf config;
|
||||
UUID uuid = null;
|
||||
try {
|
||||
uuid = UUID.fromString(name);
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
final File file = new File(userdir, string);
|
||||
final EssentialsConf conf = new EssentialsConf(file);
|
||||
conf.load();
|
||||
conf.setProperty("lastAccountName", name);
|
||||
conf.save();
|
||||
|
||||
final String uuidConf = ignoreUFCache ? "force-uuid" : "uuid";
|
||||
|
||||
final String uuidString = conf.getString(uuidConf, null);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
try {
|
||||
uuid = UUID.fromString(uuidString);
|
||||
countEssCache++;
|
||||
break;
|
||||
} catch (final Exception ex2) {
|
||||
if (conf.getBoolean("npc", false)) {
|
||||
uuid = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
|
||||
break;
|
||||
}
|
||||
|
||||
final org.bukkit.OfflinePlayer player = ess.getServer().getOfflinePlayer(name);
|
||||
uuid = player.getUniqueId();
|
||||
}
|
||||
|
||||
if (uuid != null) {
|
||||
countBukkit++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (uuid != null) {
|
||||
conf.forceSave();
|
||||
config = new EssentialsUserConf(name, uuid, new File(userdir, uuid + ".yml"));
|
||||
config.convertLegacyFile();
|
||||
ess.getUserMap().trackUUID(uuid, name, false);
|
||||
continue;
|
||||
}
|
||||
countFails++;
|
||||
}
|
||||
}
|
||||
ess.getUserMap().getUUIDMap().forceWriteUUIDMap();
|
||||
|
||||
ess.getLogger().info("Converted " + countFiles + "/" + countFiles + ". Conversion complete.");
|
||||
ess.getLogger().info("Converted via cache: " + countEssCache + " :: Converted via lookup: " + countBukkit + " :: Failed to convert: " + countFails);
|
||||
ess.getLogger().info("To rerun the conversion type /essentials uuidconvert");
|
||||
}
|
||||
|
||||
public void convertIgnoreList() {
|
||||
final Pattern pattern = Pattern.compile("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$");
|
||||
if (doneFile.getBoolean("updateUsersIgnoreListUUID", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.info("Attempting to migrate ignore list to UUIDs");
|
||||
|
||||
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
|
||||
if (!userdataFolder.exists() || !userdataFolder.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
final File[] userFiles = userdataFolder.listFiles();
|
||||
|
||||
for (final File file : userFiles) {
|
||||
if (!file.isFile() || !file.getName().endsWith(".yml")) {
|
||||
continue;
|
||||
}
|
||||
final EssentialsConf config = new EssentialsConf(file);
|
||||
try {
|
||||
config.load();
|
||||
if (config.hasProperty("ignore")) {
|
||||
final List<String> migratedIgnores = new ArrayList<>();
|
||||
for (final String name : Collections.synchronizedList(config.getStringList("ignore"))) {
|
||||
if (name == null) {
|
||||
continue;
|
||||
}
|
||||
if (pattern.matcher(name.trim()).matches()) {
|
||||
LOGGER.info("Detected already migrated ignore list!");
|
||||
return;
|
||||
}
|
||||
final User user = ess.getOfflineUser(name);
|
||||
if (user != null && user.getBase() != null) {
|
||||
migratedIgnores.add(user.getBase().getUniqueId().toString());
|
||||
}
|
||||
}
|
||||
config.removeProperty("ignore");
|
||||
config.setProperty("ignore", migratedIgnores);
|
||||
config.forceSave();
|
||||
}
|
||||
} catch (final RuntimeException ex) {
|
||||
LOGGER.log(Level.INFO, "File: " + file.toString());
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
doneFile.setProperty("updateUsersIgnoreListUUID", true);
|
||||
doneFile.save();
|
||||
LOGGER.info("Done converting ignore list.");
|
||||
}
|
||||
|
||||
public void convertKits() {
|
||||
final Kits kits = ess.getKits();
|
||||
final EssentialsConf config = kits.getConfig();
|
||||
if (doneFile.getBoolean("kitsyml", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.info("Attempting to convert old kits in config.yml to new kits.yml");
|
||||
|
||||
final ConfigurationSection section = ess.getSettings().getKitSection();
|
||||
if (section == null) {
|
||||
LOGGER.info("No kits found to migrate.");
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<String, Object> legacyKits = ess.getSettings().getKitSection().getValues(true);
|
||||
|
||||
for (final Map.Entry<String, Object> entry : legacyKits.entrySet()) {
|
||||
LOGGER.info("Converting " + entry.getKey());
|
||||
config.set("kits." + entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
config.save();
|
||||
doneFile.setProperty("kitsyml", true);
|
||||
doneFile.save();
|
||||
LOGGER.info("Done converting kits.");
|
||||
}
|
||||
|
||||
private void moveMotdRulesToFile(final String name) {
|
||||
if (doneFile.getBoolean("move" + name + "ToFile", false)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final File file = new File(ess.getDataFolder(), name + ".txt");
|
||||
if (file.exists()) {
|
||||
return;
|
||||
}
|
||||
final File configFile = new File(ess.getDataFolder(), "config.yml");
|
||||
if (!configFile.exists()) {
|
||||
return;
|
||||
}
|
||||
final EssentialsConf conf = new EssentialsConf(configFile);
|
||||
conf.load();
|
||||
final List<String> lines = conf.getStringList(name);
|
||||
if (lines != null && !lines.isEmpty()) {
|
||||
if (!file.createNewFile()) {
|
||||
throw new IOException("Failed to create file " + file);
|
||||
}
|
||||
final PrintWriter writer = new PrintWriter(file);
|
||||
|
||||
for (final String line : lines) {
|
||||
writer.println(line);
|
||||
}
|
||||
writer.close();
|
||||
}
|
||||
doneFile.setProperty("move" + name + "ToFile", true);
|
||||
doneFile.save();
|
||||
} catch (final IOException e) {
|
||||
LOGGER.log(Level.SEVERE, tl("upgradingFilesError"), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeLinesFromConfig(final File file, final String regex, final String info) throws Exception {
|
||||
boolean needUpdate = false;
|
||||
final BufferedReader bReader = new BufferedReader(new FileReader(file));
|
||||
final File tempFile = File.createTempFile("essentialsupgrade", ".tmp.yml", ess.getDataFolder());
|
||||
final BufferedWriter bWriter = new BufferedWriter(new FileWriter(tempFile));
|
||||
do {
|
||||
final String line = bReader.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
if (line.matches(regex)) {
|
||||
if (!needUpdate && info != null) {
|
||||
bWriter.write(info, 0, info.length());
|
||||
bWriter.newLine();
|
||||
}
|
||||
needUpdate = true;
|
||||
} else {
|
||||
if (line.endsWith("\r\n")) {
|
||||
bWriter.write(line, 0, line.length() - 2);
|
||||
} else if (line.endsWith("\r") || line.endsWith("\n")) {
|
||||
bWriter.write(line, 0, line.length() - 1);
|
||||
} else {
|
||||
bWriter.write(line, 0, line.length());
|
||||
}
|
||||
bWriter.newLine();
|
||||
}
|
||||
} while (true);
|
||||
bReader.close();
|
||||
bWriter.close();
|
||||
if (needUpdate) {
|
||||
if (!file.renameTo(new File(file.getParentFile(), file.getName().concat("." + System.currentTimeMillis() + ".upgradebackup")))) {
|
||||
throw new Exception(tl("configFileMoveError"));
|
||||
}
|
||||
if (!tempFile.renameTo(file)) {
|
||||
throw new Exception(tl("configFileRenameError"));
|
||||
}
|
||||
} else {
|
||||
tempFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUsersPowerToolsFormat() {
|
||||
if (doneFile.getBoolean("updateUsersPowerToolsFormat", false)) {
|
||||
return;
|
||||
}
|
||||
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
|
||||
if (!userdataFolder.exists() || !userdataFolder.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
final File[] userFiles = userdataFolder.listFiles();
|
||||
|
||||
for (final File file : userFiles) {
|
||||
if (!file.isFile() || !file.getName().endsWith(".yml")) {
|
||||
continue;
|
||||
}
|
||||
final EssentialsConf config = new EssentialsConf(file);
|
||||
try {
|
||||
config.load();
|
||||
if (config.hasProperty("powertools")) {
|
||||
final Map<String, Object> powertools = config.getConfigurationSection("powertools").getValues(false);
|
||||
if (powertools == null) {
|
||||
continue;
|
||||
}
|
||||
for (final Map.Entry<String, Object> entry : powertools.entrySet()) {
|
||||
if (entry.getValue() instanceof String) {
|
||||
final List<String> temp = new ArrayList<>();
|
||||
temp.add((String) entry.getValue());
|
||||
powertools.put(entry.getKey(), temp);
|
||||
}
|
||||
}
|
||||
config.forceSave();
|
||||
}
|
||||
} catch (final RuntimeException ex) {
|
||||
LOGGER.log(Level.INFO, "File: " + file.toString());
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
doneFile.setProperty("updateUsersPowerToolsFormat", true);
|
||||
doneFile.save();
|
||||
}
|
||||
|
||||
private void updateUsersHomesFormat() {
|
||||
if (doneFile.getBoolean("updateUsersHomesFormat", false)) {
|
||||
return;
|
||||
}
|
||||
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
|
||||
if (!userdataFolder.exists() || !userdataFolder.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
final File[] userFiles = userdataFolder.listFiles();
|
||||
|
||||
for (final File file : userFiles) {
|
||||
if (!file.isFile() || !file.getName().endsWith(".yml")) {
|
||||
continue;
|
||||
}
|
||||
final EssentialsConf config = new EssentialsConf(file);
|
||||
try {
|
||||
|
||||
config.load();
|
||||
if (config.hasProperty("home") && config.hasProperty("home.default")) {
|
||||
final String defworld = (String) config.getProperty("home.default");
|
||||
final Location defloc = getFakeLocation(config, "home.worlds." + defworld);
|
||||
if (defloc != null) {
|
||||
config.setProperty("homes.home", defloc);
|
||||
}
|
||||
|
||||
final Set<String> worlds = config.getConfigurationSection("home.worlds").getKeys(false);
|
||||
Location loc;
|
||||
String worldName;
|
||||
|
||||
if (worlds == null) {
|
||||
continue;
|
||||
}
|
||||
for (final String world : worlds) {
|
||||
if (defworld.equalsIgnoreCase(world)) {
|
||||
continue;
|
||||
}
|
||||
loc = getFakeLocation(config, "home.worlds." + world);
|
||||
if (loc == null) {
|
||||
continue;
|
||||
}
|
||||
worldName = loc.getWorld().getName().toLowerCase(Locale.ENGLISH);
|
||||
if (worldName != null && !worldName.isEmpty()) {
|
||||
config.setProperty("homes." + worldName, loc);
|
||||
}
|
||||
}
|
||||
config.removeProperty("home");
|
||||
config.forceSave();
|
||||
}
|
||||
|
||||
} catch (final RuntimeException ex) {
|
||||
LOGGER.log(Level.INFO, "File: " + file.toString());
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
doneFile.setProperty("updateUsersHomesFormat", true);
|
||||
doneFile.save();
|
||||
}
|
||||
|
||||
private void sanitizeAllUserFilenames() {
|
||||
if (doneFile.getBoolean("sanitizeAllUserFilenames", false)) {
|
||||
return;
|
||||
}
|
||||
final File usersFolder = new File(ess.getDataFolder(), "userdata");
|
||||
if (!usersFolder.exists()) {
|
||||
return;
|
||||
}
|
||||
final File[] listOfFiles = usersFolder.listFiles();
|
||||
for (final File listOfFile : listOfFiles) {
|
||||
final String filename = listOfFile.getName();
|
||||
if (!listOfFile.isFile() || !filename.endsWith(".yml")) {
|
||||
continue;
|
||||
}
|
||||
final String sanitizedFilename = StringUtil.sanitizeFileName(filename.substring(0, filename.length() - 4)) + ".yml";
|
||||
if (sanitizedFilename.equals(filename)) {
|
||||
continue;
|
||||
}
|
||||
final File tmpFile = new File(listOfFile.getParentFile(), sanitizedFilename + ".tmp");
|
||||
final File newFile = new File(listOfFile.getParentFile(), sanitizedFilename);
|
||||
if (!listOfFile.renameTo(tmpFile)) {
|
||||
LOGGER.log(Level.WARNING, tl("userdataMoveError", filename, sanitizedFilename));
|
||||
continue;
|
||||
}
|
||||
if (newFile.exists()) {
|
||||
LOGGER.log(Level.WARNING, tl("duplicatedUserdata", filename, sanitizedFilename));
|
||||
continue;
|
||||
}
|
||||
if (!tmpFile.renameTo(newFile)) {
|
||||
LOGGER.log(Level.WARNING, tl("userdataMoveBackError", sanitizedFilename, sanitizedFilename));
|
||||
}
|
||||
}
|
||||
doneFile.setProperty("sanitizeAllUserFilenames", true);
|
||||
doneFile.save();
|
||||
}
|
||||
|
||||
private World getFakeWorld(final String name) {
|
||||
final File bukkitDirectory = ess.getDataFolder().getParentFile().getParentFile();
|
||||
final File worldDirectory = new File(bukkitDirectory, name);
|
||||
if (worldDirectory.exists() && worldDirectory.isDirectory()) {
|
||||
return new FakeWorld(worldDirectory.getName(), World.Environment.NORMAL);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Location getFakeLocation(final EssentialsConf config, final String path) {
|
||||
final String worldName = config.getString((path != null ? path + "." : "") + "world");
|
||||
if (worldName == null || worldName.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final World world = getFakeWorld(worldName);
|
||||
if (world == null) {
|
||||
return null;
|
||||
}
|
||||
return new Location(world, config.getDouble((path != null ? path + "." : "") + "x", 0), config.getDouble((path != null ? path + "." : "") + "y", 0), config.getDouble((path != null ? path + "." : "") + "z", 0), (float) config.getDouble((path != null ? path + "." : "") + "yaw", 0), (float) config.getDouble((path != null ? path + "." : "") + "pitch", 0));
|
||||
}
|
||||
|
||||
private void deleteOldItemsCsv() {
|
||||
if (doneFile.getBoolean("deleteOldItemsCsv", false)) {
|
||||
return;
|
||||
}
|
||||
final File file = new File(ess.getDataFolder(), "items.csv");
|
||||
if (file.exists()) {
|
||||
try {
|
||||
final Set<BigInteger> oldconfigs = new HashSet<>();
|
||||
oldconfigs.add(new BigInteger("66ec40b09ac167079f558d1099e39f10", 16)); // sep 1
|
||||
oldconfigs.add(new BigInteger("34284de1ead43b0bee2aae85e75c041d", 16)); // crlf
|
||||
oldconfigs.add(new BigInteger("c33bc9b8ee003861611bbc2f48eb6f4f", 16)); // jul 24
|
||||
oldconfigs.add(new BigInteger("6ff17925430735129fc2a02f830c1daa", 16)); // crlf
|
||||
|
||||
final MessageDigest digest = ManagedFile.getDigest();
|
||||
final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
||||
final byte[] buffer = new byte[1024];
|
||||
try (final DigestInputStream dis = new DigestInputStream(bis, digest)) {
|
||||
while (dis.read(buffer) != -1) {
|
||||
}
|
||||
}
|
||||
|
||||
final BigInteger hash = new BigInteger(1, digest.digest());
|
||||
if (oldconfigs.contains(hash) && !file.delete()) {
|
||||
throw new IOException("Could not delete file " + file.toString());
|
||||
}
|
||||
doneFile.setProperty("deleteOldItemsCsv", true);
|
||||
doneFile.save();
|
||||
} catch (final IOException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSpawnsToNewSpawnsConfig() {
|
||||
if (doneFile.getBoolean("updateSpawnsToNewSpawnsConfig", false)) {
|
||||
return;
|
||||
}
|
||||
final File configFile = new File(ess.getDataFolder(), "spawn.yml");
|
||||
if (configFile.exists()) {
|
||||
|
||||
final EssentialsConf config = new EssentialsConf(configFile);
|
||||
try {
|
||||
config.load();
|
||||
if (!config.hasProperty("spawns")) {
|
||||
final Spawns spawns = new Spawns();
|
||||
final Set<String> keys = config.getKeys(false);
|
||||
for (final String group : keys) {
|
||||
final Location loc = getFakeLocation(config, group);
|
||||
spawns.getSpawns().put(group.toLowerCase(Locale.ENGLISH), loc);
|
||||
}
|
||||
if (!configFile.renameTo(new File(ess.getDataFolder(), "spawn.yml.old"))) {
|
||||
throw new Exception(tl("fileRenameError", "spawn.yml"));
|
||||
}
|
||||
try (final PrintWriter writer = new PrintWriter(configFile)) {
|
||||
new YamlStorageWriter(writer).save(spawns);
|
||||
}
|
||||
}
|
||||
} catch (final Exception ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
doneFile.setProperty("updateSpawnsToNewSpawnsConfig", true);
|
||||
doneFile.save();
|
||||
}
|
||||
|
||||
private void updateJailsToNewJailsConfig() {
|
||||
if (doneFile.getBoolean("updateJailsToNewJailsConfig", false)) {
|
||||
return;
|
||||
}
|
||||
final File configFile = new File(ess.getDataFolder(), "jail.yml");
|
||||
if (configFile.exists()) {
|
||||
|
||||
final EssentialsConf config = new EssentialsConf(configFile);
|
||||
try {
|
||||
config.load();
|
||||
if (!config.hasProperty("jails")) {
|
||||
final com.earth2me.essentials.settings.Jails jails = new com.earth2me.essentials.settings.Jails();
|
||||
final Set<String> keys = config.getKeys(false);
|
||||
for (final String jailName : keys) {
|
||||
final Location loc = getFakeLocation(config, jailName);
|
||||
jails.getJails().put(jailName.toLowerCase(Locale.ENGLISH), loc);
|
||||
}
|
||||
if (!configFile.renameTo(new File(ess.getDataFolder(), "jail.yml.old"))) {
|
||||
throw new Exception(tl("fileRenameError", "jail.yml"));
|
||||
}
|
||||
try (final PrintWriter writer = new PrintWriter(configFile)) {
|
||||
new YamlStorageWriter(writer).save(jails);
|
||||
}
|
||||
}
|
||||
} catch (final Exception ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
doneFile.setProperty("updateJailsToNewJailsConfig", true);
|
||||
doneFile.save();
|
||||
}
|
||||
|
||||
private void warnMetrics() {
|
||||
if (doneFile.getBoolean("warnMetrics", false)) {
|
||||
return;
|
||||
}
|
||||
doneFile.setProperty("warnMetrics", true);
|
||||
doneFile.save();
|
||||
}
|
||||
|
||||
private void uuidFileChange() {
|
||||
if (doneFile.getBoolean("uuidFileChange", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Boolean ignoreUFCache = doneFile.getBoolean("ignore-userfiles-cache", false);
|
||||
|
||||
final File userdir = new File(ess.getDataFolder(), "userdata");
|
||||
if (!userdir.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int countFiles = 0;
|
||||
int countReqFiles = 0;
|
||||
for (final String string : userdir.list()) {
|
||||
if (!string.endsWith(".yml") || string.length() < 5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
countFiles++;
|
||||
|
||||
final String name = string.substring(0, string.length() - 4);
|
||||
UUID uuid = null;
|
||||
|
||||
try {
|
||||
uuid = UUID.fromString(name);
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
countReqFiles++;
|
||||
}
|
||||
|
||||
if (countFiles > 100) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (countReqFiles < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
ess.getLogger().info("#### Starting Essentials UUID userdata conversion in a few seconds. ####");
|
||||
ess.getLogger().info("We recommend you take a backup of your server before upgrading from the old username system.");
|
||||
|
||||
try {
|
||||
Thread.sleep(15000);
|
||||
} catch (final InterruptedException ex) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
uuidFileConvert(ess, ignoreUFCache);
|
||||
|
||||
doneFile.setProperty("uuidFileChange", true);
|
||||
doneFile.save();
|
||||
}
|
||||
|
||||
public void banFormatChange() {
|
||||
if (doneFile.getBoolean("banFormatChange", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ess.getLogger().info("Starting Essentials ban format conversion");
|
||||
|
||||
final File userdir = new File(ess.getDataFolder(), "userdata");
|
||||
if (!userdir.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int countFiles = 0;
|
||||
|
||||
ess.getLogger().info("Found " + userdir.list().length + " files to convert...");
|
||||
|
||||
for (final String string : userdir.list()) {
|
||||
if (!string.endsWith(".yml") || string.length() < 5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int showProgress = countFiles % 250;
|
||||
|
||||
if (showProgress == 0) {
|
||||
ess.getLogger().info("Converted " + countFiles + "/" + userdir.list().length);
|
||||
}
|
||||
|
||||
countFiles++;
|
||||
final File pFile = new File(userdir, string);
|
||||
final EssentialsConf conf = new EssentialsConf(pFile);
|
||||
conf.load();
|
||||
|
||||
String banReason;
|
||||
long banTimeout;
|
||||
|
||||
try {
|
||||
banReason = conf.getConfigurationSection("ban").getString("reason");
|
||||
} catch (final NullPointerException n) {
|
||||
banReason = null;
|
||||
}
|
||||
|
||||
final String playerName = conf.getString("lastAccountName");
|
||||
if (playerName != null && playerName.length() > 1 && banReason != null && banReason.length() > 1) {
|
||||
try {
|
||||
if (conf.getConfigurationSection("ban").contains("timeout")) {
|
||||
banTimeout = Long.parseLong(conf.getConfigurationSection("ban").getString("timeout"));
|
||||
} else {
|
||||
banTimeout = 0L;
|
||||
}
|
||||
} catch (final NumberFormatException n) {
|
||||
banTimeout = 0L;
|
||||
}
|
||||
|
||||
if (BanLookup.isBanned(ess, playerName)) {
|
||||
updateBan(playerName, banReason, banTimeout);
|
||||
}
|
||||
}
|
||||
conf.removeProperty("ban");
|
||||
conf.save();
|
||||
}
|
||||
|
||||
doneFile.setProperty("banFormatChange", true);
|
||||
doneFile.save();
|
||||
ess.getLogger().info("Ban format update complete.");
|
||||
}
|
||||
|
||||
private void updateBan(final String playerName, final String banReason, final Long banTimeout) {
|
||||
if (banTimeout == 0) {
|
||||
Bukkit.getBanList(BanList.Type.NAME).addBan(playerName, banReason, null, Console.NAME);
|
||||
} else {
|
||||
Bukkit.getBanList(BanList.Type.NAME).addBan(playerName, banReason, new Date(banTimeout), Console.NAME);
|
||||
}
|
||||
}
|
||||
|
||||
private void repairUserMap() {
|
||||
if (doneFile.getBoolean("userMapRepaired", false)) {
|
||||
return;
|
||||
}
|
||||
ess.getLogger().info("Starting usermap repair");
|
||||
|
||||
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
|
||||
if (!userdataFolder.isDirectory()) {
|
||||
ess.getLogger().warning("Missing userdata folder, aborting");
|
||||
return;
|
||||
}
|
||||
final File[] files = userdataFolder.listFiles(YML_FILTER);
|
||||
|
||||
final DecimalFormat format = new DecimalFormat("#0.00");
|
||||
final Map<String, UUID> names = Maps.newHashMap();
|
||||
|
||||
for (int index = 0; index < files.length; index++) {
|
||||
final File file = files[index];
|
||||
try {
|
||||
UUID uuid = null;
|
||||
final String filename = file.getName();
|
||||
final String configData = new String(java.nio.file.Files.readAllBytes(file.toPath()), Charsets.UTF_8);
|
||||
|
||||
if (filename.length() > 36) {
|
||||
try {
|
||||
// ".yml" ending has 4 chars...
|
||||
uuid = UUID.fromString(filename.substring(0, filename.length() - 4));
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
final Matcher uuidMatcher = PATTERN_CONFIG_UUID.matcher(configData);
|
||||
if (uuidMatcher.find()) {
|
||||
try {
|
||||
uuid = UUID.fromString(uuidMatcher.group(1));
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
if (uuid == null) {
|
||||
// Don't import
|
||||
continue;
|
||||
}
|
||||
|
||||
final Matcher nameMatcher = PATTERN_CONFIG_NAME.matcher(configData);
|
||||
if (nameMatcher.find()) {
|
||||
final String username = nameMatcher.group(1);
|
||||
if (username != null && username.length() > 0) {
|
||||
names.put(StringUtil.safeString(username), uuid);
|
||||
}
|
||||
}
|
||||
|
||||
if (index % 1000 == 0) {
|
||||
ess.getLogger().info("Reading: " + format.format((100d * (double) index) / files.length)
|
||||
+ "%");
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
ess.getLogger().log(Level.SEVERE, "Error while reading file: ", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ess.getUserMap().getNames().putAll(names);
|
||||
ess.getUserMap().reloadConfig();
|
||||
|
||||
doneFile.setProperty("userMapRepaired", true);
|
||||
doneFile.save();
|
||||
ess.getLogger().info("Completed usermap repair.");
|
||||
}
|
||||
|
||||
public void beforeSettings() {
|
||||
if (!ess.getDataFolder().exists()) {
|
||||
ess.getDataFolder().mkdirs();
|
||||
}
|
||||
moveMotdRulesToFile("motd");
|
||||
moveMotdRulesToFile("rules");
|
||||
}
|
||||
|
||||
public void afterSettings() {
|
||||
sanitizeAllUserFilenames();
|
||||
updateUsersPowerToolsFormat();
|
||||
updateUsersHomesFormat();
|
||||
deleteOldItemsCsv();
|
||||
updateSpawnsToNewSpawnsConfig();
|
||||
updateJailsToNewJailsConfig();
|
||||
uuidFileChange();
|
||||
banFormatChange();
|
||||
warnMetrics();
|
||||
repairUserMap();
|
||||
convertIgnoreList();
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.io.Files;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class EssentialsUserConf extends EssentialsConf {
|
||||
public final String username;
|
||||
public final UUID uuid;
|
||||
|
||||
public EssentialsUserConf(final String username, final UUID uuid, final File configFile) {
|
||||
super(configFile);
|
||||
this.username = username;
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean legacyFileExists() {
|
||||
final File file = new File(configFile.getParentFile(), username + ".yml");
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void convertLegacyFile() {
|
||||
final File file = new File(configFile.getParentFile(), username + ".yml");
|
||||
try {
|
||||
Files.move(file, new File(configFile.getParentFile(), uuid + ".yml"));
|
||||
} catch (final IOException ex) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Failed to migrate user: " + username, ex);
|
||||
}
|
||||
|
||||
setProperty("lastAccountName", username);
|
||||
}
|
||||
|
||||
private File getAltFile() {
|
||||
final UUID fn = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username.toLowerCase(Locale.ENGLISH)).getBytes(Charsets.UTF_8));
|
||||
return new File(configFile.getParentFile(), fn.toString() + ".yml");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean altFileExists() {
|
||||
if (username.equals(username.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
return getAltFile().exists();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void convertAltFile() {
|
||||
try {
|
||||
Files.move(getAltFile(), new File(configFile.getParentFile(), uuid + ".yml"));
|
||||
} catch (final IOException ex) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Failed to migrate user: " + username, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import net.ess3.api.IEssentials;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.PropertyResourceBundle;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class I18n implements net.ess3.api.II18n {
|
||||
private static final String MESSAGES = "messages";
|
||||
private static final Pattern NODOUBLEMARK = Pattern.compile("''");
|
||||
private static final ResourceBundle NULL_BUNDLE = new ResourceBundle() {
|
||||
public Enumeration<String> getKeys() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Object handleGetObject(final String key) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
private static I18n instance;
|
||||
private final transient Locale defaultLocale = Locale.getDefault();
|
||||
private final transient ResourceBundle defaultBundle;
|
||||
private final transient IEssentials ess;
|
||||
private transient Locale currentLocale = defaultLocale;
|
||||
private transient ResourceBundle customBundle;
|
||||
private transient ResourceBundle localeBundle;
|
||||
private transient Map<String, MessageFormat> messageFormatCache = new HashMap<>();
|
||||
|
||||
public I18n(final IEssentials ess) {
|
||||
this.ess = ess;
|
||||
defaultBundle = ResourceBundle.getBundle(MESSAGES, Locale.ENGLISH, new UTF8PropertiesControl());
|
||||
localeBundle = defaultBundle;
|
||||
customBundle = NULL_BUNDLE;
|
||||
}
|
||||
|
||||
public static String tl(final String string, final Object... objects) {
|
||||
if (instance == null) {
|
||||
return "";
|
||||
}
|
||||
if (objects.length == 0) {
|
||||
return NODOUBLEMARK.matcher(instance.translate(string)).replaceAll("'");
|
||||
} else {
|
||||
return instance.format(string, objects);
|
||||
}
|
||||
}
|
||||
|
||||
public static String capitalCase(final String input) {
|
||||
return input == null || input.length() == 0 ? input : input.toUpperCase(Locale.ENGLISH).charAt(0) + input.toLowerCase(Locale.ENGLISH).substring(1);
|
||||
}
|
||||
|
||||
public void onEnable() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public void onDisable() {
|
||||
instance = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getCurrentLocale() {
|
||||
return currentLocale;
|
||||
}
|
||||
|
||||
private String translate(final String string) {
|
||||
try {
|
||||
try {
|
||||
return customBundle.getString(string);
|
||||
} catch (final MissingResourceException ex) {
|
||||
return localeBundle.getString(string);
|
||||
}
|
||||
} catch (final MissingResourceException ex) {
|
||||
Logger.getLogger("Essentials").log(Level.WARNING, String.format("Missing translation key \"%s\" in translation file %s", ex.getKey(), localeBundle.getLocale().toString()), ex);
|
||||
return defaultBundle.getString(string);
|
||||
}
|
||||
}
|
||||
|
||||
public String format(final String string, final Object... objects) {
|
||||
String format = translate(string);
|
||||
MessageFormat messageFormat = messageFormatCache.get(format);
|
||||
if (messageFormat == null) {
|
||||
try {
|
||||
messageFormat = new MessageFormat(format);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
ess.getLogger().log(Level.SEVERE, "Invalid Translation key for '" + string + "': " + e.getMessage());
|
||||
format = format.replaceAll("\\{(\\D*?)\\}", "\\[$1\\]");
|
||||
messageFormat = new MessageFormat(format);
|
||||
}
|
||||
messageFormatCache.put(format, messageFormat);
|
||||
}
|
||||
return messageFormat.format(objects).replace(' ', ' '); // replace nbsp with a space
|
||||
}
|
||||
|
||||
public void updateLocale(final String loc) {
|
||||
if (loc != null && !loc.isEmpty()) {
|
||||
final String[] parts = loc.split("[_\\.]");
|
||||
if (parts.length == 1) {
|
||||
currentLocale = new Locale(parts[0]);
|
||||
}
|
||||
if (parts.length == 2) {
|
||||
currentLocale = new Locale(parts[0], parts[1]);
|
||||
}
|
||||
if (parts.length == 3) {
|
||||
currentLocale = new Locale(parts[0], parts[1], parts[2]);
|
||||
}
|
||||
}
|
||||
ResourceBundle.clearCache();
|
||||
messageFormatCache = new HashMap<>();
|
||||
Logger.getLogger("Essentials").log(Level.INFO, String.format("Using locale %s", currentLocale.toString()));
|
||||
|
||||
try {
|
||||
localeBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new UTF8PropertiesControl());
|
||||
} catch (final MissingResourceException ex) {
|
||||
localeBundle = NULL_BUNDLE;
|
||||
}
|
||||
|
||||
try {
|
||||
customBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new FileResClassLoader(I18n.class.getClassLoader(), ess), new UTF8PropertiesControl());
|
||||
} catch (final MissingResourceException ex) {
|
||||
customBundle = NULL_BUNDLE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to load properties files from the plugin directory before falling back to the jar.
|
||||
*/
|
||||
private static class FileResClassLoader extends ClassLoader {
|
||||
private final transient File dataFolder;
|
||||
|
||||
FileResClassLoader(final ClassLoader classLoader, final IEssentials ess) {
|
||||
super(classLoader);
|
||||
this.dataFolder = ess.getDataFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getResource(final String string) {
|
||||
final File file = new File(dataFolder, string);
|
||||
if (file.exists()) {
|
||||
try {
|
||||
return file.toURI().toURL();
|
||||
} catch (final MalformedURLException ignored) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResourceAsStream(final String string) {
|
||||
final File file = new File(dataFolder, string);
|
||||
if (file.exists()) {
|
||||
try {
|
||||
return new FileInputStream(file);
|
||||
} catch (final FileNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads .properties files as UTF-8 instead of ISO-8859-1, which is the default on Java 8/below.
|
||||
* Java 9 fixes this by defaulting to UTF-8 for .properties files.
|
||||
*/
|
||||
private static class UTF8PropertiesControl extends ResourceBundle.Control {
|
||||
public ResourceBundle newBundle(final String baseName, final Locale locale, final String format, final ClassLoader loader, final boolean reload) throws IOException {
|
||||
final String resourceName = toResourceName(toBundleName(baseName, locale), "properties");
|
||||
ResourceBundle bundle = null;
|
||||
InputStream stream = null;
|
||||
if (reload) {
|
||||
final URL url = loader.getResource(resourceName);
|
||||
if (url != null) {
|
||||
final URLConnection connection = url.openConnection();
|
||||
if (connection != null) {
|
||||
connection.setUseCaches(false);
|
||||
stream = connection.getInputStream();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stream = loader.getResourceAsStream(resourceName);
|
||||
}
|
||||
if (stream != null) {
|
||||
try {
|
||||
// use UTF-8 here, this is the important bit
|
||||
bundle = new PropertyResourceBundle(new InputStreamReader(stream, StandardCharsets.UTF_8));
|
||||
} finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.MemoryConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.earth2me.essentials.I18n.capitalCase;
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Kits implements IConf {
|
||||
|
||||
private final EssentialsConf config;
|
||||
private ConfigurationSection kits;
|
||||
|
||||
public Kits(final IEssentials essentials) {
|
||||
config = new EssentialsConf(new File(essentials.getDataFolder(), "kits.yml"));
|
||||
config.setTemplateName("/kits.yml");
|
||||
|
||||
reloadConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
config.load();
|
||||
kits = _getKits();
|
||||
}
|
||||
|
||||
private ConfigurationSection _getKits() {
|
||||
if (config.isConfigurationSection("kits")) {
|
||||
final ConfigurationSection section = config.getConfigurationSection("kits");
|
||||
final ConfigurationSection newSection = new MemoryConfiguration();
|
||||
for (final String kitItem : section.getKeys(false)) {
|
||||
if (section.isConfigurationSection(kitItem)) {
|
||||
newSection.set(kitItem.toLowerCase(Locale.ENGLISH), section.getConfigurationSection(kitItem));
|
||||
}
|
||||
}
|
||||
return newSection;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public EssentialsConf getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public ConfigurationSection getKits() {
|
||||
return kits;
|
||||
}
|
||||
|
||||
public Map<String, Object> getKit(String name) {
|
||||
name = name.replace('.', '_').replace('/', '_');
|
||||
if (getKits() != null) {
|
||||
final ConfigurationSection kits = getKits();
|
||||
// For some reason, YAML doesn't sees keys as always lowercase even if they aren't defined like that.
|
||||
// Workaround is to toLowercase when getting from the config, but showing normally elsewhere.
|
||||
// ODDLY ENOUGH when you get the configuration section for ALL kits, it will return the proper
|
||||
// case of each kit. But when you check for each kit's configuration section, it won't return the kit
|
||||
// you just found if you don't toLowercase it.
|
||||
if (kits.isConfigurationSection(name.toLowerCase())) {
|
||||
return kits.getConfigurationSection(name.toLowerCase()).getValues(true);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Tries to find an existing kit name that matches the given name, ignoring case. Returns null if no match.
|
||||
public String matchKit(final String name) {
|
||||
if (config.isConfigurationSection("kits")) {
|
||||
final ConfigurationSection section = config.getConfigurationSection("kits");
|
||||
if (section != null) {
|
||||
for (final String kitName : section.getKeys(false)) {
|
||||
if (kitName.equalsIgnoreCase(name)) {
|
||||
return kitName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addKit(final String name, final List<String> lines, final long delay) {
|
||||
// Will overwrite but w/e
|
||||
config.set("kits." + name + ".delay", delay);
|
||||
config.set("kits." + name + ".items", lines);
|
||||
kits = _getKits();
|
||||
config.save();
|
||||
}
|
||||
|
||||
public void removeKit(final String name) {
|
||||
config.set("kits." + name, null);
|
||||
kits = _getKits();
|
||||
config.save();
|
||||
}
|
||||
|
||||
public String listKits(final net.ess3.api.IEssentials ess, final User user) throws Exception {
|
||||
try {
|
||||
final ConfigurationSection kits = config.getConfigurationSection("kits");
|
||||
final StringBuilder list = new StringBuilder();
|
||||
for (final String kitItem : kits.getKeys(false)) {
|
||||
if (user == null) {
|
||||
list.append(" ").append(capitalCase(kitItem));
|
||||
} else if (user.isAuthorized("essentials.kits." + kitItem.toLowerCase(Locale.ENGLISH))) {
|
||||
String cost = "";
|
||||
String name = capitalCase(kitItem);
|
||||
final BigDecimal costPrice = new Trade("kit-" + kitItem.toLowerCase(Locale.ENGLISH), ess).getCommandCost(user);
|
||||
if (costPrice.signum() > 0) {
|
||||
cost = tl("kitCost", NumberUtil.displayCurrency(costPrice, ess));
|
||||
}
|
||||
|
||||
final Kit kit = new Kit(kitItem, ess);
|
||||
final double nextUse = kit.getNextUse(user);
|
||||
if (nextUse == -1 && ess.getSettings().isSkippingUsedOneTimeKitsFromKitList()) {
|
||||
continue;
|
||||
} else if (nextUse != 0) {
|
||||
name = tl("kitDelay", name);
|
||||
}
|
||||
|
||||
list.append(" ").append(name).append(cost);
|
||||
}
|
||||
}
|
||||
return list.toString().trim();
|
||||
} catch (final Exception ex) {
|
||||
throw new Exception(tl("kitError"), ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public final class PlayerList {
|
||||
|
||||
private PlayerList() {
|
||||
}
|
||||
|
||||
// Cosmetic list formatting
|
||||
public static String listUsers(final IEssentials ess, final List<User> users, final String seperator) {
|
||||
final StringBuilder groupString = new StringBuilder();
|
||||
Collections.sort(users);
|
||||
boolean needComma = false;
|
||||
for (final User user : users) {
|
||||
if (needComma) {
|
||||
groupString.append(seperator);
|
||||
}
|
||||
needComma = true;
|
||||
if (user.isAfk()) {
|
||||
groupString.append(tl("listAfkTag"));
|
||||
}
|
||||
if (user.isHidden()) {
|
||||
groupString.append(tl("listHiddenTag"));
|
||||
}
|
||||
user.setDisplayNick();
|
||||
groupString.append(user.getDisplayName());
|
||||
if (ess.getSettings().realNamesOnList() && !ChatColor.stripColor(user.getDisplayName()).equals(user.getName())) {
|
||||
groupString.append(" (").append(user.getName()).append(")");
|
||||
}
|
||||
groupString.append("\u00a7f");
|
||||
}
|
||||
return groupString.toString();
|
||||
}
|
||||
|
||||
// Produce a user summary: There are 5 out of maximum 10 players online.
|
||||
public static String listSummary(final IEssentials ess, final User user, final boolean showHidden) {
|
||||
final Server server = ess.getServer();
|
||||
int playerHidden = 0;
|
||||
int hiddenCount = 0;
|
||||
for (final User onlinePlayer : ess.getOnlineUsers()) {
|
||||
if (onlinePlayer.isHidden() || (user != null && !user.getBase().canSee(onlinePlayer.getBase()))) {
|
||||
playerHidden++;
|
||||
if (showHidden || user != null && user.getBase().canSee(onlinePlayer.getBase())) {
|
||||
hiddenCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
final String online;
|
||||
if (hiddenCount > 0) {
|
||||
online = tl("listAmountHidden", ess.getOnlinePlayers().size() - playerHidden, hiddenCount, server.getMaxPlayers());
|
||||
} else {
|
||||
online = tl("listAmount", ess.getOnlinePlayers().size() - playerHidden, server.getMaxPlayers());
|
||||
}
|
||||
return online;
|
||||
}
|
||||
|
||||
// Build the basic player list, divided by groups.
|
||||
public static Map<String, List<User>> getPlayerLists(final IEssentials ess, final IUser sender, final boolean showHidden) {
|
||||
final Map<String, List<User>> playerList = new HashMap<>();
|
||||
for (final User onlineUser : ess.getOnlineUsers()) {
|
||||
if ((sender == null && !showHidden && onlineUser.isHidden()) || (sender != null && !showHidden && !sender.getBase().canSee(onlineUser.getBase()))) {
|
||||
continue;
|
||||
}
|
||||
final String group = FormatUtil.stripFormat(FormatUtil.stripEssentialsFormat(onlineUser.getGroup().toLowerCase()));
|
||||
final List<User> list = playerList.computeIfAbsent(group, k -> new ArrayList<>());
|
||||
list.add(onlineUser);
|
||||
}
|
||||
return playerList;
|
||||
}
|
||||
|
||||
// Handle the merging of groups
|
||||
public static List<User> getMergedList(final IEssentials ess, final Map<String, List<User>> playerList, final String groupName) {
|
||||
final Set<String> configGroups = ess.getSettings().getListGroupConfig().keySet();
|
||||
final List<User> users = new ArrayList<>();
|
||||
for (final String configGroup : configGroups) {
|
||||
if (configGroup.equalsIgnoreCase(groupName)) {
|
||||
final String[] groupValues = ess.getSettings().getListGroupConfig().get(configGroup).toString().trim().split(" ");
|
||||
for (String groupValue : groupValues) {
|
||||
groupValue = groupValue.toLowerCase(Locale.ENGLISH);
|
||||
if (groupValue.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
final List<User> u = playerList.get(groupValue.trim());
|
||||
if (u == null || u.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
playerList.remove(groupValue);
|
||||
users.addAll(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
// Output a playerlist of just a single group, /list <groupname>
|
||||
public static String listGroupUsers(final IEssentials ess, final Map<String, List<User>> playerList, final String groupName) throws Exception {
|
||||
final List<User> users = getMergedList(ess, playerList, groupName);
|
||||
final List<User> groupUsers = playerList.get(groupName);
|
||||
if (groupUsers != null && !groupUsers.isEmpty()) {
|
||||
users.addAll(groupUsers);
|
||||
}
|
||||
if (users.isEmpty()) {
|
||||
throw new Exception(tl("groupDoesNotExist"));
|
||||
}
|
||||
final String displayGroupName = Character.toTitleCase(groupName.charAt(0)) +
|
||||
groupName.substring(1);
|
||||
return outputFormat(displayGroupName, listUsers(ess, users, ", "));
|
||||
}
|
||||
|
||||
// Build the output string
|
||||
public static String outputFormat(final String group, final String message) {
|
||||
return tl("listGroupTag", FormatUtil.replaceFormat(group)) +
|
||||
message;
|
||||
}
|
||||
}
|
||||
@@ -1,209 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.utils.LocationUtil;
|
||||
import com.earth2me.essentials.utils.VersionUtil;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.ess3.api.InvalidWorldException;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
public class RandomTeleport implements IConf {
|
||||
private static final Random RANDOM = new Random();
|
||||
private static final int HIGHEST_BLOCK_Y_OFFSET = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_R01) ? 1 : 0;
|
||||
private final IEssentials essentials;
|
||||
private final EssentialsConf config;
|
||||
private final ConcurrentLinkedQueue<Location> cachedLocations = new ConcurrentLinkedQueue<>();
|
||||
|
||||
public RandomTeleport(final IEssentials essentials) {
|
||||
this.essentials = essentials;
|
||||
final File file = new File(essentials.getDataFolder(), "tpr.yml");
|
||||
config = new EssentialsConf(file);
|
||||
config.setTemplateName("/tpr.yml");
|
||||
config.options().copyHeader(true);
|
||||
reloadConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
config.load();
|
||||
cachedLocations.clear();
|
||||
}
|
||||
|
||||
public Location getCenter() {
|
||||
try {
|
||||
final Location center = config.getLocation("center", essentials.getServer());
|
||||
if (center != null) {
|
||||
return center;
|
||||
}
|
||||
} catch (final InvalidWorldException ignored) {
|
||||
}
|
||||
final Location center = essentials.getServer().getWorlds().get(0).getWorldBorder().getCenter();
|
||||
center.setY(center.getWorld().getHighestBlockYAt(center) + 1);
|
||||
setCenter(center);
|
||||
return center;
|
||||
}
|
||||
|
||||
public void setCenter(final Location center) {
|
||||
config.setProperty("center", center);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public double getMinRange() {
|
||||
return config.getDouble("min-range", 0d);
|
||||
}
|
||||
|
||||
public void setMinRange(final double minRange) {
|
||||
config.setProperty("min-range", minRange);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public double getMaxRange() {
|
||||
return config.getDouble("max-range", getCenter().getWorld().getWorldBorder().getSize() / 2);
|
||||
}
|
||||
|
||||
public void setMaxRange(final double maxRange) {
|
||||
config.setProperty("max-range", maxRange);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public Set<Biome> getExcludedBiomes() {
|
||||
final List<String> biomeNames = config.getStringList("excluded-biomes");
|
||||
final Set<Biome> excludedBiomes = new HashSet<>();
|
||||
for (final String biomeName : biomeNames) {
|
||||
try {
|
||||
excludedBiomes.add(Biome.valueOf(biomeName.toUpperCase()));
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
return excludedBiomes;
|
||||
}
|
||||
|
||||
public int getFindAttempts() {
|
||||
return config.getInt("find-attempts", 10);
|
||||
}
|
||||
|
||||
public int getCacheThreshold() {
|
||||
return config.getInt("cache-threshold", 10);
|
||||
}
|
||||
|
||||
public boolean getPreCache() {
|
||||
return config.getBoolean("pre-cache", false);
|
||||
}
|
||||
|
||||
public Queue<Location> getCachedLocations() {
|
||||
return cachedLocations;
|
||||
}
|
||||
|
||||
// Get a random location; cached if possible. Otherwise on demand.
|
||||
public CompletableFuture<Location> getRandomLocation(final Location center, final double minRange, final double maxRange) {
|
||||
final int findAttempts = this.getFindAttempts();
|
||||
final Queue<Location> cachedLocations = this.getCachedLocations();
|
||||
// Try to build up the cache if it is below the threshold
|
||||
if (cachedLocations.size() < this.getCacheThreshold()) {
|
||||
cacheRandomLocations(center, minRange, maxRange);
|
||||
}
|
||||
final CompletableFuture<Location> future = new CompletableFuture<>();
|
||||
// Return a random location immediately if one is available, otherwise try to find one now
|
||||
if (cachedLocations.isEmpty()) {
|
||||
attemptRandomLocation(findAttempts, center, minRange, maxRange).thenAccept(future::complete);
|
||||
} else {
|
||||
future.complete(cachedLocations.poll());
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
// Prompts caching random valid locations, up to a maximum number of attempts
|
||||
public void cacheRandomLocations(final Location center, final double minRange, final double maxRange) {
|
||||
essentials.getServer().getScheduler().scheduleSyncDelayedTask(essentials, () -> {
|
||||
for (int i = 0; i < this.getFindAttempts(); ++i) {
|
||||
calculateRandomLocation(center, minRange, maxRange).thenAccept(location -> {
|
||||
if (isValidRandomLocation(location)) {
|
||||
this.getCachedLocations().add(location);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Recursively attempt to find a random location. After a maximum number of attempts, the center is returned.
|
||||
private CompletableFuture<Location> attemptRandomLocation(final int attempts, final Location center, final double minRange, final double maxRange) {
|
||||
final CompletableFuture<Location> future = new CompletableFuture<>();
|
||||
if (attempts > 0) {
|
||||
calculateRandomLocation(center, minRange, maxRange).thenAccept(location -> {
|
||||
if (isValidRandomLocation(location)) {
|
||||
future.complete(location);
|
||||
} else {
|
||||
attemptRandomLocation(attempts - 1, center, minRange, maxRange).thenAccept(future::complete);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
future.complete(center);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
// Calculates a random location asynchronously.
|
||||
private CompletableFuture<Location> calculateRandomLocation(final Location center, final double minRange, final double maxRange) {
|
||||
final CompletableFuture<Location> future = new CompletableFuture<>();
|
||||
// Find an equally distributed offset by randomly rotating a point inside a rectangle about the origin
|
||||
final double rectX = RANDOM.nextDouble() * (maxRange - minRange) + minRange;
|
||||
final double rectZ = RANDOM.nextDouble() * (maxRange + minRange) - minRange;
|
||||
final double offsetX;
|
||||
final double offsetZ;
|
||||
final int transform = RANDOM.nextInt(4);
|
||||
if (transform == 0) {
|
||||
offsetX = rectX;
|
||||
offsetZ = rectZ;
|
||||
} else if (transform == 1) {
|
||||
offsetX = -rectZ;
|
||||
offsetZ = rectX;
|
||||
} else if (transform == 2) {
|
||||
offsetX = -rectX;
|
||||
offsetZ = -rectZ;
|
||||
} else {
|
||||
offsetX = rectZ;
|
||||
offsetZ = -rectX;
|
||||
}
|
||||
final Location location = new Location(
|
||||
center.getWorld(),
|
||||
center.getX() + offsetX,
|
||||
center.getWorld().getMaxHeight(),
|
||||
center.getZ() + offsetZ,
|
||||
360 * RANDOM.nextFloat() - 180,
|
||||
0
|
||||
);
|
||||
PaperLib.getChunkAtAsync(location).thenAccept(chunk -> {
|
||||
if (World.Environment.NETHER.equals(center.getWorld().getEnvironment())) {
|
||||
location.setY(getNetherYAt(location));
|
||||
} else {
|
||||
location.setY(center.getWorld().getHighestBlockYAt(location) + HIGHEST_BLOCK_Y_OFFSET);
|
||||
}
|
||||
future.complete(location);
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
// Returns an appropriate elevation for a given location in the nether, or -1 if none is found
|
||||
private double getNetherYAt(final Location location) {
|
||||
for (int y = 32; y < location.getWorld().getMaxHeight() / 2; ++y) {
|
||||
if (!LocationUtil.isBlockUnsafe(location.getWorld(), location.getBlockX(), y, location.getBlockZ())) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private boolean isValidRandomLocation(final Location location) {
|
||||
return location.getBlockY() > 0 && !this.getExcludedBiomes().contains(location.getBlock().getBiome());
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
|
||||
public class TNTExplodeListener implements Listener, Runnable {
|
||||
private final transient IEssentials ess;
|
||||
private transient boolean enabled = false;
|
||||
private transient int timer = -1;
|
||||
|
||||
public TNTExplodeListener(final IEssentials ess) {
|
||||
super();
|
||||
this.ess = ess;
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
if (!enabled) {
|
||||
enabled = true;
|
||||
timer = ess.scheduleSyncDelayedTask(this, 200);
|
||||
return;
|
||||
}
|
||||
if (timer != -1) {
|
||||
ess.getScheduler().cancelTask(timer);
|
||||
timer = ess.scheduleSyncDelayedTask(this, 200);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onEntityExplode(final EntityExplodeEvent event) {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
if (event.getEntity() instanceof LivingEntity) {
|
||||
return;
|
||||
}
|
||||
if (event.blockList().size() < 1) {
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
event.getLocation().getWorld().createExplosion(event.getLocation(), 0F);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
@@ -1,403 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
import com.earth2me.essentials.utils.LocationUtil;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.ITeleport;
|
||||
import net.ess3.api.IUser;
|
||||
import net.ess3.api.events.UserWarpEvent;
|
||||
import net.ess3.api.events.teleport.PreTeleportEvent;
|
||||
import net.ess3.api.events.teleport.TeleportWarmupEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
/**
|
||||
* @deprecated This API is not asynchronous. Use {@link com.earth2me.essentials.AsyncTeleport AsyncTeleport}
|
||||
*/
|
||||
@Deprecated
|
||||
public class Teleport implements ITeleport {
|
||||
private final IUser teleportOwner;
|
||||
private final IEssentials ess;
|
||||
private TimedTeleport timedTeleport;
|
||||
|
||||
private TeleportType tpType;
|
||||
|
||||
@Deprecated
|
||||
public Teleport(final IUser user, final IEssentials ess) {
|
||||
this.teleportOwner = user;
|
||||
this.ess = ess;
|
||||
tpType = TeleportType.NORMAL;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void cooldown(final boolean check) throws Exception {
|
||||
final Calendar time = new GregorianCalendar();
|
||||
if (teleportOwner.getLastTeleportTimestamp() > 0) {
|
||||
// Take the current time, and remove the delay from it.
|
||||
final double cooldown = ess.getSettings().getTeleportCooldown();
|
||||
final Calendar earliestTime = new GregorianCalendar();
|
||||
earliestTime.add(Calendar.SECOND, -(int) cooldown);
|
||||
earliestTime.add(Calendar.MILLISECOND, -(int) ((cooldown * 1000.0) % 1000.0));
|
||||
// This value contains the most recent time a teleportPlayer could have been used that would allow another use.
|
||||
final long earliestLong = earliestTime.getTimeInMillis();
|
||||
|
||||
// When was the last teleportPlayer used?
|
||||
final long lastTime = teleportOwner.getLastTeleportTimestamp();
|
||||
|
||||
if (lastTime > time.getTimeInMillis()) {
|
||||
// This is to make sure time didn't get messed up on last teleportPlayer use.
|
||||
// If this happens, let's give the user the benifit of the doubt.
|
||||
teleportOwner.setLastTeleportTimestamp(time.getTimeInMillis());
|
||||
return;
|
||||
} else if (lastTime > earliestLong
|
||||
&& cooldownApplies()) {
|
||||
time.setTimeInMillis(lastTime);
|
||||
time.add(Calendar.SECOND, (int) cooldown);
|
||||
time.add(Calendar.MILLISECOND, (int) ((cooldown * 1000.0) % 1000.0));
|
||||
throw new Exception(tl("timeBeforeTeleport", DateUtil.formatDateDiff(time.getTimeInMillis())));
|
||||
}
|
||||
}
|
||||
// if justCheck is set, don't update lastTeleport; we're just checking
|
||||
if (!check) {
|
||||
teleportOwner.setLastTeleportTimestamp(time.getTimeInMillis());
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private boolean cooldownApplies() {
|
||||
boolean applies = true;
|
||||
final String globalBypassPerm = "essentials.teleport.cooldown.bypass";
|
||||
switch (tpType) {
|
||||
case NORMAL:
|
||||
applies = !teleportOwner.isAuthorized(globalBypassPerm);
|
||||
break;
|
||||
case BACK:
|
||||
applies = !(teleportOwner.isAuthorized(globalBypassPerm) &&
|
||||
teleportOwner.isAuthorized("essentials.teleport.cooldown.bypass.back"));
|
||||
break;
|
||||
case TPA:
|
||||
applies = !(teleportOwner.isAuthorized(globalBypassPerm) &&
|
||||
teleportOwner.isAuthorized("essentials.teleport.cooldown.bypass.tpa"));
|
||||
break;
|
||||
}
|
||||
return applies;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private void warnUser(final IUser user, final double delay) {
|
||||
final Calendar c = new GregorianCalendar();
|
||||
c.add(Calendar.SECOND, (int) delay);
|
||||
c.add(Calendar.MILLISECOND, (int) ((delay * 1000.0) % 1000.0));
|
||||
user.sendMessage(tl("dontMoveMessage", DateUtil.formatDateDiff(c.getTimeInMillis())));
|
||||
}
|
||||
|
||||
//The now function is used when you want to skip tp delay when teleporting someone to a location or player.
|
||||
@Override
|
||||
@Deprecated
|
||||
public void now(final Location loc, final boolean cooldown, final TeleportCause cause) throws Exception {
|
||||
if (cooldown) {
|
||||
cooldown(false);
|
||||
}
|
||||
final ITarget target = new LocationTarget(loc);
|
||||
now(teleportOwner, target, cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void now(final Player entity, final boolean cooldown, final TeleportCause cause) throws Exception {
|
||||
if (cooldown) {
|
||||
cooldown(false);
|
||||
}
|
||||
final ITarget target = new PlayerTarget(entity);
|
||||
now(teleportOwner, target, cause);
|
||||
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
protected void now(final IUser teleportee, final ITarget target, final TeleportCause cause) throws Exception {
|
||||
cancel(false);
|
||||
Location loc = target.getLocation();
|
||||
|
||||
final PreTeleportEvent event = new PreTeleportEvent(teleportee, cause, target);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (teleportee.isAuthorized("essentials.back.onteleport")) {
|
||||
teleportee.setLastLocation();
|
||||
}
|
||||
|
||||
if (!teleportee.getBase().isEmpty()) {
|
||||
if (!ess.getSettings().isTeleportPassengerDismount()) {
|
||||
throw new Exception(tl("passengerTeleportFail"));
|
||||
}
|
||||
teleportee.getBase().eject();
|
||||
}
|
||||
|
||||
if (LocationUtil.isBlockUnsafeForUser(teleportee, loc.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) {
|
||||
if (ess.getSettings().isTeleportSafetyEnabled()) {
|
||||
if (ess.getSettings().isForceDisableTeleportSafety()) {
|
||||
PaperLib.teleportAsync(teleportee.getBase(), loc, cause);
|
||||
} else {
|
||||
PaperLib.teleportAsync(teleportee.getBase(), LocationUtil.getSafeDestination(ess, teleportee, loc), cause);
|
||||
}
|
||||
} else {
|
||||
throw new Exception(tl("unsafeTeleportDestination", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
}
|
||||
} else {
|
||||
if (ess.getSettings().isForceDisableTeleportSafety()) {
|
||||
PaperLib.teleportAsync(teleportee.getBase(), loc, cause);
|
||||
} else {
|
||||
if (ess.getSettings().isTeleportToCenterLocation()) {
|
||||
loc = LocationUtil.getRoundedDestination(loc);
|
||||
}
|
||||
PaperLib.teleportAsync(teleportee.getBase(), loc, cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//The teleportPlayer function is used when you want to normally teleportPlayer someone to a location or player.
|
||||
//This method is nolonger used internally and will be removed.
|
||||
@Deprecated
|
||||
@Override
|
||||
public void teleport(final Location loc, final Trade chargeFor) throws Exception {
|
||||
teleport(loc, chargeFor, TeleportCause.PLUGIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void teleport(final Location loc, final Trade chargeFor, final TeleportCause cause) throws Exception {
|
||||
teleport(teleportOwner, new LocationTarget(loc), chargeFor, cause);
|
||||
}
|
||||
|
||||
//This is used when teleporting to a player
|
||||
@Override
|
||||
@Deprecated
|
||||
public void teleport(final Player entity, final Trade chargeFor, final TeleportCause cause) throws Exception {
|
||||
final ITarget target = new PlayerTarget(entity);
|
||||
teleportOwner.sendMessage(tl("teleportToPlayer", entity.getDisplayName()));
|
||||
teleport(teleportOwner, target, chargeFor, cause);
|
||||
}
|
||||
|
||||
//This is used when teleporting to stored location
|
||||
@Override
|
||||
@Deprecated
|
||||
public void teleportPlayer(final IUser teleportee, final Location loc, final Trade chargeFor, final TeleportCause cause) throws Exception {
|
||||
teleport(teleportee, new LocationTarget(loc), chargeFor, cause);
|
||||
}
|
||||
|
||||
//This is used on /tphere
|
||||
@Override
|
||||
@Deprecated
|
||||
public void teleportPlayer(final IUser teleportee, final Player entity, final Trade chargeFor, final TeleportCause cause) throws Exception {
|
||||
final ITarget target = new PlayerTarget(entity);
|
||||
teleport(teleportee, target, chargeFor, cause);
|
||||
teleportee.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
|
||||
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private void teleport(final IUser teleportee, final ITarget target, final Trade chargeFor, final TeleportCause cause) throws Exception {
|
||||
double delay = ess.getSettings().getTeleportDelay();
|
||||
|
||||
final TeleportWarmupEvent event = new TeleportWarmupEvent(teleportee, cause, target, delay);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
delay = event.getDelay();
|
||||
|
||||
Trade cashCharge = chargeFor;
|
||||
|
||||
if (chargeFor != null) {
|
||||
chargeFor.isAffordableFor(teleportOwner);
|
||||
|
||||
//This code is to make sure that commandcosts are checked in the initial world, and not in the resulting world.
|
||||
if (!chargeFor.getCommandCost(teleportOwner).equals(BigDecimal.ZERO)) {
|
||||
//By converting a command cost to a regular cost, the command cost permission isn't checked when executing the charge after teleport.
|
||||
cashCharge = new Trade(chargeFor.getCommandCost(teleportOwner), ess);
|
||||
}
|
||||
}
|
||||
|
||||
cooldown(true);
|
||||
if (delay <= 0 || teleportOwner.isAuthorized("essentials.teleport.timer.bypass") || teleportee.isAuthorized("essentials.teleport.timer.bypass")) {
|
||||
cooldown(false);
|
||||
now(teleportee, target, cause);
|
||||
if (cashCharge != null) {
|
||||
cashCharge.charge(teleportOwner);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cancel(false);
|
||||
warnUser(teleportee, delay);
|
||||
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private void teleportOther(final IUser teleporter, final IUser teleportee, final ITarget target, final Trade chargeFor, final TeleportCause cause) throws Exception {
|
||||
double delay = ess.getSettings().getTeleportDelay();
|
||||
|
||||
final TeleportWarmupEvent event = new TeleportWarmupEvent(teleporter, teleportee, cause, target, delay);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
delay = event.getDelay();
|
||||
|
||||
Trade cashCharge = chargeFor;
|
||||
|
||||
if (teleporter != null && chargeFor != null) {
|
||||
chargeFor.isAffordableFor(teleporter);
|
||||
|
||||
//This code is to make sure that commandcosts are checked in the initial world, and not in the resulting world.
|
||||
if (!chargeFor.getCommandCost(teleporter).equals(BigDecimal.ZERO)) {
|
||||
//By converting a command cost to a regular cost, the command cost permission isn't checked when executing the charge after teleport.
|
||||
cashCharge = new Trade(chargeFor.getCommandCost(teleporter), ess);
|
||||
}
|
||||
}
|
||||
|
||||
cooldown(true);
|
||||
if (delay <= 0 || teleporter == null
|
||||
|| teleporter.isAuthorized("essentials.teleport.timer.bypass")
|
||||
|| teleportOwner.isAuthorized("essentials.teleport.timer.bypass")
|
||||
|| teleportee.isAuthorized("essentials.teleport.timer.bypass")) {
|
||||
cooldown(false);
|
||||
now(teleportee, target, cause);
|
||||
if (teleporter != null && cashCharge != null) {
|
||||
cashCharge.charge(teleporter);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cancel(false);
|
||||
warnUser(teleportee, delay);
|
||||
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false);
|
||||
}
|
||||
|
||||
//The respawn function is a wrapper used to handle tp fallback, on /jail and /home
|
||||
@Override
|
||||
@Deprecated
|
||||
public void respawn(final Trade chargeFor, final TeleportCause cause) throws Exception {
|
||||
double delay = ess.getSettings().getTeleportDelay();
|
||||
|
||||
final TeleportWarmupEvent event = new TeleportWarmupEvent(teleportOwner, cause, null, delay);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
delay = event.getDelay();
|
||||
|
||||
if (chargeFor != null) {
|
||||
chargeFor.isAffordableFor(teleportOwner);
|
||||
}
|
||||
cooldown(true);
|
||||
if (delay <= 0 || teleportOwner.isAuthorized("essentials.teleport.timer.bypass")) {
|
||||
cooldown(false);
|
||||
respawnNow(teleportOwner, cause);
|
||||
if (chargeFor != null) {
|
||||
chargeFor.charge(teleportOwner);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cancel(false);
|
||||
warnUser(teleportOwner, delay);
|
||||
initTimer((long) (delay * 1000.0), teleportOwner, null, chargeFor, cause, true);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
void respawnNow(final IUser teleportee, final TeleportCause cause) throws Exception {
|
||||
final Player player = teleportee.getBase();
|
||||
final Location bed = player.getBedSpawnLocation();
|
||||
if (bed != null) {
|
||||
now(teleportee, new LocationTarget(bed), cause);
|
||||
} else {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info("Could not find bed spawn, forcing respawn event.");
|
||||
}
|
||||
final PlayerRespawnEvent pre = new PlayerRespawnEvent(player, player.getWorld().getSpawnLocation(), false);
|
||||
ess.getServer().getPluginManager().callEvent(pre);
|
||||
now(teleportee, new LocationTarget(pre.getRespawnLocation()), cause);
|
||||
}
|
||||
}
|
||||
|
||||
//The warp function is a wrapper used to teleportPlayer a player to a /warp
|
||||
@Override
|
||||
@Deprecated
|
||||
public void warp(final IUser teleportee, String warp, final Trade chargeFor, final TeleportCause cause) throws Exception {
|
||||
final UserWarpEvent event = new UserWarpEvent(teleportee, warp, chargeFor);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
warp = event.getWarp();
|
||||
final Location loc = ess.getWarps().getWarp(warp);
|
||||
teleportee.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
if (!teleportee.equals(teleportOwner)) {
|
||||
teleportOwner.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
}
|
||||
teleport(teleportee, new LocationTarget(loc), chargeFor, cause);
|
||||
}
|
||||
|
||||
//The back function is a wrapper used to teleportPlayer a player /back to their previous location.
|
||||
@Override
|
||||
@Deprecated
|
||||
public void back(final Trade chargeFor) throws Exception {
|
||||
back(teleportOwner, chargeFor);
|
||||
}
|
||||
|
||||
//This function is a wrapper over the other back function for cases where another player performs back for them
|
||||
@Override
|
||||
@Deprecated
|
||||
public void back(final IUser teleporter, final Trade chargeFor) throws Exception {
|
||||
tpType = TeleportType.BACK;
|
||||
final Location loc = teleportOwner.getLastLocation();
|
||||
teleportOwner.sendMessage(tl("backUsageMsg", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
teleportOther(teleporter, teleportOwner, new LocationTarget(loc), chargeFor, TeleportCause.COMMAND);
|
||||
}
|
||||
|
||||
//This function is used to throw a user back after a jail sentence
|
||||
@Override
|
||||
@Deprecated
|
||||
public void back() throws Exception {
|
||||
now(teleportOwner, new LocationTarget(teleportOwner.getLastLocation()), TeleportCause.COMMAND);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setTpType(final TeleportType tpType) {
|
||||
this.tpType = tpType;
|
||||
}
|
||||
|
||||
//If we need to cancelTimer a pending teleportPlayer call this method
|
||||
@Deprecated
|
||||
private void cancel(final boolean notifyUser) {
|
||||
if (timedTeleport != null) {
|
||||
timedTeleport.cancelTimer(notifyUser);
|
||||
timedTeleport = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private void initTimer(final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) {
|
||||
timedTeleport = new TimedTeleport(teleportOwner, ess, this, delay, teleportUser, target, chargeFor, cause, respawn);
|
||||
}
|
||||
|
||||
public enum TeleportType {
|
||||
TPA,
|
||||
BACK,
|
||||
NORMAL
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.IUser;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
@Deprecated
|
||||
public class TimedTeleport implements Runnable {
|
||||
private static final double MOVE_CONSTANT = 0.3;
|
||||
private final IUser teleportOwner;
|
||||
private final IEssentials ess;
|
||||
private final Teleport teleport;
|
||||
private final UUID timer_teleportee;
|
||||
private final long timer_started; // time this task was initiated
|
||||
private final long timer_delay; // how long to delay the teleportPlayer
|
||||
// note that I initially stored a clone of the location for reference, but...
|
||||
// when comparing locations, I got incorrect mismatches (rounding errors, looked like)
|
||||
// so, the X/Y/Z values are stored instead and rounded off
|
||||
private final long timer_initX;
|
||||
private final long timer_initY;
|
||||
private final long timer_initZ;
|
||||
private final ITarget timer_teleportTarget;
|
||||
private final boolean timer_respawn;
|
||||
private final boolean timer_canMove;
|
||||
private final Trade timer_chargeFor;
|
||||
private final TeleportCause timer_cause;
|
||||
private int timer_task;
|
||||
private double timer_health;
|
||||
|
||||
TimedTeleport(final IUser user, final IEssentials ess, final Teleport teleport, final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) {
|
||||
this.teleportOwner = user;
|
||||
this.ess = ess;
|
||||
this.teleport = teleport;
|
||||
this.timer_started = System.currentTimeMillis();
|
||||
this.timer_delay = delay;
|
||||
this.timer_health = teleportUser.getBase().getHealth();
|
||||
this.timer_initX = Math.round(teleportUser.getBase().getLocation().getX() * MOVE_CONSTANT);
|
||||
this.timer_initY = Math.round(teleportUser.getBase().getLocation().getY() * MOVE_CONSTANT);
|
||||
this.timer_initZ = Math.round(teleportUser.getBase().getLocation().getZ() * MOVE_CONSTANT);
|
||||
this.timer_teleportee = teleportUser.getBase().getUniqueId();
|
||||
this.timer_teleportTarget = target;
|
||||
this.timer_chargeFor = chargeFor;
|
||||
this.timer_cause = cause;
|
||||
this.timer_respawn = respawn;
|
||||
this.timer_canMove = user.isAuthorized("essentials.teleport.timer.move");
|
||||
|
||||
timer_task = ess.runTaskTimerAsynchronously(this, 20, 20).getTaskId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
if (teleportOwner == null || !teleportOwner.getBase().isOnline() || teleportOwner.getBase().getLocation() == null) {
|
||||
cancelTimer(false);
|
||||
return;
|
||||
}
|
||||
|
||||
final IUser teleportUser = ess.getUser(this.timer_teleportee);
|
||||
|
||||
if (teleportUser == null || !teleportUser.getBase().isOnline()) {
|
||||
cancelTimer(false);
|
||||
return;
|
||||
}
|
||||
|
||||
final Location currLocation = teleportUser.getBase().getLocation();
|
||||
if (currLocation == null) {
|
||||
cancelTimer(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!timer_canMove && (Math.round(currLocation.getX() * MOVE_CONSTANT) != timer_initX || Math.round(currLocation.getY() * MOVE_CONSTANT) != timer_initY || Math.round(currLocation.getZ() * MOVE_CONSTANT) != timer_initZ || teleportUser.getBase().getHealth() < timer_health)) {
|
||||
// user moved, cancelTimer teleportPlayer
|
||||
cancelTimer(true);
|
||||
return;
|
||||
}
|
||||
|
||||
class DelayedTeleportTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
timer_health = teleportUser.getBase().getHealth(); // in case user healed, then later gets injured
|
||||
final long now = System.currentTimeMillis();
|
||||
if (now > timer_started + timer_delay) {
|
||||
try {
|
||||
teleport.cooldown(false);
|
||||
} catch (final Exception ex) {
|
||||
teleportOwner.sendMessage(tl("cooldownWithMessage", ex.getMessage()));
|
||||
if (teleportOwner != teleportUser) {
|
||||
teleportUser.sendMessage(tl("cooldownWithMessage", ex.getMessage()));
|
||||
}
|
||||
}
|
||||
try {
|
||||
cancelTimer(false);
|
||||
teleportUser.sendMessage(tl("teleportationCommencing"));
|
||||
|
||||
if (timer_chargeFor != null) {
|
||||
timer_chargeFor.isAffordableFor(teleportOwner);
|
||||
}
|
||||
if (timer_respawn) {
|
||||
teleport.respawnNow(teleportUser, timer_cause);
|
||||
} else {
|
||||
teleport.now(teleportUser, timer_teleportTarget, timer_cause);
|
||||
}
|
||||
if (timer_chargeFor != null) {
|
||||
timer_chargeFor.charge(teleportOwner);
|
||||
}
|
||||
|
||||
} catch (final Exception ex) {
|
||||
ess.showError(teleportOwner.getSource(), ex, "\\ teleport");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ess.scheduleSyncDelayedTask(new DelayedTeleportTask());
|
||||
}
|
||||
|
||||
//If we need to cancelTimer a pending teleportPlayer call this method
|
||||
void cancelTimer(final boolean notifyUser) {
|
||||
if (timer_task == -1) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ess.getServer().getScheduler().cancelTask(timer_task);
|
||||
if (notifyUser) {
|
||||
teleportOwner.sendMessage(tl("pendingTeleportCancelled"));
|
||||
if (timer_teleportee != null && !timer_teleportee.equals(teleportOwner.getBase().getUniqueId())) {
|
||||
ess.getUser(timer_teleportee).sendMessage(tl("pendingTeleportCancelled"));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
timer_task = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class UUIDMap {
|
||||
private static final ScheduledExecutorService writeScheduler = Executors.newScheduledThreadPool(1);
|
||||
private static boolean pendingWrite;
|
||||
private static boolean loading = false;
|
||||
private final transient net.ess3.api.IEssentials ess;
|
||||
private final File userList;
|
||||
private final transient Pattern splitPattern = Pattern.compile(",");
|
||||
private final Runnable writeTaskRunnable;
|
||||
|
||||
public UUIDMap(final net.ess3.api.IEssentials ess) {
|
||||
this.ess = ess;
|
||||
userList = new File(ess.getDataFolder(), "usermap.csv");
|
||||
pendingWrite = false;
|
||||
writeTaskRunnable = () -> {
|
||||
if (pendingWrite) {
|
||||
try {
|
||||
new WriteRunner(ess.getDataFolder(), userList, ess.getUserMap().getNames()).run();
|
||||
} catch (final Throwable t) { // bad code to prevent task from being suppressed
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
writeScheduler.scheduleWithFixedDelay(writeTaskRunnable, 5, 5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public void loadAllUsers(final ConcurrentSkipListMap<String, UUID> names, final ConcurrentSkipListMap<UUID, ArrayList<String>> history) {
|
||||
try {
|
||||
if (!userList.exists()) {
|
||||
userList.createNewFile();
|
||||
}
|
||||
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().log(Level.INFO, "Reading usermap from disk");
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
names.clear();
|
||||
history.clear();
|
||||
loading = true;
|
||||
|
||||
try (final BufferedReader reader = new BufferedReader(new FileReader(userList))) {
|
||||
while (true) {
|
||||
final String line = reader.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
} else {
|
||||
final String[] values = splitPattern.split(line);
|
||||
if (values.length == 2) {
|
||||
final String name = values[0];
|
||||
final UUID uuid = UUID.fromString(values[1]);
|
||||
names.put(name, uuid);
|
||||
if (!history.containsKey(uuid)) {
|
||||
final ArrayList<String> list = new ArrayList<>();
|
||||
list.add(name);
|
||||
history.put(uuid, list);
|
||||
} else {
|
||||
final ArrayList<String> list = history.get(uuid);
|
||||
if (!list.contains(name)) {
|
||||
list.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
loading = false;
|
||||
} catch (final IOException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeUUIDMap() {
|
||||
pendingWrite = true;
|
||||
}
|
||||
|
||||
public void forceWriteUUIDMap() {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().log(Level.INFO, "Forcing usermap write to disk");
|
||||
}
|
||||
pendingWrite = true;
|
||||
writeTaskRunnable.run();
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
writeScheduler.submit(writeTaskRunnable);
|
||||
writeScheduler.shutdown();
|
||||
}
|
||||
|
||||
private static final class WriteRunner implements Runnable {
|
||||
private final File location;
|
||||
private final File endFile;
|
||||
private final Map<String, UUID> names;
|
||||
|
||||
private WriteRunner(final File location, final File endFile, final Map<String, UUID> names) {
|
||||
this.location = location;
|
||||
this.endFile = endFile;
|
||||
this.names = new HashMap<>(names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
pendingWrite = false;
|
||||
if (loading || names.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
File configFile = null;
|
||||
|
||||
try {
|
||||
configFile = File.createTempFile("usermap", ".tmp.csv", location);
|
||||
|
||||
final BufferedWriter bWriter = new BufferedWriter(new FileWriter(configFile));
|
||||
for (final Map.Entry<String, UUID> entry : names.entrySet()) {
|
||||
bWriter.write(entry.getKey() + "," + entry.getValue().toString());
|
||||
bWriter.newLine();
|
||||
}
|
||||
|
||||
bWriter.close();
|
||||
Files.move(configFile, endFile);
|
||||
} catch (final IOException ex) {
|
||||
try {
|
||||
if (configFile != null && configFile.exists()) {
|
||||
Files.move(configFile, new File(endFile.getParentFile(), "usermap.bak.csv"));
|
||||
}
|
||||
} catch (final Exception ex2) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, ex2.getMessage(), ex2);
|
||||
}
|
||||
Bukkit.getLogger().log(Level.WARNING, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,313 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.utils.StringUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class UserMap extends CacheLoader<String, User> implements IConf {
|
||||
private static boolean legacy = false;
|
||||
private static Method getLegacy;
|
||||
private final transient IEssentials ess;
|
||||
private final transient ConcurrentSkipListSet<UUID> keys = new ConcurrentSkipListSet<>();
|
||||
private final transient ConcurrentSkipListMap<String, UUID> names = new ConcurrentSkipListMap<>();
|
||||
private final transient ConcurrentSkipListMap<UUID, ArrayList<String>> history = new ConcurrentSkipListMap<>();
|
||||
private final UUIDMap uuidMap;
|
||||
private final transient Cache<String, User> users;
|
||||
private final Pattern validUserPattern = Pattern.compile("^[a-zA-Z0-9_]{2,16}$");
|
||||
|
||||
public UserMap(final IEssentials ess) {
|
||||
super();
|
||||
this.ess = ess;
|
||||
uuidMap = new UUIDMap(ess);
|
||||
//RemovalListener<UUID, User> remListener = new UserMapRemovalListener();
|
||||
//users = CacheBuilder.newBuilder().maximumSize(ess.getSettings().getMaxUserCacheCount()).softValues().removalListener(remListener).build(this);
|
||||
final CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder();
|
||||
final int maxCount = ess.getSettings().getMaxUserCacheCount();
|
||||
try {
|
||||
cacheBuilder.maximumSize(maxCount);
|
||||
} catch (final NoSuchMethodError nsme) {
|
||||
legacy = true;
|
||||
legacyMaximumSize(cacheBuilder, maxCount);
|
||||
}
|
||||
cacheBuilder.softValues();
|
||||
if (!legacy) {
|
||||
users = cacheBuilder.build(this);
|
||||
} else {
|
||||
users = legacyBuild(cacheBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadAllUsersAsync(final IEssentials ess) {
|
||||
ess.runTaskAsynchronously(() -> {
|
||||
synchronized (users) {
|
||||
final File userdir = new File(ess.getDataFolder(), "userdata");
|
||||
if (!userdir.exists()) {
|
||||
return;
|
||||
}
|
||||
keys.clear();
|
||||
users.invalidateAll();
|
||||
for (final String string : userdir.list()) {
|
||||
if (!string.endsWith(".yml")) {
|
||||
continue;
|
||||
}
|
||||
final String name = string.substring(0, string.length() - 4);
|
||||
try {
|
||||
keys.add(UUID.fromString(name));
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
//Ignore these users till they rejoin.
|
||||
}
|
||||
}
|
||||
uuidMap.loadAllUsers(names, history);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean userExists(final UUID uuid) {
|
||||
return keys.contains(uuid);
|
||||
}
|
||||
|
||||
public User getUser(final String name) {
|
||||
try {
|
||||
final String sanitizedName = StringUtil.safeString(name);
|
||||
if (names.containsKey(sanitizedName)) {
|
||||
final UUID uuid = names.get(sanitizedName);
|
||||
return getUser(uuid);
|
||||
}
|
||||
|
||||
final File userFile = getUserFileFromString(sanitizedName);
|
||||
if (userFile.exists()) {
|
||||
ess.getLogger().info("Importing user " + name + " to usermap.");
|
||||
final User user = new User(new OfflinePlayer(sanitizedName, ess.getServer()), ess);
|
||||
trackUUID(user.getBase().getUniqueId(), user.getName(), true);
|
||||
return user;
|
||||
}
|
||||
return null;
|
||||
} catch (final UncheckedExecutionException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public User getUser(final UUID uuid) {
|
||||
try {
|
||||
if (!legacy) {
|
||||
return ((LoadingCache<String, User>) users).get(uuid.toString());
|
||||
} else {
|
||||
return legacyCacheGet(uuid);
|
||||
}
|
||||
} catch (final ExecutionException | UncheckedExecutionException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void trackUUID(final UUID uuid, final String name, final boolean replace) {
|
||||
if (uuid != null) {
|
||||
keys.add(uuid);
|
||||
if (name != null && name.length() > 0) {
|
||||
final String keyName = ess.getSettings().isSafeUsermap() ? StringUtil.safeString(name) : name;
|
||||
if (!names.containsKey(keyName)) {
|
||||
names.put(keyName, uuid);
|
||||
uuidMap.writeUUIDMap();
|
||||
} else if (!names.get(keyName).equals(uuid)) {
|
||||
if (replace) {
|
||||
ess.getLogger().info("Found new UUID for " + name + ". Replacing " + names.get(keyName).toString() + " with " + uuid.toString());
|
||||
names.put(keyName, uuid);
|
||||
uuidMap.writeUUIDMap();
|
||||
} else {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info("Found old UUID for " + name + " (" + uuid.toString() + "). Not adding to usermap.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public User load(final String stringUUID) throws Exception {
|
||||
final UUID uuid = UUID.fromString(stringUUID);
|
||||
Player player = ess.getServer().getPlayer(uuid);
|
||||
if (player != null) {
|
||||
final User user = new User(player, ess);
|
||||
trackUUID(uuid, user.getName(), true);
|
||||
return user;
|
||||
}
|
||||
|
||||
final File userFile = getUserFileFromID(uuid);
|
||||
|
||||
if (userFile.exists()) {
|
||||
player = new OfflinePlayer(uuid, ess.getServer());
|
||||
final User user = new User(player, ess);
|
||||
((OfflinePlayer) player).setName(user.getLastAccountName());
|
||||
trackUUID(uuid, user.getName(), false);
|
||||
return user;
|
||||
}
|
||||
|
||||
throw new Exception("User not found!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
getUUIDMap().forceWriteUUIDMap();
|
||||
loadAllUsersAsync(ess);
|
||||
}
|
||||
|
||||
public void invalidateAll() {
|
||||
users.invalidateAll();
|
||||
}
|
||||
|
||||
public void removeUser(final String name) {
|
||||
if (names == null) {
|
||||
ess.getLogger().warning("Name collection is null, cannot remove user.");
|
||||
return;
|
||||
}
|
||||
final UUID uuid = names.get(name);
|
||||
if (uuid != null) {
|
||||
keys.remove(uuid);
|
||||
users.invalidate(uuid.toString());
|
||||
}
|
||||
names.remove(name);
|
||||
names.remove(StringUtil.safeString(name));
|
||||
}
|
||||
|
||||
public Set<UUID> getAllUniqueUsers() {
|
||||
return Collections.unmodifiableSet(keys);
|
||||
}
|
||||
|
||||
public int getUniqueUsers() {
|
||||
return keys.size();
|
||||
}
|
||||
|
||||
protected ConcurrentSkipListMap<String, UUID> getNames() {
|
||||
return names;
|
||||
}
|
||||
|
||||
protected ConcurrentSkipListMap<UUID, ArrayList<String>> getHistory() {
|
||||
return history;
|
||||
}
|
||||
|
||||
public List<String> getUserHistory(final UUID uuid) {
|
||||
return history.get(uuid);
|
||||
}
|
||||
|
||||
public UUIDMap getUUIDMap() {
|
||||
return uuidMap;
|
||||
}
|
||||
// class UserMapRemovalListener implements RemovalListener
|
||||
// {
|
||||
// @Override
|
||||
// public void onRemoval(final RemovalNotification notification)
|
||||
// {
|
||||
// Object value = notification.getValue();
|
||||
// if (value != null)
|
||||
// {
|
||||
// ((User)value).cleanup();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
private File getUserFileFromID(final UUID uuid) {
|
||||
final File userFolder = new File(ess.getDataFolder(), "userdata");
|
||||
return new File(userFolder, uuid.toString() + ".yml");
|
||||
}
|
||||
|
||||
public File getUserFileFromString(final String name) {
|
||||
final File userFolder = new File(ess.getDataFolder(), "userdata");
|
||||
return new File(userFolder, StringUtil.sanitizeFileName(name) + ".yml");
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public User getUserFromBukkit(String name) {
|
||||
name = StringUtil.safeString(name);
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().warning("Using potentially blocking Bukkit UUID lookup for: " + name);
|
||||
}
|
||||
// Don't attempt to look up entirely invalid usernames
|
||||
if (name == null || !validUserPattern.matcher(name).matches()) {
|
||||
return null;
|
||||
}
|
||||
final org.bukkit.OfflinePlayer offlinePlayer = ess.getServer().getOfflinePlayer(name);
|
||||
if (offlinePlayer == null) {
|
||||
return null;
|
||||
}
|
||||
final UUID uuid;
|
||||
try {
|
||||
uuid = offlinePlayer.getUniqueId();
|
||||
} catch (final UnsupportedOperationException | NullPointerException e) {
|
||||
return null;
|
||||
}
|
||||
// This is how Bukkit generates fake UUIDs
|
||||
if (UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)).equals(uuid)) {
|
||||
return null;
|
||||
} else {
|
||||
names.put(name, uuid);
|
||||
return getUser(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
private User legacyCacheGet(final UUID uuid) {
|
||||
if (getLegacy == null) {
|
||||
final Class<?> usersClass = users.getClass();
|
||||
for (final Method m : usersClass.getDeclaredMethods()) {
|
||||
if (m.getName().equals("get")) {
|
||||
getLegacy = m;
|
||||
getLegacy.setAccessible(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
return (User) getLegacy.invoke(users, uuid.toString());
|
||||
} catch (final IllegalAccessException | InvocationTargetException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void legacyMaximumSize(final CacheBuilder builder, final int maxCount) {
|
||||
try {
|
||||
final Method maxSizeLegacy = builder.getClass().getDeclaredMethod("maximumSize", Integer.TYPE);
|
||||
maxSizeLegacy.setAccessible(true);
|
||||
maxSizeLegacy.invoke(builder, maxCount);
|
||||
} catch (final NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Cache<String, User> legacyBuild(final CacheBuilder builder) {
|
||||
Method build = null;
|
||||
for (final Method method : builder.getClass().getDeclaredMethods()) {
|
||||
if (method.getName().equals("build")) {
|
||||
build = method;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Cache<String, User> legacyUsers;
|
||||
try {
|
||||
assert build != null;
|
||||
build.setAccessible(true);
|
||||
legacyUsers = (Cache<String, User>) build.invoke(builder, this);
|
||||
} catch (final IllegalAccessException | InvocationTargetException e) {
|
||||
legacyUsers = null;
|
||||
}
|
||||
return legacyUsers;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.earth2me.essentials.api;
|
||||
|
||||
/**
|
||||
* Represents a storage object that is reloadable.
|
||||
*
|
||||
* @deprecated This is a remnant of the abandoned 3.x storage system. Neither future 2.x code nor external plugins
|
||||
* should use this interface.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface IReload {
|
||||
/**
|
||||
* Reloads the given storage object.
|
||||
*/
|
||||
void onReload();
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.textreader.SimpleTextInput;
|
||||
import com.earth2me.essentials.textreader.TextPager;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandbalancetop extends EssentialsCommand {
|
||||
public static final int MINUSERS = 50;
|
||||
private static final int CACHETIME = 2 * 60 * 1000;
|
||||
private static final SimpleTextInput cache = new SimpleTextInput();
|
||||
private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private static long cacheage = 0;
|
||||
|
||||
public Commandbalancetop() {
|
||||
super("balancetop");
|
||||
}
|
||||
|
||||
private static void outputCache(final CommandSource sender, final int page) {
|
||||
final Calendar cal = Calendar.getInstance();
|
||||
cal.setTimeInMillis(cacheage);
|
||||
final DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
|
||||
sender.sendMessage(tl("balanceTop", format.format(cal.getTime())));
|
||||
new TextPager(cache).showPage(Integer.toString(page), null, "balancetop", sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
int page = 0;
|
||||
boolean force = false;
|
||||
if (args.length > 0) {
|
||||
try {
|
||||
page = Integer.parseInt(args[0]);
|
||||
} catch (final NumberFormatException ex) {
|
||||
if (args[0].equalsIgnoreCase("force") && (!sender.isPlayer() || ess.getUser(sender.getPlayer()).isAuthorized("essentials.balancetop.force"))) {
|
||||
force = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!force && lock.readLock().tryLock()) {
|
||||
try {
|
||||
if (cacheage > System.currentTimeMillis() - CACHETIME) {
|
||||
outputCache(sender, page);
|
||||
return;
|
||||
}
|
||||
if (ess.getUserMap().getUniqueUsers() > MINUSERS) {
|
||||
sender.sendMessage(tl("orderBalances", ess.getUserMap().getUniqueUsers()));
|
||||
}
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
} else {
|
||||
if (ess.getUserMap().getUniqueUsers() > MINUSERS) {
|
||||
sender.sendMessage(tl("orderBalances", ess.getUserMap().getUniqueUsers()));
|
||||
}
|
||||
}
|
||||
ess.runTaskAsynchronously(new Viewer(sender, commandLabel, page, force));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
final List<String> options = Lists.newArrayList("1");
|
||||
if (!sender.isPlayer() || ess.getUser(sender.getPlayer()).isAuthorized("essentials.balancetop.force")) {
|
||||
options.add("force");
|
||||
}
|
||||
return options;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private class Calculator implements Runnable {
|
||||
private final transient Viewer viewer;
|
||||
private final boolean force;
|
||||
|
||||
Calculator(final Viewer viewer, final boolean force) {
|
||||
this.viewer = viewer;
|
||||
this.force = force;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
if (force || cacheage <= System.currentTimeMillis() - CACHETIME) {
|
||||
cache.getLines().clear();
|
||||
final Map<String, BigDecimal> balances = new HashMap<>();
|
||||
BigDecimal totalMoney = BigDecimal.ZERO;
|
||||
if (ess.getSettings().isEcoDisabled()) {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info("Internal economy functions disabled, aborting baltop.");
|
||||
}
|
||||
} else {
|
||||
for (final UUID u : ess.getUserMap().getAllUniqueUsers()) {
|
||||
final User user = ess.getUserMap().getUser(u);
|
||||
if (user != null) {
|
||||
if (!ess.getSettings().isNpcsInBalanceRanking() && user.isNPC()) {
|
||||
// Don't list NPCs in output
|
||||
continue;
|
||||
}
|
||||
if (!user.isAuthorized("essentials.balancetop.exclude")) {
|
||||
final BigDecimal userMoney = user.getMoney();
|
||||
user.updateMoneyCache(userMoney);
|
||||
totalMoney = totalMoney.add(userMoney);
|
||||
final String name = user.isHidden() ? user.getName() : user.getDisplayName();
|
||||
balances.put(name, userMoney);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final List<Map.Entry<String, BigDecimal>> sortedEntries = new ArrayList<>(balances.entrySet());
|
||||
sortedEntries.sort((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue()));
|
||||
|
||||
cache.getLines().add(tl("serverTotal", NumberUtil.displayCurrency(totalMoney, ess)));
|
||||
int pos = 1;
|
||||
for (final Map.Entry<String, BigDecimal> entry : sortedEntries) {
|
||||
cache.getLines().add(tl("balanceTopLine", pos, entry.getKey(), NumberUtil.displayCurrency(entry.getValue(), ess)));
|
||||
pos++;
|
||||
}
|
||||
cacheage = System.currentTimeMillis();
|
||||
}
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
ess.runTaskAsynchronously(viewer);
|
||||
}
|
||||
}
|
||||
|
||||
private class Viewer implements Runnable {
|
||||
private final transient CommandSource sender;
|
||||
private final transient int page;
|
||||
private final transient boolean force;
|
||||
private final transient String commandLabel;
|
||||
|
||||
Viewer(final CommandSource sender, final String commandLabel, final int page, final boolean force) {
|
||||
this.sender = sender;
|
||||
this.page = page;
|
||||
this.force = force;
|
||||
this.commandLabel = commandLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
if (!force && cacheage > System.currentTimeMillis() - CACHETIME) {
|
||||
outputCache(sender, page);
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
ess.runTaskAsynchronously(new Calculator(new Viewer(sender, commandLabel, page, false), force));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.MemoryConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConstructor;
|
||||
import org.bukkit.configuration.file.YamlRepresenter;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.representer.Representer;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandcreatekit extends EssentialsCommand {
|
||||
|
||||
private static final String PASTE_URL = "https://hastebin.com/";
|
||||
private static final String PASTE_UPLOAD_URL = PASTE_URL + "documents";
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||
private final DumperOptions yamlOptions = new DumperOptions();
|
||||
private final Representer yamlRepresenter = new YamlRepresenter();
|
||||
private final YamlConstructor yamlConstructor = new YamlConstructor();
|
||||
|
||||
public Commandcreatekit() {
|
||||
super("createkit");
|
||||
yamlOptions.setDefaultFlowStyle(FlowStyle.BLOCK);
|
||||
yamlRepresenter.setDefaultFlowStyle(FlowStyle.BLOCK);
|
||||
}
|
||||
|
||||
// /createkit <name> <delay>
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length != 2) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
// Command handler will auto fail if this fails.
|
||||
final long delay = Long.parseLong(args[1]);
|
||||
final String kitname = args[0];
|
||||
final ItemStack[] items = user.getBase().getInventory().getContents();
|
||||
final List<String> list = new ArrayList<>();
|
||||
for (final ItemStack is : items) {
|
||||
if (is != null && is.getType() != null && is.getType() != Material.AIR) {
|
||||
final String serialized = ess.getItemDb().serialize(is);
|
||||
list.add(serialized);
|
||||
}
|
||||
}
|
||||
// Some users might want to directly write to config knowing the consequences. *shrug*
|
||||
if (!ess.getSettings().isPastebinCreateKit()) {
|
||||
ess.getKits().addKit(kitname, list, delay);
|
||||
user.sendMessage(tl("createdKit", kitname, list.size(), delay));
|
||||
} else {
|
||||
final ConfigurationSection config = new MemoryConfiguration();
|
||||
config.set("kits." + kitname + ".delay", delay);
|
||||
config.set("kits." + kitname + ".items", list);
|
||||
|
||||
final Yaml yaml = new Yaml(yamlConstructor, yamlRepresenter, yamlOptions);
|
||||
String fileContents = "# Copy the kit code below into the kits section in your config.yml file\n";
|
||||
fileContents += yaml.dump(config.getValues(false));
|
||||
|
||||
uploadPaste(user.getSource(), kitname, delay, fileContents);
|
||||
}
|
||||
}
|
||||
|
||||
private void uploadPaste(final CommandSource sender, final String kitName, final long delay, final String contents) {
|
||||
executorService.submit(() -> {
|
||||
try {
|
||||
final HttpURLConnection connection = (HttpURLConnection) new URL(PASTE_UPLOAD_URL).openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
connection.setRequestProperty("User-Agent", "EssentialsX plugin");
|
||||
try (final OutputStream os = connection.getOutputStream()) {
|
||||
os.write(contents.getBytes(Charsets.UTF_8));
|
||||
}
|
||||
// Error
|
||||
if (connection.getResponseCode() >= 400) {
|
||||
sender.sendMessage(tl("createKitFailed", kitName));
|
||||
final String message = CharStreams.toString(new InputStreamReader(connection.getErrorStream(), Charsets.UTF_8));
|
||||
ess.getLogger().severe("Error creating kit: " + message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Read URL
|
||||
final JsonObject object = GSON.fromJson(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8), JsonObject.class);
|
||||
final String pasteUrl = PASTE_URL + object.get("key").getAsString();
|
||||
connection.disconnect();
|
||||
|
||||
final String separator = tl("createKitSeparator");
|
||||
String delayFormat = "0";
|
||||
if (delay > 0) {
|
||||
delayFormat = DateUtil.formatDateDiff(System.currentTimeMillis() + (delay * 1000));
|
||||
}
|
||||
sender.sendMessage(separator);
|
||||
sender.sendMessage(tl("createKitSuccess", kitName, delayFormat, pasteUrl));
|
||||
sender.sendMessage(separator);
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info(sender.getSender().getName() + " created a kit: " + pasteUrl);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
sender.sendMessage(tl("createKitFailed", kitName));
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commanddelwarp extends EssentialsCommand {
|
||||
public Commanddelwarp() {
|
||||
super("delwarp");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length == 0) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
ess.getWarps().removeWarp(args[0]);
|
||||
sender.sendMessage(tl("deleteWarp", args[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
return new ArrayList<>(ess.getWarps().getList());
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.Sign;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandeditsign extends EssentialsCommand {
|
||||
public Commandeditsign() {
|
||||
super("editsign");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length == 0 || (args.length > 1 && !NumberUtil.isInt(args[1]))) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
final Block target = user.getTargetBlock(5); //5 is a good number
|
||||
if (!(target.getState() instanceof Sign)) {
|
||||
throw new Exception(tl("editsignCommandTarget"));
|
||||
}
|
||||
final Sign sign = (Sign) target.getState();
|
||||
try {
|
||||
if (args[0].equalsIgnoreCase("set") && args.length > 2) {
|
||||
final int line = Integer.parseInt(args[1]) - 1;
|
||||
final String text = FormatUtil.formatString(user, "essentials.editsign", getFinalArg(args, 2)).trim();
|
||||
if (ChatColor.stripColor(text).length() > 15 && !user.isAuthorized("essentials.editsign.unlimited")) {
|
||||
throw new Exception(tl("editsignCommandLimit"));
|
||||
}
|
||||
sign.setLine(line, text);
|
||||
sign.update();
|
||||
user.sendMessage(tl("editsignCommandSetSuccess", line + 1, text));
|
||||
} else if (args[0].equalsIgnoreCase("clear")) {
|
||||
if (args.length == 1) {
|
||||
for (int i = 0; i < 4; i++) { // A whole one line of line savings!
|
||||
sign.setLine(i, "");
|
||||
}
|
||||
sign.update();
|
||||
user.sendMessage(tl("editsignCommandClear"));
|
||||
} else {
|
||||
final int line = Integer.parseInt(args[1]) - 1;
|
||||
sign.setLine(line, "");
|
||||
sign.update();
|
||||
user.sendMessage(tl("editsignCommandClearLine", line + 1));
|
||||
}
|
||||
} else {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
} catch (final IndexOutOfBoundsException e) {
|
||||
throw new Exception(tl("editsignCommandNoLine"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
return Lists.newArrayList("set", "clear");
|
||||
} else if (args.length == 2) {
|
||||
return Lists.newArrayList("1", "2", "3", "4");
|
||||
} else if (args.length == 3 && args[0].equalsIgnoreCase("set") && NumberUtil.isPositiveInt(args[1])) {
|
||||
final int line = Integer.parseInt(args[1]);
|
||||
final Block target = user.getTargetBlock(5);
|
||||
if (target.getState() instanceof Sign && line <= 4) {
|
||||
final Sign sign = (Sign) target.getState();
|
||||
return Lists.newArrayList(FormatUtil.unformatString(user, "essentials.editsign", sign.getLine(line - 1)));
|
||||
}
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,492 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.EssentialsUpgrade;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.UserMap;
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
import com.earth2me.essentials.utils.EnumUtil;
|
||||
import com.earth2me.essentials.utils.FloatUtil;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import com.earth2me.essentials.utils.VersionUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
// This command has 4 undocumented behaviours #EasterEgg
|
||||
public class Commandessentials extends EssentialsCommand {
|
||||
|
||||
private static final Sound NOTE_HARP = EnumUtil.valueOf(Sound.class, "BLOCK_NOTE_BLOCK_HARP", "BLOCK_NOTE_HARP", "NOTE_PIANO");
|
||||
private static final Sound MOO_SOUND = EnumUtil.valueOf(Sound.class, "COW_IDLE", "ENTITY_COW_MILK");
|
||||
|
||||
private static final String NYAN_TUNE = "1D#,1E,2F#,,2A#,1E,1D#,1E,2F#,2B,2D#,2E,2D#,2A#,2B,,2F#,,1D#,1E,2F#,2B,2C#,2A#,2B,2C#,2E,2D#,2E,2C#,,2F#,,2G#,,1D,1D#,,1C#,1D,1C#,1B,,1B,,1C#,,1D,,1D,1C#,1B,1C#,1D#,2F#,2G#,1D#,2F#,1C#,1D#,1B,1C#,1B,1D#,,2F#,,2G#,1D#,2F#,1C#,1D#,1B,1D,1D#,1D,1C#,1B,1C#,1D,,1B,1C#,1D#,2F#,1C#,1D,1C#,1B,1C#,,1B,,1C#,,2F#,,2G#,,1D,1D#,,1C#,1D,1C#,1B,,1B,,1C#,,1D,,1D,1C#,1B,1C#,1D#,2F#,2G#,1D#,2F#,1C#,1D#,1B,1C#,1B,1D#,,2F#,,2G#,1D#,2F#,1C#,1D#,1B,1D,1D#,1D,1C#,1B,1C#,1D,,1B,1C#,1D#,2F#,1C#,1D,1C#,1B,1C#,,1B,,1B,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1B,,";
|
||||
private static final String[] CONSOLE_MOO = new String[] {" (__)", " (oo)", " /------\\/", " / | ||", " * /\\---/\\", " ~~ ~~", "....\"Have you mooed today?\"..."};
|
||||
private static final String[] PLAYER_MOO = new String[] {" (__)", " (oo)", " /------\\/", " / | | |", " * /\\---/\\", " ~~ ~~", "....\"Have you mooed today?\"..."};
|
||||
private static final List<String> versionPlugins = Arrays.asList(
|
||||
"Vault", // API
|
||||
"Reserve", // API
|
||||
"PlaceholderAPI", // API
|
||||
"CMI", // potential for issues
|
||||
"Towny", // past issues; admins should ensure latest
|
||||
"ChestShop", // past issues; admins should ensure latest
|
||||
"Citizens", // fires player events
|
||||
"LuckPerms", // permissions (recommended)
|
||||
"UltraPermissions",
|
||||
"PermissionsEx", // permissions (unsupported)
|
||||
"GroupManager", // permissions (unsupported)
|
||||
"bPermissions" // permissions (unsupported)
|
||||
);
|
||||
private static final List<String> officialPlugins = Arrays.asList(
|
||||
"EssentialsAntiBuild",
|
||||
"EssentialsChat",
|
||||
"EssentialsGeoIP",
|
||||
"EssentialsProtect",
|
||||
"EssentialsSpawn",
|
||||
"EssentialsXMPP"
|
||||
);
|
||||
private static final List<String> warnPlugins = Arrays.asList(
|
||||
"PermissionsEx",
|
||||
"GroupManager",
|
||||
"bPremissions"
|
||||
);
|
||||
private transient TuneRunnable currentTune = null;
|
||||
|
||||
public Commandessentials() {
|
||||
super("essentials");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length == 0) {
|
||||
showUsage(sender);
|
||||
}
|
||||
|
||||
switch (args[0]) {
|
||||
// Info commands
|
||||
case "debug":
|
||||
case "verbose":
|
||||
runDebug(server, sender, commandLabel, args);
|
||||
break;
|
||||
|
||||
case "ver":
|
||||
case "version":
|
||||
runVersion(server, sender, commandLabel, args);
|
||||
break;
|
||||
|
||||
case "cmd":
|
||||
case "commands":
|
||||
runCommands(server, sender, commandLabel, args);
|
||||
break;
|
||||
|
||||
// Data commands
|
||||
case "reload":
|
||||
runReload(server, sender, commandLabel, args);
|
||||
break;
|
||||
case "reset":
|
||||
runReset(server, sender, commandLabel, args);
|
||||
break;
|
||||
case "cleanup":
|
||||
runCleanup(server, sender, commandLabel, args);
|
||||
break;
|
||||
case "uuidconvert":
|
||||
runUUIDConvert(server, sender, commandLabel, args);
|
||||
break;
|
||||
case "uuidtest":
|
||||
runUUIDTest(server, sender, commandLabel, args);
|
||||
break;
|
||||
|
||||
// "#EasterEgg"
|
||||
case "nya":
|
||||
case "nyan":
|
||||
runNya(server, sender, commandLabel, args);
|
||||
break;
|
||||
case "moo":
|
||||
runMoo(server, sender, commandLabel, args);
|
||||
break;
|
||||
default:
|
||||
showUsage(sender);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Displays the command's usage.
|
||||
private void showUsage(final CommandSource sender) throws Exception {
|
||||
throw new NotEnoughArgumentsException("/<command> <reload/debug/commands>");
|
||||
}
|
||||
|
||||
// Lists commands that are being handed over to other plugins.
|
||||
private void runCommands(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
final StringBuilder disabledCommands = new StringBuilder();
|
||||
for (final Map.Entry<String, String> entry : ess.getAlternativeCommandsHandler().disabledCommands().entrySet()) {
|
||||
if (disabledCommands.length() > 0) {
|
||||
disabledCommands.append("\n");
|
||||
}
|
||||
disabledCommands.append(entry.getKey()).append(" => ").append(entry.getValue());
|
||||
}
|
||||
if (disabledCommands.length() > 0) {
|
||||
sender.sendMessage(tl("blockList"));
|
||||
sender.sendMessage(disabledCommands.toString());
|
||||
} else {
|
||||
sender.sendMessage(tl("blockListEmpty"));
|
||||
}
|
||||
}
|
||||
|
||||
// Resets the given player's user data.
|
||||
private void runReset(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length < 2) {
|
||||
throw new Exception("/<command> reset <player>");
|
||||
}
|
||||
final User user = getPlayer(server, args, 1, true, true);
|
||||
user.reset();
|
||||
sender.sendMessage("Reset Essentials userdata for player: " + user.getDisplayName());
|
||||
}
|
||||
|
||||
// Toggles debug mode.
|
||||
private void runDebug(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
ess.getSettings().setDebug(!ess.getSettings().isDebug());
|
||||
sender.sendMessage("Essentials " + ess.getDescription().getVersion() + " debug mode " + (ess.getSettings().isDebug() ? "enabled" : "disabled"));
|
||||
}
|
||||
|
||||
// Reloads all reloadable configs.
|
||||
private void runReload(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
ess.reload();
|
||||
sender.sendMessage(tl("essentialsReload", ess.getDescription().getVersion()));
|
||||
}
|
||||
|
||||
// Pop tarts.
|
||||
private void runNya(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
if (currentTune != null) {
|
||||
currentTune.cancel();
|
||||
}
|
||||
|
||||
currentTune = new TuneRunnable(NYAN_TUNE, NOTE_HARP, ess::getOnlinePlayers);
|
||||
currentTune.runTaskTimer(ess, 20, 2);
|
||||
}
|
||||
|
||||
// Cow farts.
|
||||
private void runMoo(final Server server, final CommandSource sender, final String command, final String[] args) {
|
||||
if (args.length == 2 && args[1].equals("moo")) {
|
||||
for (final String s : CONSOLE_MOO) {
|
||||
logger.info(s);
|
||||
}
|
||||
for (final Player player : ess.getOnlinePlayers()) {
|
||||
player.sendMessage(PLAYER_MOO);
|
||||
player.playSound(player.getLocation(), MOO_SOUND, 1, 1.0f);
|
||||
}
|
||||
} else {
|
||||
if (sender.isPlayer()) {
|
||||
sender.getSender().sendMessage(PLAYER_MOO);
|
||||
final Player player = sender.getPlayer();
|
||||
player.playSound(player.getLocation(), MOO_SOUND, 1, 1.0f);
|
||||
|
||||
} else {
|
||||
sender.getSender().sendMessage(CONSOLE_MOO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleans up inactive users.
|
||||
private void runCleanup(final Server server, final CommandSource sender, final String command, final String[] args) throws Exception {
|
||||
if (args.length < 2 || !NumberUtil.isInt(args[1])) {
|
||||
sender.sendMessage("This sub-command will delete users who haven't logged in in the last <days> days.");
|
||||
sender.sendMessage("Optional parameters define the minimum amount required to prevent deletion.");
|
||||
sender.sendMessage("Unless you define larger default values, this command will ignore people who have more than 0 money/homes.");
|
||||
throw new Exception("/<command> cleanup <days> [money] [homes]");
|
||||
}
|
||||
|
||||
sender.sendMessage(tl("cleaning"));
|
||||
|
||||
final long daysArg = Long.parseLong(args[1]);
|
||||
final double moneyArg = args.length >= 3 ? FloatUtil.parseDouble(args[2].replaceAll("[^0-9\\.]", "")) : 0;
|
||||
final int homesArg = args.length >= 4 && NumberUtil.isInt(args[3]) ? Integer.parseInt(args[3]) : 0;
|
||||
final UserMap userMap = ess.getUserMap();
|
||||
|
||||
ess.runTaskAsynchronously(() -> {
|
||||
final long currTime = System.currentTimeMillis();
|
||||
for (final UUID u : userMap.getAllUniqueUsers()) {
|
||||
final User user = ess.getUserMap().getUser(u);
|
||||
if (user == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
long lastLog = user.getLastLogout();
|
||||
if (lastLog == 0) {
|
||||
lastLog = user.getLastLogin();
|
||||
}
|
||||
if (lastLog == 0) {
|
||||
user.setLastLogin(currTime);
|
||||
}
|
||||
|
||||
if (user.isNPC()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final long timeDiff = currTime - lastLog;
|
||||
final long milliDays = daysArg * 24L * 60L * 60L * 1000L;
|
||||
final int homeCount = user.getHomes().size();
|
||||
final double moneyCount = user.getMoney().doubleValue();
|
||||
|
||||
if ((lastLog == 0) || (timeDiff < milliDays) || (homeCount > homesArg) || (moneyCount > moneyArg)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info("Deleting user: " + user.getName() + " Money: " + moneyCount + " Homes: " + homeCount + " Last seen: " + DateUtil.formatDateDiff(lastLog));
|
||||
}
|
||||
|
||||
user.reset();
|
||||
}
|
||||
sender.sendMessage(tl("cleaned"));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Forces a rerun of userdata UUID conversion.
|
||||
private void runUUIDConvert(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
sender.sendMessage("Starting Essentials UUID userdata conversion; this may lag the server.");
|
||||
|
||||
final Boolean ignoreUFCache = args.length > 2 && args[1].toLowerCase(Locale.ENGLISH).contains("ignore");
|
||||
EssentialsUpgrade.uuidFileConvert(ess, ignoreUFCache);
|
||||
|
||||
sender.sendMessage("UUID conversion complete. Check your server log for more information.");
|
||||
}
|
||||
|
||||
// Looks up various UUIDs for a user.
|
||||
private void runUUIDTest(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length < 2) {
|
||||
throw new Exception("/<command> uuidtest <name>");
|
||||
}
|
||||
final String name = args[1];
|
||||
sender.sendMessage("Looking up UUID for " + name);
|
||||
|
||||
UUID onlineUUID = null;
|
||||
|
||||
for (final Player player : ess.getOnlinePlayers()) {
|
||||
if (player.getName().equalsIgnoreCase(name)) {
|
||||
onlineUUID = player.getUniqueId();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final UUID essUUID = ess.getUserMap().getUser(name).getConfigUUID();
|
||||
|
||||
final org.bukkit.OfflinePlayer player = ess.getServer().getOfflinePlayer(name);
|
||||
final UUID bukkituuid = player.getUniqueId();
|
||||
sender.sendMessage("Bukkit Lookup: " + bukkituuid.toString());
|
||||
|
||||
if (onlineUUID != null && onlineUUID != bukkituuid) {
|
||||
sender.sendMessage("Online player: " + onlineUUID.toString());
|
||||
}
|
||||
|
||||
if (essUUID != null && essUUID != bukkituuid) {
|
||||
sender.sendMessage("Essentials config: " + essUUID.toString());
|
||||
}
|
||||
|
||||
final UUID npcuuid = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
|
||||
sender.sendMessage("NPC UUID: " + npcuuid.toString());
|
||||
|
||||
final UUID offlineuuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8));
|
||||
sender.sendMessage("Offline Mode UUID: " + offlineuuid.toString());
|
||||
}
|
||||
|
||||
// Displays versions of EssentialsX and related plugins.
|
||||
private void runVersion(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.version")) return;
|
||||
|
||||
boolean isMismatched = false;
|
||||
boolean isVaultInstalled = false;
|
||||
boolean isUnsupported = false;
|
||||
final VersionUtil.SupportStatus supportStatus = VersionUtil.getServerSupportStatus();
|
||||
final PluginManager pm = server.getPluginManager();
|
||||
final String essVer = pm.getPlugin("Essentials").getDescription().getVersion();
|
||||
|
||||
final String serverMessageKey;
|
||||
if (supportStatus.isSupported()) {
|
||||
serverMessageKey = "versionOutputFine";
|
||||
} else if (supportStatus == VersionUtil.SupportStatus.UNSTABLE) {
|
||||
serverMessageKey = "versionOutputUnsupported";
|
||||
} else {
|
||||
serverMessageKey = "versionOutputWarn";
|
||||
}
|
||||
|
||||
sender.sendMessage(tl(serverMessageKey, "Server", server.getBukkitVersion() + " " + server.getVersion()));
|
||||
sender.sendMessage(tl("versionOutputFine", "EssentialsX", essVer));
|
||||
|
||||
for (final Plugin plugin : pm.getPlugins()) {
|
||||
final PluginDescriptionFile desc = plugin.getDescription();
|
||||
String name = desc.getName();
|
||||
final String version = desc.getVersion();
|
||||
|
||||
if (name.startsWith("Essentials") && !name.equalsIgnoreCase("Essentials")) {
|
||||
if (officialPlugins.contains(name)) {
|
||||
name = name.replace("Essentials", "EssentialsX");
|
||||
|
||||
if (!version.equalsIgnoreCase(essVer)) {
|
||||
isMismatched = true;
|
||||
sender.sendMessage(tl("versionOutputWarn", name, version));
|
||||
} else {
|
||||
sender.sendMessage(tl("versionOutputFine", name, version));
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(tl("versionOutputUnsupported", name, version));
|
||||
isUnsupported = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (versionPlugins.contains(name)) {
|
||||
if (warnPlugins.contains(name)) {
|
||||
sender.sendMessage(tl("versionOutputUnsupported", name, version));
|
||||
isUnsupported = true;
|
||||
} else {
|
||||
sender.sendMessage(tl("versionOutputFine", name, version));
|
||||
}
|
||||
}
|
||||
|
||||
if (name.equals("Vault")) isVaultInstalled = true;
|
||||
}
|
||||
|
||||
if (isMismatched) {
|
||||
sender.sendMessage(tl("versionMismatchAll"));
|
||||
}
|
||||
|
||||
if (!isVaultInstalled) {
|
||||
sender.sendMessage(tl("versionOutputVaultMissing"));
|
||||
}
|
||||
|
||||
if (isUnsupported) {
|
||||
sender.sendMessage(tl("versionOutputUnsupportedPlugins"));
|
||||
}
|
||||
|
||||
switch (supportStatus) {
|
||||
case UNSTABLE:
|
||||
sender.sendMessage(tl("serverUnsupportedMods"));
|
||||
break;
|
||||
case OUTDATED:
|
||||
sender.sendMessage(tl("serverUnsupported"));
|
||||
break;
|
||||
case LIMITED:
|
||||
sender.sendMessage(tl("serverUnsupportedLimitedApi"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
final List<String> options = Lists.newArrayList();
|
||||
options.add("debug");
|
||||
options.add("commands");
|
||||
options.add("version");
|
||||
options.add("reload");
|
||||
options.add("reset");
|
||||
options.add("cleanup");
|
||||
//options.add("uuidconvert");
|
||||
//options.add("uuidtest");
|
||||
//options.add("nya");
|
||||
//options.add("moo");
|
||||
return options;
|
||||
}
|
||||
|
||||
switch (args[0]) {
|
||||
case "moo":
|
||||
if (args.length == 2) {
|
||||
return Lists.newArrayList("moo");
|
||||
}
|
||||
break;
|
||||
case "reset":
|
||||
case "uuidtest":
|
||||
if (args.length == 2) {
|
||||
return getPlayers(server, sender);
|
||||
}
|
||||
break;
|
||||
case "cleanup":
|
||||
if (args.length == 2) {
|
||||
return COMMON_DURATIONS;
|
||||
} else if (args.length == 3 || args.length == 4) {
|
||||
return Lists.newArrayList("-1", "0");
|
||||
}
|
||||
break;
|
||||
case "uuidconvert":
|
||||
if (args.length == 2) {
|
||||
return Lists.newArrayList("ignoreUFCache");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static class TuneRunnable extends BukkitRunnable {
|
||||
private static final Map<String, Float> noteMap = ImmutableMap.<String, Float>builder()
|
||||
.put("1F#", 0.5f)
|
||||
.put("1G", 0.53f)
|
||||
.put("1G#", 0.56f)
|
||||
.put("1A", 0.6f)
|
||||
.put("1A#", 0.63f)
|
||||
.put("1B", 0.67f)
|
||||
.put("1C", 0.7f)
|
||||
.put("1C#", 0.76f)
|
||||
.put("1D", 0.8f)
|
||||
.put("1D#", 0.84f)
|
||||
.put("1E", 0.9f)
|
||||
.put("1F", 0.94f)
|
||||
.put("2F#", 1.0f)
|
||||
.put("2G", 1.06f)
|
||||
.put("2G#", 1.12f)
|
||||
.put("2A", 1.18f)
|
||||
.put("2A#", 1.26f)
|
||||
.put("2B", 1.34f)
|
||||
.put("2C", 1.42f)
|
||||
.put("2C#", 1.5f)
|
||||
.put("2D", 1.6f)
|
||||
.put("2D#", 1.68f)
|
||||
.put("2E", 1.78f)
|
||||
.put("2F", 1.88f)
|
||||
.build();
|
||||
|
||||
private final String[] tune;
|
||||
private final Sound sound;
|
||||
private final Supplier<Collection<Player>> players;
|
||||
private int i = 0;
|
||||
|
||||
TuneRunnable(final String tuneStr, final Sound sound, final Supplier<Collection<Player>> players) {
|
||||
this.tune = tuneStr.split(",");
|
||||
this.sound = sound;
|
||||
this.players = players;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final String note = tune[i];
|
||||
i++;
|
||||
if (i >= tune.length) {
|
||||
cancel();
|
||||
}
|
||||
if (note == null || note.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final Player onlinePlayer : players.get()) {
|
||||
onlinePlayer.playSound(onlinePlayer.getLocation(), sound, 1, noteMap.get(note));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.Console;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandhelpop extends EssentialsCommand {
|
||||
public Commandhelpop() {
|
||||
super("helpop");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
user.setDisplayNick();
|
||||
final String message = sendMessage(server, user.getDisplayName(), args);
|
||||
if (!user.isAuthorized("essentials.helpop.receive")) {
|
||||
user.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
sendMessage(server, Console.NAME, args);
|
||||
}
|
||||
|
||||
private String sendMessage(final Server server, final String from, final String[] args) throws Exception {
|
||||
if (args.length < 1) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
final String message = tl("helpOp", from, FormatUtil.stripFormat(getFinalArg(args, 0)));
|
||||
server.getLogger().log(Level.INFO, message);
|
||||
ess.broadcastMessage("essentials.helpop.receive", message);
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commanditemlore extends EssentialsCommand {
|
||||
|
||||
public Commanditemlore() {
|
||||
super("itemlore");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
final ItemStack item = user.getBase().getItemInHand();
|
||||
if (item.getType().name().contains("AIR")) {
|
||||
throw new Exception(tl("itemloreInvalidItem"));
|
||||
}
|
||||
|
||||
if (args.length == 0) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
final ItemMeta im = item.getItemMeta();
|
||||
if (args[0].equalsIgnoreCase("add") && args.length > 1) {
|
||||
final String line = FormatUtil.formatString(user, "essentials.itemlore", getFinalArg(args, 1)).trim();
|
||||
final List<String> lore = im.hasLore() ? im.getLore() : new ArrayList<>();
|
||||
lore.add(line);
|
||||
im.setLore(lore);
|
||||
item.setItemMeta(im);
|
||||
user.sendMessage(tl("itemloreSuccess", line));
|
||||
} else if (args[0].equalsIgnoreCase("clear")) {
|
||||
im.setLore(new ArrayList<>());
|
||||
item.setItemMeta(im);
|
||||
user.sendMessage(tl("itemloreClear"));
|
||||
} else if (args[0].equalsIgnoreCase("set") && args.length > 2 && NumberUtil.isInt(args[1])) {
|
||||
if (!im.hasLore()) {
|
||||
throw new Exception(tl("itemloreNoLore"));
|
||||
}
|
||||
|
||||
final int line = Integer.parseInt(args[1]);
|
||||
final String newLine = FormatUtil.formatString(user, "essentials.itemlore", getFinalArg(args, 2)).trim();
|
||||
final List<String> lore = im.getLore();
|
||||
try {
|
||||
lore.set(line - 1, newLine);
|
||||
} catch (final Exception e) {
|
||||
throw new Exception(tl("itemloreNoLine", line), e);
|
||||
}
|
||||
im.setLore(lore);
|
||||
item.setItemMeta(im);
|
||||
user.sendMessage(tl("itemloreSuccessLore", line, newLine));
|
||||
} else {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
return Lists.newArrayList("add", "set", "clear");
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commanditemname extends EssentialsCommand {
|
||||
|
||||
public Commanditemname() {
|
||||
super("itemname");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
final ItemStack item = user.getBase().getItemInHand();
|
||||
if (item.getType() == Material.AIR) {
|
||||
user.sendMessage(tl("itemnameInvalidItem", item.getType().toString().toLowerCase(Locale.ENGLISH).replace('_', ' ')));
|
||||
return;
|
||||
}
|
||||
|
||||
String name = FormatUtil.formatString(user, "essentials.itemname", getFinalArg(args, 0)).trim();
|
||||
if (name.isEmpty()) {
|
||||
name = null;
|
||||
}
|
||||
|
||||
final ItemMeta im = item.getItemMeta();
|
||||
im.setDisplayName(name);
|
||||
item.setItemMeta(im);
|
||||
user.sendMessage(name == null ? tl("itemnameClear") : tl("itemnameSuccess", name));
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.PlayerList;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandlist extends EssentialsCommand {
|
||||
public Commandlist() {
|
||||
super("list");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
boolean showHidden = true;
|
||||
User user = null;
|
||||
if (sender.isPlayer()) {
|
||||
user = ess.getUser(sender.getPlayer());
|
||||
showHidden = user.isAuthorized("essentials.list.hidden") || user.canInteractVanished();
|
||||
}
|
||||
sender.sendMessage(PlayerList.listSummary(ess, user, showHidden));
|
||||
final Map<String, List<User>> playerList = PlayerList.getPlayerLists(ess, user, showHidden);
|
||||
|
||||
if (args.length > 0) {
|
||||
sender.sendMessage(PlayerList.listGroupUsers(ess, playerList, args[0].toLowerCase()));
|
||||
} else {
|
||||
sendGroupedList(sender, commandLabel, playerList);
|
||||
}
|
||||
}
|
||||
|
||||
// Output the standard /list output, when no group is specified
|
||||
private void sendGroupedList(final CommandSource sender, final String commandLabel, final Map<String, List<User>> playerList) {
|
||||
final Set<String> configGroups = ess.getSettings().getListGroupConfig().keySet();
|
||||
final List<String> asterisk = new ArrayList<>();
|
||||
|
||||
// Loop through the custom defined groups and display them
|
||||
for (final String oConfigGroup : configGroups) {
|
||||
final String groupValue = ess.getSettings().getListGroupConfig().get(oConfigGroup).toString().trim();
|
||||
final String configGroup = oConfigGroup.toLowerCase();
|
||||
|
||||
// If the group value is an asterisk, then skip it, and handle it later
|
||||
if (groupValue.equals("*")) {
|
||||
asterisk.add(oConfigGroup);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the group value is hidden, we don't need to display it
|
||||
if (groupValue.equalsIgnoreCase("hidden")) {
|
||||
playerList.remove(configGroup);
|
||||
continue;
|
||||
}
|
||||
|
||||
final List<User> outputUserList;
|
||||
final List<User> matchedList = playerList.get(configGroup);
|
||||
|
||||
// If the group value is an int, then we might need to truncate it
|
||||
if (NumberUtil.isInt(groupValue)) {
|
||||
if (matchedList != null && !matchedList.isEmpty()) {
|
||||
playerList.remove(configGroup);
|
||||
outputUserList = new ArrayList<>(matchedList);
|
||||
final int limit = Integer.parseInt(groupValue);
|
||||
if (matchedList.size() > limit) {
|
||||
sender.sendMessage(PlayerList.outputFormat(oConfigGroup, tl("groupNumber", matchedList.size(), commandLabel, FormatUtil.stripFormat(configGroup))));
|
||||
} else {
|
||||
sender.sendMessage(PlayerList.outputFormat(oConfigGroup, PlayerList.listUsers(ess, outputUserList, ", ")));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
outputUserList = PlayerList.getMergedList(ess, playerList, configGroup);
|
||||
|
||||
// If we have no users, than we don't need to continue parsing this group
|
||||
if (outputUserList.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sender.sendMessage(PlayerList.outputFormat(oConfigGroup, PlayerList.listUsers(ess, outputUserList, ", ")));
|
||||
}
|
||||
|
||||
final Set<String> var = playerList.keySet();
|
||||
String[] onlineGroups = var.toArray(new String[0]);
|
||||
Arrays.sort(onlineGroups, String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
// If we have an asterisk group, then merge all remaining groups
|
||||
if (!asterisk.isEmpty()) {
|
||||
final List<User> asteriskUsers = new ArrayList<>();
|
||||
for (final String onlineGroup : onlineGroups) {
|
||||
asteriskUsers.addAll(playerList.get(onlineGroup));
|
||||
}
|
||||
for (final String key : asterisk) {
|
||||
playerList.put(key, asteriskUsers);
|
||||
}
|
||||
onlineGroups = asterisk.toArray(new String[0]);
|
||||
}
|
||||
|
||||
// If we have any groups remaining after the custom groups loop through and display them
|
||||
for (final String onlineGroup : onlineGroups) {
|
||||
final List<User> users = playerList.get(onlineGroup);
|
||||
String groupName = asterisk.isEmpty() ? users.get(0).getGroup() : onlineGroup;
|
||||
|
||||
if (ess.getPermissionsHandler().getName().equals("ConfigPermissions")) {
|
||||
groupName = tl("connectedPlayers");
|
||||
}
|
||||
if (users == null || users.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sender.sendMessage(PlayerList.outputFormat(groupName, PlayerList.listUsers(ess, users, ", ")));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
return new ArrayList<>(PlayerList.getPlayerLists(ess, sender.getUser(ess), true).keySet());
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.textreader.IText;
|
||||
import com.earth2me.essentials.textreader.SimpleTextInput;
|
||||
import com.earth2me.essentials.textreader.TextPager;
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import com.earth2me.essentials.utils.StringUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandmail extends EssentialsCommand {
|
||||
private static int mailsPerMinute = 0;
|
||||
private static long timestamp = 0;
|
||||
|
||||
public Commandmail() {
|
||||
super("mail");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length >= 1 && "read".equalsIgnoreCase(args[0])) {
|
||||
final List<String> mail = user.getMails();
|
||||
if (mail.isEmpty()) {
|
||||
user.sendMessage(tl("noMail"));
|
||||
throw new NoChargeException();
|
||||
}
|
||||
|
||||
final IText input = new SimpleTextInput(mail);
|
||||
final TextPager pager = new TextPager(input);
|
||||
pager.showPage(args.length > 1 ? args[1] : null, null, commandLabel + " " + args[0], user.getSource());
|
||||
|
||||
user.sendMessage(tl("mailClear"));
|
||||
return;
|
||||
}
|
||||
if (args.length >= 3 && "send".equalsIgnoreCase(args[0])) {
|
||||
if (!user.isAuthorized("essentials.mail.send")) {
|
||||
throw new Exception(tl("noPerm", "essentials.mail.send"));
|
||||
}
|
||||
|
||||
if (user.isMuted()) {
|
||||
final String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
|
||||
if (dateDiff == null) {
|
||||
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
|
||||
}
|
||||
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
|
||||
}
|
||||
|
||||
final User u;
|
||||
try {
|
||||
u = getPlayer(server, args[1], true, true);
|
||||
} catch (final PlayerNotFoundException e) {
|
||||
throw new Exception(tl("playerNeverOnServer", args[1]));
|
||||
}
|
||||
|
||||
final String mail = tl("mailFormat", user.getName(), FormatUtil.formatMessage(user, "essentials.mail", StringUtil.sanitizeString(FormatUtil.stripFormat(getFinalArg(args, 2)))));
|
||||
if (mail.length() > 1000) {
|
||||
throw new Exception(tl("mailTooLong"));
|
||||
}
|
||||
|
||||
if (!u.isIgnoredPlayer(user)) {
|
||||
if (Math.abs(System.currentTimeMillis() - timestamp) > 60000) {
|
||||
timestamp = System.currentTimeMillis();
|
||||
mailsPerMinute = 0;
|
||||
}
|
||||
mailsPerMinute++;
|
||||
if (mailsPerMinute > ess.getSettings().getMailsPerMinute()) {
|
||||
throw new Exception(tl("mailDelay", ess.getSettings().getMailsPerMinute()));
|
||||
}
|
||||
u.addMail(tl("mailMessage", mail));
|
||||
}
|
||||
|
||||
user.sendMessage(tl("mailSentTo", u.getDisplayName(), u.getName()));
|
||||
user.sendMessage(mail);
|
||||
return;
|
||||
}
|
||||
if (args.length > 1 && "sendall".equalsIgnoreCase(args[0])) {
|
||||
if (!user.isAuthorized("essentials.mail.sendall")) {
|
||||
throw new Exception(tl("noPerm", "essentials.mail.sendall"));
|
||||
}
|
||||
ess.runTaskAsynchronously(new SendAll(tl("mailFormat", user.getName(),
|
||||
FormatUtil.formatMessage(user, "essentials.mail", StringUtil.sanitizeString(FormatUtil.stripFormat(getFinalArg(args, 1)))))));
|
||||
user.sendMessage(tl("mailSent"));
|
||||
return;
|
||||
}
|
||||
if (args.length >= 1 && "clear".equalsIgnoreCase(args[0])) {
|
||||
if (user.getMails() == null || user.getMails().isEmpty()) {
|
||||
user.sendMessage(tl("noMail"));
|
||||
throw new NoChargeException();
|
||||
}
|
||||
|
||||
user.setMails(null);
|
||||
user.sendMessage(tl("mailCleared"));
|
||||
return;
|
||||
}
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length >= 1 && "read".equalsIgnoreCase(args[0])) {
|
||||
throw new Exception(tl("onlyPlayers", commandLabel + " read"));
|
||||
} else if (args.length >= 1 && "clear".equalsIgnoreCase(args[0])) {
|
||||
throw new Exception(tl("onlyPlayers", commandLabel + " clear"));
|
||||
} else if (args.length >= 3 && "send".equalsIgnoreCase(args[0])) {
|
||||
final User u;
|
||||
try {
|
||||
u = getPlayer(server, args[1], true, true);
|
||||
} catch (final PlayerNotFoundException e) {
|
||||
throw new Exception(tl("playerNeverOnServer", args[1]));
|
||||
}
|
||||
u.addMail(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 2))));
|
||||
sender.sendMessage(tl("mailSent"));
|
||||
return;
|
||||
} else if (args.length >= 2 && "sendall".equalsIgnoreCase(args[0])) {
|
||||
ess.runTaskAsynchronously(new SendAll(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 1)))));
|
||||
sender.sendMessage(tl("mailSent"));
|
||||
return;
|
||||
} else if (args.length >= 2) {
|
||||
//allow sending from console without "send" argument, since it's the only thing the console can do
|
||||
final User u;
|
||||
try {
|
||||
u = getPlayer(server, args[0], true, true);
|
||||
} catch (final PlayerNotFoundException e) {
|
||||
throw new Exception(tl("playerNeverOnServer", args[0]));
|
||||
}
|
||||
u.addMail(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 1))));
|
||||
sender.sendMessage(tl("mailSent"));
|
||||
return;
|
||||
}
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
final List<String> options = Lists.newArrayList("read", "clear");
|
||||
if (user.isAuthorized("essentials.mail.send")) {
|
||||
options.add("send");
|
||||
}
|
||||
if (user.isAuthorized("essentials.mail.sendall")) {
|
||||
options.add("sendall");
|
||||
}
|
||||
return options;
|
||||
} else if (args.length == 2 && args[0].equalsIgnoreCase("send") && user.isAuthorized("essentials.mail.send")) {
|
||||
return getPlayers(server, user);
|
||||
} else if (args.length == 2 && args[0].equalsIgnoreCase("read")) {
|
||||
final List<String> mail = user.getMails();
|
||||
final int pages = mail.size() / 9 + (mail.size() % 9 > 0 ? 1 : 0);
|
||||
if (pages == 0) {
|
||||
return Lists.newArrayList("0");
|
||||
} else {
|
||||
final List<String> options = Lists.newArrayList("1");
|
||||
if (pages > 1) {
|
||||
options.add(String.valueOf(pages));
|
||||
}
|
||||
return options;
|
||||
}
|
||||
} else if ((args.length > 2 && args[0].equalsIgnoreCase("send") && user.isAuthorized("essentials.mail.send")) || (args.length > 1 && args[0].equalsIgnoreCase("sendall") && user.isAuthorized("essentials.mail.sendall"))) {
|
||||
return null; // Use vanilla handler
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
return Lists.newArrayList("send", "sendall");
|
||||
} else if (args.length == 2 && args[0].equalsIgnoreCase("send")) {
|
||||
return getPlayers(server, sender);
|
||||
} else if ((args.length > 2 && args[0].equalsIgnoreCase("send")) || (args.length > 1 && args[0].equalsIgnoreCase("sendall"))) {
|
||||
return null; // Use vanilla handler
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private class SendAll implements Runnable {
|
||||
final String message;
|
||||
|
||||
SendAll(final String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (final UUID userid : ess.getUserMap().getAllUniqueUsers()) {
|
||||
final User user = ess.getUserMap().getUser(userid);
|
||||
if (user != null) {
|
||||
user.addMail(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.RandomTeleport;
|
||||
import com.earth2me.essentials.User;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandsettpr extends EssentialsCommand {
|
||||
public Commandsettpr() {
|
||||
super("settpr");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
final RandomTeleport randomTeleport = ess.getRandomTeleport();
|
||||
randomTeleport.getCachedLocations().clear();
|
||||
if (args.length == 0 || "center".equalsIgnoreCase(args[0])) {
|
||||
randomTeleport.setCenter(user.getLocation());
|
||||
user.sendMessage(tl("settpr"));
|
||||
} else if (args.length > 1) {
|
||||
if ("minrange".equalsIgnoreCase(args[0])) {
|
||||
randomTeleport.setMinRange(Double.parseDouble(args[1]));
|
||||
} else if ("maxrange".equalsIgnoreCase(args[0])) {
|
||||
randomTeleport.setMaxRange(Double.parseDouble(args[1]));
|
||||
}
|
||||
user.sendMessage(tl("settprValue", args[0].toLowerCase(), args[1].toLowerCase()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
return Arrays.asList("center", "minrange", "maxrange");
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.api.IWarps;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import com.earth2me.essentials.utils.StringUtil;
|
||||
import net.ess3.api.InvalidWorldException;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandsetwarp extends EssentialsCommand {
|
||||
public Commandsetwarp() {
|
||||
super("setwarp");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length == 0) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
if (NumberUtil.isInt(args[0]) || args[0].isEmpty()) {
|
||||
throw new Exception(tl("invalidWarpName"));
|
||||
}
|
||||
|
||||
final IWarps warps = ess.getWarps();
|
||||
Location warpLoc = null;
|
||||
|
||||
try {
|
||||
warpLoc = warps.getWarp(args[0]);
|
||||
} catch (final WarpNotFoundException | InvalidWorldException ignored) {
|
||||
}
|
||||
|
||||
if (warpLoc == null || user.isAuthorized("essentials.warp.overwrite." + StringUtil.safeString(args[0]))) {
|
||||
warps.setWarp(user, args[0], user.getLocation());
|
||||
} else {
|
||||
throw new Exception(tl("warpOverwrite"));
|
||||
}
|
||||
user.sendMessage(tl("warpSet", args[0]));
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
|
||||
import com.earth2me.essentials.utils.EnumUtil;
|
||||
import com.earth2me.essentials.utils.MaterialUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandskull extends EssentialsCommand {
|
||||
|
||||
private static final Pattern NAME_PATTERN = Pattern.compile("^[A-Za-z0-9_]+$");
|
||||
private static final Material SKULL_ITEM = EnumUtil.getMaterial("PLAYER_HEAD", "SKULL_ITEM");
|
||||
|
||||
public Commandskull() {
|
||||
super("skull");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
final String owner;
|
||||
if (args.length > 0 && user.isAuthorized("essentials.skull.others")) {
|
||||
if (!NAME_PATTERN.matcher(args[0]).matches()) {
|
||||
throw new IllegalArgumentException(tl("alphaNames"));
|
||||
}
|
||||
owner = args[0];
|
||||
} else {
|
||||
owner = user.getName();
|
||||
}
|
||||
|
||||
ItemStack itemSkull = user.getItemInHand();
|
||||
final SkullMeta metaSkull;
|
||||
boolean spawn = false;
|
||||
|
||||
if (itemSkull != null && MaterialUtil.isPlayerHead(itemSkull.getType(), itemSkull.getDurability())) {
|
||||
metaSkull = (SkullMeta) itemSkull.getItemMeta();
|
||||
} else if (user.isAuthorized("essentials.skull.spawn")) {
|
||||
itemSkull = new ItemStack(SKULL_ITEM, 1, (byte) 3);
|
||||
metaSkull = (SkullMeta) itemSkull.getItemMeta();
|
||||
spawn = true;
|
||||
} else {
|
||||
throw new Exception(tl("invalidSkull"));
|
||||
}
|
||||
|
||||
if (metaSkull.hasOwner() && !user.isAuthorized("essentials.skull.modify")) {
|
||||
throw new Exception(tl("noPermissionSkull"));
|
||||
}
|
||||
|
||||
editSkull(user, itemSkull, metaSkull, owner, spawn);
|
||||
}
|
||||
|
||||
private void editSkull(final User user, final ItemStack stack, final SkullMeta skullMeta, final String owner, final boolean spawn) {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//Run this stuff async because SkullMeta#setOwner causes a http request.
|
||||
skullMeta.setDisplayName("§fSkull of " + owner);
|
||||
skullMeta.setOwner(owner);
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
stack.setItemMeta(skullMeta);
|
||||
if (spawn) {
|
||||
InventoryWorkaround.addItems(user.getBase().getInventory(), stack);
|
||||
user.sendMessage(tl("givenSkull", owner));
|
||||
return;
|
||||
}
|
||||
user.sendMessage(tl("skullChanged", owner));
|
||||
}
|
||||
}.runTask(ess);
|
||||
}
|
||||
}.runTaskAsynchronously(ess);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
if (user.isAuthorized("essentials.skull.others")) {
|
||||
return getPlayers(server, user);
|
||||
} else {
|
||||
return Lists.newArrayList(user.getName());
|
||||
}
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
import net.ess3.api.events.JailStatusChangeEvent;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandtogglejail extends EssentialsCommand {
|
||||
public Commandtogglejail() {
|
||||
super("togglejail");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length == 0) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
final User player = getPlayer(server, args, 0, true, true);
|
||||
|
||||
if (args.length >= 2 && !player.isJailed()) {
|
||||
if (!player.getBase().isOnline()) {
|
||||
if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.togglejail.offline")) {
|
||||
sender.sendMessage(tl("mayNotJailOffline"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (player.isAuthorized("essentials.jail.exempt")) {
|
||||
sender.sendMessage(tl("mayNotJail"));
|
||||
return;
|
||||
}
|
||||
|
||||
final JailStatusChangeEvent event = new JailStatusChangeEvent(player, sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null, true);
|
||||
ess.getServer().getPluginManager().callEvent(event);
|
||||
|
||||
if (!event.isCancelled()) {
|
||||
long preTimeDiff = 0;
|
||||
if (args.length > 2) {
|
||||
final String time = getFinalArg(args, 2);
|
||||
preTimeDiff = DateUtil.parseDateDiff(time, true);
|
||||
|
||||
}
|
||||
final long timeDiff = preTimeDiff;
|
||||
final CompletableFuture<Boolean> future = getNewExceptionFuture(sender, commandLabel);
|
||||
future.thenAccept(success -> {
|
||||
if (success) {
|
||||
player.setJailed(true);
|
||||
player.sendMessage(tl("userJailed"));
|
||||
player.setJail(null);
|
||||
player.setJail(args[1]);
|
||||
if (args.length > 2) {
|
||||
player.setJailTimeout(timeDiff);
|
||||
}
|
||||
sender.sendMessage(timeDiff > 0 ? tl("playerJailedFor", player.getName(), DateUtil.formatDateDiff(timeDiff)) : tl("playerJailed", player.getName()));
|
||||
}
|
||||
});
|
||||
if (player.getBase().isOnline()) {
|
||||
ess.getJails().sendToJail(player, args[1], future);
|
||||
} else {
|
||||
// Check if jail exists
|
||||
ess.getJails().getJail(args[1]);
|
||||
future.complete(true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length >= 2 && player.isJailed() && !args[1].equalsIgnoreCase(player.getJail())) {
|
||||
sender.sendMessage(tl("jailAlreadyIncarcerated", player.getJail()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length >= 2 && player.isJailed() && args[1].equalsIgnoreCase(player.getJail())) {
|
||||
final long timeDiff = DateUtil.parseDateDiff(getFinalArg(args, 2), true);
|
||||
player.setJailTimeout(timeDiff);
|
||||
sender.sendMessage(tl("jailSentenceExtended", DateUtil.formatDateDiff(timeDiff)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length == 1 || (args.length == 2 && args[1].equalsIgnoreCase(player.getJail()))) {
|
||||
if (!player.isJailed()) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
final JailStatusChangeEvent event = new JailStatusChangeEvent(player, sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null, false);
|
||||
ess.getServer().getPluginManager().callEvent(event);
|
||||
|
||||
if (!event.isCancelled()) {
|
||||
player.setJailed(false);
|
||||
player.setJailTimeout(0);
|
||||
player.sendMessage(tl("jailReleasedPlayerNotify"));
|
||||
player.setJail(null);
|
||||
if (player.getBase().isOnline() && ess.getSettings().isTeleportBackWhenFreedFromJail()) {
|
||||
final CompletableFuture<Boolean> future = getNewExceptionFuture(sender, commandLabel);
|
||||
player.getAsyncTeleport().back(future);
|
||||
future.thenAccept(success -> {
|
||||
if (success) {
|
||||
sender.sendMessage(tl("jailReleased", player.getName()));
|
||||
}
|
||||
});
|
||||
future.exceptionally(e -> {
|
||||
player.getAsyncTeleport().respawn(null, PlayerTeleportEvent.TeleportCause.PLUGIN, new CompletableFuture<>());
|
||||
sender.sendMessage(tl("jailReleased", player.getName()));
|
||||
return false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(tl("jailReleased", player.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
return getPlayers(server, sender);
|
||||
} else if (args.length == 2) {
|
||||
try {
|
||||
return new ArrayList<>(ess.getJails().getList());
|
||||
} catch (final Exception e) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else {
|
||||
return COMMON_DATE_DIFFS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.AsyncTeleport;
|
||||
import com.earth2me.essentials.Trade;
|
||||
import com.earth2me.essentials.User;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandtpaccept extends EssentialsCommand {
|
||||
public Commandtpaccept() {
|
||||
super("tpaccept");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
final User requester;
|
||||
try {
|
||||
requester = ess.getUser(user.getTeleportRequest());
|
||||
} catch (final Exception ex) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
|
||||
if (!requester.getBase().isOnline()) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
|
||||
if (user.isTpRequestHere() && ((!requester.isAuthorized("essentials.tpahere") && !requester.isAuthorized("essentials.tpaall")) || (user.getWorld() != requester.getWorld() && ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + user.getWorld().getName())))) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
|
||||
if (!user.isTpRequestHere() && (!requester.isAuthorized("essentials.tpa") || (user.getWorld() != requester.getWorld() && ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + requester.getWorld().getName())))) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
|
||||
if (args.length > 0 && !requester.getName().contains(args[0])) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
|
||||
if (!user.hasOutstandingTeleportRequest()) {
|
||||
user.requestTeleport(null, false);
|
||||
throw new Exception(tl("requestTimedOut"));
|
||||
}
|
||||
|
||||
final Trade charge = new Trade(this.getName(), ess);
|
||||
user.sendMessage(tl("requestAccepted"));
|
||||
requester.sendMessage(tl("requestAcceptedFrom", user.getDisplayName()));
|
||||
|
||||
final CompletableFuture<Boolean> future = getNewExceptionFuture(requester.getSource(), commandLabel);
|
||||
future.exceptionally(e -> {
|
||||
user.sendMessage(tl("pendingTeleportCancelled"));
|
||||
return false;
|
||||
});
|
||||
if (user.isTpRequestHere()) {
|
||||
final Location loc = user.getTpRequestLocation();
|
||||
final AsyncTeleport teleport = requester.getAsyncTeleport();
|
||||
teleport.setTpType(AsyncTeleport.TeleportType.TPA);
|
||||
future.thenAccept(success -> {
|
||||
if (success) {
|
||||
requester.sendMessage(tl("teleporting", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
}
|
||||
});
|
||||
teleport.teleportPlayer(user, user.getTpRequestLocation(), charge, TeleportCause.COMMAND, future);
|
||||
} else {
|
||||
final AsyncTeleport teleport = requester.getAsyncTeleport();
|
||||
teleport.setTpType(AsyncTeleport.TeleportType.TPA);
|
||||
teleport.teleport(user.getBase(), charge, TeleportCause.COMMAND, future);
|
||||
}
|
||||
user.requestTeleport(null, false);
|
||||
throw new NoChargeException();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.User;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandtpdeny extends EssentialsCommand {
|
||||
public Commandtpdeny() {
|
||||
super("tpdeny");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
if (user.getTeleportRequest() == null) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
final User player = ess.getUser(user.getTeleportRequest());
|
||||
if (player == null) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
|
||||
user.sendMessage(tl("requestDenied"));
|
||||
player.sendMessage(tl("requestDeniedFrom", user.getDisplayName()));
|
||||
user.requestTeleport(null, false);
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.RandomTeleport;
|
||||
import com.earth2me.essentials.Trade;
|
||||
import com.earth2me.essentials.User;
|
||||
import net.ess3.api.events.UserRandomTeleportEvent;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandtpr extends EssentialsCommand {
|
||||
|
||||
public Commandtpr() {
|
||||
super("tpr");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
final Trade charge = new Trade(this.getName(), ess);
|
||||
charge.isAffordableFor(user);
|
||||
final RandomTeleport randomTeleport = ess.getRandomTeleport();
|
||||
final UserRandomTeleportEvent event = new UserRandomTeleportEvent(user, randomTeleport.getCenter(), randomTeleport.getMinRange(), randomTeleport.getMaxRange());
|
||||
server.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
randomTeleport.getRandomLocation(event.getCenter(), event.getMinRange(), event.getMaxRange()).thenAccept(location -> {
|
||||
final CompletableFuture<Boolean> future = getNewExceptionFuture(user.getSource(), commandLabel);
|
||||
user.getAsyncTeleport().teleport(location, charge, PlayerTeleportEvent.TeleportCause.COMMAND, future);
|
||||
future.thenAccept(success -> {
|
||||
if (success) {
|
||||
user.sendMessage(tl("tprSuccess"));
|
||||
}
|
||||
});
|
||||
});
|
||||
throw new NoChargeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.craftbukkit.SetExpFix;
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
import com.earth2me.essentials.utils.EnumUtil;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.Statistic;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandwhois extends EssentialsCommand {
|
||||
// For some reason, in 1.13 PLAY_ONE_MINUTE = ticks played = what used to be PLAY_ONE_TICK
|
||||
// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/commits/b848d8ce633871b52115247b089029749c02f579
|
||||
private static final Statistic PLAY_ONE_TICK = EnumUtil.getStatistic("PLAY_ONE_MINUTE", "PLAY_ONE_TICK");
|
||||
|
||||
public Commandwhois() {
|
||||
super("whois");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length < 1) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
final User user = getPlayer(server, sender, args, 0);
|
||||
|
||||
sender.sendMessage(tl("whoisTop", user.getName()));
|
||||
user.setDisplayNick();
|
||||
sender.sendMessage(tl("whoisNick", user.getDisplayName()));
|
||||
sender.sendMessage(tl("whoisUuid", user.getBase().getUniqueId().toString()));
|
||||
sender.sendMessage(tl("whoisHealth", user.getBase().getHealth()));
|
||||
sender.sendMessage(tl("whoisHunger", user.getBase().getFoodLevel(), user.getBase().getSaturation()));
|
||||
sender.sendMessage(tl("whoisExp", SetExpFix.getTotalExperience(user.getBase()), user.getBase().getLevel()));
|
||||
sender.sendMessage(tl("whoisLocation", user.getLocation().getWorld().getName(), user.getLocation().getBlockX(), user.getLocation().getBlockY(), user.getLocation().getBlockZ()));
|
||||
final long playtimeMs = System.currentTimeMillis() - (user.getBase().getStatistic(PLAY_ONE_TICK) * 50);
|
||||
sender.sendMessage(tl("whoisPlaytime", DateUtil.formatDateDiff(playtimeMs)));
|
||||
if (!ess.getSettings().isEcoDisabled()) {
|
||||
sender.sendMessage(tl("whoisMoney", NumberUtil.displayCurrency(user.getMoney(), ess)));
|
||||
}
|
||||
if (!sender.isPlayer() || ess.getUser(sender.getPlayer()).isAuthorized("essentials.whois.ip")) {
|
||||
sender.sendMessage(tl("whoisIPAddress", user.getBase().getAddress().getAddress().toString()));
|
||||
}
|
||||
final String location = user.getGeoLocation();
|
||||
if (location != null && (!sender.isPlayer() || ess.getUser(sender.getPlayer()).isAuthorized("essentials.geoip.show"))) {
|
||||
sender.sendMessage(tl("whoisGeoLocation", location));
|
||||
}
|
||||
sender.sendMessage(tl("whoisGamemode", tl(user.getBase().getGameMode().toString().toLowerCase(Locale.ENGLISH))));
|
||||
sender.sendMessage(tl("whoisGod", user.isGodModeEnabled() ? tl("true") : tl("false")));
|
||||
sender.sendMessage(tl("whoisOp", user.getBase().isOp() ? tl("true") : tl("false")));
|
||||
sender.sendMessage(tl("whoisFly", user.getBase().getAllowFlight() ? tl("true") : tl("false"), user.getBase().isFlying() ? tl("flying") : tl("notFlying")));
|
||||
sender.sendMessage(tl("whoisSpeed", user.getBase().isFlying() ? user.getBase().getFlySpeed() : user.getBase().getWalkSpeed()));
|
||||
if (user.isAfk()) {
|
||||
sender.sendMessage(tl("whoisAFKSince", tl("true"), DateUtil.formatDateDiff(user.getAfkSince())));
|
||||
} else {
|
||||
sender.sendMessage(tl("whoisAFK", tl("false")));
|
||||
}
|
||||
sender.sendMessage(tl("whoisJail", user.isJailed() ? user.getJailTimeout() > 0 ? DateUtil.formatDateDiff(user.getJailTimeout()) : tl("true") : tl("false")));
|
||||
|
||||
final long muteTimeout = user.getMuteTimeout();
|
||||
if (!user.hasMuteReason()) {
|
||||
sender.sendMessage(tl("whoisMuted", user.isMuted() ? muteTimeout > 0 ? DateUtil.formatDateDiff(muteTimeout) : tl("true") : tl("false")));
|
||||
} else {
|
||||
sender.sendMessage(tl("whoisMutedReason", user.isMuted() ? muteTimeout > 0 ? DateUtil.formatDateDiff(muteTimeout) : tl("true") : tl("false"),
|
||||
user.getMuteReason()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
return getPlayers(server, sender);
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
public class PlayerExemptException extends NoSuchFieldException {
|
||||
public PlayerExemptException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class PlayerNotFoundException extends NoSuchFieldException {
|
||||
public PlayerNotFoundException() {
|
||||
super(tl("playerNotFound"));
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class WarpNotFoundException extends Exception {
|
||||
public WarpNotFoundException() {
|
||||
super(tl("warpNotExist"));
|
||||
}
|
||||
|
||||
public WarpNotFoundException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,288 +0,0 @@
|
||||
package com.earth2me.essentials.craftbukkit;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.EntityEquipment;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/*
|
||||
* This class can be removed when https://github.com/Bukkit/CraftBukkit/pull/193 is accepted to CraftBukkit
|
||||
*/
|
||||
|
||||
public final class InventoryWorkaround {
|
||||
/*
|
||||
Spigot 1.9, for whatever reason, decided to merge the armor and main player inventories without providing a way
|
||||
to access the main inventory. There's lots of ugly code in here to work around that.
|
||||
*/
|
||||
private static final int USABLE_PLAYER_INV_SIZE = 36;
|
||||
// Hot-ish code so cache
|
||||
private static Boolean hasMainHandSupport = null;
|
||||
|
||||
private InventoryWorkaround() {
|
||||
}
|
||||
|
||||
private static int firstPartial(final Inventory inventory, final ItemStack item, final int maxAmount) {
|
||||
if (item == null) {
|
||||
return -1;
|
||||
}
|
||||
final ItemStack[] stacks = inventory.getContents();
|
||||
for (int i = 0; i < stacks.length; i++) {
|
||||
final ItemStack cItem = stacks[i];
|
||||
if (cItem != null && cItem.getAmount() < maxAmount && cItem.isSimilar(item)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static boolean isCombinedInventory(final Inventory inventory) {
|
||||
return inventory instanceof PlayerInventory && inventory.getContents().length > USABLE_PLAYER_INV_SIZE;
|
||||
}
|
||||
|
||||
// Clears inventory without clearing armor
|
||||
public static void clearInventoryNoArmor(final PlayerInventory inventory) {
|
||||
if (isCombinedInventory(inventory)) {
|
||||
for (int i = 0; i < USABLE_PLAYER_INV_SIZE; i++) {
|
||||
inventory.setItem(i, null);
|
||||
}
|
||||
} else {
|
||||
inventory.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static Inventory makeTruncatedPlayerInventory(final PlayerInventory playerInventory) {
|
||||
final Inventory fakeInventory = Bukkit.getServer().createInventory(null, USABLE_PLAYER_INV_SIZE);
|
||||
fakeInventory.setContents(Arrays.copyOf(playerInventory.getContents(), fakeInventory.getSize()));
|
||||
return fakeInventory;
|
||||
}
|
||||
|
||||
// Returns what it couldn't store
|
||||
// This will will abort if it couldn't store all items
|
||||
public static Map<Integer, ItemStack> addAllItems(final Inventory inventory, final ItemStack... items) {
|
||||
final ItemStack[] contents = inventory.getContents();
|
||||
|
||||
final Inventory fakeInventory;
|
||||
if (isCombinedInventory(inventory)) {
|
||||
fakeInventory = makeTruncatedPlayerInventory((PlayerInventory) inventory);
|
||||
} else {
|
||||
fakeInventory = Bukkit.getServer().createInventory(null, inventory.getType());
|
||||
fakeInventory.setContents(contents);
|
||||
}
|
||||
final Map<Integer, ItemStack> overflow = addItems(fakeInventory, items);
|
||||
if (overflow.isEmpty()) {
|
||||
addItems(inventory, items);
|
||||
return null;
|
||||
}
|
||||
return addItems(fakeInventory, items);
|
||||
}
|
||||
|
||||
public static Map<Integer, ItemStack> addAllOversizedItems(final Inventory inventory, final int oversizedStacks, final ItemStack... items) {
|
||||
final ItemStack[] contents = inventory.getContents();
|
||||
|
||||
final Inventory fakeInventory;
|
||||
if (isCombinedInventory(inventory)) {
|
||||
fakeInventory = makeTruncatedPlayerInventory((PlayerInventory) inventory);
|
||||
} else {
|
||||
fakeInventory = Bukkit.getServer().createInventory(null, inventory.getType());
|
||||
fakeInventory.setContents(contents);
|
||||
}
|
||||
final Map<Integer, ItemStack> overflow = addOversizedItems(fakeInventory, oversizedStacks, items);
|
||||
if (overflow.isEmpty()) {
|
||||
addOversizedItems(inventory, oversizedStacks, items);
|
||||
return null;
|
||||
}
|
||||
return overflow;
|
||||
}
|
||||
|
||||
// Returns what it couldn't store
|
||||
public static Map<Integer, ItemStack> addItems(final Inventory inventory, final ItemStack... items) {
|
||||
return addOversizedItems(inventory, 0, items);
|
||||
}
|
||||
|
||||
// Returns what it couldn't store
|
||||
// Set oversizedStack to below normal stack size to disable oversized stacks
|
||||
public static Map<Integer, ItemStack> addOversizedItems(final Inventory inventory, final int oversizedStacks, final ItemStack... items) {
|
||||
if (isCombinedInventory(inventory)) {
|
||||
final Inventory fakeInventory = makeTruncatedPlayerInventory((PlayerInventory) inventory);
|
||||
final Map<Integer, ItemStack> overflow = addOversizedItems(fakeInventory, oversizedStacks, items);
|
||||
for (int i = 0; i < fakeInventory.getContents().length; i++) {
|
||||
inventory.setItem(i, fakeInventory.getContents()[i]);
|
||||
}
|
||||
return overflow;
|
||||
}
|
||||
|
||||
final Map<Integer, ItemStack> leftover = new HashMap<>();
|
||||
|
||||
/*
|
||||
* TODO: some optimization - Create a 'firstPartial' with a 'fromIndex' - Record the lastPartial per Material -
|
||||
* Cache firstEmpty result
|
||||
*/
|
||||
|
||||
// combine items
|
||||
|
||||
final ItemStack[] combined = new ItemStack[items.length];
|
||||
for (final ItemStack item : items) {
|
||||
if (item == null || item.getAmount() < 1) {
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < combined.length; j++) {
|
||||
if (combined[j] == null) {
|
||||
combined[j] = item.clone();
|
||||
break;
|
||||
}
|
||||
if (combined[j].isSimilar(item)) {
|
||||
combined[j].setAmount(combined[j].getAmount() + item.getAmount());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < combined.length; i++) {
|
||||
final ItemStack item = combined[i];
|
||||
if (item == null || item.getType() == Material.AIR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
// Do we already have a stack of it?
|
||||
final int maxAmount = Math.max(oversizedStacks, item.getType().getMaxStackSize());
|
||||
final int firstPartial = firstPartial(inventory, item, maxAmount);
|
||||
|
||||
// Drat! no partial stack
|
||||
if (firstPartial == -1) {
|
||||
// Find a free spot!
|
||||
final int firstFree = inventory.firstEmpty();
|
||||
|
||||
if (firstFree == -1) {
|
||||
// No space at all!
|
||||
leftover.put(i, item);
|
||||
break;
|
||||
} else {
|
||||
// More than a single stack!
|
||||
if (item.getAmount() > maxAmount) {
|
||||
final ItemStack stack = item.clone();
|
||||
stack.setAmount(maxAmount);
|
||||
inventory.setItem(firstFree, stack);
|
||||
item.setAmount(item.getAmount() - maxAmount);
|
||||
} else {
|
||||
// Just store it
|
||||
inventory.setItem(firstFree, item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// So, apparently it might only partially fit, well lets do just that
|
||||
final ItemStack partialItem = inventory.getItem(firstPartial);
|
||||
|
||||
final int amount = item.getAmount();
|
||||
final int partialAmount = partialItem.getAmount();
|
||||
|
||||
// Check if it fully fits
|
||||
if (amount + partialAmount <= maxAmount) {
|
||||
partialItem.setAmount(amount + partialAmount);
|
||||
break;
|
||||
}
|
||||
|
||||
// It fits partially
|
||||
partialItem.setAmount(maxAmount);
|
||||
item.setAmount(amount + partialAmount - maxAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
return leftover;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void setItemInMainHand(final Player p, final ItemStack item) {
|
||||
if (hasMainHandSupport == null) {
|
||||
try {
|
||||
p.getInventory().setItemInMainHand(item);
|
||||
hasMainHandSupport = true;
|
||||
} catch (final Throwable e) {
|
||||
p.setItemInHand(item);
|
||||
hasMainHandSupport = false;
|
||||
}
|
||||
} else {
|
||||
if (hasMainHandSupport) {
|
||||
p.getInventory().setItemInMainHand(item);
|
||||
} else {
|
||||
p.setItemInHand(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void setItemInMainHand(final EntityEquipment invent, final ItemStack item) {
|
||||
if (hasMainHandSupport == null) {
|
||||
try {
|
||||
invent.setItemInMainHand(item);
|
||||
hasMainHandSupport = true;
|
||||
} catch (final Throwable e) {
|
||||
invent.setItemInHand(item);
|
||||
hasMainHandSupport = false;
|
||||
}
|
||||
} else {
|
||||
if (hasMainHandSupport) {
|
||||
invent.setItemInMainHand(item);
|
||||
} else {
|
||||
invent.setItemInHand(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void setItemInMainHandDropChance(final EntityEquipment invent, final float chance) {
|
||||
if (hasMainHandSupport == null) {
|
||||
try {
|
||||
invent.setItemInMainHandDropChance(chance);
|
||||
hasMainHandSupport = true;
|
||||
} catch (final Throwable e) {
|
||||
invent.setItemInHandDropChance(chance);
|
||||
hasMainHandSupport = false;
|
||||
}
|
||||
} else {
|
||||
if (hasMainHandSupport) {
|
||||
invent.setItemInMainHandDropChance(chance);
|
||||
} else {
|
||||
invent.setItemInHandDropChance(chance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setItemInOffHand(final Player p, final ItemStack item) {
|
||||
// This assumes that all builds that support a main hand also support an off hand.
|
||||
if (hasMainHandSupport == null || hasMainHandSupport) {
|
||||
try {
|
||||
p.getInventory().setItemInOffHand(item);
|
||||
hasMainHandSupport = true;
|
||||
} catch (final Throwable e) {
|
||||
hasMainHandSupport = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int clearItemInOffHand(final Player p, final ItemStack item) {
|
||||
// This should be added because if `/clear` itself is not initilized it will return an Error: null.
|
||||
if (hasMainHandSupport == null || hasMainHandSupport) {
|
||||
try {
|
||||
int removedAmount = 0;
|
||||
if (p.getInventory().getItemInOffHand().getType().equals(item.getType())) {
|
||||
removedAmount = p.getInventory().getItemInOffHand().getAmount();
|
||||
p.getInventory().setItemInOffHand(null);
|
||||
}
|
||||
hasMainHandSupport = true;
|
||||
return removedAmount;
|
||||
} catch (final Throwable e) {
|
||||
hasMainHandSupport = false;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,729 +0,0 @@
|
||||
package com.earth2me.essentials.metrics;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.logging.Level;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
/**
|
||||
* bStats collects some data for plugin authors.
|
||||
* <p>
|
||||
* Check out https://bStats.org/ to learn more about bStats!
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
public class Metrics {
|
||||
|
||||
// The version of this bStats class
|
||||
public static final int B_STATS_VERSION = 1;
|
||||
// The url to which the data is sent
|
||||
private static final String URL = "https://bStats.org/submitData/bukkit";
|
||||
// Should failed requests be logged?
|
||||
private static boolean logFailedRequests;
|
||||
// Should the sent data be logged?
|
||||
private static boolean logSentData;
|
||||
// Should the response text be logged?
|
||||
private static boolean logResponseStatusText;
|
||||
// The uuid of the server
|
||||
private static String serverUUID;
|
||||
|
||||
static {
|
||||
// You can use the property to disable the check in your test environment
|
||||
if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) {
|
||||
// Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D
|
||||
final String defaultPackage = new String(
|
||||
new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'});
|
||||
final String examplePackage = new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
|
||||
// We want to make sure nobody just copy & pastes the example and use the wrong package names
|
||||
if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) {
|
||||
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is bStats enabled on this server?
|
||||
private final boolean enabled;
|
||||
// The plugin
|
||||
private final Plugin plugin;
|
||||
|
||||
// The plugin id
|
||||
private final int pluginId;
|
||||
|
||||
// A list with all custom charts
|
||||
private final List<CustomChart> charts = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param plugin The plugin which stats should be submitted.
|
||||
* @param pluginId The id of the plugin.
|
||||
* It can be found at <a href="https://bstats.org/what-is-my-plugin-id">What is my plugin id?</a>
|
||||
*/
|
||||
public Metrics(final Plugin plugin, final int pluginId) {
|
||||
if (plugin == null) {
|
||||
throw new IllegalArgumentException("Plugin cannot be null!");
|
||||
}
|
||||
this.plugin = plugin;
|
||||
this.pluginId = pluginId;
|
||||
|
||||
// Get the config file
|
||||
final File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
||||
final File configFile = new File(bStatsFolder, "config.yml");
|
||||
final YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
|
||||
|
||||
// Check if the config file exists
|
||||
if (!config.isSet("serverUuid")) {
|
||||
|
||||
// Add default values
|
||||
config.addDefault("enabled", true);
|
||||
// Every server gets it's unique random id.
|
||||
config.addDefault("serverUuid", UUID.randomUUID().toString());
|
||||
// Should failed request be logged?
|
||||
config.addDefault("logFailedRequests", false);
|
||||
// Should the sent data be logged?
|
||||
config.addDefault("logSentData", false);
|
||||
// Should the response text be logged?
|
||||
config.addDefault("logResponseStatusText", false);
|
||||
|
||||
// Inform the server owners about bStats
|
||||
config.options().header(
|
||||
"bStats collects some data for plugin authors like how many servers are using their plugins.\n" +
|
||||
"To honor their work, you should not disable it.\n" +
|
||||
"This has nearly no effect on the server performance!\n" +
|
||||
"Check out https://bStats.org/ to learn more :)"
|
||||
).copyDefaults(true);
|
||||
try {
|
||||
config.save(configFile);
|
||||
} catch (final IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
// Load the data
|
||||
enabled = config.getBoolean("enabled", true);
|
||||
serverUUID = config.getString("serverUuid");
|
||||
logFailedRequests = config.getBoolean("logFailedRequests", false);
|
||||
logSentData = config.getBoolean("logSentData", false);
|
||||
logResponseStatusText = config.getBoolean("logResponseStatusText", false);
|
||||
|
||||
if (enabled) {
|
||||
boolean found = false;
|
||||
// Search for all other bStats Metrics classes to see if we are the first one
|
||||
for (final Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
|
||||
try {
|
||||
service.getField("B_STATS_VERSION"); // Our identifier :)
|
||||
found = true; // We aren't the first
|
||||
break;
|
||||
} catch (final NoSuchFieldException ignored) {
|
||||
}
|
||||
}
|
||||
// Register our service
|
||||
Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal);
|
||||
if (!found) {
|
||||
// We are the first!
|
||||
startSubmitting();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the data to the bStats server.
|
||||
*
|
||||
* @param plugin Any plugin. It's just used to get a logger instance.
|
||||
* @param data The data to send.
|
||||
* @throws Exception If the request failed.
|
||||
*/
|
||||
private static void sendData(final Plugin plugin, final JsonObject data) throws Exception {
|
||||
if (data == null) {
|
||||
throw new IllegalArgumentException("Data cannot be null!");
|
||||
}
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
throw new IllegalAccessException("This method must not be called from the main thread!");
|
||||
}
|
||||
if (logSentData) {
|
||||
plugin.getLogger().info("Sending data to bStats: " + data);
|
||||
}
|
||||
final HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
|
||||
|
||||
// Compress the data to save bandwidth
|
||||
final byte[] compressedData = compress(data.toString());
|
||||
|
||||
// Add headers
|
||||
connection.setRequestMethod("POST");
|
||||
connection.addRequestProperty("Accept", "application/json");
|
||||
connection.addRequestProperty("Connection", "close");
|
||||
connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
|
||||
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
|
||||
connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
|
||||
connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
|
||||
|
||||
// Send data
|
||||
connection.setDoOutput(true);
|
||||
try (final DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
|
||||
outputStream.write(compressedData);
|
||||
}
|
||||
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
try (final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
}
|
||||
|
||||
if (logResponseStatusText) {
|
||||
plugin.getLogger().info("Sent data to bStats and received response: " + builder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gzips the given String.
|
||||
*
|
||||
* @param str The string to gzip.
|
||||
* @return The gzipped String.
|
||||
* @throws IOException If the compression failed.
|
||||
*/
|
||||
private static byte[] compress(final String str) throws IOException {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try (final GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
|
||||
gzip.write(str.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if bStats is enabled.
|
||||
*
|
||||
* @return Whether bStats is enabled or not.
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom chart.
|
||||
*
|
||||
* @param chart The chart to add.
|
||||
*/
|
||||
public void addCustomChart(final CustomChart chart) {
|
||||
if (chart == null) {
|
||||
throw new IllegalArgumentException("Chart cannot be null!");
|
||||
}
|
||||
charts.add(chart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the Scheduler which submits our data every 30 minutes.
|
||||
*/
|
||||
private void startSubmitting() {
|
||||
final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!plugin.isEnabled()) { // Plugin was disabled
|
||||
timer.cancel();
|
||||
return;
|
||||
}
|
||||
// Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler
|
||||
// Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;)
|
||||
Bukkit.getScheduler().runTask(plugin, () -> submitData());
|
||||
}
|
||||
}, 1000 * 60 * 5, 1000 * 60 * 30);
|
||||
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
|
||||
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
|
||||
// WARNING: Just don't do it!
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plugin specific data.
|
||||
* This method is called using Reflection.
|
||||
*
|
||||
* @return The plugin specific data.
|
||||
*/
|
||||
public JsonObject getPluginData() {
|
||||
final JsonObject data = new JsonObject();
|
||||
|
||||
final String pluginName = plugin.getDescription().getName().replace("Essentials", "EssentialsX");
|
||||
final String pluginVersion = plugin.getDescription().getVersion();
|
||||
|
||||
data.addProperty("pluginName", pluginName); // Append the name of the plugin
|
||||
data.addProperty("id", pluginId); // Append the id of the plugin
|
||||
data.addProperty("pluginVersion", pluginVersion); // Append the version of the plugin
|
||||
final JsonArray customCharts = new JsonArray();
|
||||
for (final CustomChart customChart : charts) {
|
||||
// Add the data of the custom charts
|
||||
final JsonObject chart = customChart.getRequestJsonObject();
|
||||
if (chart == null) { // If the chart is null, we skip it
|
||||
continue;
|
||||
}
|
||||
customCharts.add(chart);
|
||||
}
|
||||
data.add("customCharts", customCharts);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server specific data.
|
||||
*
|
||||
* @return The server specific data.
|
||||
*/
|
||||
private JsonObject getServerData() {
|
||||
// Minecraft specific data
|
||||
int playerAmount;
|
||||
try {
|
||||
// Around MC 1.8 the return type was changed to a collection from an array,
|
||||
// This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
|
||||
final Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
|
||||
playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class)
|
||||
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
|
||||
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
|
||||
} catch (final Exception e) {
|
||||
playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed
|
||||
}
|
||||
final int onlineMode = Bukkit.getOnlineMode() ? 1 : 0;
|
||||
final String bukkitVersion = Bukkit.getVersion();
|
||||
final String bukkitName = Bukkit.getName();
|
||||
|
||||
// OS/Java specific data
|
||||
final String javaVersion = System.getProperty("java.version");
|
||||
final String osName = System.getProperty("os.name");
|
||||
final String osArch = System.getProperty("os.arch");
|
||||
final String osVersion = System.getProperty("os.version");
|
||||
final int coreCount = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
final JsonObject data = new JsonObject();
|
||||
|
||||
data.addProperty("serverUUID", serverUUID);
|
||||
|
||||
data.addProperty("playerAmount", playerAmount);
|
||||
data.addProperty("onlineMode", onlineMode);
|
||||
data.addProperty("bukkitVersion", bukkitVersion);
|
||||
data.addProperty("bukkitName", bukkitName);
|
||||
|
||||
data.addProperty("javaVersion", javaVersion);
|
||||
data.addProperty("osName", osName);
|
||||
data.addProperty("osArch", osArch);
|
||||
data.addProperty("osVersion", osVersion);
|
||||
data.addProperty("coreCount", coreCount);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the data and sends it afterwards.
|
||||
*/
|
||||
private void submitData() {
|
||||
final JsonObject data = getServerData();
|
||||
|
||||
final JsonArray pluginData = new JsonArray();
|
||||
// Search for all other bStats Metrics classes to get their plugin data
|
||||
for (final Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
|
||||
try {
|
||||
service.getField("B_STATS_VERSION"); // Our identifier :)
|
||||
|
||||
for (final RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service)) {
|
||||
try {
|
||||
final Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider());
|
||||
if (plugin instanceof JsonObject) {
|
||||
pluginData.add((JsonObject) plugin);
|
||||
} else { // old bstats version compatibility
|
||||
try {
|
||||
final Class<?> jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject");
|
||||
if (plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) {
|
||||
final Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString");
|
||||
jsonStringGetter.setAccessible(true);
|
||||
final String jsonString = (String) jsonStringGetter.invoke(plugin);
|
||||
final JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject();
|
||||
pluginData.add(object);
|
||||
}
|
||||
} catch (final ClassNotFoundException e) {
|
||||
// minecraft version 1.14+
|
||||
if (logFailedRequests) {
|
||||
this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) {
|
||||
}
|
||||
}
|
||||
} catch (final NoSuchFieldException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
data.add("plugins", pluginData);
|
||||
|
||||
// Create a new thread for the connection to the bStats server
|
||||
new Thread(() -> {
|
||||
try {
|
||||
// Send the data
|
||||
sendData(plugin, data);
|
||||
} catch (final Exception e) {
|
||||
// Something went wrong! :(
|
||||
if (logFailedRequests) {
|
||||
plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom chart.
|
||||
*/
|
||||
public static abstract class CustomChart {
|
||||
|
||||
// The id of the chart
|
||||
final String chartId;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
*/
|
||||
CustomChart(final String chartId) {
|
||||
if (chartId == null || chartId.isEmpty()) {
|
||||
throw new IllegalArgumentException("ChartId cannot be null or empty!");
|
||||
}
|
||||
this.chartId = chartId;
|
||||
}
|
||||
|
||||
private JsonObject getRequestJsonObject() {
|
||||
final JsonObject chart = new JsonObject();
|
||||
chart.addProperty("chartId", chartId);
|
||||
try {
|
||||
final JsonObject data = getChartData();
|
||||
if (data == null) {
|
||||
// If the data is null we don't send the chart.
|
||||
return null;
|
||||
}
|
||||
chart.add("data", data);
|
||||
} catch (final Throwable t) {
|
||||
if (logFailedRequests) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return chart;
|
||||
}
|
||||
|
||||
protected abstract JsonObject getChartData() throws Exception;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom simple pie.
|
||||
*/
|
||||
public static class SimplePie extends CustomChart {
|
||||
|
||||
private final Callable<String> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimplePie(final String chartId, final Callable<String> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final String value = callable.call();
|
||||
if (value == null || value.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.addProperty("value", value);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom advanced pie.
|
||||
*/
|
||||
public static class AdvancedPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedPie(final String chartId, final Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final JsonObject values = new JsonObject();
|
||||
final Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (final Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
continue; // Skip this invalid
|
||||
}
|
||||
allSkipped = false;
|
||||
values.addProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom drilldown pie.
|
||||
*/
|
||||
public static class DrilldownPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Map<String, Integer>>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public DrilldownPie(final String chartId, final Callable<Map<String, Map<String, Integer>>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final JsonObject values = new JsonObject();
|
||||
final Map<String, Map<String, Integer>> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean reallyAllSkipped = true;
|
||||
for (final Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
|
||||
final JsonObject value = new JsonObject();
|
||||
boolean allSkipped = true;
|
||||
for (final Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
|
||||
value.addProperty(valueEntry.getKey(), valueEntry.getValue());
|
||||
allSkipped = false;
|
||||
}
|
||||
if (!allSkipped) {
|
||||
reallyAllSkipped = false;
|
||||
values.add(entryValues.getKey(), value);
|
||||
}
|
||||
}
|
||||
if (reallyAllSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom single line chart.
|
||||
*/
|
||||
public static class SingleLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Integer> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SingleLineChart(final String chartId, final Callable<Integer> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final int value = callable.call();
|
||||
if (value == 0) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.addProperty("value", value);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom multi line chart.
|
||||
*/
|
||||
public static class MultiLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public MultiLineChart(final String chartId, final Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final JsonObject values = new JsonObject();
|
||||
final Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (final Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
continue; // Skip this invalid
|
||||
}
|
||||
allSkipped = false;
|
||||
values.addProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom simple bar chart.
|
||||
*/
|
||||
public static class SimpleBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimpleBarChart(final String chartId, final Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final JsonObject values = new JsonObject();
|
||||
final Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
for (final Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
final JsonArray categoryValues = new JsonArray();
|
||||
categoryValues.add(new JsonPrimitive(entry.getValue()));
|
||||
values.add(entry.getKey(), categoryValues);
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom advanced bar chart.
|
||||
*/
|
||||
public static class AdvancedBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, int[]>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedBarChart(final String chartId, final Callable<Map<String, int[]>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final JsonObject values = new JsonObject();
|
||||
final Map<String, int[]> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (final Map.Entry<String, int[]> entry : map.entrySet()) {
|
||||
if (entry.getValue().length == 0) {
|
||||
continue; // Skip this invalid
|
||||
}
|
||||
allSkipped = false;
|
||||
final JsonArray categoryValues = new JsonArray();
|
||||
for (final int categoryValue : entry.getValue()) {
|
||||
categoryValues.add(new JsonPrimitive(categoryValue));
|
||||
}
|
||||
values.add(entry.getKey(), categoryValues);
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
package com.earth2me.essentials.metrics;
|
||||
|
||||
import com.earth2me.essentials.Essentials;
|
||||
import com.earth2me.essentials.register.payment.Methods;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MetricsWrapper {
|
||||
|
||||
private static final List<String> KNOWN_FORCED_METRICS = ImmutableList.of("ChatControl");
|
||||
private static boolean hasWarned = false;
|
||||
private final Essentials ess;
|
||||
private final Metrics metrics;
|
||||
private final Map<String, Boolean> commands = new HashMap<>();
|
||||
private final Plugin plugin;
|
||||
|
||||
public MetricsWrapper(final Plugin plugin, final int pluginId, final boolean includeCommands) {
|
||||
this.plugin = plugin;
|
||||
this.ess = (Essentials) Bukkit.getPluginManager().getPlugin("Essentials");
|
||||
this.metrics = new Metrics(plugin, pluginId);
|
||||
|
||||
if (metrics.isEnabled()) {
|
||||
plugin.getLogger().info("Starting Metrics. Opt-out using the global bStats config.");
|
||||
} else {
|
||||
plugin.getLogger().info("Metrics disabled per bStats config.");
|
||||
}
|
||||
|
||||
checkForcedMetrics();
|
||||
addPermsChart();
|
||||
addEconomyChart();
|
||||
|
||||
// bStats' backend currently doesn't support multi-line charts or advanced bar charts
|
||||
// These are included for when bStats is ready to accept this data
|
||||
addVersionHistoryChart();
|
||||
if (includeCommands) addCommandsChart();
|
||||
}
|
||||
|
||||
public void markCommand(final String command, final boolean state) {
|
||||
commands.put(command, state);
|
||||
}
|
||||
|
||||
public void addCustomChart(final Metrics.CustomChart chart) {
|
||||
metrics.addCustomChart(chart);
|
||||
}
|
||||
|
||||
private void addPermsChart() {
|
||||
metrics.addCustomChart(new Metrics.DrilldownPie("permsPlugin", () -> {
|
||||
final Map<String, Map<String, Integer>> result = new HashMap<>();
|
||||
final String handler = ess.getPermissionsHandler().getName();
|
||||
final Map<String, Integer> backend = new HashMap<>();
|
||||
backend.put(ess.getPermissionsHandler().getBackendName(), 1);
|
||||
result.put(handler, backend);
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
|
||||
private void addEconomyChart() {
|
||||
metrics.addCustomChart(new Metrics.DrilldownPie("econPlugin", () -> {
|
||||
final Map<String, Map<String, Integer>> result = new HashMap<>();
|
||||
final Map<String, Integer> backend = new HashMap<>();
|
||||
if (Methods.hasMethod()) {
|
||||
backend.put(Methods.getMethod().getBackend(), 1);
|
||||
result.put(Methods.getMethod().getName(), backend);
|
||||
} else {
|
||||
backend.put("Essentials", 1);
|
||||
result.put("Essentials", backend);
|
||||
}
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
|
||||
private void addVersionHistoryChart() {
|
||||
metrics.addCustomChart(new Metrics.MultiLineChart("versionHistory", () -> {
|
||||
final HashMap<String, Integer> result = new HashMap<>();
|
||||
result.put(plugin.getDescription().getVersion(), 1);
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
|
||||
private void addCommandsChart() {
|
||||
for (final String command : plugin.getDescription().getCommands().keySet()) {
|
||||
markCommand(command, false);
|
||||
}
|
||||
|
||||
metrics.addCustomChart(new Metrics.AdvancedBarChart("commands", () -> {
|
||||
final Map<String, int[]> result = new HashMap<>();
|
||||
for (final Map.Entry<String, Boolean> entry : commands.entrySet()) {
|
||||
if (entry.getValue()) {
|
||||
result.put(entry.getKey(), new int[] {1, 0});
|
||||
} else {
|
||||
result.put(entry.getKey(), new int[] {0, 1});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
|
||||
private void checkForcedMetrics() {
|
||||
if (hasWarned) return;
|
||||
hasWarned = true;
|
||||
|
||||
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
||||
for (final Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
|
||||
try {
|
||||
service.getField("B_STATS_VERSION"); // Identifies bStats classes
|
||||
|
||||
final JavaPlugin owningPlugin = getProvidingPlugin(service);
|
||||
if (owningPlugin != null && KNOWN_FORCED_METRICS.contains(owningPlugin.getName())) {
|
||||
warnForcedMetrics(service);
|
||||
} else {
|
||||
try {
|
||||
service.getDeclaredField("pluginId"); // Only present in recent bStats classes, which should also have the enabled field unless modified
|
||||
} catch (final NoSuchFieldException e) {
|
||||
// Old bStats class found so "enabled" field detection is unreliable.
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
service.getDeclaredField("enabled"); // In modified forced metrics classes, this will fail
|
||||
} catch (final NoSuchFieldException e) {
|
||||
warnForcedMetrics(service);
|
||||
}
|
||||
}
|
||||
} catch (final NoSuchFieldException ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void warnForcedMetrics(final Class<?> service) {
|
||||
final Plugin servicePlugin = JavaPlugin.getProvidingPlugin(service);
|
||||
plugin.getLogger().severe("WARNING: Potential forced metrics collection by plugin '" + servicePlugin.getName() + "' v" + servicePlugin.getDescription().getVersion());
|
||||
plugin.getLogger().severe("Your server is running a plugin that may not respect bStats' opt-out settings.");
|
||||
plugin.getLogger().severe("This may cause data to be uploaded to bStats.org for plugins that use bStats, even if you've opted out in the bStats config.");
|
||||
plugin.getLogger().severe("Please report this to bStats and to the authors of '" + servicePlugin.getName() + "'. (Offending class: " + service.getName() + ")");
|
||||
}
|
||||
|
||||
private JavaPlugin getProvidingPlugin(final Class<?> clazz) {
|
||||
try {
|
||||
return JavaPlugin.getProvidingPlugin(clazz);
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
|
||||
final ClassLoader parent = clazz.getClassLoader().getParent();
|
||||
if (parent.getClass().getName().equals("org.bukkit.plugin.java.PluginClassLoader")) {
|
||||
try {
|
||||
final Field pluginField = parent.getClass().getDeclaredField("plugin");
|
||||
pluginField.setAccessible(true);
|
||||
return (JavaPlugin) pluginField.get(parent);
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.earth2me.essentials.perm;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface IPermissionsHandler {
|
||||
String getGroup(Player base);
|
||||
|
||||
List<String> getGroups(Player base);
|
||||
|
||||
boolean canBuild(Player base, String group);
|
||||
|
||||
boolean inGroup(Player base, String group);
|
||||
|
||||
boolean hasPermission(Player base, String node);
|
||||
|
||||
// Does not check for * permissions
|
||||
boolean isPermissionSet(Player base, String node);
|
||||
|
||||
String getPrefix(Player base);
|
||||
|
||||
String getSuffix(Player base);
|
||||
|
||||
void registerContext(String context, Function<Player, Iterable<String>> calculator, Supplier<Iterable<String>> suggestions);
|
||||
|
||||
void unregisterContexts();
|
||||
|
||||
String getBackendName();
|
||||
|
||||
boolean tryProvider();
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.earth2me.essentials.perm.impl;
|
||||
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.context.ContextCalculator;
|
||||
import net.luckperms.api.context.ContextConsumer;
|
||||
import net.luckperms.api.context.ContextSet;
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LuckPermsHandler extends ModernVaultHandler {
|
||||
private LuckPerms luckPerms;
|
||||
private Set<ContextCalculator<Player>> contextCalculators;
|
||||
|
||||
@Override
|
||||
public void registerContext(final String context, final Function<Player, Iterable<String>> calculator, final Supplier<Iterable<String>> suggestions) {
|
||||
final ContextCalculator<Player> contextCalculator = new ContextCalculator<Player>() {
|
||||
@Override
|
||||
public void calculate(final Player target, final ContextConsumer consumer) {
|
||||
calculator.apply(target).forEach(value -> consumer.accept(context, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextSet estimatePotentialContexts() {
|
||||
final ImmutableContextSet.Builder builder = ImmutableContextSet.builder();
|
||||
suggestions.get().forEach(value -> builder.add(context, value));
|
||||
return builder.build();
|
||||
}
|
||||
};
|
||||
luckPerms.getContextManager().registerCalculator(contextCalculator);
|
||||
contextCalculators.add(contextCalculator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterContexts() {
|
||||
contextCalculators.forEach(contextCalculator -> luckPerms.getContextManager().unregisterCalculator(contextCalculator));
|
||||
contextCalculators.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryProvider() {
|
||||
final RegisteredServiceProvider<LuckPerms> provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class);
|
||||
if (provider != null) {
|
||||
luckPerms = provider.getProvider();
|
||||
contextCalculators = new HashSet<>();
|
||||
}
|
||||
return luckPerms != null && super.tryProvider();
|
||||
}
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
package com.earth2me.essentials.register.payment;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by a payment method.
|
||||
* Copyright (C) 2011
|
||||
* AOL license <http://aol.nexua.org>
|
||||
* <p>
|
||||
* For more information about the licensing of this code in EssentialsX, see below:
|
||||
* https://gist.github.com/md678685/0935441c9573c030c8bd5a2e604aeec3
|
||||
*
|
||||
* @author Nijikokun <nijikokun@shortmail.com> (@nijikokun)
|
||||
*/
|
||||
public interface Method {
|
||||
/**
|
||||
* Encodes the Plugin into an Object disguised as the Plugin. If you want the original Plugin Class you must cast it
|
||||
* to the correct Plugin, to do so you have to verify the name and or version then cast.
|
||||
* <p/>
|
||||
* <pre>
|
||||
* if(method.getName().equalsIgnoreCase("iConomy"))
|
||||
* iConomy plugin = ((iConomy)method.getPlugin());</pre>
|
||||
*
|
||||
* @return <code>Object</code>
|
||||
* @see #getName()
|
||||
* @see #getVersion()
|
||||
*/
|
||||
Plugin getPlugin();
|
||||
|
||||
/**
|
||||
* Set Plugin data.
|
||||
*
|
||||
* @param plugin Plugin
|
||||
*/
|
||||
void setPlugin(Plugin plugin);
|
||||
|
||||
/**
|
||||
* Returns the actual name of this method.
|
||||
*
|
||||
* @return <code>String</code> Plugin name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns the backend plugin of this economy method, if applicable.
|
||||
*
|
||||
* @return <code>String</code> Plugin name.
|
||||
*/
|
||||
String getBackend();
|
||||
|
||||
/**
|
||||
* Returns the reported name of this method.
|
||||
*
|
||||
* @return <code>String</code> Plugin name.
|
||||
*/
|
||||
String getLongName();
|
||||
|
||||
/**
|
||||
* Returns the actual version of this method.
|
||||
*
|
||||
* @return <code>String</code> Plugin version.
|
||||
*/
|
||||
String getVersion();
|
||||
|
||||
/**
|
||||
* Returns the amount of decimal places that get stored NOTE: it will return -1 if there is no rounding
|
||||
*
|
||||
* @return <code>int</code> for each decimal place
|
||||
*/
|
||||
int fractionalDigits();
|
||||
|
||||
/**
|
||||
* Formats amounts into this payment methods style of currency display.
|
||||
*
|
||||
* @param amount Double
|
||||
* @return <code>String</code> - Formatted Currency Display.
|
||||
*/
|
||||
String format(double amount);
|
||||
|
||||
/**
|
||||
* Allows the verification of bank API existence in this payment method.
|
||||
*
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
boolean hasBanks();
|
||||
|
||||
/**
|
||||
* Determines the existence of a bank via name.
|
||||
*
|
||||
* @param bank Bank name
|
||||
* @return <code>boolean</code>
|
||||
* @see #hasBanks
|
||||
*/
|
||||
boolean hasBank(String bank);
|
||||
|
||||
/**
|
||||
* Determines the existence of an account via name.
|
||||
*
|
||||
* @param name Account name
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
boolean hasAccount(String name);
|
||||
|
||||
/**
|
||||
* Check to see if an account <code>name</code> is tied to a <code>bank</code>.
|
||||
*
|
||||
* @param bank Bank name
|
||||
* @param name Account name
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
boolean hasBankAccount(String bank, String name);
|
||||
|
||||
/**
|
||||
* Forces an account creation
|
||||
*
|
||||
* @param name Account name
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
boolean createAccount(String name);
|
||||
|
||||
/**
|
||||
* Forces an account creation
|
||||
*
|
||||
* @param name Account name
|
||||
* @param balance Initial account balance
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
boolean createAccount(String name, Double balance);
|
||||
|
||||
/**
|
||||
* Returns a <code>MethodAccount</code> class for an account <code>name</code>.
|
||||
*
|
||||
* @param name Account name
|
||||
* @return <code>MethodAccount</code> <em>or</em> <code>Null</code>
|
||||
*/
|
||||
MethodAccount getAccount(String name);
|
||||
|
||||
/**
|
||||
* Returns a <code>MethodBankAccount</code> class for an account <code>name</code>.
|
||||
*
|
||||
* @param bank Bank name
|
||||
* @param name Account name
|
||||
* @return <code>MethodBankAccount</code> <em>or</em> <code>Null</code>
|
||||
*/
|
||||
MethodBankAccount getBankAccount(String bank, String name);
|
||||
|
||||
/**
|
||||
* Checks to verify the compatibility between this Method and a plugin. Internal usage only, for the most part.
|
||||
*
|
||||
* @param plugin Plugin
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
boolean isCompatible(Plugin plugin);
|
||||
|
||||
/**
|
||||
* Contains Calculator and Balance functions for Accounts.
|
||||
*/
|
||||
interface MethodAccount {
|
||||
double balance();
|
||||
|
||||
boolean set(double amount);
|
||||
|
||||
boolean add(double amount);
|
||||
|
||||
boolean subtract(double amount);
|
||||
|
||||
boolean multiply(double amount);
|
||||
|
||||
boolean divide(double amount);
|
||||
|
||||
boolean hasEnough(double amount);
|
||||
|
||||
boolean hasOver(double amount);
|
||||
|
||||
boolean hasUnder(double amount);
|
||||
|
||||
boolean isNegative();
|
||||
|
||||
boolean remove();
|
||||
|
||||
@Override
|
||||
String toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains Calculator and Balance functions for Bank Accounts.
|
||||
*/
|
||||
interface MethodBankAccount {
|
||||
double balance();
|
||||
|
||||
String getBankName();
|
||||
|
||||
int getBankId();
|
||||
|
||||
boolean set(double amount);
|
||||
|
||||
boolean add(double amount);
|
||||
|
||||
boolean subtract(double amount);
|
||||
|
||||
boolean multiply(double amount);
|
||||
|
||||
boolean divide(double amount);
|
||||
|
||||
boolean hasEnough(double amount);
|
||||
|
||||
boolean hasOver(double amount);
|
||||
|
||||
boolean hasUnder(double amount);
|
||||
|
||||
boolean isNegative();
|
||||
|
||||
boolean remove();
|
||||
|
||||
@Override
|
||||
String toString();
|
||||
}
|
||||
}
|
||||
@@ -1,245 +0,0 @@
|
||||
package com.earth2me.essentials.register.payment;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The <code>Methods</code> initializes Methods that utilize the Method interface based on a "first come, first served"
|
||||
* basis.
|
||||
* <p/>
|
||||
* Allowing you to check whether a payment method exists or not.
|
||||
* <p/>
|
||||
* Methods also allows you to set a preferred method of payment before it captures payment plugins in the initialization
|
||||
* process.
|
||||
* <p/>
|
||||
* in
|
||||
* <code>bukkit.yml</code>: <blockquote><pre>
|
||||
* economy:
|
||||
* preferred: "iConomy"
|
||||
* </pre></blockquote>
|
||||
* <p>
|
||||
* For more information about the licensing of this code in EssentialsX, see below:
|
||||
* https://gist.github.com/md678685/0935441c9573c030c8bd5a2e604aeec3
|
||||
*
|
||||
* @author Nijikokun <nijikokun@shortmail.com> (@nijikokun) @copyright: Copyright (C) 2011 @license: AOL license
|
||||
* <http://aol.nexua.org>
|
||||
*/
|
||||
public final class Methods {
|
||||
private static final Set<Method> Methods = new HashSet<>();
|
||||
private static final Set<String> Dependencies = new HashSet<>();
|
||||
private static final Set<Method> Attachables = new HashSet<>();
|
||||
private static String version = null;
|
||||
private static boolean self = false;
|
||||
private static Method Method = null;
|
||||
private static String preferred = "";
|
||||
|
||||
private Methods() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement all methods along with their respective name & class.
|
||||
*/
|
||||
public static void init() {
|
||||
if (!Methods.isEmpty()) {
|
||||
throw new IllegalStateException("Methods already initialised!");
|
||||
}
|
||||
|
||||
addMethod("Vault", new com.earth2me.essentials.register.payment.methods.VaultEco());
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to reset methods during disable
|
||||
*/
|
||||
public static void reset() {
|
||||
version = null;
|
||||
self = false;
|
||||
Method = null;
|
||||
preferred = "";
|
||||
Attachables.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to get version of Register plugin
|
||||
*
|
||||
* @return version
|
||||
*/
|
||||
public static String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the plugin to setup version
|
||||
*
|
||||
* @param v version
|
||||
*/
|
||||
public static void setVersion(final String v) {
|
||||
version = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of payment method names that have been loaded through the <code>_init</code> method.
|
||||
*
|
||||
* @return <code>Set<String></code> - Array of payment methods that are loaded.
|
||||
* @see #setMethod(PluginManager)
|
||||
*/
|
||||
public static Set<String> getDependencies() {
|
||||
return Dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interprets Plugin class data to verify whether it is compatible with an existing payment method to use for
|
||||
* payments and other various economic activity.
|
||||
*
|
||||
* @param plugin Plugin data from bukkit, Internal Class file.
|
||||
* @return Method <em>or</em> Null
|
||||
*/
|
||||
public static Method createMethod(final Plugin plugin) {
|
||||
for (final Method method : Methods) {
|
||||
if (method.isCompatible(plugin)) {
|
||||
method.setPlugin(plugin);
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void addMethod(final String name, final Method method) {
|
||||
Dependencies.add(name);
|
||||
Methods.add(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if Register has set a payment method for usage yet.
|
||||
*
|
||||
* @return <code>boolean</code>
|
||||
* @see #setMethod(PluginManager)
|
||||
* @see #checkDisabled(Plugin)
|
||||
*/
|
||||
public static boolean hasMethod() {
|
||||
return Method != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks Plugin Class against a multitude of checks to verify it's usability as a payment method.
|
||||
*
|
||||
* @param manager the plugin manager for the server
|
||||
* @return <code>boolean</code> True on success, False on failure.
|
||||
*/
|
||||
public static boolean setMethod(final PluginManager manager) {
|
||||
if (hasMethod()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (self) {
|
||||
self = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
boolean match = false;
|
||||
Plugin plugin;
|
||||
|
||||
for (final String name : getDependencies()) {
|
||||
if (hasMethod()) {
|
||||
break;
|
||||
}
|
||||
|
||||
plugin = manager.getPlugin(name);
|
||||
if (plugin == null || !plugin.isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Method current = createMethod(plugin);
|
||||
if (current == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preferred.isEmpty()) {
|
||||
Method = current;
|
||||
} else {
|
||||
Attachables.add(current);
|
||||
}
|
||||
}
|
||||
|
||||
if (!preferred.isEmpty()) {
|
||||
do {
|
||||
if (hasMethod()) {
|
||||
match = true;
|
||||
} else {
|
||||
for (final Method attached : Attachables) {
|
||||
if (attached == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasMethod()) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (preferred.isEmpty()) {
|
||||
Method = attached;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
if (preferred.equalsIgnoreCase(attached.getName())) {
|
||||
Method = attached;
|
||||
} else {
|
||||
Method = attached;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
} while (!match);
|
||||
}
|
||||
|
||||
return hasMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the preferred economy
|
||||
*
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
public static boolean setPreferred(final String check) {
|
||||
if (getDependencies().contains(check)) {
|
||||
preferred = check;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grab the existing and initialized (hopefully) Method Class.
|
||||
*
|
||||
* @return <code>Method</code> <em>or</em> <code>Null</code>
|
||||
*/
|
||||
public static Method getMethod() {
|
||||
return Method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify is a plugin is disabled, only does this if we there is an existing payment method initialized in
|
||||
* Register.
|
||||
*
|
||||
* @param method Plugin data from bukkit, Internal Class file.
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
public static boolean checkDisabled(final Plugin method) {
|
||||
if (!hasMethod()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Method.isCompatible(method)) {
|
||||
Method = null;
|
||||
}
|
||||
|
||||
return Method == null;
|
||||
}
|
||||
}
|
||||
@@ -1,280 +0,0 @@
|
||||
package com.earth2me.essentials.register.payment.methods;
|
||||
|
||||
import com.earth2me.essentials.register.payment.Method;
|
||||
import net.milkbowl.vault.economy.Economy;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
public class VaultEco implements Method {
|
||||
private Plugin vault;
|
||||
private Economy economy;
|
||||
|
||||
@Override
|
||||
public Plugin getPlugin() {
|
||||
return this.vault;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlugin(final Plugin plugin) {
|
||||
this.vault = plugin;
|
||||
final RegisteredServiceProvider<Economy> economyProvider = this.vault.getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
|
||||
if (economyProvider != null) {
|
||||
this.economy = economyProvider.getProvider();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createAccount(final String name, final Double amount) {
|
||||
if (hasAccount(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.vault.getDescription().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBackend() {
|
||||
return economy == null ? "NoEco" : economy.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLongName() {
|
||||
return getName().concat(" - Economy: ").concat(getBackend());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return this.vault.getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fractionalDigits() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(final double amount) {
|
||||
return this.economy.format(amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBanks() {
|
||||
return this.economy.hasBankSupport();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBank(final String bank) {
|
||||
return this.economy.getBanks().contains(bank);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAccount(final String name) {
|
||||
return this.economy.hasAccount(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBankAccount(final String bank, final String name) {
|
||||
return this.economy.isBankOwner(bank, name).transactionSuccess() || this.economy.isBankMember(bank, name).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createAccount(final String name) {
|
||||
return this.economy.createBank(name, "").transactionSuccess();
|
||||
}
|
||||
|
||||
public boolean createAccount(final String name, final double balance) {
|
||||
if (!this.economy.createBank(name, "").transactionSuccess()) {
|
||||
return false;
|
||||
}
|
||||
return this.economy.bankDeposit(name, balance).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodAccount getAccount(final String name) {
|
||||
if (!hasAccount(name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new VaultAccount(name, this.economy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodBankAccount getBankAccount(final String bank, final String name) {
|
||||
if (!hasBankAccount(bank, name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new VaultBankAccount(bank, economy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompatible(final Plugin plugin) {
|
||||
try {
|
||||
final RegisteredServiceProvider<Economy> ecoPlugin = plugin.getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
|
||||
return plugin.getName().equals("Vault") && ecoPlugin != null && !ecoPlugin.getProvider().getName().equals("Essentials Economy");
|
||||
} catch (final LinkageError | Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class VaultAccount implements MethodAccount {
|
||||
private final String name;
|
||||
private final Economy economy;
|
||||
|
||||
VaultAccount(final String name, final Economy economy) {
|
||||
this.name = name;
|
||||
this.economy = economy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double balance() {
|
||||
return this.economy.getBalance(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean set(final double amount) {
|
||||
if (!this.economy.withdrawPlayer(this.name, this.balance()).transactionSuccess()) {
|
||||
return false;
|
||||
}
|
||||
if (amount == 0) {
|
||||
return true;
|
||||
}
|
||||
return this.economy.depositPlayer(this.name, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(final double amount) {
|
||||
return this.economy.depositPlayer(this.name, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean subtract(final double amount) {
|
||||
return this.economy.withdrawPlayer(this.name, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean multiply(final double amount) {
|
||||
final double balance = this.balance();
|
||||
return this.set(balance * amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean divide(final double amount) {
|
||||
final double balance = this.balance();
|
||||
return this.set(balance / amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEnough(final double amount) {
|
||||
return this.balance() >= amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOver(final double amount) {
|
||||
return this.balance() > amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnder(final double amount) {
|
||||
return this.balance() < amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegative() {
|
||||
return this.balance() < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove() {
|
||||
return this.set(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
public static class VaultBankAccount implements MethodBankAccount {
|
||||
private final String bank;
|
||||
private final Economy economy;
|
||||
|
||||
public VaultBankAccount(final String bank, final Economy economy) {
|
||||
this.bank = bank;
|
||||
this.economy = economy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBankName() {
|
||||
return this.bank;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBankId() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double balance() {
|
||||
return this.economy.bankBalance(this.bank).balance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean set(final double amount) {
|
||||
if (!this.economy.bankWithdraw(this.bank, this.balance()).transactionSuccess()) {
|
||||
return false;
|
||||
}
|
||||
if (amount == 0) {
|
||||
return true;
|
||||
}
|
||||
return this.economy.bankDeposit(this.bank, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(final double amount) {
|
||||
return this.economy.bankDeposit(this.bank, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean subtract(final double amount) {
|
||||
return this.economy.bankWithdraw(this.bank, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean multiply(final double amount) {
|
||||
final double balance = this.balance();
|
||||
return this.set(balance * amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean divide(final double amount) {
|
||||
final double balance = this.balance();
|
||||
return this.set(balance / amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEnough(final double amount) {
|
||||
return this.balance() >= amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOver(final double amount) {
|
||||
return this.balance() > amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnder(final double amount) {
|
||||
return this.balance() < amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegative() {
|
||||
return this.balance() < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove() {
|
||||
return this.set(0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.earth2me.essentials.settings;
|
||||
|
||||
import com.earth2me.essentials.storage.MapValueType;
|
||||
import com.earth2me.essentials.storage.StorageObject;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Jails implements StorageObject {
|
||||
@MapValueType(Location.class)
|
||||
private Map<String, Location> jails = new HashMap<>();
|
||||
|
||||
public Map<String, Location> getJails() {
|
||||
return jails;
|
||||
}
|
||||
|
||||
public void setJails(final Map<String, Location> jails) {
|
||||
this.jails = jails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Jails jails1 = (Jails) o;
|
||||
return Objects.equals(jails, jails1.jails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(jails);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.earth2me.essentials.settings;
|
||||
|
||||
import com.earth2me.essentials.storage.MapValueType;
|
||||
import com.earth2me.essentials.storage.StorageObject;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Spawns implements StorageObject {
|
||||
@MapValueType(Location.class)
|
||||
private Map<String, Location> spawns = new HashMap<>();
|
||||
|
||||
public Map<String, Location> getSpawns() {
|
||||
return spawns;
|
||||
}
|
||||
|
||||
public void setSpawns(final Map<String, Location> spawns) {
|
||||
this.spawns = spawns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Spawns spawns1 = (Spawns) o;
|
||||
return Objects.equals(spawns, spawns1.spawns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(spawns);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.earth2me.essentials.signs;
|
||||
|
||||
public class SignException extends Exception {
|
||||
public SignException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SignException(final String message, final Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.earth2me.essentials.signs;
|
||||
|
||||
import com.earth2me.essentials.User;
|
||||
import net.ess3.api.IEssentials;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class SignMail extends EssentialsSign {
|
||||
public SignMail() {
|
||||
super("Mail");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException {
|
||||
final List<String> mail = player.getMails();
|
||||
if (mail.isEmpty()) {
|
||||
player.sendMessage(tl("noNewMail"));
|
||||
return false;
|
||||
}
|
||||
for (final String s : mail) {
|
||||
player.sendMessage(s);
|
||||
}
|
||||
player.sendMessage(tl("markMailAsRead"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public abstract class AbstractDelayedYamlFileReader<T extends StorageObject> implements Runnable {
|
||||
protected final transient IEssentials plugin;
|
||||
private final transient File file;
|
||||
private final transient Class<T> clazz;
|
||||
|
||||
public AbstractDelayedYamlFileReader(final IEssentials ess, final File file, final Class<T> clazz) {
|
||||
this.file = file;
|
||||
this.clazz = clazz;
|
||||
this.plugin = ess;
|
||||
ess.runTaskAsynchronously(this);
|
||||
}
|
||||
|
||||
public abstract void onStart();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
onStart();
|
||||
try {
|
||||
final FileReader reader = new FileReader(file);
|
||||
try {
|
||||
final T object = new YamlStorageReader(reader, plugin).load(clazz);
|
||||
onSuccess(object);
|
||||
} finally {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (final IOException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "File can't be closed: " + file.toString(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (final FileNotFoundException ex) {
|
||||
onException();
|
||||
if (plugin.getSettings() == null || plugin.getSettings().isDebug()) {
|
||||
Bukkit.getLogger().log(Level.INFO, "File not found: " + file.toString());
|
||||
}
|
||||
} catch (final ObjectLoadException ex) {
|
||||
onException();
|
||||
Bukkit.getLogger().log(Level.SEVERE, "File broken: " + file.toString(), ex.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void onSuccess(T object);
|
||||
|
||||
public abstract void onException();
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public abstract class AbstractDelayedYamlFileWriter implements Runnable {
|
||||
private final transient File file;
|
||||
|
||||
public AbstractDelayedYamlFileWriter(final IEssentials ess, final File file) {
|
||||
this.file = file;
|
||||
ess.runTaskAsynchronously(this);
|
||||
}
|
||||
|
||||
public abstract StorageObject getObject();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
PrintWriter pw = null;
|
||||
try {
|
||||
final StorageObject object = getObject();
|
||||
final File folder = file.getParentFile();
|
||||
if (!folder.exists()) {
|
||||
folder.mkdirs();
|
||||
}
|
||||
pw = new PrintWriter(file);
|
||||
new YamlStorageWriter(pw).save(object);
|
||||
} catch (final FileNotFoundException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, file.toString(), ex);
|
||||
} finally {
|
||||
onFinish();
|
||||
if (pw != null) {
|
||||
pw.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract void onFinish();
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import com.earth2me.essentials.IConf;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.IReload;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public abstract class AsyncStorageObjectHolder<T extends StorageObject> implements IConf, IStorageObjectHolder<T>, IReload {
|
||||
protected final transient IEssentials ess;
|
||||
private final transient ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||
private final transient Class<T> clazz;
|
||||
private transient T data;
|
||||
|
||||
public AsyncStorageObjectHolder(final IEssentials ess, final Class<T> clazz) {
|
||||
this.ess = ess;
|
||||
this.clazz = clazz;
|
||||
try {
|
||||
this.data = clazz.newInstance();
|
||||
} catch (final IllegalAccessException | InstantiationException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acquireReadLock() {
|
||||
rwl.readLock().lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acquireWriteLock() {
|
||||
while (rwl.getReadHoldCount() > 0) {
|
||||
rwl.readLock().unlock();
|
||||
}
|
||||
rwl.writeLock().lock();
|
||||
rwl.readLock().lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
if (rwl.isWriteLockedByCurrentThread()) {
|
||||
rwl.writeLock().unlock();
|
||||
new StorageObjectDataWriter();
|
||||
}
|
||||
while (rwl.getReadHoldCount() > 0) {
|
||||
rwl.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
new StorageObjectDataReader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload() {
|
||||
new StorageObjectDataReader();
|
||||
}
|
||||
|
||||
public abstract void finishRead();
|
||||
|
||||
public abstract void finishWrite();
|
||||
|
||||
public abstract File getStorageFile();
|
||||
|
||||
private class StorageObjectDataWriter extends AbstractDelayedYamlFileWriter {
|
||||
StorageObjectDataWriter() {
|
||||
super(ess, getStorageFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageObject getObject() {
|
||||
acquireReadLock();
|
||||
return getData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
unlock();
|
||||
finishWrite();
|
||||
}
|
||||
}
|
||||
|
||||
private class StorageObjectDataReader extends AbstractDelayedYamlFileReader<T> {
|
||||
StorageObjectDataReader() {
|
||||
super(ess, getStorageFile(), clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
rwl.writeLock().lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(final T object) {
|
||||
if (object != null) {
|
||||
data = object;
|
||||
}
|
||||
rwl.writeLock().unlock();
|
||||
finishRead();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException() {
|
||||
if (data == null) {
|
||||
try {
|
||||
data = clazz.newInstance();
|
||||
} catch (final IllegalAccessException | InstantiationException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
rwl.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import com.earth2me.essentials.Enchantments;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.material.MaterialData;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.yaml.snakeyaml.constructor.BaseConstructor;
|
||||
import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor;
|
||||
import org.yaml.snakeyaml.introspector.PropertyUtils;
|
||||
import org.yaml.snakeyaml.nodes.MappingNode;
|
||||
import org.yaml.snakeyaml.nodes.Node;
|
||||
import org.yaml.snakeyaml.nodes.NodeId;
|
||||
import org.yaml.snakeyaml.nodes.NodeTuple;
|
||||
import org.yaml.snakeyaml.nodes.ScalarNode;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class BukkitConstructor extends CustomClassLoaderConstructor {
|
||||
private Method constructScalarMethod = null;
|
||||
|
||||
public BukkitConstructor(final Class<?> clazz, final Plugin plugin) {
|
||||
super(clazz, plugin.getClass().getClassLoader());
|
||||
yamlClassConstructors.put(NodeId.scalar, new ConstructBukkitScalar());
|
||||
yamlClassConstructors.put(NodeId.mapping, new ConstructBukkitMapping());
|
||||
|
||||
final PropertyUtils propertyUtils = getPropertyUtils();
|
||||
propertyUtils.setSkipMissingProperties(true);
|
||||
setPropertyUtils(propertyUtils);
|
||||
}
|
||||
|
||||
protected String constructScalarRefl(final ScalarNode scalarNode) {
|
||||
try {
|
||||
if (constructScalarMethod == null) {
|
||||
constructScalarMethod = BaseConstructor.class.getDeclaredMethod("constructScalar", ScalarNode.class);
|
||||
}
|
||||
return (String) constructScalarMethod.invoke(this, scalarNode);
|
||||
} catch (final NoSuchMethodException
|
||||
| SecurityException
|
||||
| IllegalAccessException
|
||||
| IllegalArgumentException
|
||||
| InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private class ConstructBukkitScalar extends ConstructScalar {
|
||||
|
||||
@Override
|
||||
public Object construct(final Node node) {
|
||||
if (node.getType().equals(Material.class)) {
|
||||
final String val = constructScalarRefl((ScalarNode) node);
|
||||
return Material.matchMaterial(val);
|
||||
}
|
||||
|
||||
if (node.getType().equals(MaterialData.class)) {
|
||||
final String val = constructScalarRefl((ScalarNode) node);
|
||||
if (val.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final String[] split = val.split("[:+',;.]", 2);
|
||||
if (split.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Material mat = Material.matchMaterial(split[0]);
|
||||
|
||||
if (mat == null) {
|
||||
return null;
|
||||
}
|
||||
byte data = 0;
|
||||
if (split.length == 2 && NumberUtil.isInt(split[1])) {
|
||||
data = Byte.parseByte(split[1]);
|
||||
}
|
||||
return new MaterialData(mat, data);
|
||||
}
|
||||
if (node.getType().equals(ItemStack.class)) {
|
||||
final String val = constructScalarRefl((ScalarNode) node);
|
||||
if (val.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final String[] split1 = val.split("\\W");
|
||||
if (split1.length == 0) {
|
||||
return null;
|
||||
}
|
||||
final String[] split2 = split1[0].split("[:+',;.]", 2);
|
||||
if (split2.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Material mat = Material.matchMaterial(split2[0]);
|
||||
|
||||
if (mat == null) {
|
||||
return null;
|
||||
}
|
||||
short data = 0;
|
||||
if (split2.length == 2 && NumberUtil.isInt(split2[1])) {
|
||||
data = Short.parseShort(split2[1]);
|
||||
}
|
||||
int size = mat.getMaxStackSize();
|
||||
if (split1.length > 1 && NumberUtil.isInt(split1[1])) {
|
||||
size = Integer.parseInt(split1[1]);
|
||||
}
|
||||
final ItemStack stack = new ItemStack(mat, size, data);
|
||||
if (split1.length > 2) {
|
||||
for (int i = 2; i < split1.length; i++) {
|
||||
final String[] split3 = split1[0].split("[:+',;.]", 2);
|
||||
if (split3.length < 1) {
|
||||
continue;
|
||||
}
|
||||
final Enchantment enchantment = Enchantments.getByName(split3[0]);
|
||||
if (enchantment == null) {
|
||||
continue;
|
||||
}
|
||||
int level = enchantment.getStartLevel();
|
||||
if (split3.length == 2 && NumberUtil.isInt(split3[1])) {
|
||||
level = Integer.parseInt(split3[1]);
|
||||
}
|
||||
if (level < enchantment.getStartLevel()) {
|
||||
level = enchantment.getStartLevel();
|
||||
}
|
||||
if (level > enchantment.getMaxLevel()) {
|
||||
level = enchantment.getMaxLevel();
|
||||
}
|
||||
stack.addUnsafeEnchantment(enchantment, level);
|
||||
}
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
if (node.getType().equals(EnchantmentLevel.class)) {
|
||||
final String val = constructScalarRefl((ScalarNode) node);
|
||||
if (val.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final String[] split = val.split("[:+',;.]", 2);
|
||||
if (split.length == 0) {
|
||||
return null;
|
||||
}
|
||||
final Enchantment enchant = Enchantments.getByName(split[0]);
|
||||
if (enchant == null) {
|
||||
return null;
|
||||
}
|
||||
int level = enchant.getStartLevel();
|
||||
if (split.length == 2 && NumberUtil.isInt(split[1])) {
|
||||
level = Integer.parseInt(split[1]);
|
||||
}
|
||||
if (level < enchant.getStartLevel()) {
|
||||
level = enchant.getStartLevel();
|
||||
}
|
||||
if (level > enchant.getMaxLevel()) {
|
||||
level = enchant.getMaxLevel();
|
||||
}
|
||||
return new EnchantmentLevel(enchant, level);
|
||||
}
|
||||
return super.construct(node);
|
||||
}
|
||||
}
|
||||
|
||||
private class ConstructBukkitMapping extends ConstructMapping {
|
||||
|
||||
@Override
|
||||
public Object construct(final Node node) {
|
||||
if (node.getType().equals(Location.class)) {
|
||||
//TODO: NPE checks
|
||||
final MappingNode mnode = (MappingNode) node;
|
||||
String worldName = "";
|
||||
double x = 0, y = 0, z = 0;
|
||||
float yaw = 0, pitch = 0;
|
||||
if (mnode.getValue().size() < 4) {
|
||||
return null;
|
||||
}
|
||||
for (final NodeTuple nodeTuple : mnode.getValue()) {
|
||||
final String key = constructScalarRefl((ScalarNode) nodeTuple.getKeyNode());
|
||||
final ScalarNode snode = (ScalarNode) nodeTuple.getValueNode();
|
||||
if (key.equalsIgnoreCase("world")) {
|
||||
worldName = constructScalarRefl(snode);
|
||||
}
|
||||
if (key.equalsIgnoreCase("x")) {
|
||||
x = Double.parseDouble(constructScalarRefl(snode));
|
||||
}
|
||||
if (key.equalsIgnoreCase("y")) {
|
||||
y = Double.parseDouble(constructScalarRefl(snode));
|
||||
}
|
||||
if (key.equalsIgnoreCase("z")) {
|
||||
z = Double.parseDouble(constructScalarRefl(snode));
|
||||
}
|
||||
if (key.equalsIgnoreCase("yaw")) {
|
||||
yaw = Float.parseFloat(constructScalarRefl(snode));
|
||||
}
|
||||
if (key.equalsIgnoreCase("pitch")) {
|
||||
pitch = Float.parseFloat(constructScalarRefl(snode));
|
||||
}
|
||||
}
|
||||
if (worldName == null || worldName.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) {
|
||||
return null;
|
||||
}
|
||||
return new Location(world, x, y, z, yaw, pitch);
|
||||
}
|
||||
return super.construct(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Comment {
|
||||
String[] value() default "";
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class EnchantmentLevel implements Entry<Enchantment, Integer> {
|
||||
private Enchantment enchantment;
|
||||
private int level;
|
||||
|
||||
public EnchantmentLevel(final Enchantment enchantment, final int level) {
|
||||
this.enchantment = enchantment;
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public Enchantment getEnchantment() {
|
||||
return enchantment;
|
||||
}
|
||||
|
||||
public void setEnchantment(final Enchantment enchantment) {
|
||||
this.enchantment = enchantment;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(final int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enchantment getKey() {
|
||||
return enchantment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer setValue(final Integer v) {
|
||||
final int t = level;
|
||||
level = v;
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return enchantment.hashCode() ^ level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj instanceof Entry) {
|
||||
final Entry entry = (Entry) obj;
|
||||
if (entry.getKey() instanceof Enchantment && entry.getValue() instanceof Integer) {
|
||||
final Enchantment enchant = (Enchantment) entry.getKey();
|
||||
final Integer lvl = (Integer) entry.getValue();
|
||||
return this.enchantment.equals(enchant) && this.level == lvl;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
public interface IStorageObjectHolder<T extends StorageObject> {
|
||||
T getData();
|
||||
|
||||
void acquireReadLock();
|
||||
|
||||
void acquireWriteLock();
|
||||
|
||||
void close();
|
||||
|
||||
void unlock();
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
public interface IStorageReader {
|
||||
<T extends StorageObject> T load(final Class<? extends T> clazz) throws ObjectLoadException;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
public interface IStorageWriter {
|
||||
void save(final StorageObject object);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MapKeyType {
|
||||
Class value() default String.class;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
public class ObjectLoadException extends Exception {
|
||||
public ObjectLoadException(final Throwable thrwbl) {
|
||||
super(thrwbl);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
public interface StorageObject {
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.yaml.snakeyaml.TypeDescription;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class YamlStorageReader implements IStorageReader {
|
||||
private transient static final Map<Class, Yaml> PREPARED_YAMLS = Collections.synchronizedMap(new HashMap<>());
|
||||
private transient static final Map<Class, ReentrantLock> LOCKS = new HashMap<>();
|
||||
private transient final Reader reader;
|
||||
private transient final Plugin plugin;
|
||||
|
||||
public YamlStorageReader(final Reader reader, final Plugin plugin) {
|
||||
this.reader = reader;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends StorageObject> T load(final Class<? extends T> clazz) throws ObjectLoadException {
|
||||
Yaml yaml = PREPARED_YAMLS.get(clazz);
|
||||
if (yaml == null) {
|
||||
yaml = new Yaml(prepareConstructor(clazz));
|
||||
PREPARED_YAMLS.put(clazz, yaml);
|
||||
}
|
||||
ReentrantLock lock;
|
||||
synchronized (LOCKS) {
|
||||
lock = LOCKS.get(clazz);
|
||||
if (lock == null) {
|
||||
lock = new ReentrantLock();
|
||||
}
|
||||
}
|
||||
lock.lock();
|
||||
try {
|
||||
T object = yaml.load(reader);
|
||||
if (object == null) {
|
||||
object = clazz.newInstance();
|
||||
}
|
||||
return object;
|
||||
} catch (final IllegalAccessException | InstantiationException ex) {
|
||||
throw new ObjectLoadException(ex);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private Constructor prepareConstructor(final Class<?> clazz) {
|
||||
final Constructor constructor = new BukkitConstructor(clazz, plugin);
|
||||
final Set<Class> classes = new HashSet<>();
|
||||
|
||||
prepareConstructor(constructor, classes, clazz);
|
||||
return constructor;
|
||||
}
|
||||
|
||||
private void prepareConstructor(final Constructor constructor, final Set<Class> classes, final Class clazz) {
|
||||
classes.add(clazz);
|
||||
final TypeDescription description = new TypeDescription(clazz);
|
||||
for (final Field field : clazz.getDeclaredFields()) {
|
||||
prepareList(field, description, classes, constructor);
|
||||
prepareMap(field, description, classes, constructor);
|
||||
if (StorageObject.class.isAssignableFrom(field.getType()) && !classes.contains(field.getType())) {
|
||||
prepareConstructor(constructor, classes, field.getType());
|
||||
}
|
||||
}
|
||||
constructor.addTypeDescription(description);
|
||||
}
|
||||
|
||||
private void prepareList(final Field field, final TypeDescription description, final Set<Class> classes, final Constructor constructor) {
|
||||
final ListType listType = field.getAnnotation(ListType.class);
|
||||
if (listType != null) {
|
||||
description.putListPropertyType(field.getName(), listType.value());
|
||||
if (StorageObject.class.isAssignableFrom(listType.value()) && !classes.contains(listType.value())) {
|
||||
prepareConstructor(constructor, classes, listType.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareMap(final Field field, final TypeDescription description, final Set<Class> classes, final Constructor constructor) {
|
||||
final MapValueType mapType = field.getAnnotation(MapValueType.class);
|
||||
if (mapType != null) {
|
||||
final MapKeyType mapKeyType = field.getAnnotation(MapKeyType.class);
|
||||
description.putMapPropertyType(field.getName(), mapKeyType == null ? String.class : mapKeyType.value(), mapType.value());
|
||||
if (StorageObject.class.isAssignableFrom(mapType.value()) && !classes.contains(mapType.value())) {
|
||||
prepareConstructor(constructor, classes, mapType.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.material.MaterialData;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class YamlStorageWriter implements IStorageWriter {
|
||||
private transient static final Pattern NON_WORD_PATTERN = Pattern.compile("\\W");
|
||||
private transient static final Yaml YAML = new Yaml();
|
||||
private transient final PrintWriter writer;
|
||||
|
||||
public YamlStorageWriter(final PrintWriter writer) {
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(final StorageObject object) {
|
||||
try {
|
||||
writeToFile(object, 0, object.getClass());
|
||||
} catch (final IllegalArgumentException | IllegalAccessException ex) {
|
||||
Logger.getLogger(YamlStorageWriter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeToFile(final Object object, final int depth, final Class clazz) throws IllegalAccessException {
|
||||
for (final Field field : clazz.getDeclaredFields()) {
|
||||
final int modifier = field.getModifiers();
|
||||
if (Modifier.isPrivate(modifier) && !Modifier.isTransient(modifier) && !Modifier.isStatic(modifier)) {
|
||||
field.setAccessible(true);
|
||||
|
||||
final Object data = field.get(object);
|
||||
if (writeKey(field, depth, data)) {
|
||||
continue;
|
||||
}
|
||||
if (data instanceof StorageObject) {
|
||||
writer.println();
|
||||
writeToFile(data, depth + 1, data.getClass());
|
||||
} else if (data instanceof Map) {
|
||||
writeMap((Map<Object, Object>) data, depth + 1);
|
||||
} else if (data instanceof Collection) {
|
||||
writeCollection((Collection<Object>) data, depth + 1);
|
||||
} else if (data instanceof Location) {
|
||||
writeLocation((Location) data, depth + 1);
|
||||
} else {
|
||||
writeScalar(data);
|
||||
writer.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean writeKey(final Field field, final int depth, final Object data) {
|
||||
final boolean commentPresent = writeComment(field, depth);
|
||||
if (data == null && !commentPresent) {
|
||||
return true;
|
||||
}
|
||||
writeIndention(depth);
|
||||
if (data == null && commentPresent) {
|
||||
writer.print('#');
|
||||
}
|
||||
final String name = field.getName();
|
||||
writer.print(name);
|
||||
writer.print(": ");
|
||||
if (data == null && commentPresent) {
|
||||
writer.println();
|
||||
writer.println();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean writeComment(final Field field, final int depth) {
|
||||
final boolean commentPresent = field.isAnnotationPresent(Comment.class);
|
||||
if (commentPresent) {
|
||||
final Comment comments = field.getAnnotation(Comment.class);
|
||||
for (final String comment : comments.value()) {
|
||||
final String trimmed = comment.trim();
|
||||
if (trimmed.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
writeIndention(depth);
|
||||
writer.print("# ");
|
||||
writer.print(trimmed);
|
||||
writer.println();
|
||||
}
|
||||
}
|
||||
return commentPresent;
|
||||
}
|
||||
|
||||
private void writeCollection(final Collection<Object> data, final int depth) throws IllegalAccessException {
|
||||
writer.println();
|
||||
if (data.isEmpty()) {
|
||||
writer.println();
|
||||
}
|
||||
for (final Object entry : data) {
|
||||
if (entry != null) {
|
||||
writeIndention(depth);
|
||||
writer.print("- ");
|
||||
if (entry instanceof StorageObject) {
|
||||
writer.println();
|
||||
writeToFile(entry, depth + 1, entry.getClass());
|
||||
} else if (entry instanceof Location) {
|
||||
writeLocation((Location) entry, depth + 1);
|
||||
} else {
|
||||
writeScalar(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
writer.println();
|
||||
}
|
||||
|
||||
private void writeMap(final Map<Object, Object> data, final int depth) throws IllegalArgumentException, IllegalAccessException {
|
||||
writer.println();
|
||||
if (data.isEmpty()) {
|
||||
writer.println();
|
||||
}
|
||||
for (final Entry<Object, Object> entry : data.entrySet()) {
|
||||
final Object value = entry.getValue();
|
||||
if (value != null) {
|
||||
writeIndention(depth);
|
||||
writeKey(entry.getKey());
|
||||
writer.print(": ");
|
||||
if (value instanceof StorageObject) {
|
||||
writer.println();
|
||||
writeToFile(value, depth + 1, value.getClass());
|
||||
} else if (value instanceof Collection) {
|
||||
writeCollection((Collection<Object>) value, depth + 1);
|
||||
} else if (value instanceof Location) {
|
||||
writeLocation((Location) value, depth + 1);
|
||||
} else {
|
||||
writeScalar(value);
|
||||
writer.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeIndention(final int depth) {
|
||||
for (int i = 0; i < depth; i++) {
|
||||
writer.print(" ");
|
||||
}
|
||||
}
|
||||
|
||||
private void writeScalar(final Object data) {
|
||||
if (data instanceof String || data instanceof Boolean || data instanceof Number) {
|
||||
synchronized (YAML) {
|
||||
YAML.dumpAll(Collections.singletonList(data).iterator(), writer);
|
||||
}
|
||||
} else if (data instanceof Material) {
|
||||
writeMaterial(data);
|
||||
writer.println();
|
||||
} else if (data instanceof MaterialData) {
|
||||
writeMaterialData(data);
|
||||
writer.println();
|
||||
} else if (data instanceof ItemStack) {
|
||||
writeItemStack(data);
|
||||
writer.println();
|
||||
} else if (data instanceof EnchantmentLevel) {
|
||||
writeEnchantmentLevel(data);
|
||||
writer.println();
|
||||
} else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeKey(final Object data) {
|
||||
if (data instanceof String || data instanceof Boolean || data instanceof Number) {
|
||||
final String output = data.toString();
|
||||
if (NON_WORD_PATTERN.matcher(output).find()) {
|
||||
writer.print('"');
|
||||
writer.print(output.replace("\"", "\\\""));
|
||||
writer.print('"');
|
||||
} else {
|
||||
writer.print(output);
|
||||
}
|
||||
} else if (data instanceof Material) {
|
||||
writeMaterial(data);
|
||||
} else if (data instanceof MaterialData) {
|
||||
writeMaterialData(data);
|
||||
} else if (data instanceof EnchantmentLevel) {
|
||||
writeEnchantmentLevel(data);
|
||||
} else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeMaterial(final Object data) {
|
||||
writer.print(data.toString().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
private void writeMaterialData(final Object data) {
|
||||
final MaterialData matData = (MaterialData) data;
|
||||
writeMaterial(matData.getItemType());
|
||||
if (matData.getData() > 0) {
|
||||
writer.print(':');
|
||||
writer.print(matData.getData());
|
||||
}
|
||||
}
|
||||
|
||||
private void writeItemStack(final Object data) {
|
||||
final ItemStack itemStack = (ItemStack) data;
|
||||
writeMaterialData(itemStack.getData());
|
||||
writer.print(' ');
|
||||
writer.print(itemStack.getAmount());
|
||||
for (final Entry<Enchantment, Integer> entry : itemStack.getEnchantments().entrySet()) {
|
||||
writer.print(' ');
|
||||
writeEnchantmentLevel(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeEnchantmentLevel(final Object data) {
|
||||
final Entry<Enchantment, Integer> enchLevel = (Entry<Enchantment, Integer>) data;
|
||||
writer.print(enchLevel.getKey().getName().toLowerCase(Locale.ENGLISH));
|
||||
writer.print(':');
|
||||
writer.print(enchLevel.getValue());
|
||||
}
|
||||
|
||||
private void writeLocation(final Location entry, final int depth) {
|
||||
writer.println();
|
||||
writeIndention(depth);
|
||||
writer.print("world: ");
|
||||
writeScalar(entry.getWorld().getName());
|
||||
writeIndention(depth);
|
||||
writer.print("x: ");
|
||||
writeScalar(entry.getX());
|
||||
writeIndention(depth);
|
||||
writer.print("y: ");
|
||||
writeScalar(entry.getY());
|
||||
writeIndention(depth);
|
||||
writer.print("z: ");
|
||||
writeScalar(entry.getZ());
|
||||
writeIndention(depth);
|
||||
writer.print("yaw: ");
|
||||
writeScalar(entry.getYaw());
|
||||
writeIndention(depth);
|
||||
writer.print("pitch: ");
|
||||
writeScalar(entry.getPitch());
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.earth2me.essentials.textreader;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SimpleTextPager {
|
||||
private final transient IText text;
|
||||
|
||||
public SimpleTextPager(final IText text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public void showPage(final CommandSource sender) {
|
||||
for (final String line : text.getLines()) {
|
||||
sender.sendMessage(line);
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getLines() {
|
||||
return text.getLines();
|
||||
}
|
||||
|
||||
public String getLine(final int line) {
|
||||
if (text.getLines().size() < line) {
|
||||
return null;
|
||||
}
|
||||
return text.getLines().get(line);
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
package com.earth2me.essentials.utils;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.material.MaterialData;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
public final class MaterialUtil {
|
||||
|
||||
public static final Material SPAWNER = EnumUtil.getMaterial("MOB_SPAWNER", "SPAWNER");
|
||||
private static final Set<Material> BEDS;
|
||||
private static final Set<Material> BANNERS;
|
||||
private static final Set<Material> FIREWORKS;
|
||||
private static final Set<Material> LEGACY_SKULLS;
|
||||
private static final Set<Material> LEATHER_ARMOR;
|
||||
private static final Set<Material> MOB_HEADS;
|
||||
// includes TIPPED_ARROW which also has potion effects
|
||||
private static final Set<Material> PLAYER_HEADS;
|
||||
private static final Set<Material> POTIONS;
|
||||
private static final Set<Material> SIGN_POSTS;
|
||||
private static final Set<Material> WALL_SIGNS;
|
||||
|
||||
static {
|
||||
|
||||
BEDS = EnumUtil.getAllMatching(Material.class, "BED", "BED_BLOCK", "WHITE_BED", "ORANGE_BED",
|
||||
"MAGENTA_BED", "LIGHT_BLUE_BED", "YELLOW_BED", "LIME_BED", "PINK_BED", "GRAY_BED",
|
||||
"LIGHT_GRAY_BED", "CYAN_BED", "PURPLE_BED", "BLUE_BED", "BROWN_BED", "GREEN_BED",
|
||||
"RED_BED", "BLACK_BED");
|
||||
|
||||
BANNERS = EnumUtil.getAllMatching(Material.class, "BANNER", "WHITE_BANNER",
|
||||
"ORANGE_BANNER", "MAGENTA_BANNER", "LIGHT_BLUE_BANNER", "YELLOW_BANNER", "LIME_BANNER",
|
||||
"PINK_BANNER", "GRAY_BANNER", "LIGHT_GRAY_BANNER", "CYAN_BANNER", "PURPLE_BANNER",
|
||||
"BLUE_BANNER", "BROWN_BANNER", "GREEN_BANNER", "RED_BANNER", "BLACK_BANNER", "SHIELD");
|
||||
|
||||
FIREWORKS = EnumUtil.getAllMatching(Material.class, "FIREWORK", "FIREWORK_ROCKET",
|
||||
"FIREWORK_CHARGE", "FIREWORK_STAR");
|
||||
|
||||
LEATHER_ARMOR = EnumUtil.getAllMatching(Material.class, "LEATHER_HELMET",
|
||||
"LEATHER_CHESTPLATE", "LEATHER_LEGGINGS", "LEATHER_BOOTS");
|
||||
|
||||
LEGACY_SKULLS = EnumUtil.getAllMatching(Material.class, "SKULL", "SKULL_ITEM");
|
||||
|
||||
MOB_HEADS = EnumUtil.getAllMatching(Material.class, "SKELETON_SKULL",
|
||||
"SKELETON_WALL_SKULL", "WITHER_SKELETON_SKULL", "WITHER_SKELETON_WALL_SKULL",
|
||||
"CREEPER_HEAD", "CREEPER_WALL_HEAD", "ZOMBIE_HEAD", "ZOMBIE_WALL_HEAD", "DRAGON_HEAD"
|
||||
, "DRAGON_WALL_HEAD");
|
||||
|
||||
PLAYER_HEADS = EnumUtil.getAllMatching(Material.class, "PLAYER_HEAD", "PLAYER_WALL_HEAD");
|
||||
|
||||
POTIONS = EnumUtil.getAllMatching(Material.class, "POTION", "SPLASH_POTION",
|
||||
"LINGERING_POTION", "TIPPED_ARROW");
|
||||
|
||||
SIGN_POSTS = EnumUtil.getAllMatching(Material.class, "SIGN", "SIGN_POST",
|
||||
"ACACIA_SIGN", "BIRCH_SIGN",
|
||||
"DARK_OAK_SIGN", "JUNGLE_SIGN",
|
||||
"OAK_SIGN", "SPRUCE_SIGN",
|
||||
"CRIMSON_SIGN", "WARPED_SIGN");
|
||||
|
||||
WALL_SIGNS = EnumUtil.getAllMatching(Material.class, "WALL_SIGN",
|
||||
"ACACIA_WALL_SIGN", "BIRCH_WALL_SIGN",
|
||||
"DARK_OAK_WALL_SIGN", "JUNGLE_WALL_SIGN",
|
||||
"OAK_WALL_SIGN", "SPRUCE_WALL_SIGN",
|
||||
"CRIMSON_WALL_SIGN", "WARPED_WALL_SIGN");
|
||||
}
|
||||
|
||||
private MaterialUtil() {
|
||||
}
|
||||
|
||||
public static boolean isBed(final Material material) {
|
||||
return BEDS.contains(material);
|
||||
}
|
||||
|
||||
public static boolean isBanner(final Material material) {
|
||||
return BANNERS.contains(material);
|
||||
}
|
||||
|
||||
public static boolean isFirework(final Material material) {
|
||||
return FIREWORKS.contains(material);
|
||||
}
|
||||
|
||||
public static boolean isLeatherArmor(final Material material) {
|
||||
return LEATHER_ARMOR.contains(material);
|
||||
}
|
||||
|
||||
public static boolean isMobHead(final Material material, final int durability) {
|
||||
if (MOB_HEADS.contains(material)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return LEGACY_SKULLS.contains(material) && (durability != 3);
|
||||
}
|
||||
|
||||
public static boolean isPlayerHead(final Material material, final int durability) {
|
||||
if (PLAYER_HEADS.contains(material)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return LEGACY_SKULLS.contains(material) && durability == 3;
|
||||
}
|
||||
|
||||
public static boolean isPotion(final Material material) {
|
||||
return POTIONS.contains(material);
|
||||
}
|
||||
|
||||
public static boolean isSignPost(final Material material) {
|
||||
return SIGN_POSTS.contains(material);
|
||||
}
|
||||
|
||||
public static boolean isWallSign(final Material material) {
|
||||
return WALL_SIGNS.contains(material);
|
||||
}
|
||||
|
||||
public static boolean isSign(final Material material) {
|
||||
return isSignPost(material) || isWallSign(material);
|
||||
}
|
||||
|
||||
public static boolean isSkull(final Material material) {
|
||||
return isPlayerHead(material, -1) || isMobHead(material, -1);
|
||||
}
|
||||
|
||||
public static Material convertFromLegacy(final int id, final byte damage) {
|
||||
for (final Material material : EnumSet.allOf(Material.class)) {
|
||||
if (material.getId() == id) {
|
||||
try {
|
||||
return Bukkit.getUnsafe().fromLegacy(new MaterialData(material, damage));
|
||||
} catch (final NoSuchMethodError error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
//noinspection JavaReflectionMemberAccess
|
||||
final Method getMaterialFromId = Material.class.getDeclaredMethod("getMaterial", int.class);
|
||||
return (Material) getMaterialFromId.invoke(null, id);
|
||||
} catch (final NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static DyeColor getColorOf(final Material material) {
|
||||
for (final DyeColor color : DyeColor.values()) {
|
||||
if (material.toString().contains(color.name())) {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
return DyeColor.WHITE;
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
package com.earth2me.essentials.utils;
|
||||
|
||||
import net.ess3.api.IEssentials;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public final class NumberUtil {
|
||||
|
||||
private static final DecimalFormat twoDPlaces = new DecimalFormat("#,###.##");
|
||||
private static final DecimalFormat currencyFormat = new DecimalFormat("#0.00", DecimalFormatSymbols.getInstance(Locale.US));
|
||||
|
||||
// This field is likely to be modified in com.earth2me.essentials.Settings when loading currency format.
|
||||
// This ensures that we can supply a constant formatting.
|
||||
private static NumberFormat PRETTY_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||
|
||||
static {
|
||||
twoDPlaces.setRoundingMode(RoundingMode.HALF_UP);
|
||||
currencyFormat.setRoundingMode(RoundingMode.FLOOR);
|
||||
|
||||
PRETTY_FORMAT.setRoundingMode(RoundingMode.FLOOR);
|
||||
PRETTY_FORMAT.setGroupingUsed(true);
|
||||
PRETTY_FORMAT.setMinimumFractionDigits(2);
|
||||
PRETTY_FORMAT.setMaximumFractionDigits(2);
|
||||
}
|
||||
|
||||
private NumberUtil() {
|
||||
}
|
||||
|
||||
// this method should only be called by Essentials
|
||||
public static void internalSetPrettyFormat(final NumberFormat prettyFormat) {
|
||||
PRETTY_FORMAT = prettyFormat;
|
||||
}
|
||||
|
||||
public static String shortCurrency(final BigDecimal value, final IEssentials ess) {
|
||||
if (ess.getSettings().isCurrencySymbolSuffixed()) {
|
||||
return formatAsCurrency(value) + ess.getSettings().getCurrencySymbol();
|
||||
}
|
||||
return ess.getSettings().getCurrencySymbol() + formatAsCurrency(value);
|
||||
}
|
||||
|
||||
public static String formatDouble(final double value) {
|
||||
return twoDPlaces.format(value);
|
||||
}
|
||||
|
||||
public static String formatAsCurrency(final BigDecimal value) {
|
||||
String str = currencyFormat.format(value);
|
||||
if (str.endsWith(".00")) {
|
||||
str = str.substring(0, str.length() - 3);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public static String formatAsPrettyCurrency(final BigDecimal value) {
|
||||
String str = PRETTY_FORMAT.format(value);
|
||||
if (str.endsWith(".00")) {
|
||||
str = str.substring(0, str.length() - 3);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public static String displayCurrency(final BigDecimal value, final IEssentials ess) {
|
||||
String currency = formatAsPrettyCurrency(value);
|
||||
String sign = "";
|
||||
if (value.signum() < 0) {
|
||||
currency = currency.substring(1);
|
||||
sign = "-";
|
||||
}
|
||||
if (ess.getSettings().isCurrencySymbolSuffixed()) {
|
||||
return sign + tl("currency", currency, ess.getSettings().getCurrencySymbol());
|
||||
}
|
||||
return sign + tl("currency", ess.getSettings().getCurrencySymbol(), currency);
|
||||
}
|
||||
|
||||
public static String displayCurrencyExactly(final BigDecimal value, final IEssentials ess) {
|
||||
String currency = value.toPlainString();
|
||||
String sign = "";
|
||||
if (value.signum() < 0) {
|
||||
currency = currency.substring(1);
|
||||
sign = "-";
|
||||
}
|
||||
if (ess.getSettings().isCurrencySymbolSuffixed()) {
|
||||
return sign + tl("currency", currency, ess.getSettings().getCurrencySymbol());
|
||||
}
|
||||
return sign + tl("currency", ess.getSettings().getCurrencySymbol(), currency);
|
||||
}
|
||||
|
||||
public static String sanitizeCurrencyString(final String input, final IEssentials ess) {
|
||||
final String symbol = ess.getSettings().getCurrencySymbol();
|
||||
final boolean suffix = ess.getSettings().isCurrencySymbolSuffixed();
|
||||
if (input.contains(symbol)) {
|
||||
return suffix ? input.substring(0, input.indexOf(symbol)) : input.substring(symbol.length());
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
public static boolean isInt(final String sInt) {
|
||||
try {
|
||||
Integer.parseInt(sInt);
|
||||
} catch (final NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isPositiveInt(final String sInt) {
|
||||
if (!isInt(sInt)) {
|
||||
return false;
|
||||
}
|
||||
return Integer.parseInt(sInt) > 0;
|
||||
}
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
package com.earth2me.essentials.utils;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class VersionUtil {
|
||||
|
||||
public static final BukkitVersion v1_14_R01 = BukkitVersion.fromString("1.14-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_8_8_R01 = BukkitVersion.fromString("1.8.8-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_9_R01 = BukkitVersion.fromString("1.9-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_9_4_R01 = BukkitVersion.fromString("1.9.4-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_10_R01 = BukkitVersion.fromString("1.10-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_10_2_R01 = BukkitVersion.fromString("1.10.2-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_11_R01 = BukkitVersion.fromString("1.11-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_11_2_R01 = BukkitVersion.fromString("1.11.2-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_12_0_R01 = BukkitVersion.fromString("1.12.0-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_12_2_R01 = BukkitVersion.fromString("1.12.2-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_13_0_R01 = BukkitVersion.fromString("1.13.0-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_13_2_R01 = BukkitVersion.fromString("1.13.2-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_14_4_R01 = BukkitVersion.fromString("1.14.4-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_15_R01 = BukkitVersion.fromString("1.15-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_15_2_R01 = BukkitVersion.fromString("1.15.2-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_16_1_R01 = BukkitVersion.fromString("1.16.1-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_16_2_R01 = BukkitVersion.fromString("1.16.2-R0.1-SNAPSHOT");
|
||||
public static final BukkitVersion v1_16_4_R01 = BukkitVersion.fromString("1.16.4-R0.1-SNAPSHOT");
|
||||
|
||||
private static final Set<BukkitVersion> supportedVersions = ImmutableSet.of(v1_8_8_R01, v1_9_4_R01, v1_10_2_R01, v1_11_2_R01, v1_12_2_R01, v1_13_2_R01, v1_14_4_R01, v1_15_2_R01, v1_16_4_R01);
|
||||
|
||||
private static BukkitVersion serverVersion = null;
|
||||
|
||||
private VersionUtil() {
|
||||
}
|
||||
|
||||
public static BukkitVersion getServerBukkitVersion() {
|
||||
if (serverVersion == null) {
|
||||
serverVersion = BukkitVersion.fromString(Bukkit.getServer().getBukkitVersion());
|
||||
}
|
||||
return serverVersion;
|
||||
}
|
||||
|
||||
public static SupportStatus getServerSupportStatus() {
|
||||
try {
|
||||
Class.forName("net.minecraftforge.common.MinecraftForge");
|
||||
return SupportStatus.UNSTABLE;
|
||||
} catch (final ClassNotFoundException ignored) {
|
||||
}
|
||||
|
||||
if (!supportedVersions.contains(getServerBukkitVersion())) {
|
||||
return SupportStatus.OUTDATED;
|
||||
}
|
||||
|
||||
return PaperLib.isPaper() ? SupportStatus.FULL : SupportStatus.LIMITED;
|
||||
}
|
||||
|
||||
public static boolean isServerSupported() {
|
||||
return getServerSupportStatus().isSupported();
|
||||
}
|
||||
|
||||
public static final class BukkitVersion implements Comparable<BukkitVersion> {
|
||||
private static final Pattern VERSION_PATTERN = Pattern.compile("^(\\d+)\\.(\\d+)\\.?([0-9]*)?(?:-pre(\\d))?(?:-?R?([\\d.]+))?(?:-SNAPSHOT)?");
|
||||
|
||||
private final int major;
|
||||
private final int minor;
|
||||
private final int prerelease;
|
||||
private final int patch;
|
||||
private final double revision;
|
||||
|
||||
private BukkitVersion(final int major, final int minor, final int patch, final double revision, final int prerelease) {
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.patch = patch;
|
||||
this.revision = revision;
|
||||
this.prerelease = prerelease;
|
||||
}
|
||||
|
||||
public static BukkitVersion fromString(final String string) {
|
||||
Preconditions.checkNotNull(string, "string cannot be null.");
|
||||
Matcher matcher = VERSION_PATTERN.matcher(string);
|
||||
if (!matcher.matches()) {
|
||||
if (!Bukkit.getName().equals("Essentials Fake Server")) {
|
||||
throw new IllegalArgumentException(string + " is not in valid version format. e.g. 1.8.8-R0.1");
|
||||
}
|
||||
matcher = VERSION_PATTERN.matcher(v1_14_R01.toString());
|
||||
Preconditions.checkArgument(matcher.matches(), string + " is not in valid version format. e.g. 1.8.8-R0.1");
|
||||
}
|
||||
|
||||
return from(matcher.group(1), matcher.group(2), matcher.group(3), matcher.groupCount() < 5 ? "" : matcher.group(5), matcher.group(4));
|
||||
}
|
||||
|
||||
private static BukkitVersion from(final String major, final String minor, String patch, String revision, String prerelease) {
|
||||
if (patch == null || patch.isEmpty()) patch = "0";
|
||||
if (revision == null || revision.isEmpty()) revision = "0";
|
||||
if (prerelease == null || prerelease.isEmpty()) prerelease = "-1";
|
||||
return new BukkitVersion(Integer.parseInt(major),
|
||||
Integer.parseInt(minor),
|
||||
Integer.parseInt(patch),
|
||||
Double.parseDouble(revision),
|
||||
Integer.parseInt(prerelease));
|
||||
}
|
||||
|
||||
public boolean isHigherThan(final BukkitVersion o) {
|
||||
return compareTo(o) > 0;
|
||||
}
|
||||
|
||||
public boolean isHigherThanOrEqualTo(final BukkitVersion o) {
|
||||
return compareTo(o) >= 0;
|
||||
}
|
||||
|
||||
public boolean isLowerThan(final BukkitVersion o) {
|
||||
return compareTo(o) < 0;
|
||||
}
|
||||
|
||||
public boolean isLowerThanOrEqualTo(final BukkitVersion o) {
|
||||
return compareTo(o) <= 0;
|
||||
}
|
||||
|
||||
public int getMajor() {
|
||||
return major;
|
||||
}
|
||||
|
||||
public int getMinor() {
|
||||
return minor;
|
||||
}
|
||||
|
||||
public int getPatch() {
|
||||
return patch;
|
||||
}
|
||||
|
||||
public double getRevision() {
|
||||
return revision;
|
||||
}
|
||||
|
||||
public int getPrerelease() {
|
||||
return prerelease;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final BukkitVersion that = (BukkitVersion) o;
|
||||
return major == that.major &&
|
||||
minor == that.minor &&
|
||||
patch == that.patch &&
|
||||
revision == that.revision &&
|
||||
prerelease == that.prerelease;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(major, minor, patch, revision, prerelease);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder(major + "." + minor);
|
||||
if (patch != 0) {
|
||||
sb.append(".").append(patch);
|
||||
}
|
||||
if (prerelease != -1) {
|
||||
sb.append("-pre").append(prerelease);
|
||||
}
|
||||
return sb.append("-R").append(revision).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final BukkitVersion o) {
|
||||
if (major < o.major) {
|
||||
return -1;
|
||||
} else if (major > o.major) {
|
||||
return 1;
|
||||
} else { // equal major
|
||||
if (minor < o.minor) {
|
||||
return -1;
|
||||
} else if (minor > o.minor) {
|
||||
return 1;
|
||||
} else { // equal minor
|
||||
if (patch < o.patch) {
|
||||
return -1;
|
||||
} else if (patch > o.patch) {
|
||||
return 1;
|
||||
} else { // equal patch
|
||||
if (prerelease < o.prerelease) {
|
||||
return -1;
|
||||
} else if (prerelease > o.prerelease) {
|
||||
return 1;
|
||||
} else { // equal prerelease
|
||||
return Double.compare(revision, o.revision);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum SupportStatus {
|
||||
FULL(true),
|
||||
LIMITED(true),
|
||||
UNSTABLE(false),
|
||||
OUTDATED(false)
|
||||
;
|
||||
|
||||
private final boolean supported;
|
||||
|
||||
SupportStatus(final boolean supported) {
|
||||
this.supported = supported;
|
||||
}
|
||||
|
||||
public boolean isSupported() {
|
||||
return supported;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import net.ess3.provider.KnownCommandsProvider;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.PluginIdentifiableCommand;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class AlternativeCommandsHandler {
|
||||
private final transient Map<String, List<WeakReference<Command>>> altCommands = new HashMap<>();
|
||||
private final transient Map<String, String> disabledList = new HashMap<>();
|
||||
private final transient IEssentials ess;
|
||||
|
||||
public AlternativeCommandsHandler(final IEssentials ess) {
|
||||
this.ess = ess;
|
||||
for (final Plugin plugin : ess.getServer().getPluginManager().getPlugins()) {
|
||||
if (plugin.isEnabled()) {
|
||||
addPlugin(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void addPlugin(final Plugin plugin) {
|
||||
if (plugin.getDescription().getMain().contains("com.earth2me.essentials") || plugin.getDescription().getMain().contains("net.essentialsx")) {
|
||||
return;
|
||||
}
|
||||
for (final Map.Entry<String, Command> entry : getPluginCommands(plugin)) {
|
||||
final String[] commandSplit = entry.getKey().split(":", 2);
|
||||
final String commandName = commandSplit.length > 1 ? commandSplit[1] : entry.getKey();
|
||||
final Command command = entry.getValue();
|
||||
|
||||
final List<WeakReference<Command>> pluginCommands = altCommands.computeIfAbsent(commandName.toLowerCase(Locale.ENGLISH), k -> new ArrayList<>());
|
||||
boolean found = false;
|
||||
|
||||
final Iterator<WeakReference<Command>> pluginCmdIterator = pluginCommands.iterator();
|
||||
while (pluginCmdIterator.hasNext()) {
|
||||
final Command cmd = pluginCmdIterator.next().get();
|
||||
if (cmd == null) {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().log(Level.INFO, "Essentials: Alternative command for " + commandName + " removed due to garbage collection");
|
||||
}
|
||||
|
||||
pluginCmdIterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Safe cast, everything that's added comes from getPluginCommands which already performs the cast check.
|
||||
if (((PluginIdentifiableCommand) cmd).getPlugin().equals(plugin)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
pluginCommands.add(new WeakReference<>(command));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Map.Entry<String, Command>> getPluginCommands(Plugin plugin) {
|
||||
final Map<String, Command> commands = new HashMap<>();
|
||||
for (final Map.Entry<String, Command> entry : ess.provider(KnownCommandsProvider.class).getKnownCommands().entrySet()) {
|
||||
if (entry.getValue() instanceof PluginIdentifiableCommand && ((PluginIdentifiableCommand) entry.getValue()).getPlugin().equals(plugin)) {
|
||||
commands.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
// Try to use non-namespaced commands first if we can, some Commands may not like being registered under a
|
||||
// different label than their getName() returns, so avoid doing that when we can
|
||||
return commands.entrySet().stream().sorted((o1, o2) -> {
|
||||
if (o1.getKey().contains(":") && !o2.getKey().contains(":")) {
|
||||
return 1;
|
||||
} else if (!o1.getKey().contains(":") && o2.getKey().contains(":")) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void removePlugin(final Plugin plugin) {
|
||||
final Iterator<Map.Entry<String, List<WeakReference<Command>>>> iterator = altCommands.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final Map.Entry<String, List<WeakReference<Command>>> entry = iterator.next();
|
||||
|
||||
final Iterator<WeakReference<Command>> commands = entry.getValue().iterator();
|
||||
while (commands.hasNext()) {
|
||||
final Command pc = commands.next().get();
|
||||
if (pc instanceof PluginIdentifiableCommand && !((PluginIdentifiableCommand) pc).getPlugin().equals(plugin)) {
|
||||
continue;
|
||||
}
|
||||
commands.remove();
|
||||
}
|
||||
|
||||
if (entry.getValue().isEmpty()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Command getAlternative(final String label) {
|
||||
final List<WeakReference<Command>> commands = altCommands.get(label);
|
||||
if (commands == null || commands.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (commands.size() == 1) {
|
||||
return commands.get(0).get();
|
||||
}
|
||||
|
||||
// return the first command that is not an alias
|
||||
final Iterator<WeakReference<Command>> iterator = commands.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final Command cmd = iterator.next().get();
|
||||
if (cmd == null) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cmd.getName().equalsIgnoreCase(label)) {
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
|
||||
// return the first alias
|
||||
return commands.get(0).get();
|
||||
}
|
||||
|
||||
public void executed(final String label, final Command pc) {
|
||||
if (pc instanceof PluginIdentifiableCommand) {
|
||||
final String altString = ((PluginIdentifiableCommand) pc).getPlugin().getName() + ":" + pc.getName();
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().log(Level.INFO, "Essentials: Alternative command " + label + " found, using " + altString);
|
||||
}
|
||||
disabledList.put(label, altString);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> disabledCommands() {
|
||||
return disabledList;
|
||||
}
|
||||
}
|
||||
+54
-28
@@ -7,7 +7,7 @@ import com.earth2me.essentials.utils.LocationUtil;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.IUser;
|
||||
import net.ess3.api.InvalidWorldException;
|
||||
import net.ess3.api.TranslatableException;
|
||||
import net.ess3.api.events.UserWarpEvent;
|
||||
import net.ess3.api.events.teleport.PreTeleportEvent;
|
||||
import net.ess3.api.events.teleport.TeleportWarmupEvent;
|
||||
@@ -23,8 +23,6 @@ import java.util.GregorianCalendar;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class AsyncTeleport implements IAsyncTeleport {
|
||||
private final IUser teleportOwner;
|
||||
private final IEssentials ess;
|
||||
@@ -73,7 +71,7 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
time.setTimeInMillis(lastTime);
|
||||
time.add(Calendar.SECOND, (int) cooldown);
|
||||
time.add(Calendar.MILLISECOND, (int) ((cooldown * 1000.0) % 1000.0));
|
||||
future.completeExceptionally(new Exception(tl("timeBeforeTeleport", DateUtil.formatDateDiff(time.getTimeInMillis()))));
|
||||
future.completeExceptionally(new TranslatableException("timeBeforeTeleport", DateUtil.formatDateDiff(time.getTimeInMillis())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -107,7 +105,7 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
final Calendar c = new GregorianCalendar();
|
||||
c.add(Calendar.SECOND, (int) delay);
|
||||
c.add(Calendar.MILLISECOND, (int) ((delay * 1000.0) % 1000.0));
|
||||
user.sendMessage(tl("dontMoveMessage", DateUtil.formatDateDiff(c.getTimeInMillis())));
|
||||
user.sendTl("dontMoveMessage", DateUtil.formatDateDiff(c.getTimeInMillis()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,11 +127,18 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
nowAsync(teleportOwner, target, cause, future);
|
||||
future.thenAccept(success -> {
|
||||
if (success) {
|
||||
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
|
||||
teleportOwner.sendTl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nowUnsafe(Location loc, TeleportCause cause, CompletableFuture<Boolean> future) {
|
||||
final CompletableFuture<Boolean> paperFuture = PaperLib.teleportAsync(teleportOwner.getBase(), loc, cause);
|
||||
paperFuture.thenAccept(future::complete);
|
||||
paperFuture.exceptionally(future::completeExceptionally);
|
||||
}
|
||||
|
||||
private void runOnMain(final Runnable runnable) throws ExecutionException, InterruptedException {
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
runnable.run();
|
||||
@@ -153,13 +158,13 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
final PreTeleportEvent event = new PreTeleportEvent(teleportee, cause, target);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
future.complete(false);
|
||||
return;
|
||||
}
|
||||
teleportee.setLastLocation();
|
||||
|
||||
if (!ess.getSettings().isForcePassengerTeleport() && !teleportee.getBase().isEmpty()) {
|
||||
if (!ess.getSettings().isTeleportPassengerDismount()) {
|
||||
future.completeExceptionally(new Exception(tl("passengerTeleportFail")));
|
||||
future.completeExceptionally(new TranslatableException("passengerTeleportFail"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -170,15 +175,19 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
return;
|
||||
}
|
||||
}
|
||||
teleportee.setLastLocation();
|
||||
|
||||
if (teleportee.isAuthorized("essentials.back.onteleport")) {
|
||||
teleportee.setLastLocation();
|
||||
}
|
||||
|
||||
final Location targetLoc = target.getLocation();
|
||||
if (ess.getSettings().isTeleportSafetyEnabled() && LocationUtil.isBlockOutsideWorldBorder(targetLoc.getWorld(), targetLoc.getBlockX(), targetLoc.getBlockZ())) {
|
||||
if (ess.getSettings().isTeleportSafetyEnabled() && !ess.getSettings().isForceDisableTeleportSafety() && LocationUtil.isBlockOutsideWorldBorder(targetLoc.getWorld(), targetLoc.getBlockX(), targetLoc.getBlockZ())) {
|
||||
targetLoc.setX(LocationUtil.getXInsideWorldBorder(targetLoc.getWorld(), targetLoc.getBlockX()));
|
||||
targetLoc.setZ(LocationUtil.getZInsideWorldBorder(targetLoc.getWorld(), targetLoc.getBlockZ()));
|
||||
}
|
||||
PaperLib.getChunkAtAsync(targetLoc).thenAccept(chunk -> {
|
||||
PaperLib.getChunkAtAsync(targetLoc.getWorld(), targetLoc.getBlockX() >> 4, targetLoc.getBlockZ() >> 4, true, true).thenAccept(chunk -> {
|
||||
Location loc = targetLoc;
|
||||
if (LocationUtil.isBlockUnsafeForUser(teleportee, chunk.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) {
|
||||
if (LocationUtil.isBlockUnsafeForUser(ess, teleportee, chunk.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) {
|
||||
if (ess.getSettings().isTeleportSafetyEnabled()) {
|
||||
if (ess.getSettings().isForceDisableTeleportSafety()) {
|
||||
//The chunk we're teleporting to is 100% going to be loaded here, no need to teleport async.
|
||||
@@ -193,7 +202,7 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
future.completeExceptionally(new Exception(tl("unsafeTeleportDestination", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())));
|
||||
future.completeExceptionally(new TranslatableException("unsafeTeleportDestination", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -209,6 +218,9 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
}
|
||||
}
|
||||
future.complete(true);
|
||||
}).exceptionally(th -> {
|
||||
future.completeExceptionally(th);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -219,7 +231,7 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
|
||||
@Override
|
||||
public void teleport(final Player entity, final Trade chargeFor, final TeleportCause cause, final CompletableFuture<Boolean> future) {
|
||||
teleportOwner.sendMessage(tl("teleportToPlayer", entity.getDisplayName()));
|
||||
teleportOwner.sendTl("teleportToPlayer", entity.getDisplayName());
|
||||
teleport(teleportOwner, new PlayerTarget(entity), chargeFor, cause, future);
|
||||
}
|
||||
|
||||
@@ -234,8 +246,8 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
teleport(otherUser, target, chargeFor, cause, future);
|
||||
future.thenAccept(success -> {
|
||||
if (success) {
|
||||
otherUser.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
|
||||
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
|
||||
otherUser.sendTl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ());
|
||||
teleportOwner.sendTl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -246,6 +258,7 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
final TeleportWarmupEvent event = new TeleportWarmupEvent(teleportee, cause, target, delay);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
future.complete(false);
|
||||
return;
|
||||
}
|
||||
delay = event.getDelay();
|
||||
@@ -266,10 +279,12 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
}
|
||||
|
||||
if (cooldown(true, future)) {
|
||||
future.complete(false);
|
||||
return;
|
||||
}
|
||||
if (delay <= 0 || teleportOwner.isAuthorized("essentials.teleport.timer.bypass") || teleportee.isAuthorized("essentials.teleport.timer.bypass")) {
|
||||
if (cooldown(false, future)) {
|
||||
future.complete(false);
|
||||
return;
|
||||
}
|
||||
nowAsync(teleportee, target, cause, future);
|
||||
@@ -279,18 +294,19 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
return;
|
||||
}
|
||||
}
|
||||
future.complete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
cancel(false);
|
||||
warnUser(teleportee, delay);
|
||||
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false);
|
||||
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false, future);
|
||||
}
|
||||
|
||||
private void teleportOther(final IUser teleporter, final IUser teleportee, final ITarget target, final Trade chargeFor, final TeleportCause cause, final CompletableFuture<Boolean> future) {
|
||||
double delay = ess.getSettings().getTeleportDelay();
|
||||
|
||||
final TeleportWarmupEvent event = new TeleportWarmupEvent(teleportee, cause, target, delay);
|
||||
final TeleportWarmupEvent event = new TeleportWarmupEvent(teleporter, teleportee, cause, target, delay);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
@@ -330,12 +346,13 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
return;
|
||||
}
|
||||
}
|
||||
future.complete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
cancel(false);
|
||||
warnUser(teleportee, delay);
|
||||
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false);
|
||||
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false, future);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -366,12 +383,13 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
if (chargeFor != null) {
|
||||
chargeFor.charge(teleportOwner, future);
|
||||
}
|
||||
future.complete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
cancel(false);
|
||||
warnUser(teleportOwner, delay);
|
||||
initTimer((long) (delay * 1000.0), teleportOwner, null, chargeFor, cause, true);
|
||||
initTimer((long) (delay * 1000.0), teleportOwner, null, chargeFor, cause, true, future);
|
||||
}
|
||||
|
||||
void respawnNow(final IUser teleportee, final TeleportCause cause, final CompletableFuture<Boolean> future) {
|
||||
@@ -387,6 +405,9 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
ess.getServer().getPluginManager().callEvent(pre);
|
||||
nowAsync(teleportee, new LocationTarget(pre.getRespawnLocation()), cause, future);
|
||||
}
|
||||
}).exceptionally(th -> {
|
||||
future.completeExceptionally(th);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -402,14 +423,19 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
final Location loc;
|
||||
try {
|
||||
loc = ess.getWarps().getWarp(warp);
|
||||
} catch (final WarpNotFoundException | InvalidWorldException e) {
|
||||
} catch (final WarpNotFoundException e) {
|
||||
future.completeExceptionally(e);
|
||||
return;
|
||||
}
|
||||
otherUser.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
if (!otherUser.equals(teleportOwner)) {
|
||||
teleportOwner.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
}
|
||||
final String finalWarp = warp;
|
||||
future.thenAccept(success -> {
|
||||
if (success) {
|
||||
otherUser.sendTl("warpingTo", finalWarp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
if (!otherUser.equals(teleportOwner)) {
|
||||
teleportOwner.sendTl("warpingTo", finalWarp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
}
|
||||
}
|
||||
});
|
||||
teleport(otherUser, new LocationTarget(loc), chargeFor, cause, future);
|
||||
}
|
||||
|
||||
@@ -422,7 +448,7 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
public void back(final IUser teleporter, final Trade chargeFor, final CompletableFuture<Boolean> future) {
|
||||
tpType = TeleportType.BACK;
|
||||
final Location loc = teleportOwner.getLastLocation();
|
||||
teleportOwner.sendMessage(tl("backUsageMsg", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
teleportOwner.sendTl("backUsageMsg", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
teleportOther(teleporter, teleportOwner, new LocationTarget(loc), chargeFor, TeleportCause.COMMAND, future);
|
||||
}
|
||||
|
||||
@@ -443,8 +469,8 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
}
|
||||
}
|
||||
|
||||
private void initTimer(final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) {
|
||||
timedTeleport = new AsyncTimedTeleport(teleportOwner, ess, this, delay, teleportUser, target, chargeFor, cause, respawn);
|
||||
private void initTimer(final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn, CompletableFuture<Boolean> future) {
|
||||
timedTeleport = new AsyncTimedTeleport(teleportOwner, ess, this, delay, future, teleportUser, target, chargeFor, cause, respawn);
|
||||
}
|
||||
|
||||
public enum TeleportType {
|
||||
+26
-15
@@ -8,8 +8,6 @@ import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class AsyncTimedTeleport implements Runnable {
|
||||
private static final double MOVE_CONSTANT = 0.3;
|
||||
private final IUser teleportOwner;
|
||||
@@ -18,6 +16,7 @@ public class AsyncTimedTeleport implements Runnable {
|
||||
private final UUID timer_teleportee;
|
||||
private final long timer_started; // time this task was initiated
|
||||
private final long timer_delay; // how long to delay the teleportPlayer
|
||||
private final CompletableFuture<Boolean> parentFuture;
|
||||
// note that I initially stored a clone of the location for reference, but...
|
||||
// when comparing locations, I got incorrect mismatches (rounding errors, looked like)
|
||||
// so, the X/Y/Z values are stored instead and rounded off
|
||||
@@ -33,6 +32,10 @@ public class AsyncTimedTeleport implements Runnable {
|
||||
private double timer_health;
|
||||
|
||||
AsyncTimedTeleport(final IUser user, final IEssentials ess, final AsyncTeleport teleport, final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) {
|
||||
this(user, ess, teleport, delay, null, teleportUser, target, chargeFor, cause, respawn);
|
||||
}
|
||||
|
||||
AsyncTimedTeleport(final IUser user, final IEssentials ess, final AsyncTeleport teleport, final long delay, final CompletableFuture<Boolean> future, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) {
|
||||
this.teleportOwner = user;
|
||||
this.ess = ess;
|
||||
this.teleport = teleport;
|
||||
@@ -50,6 +53,18 @@ public class AsyncTimedTeleport implements Runnable {
|
||||
this.timer_canMove = user.isAuthorized("essentials.teleport.timer.move");
|
||||
|
||||
timer_task = ess.runTaskTimerAsynchronously(this, 20, 20).getTaskId();
|
||||
|
||||
if (future != null) {
|
||||
this.parentFuture = future;
|
||||
return;
|
||||
}
|
||||
|
||||
final CompletableFuture<Boolean> cFuture = new CompletableFuture<>();
|
||||
cFuture.exceptionally(e -> {
|
||||
ess.showError(teleportOwner.getSource(), e, "\\ teleport");
|
||||
return false;
|
||||
});
|
||||
this.parentFuture = cFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -89,29 +104,25 @@ public class AsyncTimedTeleport implements Runnable {
|
||||
try {
|
||||
teleport.cooldown(false);
|
||||
} catch (final Throwable ex) {
|
||||
teleportOwner.sendMessage(tl("cooldownWithMessage", ex.getMessage()));
|
||||
teleportOwner.sendTl("cooldownWithMessage", ex.getMessage());
|
||||
if (teleportOwner != teleportUser) {
|
||||
teleportUser.sendMessage(tl("cooldownWithMessage", ex.getMessage()));
|
||||
teleportUser.sendTl("cooldownWithMessage", ex.getMessage());
|
||||
}
|
||||
}
|
||||
try {
|
||||
cancelTimer(false);
|
||||
teleportUser.sendMessage(tl("teleportationCommencing"));
|
||||
teleportUser.sendTl("teleportationCommencing");
|
||||
|
||||
final CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||
future.exceptionally(e -> {
|
||||
ess.showError(teleportOwner.getSource(), e, "\\ teleport");
|
||||
return false;
|
||||
});
|
||||
if (timer_chargeFor != null) {
|
||||
timer_chargeFor.isAffordableFor(teleportOwner);
|
||||
}
|
||||
|
||||
if (timer_respawn) {
|
||||
teleport.respawnNow(teleportUser, timer_cause, future);
|
||||
teleport.respawnNow(teleportUser, timer_cause, parentFuture);
|
||||
} else {
|
||||
teleport.nowAsync(teleportUser, timer_teleportTarget, timer_cause, future);
|
||||
teleport.nowAsync(teleportUser, timer_teleportTarget, timer_cause, parentFuture);
|
||||
}
|
||||
future.thenAccept(success -> {
|
||||
parentFuture.thenAccept(success -> {
|
||||
if (timer_chargeFor != null) {
|
||||
try {
|
||||
timer_chargeFor.charge(teleportOwner);
|
||||
@@ -139,9 +150,9 @@ public class AsyncTimedTeleport implements Runnable {
|
||||
try {
|
||||
ess.getServer().getScheduler().cancelTask(timer_task);
|
||||
if (notifyUser) {
|
||||
teleportOwner.sendMessage(tl("pendingTeleportCancelled"));
|
||||
teleportOwner.sendTl("pendingTeleportCancelled");
|
||||
if (timer_teleportee != null && !timer_teleportee.equals(teleportOwner.getBase().getUniqueId())) {
|
||||
ess.getUser(timer_teleportee).sendMessage(tl("pendingTeleportCancelled"));
|
||||
ess.getUser(timer_teleportee).sendTl("pendingTeleportCancelled");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
+7
-8
@@ -1,5 +1,6 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.utils.AdventureUtil;
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@@ -10,12 +11,10 @@ import java.io.InputStreamReader;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
import static com.earth2me.essentials.I18n.tlLiteral;
|
||||
|
||||
public class Backup implements Runnable {
|
||||
private static final Logger LOGGER = Logger.getLogger("Essentials");
|
||||
private transient final Server server;
|
||||
private transient final IEssentials ess;
|
||||
private final AtomicBoolean pendingShutdown = new AtomicBoolean(false);
|
||||
@@ -81,7 +80,7 @@ public class Backup implements Runnable {
|
||||
taskLock.complete(new Object());
|
||||
return;
|
||||
}
|
||||
LOGGER.log(Level.INFO, tl("backupStarted"));
|
||||
ess.getLogger().log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("backupStarted")));
|
||||
final CommandSender cs = server.getConsoleSender();
|
||||
server.dispatchCommand(cs, "save-all");
|
||||
server.dispatchCommand(cs, "save-off");
|
||||
@@ -99,17 +98,17 @@ public class Backup implements Runnable {
|
||||
do {
|
||||
line = reader.readLine();
|
||||
if (line != null) {
|
||||
LOGGER.log(Level.INFO, line);
|
||||
ess.getLogger().log(Level.INFO, line);
|
||||
}
|
||||
} while (line != null);
|
||||
}
|
||||
} catch (final IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, null, ex);
|
||||
ess.getLogger().log(Level.SEVERE, "An error occurred while reading backup child process", ex);
|
||||
}
|
||||
});
|
||||
child.waitFor();
|
||||
} catch (final InterruptedException | IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, null, ex);
|
||||
ess.getLogger().log(Level.SEVERE, "An error occurred while building the backup child process", ex);
|
||||
} finally {
|
||||
class BackupEnableSaveTask implements Runnable {
|
||||
@Override
|
||||
@@ -120,7 +119,7 @@ public class Backup implements Runnable {
|
||||
}
|
||||
active = false;
|
||||
taskLock.complete(new Object());
|
||||
LOGGER.log(Level.INFO, tl("backupFinished"));
|
||||
ess.getLogger().log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("backupFinished")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.essentialsx.api.v2.services.BalanceTop;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class BalanceTopImpl implements BalanceTop {
|
||||
private final IEssentials ess;
|
||||
private LinkedHashMap<UUID, BalanceTop.Entry> topCache = new LinkedHashMap<>();
|
||||
private BigDecimal balanceTopTotal = BigDecimal.ZERO;
|
||||
private long cacheAge = 0;
|
||||
private CompletableFuture<Void> cacheLock;
|
||||
|
||||
public BalanceTopImpl(IEssentials ess) {
|
||||
this.ess = ess;
|
||||
ess.getServer().getServicesManager().register(BalanceTop.class, this, ess, ServicePriority.Normal);
|
||||
}
|
||||
|
||||
private void calculateBalanceTopMap() {
|
||||
final List<Entry> entries = new LinkedList<>();
|
||||
BigDecimal newTotal = BigDecimal.ZERO;
|
||||
for (UUID u : ess.getUsers().getAllUserUUIDs()) {
|
||||
final User user = ess.getUsers().loadUncachedUser(u);
|
||||
if (user != null) {
|
||||
if (!ess.getSettings().isNpcsInBalanceRanking() && user.isNPC()) {
|
||||
// Don't list NPCs in output
|
||||
continue;
|
||||
}
|
||||
if (!user.isBaltopExempt()) {
|
||||
final BigDecimal userMoney = user.getMoney();
|
||||
user.updateMoneyCache(userMoney);
|
||||
newTotal = newTotal.add(userMoney);
|
||||
final String name;
|
||||
if (user.getBase() instanceof OfflinePlayerStub) {
|
||||
name = user.getLastAccountName();
|
||||
} else if (user.isHidden()) {
|
||||
name = user.getName();
|
||||
} else {
|
||||
name = user.getDisplayName();
|
||||
}
|
||||
entries.add(new BalanceTop.Entry(user.getUUID(), name, userMoney));
|
||||
}
|
||||
}
|
||||
}
|
||||
final LinkedHashMap<UUID, Entry> sortedMap = new LinkedHashMap<>();
|
||||
entries.sort((entry1, entry2) -> entry2.getBalance().compareTo(entry1.getBalance()));
|
||||
for (Entry entry : entries) {
|
||||
sortedMap.put(entry.getUuid(), entry);
|
||||
}
|
||||
topCache = sortedMap;
|
||||
balanceTopTotal = newTotal;
|
||||
cacheAge = System.currentTimeMillis();
|
||||
cacheLock.complete(null);
|
||||
cacheLock = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> calculateBalanceTopMapAsync() {
|
||||
if (cacheLock != null) {
|
||||
return cacheLock;
|
||||
}
|
||||
cacheLock = new CompletableFuture<>();
|
||||
ess.runTaskAsynchronously(this::calculateBalanceTopMap);
|
||||
return cacheLock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, Entry> getBalanceTopCache() {
|
||||
return Collections.unmodifiableMap(topCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCacheAge() {
|
||||
return cacheAge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getBalanceTopTotal() {
|
||||
return balanceTopTotal;
|
||||
}
|
||||
|
||||
public boolean isCacheLocked() {
|
||||
return cacheLock != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import net.ess3.api.TranslatableException;
|
||||
|
||||
public class ChargeException extends TranslatableException {
|
||||
public ChargeException(String tlKey, Object... args) {
|
||||
super(tlKey, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.utils.AdventureUtil;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tlLiteral;
|
||||
|
||||
public class CommandSource {
|
||||
protected Essentials ess;
|
||||
protected CommandSender sender;
|
||||
|
||||
public CommandSource(final Essentials ess, final CommandSender base) {
|
||||
this.ess = ess;
|
||||
this.sender = base;
|
||||
}
|
||||
|
||||
public final CommandSender getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public final Player getPlayer() {
|
||||
if (sender instanceof Player) {
|
||||
return (Player) sender;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void sendTl(final String tlKey, final Object... args) {
|
||||
if (isPlayer()) {
|
||||
//noinspection ConstantConditions
|
||||
getUser().sendTl(tlKey, args);
|
||||
return;
|
||||
}
|
||||
|
||||
final String translation = tlLiteral(tlKey, args);
|
||||
if (!translation.isEmpty()) {
|
||||
sendComponent(AdventureUtil.miniMessage().deserialize(translation));
|
||||
}
|
||||
}
|
||||
|
||||
public String tl(final String tlKey, final Object... args) {
|
||||
if (isPlayer()) {
|
||||
//noinspection ConstantConditions
|
||||
return getUser().playerTl(tlKey, args);
|
||||
}
|
||||
return tlLiteral(tlKey, args);
|
||||
}
|
||||
|
||||
public Component tlComponent(final String tlKey, final Object... args) {
|
||||
if (isPlayer()) {
|
||||
//noinspection ConstantConditions
|
||||
return getUser().tlComponent(tlKey, args);
|
||||
}
|
||||
final String translation = tlLiteral(tlKey, args);
|
||||
return AdventureUtil.miniMessage().deserialize(translation);
|
||||
}
|
||||
|
||||
public void sendComponent(final Component component) {
|
||||
final BukkitAudiences audiences = ess.getBukkitAudience();
|
||||
audiences.sender(sender).sendMessage(component);
|
||||
}
|
||||
|
||||
public final net.ess3.api.IUser getUser() {
|
||||
if (sender instanceof Player) {
|
||||
return ess.getUser((Player) sender);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public final boolean isPlayer() {
|
||||
return sender instanceof Player;
|
||||
}
|
||||
|
||||
public final CommandSender setSender(final CommandSender base) {
|
||||
return this.sender = base;
|
||||
}
|
||||
|
||||
public void sendMessage(final String message) {
|
||||
if (!message.isEmpty()) {
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAuthorized(final String permission) {
|
||||
//noinspection ConstantConditions
|
||||
return !(sender instanceof Player) || getUser().isAuthorized(permission);
|
||||
}
|
||||
|
||||
public String getSelfSelector() {
|
||||
//noinspection ConstantConditions
|
||||
return sender instanceof Player ? getPlayer().getName() : "*";
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
//noinspection ConstantConditions
|
||||
return sender instanceof Player ? getPlayer().getDisplayName() : getSender().getName();
|
||||
}
|
||||
}
|
||||
+32
-1
@@ -2,12 +2,20 @@ package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.messaging.IMessageRecipient;
|
||||
import com.earth2me.essentials.messaging.SimpleMessageRecipient;
|
||||
import com.earth2me.essentials.utils.AdventureUtil;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tlLiteral;
|
||||
|
||||
public final class Console implements IMessageRecipient {
|
||||
public static final String NAME = "Console";
|
||||
public static final String DISPLAY_NAME = tlLiteral("consoleName");
|
||||
private static Console instance; // Set in essentials
|
||||
|
||||
private final IEssentials ess;
|
||||
@@ -43,9 +51,14 @@ public final class Console implements IMessageRecipient {
|
||||
return Console.NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return Console.NAME;
|
||||
return Console.DISPLAY_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,6 +66,24 @@ public final class Console implements IMessageRecipient {
|
||||
getCommandSender().sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTl(String tlKey, Object... args) {
|
||||
final String translation = tlLiteral(tlKey, args);
|
||||
if (translation.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Audience consoleAudience = ((Essentials) ess).getBukkitAudience().sender(getCommandSender());
|
||||
final Component component = AdventureUtil.miniMessage()
|
||||
.deserialize(translation);
|
||||
consoleAudience.sendMessage(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tlSender(String tlKey, Object... args) {
|
||||
return tlLiteral(tlKey, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReachable() {
|
||||
return true;
|
||||
@@ -0,0 +1,402 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.utils.RegistryUtil;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
public final class Enchantments {
|
||||
private static final Map<String, Enchantment> ENCHANTMENTS = new HashMap<>();
|
||||
private static final Map<String, Enchantment> ALIASENCHANTMENTS = new HashMap<>();
|
||||
private static boolean isFlat;
|
||||
|
||||
static {
|
||||
final Enchantment SHARPNESS = RegistryUtil.valueOf(Enchantment.class, "DAMAGE_ALL", "SHARPNESS");
|
||||
|
||||
ENCHANTMENTS.put("alldamage", SHARPNESS);
|
||||
ALIASENCHANTMENTS.put("alldmg", SHARPNESS);
|
||||
ENCHANTMENTS.put("sharpness", SHARPNESS);
|
||||
ALIASENCHANTMENTS.put("sharp", SHARPNESS);
|
||||
ALIASENCHANTMENTS.put("dal", SHARPNESS);
|
||||
|
||||
final Enchantment BANE_OF_ARTHROPODS = RegistryUtil.valueOf(Enchantment.class, "DAMAGE_ARTHROPODS", "BANE_OF_ARTHROPODS");
|
||||
|
||||
ENCHANTMENTS.put("ardmg", BANE_OF_ARTHROPODS);
|
||||
ENCHANTMENTS.put("baneofarthropods", BANE_OF_ARTHROPODS);
|
||||
ALIASENCHANTMENTS.put("baneofarthropod", BANE_OF_ARTHROPODS);
|
||||
ALIASENCHANTMENTS.put("arthropod", BANE_OF_ARTHROPODS);
|
||||
ALIASENCHANTMENTS.put("dar", BANE_OF_ARTHROPODS);
|
||||
|
||||
final Enchantment SMITE = RegistryUtil.valueOf(Enchantment.class, "DAMAGE_UNDEAD", "SMITE");
|
||||
|
||||
ENCHANTMENTS.put("undeaddamage", SMITE);
|
||||
ENCHANTMENTS.put("smite", SMITE);
|
||||
ALIASENCHANTMENTS.put("du", SMITE);
|
||||
|
||||
final Enchantment EFFICIENCY = RegistryUtil.valueOf(Enchantment.class, "DIG_SPEED", "EFFICIENCY");
|
||||
|
||||
ENCHANTMENTS.put("digspeed", EFFICIENCY);
|
||||
ENCHANTMENTS.put("efficiency", EFFICIENCY);
|
||||
ALIASENCHANTMENTS.put("minespeed", EFFICIENCY);
|
||||
ALIASENCHANTMENTS.put("cutspeed", EFFICIENCY);
|
||||
ALIASENCHANTMENTS.put("ds", EFFICIENCY);
|
||||
ALIASENCHANTMENTS.put("eff", EFFICIENCY);
|
||||
|
||||
final Enchantment UNBREAKING = RegistryUtil.valueOf(Enchantment.class, "DURABILITY", "UNBREAKING");
|
||||
|
||||
ENCHANTMENTS.put("durability", UNBREAKING);
|
||||
ALIASENCHANTMENTS.put("dura", UNBREAKING);
|
||||
ENCHANTMENTS.put("unbreaking", UNBREAKING);
|
||||
ALIASENCHANTMENTS.put("d", UNBREAKING);
|
||||
|
||||
ENCHANTMENTS.put("thorns", Enchantment.THORNS);
|
||||
ENCHANTMENTS.put("highcrit", Enchantment.THORNS);
|
||||
ALIASENCHANTMENTS.put("thorn", Enchantment.THORNS);
|
||||
ALIASENCHANTMENTS.put("highercrit", Enchantment.THORNS);
|
||||
ALIASENCHANTMENTS.put("t", Enchantment.THORNS);
|
||||
|
||||
ENCHANTMENTS.put("fireaspect", Enchantment.FIRE_ASPECT);
|
||||
ENCHANTMENTS.put("fire", Enchantment.FIRE_ASPECT);
|
||||
ALIASENCHANTMENTS.put("meleefire", Enchantment.FIRE_ASPECT);
|
||||
ALIASENCHANTMENTS.put("meleeflame", Enchantment.FIRE_ASPECT);
|
||||
ALIASENCHANTMENTS.put("fa", Enchantment.FIRE_ASPECT);
|
||||
|
||||
ENCHANTMENTS.put("knockback", Enchantment.KNOCKBACK);
|
||||
ALIASENCHANTMENTS.put("kback", Enchantment.KNOCKBACK);
|
||||
ALIASENCHANTMENTS.put("kb", Enchantment.KNOCKBACK);
|
||||
ALIASENCHANTMENTS.put("k", Enchantment.KNOCKBACK);
|
||||
|
||||
final Enchantment FORTUNE = RegistryUtil.valueOf(Enchantment.class, "LOOT_BONUS_BLOCKS", "FORTUNE");
|
||||
|
||||
ALIASENCHANTMENTS.put("blockslootbonus", FORTUNE);
|
||||
ENCHANTMENTS.put("fortune", FORTUNE);
|
||||
ALIASENCHANTMENTS.put("fort", FORTUNE);
|
||||
ALIASENCHANTMENTS.put("lbb", FORTUNE);
|
||||
|
||||
final Enchantment LOOTING = RegistryUtil.valueOf(Enchantment.class, "LOOT_BONUS_MOBS", "LOOTING");
|
||||
|
||||
ALIASENCHANTMENTS.put("mobslootbonus", LOOTING);
|
||||
ENCHANTMENTS.put("mobloot", LOOTING);
|
||||
ENCHANTMENTS.put("looting", LOOTING);
|
||||
ALIASENCHANTMENTS.put("lbm", LOOTING);
|
||||
|
||||
final Enchantment RESPIRATION = RegistryUtil.valueOf(Enchantment.class, "OXYGEN", "RESPIRATION");
|
||||
|
||||
ALIASENCHANTMENTS.put("oxygen", RESPIRATION);
|
||||
ENCHANTMENTS.put("respiration", RESPIRATION);
|
||||
ALIASENCHANTMENTS.put("breathing", RESPIRATION);
|
||||
ENCHANTMENTS.put("breath", RESPIRATION);
|
||||
ALIASENCHANTMENTS.put("o", RESPIRATION);
|
||||
|
||||
final Enchantment PROTECTION = RegistryUtil.valueOf(Enchantment.class, "PROTECTION_ENVIRONMENTAL", "PROTECTION");
|
||||
|
||||
ENCHANTMENTS.put("protection", PROTECTION);
|
||||
ALIASENCHANTMENTS.put("prot", PROTECTION);
|
||||
ENCHANTMENTS.put("protect", PROTECTION);
|
||||
ALIASENCHANTMENTS.put("p", PROTECTION);
|
||||
|
||||
final Enchantment BLAST_PROTECTION = RegistryUtil.valueOf(Enchantment.class, "PROTECTION_EXPLOSIONS", "BLAST_PROTECTION");
|
||||
|
||||
ALIASENCHANTMENTS.put("explosionsprotection", BLAST_PROTECTION);
|
||||
ALIASENCHANTMENTS.put("explosionprotection", BLAST_PROTECTION);
|
||||
ALIASENCHANTMENTS.put("expprot", BLAST_PROTECTION);
|
||||
ALIASENCHANTMENTS.put("blastprotection", BLAST_PROTECTION);
|
||||
ALIASENCHANTMENTS.put("bprotection", BLAST_PROTECTION);
|
||||
ALIASENCHANTMENTS.put("bprotect", BLAST_PROTECTION);
|
||||
ENCHANTMENTS.put("blastprotect", BLAST_PROTECTION);
|
||||
ALIASENCHANTMENTS.put("pe", BLAST_PROTECTION);
|
||||
|
||||
final Enchantment FEATHER_FALLING = RegistryUtil.valueOf(Enchantment.class, "PROTECTION_FALL", "FEATHER_FALLING");
|
||||
|
||||
ALIASENCHANTMENTS.put("fallprotection", FEATHER_FALLING);
|
||||
ENCHANTMENTS.put("fallprot", FEATHER_FALLING);
|
||||
ENCHANTMENTS.put("featherfall", FEATHER_FALLING);
|
||||
ALIASENCHANTMENTS.put("featherfalling", FEATHER_FALLING);
|
||||
ALIASENCHANTMENTS.put("pfa", FEATHER_FALLING);
|
||||
|
||||
final Enchantment FIRE_PROTECTION = RegistryUtil.valueOf(Enchantment.class, "PROTECTION_FIRE", "FIRE_PROTECTION");
|
||||
|
||||
ALIASENCHANTMENTS.put("fireprotection", FIRE_PROTECTION);
|
||||
ALIASENCHANTMENTS.put("flameprotection", FIRE_PROTECTION);
|
||||
ENCHANTMENTS.put("fireprotect", FIRE_PROTECTION);
|
||||
ALIASENCHANTMENTS.put("flameprotect", FIRE_PROTECTION);
|
||||
ENCHANTMENTS.put("fireprot", FIRE_PROTECTION);
|
||||
ALIASENCHANTMENTS.put("flameprot", FIRE_PROTECTION);
|
||||
ALIASENCHANTMENTS.put("pf", FIRE_PROTECTION);
|
||||
|
||||
final Enchantment PROJECTILE_PROTECTION = RegistryUtil.valueOf(Enchantment.class, "PROTECTION_PROJECTILE", "PROJECTILE_PROTECTION");
|
||||
|
||||
ENCHANTMENTS.put("projectileprotection", PROJECTILE_PROTECTION);
|
||||
ENCHANTMENTS.put("projprot", PROJECTILE_PROTECTION);
|
||||
ALIASENCHANTMENTS.put("pp", PROJECTILE_PROTECTION);
|
||||
|
||||
ENCHANTMENTS.put("silktouch", Enchantment.SILK_TOUCH);
|
||||
ALIASENCHANTMENTS.put("softtouch", Enchantment.SILK_TOUCH);
|
||||
ALIASENCHANTMENTS.put("st", Enchantment.SILK_TOUCH);
|
||||
|
||||
final Enchantment AQUA_AFFINITY = RegistryUtil.valueOf(Enchantment.class, "WATER_WORKER", "AQUA_AFFINITY");
|
||||
|
||||
ENCHANTMENTS.put("waterworker", AQUA_AFFINITY);
|
||||
ENCHANTMENTS.put("aquaaffinity", AQUA_AFFINITY);
|
||||
ALIASENCHANTMENTS.put("watermine", AQUA_AFFINITY);
|
||||
ALIASENCHANTMENTS.put("ww", AQUA_AFFINITY);
|
||||
|
||||
final Enchantment FLAME = RegistryUtil.valueOf(Enchantment.class, "ARROW_FIRE", "FLAME");
|
||||
|
||||
ALIASENCHANTMENTS.put("firearrow", FLAME);
|
||||
ENCHANTMENTS.put("flame", FLAME);
|
||||
ENCHANTMENTS.put("flamearrow", FLAME);
|
||||
ALIASENCHANTMENTS.put("af", FLAME);
|
||||
|
||||
final Enchantment POWER = RegistryUtil.valueOf(Enchantment.class, "ARROW_DAMAGE", "POWER");
|
||||
|
||||
ENCHANTMENTS.put("arrowdamage", POWER);
|
||||
ENCHANTMENTS.put("power", POWER);
|
||||
ALIASENCHANTMENTS.put("arrowpower", POWER);
|
||||
ALIASENCHANTMENTS.put("ad", POWER);
|
||||
|
||||
final Enchantment PUNCH = RegistryUtil.valueOf(Enchantment.class, "ARROW_KNOCKBACK", "PUNCH");
|
||||
|
||||
ENCHANTMENTS.put("arrowknockback", PUNCH);
|
||||
ALIASENCHANTMENTS.put("arrowkb", PUNCH);
|
||||
ENCHANTMENTS.put("punch", PUNCH);
|
||||
ALIASENCHANTMENTS.put("arrowpunch", PUNCH);
|
||||
ALIASENCHANTMENTS.put("ak", PUNCH);
|
||||
|
||||
final Enchantment INFINITY = RegistryUtil.valueOf(Enchantment.class, "ARROW_INFINITE", "INFINITY");
|
||||
|
||||
ALIASENCHANTMENTS.put("infinitearrows", INFINITY);
|
||||
ENCHANTMENTS.put("infarrows", INFINITY);
|
||||
ENCHANTMENTS.put("infinity", INFINITY);
|
||||
ALIASENCHANTMENTS.put("infinite", INFINITY);
|
||||
ALIASENCHANTMENTS.put("unlimited", INFINITY);
|
||||
ALIASENCHANTMENTS.put("unlimitedarrows", INFINITY);
|
||||
ALIASENCHANTMENTS.put("ai", INFINITY);
|
||||
|
||||
final Enchantment LUCK_OF_THE_SEA = RegistryUtil.valueOf(Enchantment.class, "LUCK", "LUCK_OF_THE_SEA");
|
||||
|
||||
ENCHANTMENTS.put("luck", LUCK_OF_THE_SEA);
|
||||
ALIASENCHANTMENTS.put("luckofsea", LUCK_OF_THE_SEA);
|
||||
ALIASENCHANTMENTS.put("luckofseas", LUCK_OF_THE_SEA);
|
||||
ALIASENCHANTMENTS.put("rodluck", LUCK_OF_THE_SEA);
|
||||
|
||||
ENCHANTMENTS.put("lure", Enchantment.LURE);
|
||||
ALIASENCHANTMENTS.put("rodlure", Enchantment.LURE);
|
||||
|
||||
ENCHANTMENTS.put("depthstrider", Enchantment.DEPTH_STRIDER);
|
||||
ALIASENCHANTMENTS.put("depth", Enchantment.DEPTH_STRIDER);
|
||||
ALIASENCHANTMENTS.put("strider", Enchantment.DEPTH_STRIDER);
|
||||
|
||||
// 1.9
|
||||
try {
|
||||
final Enchantment frostWalker = Enchantment.getByName("FROST_WALKER");
|
||||
if (frostWalker != null) {
|
||||
ENCHANTMENTS.put("frostwalker", frostWalker);
|
||||
ALIASENCHANTMENTS.put("frost", frostWalker);
|
||||
ALIASENCHANTMENTS.put("walker", frostWalker);
|
||||
}
|
||||
|
||||
final Enchantment mending = Enchantment.getByName("MENDING");
|
||||
if (mending != null) {
|
||||
ENCHANTMENTS.put("mending", mending);
|
||||
}
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
// 1.11
|
||||
try {
|
||||
final Enchantment bindingCurse = Enchantment.getByName("BINDING_CURSE");
|
||||
if (bindingCurse != null) {
|
||||
ENCHANTMENTS.put("bindingcurse", bindingCurse);
|
||||
ALIASENCHANTMENTS.put("bindcurse", bindingCurse);
|
||||
ALIASENCHANTMENTS.put("binding", bindingCurse);
|
||||
ALIASENCHANTMENTS.put("bind", bindingCurse);
|
||||
}
|
||||
final Enchantment vanishingCurse = Enchantment.getByName("VANISHING_CURSE");
|
||||
if (vanishingCurse != null) {
|
||||
ENCHANTMENTS.put("vanishingcurse", vanishingCurse);
|
||||
ALIASENCHANTMENTS.put("vanishcurse", vanishingCurse);
|
||||
ALIASENCHANTMENTS.put("vanishing", vanishingCurse);
|
||||
ALIASENCHANTMENTS.put("vanish", vanishingCurse);
|
||||
}
|
||||
final Enchantment sweeping = Enchantment.getByName("SWEEPING_EDGE");
|
||||
if (sweeping != null) {
|
||||
ENCHANTMENTS.put("sweepingedge", sweeping);
|
||||
ALIASENCHANTMENTS.put("sweepedge", sweeping);
|
||||
ALIASENCHANTMENTS.put("sweeping", sweeping);
|
||||
}
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
try { // 1.13
|
||||
final Enchantment loyalty = Enchantment.getByName("LOYALTY");
|
||||
if (loyalty != null) {
|
||||
ENCHANTMENTS.put("loyalty", loyalty);
|
||||
ALIASENCHANTMENTS.put("loyal", loyalty);
|
||||
ALIASENCHANTMENTS.put("return", loyalty);
|
||||
}
|
||||
final Enchantment impaling = Enchantment.getByName("IMPALING");
|
||||
if (impaling != null) {
|
||||
ENCHANTMENTS.put("impaling", impaling);
|
||||
ALIASENCHANTMENTS.put("impale", impaling);
|
||||
ALIASENCHANTMENTS.put("oceandamage", impaling);
|
||||
ALIASENCHANTMENTS.put("oceandmg", impaling);
|
||||
}
|
||||
final Enchantment riptide = Enchantment.getByName("RIPTIDE");
|
||||
if (riptide != null) {
|
||||
ENCHANTMENTS.put("riptide", riptide);
|
||||
ALIASENCHANTMENTS.put("rip", riptide);
|
||||
ALIASENCHANTMENTS.put("tide", riptide);
|
||||
ALIASENCHANTMENTS.put("launch", riptide);
|
||||
}
|
||||
final Enchantment channelling = Enchantment.getByName("CHANNELING");
|
||||
if (channelling != null) {
|
||||
ENCHANTMENTS.put("channelling", channelling);
|
||||
ALIASENCHANTMENTS.put("chanelling", channelling);
|
||||
ALIASENCHANTMENTS.put("channeling", channelling);
|
||||
ALIASENCHANTMENTS.put("chaneling", channelling);
|
||||
ALIASENCHANTMENTS.put("channel", channelling);
|
||||
}
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
try { // 1.14
|
||||
final Enchantment multishot = Enchantment.getByName("MULTISHOT");
|
||||
if (multishot != null) {
|
||||
ENCHANTMENTS.put("multishot", multishot);
|
||||
ALIASENCHANTMENTS.put("tripleshot", multishot);
|
||||
}
|
||||
final Enchantment quickCharge = Enchantment.getByName("QUICK_CHARGE");
|
||||
if (quickCharge != null) {
|
||||
ENCHANTMENTS.put("quickcharge", quickCharge);
|
||||
ALIASENCHANTMENTS.put("quickdraw", quickCharge);
|
||||
ALIASENCHANTMENTS.put("fastcharge", quickCharge);
|
||||
ALIASENCHANTMENTS.put("fastdraw", quickCharge);
|
||||
}
|
||||
final Enchantment piercing = Enchantment.getByName("PIERCING");
|
||||
if (piercing != null) {
|
||||
ENCHANTMENTS.put("piercing", piercing);
|
||||
}
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
try { // 1.16
|
||||
final Enchantment soulspeed = Enchantment.getByName("SOUL_SPEED");
|
||||
if (soulspeed != null) {
|
||||
ENCHANTMENTS.put("soulspeed", soulspeed);
|
||||
ALIASENCHANTMENTS.put("soilspeed", soulspeed);
|
||||
ALIASENCHANTMENTS.put("sandspeed", soulspeed);
|
||||
}
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
try { // 1.19
|
||||
final Enchantment swiftSneak = Enchantment.getByName("SWIFT_SNEAK");
|
||||
if (swiftSneak != null) {
|
||||
ENCHANTMENTS.put("swiftsneak", swiftSneak);
|
||||
}
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
try { // 1.21
|
||||
final Enchantment breach = Enchantment.getByName("BREACH");
|
||||
if (breach != null) {
|
||||
ENCHANTMENTS.put("breach", breach);
|
||||
}
|
||||
final Enchantment density = Enchantment.getByName("DENSITY");
|
||||
if (density != null) {
|
||||
ENCHANTMENTS.put("density", density);
|
||||
}
|
||||
final Enchantment windBurst = Enchantment.getByName("WIND_BURST");
|
||||
if (breach != null) {
|
||||
ENCHANTMENTS.put("windburst", windBurst);
|
||||
ALIASENCHANTMENTS.put("wind", windBurst);
|
||||
ALIASENCHANTMENTS.put("burst", windBurst);
|
||||
}
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
final Class<?> namespacedKeyClass = Class.forName("org.bukkit.NamespacedKey");
|
||||
final Class<?> enchantmentClass = Class.forName("org.bukkit.enchantments.Enchantment");
|
||||
enchantmentClass.getDeclaredMethod("getByKey", namespacedKeyClass);
|
||||
isFlat = true;
|
||||
} catch (final ClassNotFoundException | NoSuchMethodException e) {
|
||||
isFlat = false;
|
||||
}
|
||||
}
|
||||
|
||||
private Enchantments() {
|
||||
}
|
||||
|
||||
public static String getRealName(final Enchantment enchantment) {
|
||||
if (enchantment == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isFlat) { // 1.13+ only
|
||||
return enchantment.getKey().getKey();
|
||||
}
|
||||
return enchantment.getName().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
public static Enchantment getByName(final String name) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Enchantment enchantment = null;
|
||||
if (isFlat) { // 1.13+ only
|
||||
try {
|
||||
enchantment = Enchantment.getByKey(NamespacedKey.minecraft(name.toLowerCase()));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// NamespacedKey throws IAE if key does not match regex
|
||||
}
|
||||
}
|
||||
|
||||
if (enchantment == null) {
|
||||
enchantment = Enchantment.getByName(name.toUpperCase());
|
||||
}
|
||||
if (enchantment == null) {
|
||||
enchantment = Enchantment.getByName(name.toLowerCase());
|
||||
}
|
||||
if (enchantment == null) {
|
||||
enchantment = Enchantment.getByName(name);
|
||||
}
|
||||
if (enchantment == null) {
|
||||
enchantment = ENCHANTMENTS.get(name.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
if (enchantment == null) {
|
||||
enchantment = ALIASENCHANTMENTS.get(name.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
return enchantment;
|
||||
}
|
||||
|
||||
public static Set<Entry<String, Enchantment>> entrySet() {
|
||||
return ENCHANTMENTS.entrySet();
|
||||
}
|
||||
|
||||
public static Set<String> keySet() {
|
||||
return ENCHANTMENTS.keySet();
|
||||
}
|
||||
|
||||
public static void registerEnchantment(String name, Enchantment enchantment) {
|
||||
if (ENCHANTMENTS.containsKey(name) || ALIASENCHANTMENTS.containsKey(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ENCHANTMENTS.put(name, enchantment);
|
||||
}
|
||||
|
||||
public static void registerAlias(String name, Enchantment enchantment) {
|
||||
if (ENCHANTMENTS.containsKey(name) || ALIASENCHANTMENTS.containsKey(name) || !ENCHANTMENTS.containsValue(enchantment)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ALIASENCHANTMENTS.put(name, enchantment);
|
||||
}
|
||||
}
|
||||
+558
-279
File diff suppressed because it is too large.
Load diff
Loaded 100 of 847 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user