mirror of
https://github.com/EssentialsX/Essentials.git
synced 2026-11-05 09:10:17 -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 | ||
|
|
a6edf04a60 | ||
|
|
3ba675a899 | ||
|
|
1fed7a9a3a | ||
|
|
80fb91b6d7 | ||
|
|
5b0c2a4131 | ||
|
|
bb43e8f7b6 | ||
|
|
4d9a10147a | ||
|
|
ea4f5cf919 | ||
|
|
295bc9f76d | ||
|
|
327806d9a1 | ||
|
|
80e7558fc0 | ||
|
|
9cda59511e | ||
|
|
c12a031918 | ||
|
|
a4f580e319 | ||
|
|
583bf88207 | ||
|
|
a5f8e83e03 | ||
|
|
e2f17f11d3 | ||
|
|
4f8c040d06 | ||
|
|
af1d068022 | ||
|
|
1bd8d1c85c | ||
|
|
d7fc859d14 | ||
|
|
ac953cd114 | ||
|
|
6e6dd041d5 | ||
|
|
9b3c8a9df2 | ||
|
|
234a481b0d | ||
|
|
89b3c9233e | ||
|
|
5d61a43fe1 | ||
|
|
29d5ccf751 | ||
|
|
fde0665593 | ||
|
|
29541b0995 | ||
|
|
05f31c5ddf | ||
|
|
f89840545d | ||
|
|
18534f8576 | ||
|
|
1382a05dc8 | ||
|
|
1671d4839c | ||
|
|
4d2fbd04c5 | ||
|
|
dc6b9b89cd | ||
|
|
76f36aa895 | ||
|
|
fa835e9c64 |
No files matched your search
@@ -0,0 +1,183 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE module PUBLIC "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
|
||||
<!-- based on https://github.com/KyoriPowered/adventure/blob/master/.checkstyle/checkstyle.xml -->
|
||||
|
||||
<module name="Checker">
|
||||
<property name="charset" value="UTF-8"/>
|
||||
<property name="fileExtensions" value="java, properties, xml"/>
|
||||
<property name="severity" value="error"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_filefilters.html#BeforeExecutionExclusionFileFilter -->
|
||||
<module name="BeforeExecutionExclusionFileFilter">
|
||||
<property name="fileNamePattern" value="module\-info\.java$"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_whitespace.html#FileTabCharacter -->
|
||||
<module name="FileTabCharacter">
|
||||
<property name="eachLine" value="true"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_misc.html#NewlineAtEndOfFile -->
|
||||
<module name="NewlineAtEndOfFile"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_filters.html#SuppressionFilter -->
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${configDirectory}/suppressions.xml"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_filters.html#SuppressWithPlainTextCommentFilter -->
|
||||
<module name="SuppressWithPlainTextCommentFilter"/>
|
||||
|
||||
<module name="TreeWalker">
|
||||
<!-- https://checkstyle.org/config_misc.html#ArrayTypeStyle -->
|
||||
<module name="ArrayTypeStyle"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_imports.html#AvoidStarImport -->
|
||||
<module name="AvoidStarImport"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_misc.html#AvoidEscapedUnicodeCharacters -->
|
||||
<module name="AvoidEscapedUnicodeCharacters">
|
||||
<property name="allowByTailComment" value="true"/>
|
||||
<property name="allowEscapesForControlCharacters" value="true"/>
|
||||
<property name="allowNonPrintableEscapes" value="true"/>
|
||||
<property name="severity" value="info"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_misc.html#CommentsIndentation -->
|
||||
<module name="CommentsIndentation"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_whitespace.html#EmptyForInitializerPad -->
|
||||
<module name="EmptyForInitializerPad"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_whitespace.html#EmptyForIteratorPad -->
|
||||
<module name="EmptyForIteratorPad"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_whitespace.html#EmptyLineSeparator -->
|
||||
<module name="EmptyLineSeparator">
|
||||
<property name="allowMultipleEmptyLines" value="false"/>
|
||||
<property name="allowMultipleEmptyLinesInsideClassMembers" value="false"/>
|
||||
<property name="allowNoEmptyLineBetweenFields" value="true"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, CTOR_DEF, ENUM_DEF, IMPORT, INSTANCE_INIT, INTERFACE_DEF, METHOD_DEF, STATIC_IMPORT, STATIC_INIT, VARIABLE_DEF"/> <!-- remove PACKAGE_DEF, temporarily remove COMPACT_CTOR_DEF, RECORD_DEF -->
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_coding.html#FallThrough -->
|
||||
<module name="FallThrough">
|
||||
<property name="checkLastCaseGroup" value="true"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_design.html#FinalClass -->
|
||||
<module name="FinalClass"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_coding.html#FinalLocalVariable -->
|
||||
<module name="FinalLocalVariable"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_whitespace.html#GenericWhitespace -->
|
||||
<module name="GenericWhitespace"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_design.html#HideUtilityClassConstructor -->
|
||||
<module name="HideUtilityClassConstructor"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_imports.html#IllegalImport -->
|
||||
<module name="IllegalImport">
|
||||
<property name="illegalPkgs" value="sun, jdk, com.sun"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_coding.html#IllegalTokenText -->
|
||||
<module name="IllegalTokenText">
|
||||
<property name="format"
|
||||
value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
|
||||
<property name="message"
|
||||
value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
|
||||
<property name="tokens" value="CHAR_LITERAL, STRING_LITERAL"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_misc.html#Indentation -->
|
||||
<module name="Indentation"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_blocks.html#LeftCurly -->
|
||||
<module name="LeftCurly"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_naming.html#MethodName -->
|
||||
<module name="MethodName">
|
||||
<property name="format" value="^[_]?[a-z][a-zA-Z0-9]*$"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_whitespace.html#MethodParamPad -->
|
||||
<module name="MethodParamPad"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_javadoc.html#MissingJavadocMethod -->
|
||||
<module name="MissingJavadocMethod">
|
||||
<property name="allowMissingPropertyJavadoc" value="true"/>
|
||||
<property name="tokens" value="METHOD_DEF, ANNOTATION_FIELD_DEF"/> <!-- remove CTOR_DEF, COMPACT_CTOR_DEF -->
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_javadoc.html#MissingJavadocType -->
|
||||
<module name="MissingJavadocType"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_coding.html#NoFinalizer -->
|
||||
<module name="NoFinalizer"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_whitespace.html#NoLineWrap -->
|
||||
<module name="NoLineWrap"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_whitespace.html#NoWhitespaceAfter -->
|
||||
<module name="NoWhitespaceAfter">
|
||||
<property name="allowLineBreaks" value="false"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_whitespace.html#NoWhitespaceBefore -->
|
||||
<module name="NoWhitespaceBefore">
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_coding.html#OneStatementPerLine -->
|
||||
<module name="OneStatementPerLine"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_misc.html#OuterTypeFilename -->
|
||||
<module name="OuterTypeFilename"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_imports.html#RedundantImport -->
|
||||
<module name="RedundantImport"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_modifier.html#RedundantModifier -->
|
||||
<module name="RedundantModifier">
|
||||
<property name="tokens"
|
||||
value="ANNOTATION_FIELD_DEF, CLASS_DEF, CTOR_DEF, ENUM_DEF, INTERFACE_DEF, VARIABLE_DEF"/> <!-- remove METHOD_DEF and RESOURCE -->
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_coding.html#RequireThis -->
|
||||
<module name="RequireThis"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_blocks.html#RightCurly -->
|
||||
<module name="RightCurly">
|
||||
<property name="id" value="RightCurlyAlone"/>
|
||||
<property name="option" value="alone"/>
|
||||
<property name="tokens"
|
||||
value="ANNOTATION_DEF, CLASS_DEF, CTOR_DEF, ENUM_DEF, INSTANCE_INIT, LITERAL_FOR, LITERAL_WHILE, METHOD_DEF, STATIC_INIT"/>
|
||||
</module>
|
||||
<module name="RightCurly">
|
||||
<property name="id" value="RightCurlySame"/>
|
||||
<property name="option" value="same"/>
|
||||
<property name="tokens"
|
||||
value="LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_IF, LITERAL_TRY"/> <!-- add LITERAL_DO -->
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_whitespace.html#SingleSpaceSeparator -->
|
||||
<module name="SingleSpaceSeparator">
|
||||
<property name="validateComments" value="true"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_whitespace.html#TypecastParenPad -->
|
||||
<module name="TypecastParenPad"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_coding.html#UnnecessaryParentheses -->
|
||||
<module name="UnnecessaryParentheses"/>
|
||||
|
||||
<!-- https://checkstyle.org/config_imports.html#UnusedImports -->
|
||||
<module name="UnusedImports"/>
|
||||
|
||||
</module>
|
||||
</module>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE suppressions PUBLIC "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" "http://checkstyle.org/dtds/suppressions_1_2.dtd">
|
||||
<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[\\/]|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
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- 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: Join the MOSS Discord for community-powered EssentialsX support!
|
||||
@@ -1,45 +0,0 @@
|
||||
---
|
||||
name: Help!
|
||||
about: Encountered a problem with EssentialsX? Not sure how to fix it?
|
||||
|
||||
---
|
||||
|
||||
<!-- EssentialsX help guide
|
||||
|
||||
Don't write inside the arrows as they will be hidden when you post your issue.
|
||||
|
||||
Want faster support? Come join our Discord server to get help sooner:
|
||||
https://discord.gg/F7gexAQ
|
||||
|
||||
If you're happy to wait (or you were sent here from Discord), read on:
|
||||
|
||||
1. Fill out the template.
|
||||
This will help us understand what problem you've encountered and help us
|
||||
find a solution.
|
||||
|
||||
2. Check the Common Issues page.
|
||||
Read through the wiki page to see if you've encountered a regular issue:
|
||||
https://essentialsx.github.io/#/Common-Issues
|
||||
|
||||
3. Delete this line and all above lines before posting your issue! -->
|
||||
|
||||
### Information
|
||||
|
||||
Full output of `/ess version`:
|
||||
|
||||
<!-- Replace this with the command output -->
|
||||
|
||||
**Server log:** <!-- Upload `logs/latest.log` to https://gist.github.com/ -->
|
||||
|
||||
**EssentialsX config** <!-- Upload `plugins/Essentials/config.yml` to https://gist.github.com/ -->
|
||||
|
||||
### Help request
|
||||
|
||||
**Problem**
|
||||
<!-- What problem did you encounter? -->
|
||||
|
||||
**What I have tried**
|
||||
<!-- What have you tried so far? -->
|
||||
|
||||
**Screenshots**
|
||||
<!-- If relevant, include any screenshots here. -->
|
||||
@@ -1,58 +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!".
|
||||
|
||||
---
|
||||
|
||||
<!-- EssentialsX bug reporting guide
|
||||
|
||||
Don't put anything inside this block, as it won't be included in the issue.
|
||||
|
||||
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 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.
|
||||
|
||||
5. Make sure not to write between the arrows, as anything there will be
|
||||
hidden.
|
||||
|
||||
6. Delete this line and all above lines before posting your issue! -->
|
||||
|
||||
### Information
|
||||
|
||||
**Full output of `/ess version`**:
|
||||
|
||||
```
|
||||
<!-- Run the command in your console, and copy and paste the whole output here -->
|
||||
```
|
||||
|
||||
**Server log**: <!-- Upload `logs/latest.log` to https://gist.github.com/, replace this with link -->
|
||||
|
||||
**EssentialsX config**: <!-- Upload `plugins/Essentials/config.yml` to https://gist.github.com/, replace this with link -->
|
||||
|
||||
### Details
|
||||
|
||||
**Description**
|
||||
<!-- Replace this with a brief summary of the bug. -->
|
||||
|
||||
**Steps to reproduce**
|
||||
<!-- Replace this with exactly what you did to cause the bug. -->
|
||||
|
||||
**Expected behavior**
|
||||
<!-- Replace this with what you expected to happen. -->
|
||||
|
||||
**Screenshots**
|
||||
<!-- Replace this with screenshots, if necessary. -->
|
||||
@@ -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,45 +0,0 @@
|
||||
---
|
||||
name: Request a feature
|
||||
about: Suggest a feature you want to see in EssentialsX!
|
||||
|
||||
---
|
||||
|
||||
<!-- EssentialsX feature request guide
|
||||
|
||||
Fill out the template. Don't write inside the arrows as they will be hidden
|
||||
when you post your issue.
|
||||
|
||||
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 wiki at https://essentialsx.github.io/ to see if the
|
||||
feature was recently added.
|
||||
|
||||
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.
|
||||
|
||||
5. Delete this line and all above lines before posting your issue! -->
|
||||
|
||||
### Feature request
|
||||
|
||||
**Feature description**
|
||||
<!-- What feature are you suggesting? -->
|
||||
|
||||
**How the feature is useful**
|
||||
<!-- How is the feature useful to players, server owners and/or developers? -->
|
||||
@@ -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
|
||||
@@ -0,0 +1,94 @@
|
||||
<!--
|
||||
|
||||
EssentialsX bug fix submission guide
|
||||
====================================
|
||||
|
||||
NOTE: Failure to fill out this template properly may result in your PR being
|
||||
delayed or ignored without warning.
|
||||
|
||||
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.
|
||||
This includes providing screenshots and a link to the original bug
|
||||
report. If there isn't an existing bug report, we recommend opening a new
|
||||
detailed bug report BEFORE opening your PR to fix it, else your PR may be
|
||||
delayed or rejected without warning.
|
||||
|
||||
You can open a new bug report by following this link:
|
||||
https://github.com/EssentialsX/Essentials/issues/new/choose
|
||||
|
||||
2. 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 with future reviews.
|
||||
|
||||
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 can drag screenshots into the bottom of the editor.)
|
||||
|
||||
-->
|
||||
|
||||
### Information
|
||||
|
||||
<!--
|
||||
Replace #nnnn with the number of the original issue. If this PR fixes
|
||||
multiple issues, you should repeat the phrase "fixes #nnnn" for each issue.
|
||||
-->
|
||||
|
||||
This PR fixes #nnnn.
|
||||
|
||||
### Details
|
||||
|
||||
**Proposed fix:**
|
||||
<!-- Type a description of your proposed fix below this line. -->
|
||||
|
||||
|
||||
**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/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,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: MOSS Discord Server
|
||||
url: https://discord.gg/casfFyh
|
||||
about: Need help with using EssentialsX? Join the MOSS Discord server for help.
|
||||
- name: EssentialsX Development Discord Server
|
||||
url: https://discord.gg/CUN7qVb
|
||||
about: Got questions or want to discuss changes before opening your PR? Join the EssentialsX Development Discord server. (Need help? Join MOSS instead.)
|
||||
@@ -0,0 +1,93 @@
|
||||
<!--
|
||||
|
||||
EssentialsX feature submission guide
|
||||
====================================
|
||||
|
||||
NOTE: Failure to fill out this template properly may result in your PR being
|
||||
delayed or ignored without warning.
|
||||
|
||||
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.
|
||||
This includes providing screenshots and a link to the original feature
|
||||
request. If there isn't an existing feature request, we strongly
|
||||
recommend opening a new feature request BEFORE opening your PR to
|
||||
implement it, as this allows us to review whether we're likely to accept
|
||||
your feature in advance, and also allows us to discuss possible
|
||||
implementations for the feature. If there is no associated feature
|
||||
request, your PR may be delayed or rejected without warning.
|
||||
|
||||
You can open a new feature request by following this link:
|
||||
https://github.com/EssentialsX/Essentials/issues/new/choose
|
||||
|
||||
2. If you are fixing a performance issue, please use the "Bug fix" PR template
|
||||
instead. The "bug fix" template is better suited to performance issues.
|
||||
|
||||
3. Include a demonstration.
|
||||
If you are adding commands, please provide screenshots and/or a video
|
||||
demonstration of the feature. Similarly, if you are adding a new API,
|
||||
please include a link to example code that takes advantage of your
|
||||
proposed API. This will aid us in reviewing PRs and speed up the process
|
||||
significantly.
|
||||
|
||||
-->
|
||||
|
||||
### Information
|
||||
|
||||
<!--
|
||||
Replace #nnnn with the number of the original issue. If this PR implements
|
||||
features from multiple issues, you should repeat the phrase "closes #nnnn"
|
||||
for each issue.
|
||||
-->
|
||||
|
||||
This PR closes #nnnn.
|
||||
|
||||
### Details
|
||||
|
||||
**Proposed feature:**
|
||||
<!-- Type a description of your proposed feature below this line. -->
|
||||
|
||||
|
||||
**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/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 --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/
|
||||
+15
-4
@@ -1,19 +1,30 @@
|
||||
# IDE files
|
||||
# Other IDE files
|
||||
*.classpath
|
||||
*.project
|
||||
*.settings/
|
||||
.idea/
|
||||
.idea/*
|
||||
*.iml
|
||||
.DS_Store
|
||||
|
||||
# Checkstyle-IDEA config
|
||||
!.idea/checkstyle-idea.xml
|
||||
|
||||
# Essentials files
|
||||
/Essentials/userdata
|
||||
/Essentials/config.yml
|
||||
/Essentials/kits.yml
|
||||
/Essentials/userdata/testplayer1.yml
|
||||
/Essentials/usermap.csv
|
||||
/Essentials/usermap.bin
|
||||
/Essentials/uuids.bin
|
||||
|
||||
# Build files
|
||||
.gradle/
|
||||
/jars/
|
||||
out/
|
||||
build/
|
||||
target/
|
||||
jars/
|
||||
out/
|
||||
*.class
|
||||
|
||||
# Run directory
|
||||
/run/
|
||||
Generated
+27
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<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>
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
# Contributing to EssentialsX
|
||||
|
||||
*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).*
|
||||
|
||||
## Submitting code changes to EssentialsX
|
||||
|
||||
If you're interested in submitting new code to EssentialsX, we accept changes via GitHub pull requests.
|
||||
|
||||
### Adding features
|
||||
|
||||
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.
|
||||
|
||||
#### Keep it focused
|
||||
|
||||
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.1</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.4</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>BaseProviders</artifactId>
|
||||
<version>2.18.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>NMSReflectionProvider</artifactId>
|
||||
<version>2.18.1</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.1</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.1</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,104 +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.*;
|
||||
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 (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 (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 (String label : labels) {
|
||||
List<PluginCommand> plugincommands = altcommands.computeIfAbsent(label.toLowerCase(Locale.ENGLISH), k -> new ArrayList<>());
|
||||
boolean found = false;
|
||||
for (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 (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,12 +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,54 +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(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(String message) {
|
||||
if (!message.isEmpty()) {
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAuthorized(String permission, IEssentials ess) {
|
||||
return !(sender instanceof Player) || getUser(ess).isAuthorized(permission);
|
||||
}
|
||||
|
||||
public String getSelfSelector() {
|
||||
return sender instanceof Player ? getPlayer().getName() : "*";
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.messaging.IMessageRecipient;
|
||||
import com.earth2me.essentials.messaging.SimpleMessageRecipient;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
|
||||
public final class Console implements IMessageRecipient {
|
||||
public static final String NAME = "Console";
|
||||
private static Console instance; // Set in essentials
|
||||
|
||||
private final IEssentials ess;
|
||||
private final IMessageRecipient messageRecipient;
|
||||
|
||||
public static Console getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void setInstance(IEssentials ess) { // Called in Essentials#onEnable()
|
||||
instance = new Console(ess);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link Console#getCommandSender()}
|
||||
*/
|
||||
@Deprecated
|
||||
public static CommandSender getCommandSender(Server server) throws Exception {
|
||||
return server.getConsoleSender();
|
||||
}
|
||||
|
||||
private Console(IEssentials ess) {
|
||||
this.ess = ess;
|
||||
this.messageRecipient = new SimpleMessageRecipient(ess, this);
|
||||
}
|
||||
|
||||
public CommandSender getCommandSender() {
|
||||
return ess.getServer().getConsoleSender();
|
||||
}
|
||||
|
||||
@Override public String getName() {
|
||||
return Console.NAME;
|
||||
}
|
||||
|
||||
@Override public String getDisplayName() {
|
||||
return Console.NAME;
|
||||
}
|
||||
|
||||
@Override public void sendMessage(String message) {
|
||||
getCommandSender().sendMessage(message);
|
||||
}
|
||||
|
||||
@Override public boolean isReachable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ================================
|
||||
* >> DELEGATE METHODS
|
||||
* ================================ */
|
||||
|
||||
@Override public MessageResponse sendMessage(IMessageRecipient recipient, String message) {
|
||||
return this.messageRecipient.sendMessage(recipient, message);
|
||||
}
|
||||
|
||||
@Override public MessageResponse onReceiveMessage(IMessageRecipient sender, String message) {
|
||||
return this.messageRecipient.onReceiveMessage(sender, message);
|
||||
}
|
||||
|
||||
@Override public IMessageRecipient getReplyRecipient() {
|
||||
return this.messageRecipient.getReplyRecipient();
|
||||
}
|
||||
|
||||
@Override public void setReplyRecipient(IMessageRecipient recipient) {
|
||||
this.messageRecipient.setReplyRecipient(recipient);
|
||||
}
|
||||
}
|
||||
@@ -1,298 +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 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 {
|
||||
Enchantment depthStrider = Enchantment.getByName("DEPTH_STRIDER");
|
||||
if (depthStrider != null) {
|
||||
ENCHANTMENTS.put("depthstrider", depthStrider);
|
||||
ALIASENCHANTMENTS.put("depth", depthStrider);
|
||||
ALIASENCHANTMENTS.put("strider", depthStrider);
|
||||
}
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
|
||||
// 1.9
|
||||
try {
|
||||
Enchantment frostWalker = Enchantment.getByName("FROST_WALKER");
|
||||
if (frostWalker != null) {
|
||||
ENCHANTMENTS.put("frostwalker", frostWalker);
|
||||
ALIASENCHANTMENTS.put("frost", frostWalker);
|
||||
ALIASENCHANTMENTS.put("walker", frostWalker);
|
||||
}
|
||||
|
||||
Enchantment mending = Enchantment.getByName("MENDING");
|
||||
if (mending != null) {
|
||||
ENCHANTMENTS.put("mending", mending);
|
||||
}
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
|
||||
// 1.11
|
||||
try {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
Enchantment sweeping = Enchantment.getByName("SWEEPING_EDGE");
|
||||
if (sweeping != null) {
|
||||
ENCHANTMENTS.put("sweepingedge", sweeping);
|
||||
ALIASENCHANTMENTS.put("sweepedge", sweeping);
|
||||
ALIASENCHANTMENTS.put("sweeping", sweeping);
|
||||
}
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
|
||||
|
||||
try { // 1.13
|
||||
Enchantment loyalty = Enchantment.getByName("LOYALTY");
|
||||
if (loyalty != null) {
|
||||
ENCHANTMENTS.put("loyalty", loyalty);
|
||||
ALIASENCHANTMENTS.put("loyal", loyalty);
|
||||
ALIASENCHANTMENTS.put("return", loyalty);
|
||||
}
|
||||
Enchantment impaling = Enchantment.getByName("IMPALING");
|
||||
if (impaling != null) {
|
||||
ENCHANTMENTS.put("impaling", impaling);
|
||||
ALIASENCHANTMENTS.put("impale", impaling);
|
||||
ALIASENCHANTMENTS.put("oceandamage", impaling);
|
||||
ALIASENCHANTMENTS.put("oceandmg", impaling);
|
||||
}
|
||||
Enchantment riptide = Enchantment.getByName("RIPTIDE");
|
||||
if (riptide != null) {
|
||||
ENCHANTMENTS.put("riptide", riptide);
|
||||
ALIASENCHANTMENTS.put("rip", riptide);
|
||||
ALIASENCHANTMENTS.put("tide", riptide);
|
||||
ALIASENCHANTMENTS.put("launch", riptide);
|
||||
}
|
||||
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 (IllegalArgumentException ignored) {}
|
||||
|
||||
|
||||
try { // 1.14
|
||||
Enchantment multishot = Enchantment.getByName("MULTISHOT");
|
||||
if (multishot != null) {
|
||||
ENCHANTMENTS.put("multishot", multishot);
|
||||
ALIASENCHANTMENTS.put("tripleshot", multishot);
|
||||
}
|
||||
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);
|
||||
}
|
||||
Enchantment piercing = Enchantment.getByName("PIERCING");
|
||||
if (piercing != null) {
|
||||
ENCHANTMENTS.put("piercing", piercing);
|
||||
}
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
|
||||
try { // 1.16
|
||||
Enchantment soulspeed = Enchantment.getByName("SOUL_SPEED");
|
||||
if (soulspeed != null) {
|
||||
ENCHANTMENTS.put("soulspeed", soulspeed);
|
||||
ALIASENCHANTMENTS.put("soilspeed", soulspeed);
|
||||
ALIASENCHANTMENTS.put("sandspeed", soulspeed);
|
||||
}
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
|
||||
try {
|
||||
Class<?> namespacedKeyClass = Class.forName("org.bukkit.NamespacedKey");
|
||||
Class<?> enchantmentClass = Class.forName("org.bukkit.enchantments.Enchantment");
|
||||
enchantmentClass.getDeclaredMethod("getByKey", namespacedKeyClass);
|
||||
isFlat = true;
|
||||
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||
isFlat = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Enchantment getByName(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();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,662 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import net.ess3.api.InvalidWorldException;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.*;
|
||||
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.*;
|
||||
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.*;
|
||||
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 final File configFile;
|
||||
protected String templateName = null;
|
||||
protected static final Charset UTF8 = StandardCharsets.UTF_8;
|
||||
private Class<?> resourceClass = EssentialsConf.class;
|
||||
private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
|
||||
private final AtomicInteger pendingDiskWrites = new AtomicInteger(0);
|
||||
private final AtomicBoolean transaction = new AtomicBoolean(false);
|
||||
|
||||
public EssentialsConf(final File configFile) {
|
||||
super();
|
||||
this.configFile = configFile.getAbsoluteFile();
|
||||
}
|
||||
|
||||
private final byte[] bytebuffer = new byte[1024];
|
||||
|
||||
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 (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, null, ex);
|
||||
} finally {
|
||||
try {
|
||||
input.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
} catch (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 (FileInputStream inputStream = new FileInputStream(configFile)) {
|
||||
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()) {
|
||||
ByteBuffer resize = ByteBuffer.allocate(buffer.capacity() + length - buffer.remaining());
|
||||
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 (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
|
||||
} catch (InvalidConfigurationException ex) {
|
||||
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);
|
||||
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 (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, tl("failedToWriteConfig", configFile.toString()), ex);
|
||||
} finally {
|
||||
try {
|
||||
if (istr != null) {
|
||||
istr.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(EssentialsConf.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
try {
|
||||
if (ostr != null) {
|
||||
ostr.close();
|
||||
}
|
||||
} catch (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 (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 {
|
||||
Future<?> future = delayedSave(configFile);
|
||||
if (future != null) {
|
||||
future.get();
|
||||
}
|
||||
} catch (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));
|
||||
}
|
||||
|
||||
|
||||
private static 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 (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, tl("failedToCreateConfig", configFile.toString()), ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(configFile)) {
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(fos, UTF8)) {
|
||||
writer.write(data);
|
||||
}
|
||||
}
|
||||
} catch (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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (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());
|
||||
Map<Enchantment, Integer> enchantments = stack.getEnchantments();
|
||||
if (!enchantments.isEmpty()) {
|
||||
Map<String, Integer> enchant = new HashMap<>();
|
||||
for (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(String path, List object) {
|
||||
set(path, new ArrayList(object));
|
||||
}
|
||||
|
||||
public void setProperty(String path, Map object) {
|
||||
set(path, new LinkedHashMap(object));
|
||||
}
|
||||
|
||||
public Object getProperty(String path) {
|
||||
return get(path);
|
||||
}
|
||||
|
||||
public void setProperty(final String path, final BigDecimal bigDecimal) {
|
||||
set(path, bigDecimal.toString());
|
||||
}
|
||||
|
||||
public void setProperty(String path, Object object) {
|
||||
set(path, object);
|
||||
}
|
||||
|
||||
public void removeProperty(String path) {
|
||||
set(path, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Object get(String path) {
|
||||
return super.get(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Object get(String path, 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);
|
||||
}
|
||||
|
||||
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 (NumberFormatException | ArithmeticException e) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean getBoolean(String path) {
|
||||
return super.getBoolean(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean getBoolean(String path, boolean def) {
|
||||
return super.getBoolean(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Boolean> getBooleanList(String path) {
|
||||
return super.getBooleanList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Byte> getByteList(String path) {
|
||||
return super.getByteList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Character> getCharacterList(String path) {
|
||||
return super.getCharacterList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ConfigurationSection getConfigurationSection(String path) {
|
||||
return super.getConfigurationSection(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized double getDouble(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(String path) {
|
||||
return super.getDoubleList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Float> getFloatList(String path) {
|
||||
return super.getFloatList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getInt(String path) {
|
||||
return super.getInt(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getInt(String path, int def) {
|
||||
return super.getInt(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Integer> getIntegerList(String path) {
|
||||
return super.getIntegerList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ItemStack getItemStack(String path, ItemStack def) {
|
||||
return super.getItemStack(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Set<String> getKeys(boolean deep) {
|
||||
return super.getKeys(deep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<?> getList(String path) {
|
||||
return super.getList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<?> getList(String path, List<?> def) {
|
||||
return super.getList(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized long getLong(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(String path) {
|
||||
return super.getLongList(path);
|
||||
}
|
||||
|
||||
public synchronized Map<String, Object> getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Map<?, ?>> getMapList(String path) {
|
||||
return super.getMapList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized OfflinePlayer getOfflinePlayer(String path) {
|
||||
return super.getOfflinePlayer(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized OfflinePlayer getOfflinePlayer(String path, OfflinePlayer def) {
|
||||
return super.getOfflinePlayer(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Short> getShortList(String path) {
|
||||
return super.getShortList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String getString(String path) {
|
||||
return super.getString(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String getString(String path, String def) {
|
||||
return super.getString(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<String> getStringList(String path) {
|
||||
return super.getStringList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Map<String, Object> getValues(boolean deep) {
|
||||
return super.getValues(deep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Vector getVector(String path) {
|
||||
return super.getVector(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Vector getVector(String path, Vector def) {
|
||||
return super.getVector(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isBoolean(String path) {
|
||||
return super.isBoolean(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isConfigurationSection(String path) {
|
||||
return super.isConfigurationSection(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isDouble(String path) {
|
||||
return super.isDouble(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isInt(String path) {
|
||||
return super.isInt(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isItemStack(String path) {
|
||||
return super.isItemStack(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isList(String path) {
|
||||
return super.isList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isLong(String path) {
|
||||
return super.isLong(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isOfflinePlayer(String path) {
|
||||
return super.isOfflinePlayer(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isSet(String path) {
|
||||
return super.isSet(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isString(String path) {
|
||||
return super.isString(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isVector(String path) {
|
||||
return super.isVector(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void set(String path, Object value) {
|
||||
super.set(path, value);
|
||||
}
|
||||
}
|
||||
@@ -1,768 +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.*;
|
||||
import java.math.BigInteger;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.*;
|
||||
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 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 void convertIgnoreList() {
|
||||
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 (File file : userFiles) {
|
||||
if (!file.isFile() || !file.getName().endsWith(".yml")) {
|
||||
continue;
|
||||
}
|
||||
final EssentialsConf config = new EssentialsConf(file);
|
||||
try {
|
||||
config.load();
|
||||
if (config.hasProperty("ignore")) {
|
||||
List<String> migratedIgnores = new ArrayList<>();
|
||||
for (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;
|
||||
}
|
||||
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 (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() {
|
||||
Kits kits = ess.getKits();
|
||||
EssentialsConf config = kits.getConfig();
|
||||
if (doneFile.getBoolean("kitsyml", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.info("Attempting to convert old kits in config.yml to new kits.yml");
|
||||
|
||||
ConfigurationSection section = ess.getSettings().getKitSection();
|
||||
if (section == null) {
|
||||
LOGGER.info("No kits found to migrate.");
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> legacyKits = ess.getSettings().getKitSection().getValues(true);
|
||||
|
||||
for (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(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();
|
||||
List<String> lines = conf.getStringList(name);
|
||||
if (lines != null && !lines.isEmpty()) {
|
||||
if (!file.createNewFile()) {
|
||||
throw new IOException("Failed to create file " + file);
|
||||
}
|
||||
PrintWriter writer = new PrintWriter(file);
|
||||
|
||||
for (String line : lines) {
|
||||
writer.println(line);
|
||||
}
|
||||
writer.close();
|
||||
}
|
||||
doneFile.setProperty("move" + name + "ToFile", true);
|
||||
doneFile.save();
|
||||
} catch (IOException e) {
|
||||
LOGGER.log(Level.SEVERE, tl("upgradingFilesError"), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeLinesFromConfig(File file, String regex, 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 (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 (Map.Entry<String, Object> entry : powertools.entrySet()) {
|
||||
if (entry.getValue() instanceof String) {
|
||||
List<String> temp = new ArrayList<>();
|
||||
temp.add((String) entry.getValue());
|
||||
powertools.put(entry.getKey(), temp);
|
||||
}
|
||||
}
|
||||
config.forceSave();
|
||||
}
|
||||
} catch (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 (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);
|
||||
}
|
||||
|
||||
Set<String> worlds = config.getConfigurationSection("home.worlds").getKeys(false);
|
||||
Location loc;
|
||||
String worldName;
|
||||
|
||||
if (worlds == null) {
|
||||
continue;
|
||||
}
|
||||
for (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 (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 (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(EssentialsConf config, String path) {
|
||||
String worldName = config.getString((path != null ? path + "." : "") + "world");
|
||||
if (worldName == null || worldName.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
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
|
||||
|
||||
MessageDigest digest = ManagedFile.getDigest();
|
||||
final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
||||
final byte[] buffer = new byte[1024];
|
||||
try (DigestInputStream dis = new DigestInputStream(bis, digest)) {
|
||||
while (dis.read(buffer) != -1) {
|
||||
}
|
||||
}
|
||||
|
||||
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 (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();
|
||||
Set<String> keys = config.getKeys(false);
|
||||
for (String group : keys) {
|
||||
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 (PrintWriter writer = new PrintWriter(configFile)) {
|
||||
new YamlStorageWriter(writer).save(spawns);
|
||||
}
|
||||
}
|
||||
} catch (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();
|
||||
Set<String> keys = config.getKeys(false);
|
||||
for (String jailName : keys) {
|
||||
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 (PrintWriter writer = new PrintWriter(configFile)) {
|
||||
new YamlStorageWriter(writer).save(jails);
|
||||
}
|
||||
}
|
||||
} catch (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;
|
||||
}
|
||||
|
||||
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 (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 (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 (InterruptedException ex) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
uuidFileConvert(ess, ignoreUFCache);
|
||||
|
||||
doneFile.setProperty("uuidFileChange", true);
|
||||
doneFile.save();
|
||||
}
|
||||
|
||||
public static void uuidFileConvert(IEssentials ess, 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 (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++;
|
||||
|
||||
String name = string.substring(0, string.length() - 4);
|
||||
EssentialsUserConf config;
|
||||
UUID uuid = null;
|
||||
try {
|
||||
uuid = UUID.fromString(name);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
File file = new File(userdir, string);
|
||||
EssentialsConf conf = new EssentialsConf(file);
|
||||
conf.load();
|
||||
conf.setProperty("lastAccountName", name);
|
||||
conf.save();
|
||||
|
||||
String uuidConf = ignoreUFCache ? "force-uuid" : "uuid";
|
||||
|
||||
String uuidString = conf.getString(uuidConf, null);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
try {
|
||||
uuid = UUID.fromString(uuidString);
|
||||
countEssCache++;
|
||||
break;
|
||||
} catch (Exception ex2) {
|
||||
if (conf.getBoolean("npc", false)) {
|
||||
uuid = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
|
||||
break;
|
||||
}
|
||||
|
||||
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 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 (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 (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 (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(String playerName, String banReason, 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 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 void repairUserMap() {
|
||||
if (doneFile.getBoolean("userMapRepaired", false)) {
|
||||
return;
|
||||
}
|
||||
ess.getLogger().info("Starting usermap repair");
|
||||
|
||||
File userdataFolder = new File(ess.getDataFolder(), "userdata");
|
||||
if (!userdataFolder.isDirectory()) {
|
||||
ess.getLogger().warning("Missing userdata folder, aborting");
|
||||
return;
|
||||
}
|
||||
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 (IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
final Matcher uuidMatcher = PATTERN_CONFIG_UUID.matcher(configData);
|
||||
if (uuidMatcher.find()) {
|
||||
try {
|
||||
uuid = UUID.fromString(uuidMatcher.group(1));
|
||||
} catch (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,63 +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 (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 (IOException ex) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Failed to migrate user: " + username, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import net.ess3.api.IEssentials;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
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 I18n instance;
|
||||
private static final String MESSAGES = "messages";
|
||||
private final transient Locale defaultLocale = Locale.getDefault();
|
||||
private transient Locale currentLocale = defaultLocale;
|
||||
private transient ResourceBundle customBundle;
|
||||
private transient ResourceBundle localeBundle;
|
||||
private final transient ResourceBundle defaultBundle;
|
||||
private transient Map<String, MessageFormat> messageFormatCache = new HashMap<>();
|
||||
private final transient IEssentials ess;
|
||||
private static final Pattern NODOUBLEMARK = Pattern.compile("''");
|
||||
private static final ResourceBundle NULL_BUNDLE = new ResourceBundle() {
|
||||
public Enumeration<String> getKeys() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Object handleGetObject(String key) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public I18n(final IEssentials ess) {
|
||||
this.ess = ess;
|
||||
defaultBundle = ResourceBundle.getBundle(MESSAGES, Locale.ENGLISH, new UTF8PropertiesControl());
|
||||
localeBundle = defaultBundle;
|
||||
customBundle = NULL_BUNDLE;
|
||||
}
|
||||
|
||||
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 (MissingResourceException ex) {
|
||||
return localeBundle.getString(string);
|
||||
}
|
||||
} catch (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 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 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 (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 (MissingResourceException ex) {
|
||||
localeBundle = NULL_BUNDLE;
|
||||
}
|
||||
|
||||
try {
|
||||
customBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new FileResClassLoader(I18n.class.getClassLoader(), ess), new UTF8PropertiesControl());
|
||||
} catch (MissingResourceException ex) {
|
||||
customBundle = NULL_BUNDLE;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (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 (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(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IOException {
|
||||
String resourceName = toResourceName(toBundleName(baseName, locale), "properties");
|
||||
ResourceBundle bundle = null;
|
||||
InputStream stream = null;
|
||||
if (reload) {
|
||||
URL url = loader.getResource(resourceName);
|
||||
if (url != null) {
|
||||
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,207 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.api.IAsyncTeleport;
|
||||
import com.earth2me.essentials.commands.IEssentialsCommand;
|
||||
import net.ess3.api.ITeleport;
|
||||
import net.ess3.api.MaxMoneyException;
|
||||
import net.ess3.api.events.AfkStatusChangeEvent;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
public interface IUser {
|
||||
boolean isAuthorized(String node);
|
||||
|
||||
boolean isAuthorized(IEssentialsCommand cmd);
|
||||
|
||||
boolean isAuthorized(IEssentialsCommand cmd, String permissionPrefix);
|
||||
|
||||
boolean isPermissionSet(String node);
|
||||
|
||||
void healCooldown() throws Exception;
|
||||
|
||||
void giveMoney(BigDecimal value) throws MaxMoneyException;
|
||||
|
||||
void giveMoney(final BigDecimal value, final CommandSource initiator) throws MaxMoneyException;
|
||||
|
||||
void payUser(final User reciever, final BigDecimal value) throws Exception;
|
||||
|
||||
void takeMoney(BigDecimal value);
|
||||
|
||||
void takeMoney(final BigDecimal value, final CommandSource initiator);
|
||||
|
||||
boolean canAfford(BigDecimal value);
|
||||
|
||||
Boolean canSpawnItem(final Material material);
|
||||
|
||||
void setLastLocation();
|
||||
|
||||
void setLogoutLocation();
|
||||
|
||||
void requestTeleport(final User player, final boolean here);
|
||||
|
||||
/**
|
||||
* Returns whether this user has an outstanding teleport request to deal with.
|
||||
*
|
||||
* @return whether there is a teleport request
|
||||
*/
|
||||
boolean hasOutstandingTeleportRequest();
|
||||
|
||||
/**
|
||||
* @deprecated This API is not asynchronous. Use {@link com.earth2me.essentials.api.IAsyncTeleport IAsyncTeleport} with {@link IUser#getAsyncTeleport()}
|
||||
*/
|
||||
@Deprecated
|
||||
ITeleport getTeleport();
|
||||
|
||||
IAsyncTeleport getAsyncTeleport();
|
||||
|
||||
BigDecimal getMoney();
|
||||
|
||||
void setMoney(final BigDecimal value) throws MaxMoneyException;
|
||||
|
||||
@Deprecated
|
||||
void setAfk(final boolean set);
|
||||
|
||||
void setAfk(final boolean set, final AfkStatusChangeEvent.Cause cause);
|
||||
|
||||
/**
|
||||
* 'Hidden' Represents when a player is hidden from others. This status includes when the player is hidden via other
|
||||
* supported plugins. Use isVanished() if you want to check if a user is vanished by Essentials.
|
||||
*
|
||||
* @return If the user is hidden or not
|
||||
*
|
||||
* @see IUser#isVanished()
|
||||
*/
|
||||
boolean isHidden();
|
||||
|
||||
void setHidden(boolean vanish);
|
||||
|
||||
boolean isGodModeEnabled();
|
||||
|
||||
String getGroup();
|
||||
|
||||
boolean inGroup(final String group);
|
||||
|
||||
boolean canBuild();
|
||||
|
||||
long getTeleportRequestTime();
|
||||
|
||||
void enableInvulnerabilityAfterTeleport();
|
||||
|
||||
void resetInvulnerabilityAfterTeleport();
|
||||
|
||||
boolean hasInvulnerabilityAfterTeleport();
|
||||
|
||||
/**
|
||||
* 'Vanished' Represents when a player is hidden from others by Essentials. This status does NOT include when the
|
||||
* player is hidden via other plugins. Use isHidden() if you want to check if a user is vanished by any supported
|
||||
* plugin.
|
||||
*
|
||||
* @return If the user is vanished or not
|
||||
*
|
||||
* @see IUser#isHidden()
|
||||
*/
|
||||
boolean isVanished();
|
||||
|
||||
void setVanished(boolean vanish);
|
||||
|
||||
boolean isIgnoreExempt();
|
||||
|
||||
void sendMessage(String message);
|
||||
|
||||
/*
|
||||
* UserData
|
||||
*/
|
||||
Location getHome(String name) throws Exception;
|
||||
|
||||
Location getHome(Location loc) throws Exception;
|
||||
|
||||
List<String> getHomes();
|
||||
|
||||
void setHome(String name, Location loc);
|
||||
|
||||
void delHome(String name) throws Exception;
|
||||
|
||||
boolean hasHome();
|
||||
|
||||
Location getLastLocation();
|
||||
|
||||
Location getLogoutLocation();
|
||||
|
||||
long getLastTeleportTimestamp();
|
||||
|
||||
void setLastTeleportTimestamp(long time);
|
||||
|
||||
String getJail();
|
||||
|
||||
void setJail(String jail);
|
||||
|
||||
List<String> getMails();
|
||||
|
||||
void addMail(String mail);
|
||||
|
||||
boolean isAfk();
|
||||
|
||||
void setIgnoreMsg(boolean ignoreMsg);
|
||||
|
||||
boolean isIgnoreMsg();
|
||||
|
||||
void setConfigProperty(String node, Object object);
|
||||
|
||||
Set<String> getConfigKeys();
|
||||
|
||||
Map<String, Object> getConfigMap();
|
||||
|
||||
Map<String, Object> getConfigMap(String node);
|
||||
|
||||
Map<Pattern, Long> getCommandCooldowns();
|
||||
|
||||
Date getCommandCooldownExpiry(String label);
|
||||
|
||||
void addCommandCooldown(Pattern pattern, Date expiresAt, boolean save);
|
||||
|
||||
boolean clearCommandCooldown(Pattern pattern);
|
||||
|
||||
/*
|
||||
* PlayerExtension
|
||||
*/
|
||||
Player getBase();
|
||||
|
||||
CommandSource getSource();
|
||||
|
||||
String getName();
|
||||
|
||||
String getDisplayName();
|
||||
|
||||
String getAfkMessage();
|
||||
|
||||
void setAfkMessage(final String message);
|
||||
|
||||
long getAfkSince();
|
||||
|
||||
boolean isAcceptingPay();
|
||||
|
||||
void setAcceptingPay(boolean acceptingPay);
|
||||
|
||||
boolean isPromptingPayConfirm();
|
||||
|
||||
void setPromptingPayConfirm(boolean prompt);
|
||||
|
||||
boolean isPromptingClearConfirm();
|
||||
|
||||
void setPromptingClearConfirm(boolean prompt);
|
||||
|
||||
boolean isLastMessageReplyRecipient();
|
||||
|
||||
void setLastMessageReplyRecipient(boolean enabled);
|
||||
|
||||
Map<User, BigDecimal> getConfirmingPayments();
|
||||
}
|
||||
@@ -1,298 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.storage.AsyncStorageObjectHolder;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.IUser;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockDamageEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||
import org.bukkit.event.player.*;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Jails extends AsyncStorageObjectHolder<com.earth2me.essentials.settings.Jails> implements net.ess3.api.IJails {
|
||||
private static final transient Logger LOGGER = Bukkit.getLogger();
|
||||
private static transient boolean enabled = false;
|
||||
|
||||
public Jails(final IEssentials ess) {
|
||||
super(ess, com.earth2me.essentials.settings.Jails.class);
|
||||
reloadConfig();
|
||||
}
|
||||
|
||||
private void registerListeners() {
|
||||
enabled = true;
|
||||
final PluginManager pluginManager = ess.getServer().getPluginManager();
|
||||
final JailListener blockListener = new JailListener();
|
||||
pluginManager.registerEvents(blockListener, ess);
|
||||
if (ess.getSettings().isDebug()) {
|
||||
LOGGER.log(Level.INFO, "Registering Jail listener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getStorageFile() {
|
||||
return new File(ess.getDataFolder(), "jail.yml");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishRead() {
|
||||
checkRegister();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishWrite() {
|
||||
checkRegister();
|
||||
}
|
||||
|
||||
public void resetListener() {
|
||||
enabled = false;
|
||||
checkRegister();
|
||||
}
|
||||
|
||||
private void checkRegister() {
|
||||
if (!enabled && getCount() > 0) {
|
||||
registerListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getJail(final String jailName) throws Exception {
|
||||
acquireReadLock();
|
||||
try {
|
||||
if (getData().getJails() == null || jailName == null || !getData().getJails().containsKey(jailName.toLowerCase(Locale.ENGLISH))) {
|
||||
throw new Exception(tl("jailNotExist"));
|
||||
}
|
||||
Location loc = getData().getJails().get(jailName.toLowerCase(Locale.ENGLISH));
|
||||
if (loc == null || loc.getWorld() == null) {
|
||||
throw new Exception(tl("jailNotExist"));
|
||||
}
|
||||
return loc;
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getList() throws Exception {
|
||||
acquireReadLock();
|
||||
try {
|
||||
if (getData().getJails() == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return new ArrayList<>(getData().getJails().keySet());
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeJail(final String jail) throws Exception {
|
||||
acquireWriteLock();
|
||||
try {
|
||||
if (getData().getJails() == null) {
|
||||
return;
|
||||
}
|
||||
getData().getJails().remove(jail.toLowerCase(Locale.ENGLISH));
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method does not use asynchronous teleportation. Use {@link Jails#sendToJail(IUser, String, CompletableFuture)}
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void sendToJail(final IUser user, final String jail) throws Exception {
|
||||
acquireReadLock();
|
||||
try {
|
||||
if (user.getBase().isOnline()) {
|
||||
Location loc = getJail(jail);
|
||||
user.getTeleport().now(loc, false, TeleportCause.COMMAND);
|
||||
}
|
||||
user.setJail(jail);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToJail(IUser user, String jail, CompletableFuture<Boolean> future) throws Exception {
|
||||
acquireReadLock();
|
||||
try {
|
||||
if (user.getBase().isOnline()) {
|
||||
Location loc = getJail(jail);
|
||||
user.getAsyncTeleport().now(loc, false, TeleportCause.COMMAND, future);
|
||||
future.thenAccept(success -> {
|
||||
user.setJail(jail);
|
||||
});
|
||||
return;
|
||||
}
|
||||
user.setJail(jail);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setJail(final String jailName, final Location loc) throws Exception {
|
||||
acquireWriteLock();
|
||||
try {
|
||||
if (getData().getJails() == null) {
|
||||
getData().setJails(new HashMap<>());
|
||||
}
|
||||
getData().getJails().put(jailName.toLowerCase(Locale.ENGLISH), loc);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
try {
|
||||
return getList().size();
|
||||
} catch (Exception ex) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class JailListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onJailBlockBreak(final BlockBreakEvent event) {
|
||||
final User user = ess.getUser(event.getPlayer());
|
||||
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-break")) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onJailBlockPlace(final BlockPlaceEvent event) {
|
||||
final User user = ess.getUser(event.getPlayer());
|
||||
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-place")) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onJailBlockDamage(final BlockDamageEvent event) {
|
||||
final User user = ess.getUser(event.getPlayer());
|
||||
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-block-damage")) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onJailEntityDamageByEntity(final EntityDamageByEntityEvent event) {
|
||||
if (event.getCause() != DamageCause.ENTITY_ATTACK || event.getEntity().getType() != EntityType.PLAYER) {
|
||||
return;
|
||||
}
|
||||
final Entity damager = event.getDamager();
|
||||
if (damager.getType() == EntityType.PLAYER) {
|
||||
final User user = ess.getUser((Player) damager);
|
||||
if (user != null && user.isJailed()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onJailPlayerInteract(final PlayerInteractEvent event) {
|
||||
final User user = ess.getUser(event.getPlayer());
|
||||
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-interact")) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onJailPlayerGameModeChange(PlayerGameModeChangeEvent event) {
|
||||
final User user = ess.getUser(event.getPlayer());
|
||||
if (user.isJailed()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onJailPlayerRespawn(final PlayerRespawnEvent event) {
|
||||
final User user = ess.getUser(event.getPlayer());
|
||||
if (!user.isJailed() || user.getJail() == null || user.getJail().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
event.setRespawnLocation(getJail(user.getJail()));
|
||||
} catch (Exception ex) {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()), ex);
|
||||
} else {
|
||||
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onJailPlayerTeleport(final PlayerTeleportEvent event) {
|
||||
final User user = ess.getUser(event.getPlayer());
|
||||
if (!user.isJailed() || user.getJail() == null || user.getJail().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
event.setTo(getJail(user.getJail()));
|
||||
} catch (Exception ex) {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()), ex);
|
||||
} else {
|
||||
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()));
|
||||
}
|
||||
}
|
||||
user.sendMessage(tl("jailMessage"));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onJailPlayerJoin(final PlayerJoinEvent event) {
|
||||
final User user = ess.getUser(event.getPlayer());
|
||||
final long currentTime = System.currentTimeMillis();
|
||||
user.checkJailTimeout(currentTime);
|
||||
if (!user.isJailed() || user.getJail() == null || user.getJail().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||
future.exceptionally(ex -> {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()), ex);
|
||||
} else {
|
||||
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()));
|
||||
}
|
||||
return false;
|
||||
});
|
||||
future.thenAccept(success -> user.sendMessage(tl("jailMessage")));
|
||||
|
||||
try {
|
||||
sendToJail(user, user.getJail(), future);
|
||||
} catch (Exception ex) {
|
||||
future.completeExceptionally(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 (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(String name) {
|
||||
if (config.isConfigurationSection("kits")) {
|
||||
final ConfigurationSection section = config.getConfigurationSection("kits");
|
||||
if (section != null) {
|
||||
for (String kitName : section.getKeys(false)) {
|
||||
if (kitName.equalsIgnoreCase(name)) {
|
||||
return kitName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addKit(String name, List<String> lines, 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(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 (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);
|
||||
BigDecimal costPrice = new Trade("kit-" + kitItem.toLowerCase(Locale.ENGLISH), ess).getCommandCost(user);
|
||||
if (costPrice.signum() > 0) {
|
||||
cost = tl("kitCost", NumberUtil.displayCurrency(costPrice, ess));
|
||||
}
|
||||
|
||||
Kit kit = new Kit(kitItem, ess);
|
||||
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 (Exception ex) {
|
||||
throw new Exception(tl("kitError"), ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class 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 (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) {
|
||||
Server server = ess.getServer();
|
||||
int playerHidden = 0;
|
||||
int hiddenCount = 0;
|
||||
for (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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
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 (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()));
|
||||
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 (String configGroup : configGroups) {
|
||||
if (configGroup.equalsIgnoreCase(groupName)) {
|
||||
String[] groupValues = ess.getSettings().getListGroupConfig().get(configGroup).toString().trim().split(" ");
|
||||
for (String groupValue : groupValues) {
|
||||
groupValue = groupValue.toLowerCase(Locale.ENGLISH);
|
||||
if (groupValue.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
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"));
|
||||
}
|
||||
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,208 +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 final IEssentials essentials;
|
||||
private final EssentialsConf config;
|
||||
private final ConcurrentLinkedQueue<Location> cachedLocations = new ConcurrentLinkedQueue<>();
|
||||
private static final Random RANDOM = new Random();
|
||||
private static final int HIGHEST_BLOCK_Y_OFFSET = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_R01) ? 1 : 0;
|
||||
|
||||
public RandomTeleport(final IEssentials essentials) {
|
||||
this.essentials = essentials;
|
||||
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 {
|
||||
Location center = config.getLocation("center", essentials.getServer());
|
||||
if (center != null) {
|
||||
return center;
|
||||
}
|
||||
} catch (InvalidWorldException ignored) {
|
||||
}
|
||||
Location center = essentials.getServer().getWorlds().get(0).getWorldBorder().getCenter();
|
||||
center.setY(center.getWorld().getHighestBlockYAt(center) + 1);
|
||||
setCenter(center);
|
||||
return center;
|
||||
}
|
||||
|
||||
public void setCenter(Location center) {
|
||||
config.setProperty("center", center);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public double getMinRange() {
|
||||
return config.getDouble("min-range", 0d);
|
||||
}
|
||||
|
||||
public void setMinRange(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(double maxRange) {
|
||||
config.setProperty("max-range", maxRange);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public Set<Biome> getExcludedBiomes() {
|
||||
List<String> biomeNames = config.getStringList("excluded-biomes");
|
||||
Set<Biome> excludedBiomes = new HashSet<>();
|
||||
for (String biomeName : biomeNames) {
|
||||
try {
|
||||
excludedBiomes.add(Biome.valueOf(biomeName.toUpperCase()));
|
||||
} catch (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(Location center, double minRange, double maxRange) {
|
||||
int findAttempts = this.getFindAttempts();
|
||||
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);
|
||||
}
|
||||
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(Location center, double minRange, 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(int attempts, Location center, double minRange, double maxRange) {
|
||||
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(Location center, double minRange, double maxRange) {
|
||||
CompletableFuture<Location> future = new CompletableFuture<>();
|
||||
// Find an equally distributed offset by randomly rotating a point inside a rectangle about the origin
|
||||
double rectX = RANDOM.nextDouble() * (maxRange - minRange) + minRange;
|
||||
double rectZ = RANDOM.nextDouble() * (maxRange + minRange) - minRange;
|
||||
double offsetX, offsetZ;
|
||||
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;
|
||||
}
|
||||
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(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(Location location) {
|
||||
return location.getBlockY() > 0 && !this.getExcludedBiomes().contains(location.getBlock().getBiome());
|
||||
}
|
||||
}
|
||||
@@ -1,52 +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,404 +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(IUser user, IEssentials ess) {
|
||||
this.teleportOwner = user;
|
||||
this.ess = ess;
|
||||
tpType = TeleportType.NORMAL;
|
||||
}
|
||||
|
||||
public enum TeleportType {
|
||||
TPA,
|
||||
BACK,
|
||||
NORMAL
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void cooldown(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;
|
||||
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) {
|
||||
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(Location loc, boolean cooldown, TeleportCause cause) throws Exception {
|
||||
if (cooldown) {
|
||||
cooldown(false);
|
||||
}
|
||||
final ITarget target = new LocationTarget(loc);
|
||||
now(teleportOwner, target, cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void now(Player entity, boolean cooldown, 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(IUser teleportee, ITarget target, TeleportCause cause) throws Exception {
|
||||
cancel(false);
|
||||
Location loc = target.getLocation();
|
||||
|
||||
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(Location loc, Trade chargeFor) throws Exception {
|
||||
teleport(loc, chargeFor, TeleportCause.PLUGIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void teleport(Location loc, Trade chargeFor, TeleportCause cause) throws Exception {
|
||||
teleport(teleportOwner, new LocationTarget(loc), chargeFor, cause);
|
||||
}
|
||||
|
||||
//This is used when teleporting to a player
|
||||
@Override
|
||||
@Deprecated
|
||||
public void teleport(Player entity, Trade chargeFor, TeleportCause cause) throws Exception {
|
||||
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(IUser teleportee, Location loc, Trade chargeFor, TeleportCause cause) throws Exception {
|
||||
teleport(teleportee, new LocationTarget(loc), chargeFor, cause);
|
||||
}
|
||||
|
||||
//This is used on /tphere
|
||||
@Override
|
||||
@Deprecated
|
||||
public void teleportPlayer(IUser teleportee, Player entity, Trade chargeFor, TeleportCause cause) throws Exception {
|
||||
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(IUser teleportee, ITarget target, Trade chargeFor, TeleportCause cause) throws Exception {
|
||||
double delay = ess.getSettings().getTeleportDelay();
|
||||
|
||||
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(IUser teleporter, IUser teleportee, ITarget target, Trade chargeFor, TeleportCause cause) throws Exception {
|
||||
double delay = ess.getSettings().getTeleportDelay();
|
||||
|
||||
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, TeleportCause cause) throws Exception {
|
||||
double delay = ess.getSettings().getTeleportDelay();
|
||||
|
||||
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(IUser teleportee, TeleportCause cause) throws Exception {
|
||||
final Player player = teleportee.getBase();
|
||||
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(IUser teleportee, String warp, Trade chargeFor, TeleportCause cause) throws Exception {
|
||||
UserWarpEvent event = new UserWarpEvent(teleportee, warp, chargeFor);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
warp = event.getWarp();
|
||||
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(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(IUser teleporter, 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(TeleportType tpType) {
|
||||
this.tpType = tpType;
|
||||
}
|
||||
|
||||
//If we need to cancelTimer a pending teleportPlayer call this method
|
||||
@Deprecated
|
||||
private void cancel(boolean notifyUser) {
|
||||
if (timedTeleport != null) {
|
||||
timedTeleport.cancelTimer(notifyUser);
|
||||
timedTeleport = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private void initTimer(long delay, IUser teleportUser, ITarget target, Trade chargeFor, TeleportCause cause, boolean respawn) {
|
||||
timedTeleport = new TimedTeleport(teleportOwner, ess, this, delay, teleportUser, target, chargeFor, cause, respawn);
|
||||
}
|
||||
}
|
||||
@@ -1,139 +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 int timer_task;
|
||||
private final long timer_started; // time this task was initiated
|
||||
private final long timer_delay; // how long to delay the teleportPlayer
|
||||
private double timer_health;
|
||||
// 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;
|
||||
|
||||
TimedTeleport(IUser user, IEssentials ess, Teleport teleport, long delay, IUser teleportUser, ITarget target, Trade chargeFor, TeleportCause cause, 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 (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 (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(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,151 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
public class UUIDMap {
|
||||
private final transient net.ess3.api.IEssentials ess;
|
||||
private final File userList;
|
||||
private final transient Pattern splitPattern = Pattern.compile(",");
|
||||
|
||||
private static boolean pendingWrite;
|
||||
private static final ScheduledExecutorService writeScheduler = Executors.newScheduledThreadPool(1);
|
||||
private final Runnable writeTaskRunnable;
|
||||
|
||||
private static boolean loading = false;
|
||||
|
||||
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 (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 (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 (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 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 (Map.Entry<String, UUID> entry : names.entrySet()) {
|
||||
bWriter.write(entry.getKey() + "," + entry.getValue().toString());
|
||||
bWriter.newLine();
|
||||
}
|
||||
|
||||
bWriter.close();
|
||||
Files.move(configFile, endFile);
|
||||
} catch (IOException ex) {
|
||||
try {
|
||||
if (configFile != null && configFile.exists()) {
|
||||
Files.move(configFile, new File(endFile.getParentFile(), "usermap.bak.csv"));
|
||||
}
|
||||
} catch (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.*;
|
||||
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 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 static boolean legacy = false;
|
||||
|
||||
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);
|
||||
CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder();
|
||||
int maxCount = ess.getSettings().getMaxUserCacheCount();
|
||||
try {
|
||||
cacheBuilder.maximumSize(maxCount);
|
||||
} catch (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 (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 (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.");
|
||||
User user = new User(new OfflinePlayer(sanitizedName, ess.getServer()), ess);
|
||||
trackUUID(user.getBase().getUniqueId(), user.getName(), true);
|
||||
return user;
|
||||
}
|
||||
return null;
|
||||
} catch (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 (ExecutionException | UncheckedExecutionException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void trackUUID(final UUID uuid, final String name, 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 {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
// class UserMapRemovalListener implements RemovalListener
|
||||
// {
|
||||
// @Override
|
||||
// public void onRemoval(final RemovalNotification notification)
|
||||
// {
|
||||
// Object value = notification.getValue();
|
||||
// if (value != null)
|
||||
// {
|
||||
// ((User)value).cleanup();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
private final Pattern validUserPattern = Pattern.compile("^[a-zA-Z0-9_]{2,16}$");
|
||||
|
||||
@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;
|
||||
}
|
||||
org.bukkit.OfflinePlayer offlinePlayer = ess.getServer().getOfflinePlayer(name);
|
||||
if (offlinePlayer == null) {
|
||||
return null;
|
||||
}
|
||||
UUID uuid;
|
||||
try {
|
||||
uuid = offlinePlayer.getUniqueId();
|
||||
} catch (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 static Method getLegacy;
|
||||
|
||||
private User legacyCacheGet(UUID uuid) {
|
||||
if (getLegacy == null) {
|
||||
Class<?> usersClass = users.getClass();
|
||||
for (Method m : usersClass.getDeclaredMethods()) {
|
||||
if (m.getName().equals("get")) {
|
||||
getLegacy = m;
|
||||
getLegacy.setAccessible(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
return (User) getLegacy.invoke(users, uuid.toString());
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void legacyMaximumSize(CacheBuilder builder, int maxCount) {
|
||||
try {
|
||||
Method maxSizeLegacy = builder.getClass().getDeclaredMethod("maximumSize", Integer.TYPE);
|
||||
maxSizeLegacy.setAccessible(true);
|
||||
maxSizeLegacy.invoke(builder, maxCount);
|
||||
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Cache<String, User> legacyBuild(CacheBuilder builder) {
|
||||
Method build = null;
|
||||
for (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 (IllegalAccessException | InvocationTargetException e) {
|
||||
legacyUsers = null;
|
||||
}
|
||||
return legacyUsers;
|
||||
}
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.commands.WarpNotFoundException;
|
||||
import com.earth2me.essentials.utils.StringUtil;
|
||||
import net.ess3.api.InvalidNameException;
|
||||
import net.ess3.api.InvalidWorldException;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Warps implements IConf, net.ess3.api.IWarps {
|
||||
private static final Logger logger = Logger.getLogger("Essentials");
|
||||
private final Map<StringIgnoreCase, EssentialsConf> warpPoints = new HashMap<>();
|
||||
private final File warpsFolder;
|
||||
private final Server server;
|
||||
|
||||
public Warps(Server server, File dataFolder) {
|
||||
this.server = server;
|
||||
warpsFolder = new File(dataFolder, "warps");
|
||||
if (!warpsFolder.exists()) {
|
||||
warpsFolder.mkdirs();
|
||||
}
|
||||
reloadConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return warpPoints.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getList() {
|
||||
final List<String> keys = new ArrayList<>();
|
||||
for (StringIgnoreCase stringIgnoreCase : warpPoints.keySet()) {
|
||||
keys.add(stringIgnoreCase.getString());
|
||||
}
|
||||
keys.sort(String.CASE_INSENSITIVE_ORDER);
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getWarp(String warp) throws WarpNotFoundException, InvalidWorldException {
|
||||
EssentialsConf conf = warpPoints.get(new StringIgnoreCase(warp));
|
||||
if (conf == null) {
|
||||
throw new WarpNotFoundException();
|
||||
}
|
||||
return conf.getLocation(null, server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWarp(String name, Location loc) throws Exception {
|
||||
setWarp(null, name, loc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWarp(IUser user, String name, Location loc) throws Exception {
|
||||
String filename = StringUtil.sanitizeFileName(name);
|
||||
EssentialsConf conf = warpPoints.get(new StringIgnoreCase(name));
|
||||
if (conf == null) {
|
||||
File confFile = new File(warpsFolder, filename + ".yml");
|
||||
if (confFile.exists()) {
|
||||
throw new Exception(tl("similarWarpExist"));
|
||||
}
|
||||
conf = new EssentialsConf(confFile);
|
||||
warpPoints.put(new StringIgnoreCase(name), conf);
|
||||
}
|
||||
conf.setProperty(null, loc);
|
||||
conf.setProperty("name", name);
|
||||
if (user != null) conf.setProperty("lastowner", user.getBase().getUniqueId().toString());
|
||||
try {
|
||||
conf.saveWithError();
|
||||
} catch (IOException ex) {
|
||||
throw new IOException(tl("invalidWarpName"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getLastOwner(String warp) throws WarpNotFoundException {
|
||||
EssentialsConf conf = warpPoints.get(new StringIgnoreCase(warp));
|
||||
if (conf == null) {
|
||||
throw new WarpNotFoundException();
|
||||
}
|
||||
UUID uuid = null;
|
||||
try {
|
||||
uuid = UUID.fromString(conf.getString("lastowner"));
|
||||
}
|
||||
catch (Exception ignored) {}
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeWarp(String name) throws Exception {
|
||||
EssentialsConf conf = warpPoints.get(new StringIgnoreCase(name));
|
||||
if (conf == null) {
|
||||
throw new Exception(tl("warpNotExist"));
|
||||
}
|
||||
if (!conf.getFile().delete()) {
|
||||
throw new Exception(tl("warpDeleteError"));
|
||||
}
|
||||
warpPoints.remove(new StringIgnoreCase(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void reloadConfig() {
|
||||
warpPoints.clear();
|
||||
File[] listOfFiles = warpsFolder.listFiles();
|
||||
if (listOfFiles.length >= 1) {
|
||||
for (File listOfFile : listOfFiles) {
|
||||
String filename = listOfFile.getName();
|
||||
if (listOfFile.isFile() && filename.endsWith(".yml")) {
|
||||
try {
|
||||
EssentialsConf conf = new EssentialsConf(listOfFile);
|
||||
conf.load();
|
||||
String name = conf.getString("name");
|
||||
if (name != null) {
|
||||
warpPoints.put(new StringIgnoreCase(name), conf);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.WARNING, tl("loadWarpError", filename), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//This is here for future 3.x api support. Not implemented here becasue storage is handled differently
|
||||
@Override
|
||||
public File getWarpFile(String name) throws InvalidNameException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return getList().size();
|
||||
}
|
||||
|
||||
private static class StringIgnoreCase {
|
||||
private final String string;
|
||||
|
||||
public StringIgnoreCase(String string) {
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getString().toLowerCase(Locale.ENGLISH).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof StringIgnoreCase) {
|
||||
return getString().equalsIgnoreCase(((StringIgnoreCase) o).getString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getString() {
|
||||
return string;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
package com.earth2me.essentials.api;
|
||||
|
||||
import com.earth2me.essentials.Trade;
|
||||
import net.ess3.api.IUser;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
|
||||
public interface IAsyncTeleport {
|
||||
|
||||
/**
|
||||
* Used to skip teleportPlayer delay when teleporting someone to a location or player.
|
||||
*
|
||||
* @param loc - Where should the player end up
|
||||
* @param cooldown - If cooldown should be enforced
|
||||
* @param cause - The reported teleportPlayer cause
|
||||
* @param future - Future which is completed with the success status of the execution
|
||||
*/
|
||||
void now(Location loc, boolean cooldown, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
|
||||
|
||||
/**
|
||||
* Used to skip teleportPlayer delay when teleporting someone to a location or player.
|
||||
*
|
||||
* @param entity - Where should the player end up
|
||||
* @param cooldown - If cooldown should be enforced
|
||||
* @param cause - The reported teleportPlayer cause
|
||||
* @param future - Future which is completed with the success status of the execution
|
||||
*/
|
||||
void now(Player entity, boolean cooldown, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
|
||||
|
||||
/**
|
||||
* Teleport a player to a specific location
|
||||
*
|
||||
* @param loc - Where should the player end up
|
||||
* @param chargeFor - What the user will be charged if teleportPlayer is successful
|
||||
* @param cause - The reported teleportPlayer cause.
|
||||
* @param future - Future which is completed with the success status of the execution
|
||||
*/
|
||||
void teleport(Location loc, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
|
||||
|
||||
/**
|
||||
* Teleport a player to a specific player
|
||||
*
|
||||
* @param entity - Where should the player end up
|
||||
* @param chargeFor - What the user will be charged if teleportPlayer is successful
|
||||
* @param cause - The reported teleportPlayer cause
|
||||
* @param future - Future which is completed with the success status of the execution
|
||||
*/
|
||||
void teleport(Player entity, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
|
||||
|
||||
/**
|
||||
* Teleport a player to a specific location
|
||||
*
|
||||
* @param otherUser - Which user will be teleported
|
||||
* @param loc - Where should the player end up
|
||||
* @param chargeFor - What the user will be charged if teleportPlayer is successful
|
||||
* @param cause - The reported teleportPlayer cause
|
||||
* @param future - Future which is completed with the success status of the execution
|
||||
*/
|
||||
void teleportPlayer(IUser otherUser, Location loc, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
|
||||
|
||||
/**
|
||||
* Teleport a player to a specific player
|
||||
*
|
||||
* @param otherUser - Which user will be teleported
|
||||
* @param entity - Where should the player end up
|
||||
* @param chargeFor - What the user will be charged if teleportPlayer is successful
|
||||
* @param cause - The reported teleportPlayer cause
|
||||
* @param future - Future which is completed with the success status of the execution
|
||||
*/
|
||||
void teleportPlayer(IUser otherUser, Player entity, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
|
||||
|
||||
/**
|
||||
* Teleport wrapper used to handle tp fallback on /jail and /home
|
||||
*
|
||||
* @param chargeFor - What the user will be charged if teleportPlayer is successful
|
||||
* @param cause - The reported teleportPlayer cause
|
||||
* @param future - Future which is completed with the success status of the execution
|
||||
*/
|
||||
void respawn(final Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
|
||||
|
||||
/**
|
||||
* Teleport wrapper used to handle /warp teleports
|
||||
*
|
||||
* @param otherUser - Which user will be teleported
|
||||
* @param warp - The name of the warp the user will be teleported too.
|
||||
* @param chargeFor - What the user will be charged if teleportPlayer is successful
|
||||
* @param cause - The reported teleportPlayer cause
|
||||
* @param future - Future which is completed with the success status of the execution
|
||||
*/
|
||||
void warp(IUser otherUser, String warp, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
|
||||
|
||||
/**
|
||||
* Teleport wrapper used to handle /back teleports
|
||||
*
|
||||
* @param chargeFor - What the user will be charged if teleportPlayer is successful
|
||||
* @param future - Future which is completed with the success status of the execution
|
||||
*/
|
||||
void back(Trade chargeFor, CompletableFuture<Boolean> future);
|
||||
|
||||
/**
|
||||
* Teleport wrapper used to handle /back teleports that
|
||||
* are executed by a different player with this
|
||||
* instance of teleport as a target.
|
||||
*
|
||||
* @param teleporter - The user performing the /back command.
|
||||
* This value may be {@code null} to indicate console.
|
||||
* @param chargeFor - What the {@code teleporter} will be charged if teleportPlayer is successful
|
||||
* @param future - Future which is completed with the success status of the execution
|
||||
*/
|
||||
void back(IUser teleporter, Trade chargeFor, CompletableFuture<Boolean> future);
|
||||
|
||||
/**
|
||||
* Teleport wrapper used to handle throwing user home after a jail sentence
|
||||
*
|
||||
* @param future - Future which is completed with the success status of the execution
|
||||
*/
|
||||
void back(CompletableFuture<Boolean> future);
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.earth2me.essentials.api;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
public interface II18n {
|
||||
/**
|
||||
* Gets the current locale setting
|
||||
*
|
||||
* @return the current locale, if not set it will return the default locale
|
||||
*/
|
||||
Locale getCurrentLocale();
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.earth2me.essentials.api;
|
||||
|
||||
|
||||
public interface IReload {
|
||||
void onReload();
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.earth2me.essentials.api;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class InvalidWorldException extends Exception {
|
||||
private final String world;
|
||||
|
||||
public InvalidWorldException(final String world) {
|
||||
super(tl("invalidWorld"));
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public String getWorld() {
|
||||
return this.world;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.earth2me.essentials.api;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class UserDoesNotExistException extends Exception {
|
||||
public UserDoesNotExistException(String name) {
|
||||
super(tl("userDoesNotExist", name));
|
||||
}
|
||||
|
||||
public UserDoesNotExistException(UUID uuid) {
|
||||
super(tl("uuidDoesNotExist", uuid.toString()));
|
||||
}
|
||||
}
|
||||
@@ -1,111 +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.AfkStatusChangeEvent;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Commandafk extends EssentialsCommand {
|
||||
public Commandafk() {
|
||||
super("afk");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Server server, User user, String commandLabel, String[] args) throws Exception {
|
||||
if (args.length > 0 && user.isAuthorized("essentials.afk.others")) {
|
||||
User afkUser = user; // if no player found, but message specified, set command executor to target user
|
||||
String message;
|
||||
try {
|
||||
afkUser = getPlayer(server, user, args, 0);
|
||||
message = args.length > 1 ? getFinalArg(args, 1) : null;
|
||||
} catch (PlayerNotFoundException e) {
|
||||
message = getFinalArg(args, 0);
|
||||
}
|
||||
toggleAfk(user, afkUser, message);
|
||||
} else {
|
||||
String message = args.length > 0 ? getFinalArg(args, 0) : null;
|
||||
toggleAfk(user, user, message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
|
||||
if (args.length > 0) {
|
||||
User afkUser = getPlayer(server, args, 0, true, false);
|
||||
String message = args.length > 1 ? getFinalArg(args, 1) : null;
|
||||
toggleAfk(null, afkUser, message);
|
||||
} else {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleAfk(User sender, User user, String message) throws Exception {
|
||||
if (message != null && sender != null) {
|
||||
if (sender.isMuted()) {
|
||||
String dateDiff = sender.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(sender.getMuteTimeout()) : null;
|
||||
if (dateDiff == null) {
|
||||
throw new Exception(sender.hasMuteReason() ? tl("voiceSilencedReason", sender.getMuteReason()) : tl("voiceSilenced"));
|
||||
}
|
||||
throw new Exception(sender.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, sender.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
|
||||
}
|
||||
if (!sender.isAuthorized("essentials.afk.message")) {
|
||||
throw new Exception(tl("noPermToAFKMessage"));
|
||||
}
|
||||
}
|
||||
user.setDisplayNick();
|
||||
String msg = "";
|
||||
String selfmsg = "";
|
||||
if (!user.toggleAfk(AfkStatusChangeEvent.Cause.COMMAND)) {
|
||||
if (!user.isHidden()) {
|
||||
msg = tl("userIsNotAway", user.getDisplayName());
|
||||
selfmsg = tl("userIsNotAwaySelf", user.getDisplayName());
|
||||
}
|
||||
user.updateActivity(false, AfkStatusChangeEvent.Cause.COMMAND);
|
||||
} else {
|
||||
if (!user.isHidden()) {
|
||||
if (message != null) {
|
||||
msg = tl("userIsAwayWithMessage", user.getDisplayName(), message);
|
||||
selfmsg = tl("userIsAwaySelfWithMessage", user.getDisplayName(), message);
|
||||
} else {
|
||||
msg = tl("userIsAway", user.getDisplayName());
|
||||
selfmsg = tl("userIsAwaySelf", user.getDisplayName());
|
||||
}
|
||||
}
|
||||
user.setAfkMessage(message);
|
||||
}
|
||||
if (!msg.isEmpty() && ess.getSettings().broadcastAfkMessage()) {
|
||||
// exclude user from receiving general AFK announcement in favor of personal message
|
||||
ess.broadcastMessage(user, msg, u -> u == user);
|
||||
}
|
||||
if (!selfmsg.isEmpty()) {
|
||||
user.sendMessage(selfmsg);
|
||||
}
|
||||
user.setDisplayNick(); // Set this again after toggling
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
|
||||
if (args.length == 1 && user.isAuthorized("essentials.afk.others")) {
|
||||
return getPlayers(server, user);
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return getPlayers(server, sender);
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,173 +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.*;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Commandbalancetop extends EssentialsCommand {
|
||||
public Commandbalancetop() {
|
||||
super("balancetop");
|
||||
}
|
||||
|
||||
private static final int CACHETIME = 2 * 60 * 1000;
|
||||
public static final int MINUSERS = 50;
|
||||
private static final SimpleTextInput cache = new SimpleTextInput();
|
||||
private static long cacheage = 0;
|
||||
private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
@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 (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));
|
||||
|
||||
}
|
||||
|
||||
private static void outputCache(final CommandSource sender, 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);
|
||||
}
|
||||
|
||||
|
||||
private class Calculator implements Runnable {
|
||||
private final transient Viewer viewer;
|
||||
private final boolean force;
|
||||
|
||||
public 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 (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 (Map.Entry<String, BigDecimal> entry : sortedEntries) {
|
||||
cache.getLines().add(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;
|
||||
|
||||
public 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));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
|
||||
if (args.length == 1) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.google.common.collect.Lists;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.BookMeta;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Commandbook extends EssentialsCommand {
|
||||
|
||||
private static final Material WRITABLE_BOOK = EnumUtil.getMaterial("WRITABLE_BOOK", "BOOK_AND_QUILL");
|
||||
|
||||
public Commandbook() {
|
||||
super("book");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
final ItemStack item = user.getItemInHand();
|
||||
final String player = user.getName();
|
||||
if (item.getType() == Material.WRITTEN_BOOK) {
|
||||
BookMeta bmeta = (BookMeta) item.getItemMeta();
|
||||
|
||||
if (args.length > 1 && args[0].equalsIgnoreCase("author")) {
|
||||
if (user.isAuthorized("essentials.book.author") && (isAuthor(bmeta, player) || user.isAuthorized("essentials.book.others"))) {
|
||||
bmeta.setAuthor(args[1]);
|
||||
item.setItemMeta(bmeta);
|
||||
user.sendMessage(tl("bookAuthorSet", getFinalArg(args, 1)));
|
||||
} else {
|
||||
throw new Exception(tl("denyChangeAuthor"));
|
||||
}
|
||||
} else if (args.length > 1 && args[0].equalsIgnoreCase("title")) {
|
||||
if (user.isAuthorized("essentials.book.title") && (isAuthor(bmeta, player) || user.isAuthorized("essentials.book.others"))) {
|
||||
bmeta.setTitle(args[1]);
|
||||
item.setItemMeta(bmeta);
|
||||
user.sendMessage(tl("bookTitleSet", getFinalArg(args, 1)));
|
||||
} else {
|
||||
throw new Exception(tl("denyChangeTitle"));
|
||||
}
|
||||
} else {
|
||||
if (isAuthor(bmeta, player) || user.isAuthorized("essentials.book.others")) {
|
||||
ItemStack newItem = new ItemStack(WRITABLE_BOOK, item.getAmount());
|
||||
newItem.setItemMeta(bmeta);
|
||||
InventoryWorkaround.setItemInMainHand(user.getBase(), newItem);
|
||||
user.sendMessage(tl("editBookContents"));
|
||||
} else {
|
||||
throw new Exception(tl("denyBookEdit"));
|
||||
}
|
||||
}
|
||||
} else if (item.getType() == WRITABLE_BOOK) {
|
||||
BookMeta bmeta = (BookMeta) item.getItemMeta();
|
||||
if (!user.isAuthorized("essentials.book.author")) {
|
||||
bmeta.setAuthor(player);
|
||||
}
|
||||
ItemStack newItem = new ItemStack(Material.WRITTEN_BOOK, item.getAmount());
|
||||
newItem.setItemMeta(bmeta);
|
||||
InventoryWorkaround.setItemInMainHand(user.getBase(), newItem);
|
||||
user.sendMessage(tl("bookLocked"));
|
||||
} else {
|
||||
throw new Exception(tl("holdBook"));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAuthor(BookMeta bmeta, String player) {
|
||||
String author = bmeta.getAuthor();
|
||||
return author != null && author.equalsIgnoreCase(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
|
||||
// Right now, we aren't testing what's held in the player's hand - we could, but it's not necessarily worth it
|
||||
if (args.length == 1) {
|
||||
List<String> options = Lists.newArrayList("sign", "unsign"); // sign and unsign aren't real, but work
|
||||
if (user.isAuthorized("essentials.book.author")) {
|
||||
options.add("author");
|
||||
}
|
||||
if (user.isAuthorized("essentials.book.title")) {
|
||||
options.add("title");
|
||||
}
|
||||
return options;
|
||||
} else if (args.length == 2 && args[0].equalsIgnoreCase("author") && user.isAuthorized("essentials.book.author")) {
|
||||
List<String> options = getPlayers(server, user);
|
||||
options.add("Herobrine"); // #EasterEgg
|
||||
return options;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Commandbroadcast extends EssentialsCommand {
|
||||
public Commandbroadcast() {
|
||||
super("broadcast");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
sendBroadcast(user.getDisplayName(), args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
sendBroadcast(sender.getSender().getName(), args);
|
||||
}
|
||||
|
||||
private void sendBroadcast(final String name, final String[] args) throws NotEnoughArgumentsException {
|
||||
if (args.length < 1) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
ess.broadcastMessage(tl("broadcast", FormatUtil.replaceFormat(getFinalArg(args, 0)).replace("\\n", "\n"), name));
|
||||
}
|
||||
}
|
||||
@@ -1,106 +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.KeywordReplacer;
|
||||
import com.earth2me.essentials.textreader.SimpleTextInput;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Commandbroadcastworld extends EssentialsCommand {
|
||||
|
||||
public Commandbroadcastworld() {
|
||||
super("broadcastworld");
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
World world = user.getWorld();
|
||||
String message = getFinalArg(args, 0);
|
||||
if (args.length > 1 && ess.getSettings().isAllowWorldInBroadcastworld()) {
|
||||
World argWorld = ess.getWorld(args[0]);
|
||||
if (argWorld != null) {
|
||||
world = argWorld;
|
||||
message = getFinalArg(args, 1);
|
||||
}
|
||||
}
|
||||
|
||||
sendBroadcast(world, user.getDisplayName(), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length < 2) {
|
||||
throw new NotEnoughArgumentsException("world");
|
||||
}
|
||||
|
||||
World world = ess.getWorld(args[0]);
|
||||
if (world == null) {
|
||||
throw new Exception(tl("invalidWorld"));
|
||||
}
|
||||
sendBroadcast(world, sender.getSender().getName(), getFinalArg(args, 1));
|
||||
}
|
||||
|
||||
private void sendBroadcast(final World world, final String name, final String message) throws Exception {
|
||||
if (message.isEmpty()) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
sendToWorld(world, tl("broadcast", FormatUtil.replaceFormat(message).replace("\\n", "\n"), name));
|
||||
}
|
||||
|
||||
private void sendToWorld(World world, String message) {
|
||||
IText broadcast = new SimpleTextInput(message);
|
||||
final Collection<Player> players = ess.getOnlinePlayers();
|
||||
|
||||
for (Player player : players) {
|
||||
if (player.getWorld().equals(world)) {
|
||||
final User user = ess.getUser(player);
|
||||
broadcast = new KeywordReplacer(broadcast, new CommandSource(player), ess, false);
|
||||
for (String messageText : broadcast.getLines()) {
|
||||
user.sendMessage(messageText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
|
||||
if (args.length == 1 && ess.getSettings().isAllowWorldInBroadcastworld()) {
|
||||
List<String> worlds = Lists.newArrayList();
|
||||
for (World world : server.getWorlds()) {
|
||||
worlds.add(world.getName());
|
||||
}
|
||||
return worlds;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
|
||||
if (args.length == 1) {
|
||||
List<String> worlds = Lists.newArrayList();
|
||||
for (World world : server.getWorlds()) {
|
||||
worlds.add(world.getName());
|
||||
}
|
||||
return worlds;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import com.earth2me.essentials.utils.StringUtil;
|
||||
import com.earth2me.essentials.utils.VersionUtil;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Commandclearinventory extends EssentialsLoopCommand {
|
||||
|
||||
public Commandclearinventory() {
|
||||
super("clearinventory");
|
||||
}
|
||||
|
||||
private static final int BASE_AMOUNT = 100000;
|
||||
|
||||
@Override
|
||||
public void run(Server server, User user, String commandLabel, String[] args) throws Exception {
|
||||
final String previousClearCommand = user.getConfirmingClearCommand();
|
||||
user.setConfirmingClearCommand(null);
|
||||
|
||||
String formattedCommand = formatCommand(commandLabel, args);
|
||||
if (user.isPromptingClearConfirm()) {
|
||||
if (!formattedCommand.equals(previousClearCommand)) {
|
||||
user.setConfirmingClearCommand(formattedCommand);
|
||||
user.sendMessage(tl("confirmClear", formattedCommand));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (args.length == 0 || (!args[0].contains("*") && server.matchPlayer(args[0]).isEmpty())) {
|
||||
clearHandler(user.getSource(), user.getBase(), args, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.isAuthorized("essentials.clearinventory.others")) {
|
||||
loopOnlinePlayers(server, user.getSource(), false, true, args[0], args);
|
||||
return;
|
||||
}
|
||||
throw new PlayerNotFoundException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
|
||||
if (args.length == 0) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
loopOnlinePlayers(server, sender, false, true, args[0], args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) {
|
||||
clearHandler(sender, player.getBase(), args, 1);
|
||||
}
|
||||
|
||||
private static class Item {
|
||||
private final Material material;
|
||||
private final short data;
|
||||
|
||||
public Item(Material material, short data) {
|
||||
this.material = material;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
public short getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
private enum ClearHandlerType {
|
||||
ALL_EXCEPT_ARMOR, ALL_INCLUDING_ARMOR, SPECIFIC_ITEM
|
||||
}
|
||||
|
||||
protected void clearHandler(CommandSource sender, Player player, String[] args, int offset) {
|
||||
ClearHandlerType type = ClearHandlerType.ALL_EXCEPT_ARMOR;
|
||||
final Set<Item> items = new HashSet<>();
|
||||
int amount = -1;
|
||||
|
||||
if (args.length > (offset + 1) && NumberUtil.isInt(args[(offset + 1)])) {
|
||||
amount = Integer.parseInt(args[(offset + 1)]);
|
||||
}
|
||||
if (args.length > offset) {
|
||||
if (args[offset].equalsIgnoreCase("**")) {
|
||||
type = ClearHandlerType.ALL_INCLUDING_ARMOR;
|
||||
} else if (!args[offset].equalsIgnoreCase("*")) {
|
||||
final String[] split = args[offset].split(",");
|
||||
for (String item : split) {
|
||||
final String[] itemParts = item.split(":");
|
||||
short data;
|
||||
try {
|
||||
data = Short.parseShort(itemParts[1]);
|
||||
} catch (Exception e) {
|
||||
data = 0;
|
||||
}
|
||||
try {
|
||||
items.add(new Item(ess.getItemDb().get(itemParts[0]).getType(), data));
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
type = ClearHandlerType.SPECIFIC_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ClearHandlerType.ALL_EXCEPT_ARMOR) {
|
||||
sender.sendMessage(tl("inventoryClearingAllItems", player.getDisplayName()));
|
||||
InventoryWorkaround.clearInventoryNoArmor(player.getInventory());
|
||||
InventoryWorkaround.setItemInOffHand(player, null);
|
||||
} else if (type == ClearHandlerType.ALL_INCLUDING_ARMOR) {
|
||||
sender.sendMessage(tl("inventoryClearingAllArmor", player.getDisplayName()));
|
||||
InventoryWorkaround.clearInventoryNoArmor(player.getInventory());
|
||||
InventoryWorkaround.setItemInOffHand(player, null);
|
||||
player.getInventory().setArmorContents(null);
|
||||
} else {
|
||||
for (Item item : items) {
|
||||
ItemStack stack = new ItemStack(item.getMaterial());
|
||||
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_13_0_R01)) {
|
||||
stack.setDurability(item.getData());
|
||||
}
|
||||
if (amount == -1) // amount -1 means all items will be cleared
|
||||
{
|
||||
stack.setAmount(BASE_AMOUNT);
|
||||
ItemStack removedStack = player.getInventory().removeItem(stack).get(0);
|
||||
final int removedAmount = (BASE_AMOUNT - removedStack.getAmount());
|
||||
if (removedAmount > 0) {
|
||||
sender.sendMessage(tl("inventoryClearingStack", removedAmount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName()));
|
||||
}
|
||||
} else {
|
||||
stack.setAmount(amount < 0 ? 1 : amount);
|
||||
if (player.getInventory().containsAtLeast(stack, amount)) {
|
||||
sender.sendMessage(tl("inventoryClearingStack", amount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName()));
|
||||
player.getInventory().removeItem(stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
|
||||
if (user.isAuthorized("essentials.clearinventory.others")) {
|
||||
if (args.length == 1) {
|
||||
List<String> options = getPlayers(server, user);
|
||||
if (user.isAuthorized("essentials.clearinventory.all") || user.isAuthorized("essentials.clearinventory.multiple")) {
|
||||
// Assume that nobody will have the 'all' permission without the 'others' permission
|
||||
options.add("*");
|
||||
}
|
||||
return options;
|
||||
} else if (args.length == 2) {
|
||||
List<String> items = new ArrayList<>(getItems());
|
||||
items.add("*");
|
||||
items.add("**");
|
||||
return items;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else {
|
||||
if (args.length == 1) {
|
||||
List<String> items = new ArrayList<>(getItems());
|
||||
items.add("*");
|
||||
items.add("**");
|
||||
return items;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
|
||||
if (args.length == 1) {
|
||||
List<String> options = getPlayers(server, sender);
|
||||
options.add("*");
|
||||
return options;
|
||||
} else if (args.length == 2) {
|
||||
List<String> items = new ArrayList<>(getItems());
|
||||
items.add("*");
|
||||
items.add("**");
|
||||
return items;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private String formatCommand(String commandLabel, String[] args) {
|
||||
return "/" + commandLabel + " " + StringUtil.joinList(" ", args);
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
|
||||
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.
|
||||
long delay = Long.parseLong(args[1]);
|
||||
String kitname = args[0];
|
||||
ItemStack[] items = user.getBase().getInventory().getContents();
|
||||
List<String> list = new ArrayList<>();
|
||||
for (ItemStack is : items) {
|
||||
if (is != null && is.getType() != null && is.getType() != Material.AIR) {
|
||||
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 {
|
||||
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 {
|
||||
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 (OutputStream os = connection.getOutputStream()) {
|
||||
os.write(contents.getBytes(Charsets.UTF_8));
|
||||
}
|
||||
// Error
|
||||
if (connection.getResponseCode() >= 400) {
|
||||
sender.sendMessage(tl("createKitFailed", kitName));
|
||||
String message = CharStreams.toString(new InputStreamReader(connection.getErrorStream(), Charsets.UTF_8));
|
||||
ess.getLogger().severe("Error creating kit: " + message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Read URL
|
||||
JsonObject object = GSON.fromJson(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8), JsonObject.class);
|
||||
String pasteUrl = PASTE_URL + object.get("key").getAsString();
|
||||
connection.disconnect();
|
||||
|
||||
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 (Exception e) {
|
||||
sender.sendMessage(tl("createKitFailed", kitName));
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Commanddelhome extends EssentialsCommand {
|
||||
public Commanddelhome() {
|
||||
super("delhome");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final CommandSource sender, final String commandLabel, String[] args) throws Exception {
|
||||
if (args.length < 1) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
User user = ess.getUser(sender.getPlayer());
|
||||
String name;
|
||||
String[] expandedArg;
|
||||
|
||||
//Allowing both formats /sethome khobbits house | /sethome khobbits:house
|
||||
final String[] nameParts = args[0].split(":");
|
||||
if (nameParts[0].length() != args[0].length()) {
|
||||
expandedArg = nameParts;
|
||||
} else {
|
||||
expandedArg = args;
|
||||
}
|
||||
|
||||
if (expandedArg.length > 1 && (user == null || user.isAuthorized("essentials.delhome.others"))) {
|
||||
user = getPlayer(server, expandedArg, 0, true, true);
|
||||
name = expandedArg[1];
|
||||
} else if (user == null) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
} else {
|
||||
name = expandedArg[0];
|
||||
}
|
||||
|
||||
if (name.equalsIgnoreCase("bed")) {
|
||||
throw new Exception(tl("invalidHomeName"));
|
||||
}
|
||||
|
||||
user.delHome(name.toLowerCase(Locale.ENGLISH));
|
||||
sender.sendMessage(tl("deleteHome", name));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
User user = ess.getUser(sender.getPlayer());
|
||||
boolean canDelOthers = user == null || user.isAuthorized("essentials.delhome.others");
|
||||
if (args.length == 1) {
|
||||
List<String> homes = user == null ? new ArrayList<>() : user.getHomes();
|
||||
if (canDelOthers) {
|
||||
int sepIndex = args[0].indexOf(':');
|
||||
if (sepIndex < 0) {
|
||||
getPlayers(server, sender).forEach(player -> homes.add(player + ":"));
|
||||
} else {
|
||||
String namePart = args[0].substring(0, sepIndex);
|
||||
User otherUser;
|
||||
try {
|
||||
otherUser = getPlayer(server, new String[]{namePart}, 0, true, true);
|
||||
} catch (Exception ex) {
|
||||
return homes;
|
||||
}
|
||||
otherUser.getHomes().forEach(home -> homes.add(namePart + ":" + home));
|
||||
}
|
||||
}
|
||||
return homes;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +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(Server server, User user, String commandLabel, String[] args) throws Exception {
|
||||
if (args.length == 0 || (args.length > 1 && !NumberUtil.isInt(args[1]))) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
Block target = user.getBase().getTargetBlock(null, 5); //5 is a good number
|
||||
if (!(target.getState() instanceof Sign)) {
|
||||
throw new Exception(tl("editsignCommandTarget"));
|
||||
}
|
||||
Sign sign = (Sign) target.getState();
|
||||
try {
|
||||
if (args[0].equalsIgnoreCase("set") && args.length > 2) {
|
||||
int line = Integer.parseInt(args[1]) - 1;
|
||||
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 {
|
||||
int line = Integer.parseInt(args[1]) - 1;
|
||||
sign.setLine(line, "");
|
||||
sign.update();
|
||||
user.sendMessage(tl("editsignCommandClearLine", line + 1));
|
||||
}
|
||||
} else {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new Exception(tl("editsignCommandNoLine"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, 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])) {
|
||||
int line = Integer.parseInt(args[1]);
|
||||
Block target = user.getBase().getTargetBlock(null, 5);
|
||||
if (target.getState() instanceof Sign && line <= 4) {
|
||||
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,468 +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.*;
|
||||
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.*;
|
||||
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?\"..."};
|
||||
|
||||
public Commandessentials() {
|
||||
super("essentials");
|
||||
}
|
||||
|
||||
private transient TuneRunnable currentTune = null;
|
||||
|
||||
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"
|
||||
);
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (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 (String s : CONSOLE_MOO) {
|
||||
logger.info(s);
|
||||
}
|
||||
for (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(() -> {
|
||||
long currTime = System.currentTimeMillis();
|
||||
for (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;
|
||||
}
|
||||
|
||||
long timeDiff = currTime - lastLog;
|
||||
long milliDays = daysArg * 24L * 60L * 60L * 1000L;
|
||||
int homeCount = user.getHomes().size();
|
||||
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.");
|
||||
|
||||
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>");
|
||||
}
|
||||
String name = args[1];
|
||||
sender.sendMessage("Looking up UUID for " + name);
|
||||
|
||||
UUID onlineUUID = null;
|
||||
|
||||
for (Player player : ess.getOnlinePlayers()) {
|
||||
if (player.getName().equalsIgnoreCase(name)) {
|
||||
onlineUUID = player.getUniqueId();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UUID essUUID = ess.getUserMap().getUser(name).getConfigUUID();
|
||||
|
||||
org.bukkit.OfflinePlayer player = ess.getServer().getOfflinePlayer(name);
|
||||
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());
|
||||
}
|
||||
|
||||
UUID npcuuid = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
|
||||
sender.sendMessage("NPC UUID: " + npcuuid.toString());
|
||||
|
||||
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 boolean isServerSupported = VersionUtil.isServerSupported();
|
||||
final PluginManager pm = server.getPluginManager();
|
||||
final String essVer = pm.getPlugin("Essentials").getDescription().getVersion();
|
||||
|
||||
sender.sendMessage(tl(isServerSupported ? "versionOutputFine" : "versionOutputWarn", "Server", server.getBukkitVersion() + " " + server.getVersion()));
|
||||
sender.sendMessage(tl("versionOutputFine", "EssentialsX", essVer));
|
||||
|
||||
for (Plugin plugin : pm.getPlugins()) {
|
||||
final PluginDescriptionFile desc = plugin.getDescription();
|
||||
String name = desc.getName();
|
||||
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"));
|
||||
}
|
||||
|
||||
if (!VersionUtil.isServerSupported()) {
|
||||
sender.sendMessage(tl("serverUnsupported"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
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 (Player onlinePlayer : players.get()) {
|
||||
onlinePlayer.playSound(onlinePlayer.getLocation(), sound, 1, noteMap.get(note));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.textreader.*;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Commandhelp extends EssentialsCommand {
|
||||
public Commandhelp() {
|
||||
super("help");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
IText output;
|
||||
String pageStr = args.length > 0 ? args[0] : null;
|
||||
String chapterPageStr = args.length > 1 ? args[1] : null;
|
||||
String command = commandLabel;
|
||||
final IText input = new TextInput(user.getSource(), "help", false, ess);
|
||||
|
||||
if (input.getLines().isEmpty()) {
|
||||
if (NumberUtil.isInt(pageStr) || pageStr == null) {
|
||||
output = new HelpInput(user, "", ess);
|
||||
} else {
|
||||
if (pageStr.length() > 26) {
|
||||
pageStr = pageStr.substring(0, 25);
|
||||
}
|
||||
output = new HelpInput(user, pageStr.toLowerCase(Locale.ENGLISH), ess);
|
||||
command = command.concat(" ").concat(pageStr);
|
||||
pageStr = chapterPageStr;
|
||||
}
|
||||
chapterPageStr = null;
|
||||
} else {
|
||||
user.setDisplayNick();
|
||||
output = new KeywordReplacer(input, user.getSource(), ess);
|
||||
}
|
||||
final TextPager pager = new TextPager(output);
|
||||
pager.showPage(pageStr, chapterPageStr, command, user.getSource());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
sender.sendMessage(tl("helpConsole"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return getCommands(server);
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +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(Server server, CommandSource sender, String commandLabel, String[] args) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.utils.VersionUtil;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Commanditemdb extends EssentialsCommand {
|
||||
public Commanditemdb() {
|
||||
super("itemdb");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
|
||||
ItemStack itemStack = null;
|
||||
boolean itemHeld = false;
|
||||
if (args.length == 0) {
|
||||
if (sender.isPlayer() && sender.getPlayer() != null) {
|
||||
itemHeld = true;
|
||||
itemStack = ess.getUser(sender.getPlayer()).getItemInHand();
|
||||
}
|
||||
if (itemStack == null) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
} else {
|
||||
itemStack = ess.getItemDb().get(args[0]);
|
||||
}
|
||||
|
||||
String itemId = "none";
|
||||
|
||||
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_13_0_R01)) {
|
||||
itemId = itemStack.getType().getId() + ":" + itemStack.getDurability();
|
||||
}
|
||||
|
||||
sender.sendMessage(tl("itemType", itemStack.getType().toString(), itemId));
|
||||
|
||||
// Don't send IDs twice
|
||||
if (!tl("itemType").contains("{1}") && !itemId.equals("none")) {
|
||||
sender.sendMessage(tl("itemId", itemId));
|
||||
}
|
||||
|
||||
if (itemHeld && itemStack.getType() != Material.AIR) {
|
||||
int maxuses = itemStack.getType().getMaxDurability();
|
||||
int durability = ((maxuses + 1) - itemStack.getDurability());
|
||||
if (maxuses != 0) {
|
||||
sender.sendMessage(tl("durability", Integer.toString(durability)));
|
||||
}
|
||||
}
|
||||
final String itemNameList = ess.getItemDb().names(itemStack);
|
||||
if (itemNameList != null) {
|
||||
sender.sendMessage(tl("itemNames", ess.getItemDb().names(itemStack)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return getItems();
|
||||
} else {
|
||||
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(Server server, User user, String commandLabel, String[] args) throws Exception {
|
||||
ItemStack item = user.getBase().getItemInHand();
|
||||
if (item.getType().name().contains("AIR")) {
|
||||
throw new Exception(tl("itemloreInvalidItem"));
|
||||
}
|
||||
|
||||
if (args.length == 0) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
ItemMeta im = item.getItemMeta();
|
||||
if (args[0].equalsIgnoreCase("add") && args.length > 1) {
|
||||
String line = FormatUtil.formatString(user, "essentials.itemlore", getFinalArg(args, 1)).trim();
|
||||
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"));
|
||||
}
|
||||
|
||||
int line = Integer.parseInt(args[1]);
|
||||
String newLine = FormatUtil.formatString(user, "essentials.itemlore", getFinalArg(args, 2)).trim();
|
||||
List<String> lore = im.getLore();
|
||||
try {
|
||||
lore.set(line - 1, newLine);
|
||||
} catch (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(Server server, User user, String commandLabel, 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(Server server, User user, String commandLabel, String[] args) throws Exception {
|
||||
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;
|
||||
}
|
||||
|
||||
ItemMeta im = item.getItemMeta();
|
||||
im.setDisplayName(name);
|
||||
item.setItemMeta(im);
|
||||
user.sendMessage(name == null ? tl("itemnameClear") : tl("itemnameSuccess", name));
|
||||
}
|
||||
}
|
||||
@@ -1,128 +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.*;
|
||||
|
||||
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(CommandSource sender, String commandLabel, 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 (String oConfigGroup : configGroups) {
|
||||
String groupValue = ess.getSettings().getListGroupConfig().get(oConfigGroup).toString().trim();
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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, ", ")));
|
||||
}
|
||||
|
||||
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()) {
|
||||
List<User> asteriskUsers = new ArrayList<>();
|
||||
for (String onlineGroup : onlineGroups) {
|
||||
asteriskUsers.addAll(playerList.get(onlineGroup));
|
||||
}
|
||||
for (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 (String onlineGroup : onlineGroups) {
|
||||
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,206 +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();
|
||||
}
|
||||
|
||||
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()) {
|
||||
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));
|
||||
}
|
||||
|
||||
User u;
|
||||
try {
|
||||
u = getPlayer(server, args[1], true, true);
|
||||
} catch (PlayerNotFoundException e) {
|
||||
throw new Exception(tl("playerNeverOnServer", args[1]));
|
||||
}
|
||||
|
||||
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(Server server, CommandSource sender, String commandLabel, 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])) {
|
||||
User u;
|
||||
try {
|
||||
u = getPlayer(server, args[1], true, true);
|
||||
} catch (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
|
||||
User u;
|
||||
try {
|
||||
u = getPlayer(server, args[0], true, true);
|
||||
} catch (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();
|
||||
}
|
||||
|
||||
|
||||
private class SendAll implements Runnable {
|
||||
String message;
|
||||
|
||||
public SendAll(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (UUID userid : ess.getUserMap().getAllUniqueUsers()) {
|
||||
User user = ess.getUserMap().getUser(userid);
|
||||
if (user != null) {
|
||||
user.addMail(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
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();
|
||||
int pages = mail.size() / 9 + (mail.size() % 9 > 0 ? 1 : 0);
|
||||
if (pages == 0) {
|
||||
return Lists.newArrayList("0");
|
||||
} else {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,106 +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.earth2me.essentials.utils.FormatUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Commandme extends EssentialsCommand {
|
||||
public Commandme() {
|
||||
super("me");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Server server, User user, String commandLabel, String[] args) throws Exception {
|
||||
if (user.isMuted()) {
|
||||
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));
|
||||
}
|
||||
|
||||
if (args.length < 1) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
String message = getFinalArg(args, 0);
|
||||
message = FormatUtil.formatMessage(user, "essentials.chat", message);
|
||||
|
||||
user.setDisplayNick();
|
||||
int radius = ess.getSettings().getChatRadius();
|
||||
String toSend = tl("action", user.getDisplayName(), message);
|
||||
if (radius < 1) {
|
||||
ess.broadcastMessage(user, toSend);
|
||||
return;
|
||||
}
|
||||
|
||||
World world = user.getWorld();
|
||||
Location loc = user.getLocation();
|
||||
Set<Player> outList = new HashSet<>();
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
final User onlineUser = ess.getUser(player);
|
||||
if (!onlineUser.equals(user)) {
|
||||
boolean abort = false;
|
||||
final Location playerLoc = onlineUser.getLocation();
|
||||
if (playerLoc.getWorld() != world) {
|
||||
abort = true;
|
||||
} else if (onlineUser.isIgnoredPlayer(user)) {
|
||||
abort = true;
|
||||
} else {
|
||||
final double delta = playerLoc.distanceSquared(loc);
|
||||
if (delta > radius) {
|
||||
abort = true;
|
||||
}
|
||||
}
|
||||
if (abort) {
|
||||
if (onlineUser.isAuthorized("essentials.chat.spy")) {
|
||||
outList.add(player); // Just use the same list unless we wanted to format spyying for this.
|
||||
}
|
||||
} else {
|
||||
outList.add(player);
|
||||
}
|
||||
} else {
|
||||
outList.add(player); // Add yourself to the list.
|
||||
}
|
||||
}
|
||||
|
||||
if (outList.size() < 2) {
|
||||
user.sendMessage(tl("localNoOne"));
|
||||
}
|
||||
|
||||
for (Player onlinePlayer : outList) {
|
||||
onlinePlayer.sendMessage(toSend);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
|
||||
if (args.length < 1) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
String message = getFinalArg(args, 0);
|
||||
message = FormatUtil.replaceFormat(message);
|
||||
|
||||
ess.getServer().broadcastMessage(tl("action", "@", message));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
|
||||
return null; // It's a chat message, use the default chat handler
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.TNTPrimed;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Commandnuke extends EssentialsCommand {
|
||||
public Commandnuke() {
|
||||
super("nuke");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws NoSuchFieldException, NotEnoughArgumentsException {
|
||||
Collection<Player> targets;
|
||||
if (args.length > 0) {
|
||||
targets = new ArrayList<>();
|
||||
for (int i = 0; i < args.length; ++i) {
|
||||
targets.add(getPlayer(server, sender, args, i).getBase());
|
||||
}
|
||||
} else {
|
||||
targets = ess.getOnlinePlayers();
|
||||
}
|
||||
ess.getTNTListener().enable();
|
||||
for (Player player : targets) {
|
||||
if (player == null) {
|
||||
continue;
|
||||
}
|
||||
player.sendMessage(tl("nuke"));
|
||||
final Location loc = player.getLocation();
|
||||
final World world = loc.getWorld();
|
||||
for (int x = -10; x <= 10; x += 5) {
|
||||
for (int z = -10; z <= 10; z += 5) {
|
||||
world.spawn(new Location(world, loc.getBlockX() + x, world.getHighestBlockYAt(loc) + 64, loc.getBlockZ() + z), TNTPrimed.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return getPlayers(server, sender);
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.UserMap;
|
||||
import com.earth2me.essentials.craftbukkit.BanLookup;
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import com.earth2me.essentials.utils.StringUtil;
|
||||
import org.bukkit.BanEntry;
|
||||
import org.bukkit.BanList;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.Collections;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Commandseen extends EssentialsCommand {
|
||||
public Commandseen() {
|
||||
super("seen");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
boolean showBan = sender.isAuthorized("essentials.seen.banreason", ess);
|
||||
boolean showIp = sender.isAuthorized("essentials.seen.ip", ess);
|
||||
boolean showLocation = sender.isAuthorized("essentials.seen.location", ess);
|
||||
if (args.length < 1) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
User player;
|
||||
// Check by uuid, if it fails check by name.
|
||||
try {
|
||||
UUID uuid = UUID.fromString(args[0]);
|
||||
player = ess.getUser(uuid);
|
||||
} catch (IllegalArgumentException ignored) { // Thrown if invalid UUID from string, check by name.
|
||||
player = ess.getOfflineUser(args[0]);
|
||||
}
|
||||
|
||||
if (player == null) {
|
||||
if (sender.isAuthorized("essentials.seen.ipsearch", ess) && FormatUtil.validIP(args[0])) {
|
||||
seenIP(sender, args[0]);
|
||||
return;
|
||||
} else if (ess.getServer().getBanList(BanList.Type.IP).isBanned(args[0])) {
|
||||
sender.sendMessage(tl("isIpBanned", args[0]));
|
||||
return;
|
||||
} else if (BanLookup.isBanned(ess, args[0])) {
|
||||
sender.sendMessage(tl("whoisBanned", showBan ? BanLookup.getBanEntry(ess, args[0]).getReason() : tl("true")));
|
||||
return;
|
||||
}
|
||||
ess.getScheduler().runTaskAsynchronously(ess, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
User userFromBukkit = ess.getUserMap().getUserFromBukkit(args[0]);
|
||||
try {
|
||||
if (userFromBukkit != null) {
|
||||
showUserSeen(userFromBukkit);
|
||||
} else {
|
||||
try {
|
||||
showUserSeen(getPlayer(server, sender, args, 0));
|
||||
} catch (PlayerNotFoundException e) {
|
||||
throw new Exception(tl("playerNeverOnServer", args[0]));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ess.showError(sender, e, commandLabel);
|
||||
}
|
||||
}
|
||||
|
||||
private void showUserSeen(User user) throws Exception {
|
||||
showSeenMessage(sender, user, showBan, showIp, showLocation);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
showSeenMessage(sender, player, showBan, showIp, showLocation);
|
||||
}
|
||||
}
|
||||
|
||||
private void showSeenMessage(CommandSource sender, User player, boolean showBan, boolean showIp, boolean showLocation) {
|
||||
if (player.getBase().isOnline() && canInteractWith(sender, player)) {
|
||||
seenOnline(sender, player, showIp);
|
||||
} else {
|
||||
seenOffline(sender, player, showBan, showIp, showLocation);
|
||||
}
|
||||
}
|
||||
|
||||
private void seenOnline(final CommandSource sender, final User user, final boolean showIp) {
|
||||
|
||||
user.setDisplayNick();
|
||||
sender.sendMessage(tl("seenOnline", user.getDisplayName(), DateUtil.formatDateDiff(user.getLastLogin())));
|
||||
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info("UUID: " + user.getBase().getUniqueId().toString());
|
||||
}
|
||||
|
||||
List<String> history = ess.getUserMap().getUserHistory(user.getBase().getUniqueId());
|
||||
if (history != null && history.size() > 1) {
|
||||
sender.sendMessage(tl("seenAccounts", StringUtil.joinListSkip(", ", user.getName(), history)));
|
||||
}
|
||||
|
||||
if (user.isAfk()) {
|
||||
sender.sendMessage(tl("whoisAFK", tl("true")));
|
||||
}
|
||||
if (user.isJailed()) {
|
||||
sender.sendMessage(tl("whoisJail", (user.getJailTimeout() > 0 ? DateUtil.formatDateDiff(user.getJailTimeout()) : tl("true"))));
|
||||
}
|
||||
if (user.isMuted()) {
|
||||
long muteTimeout = user.getMuteTimeout();
|
||||
if (!user.hasMuteReason()) {
|
||||
sender.sendMessage(tl("whoisMuted", (muteTimeout > 0 ? DateUtil.formatDateDiff(muteTimeout) : tl("true"))));
|
||||
} else {
|
||||
sender.sendMessage(tl("whoisMutedReason", (muteTimeout > 0 ? DateUtil.formatDateDiff(muteTimeout) : tl("true")), user.getMuteReason()));
|
||||
}
|
||||
}
|
||||
final String location = user.getGeoLocation();
|
||||
if (location != null && (!(sender.isPlayer()) || ess.getUser(sender.getPlayer()).isAuthorized("essentials.geoip.show"))) {
|
||||
sender.sendMessage(tl("whoisGeoLocation", location));
|
||||
}
|
||||
if (showIp) {
|
||||
sender.sendMessage(tl("whoisIPAddress", user.getBase().getAddress().getAddress().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
private void seenOffline(final CommandSource sender, User user, final boolean showBan, final boolean showIp, final boolean showLocation) {
|
||||
user.setDisplayNick();
|
||||
if (user.getLastLogout() > 0) {
|
||||
sender.sendMessage(tl("seenOffline", user.getName(), DateUtil.formatDateDiff(user.getLastLogout())));
|
||||
} else {
|
||||
sender.sendMessage(tl("userUnknown", user.getName()));
|
||||
}
|
||||
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info("UUID: " + user.getBase().getUniqueId().toString());
|
||||
}
|
||||
|
||||
List<String> history = ess.getUserMap().getUserHistory(user.getBase().getUniqueId());
|
||||
if (history != null && history.size() > 1) {
|
||||
sender.sendMessage(tl("seenAccounts", StringUtil.joinListSkip(", ", user.getName(), history)));
|
||||
}
|
||||
|
||||
if (BanLookup.isBanned(ess, user)) {
|
||||
final BanEntry banEntry = BanLookup.getBanEntry(ess, user.getName());
|
||||
final String reason = showBan ? banEntry.getReason() : tl("true");
|
||||
sender.sendMessage(tl("whoisBanned", reason));
|
||||
if (banEntry.getExpiration() != null) {
|
||||
Date expiry = banEntry.getExpiration();
|
||||
String expireString = tl("now");
|
||||
if (expiry.after(new Date())) {
|
||||
expireString = DateUtil.formatDateDiff(expiry.getTime());
|
||||
}
|
||||
sender.sendMessage(tl("whoisTempBanned", expireString));
|
||||
}
|
||||
}
|
||||
|
||||
if (user.isMuted()) {
|
||||
long muteTimeout = user.getMuteTimeout();
|
||||
if (!user.hasMuteReason()) {
|
||||
sender.sendMessage(tl("whoisMuted", (muteTimeout > 0 ? DateUtil.formatDateDiff(muteTimeout) : tl("true"))));
|
||||
} else {
|
||||
sender.sendMessage(tl("whoisMutedReason", (muteTimeout > 0 ? DateUtil.formatDateDiff(muteTimeout) : tl("true")), user.getMuteReason()));
|
||||
}
|
||||
}
|
||||
|
||||
final String location = user.getGeoLocation();
|
||||
if (location != null && (!(sender.isPlayer()) || ess.getUser(sender.getPlayer()).isAuthorized("essentials.geoip.show"))) {
|
||||
sender.sendMessage(tl("whoisGeoLocation", location));
|
||||
}
|
||||
if (showIp) {
|
||||
if (!user.getLastLoginAddress().isEmpty()) {
|
||||
sender.sendMessage(tl("whoisIPAddress", user.getLastLoginAddress()));
|
||||
}
|
||||
}
|
||||
if (showLocation) {
|
||||
final Location loc = user.getLogoutLocation();
|
||||
if (loc != null) {
|
||||
sender.sendMessage(tl("whoisLocation", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void seenIP(final CommandSource sender, final String ipAddress) {
|
||||
final UserMap userMap = ess.getUserMap();
|
||||
|
||||
if (ess.getServer().getBanList(BanList.Type.IP).isBanned(ipAddress)) {
|
||||
sender.sendMessage(tl("isIpBanned", ipAddress));
|
||||
}
|
||||
|
||||
sender.sendMessage(tl("runningPlayerMatch", ipAddress));
|
||||
|
||||
ess.runTaskAsynchronously(() -> {
|
||||
final List<String> matches = new ArrayList<>();
|
||||
for (final UUID u : userMap.getAllUniqueUsers()) {
|
||||
final User user = ess.getUserMap().getUser(u);
|
||||
if (user == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String uIPAddress = user.getLastLoginAddress();
|
||||
|
||||
if (!uIPAddress.isEmpty() && uIPAddress.equalsIgnoreCase(ipAddress)) {
|
||||
matches.add(user.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (matches.size() > 0) {
|
||||
sender.sendMessage(tl("matchingIPAddress"));
|
||||
sender.sendMessage(StringUtil.joinList(matches));
|
||||
} else {
|
||||
sender.sendMessage(tl("noMatchingPlayers"));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return getPlayers(server, sender);
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +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(Server server, User user, String commandLabel, String[] args) throws Exception {
|
||||
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(Server server, User user, String commandLabel, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return Arrays.asList("center", "minrange", "maxrange");
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -1,44 +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 (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 {
|
||||
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();
|
||||
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(User user, ItemStack stack, SkullMeta skullMeta, String owner, 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(Server server, User user, String commandLabel, 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,138 +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;
|
||||
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()) {
|
||||
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 (Exception e) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else {
|
||||
return COMMON_DATE_DIFFS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.User;
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
|
||||
public class Commandtpacancel extends EssentialsCommand {
|
||||
|
||||
public Commandtpacancel() {
|
||||
super("tpacancel");
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel {@link User}'s tp request if its {@code requester} is equal to the given {@code requester}.
|
||||
* @param ess ess instance
|
||||
* @param user user holding tp request
|
||||
* @param requester tp requester
|
||||
* @return whether tp was cancelled
|
||||
*/
|
||||
public static boolean cancelTeleportRequest(IEssentials ess, User user, User requester) throws Exception {
|
||||
if (user.getTeleportRequest() != null) {
|
||||
User userRequester = ess.getUser(user.getTeleportRequest());
|
||||
if (requester.equals(userRequester)) {
|
||||
user.requestTeleport(null, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length == 0) {
|
||||
int cancellations = 0;
|
||||
for (User onlineUser : ess.getOnlineUsers()) {
|
||||
if (onlineUser == user) continue;
|
||||
if (cancelTeleportRequest(ess, onlineUser, user)) {
|
||||
cancellations++;
|
||||
}
|
||||
}
|
||||
if (cancellations > 0) {
|
||||
user.sendMessage(tl("teleportRequestAllCancelled", cancellations));
|
||||
} else {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
} else {
|
||||
User targetPlayer = getPlayer(server, user, args, 0);
|
||||
if (cancelTeleportRequest(ess, targetPlayer, user)) {
|
||||
user.sendMessage(tl("teleportRequestSpecificCancelled", targetPlayer.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +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 (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()));
|
||||
|
||||
CompletableFuture<Boolean> future = getNewExceptionFuture(requester.getSource(), commandLabel);
|
||||
future.exceptionally(e -> {
|
||||
user.sendMessage(tl("pendingTeleportCancelled"));
|
||||
return false;
|
||||
});
|
||||
if (user.isTpRequestHere()) {
|
||||
final Location loc = user.getTpRequestLocation();
|
||||
AsyncTeleport teleport = (AsyncTeleport) 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 {
|
||||
AsyncTeleport teleport = (AsyncTeleport) requester.getAsyncTeleport();
|
||||
teleport.setTpType(AsyncTeleport.TeleportType.TPA);
|
||||
teleport.teleport(user.getBase(), charge, TeleportCause.COMMAND, future);
|
||||
}
|
||||
user.requestTeleport(null, false);
|
||||
throw new NoChargeException();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +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,35 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.User;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandtpoffline extends EssentialsCommand {
|
||||
|
||||
public Commandtpoffline() {
|
||||
super("tpoffline");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String label, final String[] args) throws Exception {
|
||||
switch (args.length) {
|
||||
case 0:
|
||||
throw new NotEnoughArgumentsException();
|
||||
|
||||
default:
|
||||
final User target = getPlayer(server, args, 0, true, true);
|
||||
final Location logout = target.getLogoutLocation();
|
||||
|
||||
if (user.getWorld() != logout.getWorld() && ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + logout.getWorld().getName())) {
|
||||
throw new Exception(tl("noPerm", "essentials.worlds." + logout.getWorld().getName()));
|
||||
}
|
||||
|
||||
user.sendMessage(tl("teleporting", logout.getWorld().getName(), logout.getBlockX(), logout.getBlockY(), logout.getBlockZ()));
|
||||
user.getAsyncTeleport().now(logout, false, PlayerTeleportEvent.TeleportCause.COMMAND, getNewExceptionFuture(user.getSource(), label));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +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(Server server, User user, String commandLabel, String[] args) throws Exception {
|
||||
final Trade charge = new Trade(this.getName(), ess);
|
||||
charge.isAffordableFor(user);
|
||||
RandomTeleport randomTeleport = ess.getRandomTeleport();
|
||||
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 -> {
|
||||
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(Server server, User user, String commandLabel, String[] args) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -1,85 +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.Locale;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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()));
|
||||
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"))));
|
||||
|
||||
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(Server server, CommandSource sender, String commandLabel, 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(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(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.earth2me.essentials.craftbukkit;
|
||||
|
||||
import com.earth2me.essentials.User;
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.BanEntry;
|
||||
import org.bukkit.BanList;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class BanLookup {
|
||||
public static Boolean isBanned(IEssentials ess, User user) {
|
||||
return isBanned(ess, user.getName());
|
||||
}
|
||||
|
||||
public static Boolean isBanned(IEssentials ess, String name) {
|
||||
return getBanEntry(ess, name) != null;
|
||||
}
|
||||
|
||||
public static BanEntry getBanEntry(IEssentials ess, String name) {
|
||||
Set<BanEntry> benteries = ess.getServer().getBanList(BanList.Type.NAME).getBanEntries();
|
||||
for (BanEntry banEnt : benteries) {
|
||||
if (banEnt.getTarget().equals(name)) {
|
||||
return banEnt;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,273 +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 {
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
|
||||
private static boolean isCombinedInventory(Inventory inventory) {
|
||||
return inventory instanceof PlayerInventory && inventory.getContents().length > USABLE_PLAYER_INV_SIZE;
|
||||
}
|
||||
|
||||
// Clears inventory without clearing armor
|
||||
public static void clearInventoryNoArmor(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(PlayerInventory playerInventory) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
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)) {
|
||||
Inventory fakeInventory = makeTruncatedPlayerInventory((PlayerInventory) inventory);
|
||||
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 (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;
|
||||
}
|
||||
|
||||
// Hot-ish code so cache
|
||||
private static Boolean hasMainHandSupport = null;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void setItemInMainHand(Player p, ItemStack item) {
|
||||
if (hasMainHandSupport == null) {
|
||||
try {
|
||||
p.getInventory().setItemInMainHand(item);
|
||||
hasMainHandSupport = true;
|
||||
} catch (Throwable e) {
|
||||
p.setItemInHand(item);
|
||||
hasMainHandSupport = false;
|
||||
}
|
||||
} else {
|
||||
if (hasMainHandSupport) {
|
||||
p.getInventory().setItemInMainHand(item);
|
||||
} else {
|
||||
p.setItemInHand(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void setItemInMainHand(EntityEquipment invent, ItemStack item) {
|
||||
if (hasMainHandSupport == null) {
|
||||
try {
|
||||
invent.setItemInMainHand(item);
|
||||
hasMainHandSupport = true;
|
||||
} catch (Throwable e) {
|
||||
invent.setItemInHand(item);
|
||||
hasMainHandSupport = false;
|
||||
}
|
||||
} else {
|
||||
if (hasMainHandSupport) {
|
||||
invent.setItemInMainHand(item);
|
||||
} else {
|
||||
invent.setItemInHand(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void setItemInMainHandDropChance(EntityEquipment invent, float chance) {
|
||||
if (hasMainHandSupport == null) {
|
||||
try {
|
||||
invent.setItemInMainHandDropChance(chance);
|
||||
hasMainHandSupport = true;
|
||||
} catch (Throwable e) {
|
||||
invent.setItemInHandDropChance(chance);
|
||||
hasMainHandSupport = false;
|
||||
}
|
||||
} else {
|
||||
if (hasMainHandSupport) {
|
||||
invent.setItemInMainHandDropChance(chance);
|
||||
} else {
|
||||
invent.setItemInHandDropChance(chance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setItemInOffHand(Player p, 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 (Throwable e) {
|
||||
hasMainHandSupport = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,349 +0,0 @@
|
||||
package com.earth2me.essentials.items;
|
||||
|
||||
import com.earth2me.essentials.IConf;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.utils.MaterialUtil;
|
||||
import com.earth2me.essentials.utils.VersionUtil;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.PluginKey;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.FireworkEffect;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Banner;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.*;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.potion.Potion;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public abstract class AbstractItemDb implements IConf, net.ess3.api.IItemDb {
|
||||
|
||||
protected final IEssentials ess;
|
||||
protected boolean ready = false;
|
||||
|
||||
private final Map<PluginKey, ItemResolver> resolverMap = new HashMap<>();
|
||||
|
||||
AbstractItemDb(IEssentials ess) {
|
||||
this.ess = ess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerResolver(Plugin plugin, String name, ItemResolver resolver) throws Exception {
|
||||
PluginKey key = PluginKey.fromKey(plugin, name);
|
||||
if (resolverMap.containsKey(key)) {
|
||||
throw new Exception("Tried to add a duplicate resolver with name " + key.toString());
|
||||
}
|
||||
|
||||
resolverMap.put(key, resolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterResolver(Plugin plugin, String name) throws Exception {
|
||||
PluginKey key = PluginKey.fromKey(plugin, name);
|
||||
if (!resolverMap.containsKey(key)) {
|
||||
throw new Exception("Tried to remove nonexistent resolver with name " + key.toString());
|
||||
}
|
||||
|
||||
resolverMap.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResolverPresent(Plugin plugin, String name) {
|
||||
return resolverMap.containsKey(PluginKey.fromKey(plugin, name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<PluginKey, ItemResolver> getResolvers() {
|
||||
return new HashMap<>(resolverMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<PluginKey, ItemResolver> getResolvers(Plugin plugin) {
|
||||
Map<PluginKey, ItemResolver> matchingResolvers = new HashMap<>();
|
||||
for (PluginKey key : resolverMap.keySet()) {
|
||||
if (key.getPlugin().equals(plugin)) {
|
||||
matchingResolvers.put(key, resolverMap.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return matchingResolvers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemResolver getResolver(Plugin plugin, String name) {
|
||||
return resolverMap.get(PluginKey.fromKey(plugin, name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack get(String id) throws Exception {
|
||||
return get(id, true);
|
||||
}
|
||||
|
||||
ItemStack tryResolverDeserialize(String id) {
|
||||
for (PluginKey key : resolverMap.keySet()) {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info(String.format("Trying to deserialize item '%s' with resolver '%s'...", id, key));
|
||||
}
|
||||
|
||||
Function<String, ItemStack> resolver = resolverMap.get(key);
|
||||
ItemStack stack = resolver.apply(id);
|
||||
|
||||
if (stack != null) {
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
String tryResolverSerialize(ItemStack stack) {
|
||||
for (PluginKey key : resolverMap.keySet()) {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info(String.format("Trying to serialize '%s' with resolver '%s'...", stack.toString(), key));
|
||||
}
|
||||
|
||||
ItemResolver resolver = resolverMap.get(key);
|
||||
String serialized = resolver.serialize(stack);
|
||||
|
||||
if (serialized != null) {
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Collection<String> getResolverNames() {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (ItemResolver resolver : resolverMap.values()) {
|
||||
Collection<String> resolverNames = resolver.getNames();
|
||||
if (resolverNames != null) {
|
||||
result.addAll(resolverNames);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemStack> getMatching(User user, String[] args) throws Exception {
|
||||
List<ItemStack> is = new ArrayList<>();
|
||||
|
||||
if (args.length < 1) {
|
||||
is.add(user.getItemInHand().clone());
|
||||
} else if (args[0].equalsIgnoreCase("hand")) {
|
||||
is.add(user.getItemInHand().clone());
|
||||
} else if (args[0].equalsIgnoreCase("inventory") || args[0].equalsIgnoreCase("invent") || args[0].equalsIgnoreCase("all")) {
|
||||
for (ItemStack stack : user.getBase().getInventory().getContents()) {
|
||||
if (stack == null || stack.getType() == Material.AIR) {
|
||||
continue;
|
||||
}
|
||||
is.add(stack.clone());
|
||||
}
|
||||
} else if (args[0].equalsIgnoreCase("blocks")) {
|
||||
for (ItemStack stack : user.getBase().getInventory().getContents()) {
|
||||
if (stack == null || stack.getType() == Material.AIR) {
|
||||
continue;
|
||||
}
|
||||
is.add(stack.clone());
|
||||
}
|
||||
} else {
|
||||
is.add(get(args[0]));
|
||||
}
|
||||
|
||||
if (is.isEmpty() || is.get(0).getType() == Material.AIR) {
|
||||
throw new Exception(tl("itemSellAir"));
|
||||
}
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize(ItemStack is) {
|
||||
return serialize(is, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize(ItemStack is, boolean useResolvers) {
|
||||
if (useResolvers) {
|
||||
String serialized = tryResolverSerialize(is);
|
||||
if (serialized != null) {
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
|
||||
String mat = name(is);
|
||||
if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_12_2_R01) && is.getData().getData() != 0) {
|
||||
mat = mat + ":" + is.getData().getData();
|
||||
}
|
||||
int quantity = is.getAmount();
|
||||
StringBuilder sb = new StringBuilder(); // Add space AFTER you add something. We can trim at end.
|
||||
sb.append(mat).append(" ").append(quantity).append(" ");
|
||||
|
||||
// ItemMeta applies to anything.
|
||||
if (is.hasItemMeta()) {
|
||||
ItemMeta meta = is.getItemMeta();
|
||||
if (meta.hasDisplayName()) {
|
||||
sb.append("name:").append(meta.getDisplayName().replaceAll(" ", "_")).append(" ");
|
||||
}
|
||||
|
||||
if (meta.hasLore()) {
|
||||
sb.append("lore:");
|
||||
boolean first = true;
|
||||
for (String s : meta.getLore()) {
|
||||
// Add | before the line if it's not the first one. Easy but weird way
|
||||
// to do this since we need each line separated by |
|
||||
if (!first) {
|
||||
sb.append("|");
|
||||
}
|
||||
first = false;
|
||||
sb.append(s.replaceAll(" ", "_"));
|
||||
}
|
||||
sb.append(" ");
|
||||
}
|
||||
|
||||
if (meta.hasEnchants()) {
|
||||
for (Enchantment e : meta.getEnchants().keySet()) {
|
||||
sb.append(e.getName().toLowerCase()).append(":").append(meta.getEnchantLevel(e)).append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
Set<ItemFlag> flags = meta.getItemFlags();
|
||||
if (flags != null && !flags.isEmpty()) {
|
||||
sb.append("itemflags:");
|
||||
boolean first = true;
|
||||
for (ItemFlag flag : flags) {
|
||||
if (!first) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(flag.name());
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Material material = is.getType();
|
||||
|
||||
switch (material) {
|
||||
case WRITTEN_BOOK:
|
||||
// Everything from http://wiki.ess3.net/wiki/Item_Meta#Books in that order.
|
||||
// Interesting as I didn't see a way to do pages or chapters.
|
||||
BookMeta bookMeta = (BookMeta) is.getItemMeta();
|
||||
if (bookMeta.hasTitle()) {
|
||||
sb.append("title:").append(bookMeta.getTitle()).append(" ");
|
||||
}
|
||||
if (bookMeta.hasAuthor()) {
|
||||
sb.append("author:").append(bookMeta.getAuthor()).append(" ");
|
||||
}
|
||||
// Only other thing it could have is lore but that's done up there ^^^
|
||||
break;
|
||||
case ENCHANTED_BOOK:
|
||||
EnchantmentStorageMeta enchantmentStorageMeta = (EnchantmentStorageMeta) is.getItemMeta();
|
||||
for (Enchantment e : enchantmentStorageMeta.getStoredEnchants().keySet()) {
|
||||
sb.append(e.getName().toLowerCase()).append(":").append(enchantmentStorageMeta.getStoredEnchantLevel(e)).append(" ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (MaterialUtil.isFirework(material)) {
|
||||
// Everything from http://wiki.ess3.net/wiki/Item_Meta#Fireworks in that order.
|
||||
FireworkMeta fireworkMeta = (FireworkMeta) is.getItemMeta();
|
||||
if (fireworkMeta.hasEffects()) {
|
||||
for (FireworkEffect effect : fireworkMeta.getEffects()) {
|
||||
if (effect.getColors() != null && !effect.getColors().isEmpty()) {
|
||||
sb.append("color:");
|
||||
boolean first = true;
|
||||
for (Color c : effect.getColors()) {
|
||||
if (!first) {
|
||||
sb.append(","); // same thing as above.
|
||||
}
|
||||
sb.append(c.toString());
|
||||
first = false;
|
||||
}
|
||||
sb.append(" ");
|
||||
}
|
||||
|
||||
sb.append("shape:").append(effect.getType().name()).append(" ");
|
||||
if (effect.getFadeColors() != null && !effect.getFadeColors().isEmpty()) {
|
||||
sb.append("fade:");
|
||||
boolean first = true;
|
||||
for (Color c : effect.getFadeColors()) {
|
||||
if (!first) {
|
||||
sb.append(","); // same thing as above.
|
||||
}
|
||||
sb.append(c.toString());
|
||||
first = false;
|
||||
}
|
||||
sb.append(" ");
|
||||
}
|
||||
}
|
||||
sb.append("power:").append(fireworkMeta.getPower()).append(" ");
|
||||
}
|
||||
} else if (MaterialUtil.isPotion(material)) {
|
||||
Potion potion = Potion.fromItemStack(is);
|
||||
for (PotionEffect e : potion.getEffects()) {
|
||||
// long but needs to be effect:speed power:2 duration:120 in that order.
|
||||
sb.append("splash:").append(potion.isSplash()).append(" ").append("effect:").append(e.getType().getName().toLowerCase()).append(" ").append("power:").append(e.getAmplifier()).append(" ").append("duration:").append(e.getDuration() / 20).append(" ");
|
||||
}
|
||||
} else if (MaterialUtil.isPlayerHead(material, is.getData().getData())) {
|
||||
// item stack with meta
|
||||
SkullMeta skullMeta = (SkullMeta) is.getItemMeta();
|
||||
if (skullMeta != null && skullMeta.hasOwner()) {
|
||||
sb.append("player:").append(skullMeta.getOwner()).append(" ");
|
||||
}
|
||||
} else if (MaterialUtil.isBanner(material)) {
|
||||
if (material.toString().contains("SHIELD")) {
|
||||
// Hacky fix for accessing Shield meta - https://github.com/drtshock/Essentials/pull/745#issuecomment-234843795
|
||||
BlockStateMeta shieldMeta = (BlockStateMeta) is.getItemMeta();
|
||||
Banner shieldBannerMeta = (Banner) shieldMeta.getBlockState();
|
||||
DyeColor baseDyeColor = shieldBannerMeta.getBaseColor();
|
||||
if (baseDyeColor != null) {
|
||||
int basecolor = baseDyeColor.getColor().asRGB();
|
||||
sb.append("basecolor:").append(basecolor).append(" ");
|
||||
}
|
||||
for (org.bukkit.block.banner.Pattern p : shieldBannerMeta.getPatterns()) {
|
||||
String type = p.getPattern().getIdentifier();
|
||||
int color = p.getColor().getColor().asRGB();
|
||||
sb.append(type).append(",").append(color).append(" ");
|
||||
}
|
||||
} else {
|
||||
BannerMeta bannerMeta = (BannerMeta) is.getItemMeta();
|
||||
if (bannerMeta != null) {
|
||||
DyeColor baseDyeColor = bannerMeta.getBaseColor();
|
||||
if (baseDyeColor == null) {
|
||||
baseDyeColor = MaterialUtil.getColorOf(material);
|
||||
}
|
||||
if (baseDyeColor != null) {
|
||||
int basecolor = baseDyeColor
|
||||
.getColor()
|
||||
.asRGB();
|
||||
sb.append("basecolor:").append(basecolor).append(" ");
|
||||
}
|
||||
for (org.bukkit.block.banner.Pattern p : bannerMeta.getPatterns()) {
|
||||
String type = p.getPattern().getIdentifier();
|
||||
int color = p.getColor().getColor().asRGB();
|
||||
sb.append(type).append(",").append(color).append(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (MaterialUtil.isLeatherArmor(material)) {
|
||||
LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) is.getItemMeta();
|
||||
int rgb = leatherArmorMeta.getColor().asRGB();
|
||||
sb.append("color:").append(rgb).append(" ");
|
||||
}
|
||||
|
||||
return sb.toString().trim().replaceAll("§", "&");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return ready;
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package com.earth2me.essentials.items;
|
||||
|
||||
import com.earth2me.essentials.Essentials;
|
||||
import com.earth2me.essentials.EssentialsConf;
|
||||
import com.earth2me.essentials.IConf;
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import net.ess3.api.IItemDb;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class CustomItemResolver implements IItemDb.ItemResolver, IConf {
|
||||
private final EssentialsConf config;
|
||||
private final Essentials ess;
|
||||
private final HashMap<String, String> map = new HashMap<>();
|
||||
|
||||
public CustomItemResolver(Essentials ess) {
|
||||
config = new EssentialsConf(new File(ess.getDataFolder(), "custom_items.yml"));
|
||||
this.ess = ess;
|
||||
config.setTemplateName("/custom_items.yml");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack apply(String item) {
|
||||
if (map.containsKey(item)) {
|
||||
try {
|
||||
return ess.getItemDb().get(map.get(item));
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getNames() {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
map.clear();
|
||||
config.load();
|
||||
|
||||
ConfigurationSection section = config.getConfigurationSection("aliases");
|
||||
if (section == null || section.getKeys(false).isEmpty()) {
|
||||
ess.getLogger().warning("No aliases found in custom_items.yml.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (String alias : section.getKeys(false)) {
|
||||
if (!section.isString(alias)) continue;
|
||||
String target = section.getString(alias);
|
||||
|
||||
if (target != null && !section.contains(target) && existsInItemDb(target)) {
|
||||
map.put(alias, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setAlias(String alias, String target) {
|
||||
if (map.containsKey(alias) && map.get(alias).equalsIgnoreCase(target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
map.put(alias, target);
|
||||
save();
|
||||
}
|
||||
|
||||
public void removeAlias(String alias) {
|
||||
if (map.remove(alias) != null) {
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
private void save() {
|
||||
config.setProperty("aliases", map);
|
||||
config.save();
|
||||
}
|
||||
|
||||
private boolean existsInItemDb(String item) {
|
||||
try {
|
||||
ess.getItemDb().get(item);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,720 +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.*;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
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 {
|
||||
|
||||
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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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";
|
||||
|
||||
// Is bStats enabled on this server?
|
||||
private boolean enabled;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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(Plugin plugin, int pluginId) {
|
||||
if (plugin == null) {
|
||||
throw new IllegalArgumentException("Plugin cannot be null!");
|
||||
}
|
||||
this.plugin = plugin;
|
||||
this.pluginId = pluginId;
|
||||
|
||||
// Get the config file
|
||||
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
||||
File configFile = new File(bStatsFolder, "config.yml");
|
||||
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 (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 (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
|
||||
try {
|
||||
service.getField("B_STATS_VERSION"); // Our identifier :)
|
||||
found = true; // We aren't the first
|
||||
break;
|
||||
} catch (NoSuchFieldException ignored) { }
|
||||
}
|
||||
// Register our service
|
||||
Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal);
|
||||
if (!found) {
|
||||
// We are the first!
|
||||
startSubmitting();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(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() {
|
||||
JsonObject data = new JsonObject();
|
||||
|
||||
String pluginName = plugin.getDescription().getName().replace("Essentials", "EssentialsX");
|
||||
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
|
||||
JsonArray customCharts = new JsonArray();
|
||||
for (CustomChart customChart : charts) {
|
||||
// Add the data of the custom charts
|
||||
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;
|
||||
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 (Exception e) {
|
||||
playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed
|
||||
}
|
||||
int onlineMode = Bukkit.getOnlineMode() ? 1 : 0;
|
||||
String bukkitVersion = Bukkit.getVersion();
|
||||
String bukkitName = Bukkit.getName();
|
||||
|
||||
// OS/Java specific data
|
||||
String javaVersion = System.getProperty("java.version");
|
||||
String osName = System.getProperty("os.name");
|
||||
String osArch = System.getProperty("os.arch");
|
||||
String osVersion = System.getProperty("os.version");
|
||||
int coreCount = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
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();
|
||||
|
||||
JsonArray pluginData = new JsonArray();
|
||||
// Search for all other bStats Metrics classes to get their plugin data
|
||||
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
|
||||
try {
|
||||
service.getField("B_STATS_VERSION"); // Our identifier :)
|
||||
|
||||
for (RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service)) {
|
||||
try {
|
||||
Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider());
|
||||
if (plugin instanceof JsonObject) {
|
||||
pluginData.add((JsonObject) plugin);
|
||||
} else { // old bstats version compatibility
|
||||
try {
|
||||
Class<?> jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject");
|
||||
if (plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) {
|
||||
Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString");
|
||||
jsonStringGetter.setAccessible(true);
|
||||
String jsonString = (String) jsonStringGetter.invoke(plugin);
|
||||
JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject();
|
||||
pluginData.add(object);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
// minecraft version 1.14+
|
||||
if (logFailedRequests) {
|
||||
this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { }
|
||||
}
|
||||
} catch (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 (Exception e) {
|
||||
// Something went wrong! :(
|
||||
if (logFailedRequests) {
|
||||
plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(Plugin plugin, 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);
|
||||
}
|
||||
HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
|
||||
|
||||
// Compress the data to save bandwidth
|
||||
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 (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
|
||||
outputStream.write(compressedData);
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try (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;
|
||||
}
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
|
||||
gzip.write(str.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(String chartId) {
|
||||
if (chartId == null || chartId.isEmpty()) {
|
||||
throw new IllegalArgumentException("ChartId cannot be null or empty!");
|
||||
}
|
||||
this.chartId = chartId;
|
||||
}
|
||||
|
||||
private JsonObject getRequestJsonObject() {
|
||||
JsonObject chart = new JsonObject();
|
||||
chart.addProperty("chartId", chartId);
|
||||
try {
|
||||
JsonObject data = getChartData();
|
||||
if (data == null) {
|
||||
// If the data is null we don't send the chart.
|
||||
return null;
|
||||
}
|
||||
chart.add("data", data);
|
||||
} catch (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(String chartId, Callable<String> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
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(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
JsonObject values = new JsonObject();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (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(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
JsonObject values = new JsonObject();
|
||||
Map<String, Map<String, Integer>> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean reallyAllSkipped = true;
|
||||
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
|
||||
JsonObject value = new JsonObject();
|
||||
boolean allSkipped = true;
|
||||
for (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(String chartId, Callable<Integer> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
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(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
JsonObject values = new JsonObject();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (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(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
JsonObject values = new JsonObject();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
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(String chartId, Callable<Map<String, int[]>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
JsonObject values = new JsonObject();
|
||||
Map<String, int[]> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, int[]> entry : map.entrySet()) {
|
||||
if (entry.getValue().length == 0) {
|
||||
continue; // Skip this invalid
|
||||
}
|
||||
allSkipped = false;
|
||||
JsonArray categoryValues = new JsonArray();
|
||||
for (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,142 +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.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MetricsWrapper {
|
||||
|
||||
private final Essentials ess;
|
||||
private final Metrics metrics;
|
||||
private final Map<String, Boolean> commands = new HashMap<>();
|
||||
private final Plugin plugin;
|
||||
|
||||
private static boolean hasWarned = false;
|
||||
private static final List<String> KNOWN_FORCED_METRICS = ImmutableList.of("ChatControl");
|
||||
|
||||
public MetricsWrapper(Plugin plugin, int pluginId, 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(String command, boolean state) {
|
||||
commands.put(command, state);
|
||||
}
|
||||
|
||||
public void addCustomChart(Metrics.CustomChart chart) {
|
||||
metrics.addCustomChart(chart);
|
||||
}
|
||||
|
||||
private void addPermsChart() {
|
||||
metrics.addCustomChart(new Metrics.DrilldownPie("permsPlugin", () -> {
|
||||
Map<String, Map<String, Integer>> result = new HashMap<>();
|
||||
String handler = ess.getPermissionsHandler().getName();
|
||||
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", () -> {
|
||||
Map<String, Map<String, Integer>> result = new HashMap<>();
|
||||
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", () -> {
|
||||
HashMap<String, Integer> result = new HashMap<>();
|
||||
result.put(plugin.getDescription().getVersion(), 1);
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
|
||||
private void addCommandsChart() {
|
||||
for (String command : plugin.getDescription().getCommands().keySet()) {
|
||||
markCommand(command, false);
|
||||
}
|
||||
|
||||
metrics.addCustomChart(new Metrics.AdvancedBarChart("commands", () -> {
|
||||
Map<String, int[]> result = new HashMap<>();
|
||||
for (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 (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
|
||||
try {
|
||||
service.getField("B_STATS_VERSION"); // Identifies bStats classes
|
||||
|
||||
if (KNOWN_FORCED_METRICS.contains(JavaPlugin.getProvidingPlugin(service).getName())) {
|
||||
warnForcedMetrics(service);
|
||||
} else {
|
||||
try {
|
||||
service.getDeclaredField("pluginId"); // Only present in recent bStats classes, which should also have the enabled field unless modified
|
||||
} catch (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 (NoSuchFieldException e) {
|
||||
warnForcedMetrics(service);
|
||||
}
|
||||
}
|
||||
} catch (NoSuchFieldException ignored) {}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void warnForcedMetrics(Class<?> service) {
|
||||
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() + ")");
|
||||
}
|
||||
}
|
||||
@@ -1,35 +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(String context, Function<Player, Iterable<String>> calculator, Supplier<Iterable<String>> suggestions) {
|
||||
ContextCalculator<Player> contextCalculator = new ContextCalculator<Player>() {
|
||||
@Override
|
||||
public void calculate(Player target, ContextConsumer consumer) {
|
||||
calculator.apply(target).forEach(value -> consumer.accept(context, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextSet estimatePotentialContexts() {
|
||||
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() {
|
||||
RegisteredServiceProvider<LuckPerms> provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class);
|
||||
if (provider != null) {
|
||||
luckPerms = provider.getProvider();
|
||||
contextCalculators = new HashSet<>();
|
||||
}
|
||||
return luckPerms != null && super.tryProvider();
|
||||
}
|
||||
}
|
||||
@@ -1,229 +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>
|
||||
*
|
||||
* @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();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Set Plugin data.
|
||||
*
|
||||
* @param plugin Plugin
|
||||
*/
|
||||
void setPlugin(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>
|
||||
*
|
||||
* @author Nijikokun <nijikokun@shortmail.com> (@nijikokun) @copyright: Copyright (C) 2011 @license: AOL license
|
||||
* <http://aol.nexua.org>
|
||||
*/
|
||||
public class Methods {
|
||||
private static String version = null;
|
||||
private static boolean self = false;
|
||||
private static Method Method = null;
|
||||
private static String preferred = "";
|
||||
private static final Set<Method> Methods = new HashSet<>();
|
||||
private static final Set<String> Dependencies = new HashSet<>();
|
||||
private static final Set<Method> Attachables = new HashSet<>();
|
||||
|
||||
static {
|
||||
_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement all methods along with their respective name & class.
|
||||
*/
|
||||
private static void _init() {
|
||||
addMethod("Vault", new com.earth2me.essentials.register.payment.methods.VaultEco());
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the plugin to setup version
|
||||
*
|
||||
* @param v version
|
||||
*/
|
||||
public static void setVersion(String v) {
|
||||
version = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(Plugin plugin) {
|
||||
for (Method method : Methods) {
|
||||
if (method.isCompatible(plugin)) {
|
||||
method.setPlugin(plugin);
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void addMethod(String name, 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(PluginManager manager) {
|
||||
if (hasMethod()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (self) {
|
||||
self = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
boolean match = false;
|
||||
Plugin plugin;
|
||||
|
||||
for (String name : getDependencies()) {
|
||||
if (hasMethod()) {
|
||||
break;
|
||||
}
|
||||
|
||||
plugin = manager.getPlugin(name);
|
||||
if (plugin == null || !plugin.isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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 (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(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(Plugin method) {
|
||||
if (!hasMethod()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Method.isCompatible(method)) {
|
||||
Method = null;
|
||||
}
|
||||
|
||||
return (Method == null);
|
||||
}
|
||||
}
|
||||
@@ -1,283 +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 boolean createAccount(String name, 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(double amount) {
|
||||
return this.economy.format(amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBanks() {
|
||||
return this.economy.hasBankSupport();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBank(String bank) {
|
||||
return this.economy.getBanks().contains(bank);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAccount(String name) {
|
||||
return this.economy.hasAccount(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBankAccount(String bank, String name) {
|
||||
return this.economy.isBankOwner(bank, name).transactionSuccess() || this.economy.isBankMember(bank, name).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createAccount(String name) {
|
||||
return this.economy.createBank(name, "").transactionSuccess();
|
||||
}
|
||||
|
||||
public boolean createAccount(String name, double balance) {
|
||||
if (!this.economy.createBank(name, "").transactionSuccess()) {
|
||||
return false;
|
||||
}
|
||||
return this.economy.bankDeposit(name, balance).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodAccount getAccount(String name) {
|
||||
if (!hasAccount(name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new VaultAccount(name, this.economy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodBankAccount getBankAccount(String bank, String name) {
|
||||
if (!hasBankAccount(bank, name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new VaultBankAccount(bank, economy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompatible(Plugin plugin) {
|
||||
try {
|
||||
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 (LinkageError | Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlugin(Plugin plugin) {
|
||||
this.vault = plugin;
|
||||
RegisteredServiceProvider<Economy> economyProvider = this.vault.getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
|
||||
if (economyProvider != null) {
|
||||
this.economy = economyProvider.getProvider();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class VaultAccount implements MethodAccount {
|
||||
private final String name;
|
||||
private final Economy economy;
|
||||
|
||||
VaultAccount(String name, Economy economy) {
|
||||
this.name = name;
|
||||
this.economy = economy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double balance() {
|
||||
return this.economy.getBalance(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean set(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(double amount) {
|
||||
return this.economy.depositPlayer(this.name, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean subtract(double amount) {
|
||||
return this.economy.withdrawPlayer(this.name, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean multiply(double amount) {
|
||||
double balance = this.balance();
|
||||
return this.set(balance * amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean divide(double amount) {
|
||||
double balance = this.balance();
|
||||
return this.set(balance / amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEnough(double amount) {
|
||||
return (this.balance() >= amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOver(double amount) {
|
||||
return (this.balance() > amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnder(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(String bank, 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(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(double amount) {
|
||||
return this.economy.bankDeposit(this.bank, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean subtract(double amount) {
|
||||
return this.economy.bankWithdraw(this.bank, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean multiply(double amount) {
|
||||
double balance = this.balance();
|
||||
return this.set(balance * amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean divide(double amount) {
|
||||
double balance = this.balance();
|
||||
return this.set(balance / amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEnough(double amount) {
|
||||
return (this.balance() >= amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOver(double amount) {
|
||||
return (this.balance() > amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnder(double amount) {
|
||||
return (this.balance() < amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegative() {
|
||||
return (this.balance() < 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove() {
|
||||
return this.set(0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +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(Map<String, Location> jails) {
|
||||
this.jails = jails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
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(Map<String, Location> spawns) {
|
||||
this.spawns = spawns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Spawns spawns1 = (Spawns) o;
|
||||
return Objects.equals(spawns, spawns1.spawns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(spawns);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +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,29 +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 (String s : mail) {
|
||||
player.sendMessage(s);
|
||||
}
|
||||
player.sendMessage(tl("markMailAsRead"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +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 {
|
||||
private final transient File file;
|
||||
private final transient Class<T> clazz;
|
||||
protected final transient IEssentials plugin;
|
||||
|
||||
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 (IOException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "File can't be closed: " + file.toString(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (FileNotFoundException ex) {
|
||||
onException();
|
||||
if (plugin.getSettings() == null || plugin.getSettings().isDebug()) {
|
||||
Bukkit.getLogger().log(Level.INFO, "File not found: " + file.toString());
|
||||
}
|
||||
} catch (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,45 +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(IEssentials ess, 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 (FileNotFoundException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, file.toString(), ex);
|
||||
} finally {
|
||||
onFinish();
|
||||
if (pw != null) {
|
||||
pw.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract void onFinish();
|
||||
}
|
||||
@@ -1,131 +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 {
|
||||
private transient T data;
|
||||
private final transient ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||
private final transient Class<T> clazz;
|
||||
protected final transient IEssentials ess;
|
||||
|
||||
public AsyncStorageObjectHolder(final IEssentials ess, final Class<T> clazz) {
|
||||
this.ess = ess;
|
||||
this.clazz = clazz;
|
||||
try {
|
||||
this.data = clazz.newInstance();
|
||||
} catch (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 (IllegalAccessException | InstantiationException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
rwl.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 899 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user