mirror of
https://github.com/EssentialsX/Essentials.git
synced 2026-11-05 01:00:13 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b7e7801d0 | ||
|
|
840035944a | ||
|
|
20a7d1c7ee | ||
|
|
253185bd0e | ||
|
|
dae519494e | ||
|
|
dc27af78bf | ||
|
|
41861a8551 | ||
|
|
9b629e42d8 | ||
|
|
7794634d37 | ||
|
|
d091d6902c | ||
|
|
c45c741210 | ||
|
|
e35c65b976 | ||
|
|
0983167740 | ||
|
|
1509cf8978 | ||
|
|
c0082ee734 | ||
|
|
db2ec1b436 | ||
|
|
7a1e50d10f | ||
|
|
b6ba1768a1 | ||
|
|
c38dd997d2 | ||
|
|
f8ca1bae5d | ||
|
|
3c60bcf2de | ||
|
|
3f857e3183 | ||
|
|
668c9634ca | ||
|
|
51c49b0de6 | ||
|
|
5723dac6ba | ||
|
|
680d3230ea | ||
|
|
8f679de352 | ||
|
|
86d435eee1 | ||
|
|
e4cf965bae | ||
|
|
78c846a0a8 | ||
|
|
c466c9c370 | ||
|
|
6994005a5f | ||
|
|
e43f06bfa6 | ||
|
|
9601687190 | ||
|
|
2ed94f1048 | ||
|
|
70045c30f3 | ||
|
|
ce88c0e1e4 | ||
|
|
494e82e581 | ||
|
|
edd15132fd | ||
|
|
add664441e | ||
|
|
58b0fb089f | ||
|
|
90e4845627 | ||
|
|
43f4d306be | ||
|
|
cb7d9baf7a | ||
|
|
f3aea5e6ec | ||
|
|
a7a1fcd98c | ||
|
|
ef8bcc8bc4 | ||
|
|
b3692d18b0 | ||
|
|
a7b2b675d5 | ||
|
|
7d7a8e47ac | ||
|
|
f0da17b75c | ||
|
|
d86b471402 | ||
|
|
767508fb87 | ||
|
|
c85d772e1b | ||
|
|
fde6524e46 | ||
|
|
b2886969f0 | ||
|
|
19ca5186e4 | ||
|
|
b86a34c909 | ||
|
|
d145fbc5cc | ||
|
|
3ca960e31b | ||
|
|
8bbaf7da68 | ||
|
|
14c2ab5ddd | ||
|
|
6f20a789f9 | ||
|
|
4bee15956a | ||
|
|
e4c179f5ed | ||
|
|
4811eb1558 | ||
|
|
69850d82c8 | ||
|
|
df88a89c14 | ||
|
|
c746a1ce17 | ||
|
|
ecdaed7d11 | ||
|
|
c062651821 | ||
|
|
3692740762 | ||
|
|
1179caab88 | ||
|
|
35b1a284f3 | ||
|
|
36432c65e9 | ||
|
|
871e718f63 | ||
|
|
42293596f3 | ||
|
|
ac8a13f039 | ||
|
|
d56ecaacdc | ||
|
|
14fbfe360e | ||
|
|
5334a3fd34 | ||
|
|
2fa9c6486e | ||
|
|
c221e96122 | ||
|
|
26c016fea2 | ||
|
|
b6a08ec712 | ||
|
|
9179c6c1e2 | ||
|
|
3f9aceb922 | ||
|
|
3da8efae49 | ||
|
|
b84207f955 | ||
|
|
f57de40668 | ||
|
|
e95df57642 | ||
|
|
aaddb2af1f | ||
|
|
082950cc18 | ||
|
|
90828965df | ||
|
|
17e026f9aa | ||
|
|
f1d7e50dc0 | ||
|
|
e2cb7b2102 | ||
|
|
28578a5d8a | ||
|
|
0d8e90b8da | ||
|
|
1556b911b2 | ||
|
|
eed73e3157 | ||
|
|
c020526b1e | ||
|
|
cca98e817f | ||
|
|
46a8a7d04c | ||
|
|
d4ddc87d81 | ||
|
|
b473460ffc | ||
|
|
db027bced3 | ||
|
|
12cc0b99f9 | ||
|
|
15cac529c5 | ||
|
|
feed2d6a45 | ||
|
|
b516db669c | ||
|
|
3bc58264ea | ||
|
|
0a0416ae38 | ||
|
|
d244956b4b | ||
|
|
37e3730e9d | ||
|
|
48532a0ae6 | ||
|
|
0b6b0f9c61 | ||
|
|
435ac80ff9 | ||
|
|
a098055fc9 | ||
|
|
cba5063b33 | ||
|
|
3787b80286 | ||
|
|
2858bd3784 | ||
|
|
ff58d8e443 | ||
|
|
5e178943a0 | ||
|
|
33ca3b2981 | ||
|
|
8c8c85d753 | ||
|
|
6535edf4e0 | ||
|
|
7e25570344 | ||
|
|
409210ccde | ||
|
|
555a62c582 | ||
|
|
36a070be4c | ||
|
|
d903e40a53 | ||
|
|
d78729f343 | ||
|
|
a55289196b | ||
|
|
3505b47d8f | ||
|
|
11836e6662 | ||
|
|
4ce38bde36 | ||
|
|
711f701d62 | ||
|
|
94c509b1e2 | ||
|
|
5c08a0e72c | ||
|
|
9c451271e0 | ||
|
|
55db6c2476 | ||
|
|
0861427bf3 | ||
|
|
9d3bf337e1 | ||
|
|
4e4eb35240 | ||
|
|
e7e3f58c8f | ||
|
|
c18830ce75 | ||
|
|
3f36a52685 | ||
|
|
64eb39a417 | ||
|
|
736ecae5ff | ||
|
|
6bd4a6a037 | ||
|
|
4271938c3a | ||
|
|
e1441c1d33 | ||
|
|
9bd35a2cd2 | ||
|
|
d4e194fbf7 | ||
|
|
003d556f3d | ||
|
|
1da3b3f08e | ||
|
|
f08c176b68 | ||
|
|
780aadedf2 | ||
|
|
3fe279e229 | ||
|
|
c43af5d3d9 | ||
|
|
65b80200bd | ||
|
|
6e5a41a880 | ||
|
|
fa87c74b56 | ||
|
|
8142da608c | ||
|
|
eacc748b09 | ||
|
|
def41802b8 | ||
|
|
38dcdff659 | ||
|
|
bd9540cea3 | ||
|
|
0d71fe65f6 | ||
|
|
54c70581a2 | ||
|
|
3abddd6f84 | ||
|
|
8e712bc827 | ||
|
|
2018149395 | ||
|
|
ecea17195a | ||
|
|
a28d0823b2 | ||
|
|
6e6561a267 | ||
|
|
8b1db22a53 | ||
|
|
3d09ea386b | ||
|
|
300daea4f9 | ||
|
|
7653da0e4f | ||
|
|
19b4da07b9 | ||
|
|
ff9f93fba4 | ||
|
|
fed26071ac | ||
|
|
a4fbfbef02 | ||
|
|
347751a826 | ||
|
|
fbb3a9a0a4 | ||
|
|
f8f1facf43 | ||
|
|
0d6441d0b6 | ||
|
|
a009b2f9b5 | ||
|
|
7852aedabd | ||
|
|
b2d7d1b4cb | ||
|
|
ec50b28f4b | ||
|
|
4ed36d9bbe | ||
|
|
887772a428 | ||
|
|
e9169b890d | ||
|
|
b716c04d96 | ||
|
|
2d3cbc9783 | ||
|
|
23a497abf6 | ||
|
|
d00b90cd61 | ||
|
|
f4fe8808a4 | ||
|
|
02193b0523 | ||
|
|
c9310ea429 | ||
|
|
c76e4239bb | ||
|
|
8a8d45c91e | ||
|
|
071f99560e | ||
|
|
8b23c2c4cd | ||
|
|
0d640d1215 | ||
|
|
b4d63857ce | ||
|
|
4976484d91 | ||
|
|
16627d10b6 | ||
|
|
83ca7d2574 | ||
|
|
956afc0382 | ||
|
|
312ff110ec | ||
|
|
214d07c468 | ||
|
|
2c68d1b866 | ||
|
|
5171215817 | ||
|
|
195148a2a2 | ||
|
|
edf664e19a | ||
|
|
0668e4c48a | ||
|
|
d75787726c | ||
|
|
1e0d7fb0a3 | ||
|
|
454698bf98 | ||
|
|
bfeb0ef2ad | ||
|
|
1cf2b11f1e | ||
|
|
0ce4029483 | ||
|
|
504e82e9fd | ||
|
|
eca6a9f247 | ||
|
|
94d4385d41 | ||
|
|
c41bb0ec42 | ||
|
|
00b71cafc9 | ||
|
|
3cd69dabe9 | ||
|
|
10fa3b5a31 | ||
|
|
b43790e9d2 | ||
|
|
ee5f4b9b42 | ||
|
|
e5db842dd6 | ||
|
|
657a11b1f4 | ||
|
|
0ef1e23c69 | ||
|
|
141512f2f7 | ||
|
|
671983724a | ||
|
|
81571fc014 | ||
|
|
f806409d80 | ||
|
|
f3c347424b | ||
|
|
8cbd9b7935 | ||
|
|
158d273dbe | ||
|
|
1258d2f0a1 | ||
|
|
36422ab22b | ||
|
|
191cea7fb3 | ||
|
|
f8cc0e41d1 | ||
|
|
f29f9e1aba | ||
|
|
34fdcf8f6f | ||
|
|
adef08af3e | ||
|
|
1301e8fc99 | ||
|
|
eee1c0628b | ||
|
|
9ce839c9d8 | ||
|
|
401fc4d2eb | ||
|
|
4e7f1377bf | ||
|
|
fccf796eeb | ||
|
|
500edb7860 | ||
|
|
cb168b0c8a | ||
|
|
74131f816c | ||
|
|
f1ef21eb0d | ||
|
|
79406613c1 | ||
|
|
89c1e3b60d | ||
|
|
224634d8d2 | ||
|
|
e42d37e86d | ||
|
|
191c9e9302 | ||
|
|
a482ddf0f6 | ||
|
|
7245e84f00 | ||
|
|
e287600c34 | ||
|
|
817585a9a6 | ||
|
|
eae8bc05c9 | ||
|
|
026d279556 | ||
|
|
8177893e28 | ||
|
|
70de83827d | ||
|
|
5af9536db1 | ||
|
|
cb7b2dabf5 | ||
|
|
01987a0374 | ||
|
|
5528b5b92c | ||
|
|
1838354b70 | ||
|
|
1f1edd9b23 | ||
|
|
2b7a4364b1 | ||
|
|
2f45d3edf3 | ||
|
|
a20d20574e | ||
|
|
d78832498e | ||
|
|
e2c6170eba | ||
|
|
6864af762c | ||
|
|
a8daa2160f | ||
|
|
b84aaa1dab | ||
|
|
c6de77130f | ||
|
|
02ba924f33 | ||
|
|
318df64e54 | ||
|
|
cb45867de8 | ||
|
|
c4ca0e51e2 | ||
|
|
7bb12fd33c | ||
|
|
001213ee2c | ||
|
|
f320705216 | ||
|
|
d4ed77fdc6 | ||
|
|
ef1202923e | ||
|
|
e1e98f5048 | ||
|
|
5bb3cc88e5 | ||
|
|
43eff69a2f | ||
|
|
450da59057 | ||
|
|
dda4d58a23 | ||
|
|
f5d5ed9844 | ||
|
|
2342d53dba | ||
|
|
005d83c6fe | ||
|
|
8c4fb3fefb | ||
|
|
b0fa0d1ec8 | ||
|
|
2ce5797d5e | ||
|
|
c2617e5a1d | ||
|
|
3f73e31d9e | ||
|
|
84a48adbdd | ||
|
|
63c29a318e | ||
|
|
69748fd72e | ||
|
|
35278c6e90 | ||
|
|
088fc35435 | ||
|
|
4baad6b89c | ||
|
|
9a23f806fe | ||
|
|
82b466db0b |
No files matched your search
@@ -24,7 +24,7 @@
|
||||
|
||||
<!-- https://checkstyle.org/config_filters.html#SuppressionFilter -->
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${checkstyle.suppressions.file}"/>
|
||||
<property name="file" value="${configDirectory}/suppressions.xml"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/config_filters.html#SuppressWithPlainTextCommentFilter -->
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
<suppressions>
|
||||
<suppress files=".*[\\/]test[\\/]java[\\/].*" checks="RequireExplicitVisibilityModifier"/>
|
||||
<!-- TODO: don't suppress I-prefixed API interfaces under com.earth2me.essentials -->
|
||||
<suppress files="(com[\\/]earth2me[\\/]essentials[\\/]|net[\\/]ess3[\\/])(?:[^\\/]+$|(?!api)[^\\/]+[\\/])" checks="MissingJavadoc(Method|Type)"/>
|
||||
<suppress files="(com[\\/]earth2me[\\/]essentials[\\/]|net[\\/]ess3[\\/]|net[\\/]essentialsx[\\/])(?:[^\\/]+$|(?!api)[^\\/]+[\\/])" checks="MissingJavadoc(Method|Type)"/>
|
||||
</suppressions>
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
# Currently used
|
||||
patreon: EssentialsX
|
||||
ko_fi: essentialsx
|
||||
github: EssentialsX
|
||||
open_collective: EssentialsX
|
||||
|
||||
# Currently not used
|
||||
#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
#open_collective: # Replace with a single Open Collective username
|
||||
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
#liberapay: # Replace with a single Liberapay username
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: MOSS Discord Server
|
||||
- name: View common issues
|
||||
url: https://github.com/EssentialsX/Essentials/issues/3956
|
||||
about: Check the list of known common issues to see if it solves your problem.
|
||||
- name: Check past help requests
|
||||
url: https://github.com/EssentialsX/Essentials/discussions/categories/q-a
|
||||
about: Visit the Q&A forum to search for previous help requests.
|
||||
- name: Check past feature suggestions
|
||||
url: https://github.com/EssentialsX/Essentials/discussions/categories/ideas-and-feature-suggestions
|
||||
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: Suggest a feature
|
||||
url: https://github.com/EssentialsX/Essentials/discussions/new?category=ideas-and-feature-suggestions
|
||||
about: Suggest new features for EssentialsX!
|
||||
- name: Get help from the community on Discord
|
||||
url: https://discord.gg/casfFyh
|
||||
about: Need help with using EssentialsX? Join the MOSS Discord server for help.
|
||||
about: Join the MOSS Discord for community-powered EssentialsX support!
|
||||
@@ -1,86 +0,0 @@
|
||||
---
|
||||
name: Help!
|
||||
about: Encountered a problem with EssentialsX? Not sure how to fix it?
|
||||
labels: 'type: question'
|
||||
|
||||
---
|
||||
|
||||
<!-- EssentialsX help request guide
|
||||
|
||||
NOTE: Failure to fill out this template properly may result in your issue being
|
||||
delayed or ignored.
|
||||
|
||||
Don't type between any arrows in the template, as this text will be hidden.
|
||||
This includes this header block and any other explanatory text blocks.
|
||||
|
||||
Want faster support? Come join our Discord server to get help from both
|
||||
developers and community members: https://discord.gg/F7gexAQ
|
||||
|
||||
If you're happy to wait (or you were sent here from Discord), read on:
|
||||
|
||||
1. Check the Common Issues page.
|
||||
Read through the wiki page to see if you've encountered a regular issue:
|
||||
https://essentialsx.net/wiki/Common-Issues.html
|
||||
|
||||
2. Fill out the template.
|
||||
Run the commands in the console. Don't just put "latest" as a version, or
|
||||
we will ignore it. This will help us understand what problem you've
|
||||
encountered and help us find a solution.
|
||||
|
||||
3. When linking logs or config files, do not attach them to the post!
|
||||
Copy and paste any logs into https://gist.github.com/, then paste a
|
||||
link to them in the relevant parts of the template. Do not use Hastebin
|
||||
or Pastebin, as this can cause issues when trying to solve issues in the
|
||||
future.
|
||||
**DO NOT drag logs into this text box!**
|
||||
|
||||
4. If you are encountering a performance issue, please include a link to a
|
||||
Timings and/or profiler report.
|
||||
|
||||
-->
|
||||
|
||||
### Information
|
||||
|
||||
**Full output of `/ess version`:**
|
||||
<!--
|
||||
Run /ess version in the console, then paste the full output of the command
|
||||
between the ```s.
|
||||
-->
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
**Server startup log:**
|
||||
<!--
|
||||
Restart your server and upload `logs/latest.log` to
|
||||
https://gist.github.com/. You may redact sensitive data (such as IP
|
||||
addresses), but you should make it clear what data was removed. Once
|
||||
uploaded, paste the link below this block.
|
||||
-->
|
||||
|
||||
|
||||
**EssentialsX config:**
|
||||
<!--
|
||||
Upload `plugins/Essentials/config.yml` (and other config files if relevant)
|
||||
to https://gist.github.com/ then paste the link below this block.
|
||||
-->
|
||||
|
||||
|
||||
### Help request
|
||||
|
||||
**Problem:**
|
||||
<!-- What problem did you encounter? Type below this line. -->
|
||||
|
||||
**What I have tried:**
|
||||
<!-- What have you tried so far? Type below this line. -->
|
||||
|
||||
**Console stack trace:**
|
||||
<!--
|
||||
If you are reporting an error in the console, paste it between the ```s.
|
||||
-->
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
**Screenshots:**
|
||||
<!-- If relevant, include any screenshots or a video below this line. -->
|
||||
@@ -1,83 +0,0 @@
|
||||
---
|
||||
name: Report a bug
|
||||
about: Report an EssentialsX bug. Only use this if you're 100% sure there's something wrong with EssentialsX - otherwise, try "Help!".
|
||||
labels: 'bug: unconfirmed'
|
||||
|
||||
---
|
||||
|
||||
<!-- EssentialsX bug reporting guide
|
||||
|
||||
NOTE: Failure to fill out this template properly may result in your issue being
|
||||
delayed or ignored.
|
||||
|
||||
Don't type between any arrows in the template, as this text will be hidden.
|
||||
This includes this header block and any other explanatory text blocks.
|
||||
|
||||
If you are reporting a bug, please follow the following steps:
|
||||
|
||||
1. Fill out the template in full.
|
||||
Run the commands in the console. Don't just put "latest" as a version,
|
||||
or we will ignore it.
|
||||
|
||||
2. When linking files, do not attach them to the post!
|
||||
Copy and paste any logs into https://gist.github.com/, then paste a
|
||||
link to them in the relevant parts of the template. Avoid using
|
||||
Hastebin or Pastebin, as this makes providing support more difficult.
|
||||
**DO NOT drag files into this text box!**
|
||||
|
||||
3. If you are reporting a performance issue, please include a link to a
|
||||
Timings and/or profiler report.
|
||||
|
||||
4. If you are reporting a bug with commands or something else in-game,
|
||||
please include screenshots to help us diagnose the problem.
|
||||
|
||||
-->
|
||||
|
||||
### Information
|
||||
|
||||
**Full output of `/ess version`:**
|
||||
<!--
|
||||
Run /ess version in the console, then paste the full output of the command
|
||||
between the ```s.
|
||||
-->
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
**Server startup log:**
|
||||
<!--
|
||||
Restart your server and upload `logs/latest.log` to
|
||||
https://gist.github.com/. You may redact sensitive data (such as IP
|
||||
addresses), but you should make it clear what data was removed. Once
|
||||
uploaded, paste the link below this block.
|
||||
-->
|
||||
|
||||
|
||||
**EssentialsX config:**
|
||||
<!--
|
||||
Upload `plugins/Essentials/config.yml` (and other config files if relevant)
|
||||
to https://gist.github.com/ then paste the link below this block.
|
||||
-->
|
||||
|
||||
|
||||
### Details
|
||||
|
||||
**Description:**
|
||||
<!-- What is the bug? Type a brief summary below this line. -->
|
||||
|
||||
**Steps to reproduce:**
|
||||
<!-- How did you cause it? Describe what you did to cause the bug below. -->
|
||||
|
||||
**Expected behavior:**
|
||||
<!-- What did you expect to happen? Type below this line. -->
|
||||
|
||||
**Console stack trace:**
|
||||
<!--
|
||||
If you are encountering an error in the console, paste it between the ```s.
|
||||
-->
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
**Screenshots:**
|
||||
<!-- If necessary, include screenshots or a video below this line. -->
|
||||
@@ -0,0 +1,79 @@
|
||||
name: Report bug
|
||||
description: Report a bug in EssentialsX.
|
||||
labels: 'bug: unconfirmed'
|
||||
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: markdown
|
||||
attributes:
|
||||
value: |
|
||||
In the text box below, 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.
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
---
|
||||
name: Request a feature
|
||||
about: Suggest a feature you want to see in EssentialsX!
|
||||
labels: 'type: enhancement'
|
||||
|
||||
---
|
||||
|
||||
<!-- EssentialsX feature request guide
|
||||
|
||||
NOTE: Failure to fill out this template properly may result in your issue being
|
||||
delayed or ignored.
|
||||
|
||||
Don't type between any arrows in the template, as this text will be hidden.
|
||||
This includes this header block and any other explanatory text blocks.
|
||||
|
||||
Not sure if your feature fits in EssentialsX? Feel free to ask on our Discord
|
||||
server: https://discord.gg/F7gexAQ
|
||||
|
||||
If you have a feature suggestion for EssentialsX, read the following tips:
|
||||
|
||||
1. Fill out the template.
|
||||
This will help us understand what you're requesting and why you want us
|
||||
to add it.
|
||||
|
||||
2. Keep it simple.
|
||||
Make sure it's easy to understand what you're requesting. A good way is
|
||||
to keep it to one request per GitHub issue, as we can then easily track
|
||||
feature requests.
|
||||
|
||||
3. Check whether it has already been asked or added.
|
||||
You can search the issue tracker to see if your feature has already been
|
||||
requested at https://github.com/EssentialsX/Essentials/issues. You can
|
||||
also check the changelogs to see if the feature was recently added:
|
||||
https://github.com/EssentialsX/Essentials/releases
|
||||
|
||||
4. Ask yourself: "Does this belong in EssentialsX?"
|
||||
There are lots of features that we reject because most servers won't
|
||||
need or use them. If your feature is very specific or already exists in
|
||||
another plugin, it might not be a good fit for EssentialsX.
|
||||
|
||||
-->
|
||||
|
||||
### Feature request
|
||||
|
||||
**Feature description:**
|
||||
<!-- What feature are you suggesting? Type below this line. -->
|
||||
|
||||
**How the feature is useful:**
|
||||
<!--
|
||||
How is the feature useful to players, server owners and/or developers?
|
||||
Type below this block.
|
||||
-->
|
||||
@@ -1,24 +1,30 @@
|
||||
---
|
||||
name: Bug fix
|
||||
about: Use this if your PR fixes a bug in EssentialsX.
|
||||
labels: 'type: bugfix'
|
||||
---
|
||||
<!--
|
||||
|
||||
<!-- EssentialsX bug fix submission guide
|
||||
EssentialsX bug fix submission guide
|
||||
====================================
|
||||
|
||||
NOTE: Failure to fill out this template properly may result in your PR being
|
||||
delayed or ignored without warning.
|
||||
|
||||
Don't type between any arrows in the template, as this text will be hidden.
|
||||
This includes this header block and any other explanatory text blocks.
|
||||
NOTE: Don't type between any arrows in the template, as this text will be
|
||||
hidden. This includes this header block and any other explanation text
|
||||
blocks.
|
||||
|
||||
Want to discuss your PR before submitting it? Join the EssentialsX Development
|
||||
server: https://discord.gg/CUN7qVb
|
||||
|
||||
|
||||
EssentialsX is GPL
|
||||
------------------
|
||||
|
||||
By contributing to EssentialsX, you agree to license your code under the
|
||||
GNU General Public License version 3, which can be found at the link below:
|
||||
https://github.com/EssentialsX/Essentials/blob/2.x/LICENSE
|
||||
|
||||
|
||||
Instructions
|
||||
------------
|
||||
|
||||
If you are submitting a bug fix, please follow the following steps:
|
||||
|
||||
1. Fill out the template in full.
|
||||
@@ -34,14 +40,15 @@ If you are submitting a bug fix, please follow the following steps:
|
||||
Copy and paste any logs into https://gist.github.com/, then paste a
|
||||
link to them in the relevant parts of the template. Do not use Hastebin
|
||||
or Pastebin, as this can cause issues with future reviews.
|
||||
**DO NOT drag logs into this text box!**
|
||||
|
||||
DO NOT drag logs directly into this text box, as we cannot read these!
|
||||
|
||||
3. If you are fixing a performance issue, please include a link to a
|
||||
Timings and/or profiler report, both before and after your PR.
|
||||
|
||||
4. If you are fixing a visual bug, such as in commands, please include
|
||||
screenshots so that we can more easily review the proposed fix.
|
||||
(You may drag screenshots directly into this box.)
|
||||
(You can drag screenshots into the bottom of the editor.)
|
||||
|
||||
-->
|
||||
|
||||
@@ -61,17 +68,21 @@ This PR fixes #nnnn.
|
||||
|
||||
|
||||
**Environments tested:**
|
||||
<!--
|
||||
Below this line, put an "x" inside the box for the environments you have
|
||||
tested this bug fix on, and if relevant alter the OS and Java version
|
||||
accordingly. If this feature does not apply to an environment, strike
|
||||
through the environment using ~~strikethrough~~. If you have tested on
|
||||
other environments, add a new line with relevant details.
|
||||
-->
|
||||
|
||||
- [ ] [Latest](https://papermc.io/downloads) Paper Version (any OS, any Java 8+ version)
|
||||
- [ ] CraftBukkit/Spigot/Paper 1.12.2 (any OS, any Java 8+ version)
|
||||
- [ ] CraftBukkit 1.8.8 (any OS, any Java 8+ version)
|
||||
<!-- Type the OS you have used below. -->
|
||||
OS:
|
||||
|
||||
<!-- Type the JDK version (from java -version) you have used below. -->
|
||||
Java version:
|
||||
|
||||
<!--
|
||||
Put an "x" inside the boxes for the server software you have tested this
|
||||
bug fix on. If this feature does not apply to a server, strike through the server software using ~~strikethrough~~. If you have tested on other
|
||||
environments, add a new line with relevant details.
|
||||
-->
|
||||
- [ ] Most recent Paper version (1.XX.Y, git-Paper-BUILD)
|
||||
- [ ] CraftBukkit/Spigot/Paper 1.12.2
|
||||
- [ ] CraftBukkit 1.8.8
|
||||
|
||||
|
||||
**Demonstration:**
|
||||
@@ -80,3 +91,4 @@ This PR fixes #nnnn.
|
||||
necessary. If you have created or used a test case plugin, please link to a
|
||||
download of the plugin, source code and exact version used where possible.
|
||||
-->
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
---
|
||||
name: Feature addition
|
||||
about: Use this if your PR adds a new feature to EssentialsX.
|
||||
labels: 'type: enhancement'
|
||||
---
|
||||
<!--
|
||||
|
||||
<!-- EssentialsX feature submission guide
|
||||
EssentialsX feature submission guide
|
||||
====================================
|
||||
|
||||
NOTE: Failure to fill out this template properly may result in your PR being
|
||||
delayed or ignored without warning.
|
||||
|
||||
Don't type between any arrows in the template, as this text will be hidden.
|
||||
This includes this header block and any other explanatory text blocks.
|
||||
NOTE: Don't type between any arrows in the template, as this text will be
|
||||
hidden. This includes this header block and any other explanation text
|
||||
blocks.
|
||||
|
||||
Want to discuss your PR before submitting it? Join the EssentialsX Development
|
||||
server: https://discord.gg/CUN7qVb
|
||||
|
||||
|
||||
EssentialsX is GPL
|
||||
------------------
|
||||
|
||||
By contributing to EssentialsX, you agree to license your code under the
|
||||
GNU General Public License version 3, which can be found at the link below:
|
||||
https://github.com/EssentialsX/Essentials/blob/2.x/LICENSE
|
||||
|
||||
|
||||
Instructions
|
||||
------------
|
||||
|
||||
If you are submitting a new feature, please follow the following steps:
|
||||
|
||||
1. Fill out the template in full.
|
||||
@@ -57,26 +63,31 @@ This PR closes #nnnn.
|
||||
|
||||
### Details
|
||||
|
||||
**Proposed feature**
|
||||
**Proposed feature:**
|
||||
<!-- Type a description of your proposed feature below this line. -->
|
||||
|
||||
**Environments tested:**
|
||||
<!--
|
||||
Below this block, put an "x" inside the box for the environments you have
|
||||
tested this bug fix on, and if relevant alter the OS and Java version
|
||||
accordingly. If this feature does not apply to an environment, strike
|
||||
through the environment using ~~strikethrough~~. If you have tested on
|
||||
other environments, add a new line with relevant details.
|
||||
-->
|
||||
|
||||
- [ ] [Latest](https://papermc.io/downloads) Paper Version (any OS, any Java 8+ version)
|
||||
- [ ] CraftBukkit/Spigot/Paper 1.12.2 (any OS, any Java 8+ version)
|
||||
- [ ] CraftBukkit 1.8.8 (any OS, any Java 8+ version)
|
||||
**Environments tested:**
|
||||
|
||||
<!-- Type the OS you have used below. -->
|
||||
OS:
|
||||
|
||||
<!-- Type the JDK version (from java -version) you have used below. -->
|
||||
Java version:
|
||||
|
||||
<!--
|
||||
Put an "x" inside the boxes for the server software you have tested this
|
||||
bug fix on. If this feature does not apply to a server, strike through the server software using ~~strikethrough~~. If you have tested on other
|
||||
environments, add a new line with relevant details.
|
||||
-->
|
||||
- [ ] Most recent Paper version (1.XX.Y, git-Paper-BUILD)
|
||||
- [ ] CraftBukkit/Spigot/Paper 1.12.2
|
||||
- [ ] CraftBukkit 1.8.8
|
||||
|
||||
|
||||
**Demonstration:**
|
||||
<!--
|
||||
Below this block, include screenshots/code snippets from before and after
|
||||
as necessary. If you have created or used a test case plugin, please link
|
||||
to a download of the plugin, source code and exact version used where
|
||||
possible.
|
||||
Below this block, include screenshots/log snippets from before and after as
|
||||
necessary. If you have created or used a test case plugin, please link to a
|
||||
download of the plugin, source code and exact version used where possible.
|
||||
-->
|
||||
@@ -0,0 +1,10 @@
|
||||
You need to select a pull request template!
|
||||
|
||||
If you're adding a new feature, copy and paste the following parameter at the end of the URL:
|
||||
?template=new-feature.md
|
||||
|
||||
If you're fixing a bug, copy and paste the following parameter at the end of the URL:
|
||||
?template=bug-fix.md
|
||||
|
||||
For more information about contributing to EssentialsX, see CONTRIBUTING.md:
|
||||
https://github.com/EssentialsX/Essentials/blob/2.x/CONTRIBUTING.md
|
||||
@@ -0,0 +1,74 @@
|
||||
name: Build EssentialsX
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 2.x
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and upload
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Git repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Restore Gradle cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
|
||||
- name: Set up JDK 16
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: 16
|
||||
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
|
||||
- name: Build with Gradle
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
./gradlew build --stacktrace
|
||||
|
||||
- name: Archive plugin jars on GitHub
|
||||
uses: actions/upload-artifact@master
|
||||
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
|
||||
if: ${{ success() && github.event_name == 'push' && github.repository == 'EssentialsX/Essentials' && github.ref == 'refs/heads/2.x' }}
|
||||
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 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: Deploy Javadocs
|
||||
if: ${{ success() && github.event_name == 'push' && github.repository == 'EssentialsX/Essentials' && github.ref == 'refs/heads/2.x' }}
|
||||
uses: netlify/actions/cli@master
|
||||
with:
|
||||
args: 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,50 @@
|
||||
name: Build Pull Request
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- mc/* # MC version updates
|
||||
- pr/* # PR rebases
|
||||
pull_request:
|
||||
branches:
|
||||
- 2.x
|
||||
- mc/*
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and upload
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Git repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Restore Gradle cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
|
||||
- name: Set up JDK 16
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: 16
|
||||
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
|
||||
- name: Build with Gradle
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
./gradlew build --stacktrace
|
||||
|
||||
- name: Archive plugin jars on GitHub
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: EssentialsX plugin jars
|
||||
path: jars/
|
||||
@@ -1,38 +0,0 @@
|
||||
name: Build EssentialsX
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 2.x
|
||||
- mc/*
|
||||
pull_request:
|
||||
branches:
|
||||
- 2.x
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Git repo
|
||||
uses: actions/checkout@v1
|
||||
- name: Restore Maven cache
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maven-
|
||||
- name: Set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
- name: Build with Maven
|
||||
run: mvn package verify --file pom.xml
|
||||
- name: Copy artifacts
|
||||
run: mkdir -p ./out/ && cp -t ./out/ **/target/Essentials*.jar
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: Plugin jars
|
||||
path: out/
|
||||
+8
-2
@@ -17,6 +17,12 @@
|
||||
/Essentials/usermap.csv
|
||||
|
||||
# Build files
|
||||
target/
|
||||
jars/
|
||||
.gradle/
|
||||
/jars/
|
||||
out/
|
||||
build/
|
||||
target/
|
||||
*.class
|
||||
|
||||
# Run directory
|
||||
/run/
|
||||
Generated
+3
-3
@@ -9,11 +9,11 @@
|
||||
<entry key="location-0" value="BUNDLED:(bundled):Sun Checks" />
|
||||
<entry key="location-1" value="BUNDLED:(bundled):Google Checks" />
|
||||
<entry key="location-2" value="PROJECT_RELATIVE:$PROJECT_DIR$/.checkstyle/checkstyle.xml:EssentialsX" />
|
||||
<entry key="property-2.checkstyle.suppressions.file" value=".checkstyle/suppressions.xml" />
|
||||
<entry key="scan-before-checkin" value="false" />
|
||||
<entry key="property-2.configDirectory" value=".checkstyle/" />
|
||||
<entry key="scan-before-checkin" value="true" />
|
||||
<entry key="scanscope" value="JavaOnly" />
|
||||
<entry key="suppress-errors" value="false" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
||||
@@ -0,0 +1,58 @@
|
||||
plugins {
|
||||
id("essentials.shadow-module")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly('com.github.milkbowl:VaultAPI:1.7') {
|
||||
exclude group: "org.bukkit", module: "bukkit"
|
||||
}
|
||||
compileOnly 'net.luckperms:api:5.0'
|
||||
|
||||
api 'io.papermc:paperlib:1.0.6'
|
||||
|
||||
api 'org.bstats:bstats-bukkit:2.2.1'
|
||||
|
||||
implementation 'org.spongepowered:configurate-yaml:4.1.2'
|
||||
implementation 'org.checkerframework:checker-qual:3.14.0'
|
||||
|
||||
// Providers
|
||||
api project(':providers:BaseProviders')
|
||||
api project(':providers:PaperProvider')
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
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 (project(':providers:BaseProviders'))
|
||||
include (project(':providers:PaperProvider'))
|
||||
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'
|
||||
|
||||
minimize {
|
||||
include(dependency('org.checkerframework:checker-qual'))
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>EssentialsXParent</artifactId>
|
||||
<version>2.18.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>EssentialsX</artifactId>
|
||||
|
||||
<build>
|
||||
<finalName>EssentialsX-${full.version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<configuration>
|
||||
<showDeprecation>false</showDeprecation>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>io.papermc.lib</pattern>
|
||||
<shadedPattern>com.earth2me.essentials.paperlib</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.milkbowl</groupId>
|
||||
<artifactId>VaultAPI</artifactId>
|
||||
<version>1.7</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.luckperms</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>5.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.papermc</groupId>
|
||||
<artifactId>paperlib</artifactId>
|
||||
<version>1.0.6-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>BaseProviders</artifactId>
|
||||
<version>2.18.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>NMSReflectionProvider</artifactId>
|
||||
<version>2.18.2</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>PaperProvider</artifactId>
|
||||
<version>2.18.2</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.destroystokyo.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>1_8Provider</artifactId>
|
||||
<version>2.18.2</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,108 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.command.PluginCommandYamlParser;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class AlternativeCommandsHandler {
|
||||
private static final Logger LOGGER = Logger.getLogger("Essentials");
|
||||
private final transient Map<String, List<PluginCommand>> altcommands = new HashMap<>();
|
||||
private final transient Map<String, String> disabledList = new HashMap<>();
|
||||
private final transient IEssentials ess;
|
||||
|
||||
public AlternativeCommandsHandler(final IEssentials ess) {
|
||||
this.ess = ess;
|
||||
for (final Plugin plugin : ess.getServer().getPluginManager().getPlugins()) {
|
||||
if (plugin.isEnabled()) {
|
||||
addPlugin(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void addPlugin(final Plugin plugin) {
|
||||
if (plugin.getDescription().getMain().contains("com.earth2me.essentials")) {
|
||||
return;
|
||||
}
|
||||
final List<Command> commands = PluginCommandYamlParser.parse(plugin);
|
||||
final String pluginName = plugin.getDescription().getName().toLowerCase(Locale.ENGLISH);
|
||||
|
||||
for (final Command command : commands) {
|
||||
final PluginCommand pc = (PluginCommand) command;
|
||||
final List<String> labels = new ArrayList<>(pc.getAliases());
|
||||
labels.add(pc.getName());
|
||||
|
||||
PluginCommand reg = ess.getServer().getPluginCommand(pluginName + ":" + pc.getName().toLowerCase(Locale.ENGLISH));
|
||||
if (reg == null) {
|
||||
reg = ess.getServer().getPluginCommand(pc.getName().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
if (reg == null || !reg.getPlugin().equals(plugin)) {
|
||||
continue;
|
||||
}
|
||||
for (final String label : labels) {
|
||||
final List<PluginCommand> plugincommands = altcommands.computeIfAbsent(label.toLowerCase(Locale.ENGLISH), k -> new ArrayList<>());
|
||||
boolean found = false;
|
||||
for (final PluginCommand pc2 : plugincommands) {
|
||||
if (pc2.getPlugin().equals(plugin)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
plugincommands.add(reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removePlugin(final Plugin plugin) {
|
||||
final Iterator<Map.Entry<String, List<PluginCommand>>> iterator = altcommands.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final Map.Entry<String, List<PluginCommand>> entry = iterator.next();
|
||||
entry.getValue().removeIf(pc -> pc.getPlugin() == null || pc.getPlugin().equals(plugin));
|
||||
if (entry.getValue().isEmpty()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PluginCommand getAlternative(final String label) {
|
||||
final List<PluginCommand> commands = altcommands.get(label);
|
||||
if (commands == null || commands.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (commands.size() == 1) {
|
||||
return commands.get(0);
|
||||
}
|
||||
// return the first command that is not an alias
|
||||
for (final PluginCommand command : commands) {
|
||||
if (command.getName().equalsIgnoreCase(label)) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
// return the first alias
|
||||
return commands.get(0);
|
||||
}
|
||||
|
||||
public void executed(final String label, final PluginCommand pc) {
|
||||
final String altString = pc.getPlugin().getName() + ":" + pc.getLabel();
|
||||
if (ess.getSettings().isDebug()) {
|
||||
LOGGER.log(Level.INFO, "Essentials: Alternative command " + label + " found, using " + altString);
|
||||
}
|
||||
disabledList.put(label, altString);
|
||||
}
|
||||
|
||||
public Map<String, String> disabledCommands() {
|
||||
return disabledList;
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.MemoryConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.earth2me.essentials.I18n.capitalCase;
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Kits implements IConf {
|
||||
|
||||
private final EssentialsConf config;
|
||||
private ConfigurationSection kits;
|
||||
|
||||
public Kits(final IEssentials essentials) {
|
||||
config = new EssentialsConf(new File(essentials.getDataFolder(), "kits.yml"));
|
||||
config.setTemplateName("/kits.yml");
|
||||
|
||||
reloadConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
config.load();
|
||||
kits = _getKits();
|
||||
}
|
||||
|
||||
private ConfigurationSection _getKits() {
|
||||
if (config.isConfigurationSection("kits")) {
|
||||
final ConfigurationSection section = config.getConfigurationSection("kits");
|
||||
final ConfigurationSection newSection = new MemoryConfiguration();
|
||||
for (final String kitItem : section.getKeys(false)) {
|
||||
if (section.isConfigurationSection(kitItem)) {
|
||||
newSection.set(kitItem.toLowerCase(Locale.ENGLISH), section.getConfigurationSection(kitItem));
|
||||
}
|
||||
}
|
||||
return newSection;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public EssentialsConf getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public ConfigurationSection getKits() {
|
||||
return kits;
|
||||
}
|
||||
|
||||
public Map<String, Object> getKit(String name) {
|
||||
name = name.replace('.', '_').replace('/', '_');
|
||||
if (getKits() != null) {
|
||||
final ConfigurationSection kits = getKits();
|
||||
// For some reason, YAML doesn't sees keys as always lowercase even if they aren't defined like that.
|
||||
// Workaround is to toLowercase when getting from the config, but showing normally elsewhere.
|
||||
// ODDLY ENOUGH when you get the configuration section for ALL kits, it will return the proper
|
||||
// case of each kit. But when you check for each kit's configuration section, it won't return the kit
|
||||
// you just found if you don't toLowercase it.
|
||||
if (kits.isConfigurationSection(name.toLowerCase())) {
|
||||
return kits.getConfigurationSection(name.toLowerCase()).getValues(true);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Tries to find an existing kit name that matches the given name, ignoring case. Returns null if no match.
|
||||
public String matchKit(final String name) {
|
||||
if (config.isConfigurationSection("kits")) {
|
||||
final ConfigurationSection section = config.getConfigurationSection("kits");
|
||||
if (section != null) {
|
||||
for (final String kitName : section.getKeys(false)) {
|
||||
if (kitName.equalsIgnoreCase(name)) {
|
||||
return kitName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addKit(final String name, final List<String> lines, final long delay) {
|
||||
// Will overwrite but w/e
|
||||
config.set("kits." + name + ".delay", delay);
|
||||
config.set("kits." + name + ".items", lines);
|
||||
kits = _getKits();
|
||||
config.save();
|
||||
}
|
||||
|
||||
public void removeKit(final String name) {
|
||||
config.set("kits." + name, null);
|
||||
kits = _getKits();
|
||||
config.save();
|
||||
}
|
||||
|
||||
public String listKits(final net.ess3.api.IEssentials ess, final User user) throws Exception {
|
||||
try {
|
||||
final ConfigurationSection kits = config.getConfigurationSection("kits");
|
||||
final StringBuilder list = new StringBuilder();
|
||||
for (final String kitItem : kits.getKeys(false)) {
|
||||
if (user == null) {
|
||||
list.append(" ").append(capitalCase(kitItem));
|
||||
} else if (user.isAuthorized("essentials.kits." + kitItem.toLowerCase(Locale.ENGLISH))) {
|
||||
String cost = "";
|
||||
String name = capitalCase(kitItem);
|
||||
final BigDecimal costPrice = new Trade("kit-" + kitItem.toLowerCase(Locale.ENGLISH), ess).getCommandCost(user);
|
||||
if (costPrice.signum() > 0) {
|
||||
cost = tl("kitCost", NumberUtil.displayCurrency(costPrice, ess));
|
||||
}
|
||||
|
||||
final Kit kit = new Kit(kitItem, ess);
|
||||
final double nextUse = kit.getNextUse(user);
|
||||
if (nextUse == -1 && ess.getSettings().isSkippingUsedOneTimeKitsFromKitList()) {
|
||||
continue;
|
||||
} else if (nextUse != 0) {
|
||||
name = tl("kitDelay", name);
|
||||
}
|
||||
|
||||
list.append(" ").append(name).append(cost);
|
||||
}
|
||||
}
|
||||
return list.toString().trim();
|
||||
} catch (final Exception ex) {
|
||||
throw new Exception(tl("kitError"), ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,15 +0,0 @@
|
||||
package com.earth2me.essentials.api;
|
||||
|
||||
/**
|
||||
* Represents a storage object that is reloadable.
|
||||
*
|
||||
* @deprecated This is a remnant of the abandoned 3.x storage system. Neither future 2.x code nor external plugins
|
||||
* should use this interface.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface IReload {
|
||||
/**
|
||||
* Reloads the given storage object.
|
||||
*/
|
||||
void onReload();
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.textreader.SimpleTextInput;
|
||||
import com.earth2me.essentials.textreader.TextPager;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandbalancetop extends EssentialsCommand {
|
||||
public static final int MINUSERS = 50;
|
||||
private static final int CACHETIME = 2 * 60 * 1000;
|
||||
private static final SimpleTextInput cache = new SimpleTextInput();
|
||||
private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private static long cacheage = 0;
|
||||
|
||||
public Commandbalancetop() {
|
||||
super("balancetop");
|
||||
}
|
||||
|
||||
private static void outputCache(final CommandSource sender, final int page) {
|
||||
final Calendar cal = Calendar.getInstance();
|
||||
cal.setTimeInMillis(cacheage);
|
||||
final DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
|
||||
sender.sendMessage(tl("balanceTop", format.format(cal.getTime())));
|
||||
new TextPager(cache).showPage(Integer.toString(page), null, "balancetop", sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
int page = 0;
|
||||
boolean force = false;
|
||||
if (args.length > 0) {
|
||||
try {
|
||||
page = Integer.parseInt(args[0]);
|
||||
} catch (final NumberFormatException ex) {
|
||||
if (args[0].equalsIgnoreCase("force") && (!sender.isPlayer() || ess.getUser(sender.getPlayer()).isAuthorized("essentials.balancetop.force"))) {
|
||||
force = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!force && lock.readLock().tryLock()) {
|
||||
try {
|
||||
if (cacheage > System.currentTimeMillis() - CACHETIME) {
|
||||
outputCache(sender, page);
|
||||
return;
|
||||
}
|
||||
if (ess.getUserMap().getUniqueUsers() > MINUSERS) {
|
||||
sender.sendMessage(tl("orderBalances", ess.getUserMap().getUniqueUsers()));
|
||||
}
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
} else {
|
||||
if (ess.getUserMap().getUniqueUsers() > MINUSERS) {
|
||||
sender.sendMessage(tl("orderBalances", ess.getUserMap().getUniqueUsers()));
|
||||
}
|
||||
}
|
||||
ess.runTaskAsynchronously(new Viewer(sender, commandLabel, page, force));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
final List<String> options = Lists.newArrayList("1");
|
||||
if (!sender.isPlayer() || ess.getUser(sender.getPlayer()).isAuthorized("essentials.balancetop.force")) {
|
||||
options.add("force");
|
||||
}
|
||||
return options;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private class Calculator implements Runnable {
|
||||
private final transient Viewer viewer;
|
||||
private final boolean force;
|
||||
|
||||
Calculator(final Viewer viewer, final boolean force) {
|
||||
this.viewer = viewer;
|
||||
this.force = force;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
if (force || cacheage <= System.currentTimeMillis() - CACHETIME) {
|
||||
cache.getLines().clear();
|
||||
final Map<String, BigDecimal> balances = new HashMap<>();
|
||||
BigDecimal totalMoney = BigDecimal.ZERO;
|
||||
if (ess.getSettings().isEcoDisabled()) {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info("Internal economy functions disabled, aborting baltop.");
|
||||
}
|
||||
} else {
|
||||
for (final UUID u : ess.getUserMap().getAllUniqueUsers()) {
|
||||
final User user = ess.getUserMap().getUser(u);
|
||||
if (user != null) {
|
||||
if (!ess.getSettings().isNpcsInBalanceRanking() && user.isNPC()) {
|
||||
// Don't list NPCs in output
|
||||
continue;
|
||||
}
|
||||
if (!user.isAuthorized("essentials.balancetop.exclude")) {
|
||||
final BigDecimal userMoney = user.getMoney();
|
||||
user.updateMoneyCache(userMoney);
|
||||
totalMoney = totalMoney.add(userMoney);
|
||||
final String name = user.isHidden() ? user.getName() : user.getDisplayName();
|
||||
balances.put(name, userMoney);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final List<Map.Entry<String, BigDecimal>> sortedEntries = new ArrayList<>(balances.entrySet());
|
||||
sortedEntries.sort((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue()));
|
||||
|
||||
cache.getLines().add(tl("serverTotal", NumberUtil.displayCurrency(totalMoney, ess)));
|
||||
int pos = 1;
|
||||
for (final Map.Entry<String, BigDecimal> entry : sortedEntries) {
|
||||
cache.getLines().add(tl("balanceTopLine", pos, entry.getKey(), NumberUtil.displayCurrency(entry.getValue(), ess)));
|
||||
pos++;
|
||||
}
|
||||
cacheage = System.currentTimeMillis();
|
||||
}
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
ess.runTaskAsynchronously(viewer);
|
||||
}
|
||||
}
|
||||
|
||||
private class Viewer implements Runnable {
|
||||
private final transient CommandSource sender;
|
||||
private final transient int page;
|
||||
private final transient boolean force;
|
||||
private final transient String commandLabel;
|
||||
|
||||
Viewer(final CommandSource sender, final String commandLabel, final int page, final boolean force) {
|
||||
this.sender = sender;
|
||||
this.page = page;
|
||||
this.force = force;
|
||||
this.commandLabel = commandLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
if (!force && cacheage > System.currentTimeMillis() - CACHETIME) {
|
||||
outputCache(sender, page);
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
ess.runTaskAsynchronously(new Calculator(new Viewer(sender, commandLabel, page, false), force));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.MemoryConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConstructor;
|
||||
import org.bukkit.configuration.file.YamlRepresenter;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.representer.Representer;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandcreatekit extends EssentialsCommand {
|
||||
|
||||
private static final String PASTE_URL = "https://hastebin.com/";
|
||||
private static final String PASTE_UPLOAD_URL = PASTE_URL + "documents";
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||
private final DumperOptions yamlOptions = new DumperOptions();
|
||||
private final Representer yamlRepresenter = new YamlRepresenter();
|
||||
private final YamlConstructor yamlConstructor = new YamlConstructor();
|
||||
|
||||
public Commandcreatekit() {
|
||||
super("createkit");
|
||||
yamlOptions.setDefaultFlowStyle(FlowStyle.BLOCK);
|
||||
yamlRepresenter.setDefaultFlowStyle(FlowStyle.BLOCK);
|
||||
}
|
||||
|
||||
// /createkit <name> <delay>
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length != 2) {
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
// Command handler will auto fail if this fails.
|
||||
final long delay = Long.parseLong(args[1]);
|
||||
final String kitname = args[0];
|
||||
final ItemStack[] items = user.getBase().getInventory().getContents();
|
||||
final List<String> list = new ArrayList<>();
|
||||
for (final ItemStack is : items) {
|
||||
if (is != null && is.getType() != null && is.getType() != Material.AIR) {
|
||||
final String serialized = ess.getItemDb().serialize(is);
|
||||
list.add(serialized);
|
||||
}
|
||||
}
|
||||
// Some users might want to directly write to config knowing the consequences. *shrug*
|
||||
if (!ess.getSettings().isPastebinCreateKit()) {
|
||||
ess.getKits().addKit(kitname, list, delay);
|
||||
user.sendMessage(tl("createdKit", kitname, list.size(), delay));
|
||||
} else {
|
||||
final ConfigurationSection config = new MemoryConfiguration();
|
||||
config.set("kits." + kitname + ".delay", delay);
|
||||
config.set("kits." + kitname + ".items", list);
|
||||
|
||||
final Yaml yaml = new Yaml(yamlConstructor, yamlRepresenter, yamlOptions);
|
||||
String fileContents = "# Copy the kit code below into the kits section in your config.yml file\n";
|
||||
fileContents += yaml.dump(config.getValues(false));
|
||||
|
||||
uploadPaste(user.getSource(), kitname, delay, fileContents);
|
||||
}
|
||||
}
|
||||
|
||||
private void uploadPaste(final CommandSource sender, final String kitName, final long delay, final String contents) {
|
||||
executorService.submit(() -> {
|
||||
try {
|
||||
final HttpURLConnection connection = (HttpURLConnection) new URL(PASTE_UPLOAD_URL).openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
connection.setRequestProperty("User-Agent", "EssentialsX plugin");
|
||||
try (final OutputStream os = connection.getOutputStream()) {
|
||||
os.write(contents.getBytes(Charsets.UTF_8));
|
||||
}
|
||||
// Error
|
||||
if (connection.getResponseCode() >= 400) {
|
||||
sender.sendMessage(tl("createKitFailed", kitName));
|
||||
final String message = CharStreams.toString(new InputStreamReader(connection.getErrorStream(), Charsets.UTF_8));
|
||||
ess.getLogger().severe("Error creating kit: " + message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Read URL
|
||||
final JsonObject object = GSON.fromJson(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8), JsonObject.class);
|
||||
final String pasteUrl = PASTE_URL + object.get("key").getAsString();
|
||||
connection.disconnect();
|
||||
|
||||
final String separator = tl("createKitSeparator");
|
||||
String delayFormat = "0";
|
||||
if (delay > 0) {
|
||||
delayFormat = DateUtil.formatDateDiff(System.currentTimeMillis() + (delay * 1000));
|
||||
}
|
||||
sender.sendMessage(separator);
|
||||
sender.sendMessage(tl("createKitSuccess", kitName, delayFormat, pasteUrl));
|
||||
sender.sendMessage(separator);
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info(sender.getSender().getName() + " created a kit: " + pasteUrl);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
sender.sendMessage(tl("createKitFailed", kitName));
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commanditemname extends EssentialsCommand {
|
||||
|
||||
public Commanditemname() {
|
||||
super("itemname");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
final ItemStack item = user.getBase().getItemInHand();
|
||||
if (item.getType() == Material.AIR) {
|
||||
user.sendMessage(tl("itemnameInvalidItem", item.getType().toString().toLowerCase(Locale.ENGLISH).replace('_', ' ')));
|
||||
return;
|
||||
}
|
||||
|
||||
String name = FormatUtil.formatString(user, "essentials.itemname", getFinalArg(args, 0)).trim();
|
||||
if (name.isEmpty()) {
|
||||
name = null;
|
||||
}
|
||||
|
||||
final ItemMeta im = item.getItemMeta();
|
||||
im.setDisplayName(name);
|
||||
item.setItemMeta(im);
|
||||
user.sendMessage(name == null ? tl("itemnameClear") : tl("itemnameSuccess", name));
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.PlayerList;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandlist extends EssentialsCommand {
|
||||
public Commandlist() {
|
||||
super("list");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
boolean showHidden = true;
|
||||
User user = null;
|
||||
if (sender.isPlayer()) {
|
||||
user = ess.getUser(sender.getPlayer());
|
||||
showHidden = user.isAuthorized("essentials.list.hidden") || user.canInteractVanished();
|
||||
}
|
||||
sender.sendMessage(PlayerList.listSummary(ess, user, showHidden));
|
||||
final Map<String, List<User>> playerList = PlayerList.getPlayerLists(ess, user, showHidden);
|
||||
|
||||
if (args.length > 0) {
|
||||
sender.sendMessage(PlayerList.listGroupUsers(ess, playerList, args[0].toLowerCase()));
|
||||
} else {
|
||||
sendGroupedList(sender, commandLabel, playerList);
|
||||
}
|
||||
}
|
||||
|
||||
// Output the standard /list output, when no group is specified
|
||||
private void sendGroupedList(final CommandSource sender, final String commandLabel, final Map<String, List<User>> playerList) {
|
||||
final Set<String> configGroups = ess.getSettings().getListGroupConfig().keySet();
|
||||
final List<String> asterisk = new ArrayList<>();
|
||||
|
||||
// Loop through the custom defined groups and display them
|
||||
for (final String oConfigGroup : configGroups) {
|
||||
final String groupValue = ess.getSettings().getListGroupConfig().get(oConfigGroup).toString().trim();
|
||||
final String configGroup = oConfigGroup.toLowerCase();
|
||||
|
||||
// If the group value is an asterisk, then skip it, and handle it later
|
||||
if (groupValue.equals("*")) {
|
||||
asterisk.add(oConfigGroup);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the group value is hidden, we don't need to display it
|
||||
if (groupValue.equalsIgnoreCase("hidden")) {
|
||||
playerList.remove(configGroup);
|
||||
continue;
|
||||
}
|
||||
|
||||
final List<User> outputUserList;
|
||||
final List<User> matchedList = playerList.get(configGroup);
|
||||
|
||||
// If the group value is an int, then we might need to truncate it
|
||||
if (NumberUtil.isInt(groupValue)) {
|
||||
if (matchedList != null && !matchedList.isEmpty()) {
|
||||
playerList.remove(configGroup);
|
||||
outputUserList = new ArrayList<>(matchedList);
|
||||
final int limit = Integer.parseInt(groupValue);
|
||||
if (matchedList.size() > limit) {
|
||||
sender.sendMessage(PlayerList.outputFormat(oConfigGroup, tl("groupNumber", matchedList.size(), commandLabel, FormatUtil.stripFormat(configGroup))));
|
||||
} else {
|
||||
sender.sendMessage(PlayerList.outputFormat(oConfigGroup, PlayerList.listUsers(ess, outputUserList, ", ")));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
outputUserList = PlayerList.getMergedList(ess, playerList, configGroup);
|
||||
|
||||
// If we have no users, than we don't need to continue parsing this group
|
||||
if (outputUserList.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sender.sendMessage(PlayerList.outputFormat(oConfigGroup, PlayerList.listUsers(ess, outputUserList, ", ")));
|
||||
}
|
||||
|
||||
final Set<String> var = playerList.keySet();
|
||||
String[] onlineGroups = var.toArray(new String[0]);
|
||||
Arrays.sort(onlineGroups, String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
// If we have an asterisk group, then merge all remaining groups
|
||||
if (!asterisk.isEmpty()) {
|
||||
final List<User> asteriskUsers = new ArrayList<>();
|
||||
for (final String onlineGroup : onlineGroups) {
|
||||
asteriskUsers.addAll(playerList.get(onlineGroup));
|
||||
}
|
||||
for (final String key : asterisk) {
|
||||
playerList.put(key, asteriskUsers);
|
||||
}
|
||||
onlineGroups = asterisk.toArray(new String[0]);
|
||||
}
|
||||
|
||||
// If we have any groups remaining after the custom groups loop through and display them
|
||||
for (final String onlineGroup : onlineGroups) {
|
||||
final List<User> users = playerList.get(onlineGroup);
|
||||
String groupName = asterisk.isEmpty() ? users.get(0).getGroup() : onlineGroup;
|
||||
|
||||
if (ess.getPermissionsHandler().getName().equals("ConfigPermissions")) {
|
||||
groupName = tl("connectedPlayers");
|
||||
}
|
||||
if (users == null || users.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sender.sendMessage(PlayerList.outputFormat(groupName, PlayerList.listUsers(ess, users, ", ")));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
return new ArrayList<>(PlayerList.getPlayerLists(ess, sender.getUser(ess), true).keySet());
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import com.earth2me.essentials.User;
|
||||
import com.earth2me.essentials.textreader.IText;
|
||||
import com.earth2me.essentials.textreader.SimpleTextInput;
|
||||
import com.earth2me.essentials.textreader.TextPager;
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import com.earth2me.essentials.utils.StringUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandmail extends EssentialsCommand {
|
||||
private static int mailsPerMinute = 0;
|
||||
private static long timestamp = 0;
|
||||
|
||||
public Commandmail() {
|
||||
super("mail");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length >= 1 && "read".equalsIgnoreCase(args[0])) {
|
||||
final List<String> mail = user.getMails();
|
||||
if (mail.isEmpty()) {
|
||||
user.sendMessage(tl("noMail"));
|
||||
throw new NoChargeException();
|
||||
}
|
||||
|
||||
final IText input = new SimpleTextInput(mail);
|
||||
final TextPager pager = new TextPager(input);
|
||||
pager.showPage(args.length > 1 ? args[1] : null, null, commandLabel + " " + args[0], user.getSource());
|
||||
|
||||
user.sendMessage(tl("mailClear"));
|
||||
return;
|
||||
}
|
||||
if (args.length >= 3 && "send".equalsIgnoreCase(args[0])) {
|
||||
if (!user.isAuthorized("essentials.mail.send")) {
|
||||
throw new Exception(tl("noPerm", "essentials.mail.send"));
|
||||
}
|
||||
|
||||
if (user.isMuted()) {
|
||||
final String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
|
||||
if (dateDiff == null) {
|
||||
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
|
||||
}
|
||||
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
|
||||
}
|
||||
|
||||
final User u;
|
||||
try {
|
||||
u = getPlayer(server, args[1], true, true);
|
||||
} catch (final PlayerNotFoundException e) {
|
||||
throw new Exception(tl("playerNeverOnServer", args[1]));
|
||||
}
|
||||
|
||||
final String mail = tl("mailFormat", user.getName(), FormatUtil.formatMessage(user, "essentials.mail", StringUtil.sanitizeString(FormatUtil.stripFormat(getFinalArg(args, 2)))));
|
||||
if (mail.length() > 1000) {
|
||||
throw new Exception(tl("mailTooLong"));
|
||||
}
|
||||
|
||||
if (!u.isIgnoredPlayer(user)) {
|
||||
if (Math.abs(System.currentTimeMillis() - timestamp) > 60000) {
|
||||
timestamp = System.currentTimeMillis();
|
||||
mailsPerMinute = 0;
|
||||
}
|
||||
mailsPerMinute++;
|
||||
if (mailsPerMinute > ess.getSettings().getMailsPerMinute()) {
|
||||
throw new Exception(tl("mailDelay", ess.getSettings().getMailsPerMinute()));
|
||||
}
|
||||
u.addMail(tl("mailMessage", mail));
|
||||
}
|
||||
|
||||
user.sendMessage(tl("mailSentTo", u.getDisplayName(), u.getName()));
|
||||
user.sendMessage(mail);
|
||||
return;
|
||||
}
|
||||
if (args.length > 1 && "sendall".equalsIgnoreCase(args[0])) {
|
||||
if (!user.isAuthorized("essentials.mail.sendall")) {
|
||||
throw new Exception(tl("noPerm", "essentials.mail.sendall"));
|
||||
}
|
||||
ess.runTaskAsynchronously(new SendAll(tl("mailFormat", user.getName(),
|
||||
FormatUtil.formatMessage(user, "essentials.mail", StringUtil.sanitizeString(FormatUtil.stripFormat(getFinalArg(args, 1)))))));
|
||||
user.sendMessage(tl("mailSent"));
|
||||
return;
|
||||
}
|
||||
if (args.length >= 1 && "clear".equalsIgnoreCase(args[0])) {
|
||||
if (user.getMails() == null || user.getMails().isEmpty()) {
|
||||
user.sendMessage(tl("noMail"));
|
||||
throw new NoChargeException();
|
||||
}
|
||||
|
||||
user.setMails(null);
|
||||
user.sendMessage(tl("mailCleared"));
|
||||
return;
|
||||
}
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
|
||||
if (args.length >= 1 && "read".equalsIgnoreCase(args[0])) {
|
||||
throw new Exception(tl("onlyPlayers", commandLabel + " read"));
|
||||
} else if (args.length >= 1 && "clear".equalsIgnoreCase(args[0])) {
|
||||
throw new Exception(tl("onlyPlayers", commandLabel + " clear"));
|
||||
} else if (args.length >= 3 && "send".equalsIgnoreCase(args[0])) {
|
||||
final User u;
|
||||
try {
|
||||
u = getPlayer(server, args[1], true, true);
|
||||
} catch (final PlayerNotFoundException e) {
|
||||
throw new Exception(tl("playerNeverOnServer", args[1]));
|
||||
}
|
||||
u.addMail(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 2))));
|
||||
sender.sendMessage(tl("mailSent"));
|
||||
return;
|
||||
} else if (args.length >= 2 && "sendall".equalsIgnoreCase(args[0])) {
|
||||
ess.runTaskAsynchronously(new SendAll(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 1)))));
|
||||
sender.sendMessage(tl("mailSent"));
|
||||
return;
|
||||
} else if (args.length >= 2) {
|
||||
//allow sending from console without "send" argument, since it's the only thing the console can do
|
||||
final User u;
|
||||
try {
|
||||
u = getPlayer(server, args[0], true, true);
|
||||
} catch (final PlayerNotFoundException e) {
|
||||
throw new Exception(tl("playerNeverOnServer", args[0]));
|
||||
}
|
||||
u.addMail(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 1))));
|
||||
sender.sendMessage(tl("mailSent"));
|
||||
return;
|
||||
}
|
||||
throw new NotEnoughArgumentsException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
final List<String> options = Lists.newArrayList("read", "clear");
|
||||
if (user.isAuthorized("essentials.mail.send")) {
|
||||
options.add("send");
|
||||
}
|
||||
if (user.isAuthorized("essentials.mail.sendall")) {
|
||||
options.add("sendall");
|
||||
}
|
||||
return options;
|
||||
} else if (args.length == 2 && args[0].equalsIgnoreCase("send") && user.isAuthorized("essentials.mail.send")) {
|
||||
return getPlayers(server, user);
|
||||
} else if (args.length == 2 && args[0].equalsIgnoreCase("read")) {
|
||||
final List<String> mail = user.getMails();
|
||||
final int pages = mail.size() / 9 + (mail.size() % 9 > 0 ? 1 : 0);
|
||||
if (pages == 0) {
|
||||
return Lists.newArrayList("0");
|
||||
} else {
|
||||
final List<String> options = Lists.newArrayList("1");
|
||||
if (pages > 1) {
|
||||
options.add(String.valueOf(pages));
|
||||
}
|
||||
return options;
|
||||
}
|
||||
} else if ((args.length > 2 && args[0].equalsIgnoreCase("send") && user.isAuthorized("essentials.mail.send")) || (args.length > 1 && args[0].equalsIgnoreCase("sendall") && user.isAuthorized("essentials.mail.sendall"))) {
|
||||
return null; // Use vanilla handler
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
|
||||
if (args.length == 1) {
|
||||
return Lists.newArrayList("send", "sendall");
|
||||
} else if (args.length == 2 && args[0].equalsIgnoreCase("send")) {
|
||||
return getPlayers(server, sender);
|
||||
} else if ((args.length > 2 && args[0].equalsIgnoreCase("send")) || (args.length > 1 && args[0].equalsIgnoreCase("sendall"))) {
|
||||
return null; // Use vanilla handler
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private class SendAll implements Runnable {
|
||||
final String message;
|
||||
|
||||
SendAll(final String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (final UUID userid : ess.getUserMap().getAllUniqueUsers()) {
|
||||
final User user = ess.getUserMap().getUser(userid);
|
||||
if (user != null) {
|
||||
user.addMail(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.AsyncTeleport;
|
||||
import com.earth2me.essentials.Trade;
|
||||
import com.earth2me.essentials.User;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandtpaccept extends EssentialsCommand {
|
||||
public Commandtpaccept() {
|
||||
super("tpaccept");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
final User requester;
|
||||
try {
|
||||
requester = ess.getUser(user.getTeleportRequest());
|
||||
} catch (final Exception ex) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
|
||||
if (!requester.getBase().isOnline()) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
|
||||
if (user.isTpRequestHere() && ((!requester.isAuthorized("essentials.tpahere") && !requester.isAuthorized("essentials.tpaall")) || (user.getWorld() != requester.getWorld() && ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + user.getWorld().getName())))) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
|
||||
if (!user.isTpRequestHere() && (!requester.isAuthorized("essentials.tpa") || (user.getWorld() != requester.getWorld() && ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + requester.getWorld().getName())))) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
|
||||
if (args.length > 0 && !requester.getName().contains(args[0])) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
|
||||
if (!user.hasOutstandingTeleportRequest()) {
|
||||
user.requestTeleport(null, false);
|
||||
throw new Exception(tl("requestTimedOut"));
|
||||
}
|
||||
|
||||
final Trade charge = new Trade(this.getName(), ess);
|
||||
user.sendMessage(tl("requestAccepted"));
|
||||
requester.sendMessage(tl("requestAcceptedFrom", user.getDisplayName()));
|
||||
|
||||
final CompletableFuture<Boolean> future = getNewExceptionFuture(requester.getSource(), commandLabel);
|
||||
future.exceptionally(e -> {
|
||||
user.sendMessage(tl("pendingTeleportCancelled"));
|
||||
return false;
|
||||
});
|
||||
if (user.isTpRequestHere()) {
|
||||
final Location loc = user.getTpRequestLocation();
|
||||
final AsyncTeleport teleport = requester.getAsyncTeleport();
|
||||
teleport.setTpType(AsyncTeleport.TeleportType.TPA);
|
||||
future.thenAccept(success -> {
|
||||
if (success) {
|
||||
requester.sendMessage(tl("teleporting", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
}
|
||||
});
|
||||
teleport.teleportPlayer(user, user.getTpRequestLocation(), charge, TeleportCause.COMMAND, future);
|
||||
} else {
|
||||
final AsyncTeleport teleport = requester.getAsyncTeleport();
|
||||
teleport.setTpType(AsyncTeleport.TeleportType.TPA);
|
||||
teleport.teleport(user.getBase(), charge, TeleportCause.COMMAND, future);
|
||||
}
|
||||
user.requestTeleport(null, false);
|
||||
throw new NoChargeException();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.earth2me.essentials.commands;
|
||||
|
||||
import com.earth2me.essentials.User;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Commandtpdeny extends EssentialsCommand {
|
||||
public Commandtpdeny() {
|
||||
super("tpdeny");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
|
||||
if (user.getTeleportRequest() == null) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
final User player = ess.getUser(user.getTeleportRequest());
|
||||
if (player == null) {
|
||||
throw new Exception(tl("noPendingRequest"));
|
||||
}
|
||||
|
||||
user.sendMessage(tl("requestDenied"));
|
||||
player.sendMessage(tl("requestDeniedFrom", user.getDisplayName()));
|
||||
user.requestTeleport(null, false);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,729 +0,0 @@
|
||||
package com.earth2me.essentials.metrics;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.logging.Level;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
/**
|
||||
* bStats collects some data for plugin authors.
|
||||
* <p>
|
||||
* Check out https://bStats.org/ to learn more about bStats!
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
public class Metrics {
|
||||
|
||||
// The version of this bStats class
|
||||
public static final int B_STATS_VERSION = 1;
|
||||
// The url to which the data is sent
|
||||
private static final String URL = "https://bStats.org/submitData/bukkit";
|
||||
// Should failed requests be logged?
|
||||
private static boolean logFailedRequests;
|
||||
// Should the sent data be logged?
|
||||
private static boolean logSentData;
|
||||
// Should the response text be logged?
|
||||
private static boolean logResponseStatusText;
|
||||
// The uuid of the server
|
||||
private static String serverUUID;
|
||||
|
||||
static {
|
||||
// You can use the property to disable the check in your test environment
|
||||
if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) {
|
||||
// Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D
|
||||
final String defaultPackage = new String(
|
||||
new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'});
|
||||
final String examplePackage = new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
|
||||
// We want to make sure nobody just copy & pastes the example and use the wrong package names
|
||||
if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) {
|
||||
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is bStats enabled on this server?
|
||||
private final boolean enabled;
|
||||
// The plugin
|
||||
private final Plugin plugin;
|
||||
|
||||
// The plugin id
|
||||
private final int pluginId;
|
||||
|
||||
// A list with all custom charts
|
||||
private final List<CustomChart> charts = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param plugin The plugin which stats should be submitted.
|
||||
* @param pluginId The id of the plugin.
|
||||
* It can be found at <a href="https://bstats.org/what-is-my-plugin-id">What is my plugin id?</a>
|
||||
*/
|
||||
public Metrics(final Plugin plugin, final int pluginId) {
|
||||
if (plugin == null) {
|
||||
throw new IllegalArgumentException("Plugin cannot be null!");
|
||||
}
|
||||
this.plugin = plugin;
|
||||
this.pluginId = pluginId;
|
||||
|
||||
// Get the config file
|
||||
final File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
||||
final File configFile = new File(bStatsFolder, "config.yml");
|
||||
final YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
|
||||
|
||||
// Check if the config file exists
|
||||
if (!config.isSet("serverUuid")) {
|
||||
|
||||
// Add default values
|
||||
config.addDefault("enabled", true);
|
||||
// Every server gets it's unique random id.
|
||||
config.addDefault("serverUuid", UUID.randomUUID().toString());
|
||||
// Should failed request be logged?
|
||||
config.addDefault("logFailedRequests", false);
|
||||
// Should the sent data be logged?
|
||||
config.addDefault("logSentData", false);
|
||||
// Should the response text be logged?
|
||||
config.addDefault("logResponseStatusText", false);
|
||||
|
||||
// Inform the server owners about bStats
|
||||
config.options().header(
|
||||
"bStats collects some data for plugin authors like how many servers are using their plugins.\n" +
|
||||
"To honor their work, you should not disable it.\n" +
|
||||
"This has nearly no effect on the server performance!\n" +
|
||||
"Check out https://bStats.org/ to learn more :)"
|
||||
).copyDefaults(true);
|
||||
try {
|
||||
config.save(configFile);
|
||||
} catch (final IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
// Load the data
|
||||
enabled = config.getBoolean("enabled", true);
|
||||
serverUUID = config.getString("serverUuid");
|
||||
logFailedRequests = config.getBoolean("logFailedRequests", false);
|
||||
logSentData = config.getBoolean("logSentData", false);
|
||||
logResponseStatusText = config.getBoolean("logResponseStatusText", false);
|
||||
|
||||
if (enabled) {
|
||||
boolean found = false;
|
||||
// Search for all other bStats Metrics classes to see if we are the first one
|
||||
for (final Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
|
||||
try {
|
||||
service.getField("B_STATS_VERSION"); // Our identifier :)
|
||||
found = true; // We aren't the first
|
||||
break;
|
||||
} catch (final NoSuchFieldException ignored) {
|
||||
}
|
||||
}
|
||||
// Register our service
|
||||
Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal);
|
||||
if (!found) {
|
||||
// We are the first!
|
||||
startSubmitting();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the data to the bStats server.
|
||||
*
|
||||
* @param plugin Any plugin. It's just used to get a logger instance.
|
||||
* @param data The data to send.
|
||||
* @throws Exception If the request failed.
|
||||
*/
|
||||
private static void sendData(final Plugin plugin, final JsonObject data) throws Exception {
|
||||
if (data == null) {
|
||||
throw new IllegalArgumentException("Data cannot be null!");
|
||||
}
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
throw new IllegalAccessException("This method must not be called from the main thread!");
|
||||
}
|
||||
if (logSentData) {
|
||||
plugin.getLogger().info("Sending data to bStats: " + data);
|
||||
}
|
||||
final HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
|
||||
|
||||
// Compress the data to save bandwidth
|
||||
final byte[] compressedData = compress(data.toString());
|
||||
|
||||
// Add headers
|
||||
connection.setRequestMethod("POST");
|
||||
connection.addRequestProperty("Accept", "application/json");
|
||||
connection.addRequestProperty("Connection", "close");
|
||||
connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
|
||||
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
|
||||
connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
|
||||
connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
|
||||
|
||||
// Send data
|
||||
connection.setDoOutput(true);
|
||||
try (final DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
|
||||
outputStream.write(compressedData);
|
||||
}
|
||||
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
try (final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
}
|
||||
|
||||
if (logResponseStatusText) {
|
||||
plugin.getLogger().info("Sent data to bStats and received response: " + builder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gzips the given String.
|
||||
*
|
||||
* @param str The string to gzip.
|
||||
* @return The gzipped String.
|
||||
* @throws IOException If the compression failed.
|
||||
*/
|
||||
private static byte[] compress(final String str) throws IOException {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try (final GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
|
||||
gzip.write(str.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if bStats is enabled.
|
||||
*
|
||||
* @return Whether bStats is enabled or not.
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom chart.
|
||||
*
|
||||
* @param chart The chart to add.
|
||||
*/
|
||||
public void addCustomChart(final CustomChart chart) {
|
||||
if (chart == null) {
|
||||
throw new IllegalArgumentException("Chart cannot be null!");
|
||||
}
|
||||
charts.add(chart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the Scheduler which submits our data every 30 minutes.
|
||||
*/
|
||||
private void startSubmitting() {
|
||||
final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!plugin.isEnabled()) { // Plugin was disabled
|
||||
timer.cancel();
|
||||
return;
|
||||
}
|
||||
// Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler
|
||||
// Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;)
|
||||
Bukkit.getScheduler().runTask(plugin, () -> submitData());
|
||||
}
|
||||
}, 1000 * 60 * 5, 1000 * 60 * 30);
|
||||
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
|
||||
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
|
||||
// WARNING: Just don't do it!
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plugin specific data.
|
||||
* This method is called using Reflection.
|
||||
*
|
||||
* @return The plugin specific data.
|
||||
*/
|
||||
public JsonObject getPluginData() {
|
||||
final JsonObject data = new JsonObject();
|
||||
|
||||
final String pluginName = plugin.getDescription().getName().replace("Essentials", "EssentialsX");
|
||||
final String pluginVersion = plugin.getDescription().getVersion();
|
||||
|
||||
data.addProperty("pluginName", pluginName); // Append the name of the plugin
|
||||
data.addProperty("id", pluginId); // Append the id of the plugin
|
||||
data.addProperty("pluginVersion", pluginVersion); // Append the version of the plugin
|
||||
final JsonArray customCharts = new JsonArray();
|
||||
for (final CustomChart customChart : charts) {
|
||||
// Add the data of the custom charts
|
||||
final JsonObject chart = customChart.getRequestJsonObject();
|
||||
if (chart == null) { // If the chart is null, we skip it
|
||||
continue;
|
||||
}
|
||||
customCharts.add(chart);
|
||||
}
|
||||
data.add("customCharts", customCharts);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server specific data.
|
||||
*
|
||||
* @return The server specific data.
|
||||
*/
|
||||
private JsonObject getServerData() {
|
||||
// Minecraft specific data
|
||||
int playerAmount;
|
||||
try {
|
||||
// Around MC 1.8 the return type was changed to a collection from an array,
|
||||
// This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
|
||||
final Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
|
||||
playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class)
|
||||
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
|
||||
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
|
||||
} catch (final Exception e) {
|
||||
playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed
|
||||
}
|
||||
final int onlineMode = Bukkit.getOnlineMode() ? 1 : 0;
|
||||
final String bukkitVersion = Bukkit.getVersion();
|
||||
final String bukkitName = Bukkit.getName();
|
||||
|
||||
// OS/Java specific data
|
||||
final String javaVersion = System.getProperty("java.version");
|
||||
final String osName = System.getProperty("os.name");
|
||||
final String osArch = System.getProperty("os.arch");
|
||||
final String osVersion = System.getProperty("os.version");
|
||||
final int coreCount = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
final JsonObject data = new JsonObject();
|
||||
|
||||
data.addProperty("serverUUID", serverUUID);
|
||||
|
||||
data.addProperty("playerAmount", playerAmount);
|
||||
data.addProperty("onlineMode", onlineMode);
|
||||
data.addProperty("bukkitVersion", bukkitVersion);
|
||||
data.addProperty("bukkitName", bukkitName);
|
||||
|
||||
data.addProperty("javaVersion", javaVersion);
|
||||
data.addProperty("osName", osName);
|
||||
data.addProperty("osArch", osArch);
|
||||
data.addProperty("osVersion", osVersion);
|
||||
data.addProperty("coreCount", coreCount);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the data and sends it afterwards.
|
||||
*/
|
||||
private void submitData() {
|
||||
final JsonObject data = getServerData();
|
||||
|
||||
final JsonArray pluginData = new JsonArray();
|
||||
// Search for all other bStats Metrics classes to get their plugin data
|
||||
for (final Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
|
||||
try {
|
||||
service.getField("B_STATS_VERSION"); // Our identifier :)
|
||||
|
||||
for (final RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service)) {
|
||||
try {
|
||||
final Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider());
|
||||
if (plugin instanceof JsonObject) {
|
||||
pluginData.add((JsonObject) plugin);
|
||||
} else { // old bstats version compatibility
|
||||
try {
|
||||
final Class<?> jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject");
|
||||
if (plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) {
|
||||
final Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString");
|
||||
jsonStringGetter.setAccessible(true);
|
||||
final String jsonString = (String) jsonStringGetter.invoke(plugin);
|
||||
final JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject();
|
||||
pluginData.add(object);
|
||||
}
|
||||
} catch (final ClassNotFoundException e) {
|
||||
// minecraft version 1.14+
|
||||
if (logFailedRequests) {
|
||||
this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) {
|
||||
}
|
||||
}
|
||||
} catch (final NoSuchFieldException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
data.add("plugins", pluginData);
|
||||
|
||||
// Create a new thread for the connection to the bStats server
|
||||
new Thread(() -> {
|
||||
try {
|
||||
// Send the data
|
||||
sendData(plugin, data);
|
||||
} catch (final Exception e) {
|
||||
// Something went wrong! :(
|
||||
if (logFailedRequests) {
|
||||
plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom chart.
|
||||
*/
|
||||
public static abstract class CustomChart {
|
||||
|
||||
// The id of the chart
|
||||
final String chartId;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
*/
|
||||
CustomChart(final String chartId) {
|
||||
if (chartId == null || chartId.isEmpty()) {
|
||||
throw new IllegalArgumentException("ChartId cannot be null or empty!");
|
||||
}
|
||||
this.chartId = chartId;
|
||||
}
|
||||
|
||||
private JsonObject getRequestJsonObject() {
|
||||
final JsonObject chart = new JsonObject();
|
||||
chart.addProperty("chartId", chartId);
|
||||
try {
|
||||
final JsonObject data = getChartData();
|
||||
if (data == null) {
|
||||
// If the data is null we don't send the chart.
|
||||
return null;
|
||||
}
|
||||
chart.add("data", data);
|
||||
} catch (final Throwable t) {
|
||||
if (logFailedRequests) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return chart;
|
||||
}
|
||||
|
||||
protected abstract JsonObject getChartData() throws Exception;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom simple pie.
|
||||
*/
|
||||
public static class SimplePie extends CustomChart {
|
||||
|
||||
private final Callable<String> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimplePie(final String chartId, final Callable<String> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final String value = callable.call();
|
||||
if (value == null || value.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.addProperty("value", value);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom advanced pie.
|
||||
*/
|
||||
public static class AdvancedPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedPie(final String chartId, final Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final JsonObject values = new JsonObject();
|
||||
final Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (final Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
continue; // Skip this invalid
|
||||
}
|
||||
allSkipped = false;
|
||||
values.addProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom drilldown pie.
|
||||
*/
|
||||
public static class DrilldownPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Map<String, Integer>>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public DrilldownPie(final String chartId, final Callable<Map<String, Map<String, Integer>>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final JsonObject values = new JsonObject();
|
||||
final Map<String, Map<String, Integer>> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean reallyAllSkipped = true;
|
||||
for (final Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
|
||||
final JsonObject value = new JsonObject();
|
||||
boolean allSkipped = true;
|
||||
for (final Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
|
||||
value.addProperty(valueEntry.getKey(), valueEntry.getValue());
|
||||
allSkipped = false;
|
||||
}
|
||||
if (!allSkipped) {
|
||||
reallyAllSkipped = false;
|
||||
values.add(entryValues.getKey(), value);
|
||||
}
|
||||
}
|
||||
if (reallyAllSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom single line chart.
|
||||
*/
|
||||
public static class SingleLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Integer> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SingleLineChart(final String chartId, final Callable<Integer> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final int value = callable.call();
|
||||
if (value == 0) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.addProperty("value", value);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom multi line chart.
|
||||
*/
|
||||
public static class MultiLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public MultiLineChart(final String chartId, final Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final JsonObject values = new JsonObject();
|
||||
final Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (final Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
continue; // Skip this invalid
|
||||
}
|
||||
allSkipped = false;
|
||||
values.addProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom simple bar chart.
|
||||
*/
|
||||
public static class SimpleBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimpleBarChart(final String chartId, final Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final JsonObject values = new JsonObject();
|
||||
final Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
for (final Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
final JsonArray categoryValues = new JsonArray();
|
||||
categoryValues.add(new JsonPrimitive(entry.getValue()));
|
||||
values.add(entry.getKey(), categoryValues);
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom advanced bar chart.
|
||||
*/
|
||||
public static class AdvancedBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, int[]>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedBarChart(final String chartId, final Callable<Map<String, int[]>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
final JsonObject data = new JsonObject();
|
||||
final JsonObject values = new JsonObject();
|
||||
final Map<String, int[]> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (final Map.Entry<String, int[]> entry : map.entrySet()) {
|
||||
if (entry.getValue().length == 0) {
|
||||
continue; // Skip this invalid
|
||||
}
|
||||
allSkipped = false;
|
||||
final JsonArray categoryValues = new JsonArray();
|
||||
for (final int categoryValue : entry.getValue()) {
|
||||
categoryValues.add(new JsonPrimitive(categoryValue));
|
||||
}
|
||||
values.add(entry.getKey(), categoryValues);
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
package com.earth2me.essentials.metrics;
|
||||
|
||||
import com.earth2me.essentials.Essentials;
|
||||
import com.earth2me.essentials.register.payment.Methods;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MetricsWrapper {
|
||||
|
||||
private static final List<String> KNOWN_FORCED_METRICS = ImmutableList.of("ChatControl");
|
||||
private static boolean hasWarned = false;
|
||||
private final Essentials ess;
|
||||
private final Metrics metrics;
|
||||
private final Map<String, Boolean> commands = new HashMap<>();
|
||||
private final Plugin plugin;
|
||||
|
||||
public MetricsWrapper(final Plugin plugin, final int pluginId, final boolean includeCommands) {
|
||||
this.plugin = plugin;
|
||||
this.ess = (Essentials) Bukkit.getPluginManager().getPlugin("Essentials");
|
||||
this.metrics = new Metrics(plugin, pluginId);
|
||||
|
||||
if (metrics.isEnabled()) {
|
||||
plugin.getLogger().info("Starting Metrics. Opt-out using the global bStats config.");
|
||||
} else {
|
||||
plugin.getLogger().info("Metrics disabled per bStats config.");
|
||||
}
|
||||
|
||||
checkForcedMetrics();
|
||||
addPermsChart();
|
||||
addEconomyChart();
|
||||
|
||||
// bStats' backend currently doesn't support multi-line charts or advanced bar charts
|
||||
// These are included for when bStats is ready to accept this data
|
||||
addVersionHistoryChart();
|
||||
if (includeCommands) addCommandsChart();
|
||||
}
|
||||
|
||||
public void markCommand(final String command, final boolean state) {
|
||||
commands.put(command, state);
|
||||
}
|
||||
|
||||
public void addCustomChart(final Metrics.CustomChart chart) {
|
||||
metrics.addCustomChart(chart);
|
||||
}
|
||||
|
||||
private void addPermsChart() {
|
||||
metrics.addCustomChart(new Metrics.DrilldownPie("permsPlugin", () -> {
|
||||
final Map<String, Map<String, Integer>> result = new HashMap<>();
|
||||
final String handler = ess.getPermissionsHandler().getName();
|
||||
final Map<String, Integer> backend = new HashMap<>();
|
||||
backend.put(ess.getPermissionsHandler().getBackendName(), 1);
|
||||
result.put(handler, backend);
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
|
||||
private void addEconomyChart() {
|
||||
metrics.addCustomChart(new Metrics.DrilldownPie("econPlugin", () -> {
|
||||
final Map<String, Map<String, Integer>> result = new HashMap<>();
|
||||
final Map<String, Integer> backend = new HashMap<>();
|
||||
if (Methods.hasMethod()) {
|
||||
backend.put(Methods.getMethod().getBackend(), 1);
|
||||
result.put(Methods.getMethod().getName(), backend);
|
||||
} else {
|
||||
backend.put("Essentials", 1);
|
||||
result.put("Essentials", backend);
|
||||
}
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
|
||||
private void addVersionHistoryChart() {
|
||||
metrics.addCustomChart(new Metrics.MultiLineChart("versionHistory", () -> {
|
||||
final HashMap<String, Integer> result = new HashMap<>();
|
||||
result.put(plugin.getDescription().getVersion(), 1);
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
|
||||
private void addCommandsChart() {
|
||||
for (final String command : plugin.getDescription().getCommands().keySet()) {
|
||||
markCommand(command, false);
|
||||
}
|
||||
|
||||
metrics.addCustomChart(new Metrics.AdvancedBarChart("commands", () -> {
|
||||
final Map<String, int[]> result = new HashMap<>();
|
||||
for (final Map.Entry<String, Boolean> entry : commands.entrySet()) {
|
||||
if (entry.getValue()) {
|
||||
result.put(entry.getKey(), new int[] {1, 0});
|
||||
} else {
|
||||
result.put(entry.getKey(), new int[] {0, 1});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
|
||||
private void checkForcedMetrics() {
|
||||
if (hasWarned) return;
|
||||
hasWarned = true;
|
||||
|
||||
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
||||
for (final Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
|
||||
try {
|
||||
service.getField("B_STATS_VERSION"); // Identifies bStats classes
|
||||
|
||||
final JavaPlugin owningPlugin = getProvidingPlugin(service);
|
||||
if (owningPlugin != null && KNOWN_FORCED_METRICS.contains(owningPlugin.getName())) {
|
||||
warnForcedMetrics(service);
|
||||
} else {
|
||||
try {
|
||||
service.getDeclaredField("pluginId"); // Only present in recent bStats classes, which should also have the enabled field unless modified
|
||||
} catch (final NoSuchFieldException e) {
|
||||
// Old bStats class found so "enabled" field detection is unreliable.
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
service.getDeclaredField("enabled"); // In modified forced metrics classes, this will fail
|
||||
} catch (final NoSuchFieldException e) {
|
||||
warnForcedMetrics(service);
|
||||
}
|
||||
}
|
||||
} catch (final NoSuchFieldException ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void warnForcedMetrics(final Class<?> service) {
|
||||
final Plugin servicePlugin = JavaPlugin.getProvidingPlugin(service);
|
||||
plugin.getLogger().severe("WARNING: Potential forced metrics collection by plugin '" + servicePlugin.getName() + "' v" + servicePlugin.getDescription().getVersion());
|
||||
plugin.getLogger().severe("Your server is running a plugin that may not respect bStats' opt-out settings.");
|
||||
plugin.getLogger().severe("This may cause data to be uploaded to bStats.org for plugins that use bStats, even if you've opted out in the bStats config.");
|
||||
plugin.getLogger().severe("Please report this to bStats and to the authors of '" + servicePlugin.getName() + "'. (Offending class: " + service.getName() + ")");
|
||||
}
|
||||
|
||||
private JavaPlugin getProvidingPlugin(final Class<?> clazz) {
|
||||
try {
|
||||
return JavaPlugin.getProvidingPlugin(clazz);
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
|
||||
final ClassLoader parent = clazz.getClassLoader().getParent();
|
||||
if (parent.getClass().getName().equals("org.bukkit.plugin.java.PluginClassLoader")) {
|
||||
try {
|
||||
final Field pluginField = parent.getClass().getDeclaredField("plugin");
|
||||
pluginField.setAccessible(true);
|
||||
return (JavaPlugin) pluginField.get(parent);
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
package com.earth2me.essentials.register.payment;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by a payment method.
|
||||
* Copyright (C) 2011
|
||||
* AOL license <http://aol.nexua.org>
|
||||
* <p>
|
||||
* For more information about the licensing of this code in EssentialsX, see below:
|
||||
* https://gist.github.com/md678685/0935441c9573c030c8bd5a2e604aeec3
|
||||
*
|
||||
* @author Nijikokun <nijikokun@shortmail.com> (@nijikokun)
|
||||
*/
|
||||
public interface Method {
|
||||
/**
|
||||
* Encodes the Plugin into an Object disguised as the Plugin. If you want the original Plugin Class you must cast it
|
||||
* to the correct Plugin, to do so you have to verify the name and or version then cast.
|
||||
* <p/>
|
||||
* <pre>
|
||||
* if(method.getName().equalsIgnoreCase("iConomy"))
|
||||
* iConomy plugin = ((iConomy)method.getPlugin());</pre>
|
||||
*
|
||||
* @return <code>Object</code>
|
||||
* @see #getName()
|
||||
* @see #getVersion()
|
||||
*/
|
||||
Plugin getPlugin();
|
||||
|
||||
/**
|
||||
* Set Plugin data.
|
||||
*
|
||||
* @param plugin Plugin
|
||||
*/
|
||||
void setPlugin(Plugin plugin);
|
||||
|
||||
/**
|
||||
* Returns the actual name of this method.
|
||||
*
|
||||
* @return <code>String</code> Plugin name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns the backend plugin of this economy method, if applicable.
|
||||
*
|
||||
* @return <code>String</code> Plugin name.
|
||||
*/
|
||||
String getBackend();
|
||||
|
||||
/**
|
||||
* Returns the reported name of this method.
|
||||
*
|
||||
* @return <code>String</code> Plugin name.
|
||||
*/
|
||||
String getLongName();
|
||||
|
||||
/**
|
||||
* Returns the actual version of this method.
|
||||
*
|
||||
* @return <code>String</code> Plugin version.
|
||||
*/
|
||||
String getVersion();
|
||||
|
||||
/**
|
||||
* Returns the amount of decimal places that get stored NOTE: it will return -1 if there is no rounding
|
||||
*
|
||||
* @return <code>int</code> for each decimal place
|
||||
*/
|
||||
int fractionalDigits();
|
||||
|
||||
/**
|
||||
* Formats amounts into this payment methods style of currency display.
|
||||
*
|
||||
* @param amount Double
|
||||
* @return <code>String</code> - Formatted Currency Display.
|
||||
*/
|
||||
String format(double amount);
|
||||
|
||||
/**
|
||||
* Allows the verification of bank API existence in this payment method.
|
||||
*
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
boolean hasBanks();
|
||||
|
||||
/**
|
||||
* Determines the existence of a bank via name.
|
||||
*
|
||||
* @param bank Bank name
|
||||
* @return <code>boolean</code>
|
||||
* @see #hasBanks
|
||||
*/
|
||||
boolean hasBank(String bank);
|
||||
|
||||
/**
|
||||
* Determines the existence of an account via name.
|
||||
*
|
||||
* @param name Account name
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
boolean hasAccount(String name);
|
||||
|
||||
/**
|
||||
* Check to see if an account <code>name</code> is tied to a <code>bank</code>.
|
||||
*
|
||||
* @param bank Bank name
|
||||
* @param name Account name
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
boolean hasBankAccount(String bank, String name);
|
||||
|
||||
/**
|
||||
* Forces an account creation
|
||||
*
|
||||
* @param name Account name
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
boolean createAccount(String name);
|
||||
|
||||
/**
|
||||
* Forces an account creation
|
||||
*
|
||||
* @param name Account name
|
||||
* @param balance Initial account balance
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
boolean createAccount(String name, Double balance);
|
||||
|
||||
/**
|
||||
* Returns a <code>MethodAccount</code> class for an account <code>name</code>.
|
||||
*
|
||||
* @param name Account name
|
||||
* @return <code>MethodAccount</code> <em>or</em> <code>Null</code>
|
||||
*/
|
||||
MethodAccount getAccount(String name);
|
||||
|
||||
/**
|
||||
* Returns a <code>MethodBankAccount</code> class for an account <code>name</code>.
|
||||
*
|
||||
* @param bank Bank name
|
||||
* @param name Account name
|
||||
* @return <code>MethodBankAccount</code> <em>or</em> <code>Null</code>
|
||||
*/
|
||||
MethodBankAccount getBankAccount(String bank, String name);
|
||||
|
||||
/**
|
||||
* Checks to verify the compatibility between this Method and a plugin. Internal usage only, for the most part.
|
||||
*
|
||||
* @param plugin Plugin
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
boolean isCompatible(Plugin plugin);
|
||||
|
||||
/**
|
||||
* Contains Calculator and Balance functions for Accounts.
|
||||
*/
|
||||
interface MethodAccount {
|
||||
double balance();
|
||||
|
||||
boolean set(double amount);
|
||||
|
||||
boolean add(double amount);
|
||||
|
||||
boolean subtract(double amount);
|
||||
|
||||
boolean multiply(double amount);
|
||||
|
||||
boolean divide(double amount);
|
||||
|
||||
boolean hasEnough(double amount);
|
||||
|
||||
boolean hasOver(double amount);
|
||||
|
||||
boolean hasUnder(double amount);
|
||||
|
||||
boolean isNegative();
|
||||
|
||||
boolean remove();
|
||||
|
||||
@Override
|
||||
String toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains Calculator and Balance functions for Bank Accounts.
|
||||
*/
|
||||
interface MethodBankAccount {
|
||||
double balance();
|
||||
|
||||
String getBankName();
|
||||
|
||||
int getBankId();
|
||||
|
||||
boolean set(double amount);
|
||||
|
||||
boolean add(double amount);
|
||||
|
||||
boolean subtract(double amount);
|
||||
|
||||
boolean multiply(double amount);
|
||||
|
||||
boolean divide(double amount);
|
||||
|
||||
boolean hasEnough(double amount);
|
||||
|
||||
boolean hasOver(double amount);
|
||||
|
||||
boolean hasUnder(double amount);
|
||||
|
||||
boolean isNegative();
|
||||
|
||||
boolean remove();
|
||||
|
||||
@Override
|
||||
String toString();
|
||||
}
|
||||
}
|
||||
@@ -1,245 +0,0 @@
|
||||
package com.earth2me.essentials.register.payment;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The <code>Methods</code> initializes Methods that utilize the Method interface based on a "first come, first served"
|
||||
* basis.
|
||||
* <p/>
|
||||
* Allowing you to check whether a payment method exists or not.
|
||||
* <p/>
|
||||
* Methods also allows you to set a preferred method of payment before it captures payment plugins in the initialization
|
||||
* process.
|
||||
* <p/>
|
||||
* in
|
||||
* <code>bukkit.yml</code>: <blockquote><pre>
|
||||
* economy:
|
||||
* preferred: "iConomy"
|
||||
* </pre></blockquote>
|
||||
* <p>
|
||||
* For more information about the licensing of this code in EssentialsX, see below:
|
||||
* https://gist.github.com/md678685/0935441c9573c030c8bd5a2e604aeec3
|
||||
*
|
||||
* @author Nijikokun <nijikokun@shortmail.com> (@nijikokun) @copyright: Copyright (C) 2011 @license: AOL license
|
||||
* <http://aol.nexua.org>
|
||||
*/
|
||||
public final class Methods {
|
||||
private static final Set<Method> Methods = new HashSet<>();
|
||||
private static final Set<String> Dependencies = new HashSet<>();
|
||||
private static final Set<Method> Attachables = new HashSet<>();
|
||||
private static String version = null;
|
||||
private static boolean self = false;
|
||||
private static Method Method = null;
|
||||
private static String preferred = "";
|
||||
|
||||
private Methods() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement all methods along with their respective name & class.
|
||||
*/
|
||||
public static void init() {
|
||||
if (!Methods.isEmpty()) {
|
||||
throw new IllegalStateException("Methods already initialised!");
|
||||
}
|
||||
|
||||
addMethod("Vault", new com.earth2me.essentials.register.payment.methods.VaultEco());
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to reset methods during disable
|
||||
*/
|
||||
public static void reset() {
|
||||
version = null;
|
||||
self = false;
|
||||
Method = null;
|
||||
preferred = "";
|
||||
Attachables.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to get version of Register plugin
|
||||
*
|
||||
* @return version
|
||||
*/
|
||||
public static String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the plugin to setup version
|
||||
*
|
||||
* @param v version
|
||||
*/
|
||||
public static void setVersion(final String v) {
|
||||
version = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of payment method names that have been loaded through the <code>_init</code> method.
|
||||
*
|
||||
* @return <code>Set<String></code> - Array of payment methods that are loaded.
|
||||
* @see #setMethod(PluginManager)
|
||||
*/
|
||||
public static Set<String> getDependencies() {
|
||||
return Dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interprets Plugin class data to verify whether it is compatible with an existing payment method to use for
|
||||
* payments and other various economic activity.
|
||||
*
|
||||
* @param plugin Plugin data from bukkit, Internal Class file.
|
||||
* @return Method <em>or</em> Null
|
||||
*/
|
||||
public static Method createMethod(final Plugin plugin) {
|
||||
for (final Method method : Methods) {
|
||||
if (method.isCompatible(plugin)) {
|
||||
method.setPlugin(plugin);
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void addMethod(final String name, final Method method) {
|
||||
Dependencies.add(name);
|
||||
Methods.add(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if Register has set a payment method for usage yet.
|
||||
*
|
||||
* @return <code>boolean</code>
|
||||
* @see #setMethod(PluginManager)
|
||||
* @see #checkDisabled(Plugin)
|
||||
*/
|
||||
public static boolean hasMethod() {
|
||||
return Method != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks Plugin Class against a multitude of checks to verify it's usability as a payment method.
|
||||
*
|
||||
* @param manager the plugin manager for the server
|
||||
* @return <code>boolean</code> True on success, False on failure.
|
||||
*/
|
||||
public static boolean setMethod(final PluginManager manager) {
|
||||
if (hasMethod()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (self) {
|
||||
self = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
boolean match = false;
|
||||
Plugin plugin;
|
||||
|
||||
for (final String name : getDependencies()) {
|
||||
if (hasMethod()) {
|
||||
break;
|
||||
}
|
||||
|
||||
plugin = manager.getPlugin(name);
|
||||
if (plugin == null || !plugin.isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Method current = createMethod(plugin);
|
||||
if (current == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preferred.isEmpty()) {
|
||||
Method = current;
|
||||
} else {
|
||||
Attachables.add(current);
|
||||
}
|
||||
}
|
||||
|
||||
if (!preferred.isEmpty()) {
|
||||
do {
|
||||
if (hasMethod()) {
|
||||
match = true;
|
||||
} else {
|
||||
for (final Method attached : Attachables) {
|
||||
if (attached == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasMethod()) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (preferred.isEmpty()) {
|
||||
Method = attached;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
if (preferred.equalsIgnoreCase(attached.getName())) {
|
||||
Method = attached;
|
||||
} else {
|
||||
Method = attached;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
} while (!match);
|
||||
}
|
||||
|
||||
return hasMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the preferred economy
|
||||
*
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
public static boolean setPreferred(final String check) {
|
||||
if (getDependencies().contains(check)) {
|
||||
preferred = check;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grab the existing and initialized (hopefully) Method Class.
|
||||
*
|
||||
* @return <code>Method</code> <em>or</em> <code>Null</code>
|
||||
*/
|
||||
public static Method getMethod() {
|
||||
return Method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify is a plugin is disabled, only does this if we there is an existing payment method initialized in
|
||||
* Register.
|
||||
*
|
||||
* @param method Plugin data from bukkit, Internal Class file.
|
||||
* @return <code>boolean</code>
|
||||
*/
|
||||
public static boolean checkDisabled(final Plugin method) {
|
||||
if (!hasMethod()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Method.isCompatible(method)) {
|
||||
Method = null;
|
||||
}
|
||||
|
||||
return Method == null;
|
||||
}
|
||||
}
|
||||
@@ -1,280 +0,0 @@
|
||||
package com.earth2me.essentials.register.payment.methods;
|
||||
|
||||
import com.earth2me.essentials.register.payment.Method;
|
||||
import net.milkbowl.vault.economy.Economy;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
public class VaultEco implements Method {
|
||||
private Plugin vault;
|
||||
private Economy economy;
|
||||
|
||||
@Override
|
||||
public Plugin getPlugin() {
|
||||
return this.vault;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlugin(final Plugin plugin) {
|
||||
this.vault = plugin;
|
||||
final RegisteredServiceProvider<Economy> economyProvider = this.vault.getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
|
||||
if (economyProvider != null) {
|
||||
this.economy = economyProvider.getProvider();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createAccount(final String name, final Double amount) {
|
||||
if (hasAccount(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.vault.getDescription().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBackend() {
|
||||
return economy == null ? "NoEco" : economy.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLongName() {
|
||||
return getName().concat(" - Economy: ").concat(getBackend());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return this.vault.getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fractionalDigits() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(final double amount) {
|
||||
return this.economy.format(amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBanks() {
|
||||
return this.economy.hasBankSupport();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBank(final String bank) {
|
||||
return this.economy.getBanks().contains(bank);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAccount(final String name) {
|
||||
return this.economy.hasAccount(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBankAccount(final String bank, final String name) {
|
||||
return this.economy.isBankOwner(bank, name).transactionSuccess() || this.economy.isBankMember(bank, name).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createAccount(final String name) {
|
||||
return this.economy.createBank(name, "").transactionSuccess();
|
||||
}
|
||||
|
||||
public boolean createAccount(final String name, final double balance) {
|
||||
if (!this.economy.createBank(name, "").transactionSuccess()) {
|
||||
return false;
|
||||
}
|
||||
return this.economy.bankDeposit(name, balance).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodAccount getAccount(final String name) {
|
||||
if (!hasAccount(name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new VaultAccount(name, this.economy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodBankAccount getBankAccount(final String bank, final String name) {
|
||||
if (!hasBankAccount(bank, name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new VaultBankAccount(bank, economy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompatible(final Plugin plugin) {
|
||||
try {
|
||||
final RegisteredServiceProvider<Economy> ecoPlugin = plugin.getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
|
||||
return plugin.getName().equals("Vault") && ecoPlugin != null && !ecoPlugin.getProvider().getName().equals("Essentials Economy");
|
||||
} catch (final LinkageError | Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class VaultAccount implements MethodAccount {
|
||||
private final String name;
|
||||
private final Economy economy;
|
||||
|
||||
VaultAccount(final String name, final Economy economy) {
|
||||
this.name = name;
|
||||
this.economy = economy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double balance() {
|
||||
return this.economy.getBalance(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean set(final double amount) {
|
||||
if (!this.economy.withdrawPlayer(this.name, this.balance()).transactionSuccess()) {
|
||||
return false;
|
||||
}
|
||||
if (amount == 0) {
|
||||
return true;
|
||||
}
|
||||
return this.economy.depositPlayer(this.name, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(final double amount) {
|
||||
return this.economy.depositPlayer(this.name, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean subtract(final double amount) {
|
||||
return this.economy.withdrawPlayer(this.name, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean multiply(final double amount) {
|
||||
final double balance = this.balance();
|
||||
return this.set(balance * amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean divide(final double amount) {
|
||||
final double balance = this.balance();
|
||||
return this.set(balance / amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEnough(final double amount) {
|
||||
return this.balance() >= amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOver(final double amount) {
|
||||
return this.balance() > amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnder(final double amount) {
|
||||
return this.balance() < amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegative() {
|
||||
return this.balance() < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove() {
|
||||
return this.set(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
public static class VaultBankAccount implements MethodBankAccount {
|
||||
private final String bank;
|
||||
private final Economy economy;
|
||||
|
||||
public VaultBankAccount(final String bank, final Economy economy) {
|
||||
this.bank = bank;
|
||||
this.economy = economy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBankName() {
|
||||
return this.bank;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBankId() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double balance() {
|
||||
return this.economy.bankBalance(this.bank).balance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean set(final double amount) {
|
||||
if (!this.economy.bankWithdraw(this.bank, this.balance()).transactionSuccess()) {
|
||||
return false;
|
||||
}
|
||||
if (amount == 0) {
|
||||
return true;
|
||||
}
|
||||
return this.economy.bankDeposit(this.bank, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(final double amount) {
|
||||
return this.economy.bankDeposit(this.bank, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean subtract(final double amount) {
|
||||
return this.economy.bankWithdraw(this.bank, amount).transactionSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean multiply(final double amount) {
|
||||
final double balance = this.balance();
|
||||
return this.set(balance * amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean divide(final double amount) {
|
||||
final double balance = this.balance();
|
||||
return this.set(balance / amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEnough(final double amount) {
|
||||
return this.balance() >= amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOver(final double amount) {
|
||||
return this.balance() > amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnder(final double amount) {
|
||||
return this.balance() < amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegative() {
|
||||
return this.balance() < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove() {
|
||||
return this.set(0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.earth2me.essentials.settings;
|
||||
|
||||
import com.earth2me.essentials.storage.MapValueType;
|
||||
import com.earth2me.essentials.storage.StorageObject;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Jails implements StorageObject {
|
||||
@MapValueType(Location.class)
|
||||
private Map<String, Location> jails = new HashMap<>();
|
||||
|
||||
public Map<String, Location> getJails() {
|
||||
return jails;
|
||||
}
|
||||
|
||||
public void setJails(final Map<String, Location> jails) {
|
||||
this.jails = jails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Jails jails1 = (Jails) o;
|
||||
return Objects.equals(jails, jails1.jails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(jails);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.earth2me.essentials.settings;
|
||||
|
||||
import com.earth2me.essentials.storage.MapValueType;
|
||||
import com.earth2me.essentials.storage.StorageObject;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Spawns implements StorageObject {
|
||||
@MapValueType(Location.class)
|
||||
private Map<String, Location> spawns = new HashMap<>();
|
||||
|
||||
public Map<String, Location> getSpawns() {
|
||||
return spawns;
|
||||
}
|
||||
|
||||
public void setSpawns(final Map<String, Location> spawns) {
|
||||
this.spawns = spawns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Spawns spawns1 = (Spawns) o;
|
||||
return Objects.equals(spawns, spawns1.spawns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(spawns);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.earth2me.essentials.signs;
|
||||
|
||||
import com.earth2me.essentials.User;
|
||||
import net.ess3.api.IEssentials;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class SignMail extends EssentialsSign {
|
||||
public SignMail() {
|
||||
super("Mail");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException {
|
||||
final List<String> mail = player.getMails();
|
||||
if (mail.isEmpty()) {
|
||||
player.sendMessage(tl("noNewMail"));
|
||||
return false;
|
||||
}
|
||||
for (final String s : mail) {
|
||||
player.sendMessage(s);
|
||||
}
|
||||
player.sendMessage(tl("markMailAsRead"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public abstract class AbstractDelayedYamlFileReader<T extends StorageObject> implements Runnable {
|
||||
protected final transient IEssentials plugin;
|
||||
private final transient File file;
|
||||
private final transient Class<T> clazz;
|
||||
|
||||
public AbstractDelayedYamlFileReader(final IEssentials ess, final File file, final Class<T> clazz) {
|
||||
this.file = file;
|
||||
this.clazz = clazz;
|
||||
this.plugin = ess;
|
||||
ess.runTaskAsynchronously(this);
|
||||
}
|
||||
|
||||
public abstract void onStart();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
onStart();
|
||||
try {
|
||||
final FileReader reader = new FileReader(file);
|
||||
try {
|
||||
final T object = new YamlStorageReader(reader, plugin).load(clazz);
|
||||
onSuccess(object);
|
||||
} finally {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (final IOException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "File can't be closed: " + file.toString(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (final FileNotFoundException ex) {
|
||||
onException();
|
||||
if (plugin.getSettings() == null || plugin.getSettings().isDebug()) {
|
||||
Bukkit.getLogger().log(Level.INFO, "File not found: " + file.toString());
|
||||
}
|
||||
} catch (final ObjectLoadException ex) {
|
||||
onException();
|
||||
Bukkit.getLogger().log(Level.SEVERE, "File broken: " + file.toString(), ex.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void onSuccess(T object);
|
||||
|
||||
public abstract void onException();
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public abstract class AbstractDelayedYamlFileWriter implements Runnable {
|
||||
private final transient File file;
|
||||
|
||||
public AbstractDelayedYamlFileWriter(final IEssentials ess, final File file) {
|
||||
this.file = file;
|
||||
ess.runTaskAsynchronously(this);
|
||||
}
|
||||
|
||||
public abstract StorageObject getObject();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
PrintWriter pw = null;
|
||||
try {
|
||||
final StorageObject object = getObject();
|
||||
final File folder = file.getParentFile();
|
||||
if (!folder.exists()) {
|
||||
folder.mkdirs();
|
||||
}
|
||||
pw = new PrintWriter(file);
|
||||
new YamlStorageWriter(pw).save(object);
|
||||
} catch (final FileNotFoundException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, file.toString(), ex);
|
||||
} finally {
|
||||
onFinish();
|
||||
if (pw != null) {
|
||||
pw.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract void onFinish();
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import com.earth2me.essentials.IConf;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.IReload;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public abstract class AsyncStorageObjectHolder<T extends StorageObject> implements IConf, IStorageObjectHolder<T>, IReload {
|
||||
protected final transient IEssentials ess;
|
||||
private final transient ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||
private final transient Class<T> clazz;
|
||||
private transient T data;
|
||||
|
||||
public AsyncStorageObjectHolder(final IEssentials ess, final Class<T> clazz) {
|
||||
this.ess = ess;
|
||||
this.clazz = clazz;
|
||||
try {
|
||||
this.data = clazz.newInstance();
|
||||
} catch (final IllegalAccessException | InstantiationException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acquireReadLock() {
|
||||
rwl.readLock().lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acquireWriteLock() {
|
||||
while (rwl.getReadHoldCount() > 0) {
|
||||
rwl.readLock().unlock();
|
||||
}
|
||||
rwl.writeLock().lock();
|
||||
rwl.readLock().lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
if (rwl.isWriteLockedByCurrentThread()) {
|
||||
rwl.writeLock().unlock();
|
||||
new StorageObjectDataWriter();
|
||||
}
|
||||
while (rwl.getReadHoldCount() > 0) {
|
||||
rwl.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
new StorageObjectDataReader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload() {
|
||||
new StorageObjectDataReader();
|
||||
}
|
||||
|
||||
public abstract void finishRead();
|
||||
|
||||
public abstract void finishWrite();
|
||||
|
||||
public abstract File getStorageFile();
|
||||
|
||||
private class StorageObjectDataWriter extends AbstractDelayedYamlFileWriter {
|
||||
StorageObjectDataWriter() {
|
||||
super(ess, getStorageFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageObject getObject() {
|
||||
acquireReadLock();
|
||||
return getData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
unlock();
|
||||
finishWrite();
|
||||
}
|
||||
}
|
||||
|
||||
private class StorageObjectDataReader extends AbstractDelayedYamlFileReader<T> {
|
||||
StorageObjectDataReader() {
|
||||
super(ess, getStorageFile(), clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
rwl.writeLock().lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(final T object) {
|
||||
if (object != null) {
|
||||
data = object;
|
||||
}
|
||||
rwl.writeLock().unlock();
|
||||
finishRead();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException() {
|
||||
if (data == null) {
|
||||
try {
|
||||
data = clazz.newInstance();
|
||||
} catch (final IllegalAccessException | InstantiationException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
rwl.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import com.earth2me.essentials.Enchantments;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.material.MaterialData;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.yaml.snakeyaml.constructor.BaseConstructor;
|
||||
import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor;
|
||||
import org.yaml.snakeyaml.introspector.PropertyUtils;
|
||||
import org.yaml.snakeyaml.nodes.MappingNode;
|
||||
import org.yaml.snakeyaml.nodes.Node;
|
||||
import org.yaml.snakeyaml.nodes.NodeId;
|
||||
import org.yaml.snakeyaml.nodes.NodeTuple;
|
||||
import org.yaml.snakeyaml.nodes.ScalarNode;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class BukkitConstructor extends CustomClassLoaderConstructor {
|
||||
private Method constructScalarMethod = null;
|
||||
|
||||
public BukkitConstructor(final Class<?> clazz, final Plugin plugin) {
|
||||
super(clazz, plugin.getClass().getClassLoader());
|
||||
yamlClassConstructors.put(NodeId.scalar, new ConstructBukkitScalar());
|
||||
yamlClassConstructors.put(NodeId.mapping, new ConstructBukkitMapping());
|
||||
|
||||
final PropertyUtils propertyUtils = getPropertyUtils();
|
||||
propertyUtils.setSkipMissingProperties(true);
|
||||
setPropertyUtils(propertyUtils);
|
||||
}
|
||||
|
||||
protected String constructScalarRefl(final ScalarNode scalarNode) {
|
||||
try {
|
||||
if (constructScalarMethod == null) {
|
||||
constructScalarMethod = BaseConstructor.class.getDeclaredMethod("constructScalar", ScalarNode.class);
|
||||
}
|
||||
return (String) constructScalarMethod.invoke(this, scalarNode);
|
||||
} catch (final NoSuchMethodException
|
||||
| SecurityException
|
||||
| IllegalAccessException
|
||||
| IllegalArgumentException
|
||||
| InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private class ConstructBukkitScalar extends ConstructScalar {
|
||||
|
||||
@Override
|
||||
public Object construct(final Node node) {
|
||||
if (node.getType().equals(Material.class)) {
|
||||
final String val = constructScalarRefl((ScalarNode) node);
|
||||
return Material.matchMaterial(val);
|
||||
}
|
||||
|
||||
if (node.getType().equals(MaterialData.class)) {
|
||||
final String val = constructScalarRefl((ScalarNode) node);
|
||||
if (val.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final String[] split = val.split("[:+',;.]", 2);
|
||||
if (split.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Material mat = Material.matchMaterial(split[0]);
|
||||
|
||||
if (mat == null) {
|
||||
return null;
|
||||
}
|
||||
byte data = 0;
|
||||
if (split.length == 2 && NumberUtil.isInt(split[1])) {
|
||||
data = Byte.parseByte(split[1]);
|
||||
}
|
||||
return new MaterialData(mat, data);
|
||||
}
|
||||
if (node.getType().equals(ItemStack.class)) {
|
||||
final String val = constructScalarRefl((ScalarNode) node);
|
||||
if (val.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final String[] split1 = val.split("\\W");
|
||||
if (split1.length == 0) {
|
||||
return null;
|
||||
}
|
||||
final String[] split2 = split1[0].split("[:+',;.]", 2);
|
||||
if (split2.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Material mat = Material.matchMaterial(split2[0]);
|
||||
|
||||
if (mat == null) {
|
||||
return null;
|
||||
}
|
||||
short data = 0;
|
||||
if (split2.length == 2 && NumberUtil.isInt(split2[1])) {
|
||||
data = Short.parseShort(split2[1]);
|
||||
}
|
||||
int size = mat.getMaxStackSize();
|
||||
if (split1.length > 1 && NumberUtil.isInt(split1[1])) {
|
||||
size = Integer.parseInt(split1[1]);
|
||||
}
|
||||
final ItemStack stack = new ItemStack(mat, size, data);
|
||||
if (split1.length > 2) {
|
||||
for (int i = 2; i < split1.length; i++) {
|
||||
final String[] split3 = split1[0].split("[:+',;.]", 2);
|
||||
if (split3.length < 1) {
|
||||
continue;
|
||||
}
|
||||
final Enchantment enchantment = Enchantments.getByName(split3[0]);
|
||||
if (enchantment == null) {
|
||||
continue;
|
||||
}
|
||||
int level = enchantment.getStartLevel();
|
||||
if (split3.length == 2 && NumberUtil.isInt(split3[1])) {
|
||||
level = Integer.parseInt(split3[1]);
|
||||
}
|
||||
if (level < enchantment.getStartLevel()) {
|
||||
level = enchantment.getStartLevel();
|
||||
}
|
||||
if (level > enchantment.getMaxLevel()) {
|
||||
level = enchantment.getMaxLevel();
|
||||
}
|
||||
stack.addUnsafeEnchantment(enchantment, level);
|
||||
}
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
if (node.getType().equals(EnchantmentLevel.class)) {
|
||||
final String val = constructScalarRefl((ScalarNode) node);
|
||||
if (val.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final String[] split = val.split("[:+',;.]", 2);
|
||||
if (split.length == 0) {
|
||||
return null;
|
||||
}
|
||||
final Enchantment enchant = Enchantments.getByName(split[0]);
|
||||
if (enchant == null) {
|
||||
return null;
|
||||
}
|
||||
int level = enchant.getStartLevel();
|
||||
if (split.length == 2 && NumberUtil.isInt(split[1])) {
|
||||
level = Integer.parseInt(split[1]);
|
||||
}
|
||||
if (level < enchant.getStartLevel()) {
|
||||
level = enchant.getStartLevel();
|
||||
}
|
||||
if (level > enchant.getMaxLevel()) {
|
||||
level = enchant.getMaxLevel();
|
||||
}
|
||||
return new EnchantmentLevel(enchant, level);
|
||||
}
|
||||
return super.construct(node);
|
||||
}
|
||||
}
|
||||
|
||||
private class ConstructBukkitMapping extends ConstructMapping {
|
||||
|
||||
@Override
|
||||
public Object construct(final Node node) {
|
||||
if (node.getType().equals(Location.class)) {
|
||||
//TODO: NPE checks
|
||||
final MappingNode mnode = (MappingNode) node;
|
||||
String worldName = "";
|
||||
double x = 0, y = 0, z = 0;
|
||||
float yaw = 0, pitch = 0;
|
||||
if (mnode.getValue().size() < 4) {
|
||||
return null;
|
||||
}
|
||||
for (final NodeTuple nodeTuple : mnode.getValue()) {
|
||||
final String key = constructScalarRefl((ScalarNode) nodeTuple.getKeyNode());
|
||||
final ScalarNode snode = (ScalarNode) nodeTuple.getValueNode();
|
||||
if (key.equalsIgnoreCase("world")) {
|
||||
worldName = constructScalarRefl(snode);
|
||||
}
|
||||
if (key.equalsIgnoreCase("x")) {
|
||||
x = Double.parseDouble(constructScalarRefl(snode));
|
||||
}
|
||||
if (key.equalsIgnoreCase("y")) {
|
||||
y = Double.parseDouble(constructScalarRefl(snode));
|
||||
}
|
||||
if (key.equalsIgnoreCase("z")) {
|
||||
z = Double.parseDouble(constructScalarRefl(snode));
|
||||
}
|
||||
if (key.equalsIgnoreCase("yaw")) {
|
||||
yaw = Float.parseFloat(constructScalarRefl(snode));
|
||||
}
|
||||
if (key.equalsIgnoreCase("pitch")) {
|
||||
pitch = Float.parseFloat(constructScalarRefl(snode));
|
||||
}
|
||||
}
|
||||
if (worldName == null || worldName.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) {
|
||||
return null;
|
||||
}
|
||||
return new Location(world, x, y, z, yaw, pitch);
|
||||
}
|
||||
return super.construct(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Comment {
|
||||
String[] value() default "";
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class EnchantmentLevel implements Entry<Enchantment, Integer> {
|
||||
private Enchantment enchantment;
|
||||
private int level;
|
||||
|
||||
public EnchantmentLevel(final Enchantment enchantment, final int level) {
|
||||
this.enchantment = enchantment;
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public Enchantment getEnchantment() {
|
||||
return enchantment;
|
||||
}
|
||||
|
||||
public void setEnchantment(final Enchantment enchantment) {
|
||||
this.enchantment = enchantment;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(final int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enchantment getKey() {
|
||||
return enchantment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer setValue(final Integer v) {
|
||||
final int t = level;
|
||||
level = v;
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return enchantment.hashCode() ^ level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj instanceof Entry) {
|
||||
final Entry entry = (Entry) obj;
|
||||
if (entry.getKey() instanceof Enchantment && entry.getValue() instanceof Integer) {
|
||||
final Enchantment enchant = (Enchantment) entry.getKey();
|
||||
final Integer lvl = (Integer) entry.getValue();
|
||||
return this.enchantment.equals(enchant) && this.level == lvl;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
public interface IStorageObjectHolder<T extends StorageObject> {
|
||||
T getData();
|
||||
|
||||
void acquireReadLock();
|
||||
|
||||
void acquireWriteLock();
|
||||
|
||||
void close();
|
||||
|
||||
void unlock();
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
public interface IStorageReader {
|
||||
<T extends StorageObject> T load(final Class<? extends T> clazz) throws ObjectLoadException;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
public interface IStorageWriter {
|
||||
void save(final StorageObject object);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ListType {
|
||||
Class value() default String.class;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MapKeyType {
|
||||
Class value() default String.class;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
public class ObjectLoadException extends Exception {
|
||||
public ObjectLoadException(final Throwable thrwbl) {
|
||||
super(thrwbl);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
public interface StorageObject {
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.yaml.snakeyaml.TypeDescription;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class YamlStorageReader implements IStorageReader {
|
||||
private transient static final Map<Class, Yaml> PREPARED_YAMLS = Collections.synchronizedMap(new HashMap<>());
|
||||
private transient static final Map<Class, ReentrantLock> LOCKS = new HashMap<>();
|
||||
private transient final Reader reader;
|
||||
private transient final Plugin plugin;
|
||||
|
||||
public YamlStorageReader(final Reader reader, final Plugin plugin) {
|
||||
this.reader = reader;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends StorageObject> T load(final Class<? extends T> clazz) throws ObjectLoadException {
|
||||
Yaml yaml = PREPARED_YAMLS.get(clazz);
|
||||
if (yaml == null) {
|
||||
yaml = new Yaml(prepareConstructor(clazz));
|
||||
PREPARED_YAMLS.put(clazz, yaml);
|
||||
}
|
||||
ReentrantLock lock;
|
||||
synchronized (LOCKS) {
|
||||
lock = LOCKS.get(clazz);
|
||||
if (lock == null) {
|
||||
lock = new ReentrantLock();
|
||||
}
|
||||
}
|
||||
lock.lock();
|
||||
try {
|
||||
T object = yaml.load(reader);
|
||||
if (object == null) {
|
||||
object = clazz.newInstance();
|
||||
}
|
||||
return object;
|
||||
} catch (final IllegalAccessException | InstantiationException ex) {
|
||||
throw new ObjectLoadException(ex);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private Constructor prepareConstructor(final Class<?> clazz) {
|
||||
final Constructor constructor = new BukkitConstructor(clazz, plugin);
|
||||
final Set<Class> classes = new HashSet<>();
|
||||
|
||||
prepareConstructor(constructor, classes, clazz);
|
||||
return constructor;
|
||||
}
|
||||
|
||||
private void prepareConstructor(final Constructor constructor, final Set<Class> classes, final Class clazz) {
|
||||
classes.add(clazz);
|
||||
final TypeDescription description = new TypeDescription(clazz);
|
||||
for (final Field field : clazz.getDeclaredFields()) {
|
||||
prepareList(field, description, classes, constructor);
|
||||
prepareMap(field, description, classes, constructor);
|
||||
if (StorageObject.class.isAssignableFrom(field.getType()) && !classes.contains(field.getType())) {
|
||||
prepareConstructor(constructor, classes, field.getType());
|
||||
}
|
||||
}
|
||||
constructor.addTypeDescription(description);
|
||||
}
|
||||
|
||||
private void prepareList(final Field field, final TypeDescription description, final Set<Class> classes, final Constructor constructor) {
|
||||
final ListType listType = field.getAnnotation(ListType.class);
|
||||
if (listType != null) {
|
||||
description.putListPropertyType(field.getName(), listType.value());
|
||||
if (StorageObject.class.isAssignableFrom(listType.value()) && !classes.contains(listType.value())) {
|
||||
prepareConstructor(constructor, classes, listType.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareMap(final Field field, final TypeDescription description, final Set<Class> classes, final Constructor constructor) {
|
||||
final MapValueType mapType = field.getAnnotation(MapValueType.class);
|
||||
if (mapType != null) {
|
||||
final MapKeyType mapKeyType = field.getAnnotation(MapKeyType.class);
|
||||
description.putMapPropertyType(field.getName(), mapKeyType == null ? String.class : mapKeyType.value(), mapType.value());
|
||||
if (StorageObject.class.isAssignableFrom(mapType.value()) && !classes.contains(mapType.value())) {
|
||||
prepareConstructor(constructor, classes, mapType.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.material.MaterialData;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class YamlStorageWriter implements IStorageWriter {
|
||||
private transient static final Pattern NON_WORD_PATTERN = Pattern.compile("\\W");
|
||||
private transient static final Yaml YAML = new Yaml();
|
||||
private transient final PrintWriter writer;
|
||||
|
||||
public YamlStorageWriter(final PrintWriter writer) {
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(final StorageObject object) {
|
||||
try {
|
||||
writeToFile(object, 0, object.getClass());
|
||||
} catch (final IllegalArgumentException | IllegalAccessException ex) {
|
||||
Logger.getLogger(YamlStorageWriter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeToFile(final Object object, final int depth, final Class clazz) throws IllegalAccessException {
|
||||
for (final Field field : clazz.getDeclaredFields()) {
|
||||
final int modifier = field.getModifiers();
|
||||
if (Modifier.isPrivate(modifier) && !Modifier.isTransient(modifier) && !Modifier.isStatic(modifier)) {
|
||||
field.setAccessible(true);
|
||||
|
||||
final Object data = field.get(object);
|
||||
if (writeKey(field, depth, data)) {
|
||||
continue;
|
||||
}
|
||||
if (data instanceof StorageObject) {
|
||||
writer.println();
|
||||
writeToFile(data, depth + 1, data.getClass());
|
||||
} else if (data instanceof Map) {
|
||||
writeMap((Map<Object, Object>) data, depth + 1);
|
||||
} else if (data instanceof Collection) {
|
||||
writeCollection((Collection<Object>) data, depth + 1);
|
||||
} else if (data instanceof Location) {
|
||||
writeLocation((Location) data, depth + 1);
|
||||
} else {
|
||||
writeScalar(data);
|
||||
writer.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean writeKey(final Field field, final int depth, final Object data) {
|
||||
final boolean commentPresent = writeComment(field, depth);
|
||||
if (data == null && !commentPresent) {
|
||||
return true;
|
||||
}
|
||||
writeIndention(depth);
|
||||
if (data == null && commentPresent) {
|
||||
writer.print('#');
|
||||
}
|
||||
final String name = field.getName();
|
||||
writer.print(name);
|
||||
writer.print(": ");
|
||||
if (data == null && commentPresent) {
|
||||
writer.println();
|
||||
writer.println();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean writeComment(final Field field, final int depth) {
|
||||
final boolean commentPresent = field.isAnnotationPresent(Comment.class);
|
||||
if (commentPresent) {
|
||||
final Comment comments = field.getAnnotation(Comment.class);
|
||||
for (final String comment : comments.value()) {
|
||||
final String trimmed = comment.trim();
|
||||
if (trimmed.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
writeIndention(depth);
|
||||
writer.print("# ");
|
||||
writer.print(trimmed);
|
||||
writer.println();
|
||||
}
|
||||
}
|
||||
return commentPresent;
|
||||
}
|
||||
|
||||
private void writeCollection(final Collection<Object> data, final int depth) throws IllegalAccessException {
|
||||
writer.println();
|
||||
if (data.isEmpty()) {
|
||||
writer.println();
|
||||
}
|
||||
for (final Object entry : data) {
|
||||
if (entry != null) {
|
||||
writeIndention(depth);
|
||||
writer.print("- ");
|
||||
if (entry instanceof StorageObject) {
|
||||
writer.println();
|
||||
writeToFile(entry, depth + 1, entry.getClass());
|
||||
} else if (entry instanceof Location) {
|
||||
writeLocation((Location) entry, depth + 1);
|
||||
} else {
|
||||
writeScalar(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
writer.println();
|
||||
}
|
||||
|
||||
private void writeMap(final Map<Object, Object> data, final int depth) throws IllegalArgumentException, IllegalAccessException {
|
||||
writer.println();
|
||||
if (data.isEmpty()) {
|
||||
writer.println();
|
||||
}
|
||||
for (final Entry<Object, Object> entry : data.entrySet()) {
|
||||
final Object value = entry.getValue();
|
||||
if (value != null) {
|
||||
writeIndention(depth);
|
||||
writeKey(entry.getKey());
|
||||
writer.print(": ");
|
||||
if (value instanceof StorageObject) {
|
||||
writer.println();
|
||||
writeToFile(value, depth + 1, value.getClass());
|
||||
} else if (value instanceof Collection) {
|
||||
writeCollection((Collection<Object>) value, depth + 1);
|
||||
} else if (value instanceof Location) {
|
||||
writeLocation((Location) value, depth + 1);
|
||||
} else {
|
||||
writeScalar(value);
|
||||
writer.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeIndention(final int depth) {
|
||||
for (int i = 0; i < depth; i++) {
|
||||
writer.print(" ");
|
||||
}
|
||||
}
|
||||
|
||||
private void writeScalar(final Object data) {
|
||||
if (data instanceof String || data instanceof Boolean || data instanceof Number) {
|
||||
synchronized (YAML) {
|
||||
YAML.dumpAll(Collections.singletonList(data).iterator(), writer);
|
||||
}
|
||||
} else if (data instanceof Material) {
|
||||
writeMaterial(data);
|
||||
writer.println();
|
||||
} else if (data instanceof MaterialData) {
|
||||
writeMaterialData(data);
|
||||
writer.println();
|
||||
} else if (data instanceof ItemStack) {
|
||||
writeItemStack(data);
|
||||
writer.println();
|
||||
} else if (data instanceof EnchantmentLevel) {
|
||||
writeEnchantmentLevel(data);
|
||||
writer.println();
|
||||
} else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeKey(final Object data) {
|
||||
if (data instanceof String || data instanceof Boolean || data instanceof Number) {
|
||||
final String output = data.toString();
|
||||
if (NON_WORD_PATTERN.matcher(output).find()) {
|
||||
writer.print('"');
|
||||
writer.print(output.replace("\"", "\\\""));
|
||||
writer.print('"');
|
||||
} else {
|
||||
writer.print(output);
|
||||
}
|
||||
} else if (data instanceof Material) {
|
||||
writeMaterial(data);
|
||||
} else if (data instanceof MaterialData) {
|
||||
writeMaterialData(data);
|
||||
} else if (data instanceof EnchantmentLevel) {
|
||||
writeEnchantmentLevel(data);
|
||||
} else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeMaterial(final Object data) {
|
||||
writer.print(data.toString().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
private void writeMaterialData(final Object data) {
|
||||
final MaterialData matData = (MaterialData) data;
|
||||
writeMaterial(matData.getItemType());
|
||||
if (matData.getData() > 0) {
|
||||
writer.print(':');
|
||||
writer.print(matData.getData());
|
||||
}
|
||||
}
|
||||
|
||||
private void writeItemStack(final Object data) {
|
||||
final ItemStack itemStack = (ItemStack) data;
|
||||
writeMaterialData(itemStack.getData());
|
||||
writer.print(' ');
|
||||
writer.print(itemStack.getAmount());
|
||||
for (final Entry<Enchantment, Integer> entry : itemStack.getEnchantments().entrySet()) {
|
||||
writer.print(' ');
|
||||
writeEnchantmentLevel(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeEnchantmentLevel(final Object data) {
|
||||
final Entry<Enchantment, Integer> enchLevel = (Entry<Enchantment, Integer>) data;
|
||||
writer.print(enchLevel.getKey().getName().toLowerCase(Locale.ENGLISH));
|
||||
writer.print(':');
|
||||
writer.print(enchLevel.getValue());
|
||||
}
|
||||
|
||||
private void writeLocation(final Location entry, final int depth) {
|
||||
writer.println();
|
||||
writeIndention(depth);
|
||||
writer.print("world: ");
|
||||
writeScalar(entry.getWorld().getName());
|
||||
writeIndention(depth);
|
||||
writer.print("x: ");
|
||||
writeScalar(entry.getX());
|
||||
writeIndention(depth);
|
||||
writer.print("y: ");
|
||||
writeScalar(entry.getY());
|
||||
writeIndention(depth);
|
||||
writer.print("z: ");
|
||||
writeScalar(entry.getZ());
|
||||
writeIndention(depth);
|
||||
writer.print("yaw: ");
|
||||
writeScalar(entry.getYaw());
|
||||
writeIndention(depth);
|
||||
writer.print("pitch: ");
|
||||
writeScalar(entry.getPitch());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.PluginIdentifiableCommand;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class AlternativeCommandsHandler {
|
||||
private static final Logger LOGGER = Logger.getLogger("Essentials");
|
||||
private final transient Map<String, List<Command>> altcommands = new HashMap<>();
|
||||
private final transient Map<String, String> disabledList = new HashMap<>();
|
||||
private final transient IEssentials ess;
|
||||
|
||||
public AlternativeCommandsHandler(final IEssentials ess) {
|
||||
this.ess = ess;
|
||||
for (final Plugin plugin : ess.getServer().getPluginManager().getPlugins()) {
|
||||
if (plugin.isEnabled()) {
|
||||
addPlugin(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void addPlugin(final Plugin plugin) {
|
||||
if (plugin.getDescription().getMain().contains("com.earth2me.essentials") || plugin.getDescription().getMain().contains("net.essentialsx")) {
|
||||
return;
|
||||
}
|
||||
for (final Map.Entry<String, Command> entry : getPluginCommands(plugin).entrySet()) {
|
||||
final String[] commandSplit = entry.getKey().split(":", 2);
|
||||
final String commandName = commandSplit.length > 1 ? commandSplit[1] : entry.getKey();
|
||||
final Command command = entry.getValue();
|
||||
|
||||
final List<Command> pluginCommands = altcommands.computeIfAbsent(commandName.toLowerCase(Locale.ENGLISH), k -> new ArrayList<>());
|
||||
boolean found = false;
|
||||
for (final Command pc2 : pluginCommands) {
|
||||
// Safe cast, everything that's added comes from getPluginCommands which already performs the cast check.
|
||||
if (((PluginIdentifiableCommand) pc2).getPlugin().equals(plugin)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
pluginCommands.add(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Command> getPluginCommands(Plugin plugin) {
|
||||
final Map<String, Command> commands = new HashMap<>();
|
||||
for (final Map.Entry<String, Command> entry : ess.getKnownCommandsProvider().getKnownCommands().entrySet()) {
|
||||
if (entry.getValue() instanceof PluginIdentifiableCommand && ((PluginIdentifiableCommand) entry.getValue()).getPlugin().equals(plugin)) {
|
||||
commands.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
|
||||
public void removePlugin(final Plugin plugin) {
|
||||
final Iterator<Map.Entry<String, List<Command>>> iterator = altcommands.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final Map.Entry<String, List<Command>> entry = iterator.next();
|
||||
entry.getValue().removeIf(pc -> !(pc instanceof PluginIdentifiableCommand) || ((PluginIdentifiableCommand) pc).getPlugin().equals(plugin));
|
||||
if (entry.getValue().isEmpty()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Command getAlternative(final String label) {
|
||||
final List<Command> commands = altcommands.get(label);
|
||||
if (commands == null || commands.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (commands.size() == 1) {
|
||||
return commands.get(0);
|
||||
}
|
||||
// return the first command that is not an alias
|
||||
for (final Command command : commands) {
|
||||
if (command.getName().equalsIgnoreCase(label)) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
// return the first alias
|
||||
return commands.get(0);
|
||||
}
|
||||
|
||||
public void executed(final String label, final Command pc) {
|
||||
if (pc instanceof PluginIdentifiableCommand) {
|
||||
final String altString = ((PluginIdentifiableCommand) pc).getPlugin().getName() + ":" + pc.getName();
|
||||
if (ess.getSettings().isDebug()) {
|
||||
LOGGER.log(Level.INFO, "Essentials: Alternative command " + label + " found, using " + altString);
|
||||
}
|
||||
disabledList.put(label, altString);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> disabledCommands() {
|
||||
return disabledList;
|
||||
}
|
||||
}
|
||||
+42
-14
@@ -134,6 +134,13 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nowUnsafe(Location loc, TeleportCause cause, CompletableFuture<Boolean> future) {
|
||||
final CompletableFuture<Boolean> paperFuture = PaperLib.teleportAsync(teleportOwner.getBase(), loc, cause);
|
||||
paperFuture.thenAccept(future::complete);
|
||||
paperFuture.exceptionally(future::completeExceptionally);
|
||||
}
|
||||
|
||||
private void runOnMain(final Runnable runnable) throws ExecutionException, InterruptedException {
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
runnable.run();
|
||||
@@ -153,9 +160,9 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
final PreTeleportEvent event = new PreTeleportEvent(teleportee, cause, target);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
future.complete(false);
|
||||
return;
|
||||
}
|
||||
teleportee.setLastLocation();
|
||||
|
||||
if (!ess.getSettings().isForcePassengerTeleport() && !teleportee.getBase().isEmpty()) {
|
||||
if (!ess.getSettings().isTeleportPassengerDismount()) {
|
||||
@@ -170,15 +177,19 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
return;
|
||||
}
|
||||
}
|
||||
teleportee.setLastLocation();
|
||||
|
||||
if (teleportee.isAuthorized("essentials.back.onteleport")) {
|
||||
teleportee.setLastLocation();
|
||||
}
|
||||
|
||||
final Location targetLoc = target.getLocation();
|
||||
if (ess.getSettings().isTeleportSafetyEnabled() && LocationUtil.isBlockOutsideWorldBorder(targetLoc.getWorld(), targetLoc.getBlockX(), targetLoc.getBlockZ())) {
|
||||
if (ess.getSettings().isTeleportSafetyEnabled() && !ess.getSettings().isForceDisableTeleportSafety() && LocationUtil.isBlockOutsideWorldBorder(targetLoc.getWorld(), targetLoc.getBlockX(), targetLoc.getBlockZ())) {
|
||||
targetLoc.setX(LocationUtil.getXInsideWorldBorder(targetLoc.getWorld(), targetLoc.getBlockX()));
|
||||
targetLoc.setZ(LocationUtil.getZInsideWorldBorder(targetLoc.getWorld(), targetLoc.getBlockZ()));
|
||||
}
|
||||
PaperLib.getChunkAtAsync(targetLoc).thenAccept(chunk -> {
|
||||
PaperLib.getChunkAtAsync(targetLoc.getWorld(), targetLoc.getBlockX() >> 4, targetLoc.getBlockZ() >> 4, true, true).thenAccept(chunk -> {
|
||||
Location loc = targetLoc;
|
||||
if (LocationUtil.isBlockUnsafeForUser(teleportee, chunk.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) {
|
||||
if (LocationUtil.isBlockUnsafeForUser(ess, teleportee, chunk.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) {
|
||||
if (ess.getSettings().isTeleportSafetyEnabled()) {
|
||||
if (ess.getSettings().isForceDisableTeleportSafety()) {
|
||||
//The chunk we're teleporting to is 100% going to be loaded here, no need to teleport async.
|
||||
@@ -209,6 +220,9 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
}
|
||||
}
|
||||
future.complete(true);
|
||||
}).exceptionally(th -> {
|
||||
future.completeExceptionally(th);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -246,6 +260,7 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
final TeleportWarmupEvent event = new TeleportWarmupEvent(teleportee, cause, target, delay);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
future.complete(false);
|
||||
return;
|
||||
}
|
||||
delay = event.getDelay();
|
||||
@@ -266,10 +281,12 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
}
|
||||
|
||||
if (cooldown(true, future)) {
|
||||
future.complete(false);
|
||||
return;
|
||||
}
|
||||
if (delay <= 0 || teleportOwner.isAuthorized("essentials.teleport.timer.bypass") || teleportee.isAuthorized("essentials.teleport.timer.bypass")) {
|
||||
if (cooldown(false, future)) {
|
||||
future.complete(false);
|
||||
return;
|
||||
}
|
||||
nowAsync(teleportee, target, cause, future);
|
||||
@@ -279,12 +296,13 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
return;
|
||||
}
|
||||
}
|
||||
future.complete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
cancel(false);
|
||||
warnUser(teleportee, delay);
|
||||
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false);
|
||||
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false, future);
|
||||
}
|
||||
|
||||
private void teleportOther(final IUser teleporter, final IUser teleportee, final ITarget target, final Trade chargeFor, final TeleportCause cause, final CompletableFuture<Boolean> future) {
|
||||
@@ -330,12 +348,13 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
return;
|
||||
}
|
||||
}
|
||||
future.complete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
cancel(false);
|
||||
warnUser(teleportee, delay);
|
||||
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false);
|
||||
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false, future);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -366,12 +385,13 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
if (chargeFor != null) {
|
||||
chargeFor.charge(teleportOwner, future);
|
||||
}
|
||||
future.complete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
cancel(false);
|
||||
warnUser(teleportOwner, delay);
|
||||
initTimer((long) (delay * 1000.0), teleportOwner, null, chargeFor, cause, true);
|
||||
initTimer((long) (delay * 1000.0), teleportOwner, null, chargeFor, cause, true, future);
|
||||
}
|
||||
|
||||
void respawnNow(final IUser teleportee, final TeleportCause cause, final CompletableFuture<Boolean> future) {
|
||||
@@ -387,6 +407,9 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
ess.getServer().getPluginManager().callEvent(pre);
|
||||
nowAsync(teleportee, new LocationTarget(pre.getRespawnLocation()), cause, future);
|
||||
}
|
||||
}).exceptionally(th -> {
|
||||
future.completeExceptionally(th);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -406,10 +429,15 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
future.completeExceptionally(e);
|
||||
return;
|
||||
}
|
||||
otherUser.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
if (!otherUser.equals(teleportOwner)) {
|
||||
teleportOwner.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
}
|
||||
final String finalWarp = warp;
|
||||
future.thenAccept(success -> {
|
||||
if (success) {
|
||||
otherUser.sendMessage(tl("warpingTo", finalWarp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
if (!otherUser.equals(teleportOwner)) {
|
||||
teleportOwner.sendMessage(tl("warpingTo", finalWarp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
}
|
||||
}
|
||||
});
|
||||
teleport(otherUser, new LocationTarget(loc), chargeFor, cause, future);
|
||||
}
|
||||
|
||||
@@ -443,8 +471,8 @@ public class AsyncTeleport implements IAsyncTeleport {
|
||||
}
|
||||
}
|
||||
|
||||
private void initTimer(final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) {
|
||||
timedTeleport = new AsyncTimedTeleport(teleportOwner, ess, this, delay, teleportUser, target, chargeFor, cause, respawn);
|
||||
private void initTimer(final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn, CompletableFuture<Boolean> future) {
|
||||
timedTeleport = new AsyncTimedTeleport(teleportOwner, ess, this, delay, future, teleportUser, target, chargeFor, cause, respawn);
|
||||
}
|
||||
|
||||
public enum TeleportType {
|
||||
+21
-8
@@ -18,6 +18,7 @@ public class AsyncTimedTeleport implements Runnable {
|
||||
private final UUID timer_teleportee;
|
||||
private final long timer_started; // time this task was initiated
|
||||
private final long timer_delay; // how long to delay the teleportPlayer
|
||||
private final CompletableFuture<Boolean> parentFuture;
|
||||
// note that I initially stored a clone of the location for reference, but...
|
||||
// when comparing locations, I got incorrect mismatches (rounding errors, looked like)
|
||||
// so, the X/Y/Z values are stored instead and rounded off
|
||||
@@ -33,6 +34,10 @@ public class AsyncTimedTeleport implements Runnable {
|
||||
private double timer_health;
|
||||
|
||||
AsyncTimedTeleport(final IUser user, final IEssentials ess, final AsyncTeleport teleport, final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) {
|
||||
this(user, ess, teleport, delay, null, teleportUser, target, chargeFor, cause, respawn);
|
||||
}
|
||||
|
||||
AsyncTimedTeleport(final IUser user, final IEssentials ess, final AsyncTeleport teleport, final long delay, final CompletableFuture<Boolean> future, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) {
|
||||
this.teleportOwner = user;
|
||||
this.ess = ess;
|
||||
this.teleport = teleport;
|
||||
@@ -50,6 +55,18 @@ public class AsyncTimedTeleport implements Runnable {
|
||||
this.timer_canMove = user.isAuthorized("essentials.teleport.timer.move");
|
||||
|
||||
timer_task = ess.runTaskTimerAsynchronously(this, 20, 20).getTaskId();
|
||||
|
||||
if (future != null) {
|
||||
this.parentFuture = future;
|
||||
return;
|
||||
}
|
||||
|
||||
final CompletableFuture<Boolean> cFuture = new CompletableFuture<>();
|
||||
cFuture.exceptionally(e -> {
|
||||
ess.showError(teleportOwner.getSource(), e, "\\ teleport");
|
||||
return false;
|
||||
});
|
||||
this.parentFuture = cFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,20 +115,16 @@ public class AsyncTimedTeleport implements Runnable {
|
||||
cancelTimer(false);
|
||||
teleportUser.sendMessage(tl("teleportationCommencing"));
|
||||
|
||||
final CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||
future.exceptionally(e -> {
|
||||
ess.showError(teleportOwner.getSource(), e, "\\ teleport");
|
||||
return false;
|
||||
});
|
||||
if (timer_chargeFor != null) {
|
||||
timer_chargeFor.isAffordableFor(teleportOwner);
|
||||
}
|
||||
|
||||
if (timer_respawn) {
|
||||
teleport.respawnNow(teleportUser, timer_cause, future);
|
||||
teleport.respawnNow(teleportUser, timer_cause, parentFuture);
|
||||
} else {
|
||||
teleport.nowAsync(teleportUser, timer_teleportTarget, timer_cause, future);
|
||||
teleport.nowAsync(teleportUser, timer_teleportTarget, timer_cause, parentFuture);
|
||||
}
|
||||
future.thenAccept(success -> {
|
||||
parentFuture.thenAccept(success -> {
|
||||
if (timer_chargeFor != null) {
|
||||
try {
|
||||
timer_chargeFor.charge(teleportOwner);
|
||||
File renamed without changes.
@@ -0,0 +1,94 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.essentialsx.api.v2.services.BalanceTop;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class BalanceTopImpl implements BalanceTop {
|
||||
private final IEssentials ess;
|
||||
private LinkedHashMap<UUID, BalanceTop.Entry> topCache = new LinkedHashMap<>();
|
||||
private BigDecimal balanceTopTotal = BigDecimal.ZERO;
|
||||
private long cacheAge = 0;
|
||||
private CompletableFuture<Void> cacheLock;
|
||||
|
||||
public BalanceTopImpl(IEssentials ess) {
|
||||
this.ess = ess;
|
||||
ess.getServer().getServicesManager().register(BalanceTop.class, this, ess, ServicePriority.Normal);
|
||||
}
|
||||
|
||||
private void calculateBalanceTopMap() {
|
||||
final List<Entry> entries = new LinkedList<>();
|
||||
BigDecimal newTotal = BigDecimal.ZERO;
|
||||
for (UUID u : ess.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.isBaltopExempt()) {
|
||||
final BigDecimal userMoney = user.getMoney();
|
||||
user.updateMoneyCache(userMoney);
|
||||
newTotal = newTotal.add(userMoney);
|
||||
final String name;
|
||||
if (user.getBase() instanceof OfflinePlayer) {
|
||||
name = user.getLastAccountName();
|
||||
} else if (user.isHidden()) {
|
||||
name = user.getName();
|
||||
} else {
|
||||
name = user.getDisplayName();
|
||||
}
|
||||
entries.add(new BalanceTop.Entry(user.getUUID(), name, userMoney));
|
||||
}
|
||||
}
|
||||
}
|
||||
final LinkedHashMap<UUID, Entry> sortedMap = new LinkedHashMap<>();
|
||||
entries.sort((entry1, entry2) -> entry2.getBalance().compareTo(entry1.getBalance()));
|
||||
for (Entry entry : entries) {
|
||||
sortedMap.put(entry.getUuid(), entry);
|
||||
}
|
||||
topCache = sortedMap;
|
||||
balanceTopTotal = newTotal;
|
||||
cacheAge = System.currentTimeMillis();
|
||||
cacheLock.complete(null);
|
||||
cacheLock = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> calculateBalanceTopMapAsync() {
|
||||
if (cacheLock != null) {
|
||||
return cacheLock;
|
||||
}
|
||||
cacheLock = new CompletableFuture<>();
|
||||
ess.runTaskAsynchronously(this::calculateBalanceTopMap);
|
||||
return cacheLock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, Entry> getBalanceTopCache() {
|
||||
return Collections.unmodifiableMap(topCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCacheAge() {
|
||||
return cacheAge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getBalanceTopTotal() {
|
||||
return balanceTopTotal;
|
||||
}
|
||||
|
||||
public boolean isCacheLocked() {
|
||||
return cacheLock != null;
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
+11
-1
@@ -6,8 +6,13 @@ import org.bukkit.Server;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public final class Console implements IMessageRecipient {
|
||||
public static final String NAME = "Console";
|
||||
public static final String DISPLAY_NAME = tl("consoleName");
|
||||
private static Console instance; // Set in essentials
|
||||
|
||||
private final IEssentials ess;
|
||||
@@ -43,9 +48,14 @@ public final class Console implements IMessageRecipient {
|
||||
return Console.NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return Console.NAME;
|
||||
return Console.DISPLAY_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
+30
-1
@@ -277,14 +277,27 @@ public final class Enchantments {
|
||||
}
|
||||
|
||||
public static Enchantment getByName(final String name) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Enchantment enchantment = null;
|
||||
if (isFlat) { // 1.13+ only
|
||||
enchantment = Enchantment.getByKey(NamespacedKey.minecraft(name.toLowerCase()));
|
||||
try {
|
||||
enchantment = Enchantment.getByKey(NamespacedKey.minecraft(name.toLowerCase()));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// NamespacedKey throws IAE if key does not match regex
|
||||
}
|
||||
}
|
||||
|
||||
if (enchantment == null) {
|
||||
enchantment = Enchantment.getByName(name.toUpperCase());
|
||||
}
|
||||
if (enchantment == null) {
|
||||
enchantment = Enchantment.getByName(name.toLowerCase());
|
||||
}
|
||||
if (enchantment == null) {
|
||||
enchantment = Enchantment.getByName(name);
|
||||
}
|
||||
if (enchantment == null) {
|
||||
enchantment = ENCHANTMENTS.get(name.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
@@ -301,4 +314,20 @@ public final class Enchantments {
|
||||
public static Set<String> keySet() {
|
||||
return ENCHANTMENTS.keySet();
|
||||
}
|
||||
|
||||
public static void registerEnchantment(String name, Enchantment enchantment) {
|
||||
if (ENCHANTMENTS.containsKey(name) || ALIASENCHANTMENTS.containsKey(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ENCHANTMENTS.put(name, enchantment);
|
||||
}
|
||||
|
||||
public static void registerAlias(String name, Enchantment enchantment) {
|
||||
if (ENCHANTMENTS.containsKey(name) || ALIASENCHANTMENTS.containsKey(name) || !ENCHANTMENTS.containsValue(enchantment)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ALIASENCHANTMENTS.put(name, enchantment);
|
||||
}
|
||||
}
|
||||
+427
-156
@@ -21,7 +21,10 @@ import com.earth2me.essentials.commands.EssentialsCommand;
|
||||
import com.earth2me.essentials.commands.IEssentialsCommand;
|
||||
import com.earth2me.essentials.commands.NoChargeException;
|
||||
import com.earth2me.essentials.commands.NotEnoughArgumentsException;
|
||||
import com.earth2me.essentials.commands.PlayerNotFoundException;
|
||||
import com.earth2me.essentials.commands.QuietAbortException;
|
||||
import com.earth2me.essentials.economy.EconomyLayers;
|
||||
import com.earth2me.essentials.economy.vault.VaultEconomyProvider;
|
||||
import com.earth2me.essentials.items.AbstractItemDb;
|
||||
import com.earth2me.essentials.items.CustomItemResolver;
|
||||
import com.earth2me.essentials.items.FlatItemDb;
|
||||
@@ -29,14 +32,14 @@ import com.earth2me.essentials.items.LegacyItemDb;
|
||||
import com.earth2me.essentials.metrics.MetricsWrapper;
|
||||
import com.earth2me.essentials.perm.PermissionsDefaults;
|
||||
import com.earth2me.essentials.perm.PermissionsHandler;
|
||||
import com.earth2me.essentials.register.payment.Methods;
|
||||
import com.earth2me.essentials.signs.SignBlockListener;
|
||||
import com.earth2me.essentials.signs.SignEntityListener;
|
||||
import com.earth2me.essentials.signs.SignPlayerListener;
|
||||
import com.earth2me.essentials.textreader.IText;
|
||||
import com.earth2me.essentials.textreader.KeywordReplacer;
|
||||
import com.earth2me.essentials.textreader.SimpleTextInput;
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
import com.earth2me.essentials.updatecheck.UpdateChecker;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import com.earth2me.essentials.utils.VersionUtil;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.ess3.api.Economy;
|
||||
@@ -44,28 +47,50 @@ import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.IItemDb;
|
||||
import net.ess3.api.IJails;
|
||||
import net.ess3.api.ISettings;
|
||||
import net.ess3.nms.refl.providers.ReflDataWorldInfoProvider;
|
||||
import net.ess3.nms.refl.providers.ReflFormattedCommandAliasProvider;
|
||||
import net.ess3.nms.refl.providers.ReflKnownCommandsProvider;
|
||||
import net.ess3.nms.refl.providers.ReflOnlineModeProvider;
|
||||
import net.ess3.nms.refl.providers.ReflPersistentDataProvider;
|
||||
import net.ess3.nms.refl.providers.ReflServerStateProvider;
|
||||
import net.ess3.nms.refl.providers.ReflSpawnEggProvider;
|
||||
import net.ess3.nms.refl.providers.ReflSpawnerBlockProvider;
|
||||
import net.ess3.nms.refl.providers.ReflKnownCommandsProvider;
|
||||
import net.ess3.nms.refl.providers.ReflSyncCommandsProvider;
|
||||
import net.ess3.provider.ContainerProvider;
|
||||
import net.ess3.provider.FormattedCommandAliasProvider;
|
||||
import net.ess3.provider.ItemUnbreakableProvider;
|
||||
import net.ess3.provider.KnownCommandsProvider;
|
||||
import net.ess3.provider.MaterialTagProvider;
|
||||
import net.ess3.provider.PersistentDataProvider;
|
||||
import net.ess3.provider.PotionMetaProvider;
|
||||
import net.ess3.provider.ProviderListener;
|
||||
import net.ess3.provider.SerializationProvider;
|
||||
import net.ess3.provider.ServerStateProvider;
|
||||
import net.ess3.provider.SpawnEggProvider;
|
||||
import net.ess3.provider.SpawnerBlockProvider;
|
||||
import net.ess3.provider.SpawnerItemProvider;
|
||||
import net.ess3.provider.SyncCommandsProvider;
|
||||
import net.ess3.provider.WorldInfoProvider;
|
||||
import net.ess3.provider.providers.BasePotionDataProvider;
|
||||
import net.ess3.provider.providers.BlockMetaSpawnerItemProvider;
|
||||
import net.ess3.provider.providers.BukkitMaterialTagProvider;
|
||||
import net.ess3.provider.providers.BukkitSpawnerBlockProvider;
|
||||
import net.ess3.provider.providers.FixedHeightWorldInfoProvider;
|
||||
import net.ess3.provider.providers.FlatSpawnEggProvider;
|
||||
import net.ess3.provider.providers.LegacyItemUnbreakableProvider;
|
||||
import net.ess3.provider.providers.LegacyPotionMetaProvider;
|
||||
import net.ess3.provider.providers.LegacySpawnEggProvider;
|
||||
import net.ess3.provider.providers.ModernItemUnbreakableProvider;
|
||||
import net.ess3.provider.providers.ModernPersistentDataProvider;
|
||||
import net.ess3.provider.providers.ModernDataWorldInfoProvider;
|
||||
import net.ess3.provider.providers.PaperContainerProvider;
|
||||
import net.ess3.provider.providers.PaperKnownCommandsProvider;
|
||||
import net.ess3.provider.providers.PaperMaterialTagProvider;
|
||||
import net.ess3.provider.providers.PaperRecipeBookListener;
|
||||
import net.ess3.provider.providers.PaperSerializationProvider;
|
||||
import net.ess3.provider.providers.PaperServerStateProvider;
|
||||
import net.essentialsx.api.v2.services.BalanceTop;
|
||||
import net.essentialsx.api.v2.services.mail.MailService;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
@@ -74,6 +99,7 @@ import org.bukkit.command.BlockCommandSender;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.command.PluginIdentifiableCommand;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
@@ -84,24 +110,26 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.world.WorldLoadEvent;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
import org.bukkit.plugin.InvalidDescriptionException;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.yaml.snakeyaml.error.YAMLException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
@@ -125,7 +153,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
private transient PermissionsHandler permissionsHandler;
|
||||
private transient AlternativeCommandsHandler alternativeCommandsHandler;
|
||||
private transient UserMap userMap;
|
||||
private transient BalanceTopImpl balanceTop;
|
||||
private transient ExecuteTimer execTimer;
|
||||
private transient MailService mail;
|
||||
private transient I18n i18n;
|
||||
private transient MetricsWrapper metrics;
|
||||
private transient EssentialsTimer timer;
|
||||
@@ -135,14 +165,23 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
private transient PotionMetaProvider potionMetaProvider;
|
||||
private transient ServerStateProvider serverStateProvider;
|
||||
private transient ContainerProvider containerProvider;
|
||||
private transient SerializationProvider serializationProvider;
|
||||
private transient KnownCommandsProvider knownCommandsProvider;
|
||||
private transient FormattedCommandAliasProvider formattedCommandAliasProvider;
|
||||
private transient ProviderListener recipeBookEventProvider;
|
||||
private transient MaterialTagProvider materialTagProvider;
|
||||
private transient SyncCommandsProvider syncCommandsProvider;
|
||||
private transient PersistentDataProvider persistentDataProvider;
|
||||
private transient ReflOnlineModeProvider onlineModeProvider;
|
||||
private transient ItemUnbreakableProvider unbreakableProvider;
|
||||
private transient WorldInfoProvider worldInfoProvider;
|
||||
private transient Kits kits;
|
||||
private transient RandomTeleport randomTeleport;
|
||||
private transient UpdateChecker updateChecker;
|
||||
private transient Map<String, IEssentialsCommand> commandMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
// TODO: improve legacy code
|
||||
Methods.init();
|
||||
EconomyLayers.init();
|
||||
}
|
||||
|
||||
public Essentials() {
|
||||
@@ -177,7 +216,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
LOGGER.log(Level.INFO, tl("usingTempFolderForTesting"));
|
||||
LOGGER.log(Level.INFO, dataFolder.toString());
|
||||
settings = new Settings(this);
|
||||
mail = new MailServiceImpl(this);
|
||||
userMap = new UserMap(this);
|
||||
balanceTop = new BalanceTopImpl(this);
|
||||
permissionsHandler = new PermissionsHandler(this, false);
|
||||
Economy.setEss(this);
|
||||
confList = new ArrayList<>();
|
||||
@@ -186,6 +227,17 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
kits = new Kits(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
try {
|
||||
// Vault registers their Essentials provider at low priority, so we have to use normal priority here
|
||||
Class.forName("net.milkbowl.vault.economy.Economy");
|
||||
getServer().getServicesManager().register(net.milkbowl.vault.economy.Economy.class, new VaultEconomyProvider(this), this, ServicePriority.Normal);
|
||||
} catch (final ClassNotFoundException ignored) {
|
||||
// Probably safer than fetching for the plugin as bukkit may not have marked it as enabled at this point in time
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
try {
|
||||
@@ -201,6 +253,12 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
Console.setInstance(this);
|
||||
|
||||
switch (VersionUtil.getServerSupportStatus()) {
|
||||
case NMS_CLEANROOM:
|
||||
getLogger().severe(tl("serverUnsupportedCleanroom"));
|
||||
break;
|
||||
case DANGEROUS_FORK:
|
||||
getLogger().severe(tl("serverUnsupportedDangerous"));
|
||||
break;
|
||||
case UNSTABLE:
|
||||
getLogger().severe(tl("serverUnsupportedMods"));
|
||||
break;
|
||||
@@ -212,6 +270,10 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
break;
|
||||
}
|
||||
|
||||
if (VersionUtil.getSupportStatusClass() != null) {
|
||||
getLogger().info(tl("serverUnsupportedClass", VersionUtil.getSupportStatusClass()));
|
||||
}
|
||||
|
||||
final PluginManager pm = getServer().getPluginManager();
|
||||
for (final Plugin plugin : pm.getPlugins()) {
|
||||
if (plugin.getDescription().getName().startsWith("Essentials") && !plugin.getDescription().getVersion().equals(this.getDescription().getVersion()) && !plugin.getDescription().getName().equals("EssentialsAntiCheat")) {
|
||||
@@ -219,131 +281,163 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
final EssentialsUpgrade upgrade = new EssentialsUpgrade(this);
|
||||
upgrade.beforeSettings();
|
||||
execTimer.mark("Upgrade");
|
||||
final EssentialsUpgrade upgrade = new EssentialsUpgrade(this);
|
||||
upgrade.beforeSettings();
|
||||
execTimer.mark("Upgrade");
|
||||
|
||||
confList = new ArrayList<>();
|
||||
settings = new Settings(this);
|
||||
confList.add(settings);
|
||||
execTimer.mark("Settings");
|
||||
confList = new ArrayList<>();
|
||||
settings = new Settings(this);
|
||||
confList.add(settings);
|
||||
execTimer.mark("Settings");
|
||||
|
||||
userMap = new UserMap(this);
|
||||
confList.add(userMap);
|
||||
execTimer.mark("Init(Usermap)");
|
||||
mail = new MailServiceImpl(this);
|
||||
execTimer.mark("Init(Mail)");
|
||||
|
||||
kits = new Kits(this);
|
||||
confList.add(kits);
|
||||
upgrade.convertKits();
|
||||
execTimer.mark("Kits");
|
||||
userMap = new UserMap(this);
|
||||
confList.add(userMap);
|
||||
execTimer.mark("Init(Usermap)");
|
||||
|
||||
upgrade.afterSettings();
|
||||
execTimer.mark("Upgrade2");
|
||||
balanceTop = new BalanceTopImpl(this);
|
||||
execTimer.mark("Init(BalanceTop)");
|
||||
|
||||
warps = new Warps(getServer(), this.getDataFolder());
|
||||
confList.add(warps);
|
||||
execTimer.mark("Init(Warp)");
|
||||
kits = new Kits(this);
|
||||
confList.add(kits);
|
||||
upgrade.convertKits();
|
||||
execTimer.mark("Kits");
|
||||
|
||||
worth = new Worth(this.getDataFolder());
|
||||
confList.add(worth);
|
||||
execTimer.mark("Init(Worth)");
|
||||
upgrade.afterSettings();
|
||||
execTimer.mark("Upgrade2");
|
||||
|
||||
itemDb = getItemDbFromConfig();
|
||||
confList.add(itemDb);
|
||||
execTimer.mark("Init(ItemDB)");
|
||||
warps = new Warps(this.getDataFolder());
|
||||
confList.add(warps);
|
||||
execTimer.mark("Init(Warp)");
|
||||
|
||||
randomTeleport = new RandomTeleport(this);
|
||||
if (randomTeleport.getPreCache()) {
|
||||
randomTeleport.cacheRandomLocations(randomTeleport.getCenter(), randomTeleport.getMinRange(), randomTeleport.getMaxRange());
|
||||
}
|
||||
confList.add(randomTeleport);
|
||||
execTimer.mark("Init(RandomTeleport)");
|
||||
worth = new Worth(this.getDataFolder());
|
||||
confList.add(worth);
|
||||
execTimer.mark("Init(Worth)");
|
||||
|
||||
customItemResolver = new CustomItemResolver(this);
|
||||
try {
|
||||
itemDb.registerResolver(this, "custom_items", customItemResolver);
|
||||
confList.add(customItemResolver);
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
customItemResolver = null;
|
||||
}
|
||||
execTimer.mark("Init(CustomItemResolver)");
|
||||
itemDb = getItemDbFromConfig();
|
||||
confList.add(itemDb);
|
||||
execTimer.mark("Init(ItemDB)");
|
||||
|
||||
jails = new Jails(this);
|
||||
confList.add(jails);
|
||||
execTimer.mark("Init(Jails)");
|
||||
|
||||
//Spawner item provider only uses one but it's here for legacy...
|
||||
spawnerItemProvider = new BlockMetaSpawnerItemProvider();
|
||||
|
||||
//Spawner block providers
|
||||
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_12_0_R01)) {
|
||||
spawnerBlockProvider = new ReflSpawnerBlockProvider();
|
||||
} else {
|
||||
spawnerBlockProvider = new BukkitSpawnerBlockProvider();
|
||||
}
|
||||
|
||||
//Spawn Egg Providers
|
||||
if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_8_8_R01)) {
|
||||
spawnEggProvider = new LegacySpawnEggProvider();
|
||||
} else if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_12_2_R01)) {
|
||||
spawnEggProvider = new ReflSpawnEggProvider();
|
||||
} else {
|
||||
spawnEggProvider = new FlatSpawnEggProvider();
|
||||
}
|
||||
|
||||
//Potion Meta Provider
|
||||
if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_8_8_R01)) {
|
||||
potionMetaProvider = new LegacyPotionMetaProvider();
|
||||
} else {
|
||||
potionMetaProvider = new BasePotionDataProvider();
|
||||
}
|
||||
|
||||
//Server State Provider
|
||||
//Container Provider
|
||||
if (PaperLib.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_2_R01)) {
|
||||
serverStateProvider = new PaperServerStateProvider();
|
||||
containerProvider = new PaperContainerProvider();
|
||||
} else {
|
||||
serverStateProvider = new ReflServerStateProvider(getLogger());
|
||||
}
|
||||
|
||||
//Event Providers
|
||||
if (PaperLib.isPaper()) {
|
||||
try {
|
||||
Class.forName("com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent");
|
||||
recipeBookEventProvider = new PaperRecipeBookListener(event -> {
|
||||
if (this.getUser(((PlayerEvent) event).getPlayer()).isRecipeSee()) {
|
||||
((Cancellable) event).setCancelled(true);
|
||||
}
|
||||
});
|
||||
} catch (final ClassNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
//Known Commands Provider
|
||||
if (PaperLib.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_11_2_R01)) {
|
||||
knownCommandsProvider = new PaperKnownCommandsProvider();
|
||||
} else {
|
||||
knownCommandsProvider = new ReflKnownCommandsProvider();
|
||||
}
|
||||
|
||||
execTimer.mark("Init(Providers)");
|
||||
reload();
|
||||
|
||||
// The item spawn blacklist is loaded with all other settings, before the item
|
||||
// DB, but it depends on the item DB, so we need to reload it again here:
|
||||
((Settings) settings)._lateLoadItemSpawnBlacklist();
|
||||
} catch (final YAMLException exception) {
|
||||
if (pm.getPlugin("EssentialsUpdate") != null) {
|
||||
LOGGER.log(Level.SEVERE, tl("essentialsHelp2"));
|
||||
} else {
|
||||
LOGGER.log(Level.SEVERE, tl("essentialsHelp1"));
|
||||
}
|
||||
handleCrash(exception);
|
||||
return;
|
||||
randomTeleport = new RandomTeleport(this);
|
||||
if (randomTeleport.getPreCache()) {
|
||||
randomTeleport.cacheRandomLocations(randomTeleport.getCenter(), randomTeleport.getMinRange(), randomTeleport.getMaxRange());
|
||||
}
|
||||
confList.add(randomTeleport);
|
||||
execTimer.mark("Init(RandomTeleport)");
|
||||
|
||||
customItemResolver = new CustomItemResolver(this);
|
||||
try {
|
||||
itemDb.registerResolver(this, "custom_items", customItemResolver);
|
||||
confList.add(customItemResolver);
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
customItemResolver = null;
|
||||
}
|
||||
execTimer.mark("Init(CustomItemResolver)");
|
||||
|
||||
jails = new Jails(this);
|
||||
confList.add(jails);
|
||||
execTimer.mark("Init(Jails)");
|
||||
|
||||
EconomyLayers.onEnable(this);
|
||||
|
||||
//Spawner item provider only uses one but it's here for legacy...
|
||||
spawnerItemProvider = new BlockMetaSpawnerItemProvider();
|
||||
|
||||
//Spawner block providers
|
||||
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_12_0_R01)) {
|
||||
spawnerBlockProvider = new ReflSpawnerBlockProvider();
|
||||
} else {
|
||||
spawnerBlockProvider = new BukkitSpawnerBlockProvider();
|
||||
}
|
||||
|
||||
//Spawn Egg Providers
|
||||
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_9_R01)) {
|
||||
spawnEggProvider = new LegacySpawnEggProvider();
|
||||
} else if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_12_2_R01)) {
|
||||
spawnEggProvider = new ReflSpawnEggProvider();
|
||||
} else {
|
||||
spawnEggProvider = new FlatSpawnEggProvider();
|
||||
}
|
||||
|
||||
//Potion Meta Provider
|
||||
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_9_R01)) {
|
||||
potionMetaProvider = new LegacyPotionMetaProvider();
|
||||
} else {
|
||||
potionMetaProvider = new BasePotionDataProvider();
|
||||
}
|
||||
|
||||
//Server State Provider
|
||||
//Container Provider
|
||||
if (PaperLib.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_2_R01)) {
|
||||
serverStateProvider = new PaperServerStateProvider();
|
||||
containerProvider = new PaperContainerProvider();
|
||||
serializationProvider = new PaperSerializationProvider();
|
||||
} else {
|
||||
serverStateProvider = new ReflServerStateProvider();
|
||||
}
|
||||
|
||||
//Event Providers
|
||||
if (PaperLib.isPaper()) {
|
||||
try {
|
||||
Class.forName("com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent");
|
||||
recipeBookEventProvider = new PaperRecipeBookListener(event -> {
|
||||
if (this.getUser(((PlayerEvent) event).getPlayer()).isRecipeSee()) {
|
||||
((Cancellable) event).setCancelled(true);
|
||||
}
|
||||
});
|
||||
} catch (final ClassNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
//Known Commands Provider
|
||||
if (PaperLib.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_11_2_R01)) {
|
||||
knownCommandsProvider = new PaperKnownCommandsProvider();
|
||||
} else {
|
||||
knownCommandsProvider = new ReflKnownCommandsProvider();
|
||||
}
|
||||
|
||||
// Command aliases provider
|
||||
formattedCommandAliasProvider = new ReflFormattedCommandAliasProvider(PaperLib.isPaper());
|
||||
|
||||
// Material Tag Providers
|
||||
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_13_0_R01)) {
|
||||
materialTagProvider = PaperLib.isPaper() ? new PaperMaterialTagProvider() : new BukkitMaterialTagProvider();
|
||||
}
|
||||
|
||||
// Sync Commands Provider
|
||||
syncCommandsProvider = new ReflSyncCommandsProvider();
|
||||
|
||||
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_14_4_R01)) {
|
||||
persistentDataProvider = new ModernPersistentDataProvider(this);
|
||||
} else {
|
||||
persistentDataProvider = new ReflPersistentDataProvider(this);
|
||||
}
|
||||
|
||||
onlineModeProvider = new ReflOnlineModeProvider();
|
||||
|
||||
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_11_2_R01)) {
|
||||
unbreakableProvider = new ModernItemUnbreakableProvider();
|
||||
} else {
|
||||
unbreakableProvider = new LegacyItemUnbreakableProvider();
|
||||
}
|
||||
|
||||
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_17_1_R01)) {
|
||||
worldInfoProvider = new ModernDataWorldInfoProvider();
|
||||
} else if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_16_5_R01)) {
|
||||
worldInfoProvider = new ReflDataWorldInfoProvider();
|
||||
} else {
|
||||
worldInfoProvider = new FixedHeightWorldInfoProvider();
|
||||
}
|
||||
|
||||
execTimer.mark("Init(Providers)");
|
||||
reload();
|
||||
|
||||
// The item spawn blacklist is loaded with all other settings, before the item
|
||||
// DB, but it depends on the item DB, so we need to reload it again here:
|
||||
((Settings) settings)._lateLoadItemSpawnBlacklist();
|
||||
backup = new Backup(this);
|
||||
permissionsHandler = new PermissionsHandler(this, settings.useBukkitPermissions());
|
||||
alternativeCommandsHandler = new AlternativeCommandsHandler(this);
|
||||
@@ -358,8 +452,18 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
PermissionsDefaults.registerAllBackDefaults();
|
||||
PermissionsDefaults.registerAllHatDefaults();
|
||||
|
||||
updateChecker = new UpdateChecker(this);
|
||||
runTaskAsynchronously(() -> {
|
||||
getLogger().log(Level.INFO, tl("versionFetching"));
|
||||
for (String str : updateChecker.getVersionMessages(false, true)) {
|
||||
getLogger().log(getSettings().isUpdateCheckEnabled() ? Level.WARNING : Level.INFO, str);
|
||||
}
|
||||
});
|
||||
|
||||
metrics = new MetricsWrapper(this, 858, true);
|
||||
|
||||
execTimer.mark("Init(External)");
|
||||
|
||||
final String timeroutput = execTimer.end();
|
||||
if (getSettings().isDebug()) {
|
||||
LOGGER.log(Level.INFO, "Essentials load {0}", timeroutput);
|
||||
@@ -435,7 +539,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
user.sendMessage(tl("unvanishedReload"));
|
||||
}
|
||||
if (stopping) {
|
||||
user.setLastLocation();
|
||||
user.setLogoutLocation();
|
||||
if (!user.isHidden()) {
|
||||
user.setLastLogout(System.currentTimeMillis());
|
||||
}
|
||||
@@ -487,6 +591,21 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
registerListeners(pm);
|
||||
}
|
||||
|
||||
private IEssentialsCommand loadCommand(final String path, final String name, final IEssentialsModule module, final ClassLoader classLoader) throws Exception {
|
||||
if (commandMap.containsKey(name)) {
|
||||
return commandMap.get(name);
|
||||
}
|
||||
final IEssentialsCommand cmd = (IEssentialsCommand) classLoader.loadClass(path + name).getDeclaredConstructor().newInstance();
|
||||
cmd.setEssentials(this);
|
||||
cmd.setEssentialsModule(module);
|
||||
commandMap.put(name, cmd);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
public Map<String, IEssentialsCommand> getCommandMap() {
|
||||
return commandMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(final CommandSender sender, final Command command, final String commandLabel, final String[] args) {
|
||||
return onTabCompleteEssentials(sender, command, commandLabel, args, Essentials.class.getClassLoader(),
|
||||
@@ -498,10 +617,10 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
final ClassLoader classLoader, final String commandPath, final String permissionPrefix,
|
||||
final IEssentialsModule module) {
|
||||
if (!getSettings().isCommandOverridden(command.getName()) && (!commandLabel.startsWith("e") || commandLabel.equalsIgnoreCase(command.getName()))) {
|
||||
final PluginCommand pc = alternativeCommandsHandler.getAlternative(commandLabel);
|
||||
if (pc != null) {
|
||||
final Command pc = alternativeCommandsHandler.getAlternative(commandLabel);
|
||||
if (pc instanceof PluginCommand) {
|
||||
try {
|
||||
final TabCompleter completer = pc.getTabCompleter();
|
||||
final TabCompleter completer = ((PluginCommand) pc).getTabCompleter();
|
||||
if (completer != null) {
|
||||
return completer.onTabComplete(cSender, command, commandLabel, args);
|
||||
}
|
||||
@@ -522,14 +641,18 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
|
||||
// Check for disabled commands
|
||||
if (getSettings().isCommandDisabled(commandLabel)) {
|
||||
if (getKnownCommandsProvider().getKnownCommands().containsKey(commandLabel)) {
|
||||
final Command newCmd = getKnownCommandsProvider().getKnownCommands().get(commandLabel);
|
||||
if (!(newCmd instanceof PluginIdentifiableCommand) || ((PluginIdentifiableCommand) newCmd).getPlugin() != this) {
|
||||
return newCmd.tabComplete(cSender, commandLabel, args);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final IEssentialsCommand cmd;
|
||||
try {
|
||||
cmd = (IEssentialsCommand) classLoader.loadClass(commandPath + command.getName()).newInstance();
|
||||
cmd.setEssentials(this);
|
||||
cmd.setEssentialsModule(module);
|
||||
cmd = loadCommand(commandPath, command.getName(), module, classLoader);
|
||||
} catch (final Exception ex) {
|
||||
sender.sendMessage(tl("commandNotLoaded", commandLabel));
|
||||
LOGGER.log(Level.SEVERE, tl("commandNotLoaded", commandLabel), ex);
|
||||
@@ -574,16 +697,19 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
public boolean onCommandEssentials(final CommandSender cSender, final Command command, final String commandLabel, final String[] args, final ClassLoader classLoader, final String commandPath, final String permissionPrefix, final IEssentialsModule module) {
|
||||
// Allow plugins to override the command via onCommand
|
||||
if (!getSettings().isCommandOverridden(command.getName()) && (!commandLabel.startsWith("e") || commandLabel.equalsIgnoreCase(command.getName()))) {
|
||||
final PluginCommand pc = alternativeCommandsHandler.getAlternative(commandLabel);
|
||||
if (getSettings().isDebug()) {
|
||||
LOGGER.log(Level.INFO, "Searching for alternative to: " + commandLabel);
|
||||
}
|
||||
final Command pc = alternativeCommandsHandler.getAlternative(commandLabel);
|
||||
if (pc != null) {
|
||||
alternativeCommandsHandler.executed(commandLabel, pc);
|
||||
try {
|
||||
return pc.execute(cSender, commandLabel, args);
|
||||
pc.execute(cSender, commandLabel, args);
|
||||
} catch (final Exception ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
|
||||
cSender.sendMessage(tl("internalError"));
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,15 +747,19 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
|
||||
// Check for disabled commands
|
||||
if (getSettings().isCommandDisabled(commandLabel)) {
|
||||
if (getKnownCommandsProvider().getKnownCommands().containsKey(commandLabel)) {
|
||||
final Command newCmd = getKnownCommandsProvider().getKnownCommands().get(commandLabel);
|
||||
if (!(newCmd instanceof PluginIdentifiableCommand) || !isEssentialsPlugin(((PluginIdentifiableCommand) newCmd).getPlugin())) {
|
||||
return newCmd.execute(cSender, commandLabel, args);
|
||||
}
|
||||
}
|
||||
sender.sendMessage(tl("commandDisabled", commandLabel));
|
||||
return true;
|
||||
}
|
||||
|
||||
final IEssentialsCommand cmd;
|
||||
try {
|
||||
cmd = (IEssentialsCommand) classLoader.loadClass(commandPath + command.getName()).newInstance();
|
||||
cmd.setEssentials(this);
|
||||
cmd.setEssentialsModule(module);
|
||||
cmd = loadCommand(commandPath, command.getName(), module, classLoader);
|
||||
} catch (final Exception ex) {
|
||||
sender.sendMessage(tl("commandNotLoaded", commandLabel));
|
||||
LOGGER.log(Level.SEVERE, tl("commandNotLoaded", commandLabel), ex);
|
||||
@@ -645,7 +775,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
|
||||
if (user != null && user.isJailed() && !user.isAuthorized(cmd, "essentials.jail.allow.")) {
|
||||
if (user.getJailTimeout() > 0) {
|
||||
user.sendMessage(tl("playerJailedFor", user.getName(), DateUtil.formatDateDiff(user.getJailTimeout())));
|
||||
user.sendMessage(tl("playerJailedFor", user.getName(), user.getFormattedJailTime()));
|
||||
} else {
|
||||
user.sendMessage(tl("jailMessage"));
|
||||
}
|
||||
@@ -663,8 +793,17 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
} catch (final NoChargeException | QuietAbortException ex) {
|
||||
return true;
|
||||
} catch (final NotEnoughArgumentsException ex) {
|
||||
sender.sendMessage(command.getDescription());
|
||||
sender.sendMessage(command.getUsage().replaceAll("<command>", commandLabel));
|
||||
if (getSettings().isVerboseCommandUsages() && !cmd.getUsageStrings().isEmpty()) {
|
||||
sender.sendMessage(tl("commandHelpLine1", commandLabel));
|
||||
sender.sendMessage(tl("commandHelpLine2", command.getDescription()));
|
||||
sender.sendMessage(tl("commandHelpLine3"));
|
||||
for (Map.Entry<String, String> usage : cmd.getUsageStrings().entrySet()) {
|
||||
sender.sendMessage(tl("commandHelpLineUsage", usage.getKey().replace("<command>", commandLabel), usage.getValue()));
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(command.getDescription());
|
||||
sender.sendMessage(command.getUsage().replace("<command>", commandLabel));
|
||||
}
|
||||
if (!ex.getMessage().isEmpty()) {
|
||||
sender.sendMessage(ex.getMessage());
|
||||
}
|
||||
@@ -685,6 +824,10 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEssentialsPlugin(Plugin plugin) {
|
||||
return plugin.getDescription().getMain().contains("com.earth2me.essentials") || plugin.getDescription().getMain().contains("net.essentialsx");
|
||||
}
|
||||
|
||||
public void cleanupOpenInventories() {
|
||||
for (final User user : getOnlineUsers()) {
|
||||
if (user.isRecipeSee()) {
|
||||
@@ -743,6 +886,11 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
return randomTeleport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateChecker getUpdateChecker() {
|
||||
return updateChecker;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public User getUser(final Object base) {
|
||||
@@ -789,6 +937,94 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User matchUser(final Server server, final User sourceUser, final String searchTerm, final Boolean getHidden, final boolean getOffline) throws PlayerNotFoundException {
|
||||
final User user;
|
||||
Player exPlayer;
|
||||
|
||||
try {
|
||||
exPlayer = server.getPlayer(UUID.fromString(searchTerm));
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
if (getOffline) {
|
||||
exPlayer = server.getPlayerExact(searchTerm);
|
||||
} else {
|
||||
exPlayer = server.getPlayer(searchTerm);
|
||||
}
|
||||
}
|
||||
|
||||
if (exPlayer != null) {
|
||||
user = getUser(exPlayer);
|
||||
} else {
|
||||
user = getUser(searchTerm);
|
||||
}
|
||||
|
||||
if (user != null) {
|
||||
if (!getOffline && !user.getBase().isOnline()) {
|
||||
throw new PlayerNotFoundException();
|
||||
}
|
||||
|
||||
if (getHidden || canInteractWith(sourceUser, user)) {
|
||||
return user;
|
||||
} else { // not looking for hidden and cannot interact (i.e is hidden)
|
||||
if (getOffline && user.getName().equalsIgnoreCase(searchTerm)) { // if looking for offline and got an exact match
|
||||
return user;
|
||||
}
|
||||
}
|
||||
throw new PlayerNotFoundException();
|
||||
}
|
||||
final List<Player> matches = server.matchPlayer(searchTerm);
|
||||
|
||||
if (matches.isEmpty()) {
|
||||
final String matchText = searchTerm.toLowerCase(Locale.ENGLISH);
|
||||
for (final User userMatch : getOnlineUsers()) {
|
||||
if (getHidden || canInteractWith(sourceUser, userMatch)) {
|
||||
final String displayName = FormatUtil.stripFormat(userMatch.getDisplayName()).toLowerCase(Locale.ENGLISH);
|
||||
if (displayName.contains(matchText)) {
|
||||
return userMatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (final Player player : matches) {
|
||||
final User userMatch = getUser(player);
|
||||
if (userMatch.getDisplayName().startsWith(searchTerm) && (getHidden || canInteractWith(sourceUser, userMatch))) {
|
||||
return userMatch;
|
||||
}
|
||||
}
|
||||
final User userMatch = getUser(matches.get(0));
|
||||
if (getHidden || canInteractWith(sourceUser, userMatch)) {
|
||||
return userMatch;
|
||||
}
|
||||
}
|
||||
throw new PlayerNotFoundException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInteractWith(final CommandSource interactor, final User interactee) {
|
||||
if (interactor == null) {
|
||||
return !interactee.isHidden();
|
||||
}
|
||||
|
||||
if (interactor.isPlayer()) {
|
||||
return canInteractWith(getUser(interactor.getPlayer()), interactee);
|
||||
}
|
||||
|
||||
return true; // console
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInteractWith(final User interactor, final User interactee) {
|
||||
if (interactor == null) {
|
||||
return !interactee.isHidden();
|
||||
}
|
||||
|
||||
if (interactor.equals(interactee)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return interactor.getBase().canSee(interactee.getBase());
|
||||
}
|
||||
|
||||
//This will create a new user if there is not a match.
|
||||
@Override
|
||||
public User getUser(final Player base) {
|
||||
@@ -947,6 +1183,11 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
return userMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BalanceTop getBalanceTop() {
|
||||
return balanceTop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public I18n getI18n() {
|
||||
return i18n;
|
||||
@@ -957,6 +1198,11 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
return timer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailService getMail() {
|
||||
return mail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getVanishedPlayers() {
|
||||
return Collections.unmodifiableList(new ArrayList<>(vanishedPlayers));
|
||||
@@ -1011,6 +1257,10 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
return serverStateProvider;
|
||||
}
|
||||
|
||||
public MaterialTagProvider getMaterialTagProvider() {
|
||||
return materialTagProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContainerProvider getContainerProvider() {
|
||||
return containerProvider;
|
||||
@@ -1021,6 +1271,46 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
return knownCommandsProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SerializationProvider getSerializationProvider() {
|
||||
return serializationProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FormattedCommandAliasProvider getFormattedCommandAliasProvider() {
|
||||
return formattedCommandAliasProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SyncCommandsProvider getSyncCommandsProvider() {
|
||||
return syncCommandsProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistentDataProvider getPersistentDataProvider() {
|
||||
return persistentDataProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReflOnlineModeProvider getOnlineModeProvider() {
|
||||
return onlineModeProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemUnbreakableProvider getItemUnbreakableProvider() {
|
||||
return unbreakableProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldInfoProvider getWorldInfoProvider() {
|
||||
return worldInfoProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginCommand getPluginCommand(final String cmd) {
|
||||
return this.getCommand(cmd);
|
||||
}
|
||||
|
||||
private AbstractItemDb getItemDbFromConfig() {
|
||||
final String setting = settings.getItemDbType();
|
||||
|
||||
@@ -1049,25 +1339,6 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onWorldLoad(final WorldLoadEvent event) {
|
||||
PermissionsDefaults.registerBackDefaultFor(event.getWorld());
|
||||
|
||||
ess.getJails().onReload();
|
||||
ess.getWarps().reloadConfig();
|
||||
for (final IConf iConf : ((Essentials) ess).confList) {
|
||||
if (iConf instanceof IEssentialsModule) {
|
||||
iConf.reloadConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onWorldUnload(final WorldUnloadEvent event) {
|
||||
ess.getJails().onReload();
|
||||
ess.getWarps().reloadConfig();
|
||||
for (final IConf iConf : ((Essentials) ess).confList) {
|
||||
if (iConf instanceof IEssentialsModule) {
|
||||
iConf.reloadConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
+6
-18
@@ -1,6 +1,5 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.utils.LocationUtil;
|
||||
import com.earth2me.essentials.utils.MaterialUtil;
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.GameMode;
|
||||
@@ -24,15 +23,9 @@ public class EssentialsBlockListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onBlockPlace(final BlockPlaceEvent event) {
|
||||
// Do not rely on getItemInHand();
|
||||
// http://leaky.bukkit.org/issues/663
|
||||
final ItemStack is = LocationUtil.convertBlockToItem(event.getBlockPlaced());
|
||||
final ItemStack is = event.getItemInHand();
|
||||
|
||||
if (is == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is.getType() == MaterialUtil.SPAWNER && event.getItemInHand() != null && event.getPlayer() != null && event.getItemInHand().getType() == MaterialUtil.SPAWNER) {
|
||||
if (is.getType() == MaterialUtil.SPAWNER && ess.getPersistentDataProvider().getString(is, "convert") != null) {
|
||||
final BlockState blockState = event.getBlockPlaced().getState();
|
||||
if (blockState instanceof CreatureSpawner) {
|
||||
final CreatureSpawner spawner = (CreatureSpawner) blockState;
|
||||
@@ -48,15 +41,10 @@ public class EssentialsBlockListener implements Listener {
|
||||
|
||||
final User user = ess.getUser(event.getPlayer());
|
||||
if (user.hasUnlimited(is) && user.getBase().getGameMode() == GameMode.SURVIVAL) {
|
||||
class UnlimitedItemSpawnTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
user.getBase().getInventory().addItem(is);
|
||||
user.getBase().updateInventory();
|
||||
}
|
||||
}
|
||||
|
||||
ess.scheduleSyncDelayedTask(new UnlimitedItemSpawnTask());
|
||||
ess.scheduleSyncDelayedTask(() -> {
|
||||
user.getBase().getInventory().addItem(is);
|
||||
user.getBase().updateInventory();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
+142
-60
@@ -6,19 +6,27 @@ import com.earth2me.essentials.textreader.KeywordReplacer;
|
||||
import com.earth2me.essentials.textreader.TextInput;
|
||||
import com.earth2me.essentials.textreader.TextPager;
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import com.earth2me.essentials.utils.LocationUtil;
|
||||
import com.earth2me.essentials.utils.MaterialUtil;
|
||||
import com.earth2me.essentials.utils.VersionUtil;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.events.AfkStatusChangeEvent;
|
||||
import net.ess3.provider.CommandSendListenerProvider;
|
||||
import net.ess3.provider.providers.BukkitCommandSendListenerProvider;
|
||||
import net.ess3.provider.providers.PaperCommandSendListenerProvider;
|
||||
import net.essentialsx.api.v2.events.AsyncUserDataLoadEvent;
|
||||
import org.bukkit.BanEntry;
|
||||
import org.bukkit.BanList;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.FormattedCommandAlias;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -32,7 +40,6 @@ import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerBucketEmptyEvent;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerCommandSendEvent;
|
||||
import org.bukkit.event.player.PlayerEggThrowEvent;
|
||||
import org.bukkit.event.player.PlayerFishEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
@@ -61,15 +68,19 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class EssentialsPlayerListener implements Listener {
|
||||
public class EssentialsPlayerListener implements Listener, FakeAccessor {
|
||||
private static final Logger LOGGER = Logger.getLogger("Essentials");
|
||||
private final transient IEssentials ess;
|
||||
private final ConcurrentHashMap<UUID, Integer> pendingMotdTasks = new ConcurrentHashMap<>();
|
||||
|
||||
public EssentialsPlayerListener(final IEssentials parent) {
|
||||
this.ess = parent;
|
||||
@@ -93,6 +104,15 @@ public class EssentialsPlayerListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isPaperCommandSendEvent() {
|
||||
try {
|
||||
Class.forName("com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent");
|
||||
return true;
|
||||
} catch (final ClassNotFoundException ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isArrowPickupEvent() {
|
||||
try {
|
||||
Class.forName("org.bukkit.event.player.PlayerPickupArrowEvent");
|
||||
@@ -115,8 +135,10 @@ public class EssentialsPlayerListener implements Listener {
|
||||
ess.getServer().getPluginManager().registerEvents(new PickupListenerPre1_12(), ess);
|
||||
}
|
||||
|
||||
if (isCommandSendEvent()) {
|
||||
ess.getServer().getPluginManager().registerEvents(new CommandSendListener(), ess);
|
||||
if (isPaperCommandSendEvent()) {
|
||||
ess.getServer().getPluginManager().registerEvents(new PaperCommandSendListenerProvider(new CommandSendFilter()), ess);
|
||||
} else if (isCommandSendEvent()) {
|
||||
ess.getServer().getPluginManager().registerEvents(new BukkitCommandSendListenerProvider(new CommandSendFilter()), ess);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +184,7 @@ public class EssentialsPlayerListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
user.updateActivityOnInteract(true);
|
||||
user.updateActivityOnChat(true);
|
||||
user.setDisplayNick();
|
||||
}
|
||||
|
||||
@@ -195,7 +217,7 @@ public class EssentialsPlayerListener implements Listener {
|
||||
to.setY(from.getY());
|
||||
to.setZ(from.getZ());
|
||||
try {
|
||||
event.setTo(LocationUtil.getSafeDestination(to));
|
||||
event.setTo(LocationUtil.getSafeDestination(ess, to));
|
||||
} catch (final Exception ex) {
|
||||
event.setTo(to);
|
||||
}
|
||||
@@ -211,6 +233,11 @@ public class EssentialsPlayerListener implements Listener {
|
||||
public void onPlayerQuit(final PlayerQuitEvent event) {
|
||||
final User user = ess.getUser(event.getPlayer());
|
||||
|
||||
final Integer pendingId = pendingMotdTasks.remove(user.getUUID());
|
||||
if (pendingId != null) {
|
||||
ess.getScheduler().cancelTask(pendingId);
|
||||
}
|
||||
|
||||
if (hideJoinQuitMessages() || (ess.getSettings().allowSilentJoinQuit() && user.isAuthorized("essentials.silentquit"))) {
|
||||
event.setQuitMessage(null);
|
||||
} else if (ess.getSettings().isCustomQuitMessage() && event.getQuitMessage() != null) {
|
||||
@@ -219,7 +246,9 @@ public class EssentialsPlayerListener implements Listener {
|
||||
.replace("{PLAYER}", player.getDisplayName())
|
||||
.replace("{USERNAME}", player.getName())
|
||||
.replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size()))
|
||||
.replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()));
|
||||
.replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()))
|
||||
.replace("{PREFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getPrefix(player)))
|
||||
.replace("{SUFFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getSuffix(player)));
|
||||
|
||||
event.setQuitMessage(msg.isEmpty() ? null : msg);
|
||||
}
|
||||
@@ -298,11 +327,15 @@ public class EssentialsPlayerListener implements Listener {
|
||||
|
||||
user.startTransaction();
|
||||
|
||||
final String lastAccountName = user.getLastAccountName(); // For comparison
|
||||
user.setLastAccountName(user.getBase().getName());
|
||||
user.setLastLogin(currentTime);
|
||||
user.setDisplayNick();
|
||||
updateCompass(user);
|
||||
|
||||
// Check for new username. If they don't want the message, let's just say it's false.
|
||||
final boolean newUsername = ess.getSettings().isCustomNewUsernameMessage() && lastAccountName != null && !lastAccountName.equals(user.getBase().getName());
|
||||
|
||||
if (!ess.getVanishedPlayersNew().isEmpty() && !user.isAuthorized("essentials.vanish.see")) {
|
||||
for (final String p : ess.getVanishedPlayersNew()) {
|
||||
final Player toVanish = ess.getServer().getPlayerExact(p);
|
||||
@@ -319,36 +352,48 @@ public class EssentialsPlayerListener implements Listener {
|
||||
user.getBase().setSleepingIgnored(true);
|
||||
}
|
||||
|
||||
final String effectiveMessage;
|
||||
if (ess.getSettings().allowSilentJoinQuit() && (user.isAuthorized("essentials.silentjoin") || user.isAuthorized("essentials.silentjoin.vanish"))) {
|
||||
if (user.isAuthorized("essentials.silentjoin.vanish")) {
|
||||
user.setVanished(true);
|
||||
}
|
||||
effectiveMessage = null;
|
||||
} else if (message == null || hideJoinQuitMessages()) {
|
||||
//NOOP
|
||||
effectiveMessage = null;
|
||||
} else if (ess.getSettings().isCustomJoinMessage()) {
|
||||
final String msg = ess.getSettings().getCustomJoinMessage()
|
||||
final String msg = (newUsername ? ess.getSettings().getCustomNewUsernameMessage() : ess.getSettings().getCustomJoinMessage())
|
||||
.replace("{PLAYER}", player.getDisplayName()).replace("{USERNAME}", player.getName())
|
||||
.replace("{UNIQUE}", NumberFormat.getInstance().format(ess.getUserMap().getUniqueUsers()))
|
||||
.replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size()))
|
||||
.replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()));
|
||||
.replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()))
|
||||
.replace("{PREFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getPrefix(player)))
|
||||
.replace("{SUFFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getSuffix(player)))
|
||||
.replace("{OLDUSERNAME}", lastAccountName == null ? "" : lastAccountName);
|
||||
if (!msg.isEmpty()) {
|
||||
ess.getServer().broadcastMessage(msg);
|
||||
}
|
||||
effectiveMessage = msg.isEmpty() ? null : msg;
|
||||
} else if (ess.getSettings().allowSilentJoinQuit()) {
|
||||
ess.getServer().broadcastMessage(message);
|
||||
effectiveMessage = message;
|
||||
} else {
|
||||
effectiveMessage = message;
|
||||
}
|
||||
|
||||
final int motdDelay = ess.getSettings().getMotdDelay() / 50;
|
||||
final DelayMotdTask motdTask = new DelayMotdTask(user);
|
||||
if (motdDelay > 0) {
|
||||
ess.scheduleSyncDelayedTask(motdTask, motdDelay);
|
||||
} else {
|
||||
motdTask.run();
|
||||
ess.runTaskAsynchronously(() -> ess.getServer().getPluginManager().callEvent(new AsyncUserDataLoadEvent(user, effectiveMessage)));
|
||||
|
||||
if (ess.getSettings().getMotdDelay() >= 0) {
|
||||
final int motdDelay = ess.getSettings().getMotdDelay() / 50;
|
||||
final DelayMotdTask motdTask = new DelayMotdTask(user);
|
||||
if (motdDelay > 0) {
|
||||
pendingMotdTasks.put(user.getUUID(), ess.scheduleSyncDelayedTask(motdTask, motdDelay));
|
||||
} else {
|
||||
motdTask.run();
|
||||
}
|
||||
}
|
||||
|
||||
if (!ess.getSettings().isCommandDisabled("mail") && user.isAuthorized("essentials.mail")) {
|
||||
final List<String> mail = user.getMails();
|
||||
if (mail.isEmpty()) {
|
||||
if (user.getUnreadMailAmount() == 0) {
|
||||
if (ess.getSettings().isNotifyNoNewMail()) {
|
||||
user.sendMessage(tl("noNewMail")); // Only notify if they want us to.
|
||||
}
|
||||
@@ -357,9 +402,17 @@ public class EssentialsPlayerListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
if (user.isAuthorized("essentials.updatecheck")) {
|
||||
ess.runTaskAsynchronously(() -> {
|
||||
for (String str : ess.getUpdateChecker().getVersionMessages(false, false)) {
|
||||
user.sendMessage(str);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (user.isAuthorized("essentials.fly.safelogin")) {
|
||||
user.getBase().setFallDistance(0);
|
||||
if (LocationUtil.shouldFly(user.getLocation())) {
|
||||
if (LocationUtil.shouldFly(ess, user.getLocation())) {
|
||||
user.getBase().setAllowFlight(true);
|
||||
user.getBase().setFlying(true);
|
||||
if (ess.getSettings().isSendFlyEnableOnJoin()) {
|
||||
@@ -398,6 +451,8 @@ public class EssentialsPlayerListener implements Listener {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
pendingMotdTasks.remove(user.getUUID());
|
||||
|
||||
IText tempInput = null;
|
||||
|
||||
if (!ess.getSettings().isCommandDisabled("motd")) {
|
||||
@@ -472,27 +527,24 @@ public class EssentialsPlayerListener implements Listener {
|
||||
event.allow();
|
||||
return;
|
||||
}
|
||||
event.disallow(Result.KICK_FULL, tl("serverFull"));
|
||||
if (ess.getSettings().isCustomServerFullMessage()) {
|
||||
event.disallow(Result.KICK_FULL, tl("serverFull"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onPlayerTeleport(final PlayerTeleportEvent event) {
|
||||
final boolean backListener = ess.getSettings().registerBackInListener();
|
||||
final boolean teleportInvulnerability = ess.getSettings().isTeleportInvulnerability();
|
||||
if (backListener || teleportInvulnerability) {
|
||||
final Player player = event.getPlayer();
|
||||
if (player.hasMetadata("NPC")) {
|
||||
return;
|
||||
}
|
||||
final User user = ess.getUser(player);
|
||||
//There is TeleportCause.COMMMAND but plugins have to actively pass the cause in on their teleports.
|
||||
if (user.isAuthorized("essentials.back.onteleport") && backListener && (event.getCause() == TeleportCause.PLUGIN || event.getCause() == TeleportCause.COMMAND)) {
|
||||
user.setLastLocation();
|
||||
}
|
||||
if (teleportInvulnerability && (event.getCause() == TeleportCause.PLUGIN || event.getCause() == TeleportCause.COMMAND)) {
|
||||
user.enableInvulnerabilityAfterTeleport();
|
||||
}
|
||||
final Player player = event.getPlayer();
|
||||
if (player.hasMetadata("NPC") || !(event.getCause() == TeleportCause.PLUGIN || event.getCause() == TeleportCause.COMMAND)) {
|
||||
return;
|
||||
}
|
||||
final User user = ess.getUser(player);
|
||||
if (ess.getSettings().registerBackInListener() && user.isAuthorized("essentials.back.onteleport")) {
|
||||
user.setLastLocation();
|
||||
}
|
||||
if (ess.getSettings().isTeleportInvulnerability()) {
|
||||
user.enableInvulnerabilityAfterTeleport();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,9 +569,30 @@ public class EssentialsPlayerListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final String cmd = event.getMessage().toLowerCase(Locale.ENGLISH).split(" ")[0].replace("/", "").toLowerCase(Locale.ENGLISH);
|
||||
final int argStartIndex = event.getMessage().indexOf(" ");
|
||||
final String args = argStartIndex == -1 ? "" // No arguments present
|
||||
: event.getMessage().substring(argStartIndex); // arguments start at argStartIndex; substring from there.
|
||||
|
||||
// If the plugin command does not exist, check if it is an alias from commands.yml
|
||||
if (ess.getServer().getPluginCommand(cmd) == null) {
|
||||
final Command knownCommand = ess.getKnownCommandsProvider().getKnownCommands().get(cmd);
|
||||
if (knownCommand instanceof FormattedCommandAlias) {
|
||||
final FormattedCommandAlias command = (FormattedCommandAlias) knownCommand;
|
||||
for (String fullCommand : ess.getFormattedCommandAliasProvider().createCommands(command, event.getPlayer(), args.split(" "))) {
|
||||
handlePlayerCommandPreprocess(event, fullCommand);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the command given from the event.
|
||||
handlePlayerCommandPreprocess(event, cmd + args);
|
||||
}
|
||||
|
||||
public void handlePlayerCommandPreprocess(final PlayerCommandPreprocessEvent event, final String effectiveCommand) {
|
||||
final Player player = event.getPlayer();
|
||||
final String cmd = effectiveCommand.toLowerCase(Locale.ENGLISH).split(" ")[0].replace("/", "").toLowerCase(Locale.ENGLISH);
|
||||
final PluginCommand pluginCommand = ess.getServer().getPluginCommand(cmd);
|
||||
|
||||
if (ess.getSettings().getSocialSpyCommands().contains(cmd) || ess.getSettings().getSocialSpyCommands().contains("*")) {
|
||||
@@ -572,12 +645,12 @@ public class EssentialsPlayerListener implements Listener {
|
||||
user.updateActivityOnInteract(broadcast);
|
||||
}
|
||||
|
||||
if (ess.getSettings().isCommandCooldownsEnabled() && pluginCommand != null
|
||||
if (ess.getSettings().isCommandCooldownsEnabled()
|
||||
&& !user.isAuthorized("essentials.commandcooldowns.bypass")) {
|
||||
final int argStartIndex = event.getMessage().indexOf(" ");
|
||||
final int argStartIndex = effectiveCommand.indexOf(" ");
|
||||
final String args = argStartIndex == -1 ? "" // No arguments present
|
||||
: " " + event.getMessage().substring(argStartIndex); // arguments start at argStartIndex; substring from there.
|
||||
final String fullCommand = pluginCommand.getName() + args;
|
||||
: " " + effectiveCommand.substring(argStartIndex); // arguments start at argStartIndex; substring from there.
|
||||
final String fullCommand = pluginCommand == null ? effectiveCommand : pluginCommand.getName() + args;
|
||||
|
||||
// Used to determine whether a user already has an existing cooldown
|
||||
// If so, no need to check for (and write) new ones.
|
||||
@@ -674,6 +747,9 @@ public class EssentialsPlayerListener implements Listener {
|
||||
switch (event.getAction()) {
|
||||
case RIGHT_CLICK_BLOCK:
|
||||
if (!event.isCancelled() && MaterialUtil.isBed(event.getClickedBlock().getType()) && ess.getSettings().getUpdateBedAtDaytime()) {
|
||||
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_13_2_R01) && ((org.bukkit.block.data.type.Bed) event.getClickedBlock().getBlockData()).isOccupied()) {
|
||||
break;
|
||||
}
|
||||
final User player = ess.getUser(event.getPlayer());
|
||||
if (player.isAuthorized("essentials.sethome.bed") && player.getWorld().getEnvironment().equals(World.Environment.NORMAL)) {
|
||||
player.getBase().setBedSpawnLocation(event.getClickedBlock().getLocation());
|
||||
@@ -782,8 +858,8 @@ public class EssentialsPlayerListener implements Listener {
|
||||
clickedInventory = event.getRawSlot() < top.getSize() ? top : event.getView().getBottomInventory();
|
||||
}
|
||||
|
||||
final User user = ess.getUser((Player) event.getWhoClicked());
|
||||
if (type == InventoryType.PLAYER) {
|
||||
final User user = ess.getUser((Player) event.getWhoClicked());
|
||||
final InventoryHolder invHolder = top.getHolder();
|
||||
if (invHolder instanceof HumanEntity) {
|
||||
final User invOwner = ess.getUser((Player) invHolder);
|
||||
@@ -793,21 +869,18 @@ public class EssentialsPlayerListener implements Listener {
|
||||
}
|
||||
}
|
||||
} else if (type == InventoryType.ENDER_CHEST) {
|
||||
final User user = ess.getUser((Player) event.getWhoClicked());
|
||||
if (user.isEnderSee() && !user.isAuthorized("essentials.enderchest.modify")) {
|
||||
event.setCancelled(true);
|
||||
refreshPlayer = user.getBase();
|
||||
}
|
||||
} else if (type == InventoryType.WORKBENCH) {
|
||||
final User user = ess.getUser((Player) event.getWhoClicked());
|
||||
if (user.isRecipeSee()) {
|
||||
event.setCancelled(true);
|
||||
refreshPlayer = user.getBase();
|
||||
}
|
||||
} else if (type == InventoryType.CHEST && top.getSize() == 9) {
|
||||
final User user = ess.getUser((Player) event.getWhoClicked());
|
||||
final InventoryHolder invHolder = top.getHolder();
|
||||
if (invHolder instanceof HumanEntity && user.isInvSee()) {
|
||||
if (invHolder instanceof HumanEntity && user.isInvSee() && event.getClick() != ClickType.MIDDLE) {
|
||||
event.setCancelled(true);
|
||||
refreshPlayer = user.getBase();
|
||||
}
|
||||
@@ -815,7 +888,8 @@ public class EssentialsPlayerListener implements Listener {
|
||||
if (ess.getSettings().isDirectHatAllowed() && event.getClick() == ClickType.LEFT && event.getSlot() == 39
|
||||
&& event.getCursor().getType() != Material.AIR && event.getCursor().getType().getMaxDurability() == 0
|
||||
&& !MaterialUtil.isSkull(event.getCursor().getType())
|
||||
&& ess.getUser(event.getWhoClicked()).isAuthorized("essentials.hat") && !ess.getUser(event.getWhoClicked()).isAuthorized("essentials.hat.prevent-type." + event.getCursor().getType().name().toLowerCase())) {
|
||||
&& user.isAuthorized("essentials.hat") && !user.isAuthorized("essentials.hat.prevent-type." + event.getCursor().getType().name().toLowerCase())
|
||||
&& !isPreventBindingHat(user, (PlayerInventory) clickedInventory)) {
|
||||
event.setCancelled(true);
|
||||
final PlayerInventory inv = (PlayerInventory) clickedInventory;
|
||||
final ItemStack head = inv.getHelmet();
|
||||
@@ -829,6 +903,14 @@ public class EssentialsPlayerListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPreventBindingHat(User user, PlayerInventory inventory) {
|
||||
if (VersionUtil.getServerBukkitVersion().isHigherThan(VersionUtil.v1_9_4_R01)) {
|
||||
final ItemStack head = inventory.getHelmet();
|
||||
return head != null && head.getEnchantments().containsKey(Enchantment.BINDING_CURSE) && !user.isAuthorized("essentials.hat.ignore-binding");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onInventoryCloseEvent(final InventoryCloseEvent event) {
|
||||
Player refreshPlayer = null;
|
||||
@@ -902,15 +984,14 @@ public class EssentialsPlayerListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
private final class CommandSendListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onCommandSend(final PlayerCommandSendEvent event) {
|
||||
final User user = ess.getUser(event.getPlayer());
|
||||
|
||||
private final class CommandSendFilter implements CommandSendListenerProvider.Filter {
|
||||
@Override
|
||||
public Predicate<String> apply(Player player) {
|
||||
final User user = ess.getUser(player);
|
||||
final Set<PluginCommand> checked = new HashSet<>();
|
||||
final Set<PluginCommand> toRemove = new HashSet<>();
|
||||
|
||||
event.getCommands().removeIf(label -> {
|
||||
return label -> {
|
||||
if (isEssentialsCommand(label)) {
|
||||
final PluginCommand command = ess.getServer().getPluginCommand(label);
|
||||
if (!checked.contains(command)) {
|
||||
@@ -922,25 +1003,26 @@ public class EssentialsPlayerListener implements Listener {
|
||||
return toRemove.contains(command);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info("Removed commands: " + toRemove.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if all of the following are true:
|
||||
* - The command is a plugin command
|
||||
* - The plugin command is from a plugin in an essentials-controlled package
|
||||
* - The plugin command is from an official EssentialsX plugin or addon
|
||||
* - There is no known alternative OR the alternative is overridden by Essentials
|
||||
*/
|
||||
private boolean isEssentialsCommand(final String label) {
|
||||
final PluginCommand command = ess.getServer().getPluginCommand(label);
|
||||
|
||||
return command != null
|
||||
&& (command.getPlugin() == ess || command.getPlugin().getClass().getName().startsWith("com.earth2me.essentials"))
|
||||
&& (ess.getSettings().isCommandOverridden(label) || (ess.getAlternativeCommandsHandler().getAlternative(label) == null));
|
||||
&& (command.getPlugin() == ess || command.getPlugin().getClass().getName().startsWith("com.earth2me.essentials") || command.getPlugin().getClass().getName().startsWith("net.essentialsx"))
|
||||
&& (ess.getSettings().isCommandOverridden(label) || (ess.getAlternativeCommandsHandler().getAlternative(label) == null));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getUser(Player player) {
|
||||
ess.getUser(player);
|
||||
}
|
||||
}
|
||||
+14
-7
@@ -1,6 +1,7 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.register.payment.Methods;
|
||||
import com.earth2me.essentials.economy.EconomyLayer;
|
||||
import com.earth2me.essentials.economy.EconomyLayers;
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
@@ -25,8 +26,11 @@ public class EssentialsPluginListener implements Listener, IConf {
|
||||
ess.getPermissionsHandler().setUseSuperperms(ess.getSettings().useBukkitPermissions());
|
||||
ess.getPermissionsHandler().checkPermissions();
|
||||
ess.getAlternativeCommandsHandler().addPlugin(event.getPlugin());
|
||||
if (!Methods.hasMethod() && Methods.setMethod(ess.getServer().getPluginManager())) {
|
||||
ess.getLogger().log(Level.INFO, "Payment method found (" + Methods.getMethod().getLongName() + " version: " + Methods.getMethod().getVersion() + ")");
|
||||
if (EconomyLayers.isServerStarted()) {
|
||||
final EconomyLayer layer = EconomyLayers.onPluginEnable(event.getPlugin());
|
||||
if (layer != null) {
|
||||
ess.getLogger().log(Level.INFO, "Essentials found a compatible payment resolution method: " + layer.getName() + " (v" + layer.getPluginVersion() + ")!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,10 +41,13 @@ public class EssentialsPluginListener implements Listener, IConf {
|
||||
}
|
||||
ess.getPermissionsHandler().checkPermissions();
|
||||
ess.getAlternativeCommandsHandler().removePlugin(event.getPlugin());
|
||||
// Check to see if the plugin thats being disabled is the one we are using
|
||||
if (Methods.hasMethod() && Methods.checkDisabled(event.getPlugin())) {
|
||||
Methods.reset();
|
||||
ess.getLogger().log(Level.INFO, "Payment method was disabled. No longer accepting payments.");
|
||||
if (EconomyLayers.onPluginDisable(event.getPlugin())) {
|
||||
final EconomyLayer layer = EconomyLayers.getSelectedLayer();
|
||||
if (layer != null) {
|
||||
ess.getLogger().log(Level.INFO, "Essentials found a new compatible payment resolution method: " + layer.getName() + " (v" + layer.getPluginVersion() + ")!");
|
||||
} else {
|
||||
ess.getLogger().log(Level.INFO, "Active payment resolution method has been disabled! Falling back to Essentials' default payment resolution system!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File renamed without changes.
+1
@@ -44,6 +44,7 @@ public class EssentialsTimer implements Runnable {
|
||||
}
|
||||
lastPoll = startTime;
|
||||
int count = 0;
|
||||
onlineUsers.clear();
|
||||
for (final Player player : ess.getOnlinePlayers()) {
|
||||
count++;
|
||||
if (skip1 > 0) {
|
||||
+301
-70
@@ -1,18 +1,21 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.config.ConfigurateUtil;
|
||||
import com.earth2me.essentials.config.EssentialsConfiguration;
|
||||
import com.earth2me.essentials.config.EssentialsUserConfiguration;
|
||||
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 com.google.common.io.Files;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.essentialsx.api.v2.services.mail.MailMessage;
|
||||
import org.bukkit.BanList;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
@@ -24,6 +27,7 @@ import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
@@ -37,6 +41,11 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -52,14 +61,14 @@ public class EssentialsUpgrade {
|
||||
private static final String PATTERN_CONFIG_NAME_REGEX = "(?mi)^lastAccountName:\\s*[\"\']?(\\w+)[\"\']?\\s*$";
|
||||
private static final Pattern PATTERN_CONFIG_NAME = Pattern.compile(PATTERN_CONFIG_NAME_REGEX);
|
||||
private final transient IEssentials ess;
|
||||
private final transient EssentialsConf doneFile;
|
||||
private final transient EssentialsConfiguration 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 = new EssentialsConfiguration(new File(ess.getDataFolder(), "upgrades-done.yml"));
|
||||
doneFile.load();
|
||||
}
|
||||
|
||||
@@ -93,13 +102,13 @@ public class EssentialsUpgrade {
|
||||
countFiles++;
|
||||
|
||||
final String name = string.substring(0, string.length() - 4);
|
||||
final EssentialsUserConf config;
|
||||
final EssentialsUserConfiguration config;
|
||||
UUID uuid = null;
|
||||
try {
|
||||
uuid = UUID.fromString(name);
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
final File file = new File(userdir, string);
|
||||
final EssentialsConf conf = new EssentialsConf(file);
|
||||
final EssentialsConfiguration conf = new EssentialsConfiguration(file);
|
||||
conf.load();
|
||||
conf.setProperty("lastAccountName", name);
|
||||
conf.save();
|
||||
@@ -130,8 +139,8 @@ public class EssentialsUpgrade {
|
||||
}
|
||||
|
||||
if (uuid != null) {
|
||||
conf.forceSave();
|
||||
config = new EssentialsUserConf(name, uuid, new File(userdir, uuid + ".yml"));
|
||||
conf.blockingSave();
|
||||
config = new EssentialsUserConfiguration(name, uuid, new File(userdir, uuid + ".yml"));
|
||||
config.convertLegacyFile();
|
||||
ess.getUserMap().trackUUID(uuid, name, false);
|
||||
continue;
|
||||
@@ -146,6 +155,237 @@ public class EssentialsUpgrade {
|
||||
ess.getLogger().info("To rerun the conversion type /essentials uuidconvert");
|
||||
}
|
||||
|
||||
public void convertMailList() {
|
||||
if (doneFile.getBoolean("updateUsersMailList", 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 EssentialsConfiguration config = new EssentialsConfiguration(file);
|
||||
try {
|
||||
config.load();
|
||||
if (config.hasProperty("mail") && config.isList("mail")) {
|
||||
final ArrayList<MailMessage> messages = new ArrayList<>();
|
||||
for (String mailStr : Collections.synchronizedList(config.getList("mail", String.class))) {
|
||||
if (mailStr == null) {
|
||||
continue;
|
||||
}
|
||||
messages.add(new MailMessage(false, true, null, null, 0L, 0L, mailStr));
|
||||
}
|
||||
|
||||
config.removeProperty("mail");
|
||||
config.setExplicitList("mail", messages, new TypeToken<List<MailMessage>>() {}.getType());
|
||||
config.blockingSave();
|
||||
}
|
||||
} catch (RuntimeException ex) {
|
||||
LOGGER.log(Level.INFO, "File: " + file);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
doneFile.setProperty("updateUsersMailList", true);
|
||||
doneFile.save();
|
||||
LOGGER.info("Done converting mail list.");
|
||||
}
|
||||
|
||||
public void convertStupidCamelCaseUserdataKeys() {
|
||||
if (doneFile.getBoolean("updateUsersStupidLegacyPathNames", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.info("Attempting to migrate legacy userdata keys to Configurate");
|
||||
|
||||
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
|
||||
if (!userdataFolder.exists() || !userdataFolder.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
final File[] userFiles = userdataFolder.listFiles();
|
||||
|
||||
for (final File file : userFiles) {
|
||||
if (!file.isFile() || !file.getName().endsWith(".yml")) {
|
||||
continue;
|
||||
}
|
||||
final EssentialsConfiguration config = new EssentialsConfiguration(file);
|
||||
try {
|
||||
config.load();
|
||||
|
||||
if (config.hasProperty("muteReason")) {
|
||||
final String reason = config.getString("muteReason", null);
|
||||
config.removeProperty("muteReason");
|
||||
config.setProperty("mute-reason", reason);
|
||||
}
|
||||
|
||||
if (config.hasProperty("ipAddress")) {
|
||||
final String ip = config.getString("ipAddress", null);
|
||||
config.removeProperty("ipAddress");
|
||||
config.setProperty("ip-address", ip);
|
||||
}
|
||||
|
||||
if (config.hasProperty("lastAccountName")) {
|
||||
final String name = config.getString("lastAccountName", null);
|
||||
config.removeProperty("lastAccountName");
|
||||
config.setProperty("last-account-name", name);
|
||||
}
|
||||
|
||||
if (config.hasProperty("acceptingPay")) {
|
||||
final boolean isPay = config.getBoolean("acceptingPay", true);
|
||||
config.removeProperty("acceptingPay");
|
||||
config.setProperty("accepting-pay", isPay);
|
||||
}
|
||||
config.blockingSave();
|
||||
} catch (final RuntimeException ex) {
|
||||
LOGGER.log(Level.INFO, "File: " + file);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
doneFile.setProperty("updateUsersStupidLegacyPathNames", true);
|
||||
doneFile.save();
|
||||
LOGGER.info("Done converting legacy userdata keys to Configurate.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This migration cleans up unused files left behind by the chaos resulting from Vault's questionable economy
|
||||
* integration, and upstream Essentials' rushed and untested 1.7.10 UUID support.
|
||||
* Both of these have been fixed in EssentialsX as of 2.18.x and 2.19.x respectively, but the leftover userdata
|
||||
* files can reach into the tens of thousands and can cause excessive memory and storage usage, so this migration
|
||||
* relocates these files to a backup folder to be removed by the server owner at a later date.
|
||||
* <p>
|
||||
* To quote JRoy, who suffered immensely while trying to debug and fix various related issues:
|
||||
* <p>
|
||||
* "Essentials decided when adding its initial support for UUIDs, it wanted an implementation which would cause
|
||||
* eternal pain and suffering for any person who dared touch any of the code in the future. This code that was made
|
||||
* was so bad, it managed to somehow not maintain any actual UUID support for any external integrations/plugins.
|
||||
* Up until 2.19.0 and 2.18.0 respectively, our Vault integration and entire Economy system was entirely based off
|
||||
* username strings, and thanks to Vault being a flawed standard, for some reason exposes account create to third
|
||||
* party plugins rather than letting the implementation handle it. That doesn't seem like a huge problem at the
|
||||
* surface, but there was one small problem: whoever made the Vault integration for Essentials suffered a stroke in
|
||||
* the process of creating it. The implementation for the createAccount method, regardless of whether it was an
|
||||
* actual player or an NPC account (which the Vault spec NEVER accounted for but plugins just have to guess when
|
||||
* to support them), it would always create an NPC account. This caused any plugin integrating with Vault, creating
|
||||
* NPC accounts for pretty much every single player on the server. It still, to this day, amazes me how nobody saw
|
||||
* this code and didn't die without rewriting it; Or how everybody simply didn't stop using this plugin because how
|
||||
* awful that godforsaken code was. Anyways, this upgrade does its best to delete NPC accounts created by the
|
||||
* horrible economy code, as any operation which loads all user data into memory will load all these NPC accounts
|
||||
* and spam the console with warnings."
|
||||
*/
|
||||
public void purgeBrokenNpcAccounts() {
|
||||
if (doneFile.getBoolean("updatePurgeBrokenNpcAccounts", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
|
||||
if (!userdataFolder.exists() || !userdataFolder.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
final File[] userFiles = userdataFolder.listFiles();
|
||||
if (userFiles.length == 0) {
|
||||
return;
|
||||
}
|
||||
final File backupFolder = new File(ess.getDataFolder(), "userdata-npc-backup");
|
||||
if (backupFolder.exists()) {
|
||||
LOGGER.info("NPC backup folder already exists; skipping NPC purge.");
|
||||
LOGGER.info("To finish purging broken NPC accounts, rename the \"plugins/Essentials/userdata-npc-backup\" folder and restart your server.");
|
||||
return;
|
||||
} else if (!backupFolder.mkdir()) {
|
||||
LOGGER.info("Skipping NPC purge due to error creating backup folder.");
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.info("#===========================================================================#");
|
||||
LOGGER.info(" EssentialsX will now purge any NPC accounts which were incorrectly created.");
|
||||
LOGGER.info(" Only NPC accounts with the default starting balance will be deleted. If");
|
||||
LOGGER.info(" they turn out to be valid NPC accounts, they will be re-created as needed.");
|
||||
LOGGER.info(" Any files deleted here will be backed up to the ");
|
||||
LOGGER.info(" \"plugins/Essentials/userdata-npc-backup\" folder. If you notice any files");
|
||||
LOGGER.info(" have been purged incorrectly, you should restore it from the backup and");
|
||||
LOGGER.info(" report it to us on GitHub:");
|
||||
LOGGER.info(" https://github.com/EssentialsX/Essentials/issues/new/choose");
|
||||
LOGGER.info("");
|
||||
LOGGER.info(" NOTE: This is a one-time process and will take several minutes if you have");
|
||||
LOGGER.info(" a lot of userdata files! If you interrupt this process, EssentialsX will");
|
||||
LOGGER.info(" skip the process until you rename or remove the backup folder.");
|
||||
LOGGER.info("#===========================================================================#");
|
||||
|
||||
final int totalUserFiles = userFiles.length;
|
||||
LOGGER.info("Found ~" + totalUserFiles + " files under \"plugins/Essentials/userdata\"...");
|
||||
|
||||
final AtomicInteger movedAccounts = new AtomicInteger(0);
|
||||
final AtomicInteger totalAccounts = new AtomicInteger(0);
|
||||
|
||||
// Less spammy feedback for greater userdata counts, eg 100 files -> 5 seconds, 1k -> 7s, 10k -> 9s, 100k -> 11s, 1m -> 14s
|
||||
final long feedbackInterval = Math.min(15, 1 + Math.round(2.1 * Math.log10(userFiles.length)));
|
||||
|
||||
final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||
final ScheduledFuture<?> feedbackTask = executor.scheduleWithFixedDelay(
|
||||
() -> LOGGER.info("Scanned " + totalAccounts.get() + "/" + totalUserFiles + " accounts; moved " + movedAccounts.get() + " accounts"),
|
||||
5, feedbackInterval, TimeUnit.SECONDS);
|
||||
|
||||
for (final File file : userFiles) {
|
||||
if (!file.isFile() || !file.getName().endsWith(".yml")) {
|
||||
continue;
|
||||
}
|
||||
final EssentialsConfiguration config = new EssentialsConfiguration(file);
|
||||
try {
|
||||
totalAccounts.incrementAndGet();
|
||||
config.load();
|
||||
|
||||
if (config.getKeys().size() > 4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!config.getBoolean("npc", false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final BigDecimal money = config.getBigDecimal("money", null);
|
||||
if (money == null || money.compareTo(ess.getSettings().getStartingBalance()) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (config.getKeys().size() == 4 && !config.hasProperty("last-account-name") && config.hasProperty("mail")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
//noinspection UnstableApiUsage
|
||||
Files.move(file, new File(backupFolder, file.getName()));
|
||||
movedAccounts.incrementAndGet();
|
||||
} catch (IOException e) {
|
||||
LOGGER.log(Level.SEVERE, "Error while moving NPC file", e);
|
||||
}
|
||||
} catch (final RuntimeException ex) {
|
||||
LOGGER.log(Level.INFO, "File: " + file);
|
||||
feedbackTask.cancel(false);
|
||||
executor.shutdown();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
feedbackTask.cancel(false);
|
||||
executor.shutdown();
|
||||
doneFile.setProperty("updatePurgeBrokenNpcAccounts", true);
|
||||
doneFile.save();
|
||||
|
||||
LOGGER.info("#===========================================================================#");
|
||||
LOGGER.info(" EssentialsX has finished purging NPC accounts.");
|
||||
LOGGER.info("");
|
||||
LOGGER.info(" Deleted accounts: " + movedAccounts);
|
||||
LOGGER.info(" Total accounts processed: " + totalAccounts);
|
||||
LOGGER.info("");
|
||||
LOGGER.info(" Purged accounts have been backed up to");
|
||||
LOGGER.info(" \"plugins/Essentials/userdata-npc-backup\", and can be restored from there");
|
||||
LOGGER.info(" if needed. Please report any files which have been incorrectly deleted");
|
||||
LOGGER.info(" to us on GitHub:");
|
||||
LOGGER.info(" https://github.com/EssentialsX/Essentials/issues/new/choose");
|
||||
LOGGER.info("#===========================================================================#");
|
||||
}
|
||||
|
||||
public void convertIgnoreList() {
|
||||
final Pattern pattern = Pattern.compile("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$");
|
||||
if (doneFile.getBoolean("updateUsersIgnoreListUUID", false)) {
|
||||
@@ -164,12 +404,12 @@ public class EssentialsUpgrade {
|
||||
if (!file.isFile() || !file.getName().endsWith(".yml")) {
|
||||
continue;
|
||||
}
|
||||
final EssentialsConf config = new EssentialsConf(file);
|
||||
final EssentialsConfiguration config = new EssentialsConfiguration(file);
|
||||
try {
|
||||
config.load();
|
||||
if (config.hasProperty("ignore")) {
|
||||
final List<String> migratedIgnores = new ArrayList<>();
|
||||
for (final String name : Collections.synchronizedList(config.getStringList("ignore"))) {
|
||||
for (final String name : Collections.synchronizedList(config.getList("ignore", String.class))) {
|
||||
if (name == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -184,10 +424,10 @@ public class EssentialsUpgrade {
|
||||
}
|
||||
config.removeProperty("ignore");
|
||||
config.setProperty("ignore", migratedIgnores);
|
||||
config.forceSave();
|
||||
config.blockingSave();
|
||||
}
|
||||
} catch (final RuntimeException ex) {
|
||||
LOGGER.log(Level.INFO, "File: " + file.toString());
|
||||
LOGGER.log(Level.INFO, "File: " + file);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
@@ -198,24 +438,24 @@ public class EssentialsUpgrade {
|
||||
|
||||
public void convertKits() {
|
||||
final Kits kits = ess.getKits();
|
||||
final EssentialsConf config = kits.getConfig();
|
||||
final EssentialsConfiguration config = kits.getRootConfig();
|
||||
if (doneFile.getBoolean("kitsyml", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.info("Attempting to convert old kits in config.yml to new kits.yml");
|
||||
|
||||
final ConfigurationSection section = ess.getSettings().getKitSection();
|
||||
final CommentedConfigurationNode section = ess.getSettings().getKitSection();
|
||||
if (section == null) {
|
||||
LOGGER.info("No kits found to migrate.");
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<String, Object> legacyKits = ess.getSettings().getKitSection().getValues(true);
|
||||
final Map<String, Object> legacyKits = ConfigurateUtil.getRawMap(section);
|
||||
|
||||
for (final Map.Entry<String, Object> entry : legacyKits.entrySet()) {
|
||||
LOGGER.info("Converting " + entry.getKey());
|
||||
config.set("kits." + entry.getKey(), entry.getValue());
|
||||
config.setRaw("kits." + entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
config.save();
|
||||
@@ -237,9 +477,9 @@ public class EssentialsUpgrade {
|
||||
if (!configFile.exists()) {
|
||||
return;
|
||||
}
|
||||
final EssentialsConf conf = new EssentialsConf(configFile);
|
||||
final EssentialsConfiguration conf = new EssentialsConfiguration(configFile);
|
||||
conf.load();
|
||||
final List<String> lines = conf.getStringList(name);
|
||||
final List<String> lines = conf.getList(name, String.class);
|
||||
if (lines != null && !lines.isEmpty()) {
|
||||
if (!file.createNewFile()) {
|
||||
throw new IOException("Failed to create file " + file);
|
||||
@@ -313,12 +553,12 @@ public class EssentialsUpgrade {
|
||||
if (!file.isFile() || !file.getName().endsWith(".yml")) {
|
||||
continue;
|
||||
}
|
||||
final EssentialsConf config = new EssentialsConf(file);
|
||||
final EssentialsConfiguration config = new EssentialsConfiguration(file);
|
||||
try {
|
||||
config.load();
|
||||
if (config.hasProperty("powertools")) {
|
||||
final Map<String, Object> powertools = config.getConfigurationSection("powertools").getValues(false);
|
||||
if (powertools == null) {
|
||||
final Map<String, Object> powertools = ConfigurateUtil.getRawMap(config.getSection("powertools"));
|
||||
if (powertools.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
for (final Map.Entry<String, Object> entry : powertools.entrySet()) {
|
||||
@@ -328,10 +568,11 @@ public class EssentialsUpgrade {
|
||||
powertools.put(entry.getKey(), temp);
|
||||
}
|
||||
}
|
||||
config.forceSave();
|
||||
config.setRaw("powertools", powertools);
|
||||
config.blockingSave();
|
||||
}
|
||||
} catch (final RuntimeException ex) {
|
||||
LOGGER.log(Level.INFO, "File: " + file.toString());
|
||||
LOGGER.log(Level.INFO, "File: " + file);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
@@ -353,43 +594,41 @@ public class EssentialsUpgrade {
|
||||
if (!file.isFile() || !file.getName().endsWith(".yml")) {
|
||||
continue;
|
||||
}
|
||||
final EssentialsConf config = new EssentialsConf(file);
|
||||
final EssentialsConfiguration config = new EssentialsConfiguration(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);
|
||||
final String defworld = config.getString("home.default", null);
|
||||
final Location defloc = getFakeLocation(config.getRootNode(), "home.worlds." + defworld);
|
||||
if (defloc != null) {
|
||||
config.setProperty("homes.home", defloc);
|
||||
}
|
||||
|
||||
final Set<String> worlds = config.getConfigurationSection("home.worlds").getKeys(false);
|
||||
final Set<String> worlds = ConfigurateUtil.getKeys(config.getSection("home.worlds"));
|
||||
Location loc;
|
||||
String worldName;
|
||||
|
||||
if (worlds == null) {
|
||||
if (worlds.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
for (final String world : worlds) {
|
||||
if (defworld.equalsIgnoreCase(world)) {
|
||||
continue;
|
||||
}
|
||||
loc = getFakeLocation(config, "home.worlds." + world);
|
||||
loc = getFakeLocation(config.getRootNode(), "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.setProperty("homes." + worldName, loc);
|
||||
}
|
||||
config.removeProperty("home");
|
||||
config.forceSave();
|
||||
config.blockingSave();
|
||||
}
|
||||
|
||||
} catch (final RuntimeException ex) {
|
||||
LOGGER.log(Level.INFO, "File: " + file.toString());
|
||||
LOGGER.log(Level.INFO, "File: " + file);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
@@ -442,7 +681,7 @@ public class EssentialsUpgrade {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Location getFakeLocation(final EssentialsConf config, final String path) {
|
||||
public Location getFakeLocation(final CommentedConfigurationNode config, final String path) {
|
||||
final String worldName = config.getString((path != null ? path + "." : "") + "world");
|
||||
if (worldName == null || worldName.isEmpty()) {
|
||||
return null;
|
||||
@@ -451,7 +690,8 @@ public class EssentialsUpgrade {
|
||||
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));
|
||||
return new Location(world, config.node("x").getDouble(0), config.node("y").getDouble(0),
|
||||
config.node("z").getDouble(0), config.node("yaw").getFloat(0), config.node("pitch").getFloat(0));
|
||||
}
|
||||
|
||||
private void deleteOldItemsCsv() {
|
||||
@@ -477,7 +717,7 @@ public class EssentialsUpgrade {
|
||||
|
||||
final BigInteger hash = new BigInteger(1, digest.digest());
|
||||
if (oldconfigs.contains(hash) && !file.delete()) {
|
||||
throw new IOException("Could not delete file " + file.toString());
|
||||
throw new IOException("Could not delete file " + file);
|
||||
}
|
||||
doneFile.setProperty("deleteOldItemsCsv", true);
|
||||
doneFile.save();
|
||||
@@ -494,22 +734,18 @@ public class EssentialsUpgrade {
|
||||
final File configFile = new File(ess.getDataFolder(), "spawn.yml");
|
||||
if (configFile.exists()) {
|
||||
|
||||
final EssentialsConf config = new EssentialsConf(configFile);
|
||||
final EssentialsConfiguration config = new EssentialsConfiguration(configFile);
|
||||
try {
|
||||
config.load();
|
||||
if (!config.hasProperty("spawns")) {
|
||||
final Spawns spawns = new Spawns();
|
||||
final Set<String> keys = config.getKeys(false);
|
||||
for (final String group : keys) {
|
||||
final Location loc = getFakeLocation(config, group);
|
||||
spawns.getSpawns().put(group.toLowerCase(Locale.ENGLISH), loc);
|
||||
for (final Map.Entry<String, CommentedConfigurationNode> entry : config.getMap().entrySet()) {
|
||||
final Location loc = getFakeLocation(entry.getValue(), entry.getKey());
|
||||
config.setProperty(entry.getKey(), loc);
|
||||
}
|
||||
if (!configFile.renameTo(new File(ess.getDataFolder(), "spawn.yml.old"))) {
|
||||
throw new Exception(tl("fileRenameError", "spawn.yml"));
|
||||
}
|
||||
try (final PrintWriter writer = new PrintWriter(configFile)) {
|
||||
new YamlStorageWriter(writer).save(spawns);
|
||||
}
|
||||
config.blockingSave();
|
||||
}
|
||||
} catch (final Exception ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
|
||||
@@ -526,22 +762,18 @@ public class EssentialsUpgrade {
|
||||
final File configFile = new File(ess.getDataFolder(), "jail.yml");
|
||||
if (configFile.exists()) {
|
||||
|
||||
final EssentialsConf config = new EssentialsConf(configFile);
|
||||
final EssentialsConfiguration config = new EssentialsConfiguration(configFile);
|
||||
try {
|
||||
config.load();
|
||||
if (!config.hasProperty("jails")) {
|
||||
final com.earth2me.essentials.settings.Jails jails = new com.earth2me.essentials.settings.Jails();
|
||||
final Set<String> keys = config.getKeys(false);
|
||||
for (final String jailName : keys) {
|
||||
final Location loc = getFakeLocation(config, jailName);
|
||||
jails.getJails().put(jailName.toLowerCase(Locale.ENGLISH), loc);
|
||||
for (final Map.Entry<String, CommentedConfigurationNode> entry : config.getMap().entrySet()) {
|
||||
final Location loc = getFakeLocation(entry.getValue(), entry.getKey());
|
||||
config.setProperty(entry.getKey(), loc);
|
||||
}
|
||||
if (!configFile.renameTo(new File(ess.getDataFolder(), "jail.yml.old"))) {
|
||||
throw new Exception(tl("fileRenameError", "jail.yml"));
|
||||
}
|
||||
try (final PrintWriter writer = new PrintWriter(configFile)) {
|
||||
new YamlStorageWriter(writer).save(jails);
|
||||
}
|
||||
config.blockingSave();
|
||||
}
|
||||
} catch (final Exception ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
|
||||
@@ -642,23 +874,23 @@ public class EssentialsUpgrade {
|
||||
|
||||
countFiles++;
|
||||
final File pFile = new File(userdir, string);
|
||||
final EssentialsConf conf = new EssentialsConf(pFile);
|
||||
final EssentialsConfiguration conf = new EssentialsConfiguration(pFile);
|
||||
conf.load();
|
||||
|
||||
String banReason;
|
||||
final String banReason;
|
||||
long banTimeout;
|
||||
|
||||
try {
|
||||
banReason = conf.getConfigurationSection("ban").getString("reason");
|
||||
} catch (final NullPointerException n) {
|
||||
if (conf.hasProperty("ban.reason")) {
|
||||
banReason = conf.getString("ban.reason", null);
|
||||
} else {
|
||||
banReason = null;
|
||||
}
|
||||
|
||||
final String playerName = conf.getString("lastAccountName");
|
||||
final String playerName = conf.getString("lastAccountName", null);
|
||||
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"));
|
||||
if (conf.hasProperty("ban.timeout")) {
|
||||
banTimeout = Long.parseLong(conf.getString("ban.timeout", null));
|
||||
} else {
|
||||
banTimeout = 0L;
|
||||
}
|
||||
@@ -680,11 +912,7 @@ public class EssentialsUpgrade {
|
||||
}
|
||||
|
||||
private void updateBan(final String playerName, final String banReason, final Long banTimeout) {
|
||||
if (banTimeout == 0) {
|
||||
Bukkit.getBanList(BanList.Type.NAME).addBan(playerName, banReason, null, Console.NAME);
|
||||
} else {
|
||||
Bukkit.getBanList(BanList.Type.NAME).addBan(playerName, banReason, new Date(banTimeout), Console.NAME);
|
||||
}
|
||||
Bukkit.getBanList(BanList.Type.NAME).addBan(playerName, banReason, banTimeout == 0 ? null : new Date(banTimeout), Console.NAME);
|
||||
}
|
||||
|
||||
private void repairUserMap() {
|
||||
@@ -777,5 +1005,8 @@ public class EssentialsUpgrade {
|
||||
warnMetrics();
|
||||
repairUserMap();
|
||||
convertIgnoreList();
|
||||
convertStupidCamelCaseUserdataKeys();
|
||||
convertMailList();
|
||||
purgeBrokenNpcAccounts();
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -11,7 +11,7 @@ import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class EssentialsUserConf extends EssentialsConf {
|
||||
public final String username;
|
||||
public String username;
|
||||
public final UUID uuid;
|
||||
|
||||
public EssentialsUserConf(final String username, final UUID uuid, final File configFile) {
|
||||
@@ -20,6 +20,10 @@ public class EssentialsUserConf extends EssentialsConf {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean legacyFileExists() {
|
||||
final File file = new File(configFile.getParentFile(), username + ".yml");
|
||||
File renamed without changes.
+3
-1
@@ -88,7 +88,9 @@ public class I18n implements net.ess3.api.II18n {
|
||||
return localeBundle.getString(string);
|
||||
}
|
||||
} catch (final MissingResourceException ex) {
|
||||
Logger.getLogger("Essentials").log(Level.WARNING, String.format("Missing translation key \"%s\" in translation file %s", ex.getKey(), localeBundle.getLocale().toString()), ex);
|
||||
if (ess == null || ess.getSettings().isDebug()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
File renamed without changes.
+48
@@ -3,15 +3,30 @@ package com.earth2me.essentials;
|
||||
import com.earth2me.essentials.api.IItemDb;
|
||||
import com.earth2me.essentials.api.IJails;
|
||||
import com.earth2me.essentials.api.IWarps;
|
||||
import com.earth2me.essentials.commands.IEssentialsCommand;
|
||||
import com.earth2me.essentials.commands.PlayerNotFoundException;
|
||||
import com.earth2me.essentials.perm.PermissionsHandler;
|
||||
import com.earth2me.essentials.updatecheck.UpdateChecker;
|
||||
import net.ess3.nms.refl.providers.ReflOnlineModeProvider;
|
||||
import net.ess3.provider.ContainerProvider;
|
||||
import net.ess3.provider.FormattedCommandAliasProvider;
|
||||
import net.ess3.provider.ItemUnbreakableProvider;
|
||||
import net.ess3.provider.KnownCommandsProvider;
|
||||
import net.ess3.provider.MaterialTagProvider;
|
||||
import net.ess3.provider.PersistentDataProvider;
|
||||
import net.ess3.provider.ServerStateProvider;
|
||||
import net.ess3.provider.SerializationProvider;
|
||||
import net.ess3.provider.SpawnerBlockProvider;
|
||||
import net.ess3.provider.SpawnerItemProvider;
|
||||
import net.ess3.provider.SyncCommandsProvider;
|
||||
import net.ess3.provider.WorldInfoProvider;
|
||||
import net.essentialsx.api.v2.services.BalanceTop;
|
||||
import net.essentialsx.api.v2.services.mail.MailService;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
@@ -19,6 +34,7 @@ import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -27,6 +43,8 @@ public interface IEssentials extends Plugin {
|
||||
|
||||
void reload();
|
||||
|
||||
Map<String, IEssentialsCommand> getCommandMap();
|
||||
|
||||
List<String> onTabCompleteEssentials(CommandSender sender, Command command, String commandLabel, String[] args, ClassLoader classLoader, String commandPath, String permissionPrefix, IEssentialsModule module);
|
||||
|
||||
boolean onCommandEssentials(CommandSender sender, Command command, String commandLabel, String[] args, ClassLoader classLoader, String commandPath, String permissionPrefix, IEssentialsModule module);
|
||||
@@ -40,6 +58,12 @@ public interface IEssentials extends Plugin {
|
||||
|
||||
User getUser(Player base);
|
||||
|
||||
User matchUser(Server server, User sourceUser, String searchTerm, Boolean getHidden, boolean getOffline) throws PlayerNotFoundException;
|
||||
|
||||
boolean canInteractWith(CommandSource interactor, User interactee);
|
||||
|
||||
boolean canInteractWith(User interactor, User interactee);
|
||||
|
||||
I18n getI18n();
|
||||
|
||||
User getOfflineUser(String name);
|
||||
@@ -70,6 +94,8 @@ public interface IEssentials extends Plugin {
|
||||
|
||||
RandomTeleport getRandomTeleport();
|
||||
|
||||
UpdateChecker getUpdateChecker();
|
||||
|
||||
BukkitTask runTaskAsynchronously(Runnable run);
|
||||
|
||||
BukkitTask runTaskLaterAsynchronously(Runnable run, long delay);
|
||||
@@ -94,8 +120,12 @@ public interface IEssentials extends Plugin {
|
||||
|
||||
UserMap getUserMap();
|
||||
|
||||
BalanceTop getBalanceTop();
|
||||
|
||||
EssentialsTimer getTimer();
|
||||
|
||||
MailService getMail();
|
||||
|
||||
/**
|
||||
* Get a list of players who are vanished.
|
||||
*
|
||||
@@ -115,7 +145,25 @@ public interface IEssentials extends Plugin {
|
||||
|
||||
ServerStateProvider getServerStateProvider();
|
||||
|
||||
MaterialTagProvider getMaterialTagProvider();
|
||||
|
||||
ContainerProvider getContainerProvider();
|
||||
|
||||
KnownCommandsProvider getKnownCommandsProvider();
|
||||
|
||||
SerializationProvider getSerializationProvider();
|
||||
|
||||
FormattedCommandAliasProvider getFormattedCommandAliasProvider();
|
||||
|
||||
SyncCommandsProvider getSyncCommandsProvider();
|
||||
|
||||
PersistentDataProvider getPersistentDataProvider();
|
||||
|
||||
ReflOnlineModeProvider getOnlineModeProvider();
|
||||
|
||||
ItemUnbreakableProvider getItemUnbreakableProvider();
|
||||
|
||||
WorldInfoProvider getWorldInfoProvider();
|
||||
|
||||
PluginCommand getPluginCommand(String cmd);
|
||||
}
|
||||
File renamed without changes.
+46
-21
@@ -4,9 +4,10 @@ import com.earth2me.essentials.commands.IEssentialsCommand;
|
||||
import com.earth2me.essentials.signs.EssentialsSign;
|
||||
import com.earth2me.essentials.textreader.IText;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.List;
|
||||
@@ -17,6 +18,8 @@ import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public interface ISettings extends IConf {
|
||||
File getConfigFile();
|
||||
|
||||
boolean areSignsDisabled();
|
||||
|
||||
IText getAnnounceNewPlayerFormat();
|
||||
@@ -33,6 +36,8 @@ public interface ISettings extends IConf {
|
||||
|
||||
String getChatFormat(String group);
|
||||
|
||||
String getWorldAlias(String world);
|
||||
|
||||
int getChatRadius();
|
||||
|
||||
int getNearRadius();
|
||||
@@ -59,28 +64,12 @@ public interface ISettings extends IConf {
|
||||
|
||||
boolean getSocialSpyListenMutedPlayers();
|
||||
|
||||
boolean isSocialSpyMessages();
|
||||
|
||||
Set<String> getMuteCommands();
|
||||
|
||||
/**
|
||||
* @Deprecated in favor of {@link Kits#getKits()}
|
||||
*/
|
||||
@Deprecated
|
||||
ConfigurationSection getKits();
|
||||
|
||||
/**
|
||||
* @Deprecated in favor of {@link Kits#getKit(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
Map<String, Object> getKit(String kit);
|
||||
|
||||
/**
|
||||
* @Deprecated in favor of {@link Kits#addKit(String, List, long)}}
|
||||
*/
|
||||
@Deprecated
|
||||
void addKit(String name, List<String> lines, long delay);
|
||||
|
||||
@Deprecated
|
||||
ConfigurationSection getKitSection();
|
||||
CommentedConfigurationNode getKitSection();
|
||||
|
||||
boolean isSkippingUsedOneTimeKitsFromKitList();
|
||||
|
||||
@@ -138,6 +127,10 @@ public interface ISettings extends IConf {
|
||||
|
||||
boolean isCommandDisabled(String label);
|
||||
|
||||
Set<String> getDisabledCommands();
|
||||
|
||||
boolean isVerboseCommandUsages();
|
||||
|
||||
boolean isCommandOverridden(String name);
|
||||
|
||||
boolean isDebug();
|
||||
@@ -179,6 +172,8 @@ public interface ISettings extends IConf {
|
||||
|
||||
boolean changePlayerListName();
|
||||
|
||||
boolean changeTabCompleteName();
|
||||
|
||||
boolean isPlayerCommand(String string);
|
||||
|
||||
boolean useBukkitPermissions();
|
||||
@@ -199,8 +194,12 @@ public interface ISettings extends IConf {
|
||||
|
||||
boolean cancelAfkOnInteract();
|
||||
|
||||
boolean cancelAfkOnChat();
|
||||
|
||||
boolean sleepIgnoresAfkPlayers();
|
||||
|
||||
boolean sleepIgnoresVanishedPlayers();
|
||||
|
||||
boolean isAfkListName();
|
||||
|
||||
String getAfkListName();
|
||||
@@ -239,6 +238,8 @@ public interface ISettings extends IConf {
|
||||
|
||||
long getTpaAcceptCancellation();
|
||||
|
||||
int getTpaMaxRequests();
|
||||
|
||||
long getTeleportInvulnerability();
|
||||
|
||||
boolean isTeleportInvulnerability();
|
||||
@@ -283,6 +284,12 @@ public interface ISettings extends IConf {
|
||||
|
||||
String getCustomQuitMessage();
|
||||
|
||||
String getCustomNewUsernameMessage();
|
||||
|
||||
boolean isCustomNewUsernameMessage();
|
||||
|
||||
boolean isCustomServerFullMessage();
|
||||
|
||||
boolean isNotifyNoNewMail();
|
||||
|
||||
boolean isDropItemsIfFull();
|
||||
@@ -329,8 +336,12 @@ public interface ISettings extends IConf {
|
||||
|
||||
List<EssentialsSign> getUnprotectedSignNames();
|
||||
|
||||
boolean isKitAutoEquip();
|
||||
|
||||
boolean isPastebinCreateKit();
|
||||
|
||||
boolean isUseBetterKits();
|
||||
|
||||
boolean isAllowBulkBuySell();
|
||||
|
||||
boolean isAllowSellNamedItems();
|
||||
@@ -349,7 +360,9 @@ public interface ISettings extends IConf {
|
||||
|
||||
boolean isConfirmCommandEnabledByDefault(String commandName);
|
||||
|
||||
boolean isTeleportBackWhenFreedFromJail();
|
||||
TeleportWhenFreePolicy getTeleportWhenFreePolicy();
|
||||
|
||||
boolean isJailOnlineTime();
|
||||
|
||||
boolean isCompassTowardsHomePerm();
|
||||
|
||||
@@ -377,10 +390,22 @@ public interface ISettings extends IConf {
|
||||
|
||||
boolean infoAfterDeath();
|
||||
|
||||
boolean isRespawnAtBed();
|
||||
|
||||
boolean isUpdateCheckEnabled();
|
||||
|
||||
boolean showZeroBaltop();
|
||||
|
||||
enum KeepInvPolicy {
|
||||
KEEP,
|
||||
DELETE,
|
||||
DROP
|
||||
}
|
||||
|
||||
enum TeleportWhenFreePolicy {
|
||||
SPAWN,
|
||||
BACK,
|
||||
OFF
|
||||
}
|
||||
|
||||
}
|
||||
File renamed without changes.
+111
@@ -2,19 +2,26 @@ package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.api.IAsyncTeleport;
|
||||
import com.earth2me.essentials.commands.IEssentialsCommand;
|
||||
import com.earth2me.essentials.config.entities.CommandCooldown;
|
||||
import net.ess3.api.ITeleport;
|
||||
import net.ess3.api.MaxMoneyException;
|
||||
import net.ess3.api.events.AfkStatusChangeEvent;
|
||||
import net.essentialsx.api.v2.services.mail.MailMessage;
|
||||
import net.essentialsx.api.v2.services.mail.MailSender;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -57,8 +64,11 @@ public interface IUser {
|
||||
/**
|
||||
* Returns whether this user has an outstanding teleport request to deal with.
|
||||
*
|
||||
* @deprecated The teleport request system has been moved into a multi-user teleport request queue.
|
||||
* @see IUser#hasPendingTpaRequests(boolean, boolean)
|
||||
* @return whether there is a teleport request
|
||||
*/
|
||||
@Deprecated
|
||||
boolean hasOutstandingTeleportRequest();
|
||||
|
||||
/**
|
||||
@@ -94,6 +104,11 @@ public interface IUser {
|
||||
|
||||
boolean canBuild();
|
||||
|
||||
/**
|
||||
* @deprecated The teleport request system has been moved into a multi-user teleport request queue.
|
||||
* @see IUser#getNextTpaRequest(boolean, boolean, boolean)
|
||||
*/
|
||||
@Deprecated
|
||||
long getTeleportRequestTime();
|
||||
|
||||
void enableInvulnerabilityAfterTeleport();
|
||||
@@ -145,10 +160,24 @@ public interface IUser {
|
||||
|
||||
void setJail(String jail);
|
||||
|
||||
String getFormattedJailTime();
|
||||
|
||||
@Deprecated
|
||||
List<String> getMails();
|
||||
|
||||
@Deprecated
|
||||
void addMail(String mail);
|
||||
|
||||
void sendMail(MailSender sender, String message);
|
||||
|
||||
void sendMail(MailSender sender, String message, long expireAt);
|
||||
|
||||
ArrayList<MailMessage> getMailMessages();
|
||||
|
||||
void setMailList(ArrayList<MailMessage> messages);
|
||||
|
||||
int getMailAmount();
|
||||
|
||||
boolean isAfk();
|
||||
|
||||
@Deprecated
|
||||
@@ -158,6 +187,7 @@ public interface IUser {
|
||||
|
||||
void setIgnoreMsg(boolean ignoreMsg);
|
||||
|
||||
@Deprecated
|
||||
void setConfigProperty(String node, Object object);
|
||||
|
||||
Set<String> getConfigKeys();
|
||||
@@ -166,8 +196,11 @@ public interface IUser {
|
||||
|
||||
Map<String, Object> getConfigMap(String node);
|
||||
|
||||
@Deprecated
|
||||
Map<Pattern, Long> getCommandCooldowns();
|
||||
|
||||
List<CommandCooldown> getCooldownsList();
|
||||
|
||||
Date getCommandCooldownExpiry(String label);
|
||||
|
||||
void addCommandCooldown(Pattern pattern, Date expiresAt, boolean save);
|
||||
@@ -183,8 +216,12 @@ public interface IUser {
|
||||
|
||||
String getName();
|
||||
|
||||
UUID getUUID();
|
||||
|
||||
String getDisplayName();
|
||||
|
||||
String getFormattedNickname();
|
||||
|
||||
String getAfkMessage();
|
||||
|
||||
void setAfkMessage(final String message);
|
||||
@@ -210,4 +247,78 @@ public interface IUser {
|
||||
Map<User, BigDecimal> getConfirmingPayments();
|
||||
|
||||
Block getTargetBlock(int maxDistance);
|
||||
|
||||
void setToggleShout(boolean toggleShout);
|
||||
|
||||
boolean isToggleShout();
|
||||
|
||||
/**
|
||||
* Gets information about the most-recently-made, non-expired TPA request in the tpa queue of this {@link IUser}.
|
||||
* <p>
|
||||
* The TPA Queue is Last-In-First-Out queue which stores all the active pending teleport
|
||||
* requests of this {@link IUser}. Timeout calculations are also done during the
|
||||
* iteration process of this method, ensuring that teleport requests made past the timeout
|
||||
* period are removed from queue and therefore not returned here. The maximum size of this
|
||||
* queue is determined by {@link ISettings#getTpaMaxRequests()}.
|
||||
*
|
||||
* @param inform true if the underlying {@link IUser} should be informed if a request expires during iteration.
|
||||
* @param performExpirations true if this method should not spend time validating time for all items in the queue and just return the first item in the queue.
|
||||
* @param excludeHere true if /tphere requests should be ignored in fetching the next tpa request.
|
||||
* @return A {@link TpaRequest} corresponding to the next available request or null if no valid request is present.
|
||||
*/
|
||||
@Nullable TpaRequest getNextTpaRequest(boolean inform, boolean performExpirations, boolean excludeHere);
|
||||
|
||||
/**
|
||||
* Whether or not this {@link IUser} has any valid TPA requests in queue.
|
||||
*
|
||||
* @param inform true if the user should be informed if a request expires during iteration.
|
||||
* @param excludeHere true if /tpahere requests should be ignored in checking if a tpa request is available.
|
||||
* @return true if the user has an available pending request in queue.
|
||||
*/
|
||||
boolean hasPendingTpaRequests(boolean inform, boolean excludeHere);
|
||||
|
||||
class TpaRequest {
|
||||
private final String name;
|
||||
private final UUID requesterUuid;
|
||||
private boolean here;
|
||||
private Location location;
|
||||
private long time;
|
||||
|
||||
public TpaRequest(String name, UUID requesterUuid) {
|
||||
this.name = name;
|
||||
this.requesterUuid = requesterUuid;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public UUID getRequesterUuid() {
|
||||
return requesterUuid;
|
||||
}
|
||||
|
||||
public boolean isHere() {
|
||||
return here;
|
||||
}
|
||||
|
||||
public void setHere(boolean here) {
|
||||
this.here = here;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(long time) {
|
||||
this.time = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
+98
-76
@@ -1,9 +1,10 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.storage.AsyncStorageObjectHolder;
|
||||
import com.earth2me.essentials.config.ConfigurateUtil;
|
||||
import com.earth2me.essentials.config.EssentialsConfiguration;
|
||||
import com.earth2me.essentials.config.entities.LazyLocation;
|
||||
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;
|
||||
@@ -23,28 +24,52 @@ import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
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();
|
||||
public class Jails implements net.ess3.api.IJails {
|
||||
private static final transient Logger LOGGER = Logger.getLogger("Essentials");
|
||||
private static transient boolean enabled = false;
|
||||
private final IEssentials ess;
|
||||
private final EssentialsConfiguration config;
|
||||
private final Map<String, LazyLocation> jails = new HashMap<>();
|
||||
|
||||
public Jails(final IEssentials ess) {
|
||||
super(ess, com.earth2me.essentials.settings.Jails.class);
|
||||
this.ess = ess;
|
||||
this.config = new EssentialsConfiguration(new File(ess.getDataFolder(), "jail.yml"));
|
||||
reloadConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
synchronized (jails) {
|
||||
config.load();
|
||||
jails.clear();
|
||||
final CommentedConfigurationNode jailsNode = config.getSection("jails");
|
||||
for (final Map.Entry<String, CommentedConfigurationNode> entry : ConfigurateUtil.getMap(jailsNode).entrySet()) {
|
||||
final CommentedConfigurationNode jailNode = entry.getValue();
|
||||
final String worldId = jailNode.node("world").getString();
|
||||
if (worldId == null || worldId.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
jails.put(entry.getKey().toLowerCase(Locale.ENGLISH), new LazyLocation(worldId, jailNode.node("world-name").getString(""), jailNode.node("x").getDouble(), jailNode.node("y").getDouble(),
|
||||
jailNode.node("z").getDouble(), jailNode.node("yaw").getFloat(), jailNode.node("pitch").getFloat()));
|
||||
}
|
||||
checkRegister();
|
||||
}
|
||||
}
|
||||
|
||||
private void registerListeners() {
|
||||
enabled = true;
|
||||
final PluginManager pluginManager = ess.getServer().getPluginManager();
|
||||
@@ -55,21 +80,6 @@ public class Jails extends AsyncStorageObjectHolder<com.earth2me.essentials.sett
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
@@ -82,92 +92,104 @@ public class Jails extends AsyncStorageObjectHolder<com.earth2me.essentials.sett
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getJail(final String jailName) throws Exception {
|
||||
acquireReadLock();
|
||||
try {
|
||||
if (getData().getJails() == null || jailName == null || !getData().getJails().containsKey(jailName.toLowerCase(Locale.ENGLISH))) {
|
||||
public void startTransaction() {
|
||||
config.startTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopTransaction(final boolean blocking) {
|
||||
config.stopTransaction(blocking);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getJail(String jailName) throws Exception {
|
||||
if (jailName == null) {
|
||||
throw new Exception(tl("jailNotExist"));
|
||||
}
|
||||
|
||||
jailName = jailName.toLowerCase(Locale.ENGLISH);
|
||||
synchronized (jails) {
|
||||
if (!jails.containsKey(jailName)) {
|
||||
throw new Exception(tl("jailNotExist"));
|
||||
}
|
||||
final Location loc = getData().getJails().get(jailName.toLowerCase(Locale.ENGLISH));
|
||||
if (loc == null || loc.getWorld() == null) {
|
||||
throw new Exception(tl("jailNotExist"));
|
||||
final Location location = jails.get(jailName).location();
|
||||
if (location == null) {
|
||||
throw new Exception(tl("jailWorldNotExist"));
|
||||
}
|
||||
return loc;
|
||||
} finally {
|
||||
unlock();
|
||||
return location;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getList() throws Exception {
|
||||
acquireReadLock();
|
||||
try {
|
||||
if (getData().getJails() == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return new ArrayList<>(getData().getJails().keySet());
|
||||
} finally {
|
||||
unlock();
|
||||
synchronized (jails) {
|
||||
return new ArrayList<>(jails.keySet());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeJail(final String jail) throws Exception {
|
||||
acquireWriteLock();
|
||||
try {
|
||||
if (getData().getJails() == null) {
|
||||
return;
|
||||
public void removeJail(String jail) throws Exception {
|
||||
if (jail == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
jail = jail.toLowerCase(Locale.ENGLISH);
|
||||
synchronized (jails) {
|
||||
if (jails.remove(jail) != null) {
|
||||
config.getSection("jails").node(jail).set(null);
|
||||
config.save();
|
||||
}
|
||||
getData().getJails().remove(jail.toLowerCase(Locale.ENGLISH));
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method does not use asynchronous teleportation. Use {@link Jails#sendToJail(IUser, String, CompletableFuture)}
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
@Deprecated
|
||||
public void sendToJail(final IUser user, final String jail) throws Exception {
|
||||
acquireReadLock();
|
||||
try {
|
||||
if (user.getBase().isOnline()) {
|
||||
final Location loc = getJail(jail);
|
||||
user.getTeleport().now(loc, false, TeleportCause.COMMAND);
|
||||
public void sendToJail(final IUser user, String jail) throws Exception {
|
||||
if (jail == null || jail.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
jail = jail.toLowerCase(Locale.ENGLISH);
|
||||
synchronized (jails) {
|
||||
if (jails.containsKey(jail)) {
|
||||
if (user.getBase().isOnline()) {
|
||||
user.getTeleport().now(getJail(jail), false, TeleportCause.COMMAND);
|
||||
}
|
||||
user.setJail(jail);
|
||||
}
|
||||
user.setJail(jail);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToJail(final IUser user, final String jail, final CompletableFuture<Boolean> future) throws Exception {
|
||||
acquireReadLock();
|
||||
try {
|
||||
if (user.getBase().isOnline()) {
|
||||
final Location loc = getJail(jail);
|
||||
user.getAsyncTeleport().now(loc, false, TeleportCause.COMMAND, future);
|
||||
future.thenAccept(success -> user.setJail(jail));
|
||||
return;
|
||||
public void sendToJail(final IUser user, final String jailName, final CompletableFuture<Boolean> future) throws Exception {
|
||||
if (jailName == null || jailName.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String jail = jailName.toLowerCase(Locale.ENGLISH);
|
||||
synchronized (jails) {
|
||||
if (jails.containsKey(jail)) {
|
||||
if (user.getBase().isOnline()) {
|
||||
user.getAsyncTeleport().now(getJail(jail), false, TeleportCause.COMMAND, future);
|
||||
future.thenAccept(success -> user.setJail(jail));
|
||||
return;
|
||||
}
|
||||
user.setJail(jail);
|
||||
}
|
||||
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();
|
||||
public void setJail(String jailName, final Location loc) throws Exception {
|
||||
jailName = jailName.toLowerCase(Locale.ENGLISH);
|
||||
synchronized (jails) {
|
||||
jails.put(jailName, LazyLocation.fromLocation(loc));
|
||||
config.setProperty("jails." + jailName, loc);
|
||||
config.save();
|
||||
}
|
||||
}
|
||||
|
||||
+54
-12
@@ -7,12 +7,15 @@ import com.earth2me.essentials.textreader.IText;
|
||||
import com.earth2me.essentials.textreader.KeywordReplacer;
|
||||
import com.earth2me.essentials.textreader.SimpleTextInput;
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
import com.earth2me.essentials.utils.MaterialUtil;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.events.KitClaimEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
@@ -73,6 +76,10 @@ public class Kit {
|
||||
user.setKitTimestamp(kitName, time.getTimeInMillis());
|
||||
}
|
||||
|
||||
public void resetTime(final User user) {
|
||||
user.setKitTimestamp(kitName, 0);
|
||||
}
|
||||
|
||||
public void chargeUser(final User user) throws Exception {
|
||||
charge.charge(user);
|
||||
}
|
||||
@@ -162,12 +169,13 @@ public class Kit {
|
||||
|
||||
boolean spew = false;
|
||||
final boolean allowUnsafe = ess.getSettings().allowUnsafeEnchantments();
|
||||
final boolean currencyIsSuffix = ess.getSettings().isCurrencySymbolSuffixed();
|
||||
final boolean autoEquip = ess.getSettings().isKitAutoEquip();
|
||||
final List<ItemStack> itemList = new ArrayList<>();
|
||||
final List<String> commandQueue = new ArrayList<>();
|
||||
final List<String> moneyQueue = new ArrayList<>();
|
||||
final String currencySymbol = ess.getSettings().getCurrencySymbol().isEmpty() ? "$" : ess.getSettings().getCurrencySymbol();
|
||||
for (final String kitItem : output.getLines()) {
|
||||
if (!currencyIsSuffix ? kitItem.startsWith(ess.getSettings().getCurrencySymbol()) : kitItem.endsWith(ess.getSettings().getCurrencySymbol())) {
|
||||
if (kitItem.startsWith("$") || kitItem.startsWith(currencySymbol)) {
|
||||
moneyQueue.add(NumberUtil.sanitizeCurrencyString(kitItem, ess));
|
||||
continue;
|
||||
}
|
||||
@@ -180,21 +188,51 @@ public class Kit {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String[] parts = kitItem.split(" +");
|
||||
final ItemStack parseStack = ess.getItemDb().get(parts[0], parts.length > 1 ? Integer.parseInt(parts[1]) : 1);
|
||||
final ItemStack stack;
|
||||
|
||||
if (parseStack.getType() == Material.AIR) {
|
||||
continue;
|
||||
if (kitItem.startsWith("@")) {
|
||||
if (ess.getSerializationProvider() == null) {
|
||||
ess.getLogger().log(Level.WARNING, tl("kitError3", kitName, user.getName()));
|
||||
continue;
|
||||
}
|
||||
stack = ess.getSerializationProvider().deserializeItem(Base64Coder.decodeLines(kitItem.substring(1)));
|
||||
} else {
|
||||
final String[] parts = kitItem.split(" +");
|
||||
final ItemStack parseStack = ess.getItemDb().get(parts[0], parts.length > 1 ? Integer.parseInt(parts[1]) : 1);
|
||||
|
||||
if (parseStack.getType() == Material.AIR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final MetaItemStack metaStack = new MetaItemStack(parseStack);
|
||||
|
||||
if (parts.length > 2) {
|
||||
// We pass a null sender here because kits should not do perm checks
|
||||
metaStack.parseStringMeta(null, allowUnsafe, parts, 2, ess);
|
||||
}
|
||||
|
||||
stack = metaStack.getItemStack();
|
||||
}
|
||||
|
||||
final MetaItemStack metaStack = new MetaItemStack(parseStack);
|
||||
|
||||
if (parts.length > 2) {
|
||||
// We pass a null sender here because kits should not do perm checks
|
||||
metaStack.parseStringMeta(null, allowUnsafe, parts, 2, ess);
|
||||
if (autoEquip) {
|
||||
final Material material = stack.getType();
|
||||
final PlayerInventory inventory = user.getBase().getInventory();
|
||||
if (MaterialUtil.isHelmet(material) && isEmptyStack(inventory.getHelmet())) {
|
||||
inventory.setHelmet(stack);
|
||||
continue;
|
||||
} else if (MaterialUtil.isChestplate(material) && isEmptyStack(inventory.getChestplate())) {
|
||||
inventory.setChestplate(stack);
|
||||
continue;
|
||||
} else if (MaterialUtil.isLeggings(material) && isEmptyStack(inventory.getLeggings())) {
|
||||
inventory.setLeggings(stack);
|
||||
continue;
|
||||
} else if (MaterialUtil.isBoots(material) && isEmptyStack(inventory.getBoots())) {
|
||||
inventory.setBoots(stack);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
itemList.add(metaStack.getItemStack());
|
||||
itemList.add(stack);
|
||||
}
|
||||
|
||||
final Map<Integer, ItemStack> overfilled;
|
||||
@@ -253,4 +291,8 @@ public class Kit {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isEmptyStack(ItemStack stack) {
|
||||
return stack == null || MaterialUtil.isAir(stack.getType());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.config.ConfigurateUtil;
|
||||
import com.earth2me.essentials.config.EssentialsConfiguration;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.earth2me.essentials.I18n.capitalCase;
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Kits implements IConf {
|
||||
private final IEssentials ess;
|
||||
private final EssentialsConfiguration rootConfig;
|
||||
private final Map<String, EssentialsConfiguration> kitToConfigMap = new HashMap<>();
|
||||
private final Map<String, Map<String, Object>> kitMap = new HashMap<>();
|
||||
|
||||
public Kits(final IEssentials essentials) {
|
||||
this.ess = essentials;
|
||||
this.rootConfig = new EssentialsConfiguration(new File(essentials.getDataFolder(), "kits.yml"), "/kits.yml");
|
||||
|
||||
reloadConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
rootConfig.load();
|
||||
parseKits();
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return rootConfig.getFile();
|
||||
}
|
||||
|
||||
private void parseKit(final String kitName, final CommentedConfigurationNode kitSection, final EssentialsConfiguration parentConfig) {
|
||||
if (kitSection.isMap()) {
|
||||
final String effectiveKitName = kitName.toLowerCase(Locale.ENGLISH);
|
||||
kitToConfigMap.put(effectiveKitName, parentConfig);
|
||||
kitMap.put(effectiveKitName, ConfigurateUtil.getRawMap(kitSection));
|
||||
}
|
||||
}
|
||||
|
||||
private void parseKits() {
|
||||
kitToConfigMap.clear();
|
||||
kitMap.clear();
|
||||
|
||||
// Kits from kits.yml file
|
||||
final CommentedConfigurationNode fileKits = rootConfig.getSection("kits");
|
||||
if (fileKits != null) {
|
||||
for (final Map.Entry<String, CommentedConfigurationNode> kitEntry : ConfigurateUtil.getMap(fileKits).entrySet()) {
|
||||
parseKit(kitEntry.getKey(), kitEntry.getValue(), rootConfig);
|
||||
}
|
||||
}
|
||||
|
||||
// Kits from kits subdirectory
|
||||
final File kitsFolder = new File(this.ess.getDataFolder(), "kits");
|
||||
if (!kitsFolder.exists() || !kitsFolder.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final File[] kitsFiles = kitsFolder.listFiles();
|
||||
|
||||
//noinspection ConstantConditions - will not be null, conditions checked above.
|
||||
for (final File kitFile : kitsFiles) {
|
||||
if (kitFile.getName().endsWith(".yml")) {
|
||||
final EssentialsConfiguration kitConfig = new EssentialsConfiguration(kitFile);
|
||||
kitConfig.load();
|
||||
final CommentedConfigurationNode kits = kitConfig.getSection("kits");
|
||||
if (kits != null) {
|
||||
for (final Map.Entry<String, CommentedConfigurationNode> kitEntry : ConfigurateUtil.getMap(kits).entrySet()) {
|
||||
parseKit(kitEntry.getKey(), kitEntry.getValue(), kitConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be used for EssentialsUpgrade conversions <b>only</b>.
|
||||
*/
|
||||
public EssentialsConfiguration getRootConfig() {
|
||||
return rootConfig;
|
||||
}
|
||||
|
||||
public Set<String> getKitKeys() {
|
||||
return kitMap.keySet();
|
||||
}
|
||||
|
||||
public Map<String, Object> getKit(final String name) {
|
||||
if (name != null) {
|
||||
return kitMap.get(name.replace('.', '_').replace('/', '_'));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Tries to find an existing kit name that matches the given name, ignoring case. Returns null if no match.
|
||||
public String matchKit(final String name) {
|
||||
if (name != null) {
|
||||
for (final String kitName : kitMap.keySet()) {
|
||||
if (kitName.equalsIgnoreCase(name)) {
|
||||
return kitName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addKit(String name, final List<String> lines, final long delay) {
|
||||
name = name.replace('.', '_').replace('/', '_').toLowerCase(Locale.ENGLISH);
|
||||
// Will overwrite but w/e
|
||||
rootConfig.setProperty("kits." + name + ".delay", delay);
|
||||
rootConfig.setProperty("kits." + name + ".items", lines);
|
||||
parseKits();
|
||||
rootConfig.save();
|
||||
}
|
||||
|
||||
public void removeKit(String name) {
|
||||
name = name.replace('.', '_').replace('/', '_').toLowerCase(Locale.ENGLISH);
|
||||
if (!kitToConfigMap.containsKey(name) || !kitMap.containsKey(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final EssentialsConfiguration config = kitToConfigMap.get(name);
|
||||
config.removeProperty("kits." + name);
|
||||
|
||||
config.blockingSave();
|
||||
parseKits();
|
||||
}
|
||||
|
||||
public String listKits(final net.ess3.api.IEssentials ess, final User user) throws Exception {
|
||||
try {
|
||||
final StringBuilder list = new StringBuilder();
|
||||
for (final String kitItem : kitMap.keySet()) {
|
||||
if (user == null) {
|
||||
list.append(" ").append(capitalCase(kitItem));
|
||||
} else if (user.isAuthorized("essentials.kits." + kitItem.toLowerCase(Locale.ENGLISH))) {
|
||||
String cost = "";
|
||||
String name = capitalCase(kitItem);
|
||||
final BigDecimal costPrice = new Trade("kit-" + kitItem.toLowerCase(Locale.ENGLISH), ess).getCommandCost(user);
|
||||
if (costPrice.signum() > 0) {
|
||||
cost = tl("kitCost", NumberUtil.displayCurrency(costPrice, ess));
|
||||
}
|
||||
|
||||
final Kit kit = new Kit(kitItem, ess);
|
||||
final double nextUse = kit.getNextUse(user);
|
||||
if (nextUse == -1 && ess.getSettings().isSkippingUsedOneTimeKitsFromKitList()) {
|
||||
continue;
|
||||
} else if (nextUse != 0) {
|
||||
name = tl("kitDelay", name);
|
||||
}
|
||||
|
||||
list.append(" ").append(name).append(cost);
|
||||
}
|
||||
}
|
||||
return list.toString().trim();
|
||||
} catch (final Exception ex) {
|
||||
throw new Exception(tl("kitError"), ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,53 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import net.ess3.api.IUser;
|
||||
import net.essentialsx.api.v2.services.mail.MailService;
|
||||
import net.essentialsx.api.v2.services.mail.MailMessage;
|
||||
import net.essentialsx.api.v2.services.mail.MailSender;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class MailServiceImpl implements MailService {
|
||||
private final transient ThreadLocal<SimpleDateFormat> df = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy/MM/dd HH:mm"));
|
||||
|
||||
public MailServiceImpl(IEssentials ess) {
|
||||
ess.getServer().getServicesManager().register(MailService.class, this, ess, ServicePriority.Normal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMail(IUser recipient, MailSender sender, String message) {
|
||||
sendMail(recipient, sender, message, 0L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMail(IUser recipient, MailSender sender, String message, long expireAt) {
|
||||
sendMail(recipient, new MailMessage(false, false, sender.getName(), sender.getUUID(), System.currentTimeMillis(), expireAt, message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLegacyMail(IUser recipient, String message) {
|
||||
sendMail(recipient, new MailMessage(false, true, null, null, 0L, 0L, message));
|
||||
}
|
||||
|
||||
private void sendMail(IUser recipient, MailMessage message) {
|
||||
final ArrayList<MailMessage> messages = recipient.getMailMessages();
|
||||
messages.add(0, message);
|
||||
recipient.setMailList(messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMailLine(MailMessage mail) {
|
||||
final String message = mail.getMessage();
|
||||
if (mail.isLegacy()) {
|
||||
return tl("mailMessage", message);
|
||||
}
|
||||
|
||||
final String expire = mail.getTimeExpire() != 0 ? "Timed" : "";
|
||||
return tl((mail.isRead() ? "mailFormatNewRead" : "mailFormatNew") + expire, df.get().format(new Date(mail.getTimeSent())), mail.getSenderUsername(), message);
|
||||
}
|
||||
}
|
||||
File renamed without changes.
+135
-61
@@ -7,9 +7,9 @@ import com.earth2me.essentials.utils.EnumUtil;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import com.earth2me.essentials.utils.MaterialUtil;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import com.earth2me.essentials.utils.VersionUtil;
|
||||
import com.google.common.base.Joiner;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.nms.refl.ReflUtil;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.FireworkEffect;
|
||||
@@ -23,6 +23,7 @@ import org.bukkit.inventory.meta.BannerMeta;
|
||||
import org.bukkit.inventory.meta.BlockStateMeta;
|
||||
import org.bukkit.inventory.meta.BookMeta;
|
||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||
import org.bukkit.inventory.meta.FireworkEffectMeta;
|
||||
import org.bukkit.inventory.meta.FireworkMeta;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.LeatherArmorMeta;
|
||||
@@ -32,7 +33,6 @@ import org.bukkit.potion.Potion;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@@ -47,9 +47,6 @@ import static com.earth2me.essentials.I18n.tl;
|
||||
public class MetaItemStack {
|
||||
private static final Map<String, DyeColor> colorMap = new HashMap<>();
|
||||
private static final Map<String, FireworkEffect.Type> fireworkShape = new HashMap<>();
|
||||
private static int bukkitUnbreakableSupport = -1;
|
||||
private static Method spigotMethod;
|
||||
private static Method setUnbreakableMethod;
|
||||
private static boolean useNewSkullMethod = true;
|
||||
|
||||
static {
|
||||
@@ -61,12 +58,14 @@ public class MetaItemStack {
|
||||
}
|
||||
}
|
||||
|
||||
private final transient Pattern splitPattern = Pattern.compile("[:+',;.]");
|
||||
private static final transient Pattern splitPattern = Pattern.compile("[:+',;.]");
|
||||
private static final transient Pattern hexPattern = Pattern.compile("#([0-9a-fA-F]{6})");
|
||||
private ItemStack stack;
|
||||
private FireworkEffect.Builder builder = FireworkEffect.builder();
|
||||
private PotionEffectType pEffectType;
|
||||
private PotionEffect pEffect;
|
||||
private boolean validFirework = false;
|
||||
private boolean validFireworkCharge = false;
|
||||
private boolean validPotionEffect = false;
|
||||
private boolean validPotionDuration = false;
|
||||
private boolean validPotionPower = false;
|
||||
@@ -174,6 +173,15 @@ public class MetaItemStack {
|
||||
}
|
||||
stack.setItemMeta(fmeta);
|
||||
}
|
||||
if (validFireworkCharge) {
|
||||
if (!hasMetaPermission(sender, "firework", true, true, ess)) {
|
||||
throw new Exception(tl("noMetaFirework"));
|
||||
}
|
||||
final FireworkEffect effect = builder.build();
|
||||
final FireworkEffectMeta meta = (FireworkEffectMeta) stack.getItemMeta();
|
||||
meta.setEffect(effect);
|
||||
stack.setItemMeta(meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +208,7 @@ public class MetaItemStack {
|
||||
stack.setItemMeta(meta);
|
||||
} else if (split[0].equalsIgnoreCase("unbreakable") && hasMetaPermission(sender, "unbreakable", false, true, ess)) {
|
||||
final boolean value = split.length <= 1 || Boolean.parseBoolean(split[1]);
|
||||
setUnbreakable(stack, value);
|
||||
setUnbreakable(ess, stack, value);
|
||||
} else if (split.length > 1 && (split[0].equalsIgnoreCase("player") || split[0].equalsIgnoreCase("owner")) && hasMetaPermission(sender, "head", false, true, ess)) {
|
||||
if (MaterialUtil.isPlayerHead(stack.getType(), stack.getDurability())) {
|
||||
final String owner = split[1];
|
||||
@@ -208,7 +216,7 @@ public class MetaItemStack {
|
||||
} else {
|
||||
throw new Exception(tl("onlyPlayerSkulls"));
|
||||
}
|
||||
} else if (split.length > 1 && split[0].equalsIgnoreCase("book") && stack.getType() == WRITTEN_BOOK && (hasMetaPermission(sender, "book", true, true, ess) || hasMetaPermission(sender, "chapter-" + split[1].toLowerCase(Locale.ENGLISH), true, true, ess))) {
|
||||
} else if (split.length > 1 && split[0].equalsIgnoreCase("book") && MaterialUtil.isEditableBook(stack.getType()) && (hasMetaPermission(sender, "book",true, true, ess) || hasMetaPermission(sender, "chapter-" + split[1].toLowerCase(Locale.ENGLISH), true, true, ess))) {
|
||||
final BookMeta meta = (BookMeta) stack.getItemMeta();
|
||||
final IText input = new BookInput("book", true, ess);
|
||||
final BookPager pager = new BookPager(input);
|
||||
@@ -226,6 +234,23 @@ public class MetaItemStack {
|
||||
final BookMeta meta = (BookMeta) stack.getItemMeta();
|
||||
meta.setTitle(title);
|
||||
stack.setItemMeta(meta);
|
||||
} else if (split.length > 1 && split[0].startsWith("page") && split[0].length() > 4 && MaterialUtil.isEditableBook(stack.getType()) && hasMetaPermission(sender, "page", false, true, ess)) {
|
||||
final int page = NumberUtil.isInt(split[0].substring(4)) ? (Integer.parseInt(split[0].substring(4)) - 1) : 0;
|
||||
final BookMeta meta = (BookMeta) stack.getItemMeta();
|
||||
final List<String> pages = meta.hasPages() ? new ArrayList<>(meta.getPages()) : new ArrayList<>();
|
||||
final List<String> lines = new ArrayList<>();
|
||||
for (final String line : split[1].split("(?<!\\\\)\\|")) {
|
||||
lines.add(FormatUtil.replaceFormat(line.replace('_', ' ').replace("\\|", "|")));
|
||||
}
|
||||
final String content = String.join("\n", lines);
|
||||
if (page >= pages.size()) {
|
||||
for (int i = 0; i <= page - pages.size(); i++) {
|
||||
pages.add("");
|
||||
}
|
||||
}
|
||||
pages.set(page, content);
|
||||
meta.setPages(pages);
|
||||
stack.setItemMeta(meta);
|
||||
} else if (split.length > 1 && split[0].equalsIgnoreCase("power") && MaterialUtil.isFirework(stack.getType()) && hasMetaPermission(sender, "firework-power", false, true, ess)) {
|
||||
final int power = NumberUtil.isInt(split[1]) ? Integer.parseInt(split[1]) : 0;
|
||||
final FireworkMeta meta = (FireworkMeta) stack.getItemMeta();
|
||||
@@ -234,20 +259,27 @@ public class MetaItemStack {
|
||||
} else if (split.length > 1 && split[0].equalsIgnoreCase("itemflags") && hasMetaPermission(sender, "itemflags", false, true, ess)) {
|
||||
addItemFlags(string);
|
||||
} else if (MaterialUtil.isFirework(stack.getType())) {
|
||||
//WARNING - Meta for fireworks will be ignored after this point.
|
||||
addFireworkMeta(sender, false, string, ess);
|
||||
if (!parseEnchantmentStrings(sender, allowUnsafe, split, ess)) {
|
||||
//WARNING - Meta for fireworks will be ignored after this point.
|
||||
addFireworkMeta(sender, false, string, ess);
|
||||
}
|
||||
} else if (MaterialUtil.isFireworkCharge(stack.getType())) {
|
||||
if (!parseEnchantmentStrings(sender, allowUnsafe, split, ess)) {
|
||||
//WARNING - Meta for fireworks will be ignored after this point.
|
||||
addChargeMeta(sender, false, string, ess);
|
||||
}
|
||||
} else if (MaterialUtil.isPotion(stack.getType())) {
|
||||
//WARNING - Meta for potions will be ignored after this point.
|
||||
addPotionMeta(sender, false, string, ess);
|
||||
if (split[0].equalsIgnoreCase("power") || !parseEnchantmentStrings(sender, allowUnsafe, split, ess)) {
|
||||
//WARNING - Meta for potions will be ignored after this point.
|
||||
addPotionMeta(sender, false, string, ess);
|
||||
}
|
||||
} else if (MaterialUtil.isBanner(stack.getType())) {
|
||||
if (stack.getType().toString().equals("SHIELD") && Enchantments.getByName(split[0]) != null) {
|
||||
parseEnchantmentStrings(sender, allowUnsafe, split, ess);
|
||||
} else {
|
||||
if (!parseEnchantmentStrings(sender, allowUnsafe, split, ess)) {
|
||||
//WARNING - Meta for banners will be ignored after this point.
|
||||
addBannerMeta(sender, false, string, ess);
|
||||
}
|
||||
} else if (split.length > 1 && (split[0].equalsIgnoreCase("color") || split[0].equalsIgnoreCase("colour")) && MaterialUtil.isLeatherArmor(stack.getType())) {
|
||||
final String[] color = split[1].split("(\\||,)");
|
||||
final String[] color = split[1].split("[|,]");
|
||||
if (color.length == 1 && (NumberUtil.isInt(color[0]) || color[0].startsWith("#"))) {
|
||||
// Either integer or hexadecimal
|
||||
final LeatherArmorMeta meta = (LeatherArmorMeta) stack.getItemMeta();
|
||||
@@ -300,6 +332,67 @@ public class MetaItemStack {
|
||||
stack.setItemMeta(meta);
|
||||
}
|
||||
|
||||
private void addChargeMeta(final CommandSource sender, final boolean allowShortName, final String string, final IEssentials ess) throws Exception {
|
||||
final String[] split = splitPattern.split(string, 2);
|
||||
if (split.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (split[0].equalsIgnoreCase("color") || split[0].equalsIgnoreCase("colour") || (allowShortName && split[0].equalsIgnoreCase("c"))) {
|
||||
final List<Color> primaryColors = new ArrayList<>();
|
||||
final String[] colors = split[1].split(",");
|
||||
for (final String color : colors) {
|
||||
if (colorMap.containsKey(color.toUpperCase())) {
|
||||
validFireworkCharge = true;
|
||||
primaryColors.add(colorMap.get(color.toUpperCase()).getFireworkColor());
|
||||
} else if (hexPattern.matcher(color).matches()) {
|
||||
validFireworkCharge = true;
|
||||
primaryColors.add(Color.fromRGB(Integer.decode(color)));
|
||||
} else {
|
||||
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
|
||||
}
|
||||
}
|
||||
builder.withColor(primaryColors);
|
||||
} else if (split[0].equalsIgnoreCase("shape") || split[0].equalsIgnoreCase("type") || (allowShortName && (split[0].equalsIgnoreCase("s") || split[0].equalsIgnoreCase("t")))) {
|
||||
FireworkEffect.Type finalEffect = null;
|
||||
split[1] = split[1].equalsIgnoreCase("large") ? "BALL_LARGE" : split[1];
|
||||
if (fireworkShape.containsKey(split[1].toUpperCase())) {
|
||||
finalEffect = fireworkShape.get(split[1].toUpperCase());
|
||||
} else {
|
||||
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
|
||||
}
|
||||
if (finalEffect != null) {
|
||||
builder.with(finalEffect);
|
||||
}
|
||||
} else if (split[0].equalsIgnoreCase("fade") || (allowShortName && split[0].equalsIgnoreCase("f"))) {
|
||||
final List<Color> fadeColors = new ArrayList<>();
|
||||
final String[] colors = split[1].split(",");
|
||||
for (final String color : colors) {
|
||||
if (colorMap.containsKey(color.toUpperCase())) {
|
||||
fadeColors.add(colorMap.get(color.toUpperCase()).getFireworkColor());
|
||||
} else if (hexPattern.matcher(color).matches()) {
|
||||
fadeColors.add(Color.fromRGB(Integer.decode(color)));
|
||||
} else {
|
||||
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
|
||||
}
|
||||
}
|
||||
if (!fadeColors.isEmpty()) {
|
||||
builder.withFade(fadeColors);
|
||||
}
|
||||
} else if (split[0].equalsIgnoreCase("effect") || (allowShortName && split[0].equalsIgnoreCase("e"))) {
|
||||
final String[] effects = split[1].split(",");
|
||||
for (final String effect : effects) {
|
||||
if (effect.equalsIgnoreCase("twinkle")) {
|
||||
builder.flicker(true);
|
||||
} else if (effect.equalsIgnoreCase("trail")) {
|
||||
builder.trail(true);
|
||||
} else {
|
||||
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addFireworkMeta(final CommandSource sender, final boolean allowShortName, final String string, final IEssentials ess) throws Exception {
|
||||
if (MaterialUtil.isFirework(stack.getType())) {
|
||||
final String[] split = splitPattern.split(string, 2);
|
||||
@@ -328,6 +421,9 @@ public class MetaItemStack {
|
||||
if (colorMap.containsKey(color.toUpperCase())) {
|
||||
validFirework = true;
|
||||
primaryColors.add(colorMap.get(color.toUpperCase()).getFireworkColor());
|
||||
} else if (hexPattern.matcher(color).matches()) {
|
||||
validFirework = true;
|
||||
primaryColors.add(Color.fromRGB(Integer.decode(color)));
|
||||
} else {
|
||||
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
|
||||
}
|
||||
@@ -350,6 +446,8 @@ public class MetaItemStack {
|
||||
for (final String color : colors) {
|
||||
if (colorMap.containsKey(color.toUpperCase())) {
|
||||
fadeColors.add(colorMap.get(color.toUpperCase()).getFireworkColor());
|
||||
} else if (hexPattern.matcher(color).matches()) {
|
||||
fadeColors.add(Color.fromRGB(Integer.decode(color)));
|
||||
} else {
|
||||
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
|
||||
}
|
||||
@@ -427,14 +525,14 @@ public class MetaItemStack {
|
||||
}
|
||||
pmeta.addCustomEffect(pEffect, true);
|
||||
stack.setItemMeta(pmeta);
|
||||
if (ReflUtil.getNmsVersionObject().isHigherThanOrEqualTo(ReflUtil.V1_9_R1)) {
|
||||
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_9_R01)) {
|
||||
if (isSplashPotion && stack.getType() != Material.SPLASH_POTION) {
|
||||
stack.setType(Material.SPLASH_POTION);
|
||||
} else if (!isSplashPotion && stack.getType() != Material.POTION) {
|
||||
stack.setType(Material.POTION);
|
||||
}
|
||||
} else {
|
||||
final Potion potion = Potion.fromItemStack(stack);
|
||||
final Potion potion = Potion.fromDamage(stack.getDurability());
|
||||
potion.setSplash(isSplashPotion);
|
||||
potion.apply(stack);
|
||||
}
|
||||
@@ -443,25 +541,27 @@ public class MetaItemStack {
|
||||
}
|
||||
}
|
||||
|
||||
private void parseEnchantmentStrings(final CommandSource sender, final boolean allowUnsafe, final String[] split, final IEssentials ess) throws Exception {
|
||||
private boolean parseEnchantmentStrings(final CommandSource sender, final boolean allowUnsafe, final String[] split, final IEssentials ess) throws Exception {
|
||||
final Enchantment enchantment = Enchantments.getByName(split[0]);
|
||||
if (enchantment == null || !hasMetaPermission(sender, "enchantments." + enchantment.getName().toLowerCase(Locale.ENGLISH), false, false, ess)) {
|
||||
return;
|
||||
if (enchantment == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int level = -1;
|
||||
if (split.length > 1) {
|
||||
try {
|
||||
level = Integer.parseInt(split[1]);
|
||||
} catch (final NumberFormatException ex) {
|
||||
level = -1;
|
||||
if (hasMetaPermission(sender, "enchantments." + enchantment.getName().toLowerCase(Locale.ENGLISH), false, false, ess)) {
|
||||
int level = -1;
|
||||
if (split.length > 1) {
|
||||
try {
|
||||
level = Integer.parseInt(split[1]);
|
||||
} catch (final NumberFormatException ex) {
|
||||
level = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (level < 0 || (!allowUnsafe && level > enchantment.getMaxLevel())) {
|
||||
level = enchantment.getMaxLevel();
|
||||
if (level < 0 || (!allowUnsafe && level > enchantment.getMaxLevel())) {
|
||||
level = enchantment.getMaxLevel();
|
||||
}
|
||||
addEnchantment(sender, allowUnsafe, enchantment, level);
|
||||
}
|
||||
addEnchantment(sender, allowUnsafe, enchantment, level);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addEnchantment(final CommandSource sender, final boolean allowUnsafe, final Enchantment enchantment, final int level) throws Exception {
|
||||
@@ -582,35 +682,9 @@ public class MetaItemStack {
|
||||
}
|
||||
}
|
||||
|
||||
private void setUnbreakable(final ItemStack is, final boolean unbreakable) {
|
||||
private void setUnbreakable(final IEssentials ess, final ItemStack is, final boolean unbreakable) {
|
||||
final ItemMeta meta = is.getItemMeta();
|
||||
try {
|
||||
if (bukkitUnbreakableSupport == -1) {
|
||||
try {
|
||||
ItemMeta.class.getDeclaredMethod("setUnbreakable", boolean.class);
|
||||
bukkitUnbreakableSupport = 1;
|
||||
} catch (final NoSuchMethodException | SecurityException ex) {
|
||||
bukkitUnbreakableSupport = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (bukkitUnbreakableSupport == 1) {
|
||||
meta.setUnbreakable(unbreakable);
|
||||
} else {
|
||||
if (spigotMethod == null) {
|
||||
spigotMethod = meta.getClass().getDeclaredMethod("spigot");
|
||||
spigotMethod.setAccessible(true);
|
||||
}
|
||||
final Object itemStackSpigot = spigotMethod.invoke(meta);
|
||||
if (setUnbreakableMethod == null) {
|
||||
setUnbreakableMethod = itemStackSpigot.getClass().getDeclaredMethod("setUnbreakable", Boolean.TYPE);
|
||||
setUnbreakableMethod.setAccessible(true);
|
||||
}
|
||||
setUnbreakableMethod.invoke(itemStackSpigot, unbreakable);
|
||||
}
|
||||
is.setItemMeta(meta);
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
ess.getItemUnbreakableProvider().setUnbreakable(meta, unbreakable);
|
||||
is.setItemMeta(meta);
|
||||
}
|
||||
}
|
||||
+3
@@ -102,6 +102,9 @@ public enum Mob {
|
||||
STRIDER("Strider", Enemies.FRIENDLY, "STRIDER"),
|
||||
ZOGLIN("Zoglin", Enemies.ENEMY, "ZOGLIN"),
|
||||
PIGLIN_BRUTE("PiglinBrute", Enemies.ADULT_ENEMY, "PIGLIN_BRUTE"),
|
||||
AXOLOTL("Axolotl", Enemies.FRIENDLY, "AXOLOTL"),
|
||||
GOAT("Goat", Enemies.NEUTRAL, "GOAT"),
|
||||
GLOW_SQUID("GlowSquid", Enemies.FRIENDLY, "GLOW_SQUID"),
|
||||
;
|
||||
|
||||
public static final Logger logger = Logger.getLogger("Essentials");
|
||||
+12
@@ -3,6 +3,7 @@ package com.earth2me.essentials;
|
||||
import com.earth2me.essentials.utils.EnumUtil;
|
||||
import com.earth2me.essentials.utils.VersionUtil;
|
||||
import net.ess3.nms.refl.ReflUtil;
|
||||
import org.bukkit.entity.Axolotl;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Fox;
|
||||
@@ -34,6 +35,8 @@ public final class MobCompat {
|
||||
public static final EntityType STRAY = getEntityType("STRAY");
|
||||
public static final EntityType FOX = getEntityType("FOX");
|
||||
public static final EntityType PHANTOM = getEntityType("PHANTOM");
|
||||
public static final EntityType AXOLOTL = getEntityType("AXOLOTL");
|
||||
public static final EntityType GOAT = getEntityType("GOAT");
|
||||
|
||||
// Constants for mobs that have changed since earlier versions
|
||||
public static final EntityType CAT = getEntityType("CAT", "OCELOT");
|
||||
@@ -152,6 +155,15 @@ public final class MobCompat {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setAxolotlVariant(final Entity entity, final String variant) {
|
||||
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_17_R01)) {
|
||||
return;
|
||||
}
|
||||
if (entity instanceof Axolotl) {
|
||||
((Axolotl) entity).setVariant(Axolotl.Variant.valueOf(variant));
|
||||
}
|
||||
}
|
||||
|
||||
public enum CatType {
|
||||
// These are (loosely) Mojang names for the cats
|
||||
SIAMESE("SIAMESE", "SIAMESE_CAT"),
|
||||
+31
@@ -3,13 +3,16 @@ package com.earth2me.essentials;
|
||||
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
|
||||
import com.earth2me.essentials.utils.EnumUtil;
|
||||
import com.earth2me.essentials.utils.StringUtil;
|
||||
import com.earth2me.essentials.utils.VersionUtil;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Ageable;
|
||||
import org.bukkit.entity.ChestedHorse;
|
||||
import org.bukkit.entity.Creeper;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.ExperienceOrb;
|
||||
import org.bukkit.entity.Goat;
|
||||
import org.bukkit.entity.Horse;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Phantom;
|
||||
@@ -95,11 +98,13 @@ public enum MobData {
|
||||
ALL_BLACK_CAT("allblack", MobCompat.CAT, MobCompat.CatType.BLACK, true),
|
||||
BABY_ZOMBIE("baby", EntityType.ZOMBIE.getEntityClass(), Data.BABYZOMBIE, true),
|
||||
ADULT_ZOMBIE("adult", EntityType.ZOMBIE.getEntityClass(), Data.ADULTZOMBIE, true),
|
||||
NETHERITE_SWORD_ZOMBIE("netheritesword", EntityType.ZOMBIE.getEntityClass(), EnumUtil.getMaterial("NETHERITE_SWORD"), true),
|
||||
DIAMOND_SWORD_ZOMBIE("diamondsword", EntityType.ZOMBIE.getEntityClass(), Material.DIAMOND_SWORD, true),
|
||||
GOLD_SWORD_ZOMBIE("goldsword", EntityType.ZOMBIE.getEntityClass(), EnumUtil.getMaterial("GOLDEN_SWORD", "GOLD_SWORD"), true),
|
||||
IRON_SWORD_ZOMBIE("ironsword", EntityType.ZOMBIE.getEntityClass(), Material.IRON_SWORD, true),
|
||||
STONE_SWORD_ZOMBIE("stonesword", EntityType.ZOMBIE.getEntityClass(), Material.STONE_SWORD, false),
|
||||
SWORD_ZOMBIE("sword", EntityType.ZOMBIE.getEntityClass(), Material.STONE_SWORD, true),
|
||||
NETHERITE_SWORD_SKELETON("netheritesword", EntityType.SKELETON, EnumUtil.getMaterial("NETHERITE_SWORD"), true),
|
||||
DIAMOND_SWORD_SKELETON("diamondsword", EntityType.SKELETON, Material.DIAMOND_SWORD, true),
|
||||
GOLD_SWORD_SKELETON("goldsword", EntityType.SKELETON, EnumUtil.getMaterial("GOLDEN_SWORD", "GOLD_SWORD"), true),
|
||||
IRON_SWORD_SKELETON("ironsword", EntityType.SKELETON, Material.IRON_SWORD, true),
|
||||
@@ -183,6 +188,15 @@ public enum MobData {
|
||||
RAID_LEADER("leader", MobCompat.RAIDER, Data.RAID_LEADER, true),
|
||||
TROPICAL_FISH_BODY_COLOR("fish_body_color", Arrays.stream(DyeColor.values()).map(color -> color.name().toLowerCase(Locale.ENGLISH) + "body").collect(Collectors.toList()), MobCompat.TROPICAL_FISH, Data.FISH_BODY_COLOR, true),
|
||||
TROPICAL_FISH_PATTERN_COLOR("fish_pattern_color", Arrays.stream(DyeColor.values()).map(color -> color.name().toLowerCase(Locale.ENGLISH) + "pattern").collect(Collectors.toList()), MobCompat.TROPICAL_FISH, Data.FISH_PATTERN_COLOR, true),
|
||||
LUCY_AXOLOTL("lucy", MobCompat.AXOLOTL, "axolotl:LUCY", true),
|
||||
LEUCISTIC_AXOLOTL("leucistic", MobCompat.AXOLOTL, "axolotl:LUCY", false),
|
||||
PINK_AXOLOTL("pink", MobCompat.AXOLOTL, "axolotl:LUCY", false),
|
||||
WILD_AXOLOTL("wild", MobCompat.AXOLOTL, "axolotl:WILD", true),
|
||||
BROWN_AXOLOTL("brown", MobCompat.AXOLOTL, "axolotl:WILD", false),
|
||||
GOLD_AXOLOTL("gold", MobCompat.AXOLOTL, "axolotl:GOLD", true),
|
||||
CYAN_AXOLOTL("cyan", MobCompat.AXOLOTL, "axolotl:CYAN", true),
|
||||
BLUE_AXOLOTL("blue", MobCompat.AXOLOTL, "axolotl:BLUE", true),
|
||||
SCREAMING_GOAT("screaming", MobCompat.GOAT, Data.GOAT_SCREAMING, true),
|
||||
;
|
||||
|
||||
public static final Logger logger = Logger.getLogger("Essentials");
|
||||
@@ -258,12 +272,22 @@ public enum MobData {
|
||||
}
|
||||
|
||||
public void setData(final Entity spawned, final Player target, final String rawData) throws Exception {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.value.equals(Data.ANGRY)) {
|
||||
((Wolf) spawned).setAngry(true);
|
||||
} else if (this.value.equals(Data.ADULT)) {
|
||||
((Ageable) spawned).setAdult();
|
||||
} else if (this.value.equals(Data.BABY)) {
|
||||
((Ageable) spawned).setBaby();
|
||||
} else if (this.value.equals(Data.CHEST)) {
|
||||
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_11_R01)) {
|
||||
((ChestedHorse) spawned).setCarryingChest(true);
|
||||
} else {
|
||||
((Horse) spawned).setCarryingChest(true);
|
||||
}
|
||||
} else if (this.value.equals(Data.ADULTZOMBIE)) {
|
||||
((Zombie) spawned).setBaby(false);
|
||||
} else if (this.value.equals(Data.BABYZOMBIE)) {
|
||||
@@ -350,6 +374,8 @@ public enum MobData {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (this.value.equals(Data.GOAT_SCREAMING)) {
|
||||
((Goat) spawned).setScreaming(true);
|
||||
} else if (this.value instanceof String) {
|
||||
final String[] split = ((String) this.value).split(":");
|
||||
switch (split[0]) {
|
||||
@@ -377,6 +403,10 @@ public enum MobData {
|
||||
case "fox":
|
||||
MobCompat.setFoxType(spawned, split[1]);
|
||||
break;
|
||||
case "axolotl": {
|
||||
MobCompat.setAxolotlVariant(spawned, split[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.warning("Unknown mob data type: " + this.toString());
|
||||
@@ -400,5 +430,6 @@ public enum MobData {
|
||||
RAID_LEADER,
|
||||
FISH_BODY_COLOR,
|
||||
FISH_PATTERN_COLOR,
|
||||
GOAT_SCREAMING,
|
||||
}
|
||||
}
|
||||
File renamed without changes.
+91
-3
@@ -1,10 +1,12 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -37,10 +39,12 @@ public final class PlayerList {
|
||||
}
|
||||
user.setDisplayNick();
|
||||
groupString.append(user.getDisplayName());
|
||||
if (ess.getSettings().realNamesOnList() && !ChatColor.stripColor(user.getDisplayName()).equals(user.getName())) {
|
||||
groupString.append(" (").append(user.getName()).append(")");
|
||||
|
||||
final String strippedNick = FormatUtil.stripFormat(user.getNickname());
|
||||
if (ess.getSettings().realNamesOnList() && strippedNick != null && !strippedNick.equals(user.getName())) {
|
||||
groupString.append(" ").append(tl("listRealName",user.getName()));
|
||||
}
|
||||
groupString.append("\u00a7f");
|
||||
groupString.append(ChatColor.WHITE.toString());
|
||||
}
|
||||
return groupString.toString();
|
||||
}
|
||||
@@ -125,4 +129,88 @@ public final class PlayerList {
|
||||
return tl("listGroupTag", FormatUtil.replaceFormat(group)) +
|
||||
message;
|
||||
}
|
||||
|
||||
public static List<String> prepareGroupedList(final IEssentials ess, final String commandLabel, final Map<String, List<User>> playerList) {
|
||||
final List<String> output = new ArrayList<>();
|
||||
|
||||
final Set<String> configGroups = ess.getSettings().getListGroupConfig().keySet();
|
||||
final List<String> asterisk = new ArrayList<>();
|
||||
|
||||
// Loop through the custom defined groups and display them
|
||||
for (final String oConfigGroup : configGroups) {
|
||||
final String groupValue = ess.getSettings().getListGroupConfig().get(oConfigGroup).toString().trim();
|
||||
final String configGroup = oConfigGroup.toLowerCase();
|
||||
|
||||
// If the group value is an asterisk, then skip it, and handle it later
|
||||
if (groupValue.equals("*")) {
|
||||
asterisk.add(oConfigGroup);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the group value is hidden, we don't need to display it
|
||||
if (groupValue.equalsIgnoreCase("hidden")) {
|
||||
playerList.remove(configGroup);
|
||||
continue;
|
||||
}
|
||||
|
||||
final List<User> outputUserList;
|
||||
final List<User> matchedList = playerList.get(configGroup);
|
||||
|
||||
// If the group value is an int, then we might need to truncate it
|
||||
if (NumberUtil.isInt(groupValue)) {
|
||||
if (matchedList != null && !matchedList.isEmpty()) {
|
||||
playerList.remove(configGroup);
|
||||
outputUserList = new ArrayList<>(matchedList);
|
||||
final int limit = Integer.parseInt(groupValue);
|
||||
if (matchedList.size() > limit) {
|
||||
output.add(outputFormat(oConfigGroup, tl("groupNumber", matchedList.size(), commandLabel, FormatUtil.stripFormat(configGroup))));
|
||||
} else {
|
||||
output.add(outputFormat(oConfigGroup, listUsers(ess, outputUserList, ", ")));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
outputUserList = getMergedList(ess, playerList, configGroup);
|
||||
|
||||
// If we have no users, than we don't need to continue parsing this group
|
||||
if (outputUserList.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
output.add(outputFormat(oConfigGroup, listUsers(ess, outputUserList, ", ")));
|
||||
}
|
||||
|
||||
final Set<String> var = playerList.keySet();
|
||||
String[] onlineGroups = var.toArray(new String[0]);
|
||||
Arrays.sort(onlineGroups, String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
// If we have an asterisk group, then merge all remaining groups
|
||||
if (!asterisk.isEmpty()) {
|
||||
final List<User> asteriskUsers = new ArrayList<>();
|
||||
for (final String onlineGroup : onlineGroups) {
|
||||
asteriskUsers.addAll(playerList.get(onlineGroup));
|
||||
}
|
||||
for (final String key : asterisk) {
|
||||
playerList.put(key, asteriskUsers);
|
||||
}
|
||||
onlineGroups = asterisk.toArray(new String[0]);
|
||||
}
|
||||
|
||||
// If we have any groups remaining after the custom groups loop through and display them
|
||||
for (final String onlineGroup : onlineGroups) {
|
||||
final List<User> users = playerList.get(onlineGroup);
|
||||
String groupName = asterisk.isEmpty() ? users.get(0).getGroup() : onlineGroup;
|
||||
|
||||
if (ess.getPermissionsHandler().getName().equals("ConfigPermissions")) {
|
||||
groupName = tl("connectedPlayers");
|
||||
}
|
||||
if (users == null || users.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
output.add(outputFormat(groupName, listUsers(ess, users, ", ")));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
+18
-18
@@ -1,5 +1,7 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.config.EssentialsConfiguration;
|
||||
import com.earth2me.essentials.config.entities.LazyLocation;
|
||||
import com.earth2me.essentials.utils.LocationUtil;
|
||||
import com.earth2me.essentials.utils.VersionUtil;
|
||||
import io.papermc.lib.PaperLib;
|
||||
@@ -20,16 +22,14 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
public class RandomTeleport implements IConf {
|
||||
private static final Random RANDOM = new Random();
|
||||
private static final int HIGHEST_BLOCK_Y_OFFSET = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_R01) ? 1 : 0;
|
||||
private final IEssentials essentials;
|
||||
private final EssentialsConf config;
|
||||
private final IEssentials ess;
|
||||
private final EssentialsConfiguration config;
|
||||
private final ConcurrentLinkedQueue<Location> cachedLocations = new ConcurrentLinkedQueue<>();
|
||||
|
||||
public RandomTeleport(final IEssentials essentials) {
|
||||
this.essentials = essentials;
|
||||
final File file = new File(essentials.getDataFolder(), "tpr.yml");
|
||||
config = new EssentialsConf(file);
|
||||
config.setTemplateName("/tpr.yml");
|
||||
config.options().copyHeader(true);
|
||||
this.ess = essentials;
|
||||
config = new EssentialsConfiguration(new File(essentials.getDataFolder(), "tpr.yml"), "/tpr.yml",
|
||||
"Configuration for the random teleport command.\nSome settings may be defaulted, and can be changed via the /settpr command in-game.");
|
||||
reloadConfig();
|
||||
}
|
||||
|
||||
@@ -41,14 +41,14 @@ public class RandomTeleport implements IConf {
|
||||
|
||||
public Location getCenter() {
|
||||
try {
|
||||
final Location center = config.getLocation("center", essentials.getServer());
|
||||
if (center != null) {
|
||||
return center;
|
||||
final LazyLocation center = config.getLocation("center");
|
||||
if (center != null && center.location() != null) {
|
||||
return center.location();
|
||||
}
|
||||
} catch (final InvalidWorldException ignored) {
|
||||
}
|
||||
final Location center = essentials.getServer().getWorlds().get(0).getWorldBorder().getCenter();
|
||||
center.setY(center.getWorld().getHighestBlockYAt(center) + 1);
|
||||
final Location center = ess.getServer().getWorlds().get(0).getWorldBorder().getCenter();
|
||||
center.setY(center.getWorld().getHighestBlockYAt(center) + HIGHEST_BLOCK_Y_OFFSET);
|
||||
setCenter(center);
|
||||
return center;
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public class RandomTeleport implements IConf {
|
||||
}
|
||||
|
||||
public Set<Biome> getExcludedBiomes() {
|
||||
final List<String> biomeNames = config.getStringList("excluded-biomes");
|
||||
final List<String> biomeNames = config.getList("excluded-biomes", String.class);
|
||||
final Set<Biome> excludedBiomes = new HashSet<>();
|
||||
for (final String biomeName : biomeNames) {
|
||||
try {
|
||||
@@ -124,7 +124,7 @@ public class RandomTeleport implements IConf {
|
||||
|
||||
// Prompts caching random valid locations, up to a maximum number of attempts
|
||||
public void cacheRandomLocations(final Location center, final double minRange, final double maxRange) {
|
||||
essentials.getServer().getScheduler().scheduleSyncDelayedTask(essentials, () -> {
|
||||
ess.getServer().getScheduler().scheduleSyncDelayedTask(ess, () -> {
|
||||
for (int i = 0; i < this.getFindAttempts(); ++i) {
|
||||
calculateRandomLocation(center, minRange, maxRange).thenAccept(location -> {
|
||||
if (isValidRandomLocation(location)) {
|
||||
@@ -177,7 +177,7 @@ public class RandomTeleport implements IConf {
|
||||
final Location location = new Location(
|
||||
center.getWorld(),
|
||||
center.getX() + offsetX,
|
||||
center.getWorld().getMaxHeight(),
|
||||
ess.getWorldInfoProvider().getMaxHeight(center.getWorld()),
|
||||
center.getZ() + offsetZ,
|
||||
360 * RANDOM.nextFloat() - 180,
|
||||
0
|
||||
@@ -195,8 +195,8 @@ public class RandomTeleport implements IConf {
|
||||
|
||||
// Returns an appropriate elevation for a given location in the nether, or -1 if none is found
|
||||
private double getNetherYAt(final Location location) {
|
||||
for (int y = 32; y < location.getWorld().getMaxHeight() / 2; ++y) {
|
||||
if (!LocationUtil.isBlockUnsafe(location.getWorld(), location.getBlockX(), y, location.getBlockZ())) {
|
||||
for (int y = 32; y < ess.getWorldInfoProvider().getMaxHeight(location.getWorld()); ++y) {
|
||||
if (!LocationUtil.isBlockUnsafe(ess, location.getWorld(), location.getBlockX(), y, location.getBlockZ())) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
@@ -204,6 +204,6 @@ public class RandomTeleport implements IConf {
|
||||
}
|
||||
|
||||
private boolean isValidRandomLocation(final Location location) {
|
||||
return location.getBlockY() > 0 && !this.getExcludedBiomes().contains(location.getBlock().getBiome());
|
||||
return location.getBlockY() > ess.getWorldInfoProvider().getMinHeight(location.getWorld()) && !this.getExcludedBiomes().contains(location.getBlock().getBiome());
|
||||
}
|
||||
}
|
||||
+300
-88
@@ -2,6 +2,8 @@ package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.api.IItemDb;
|
||||
import com.earth2me.essentials.commands.IEssentialsCommand;
|
||||
import com.earth2me.essentials.config.ConfigurateUtil;
|
||||
import com.earth2me.essentials.config.EssentialsConfiguration;
|
||||
import com.earth2me.essentials.signs.EssentialsSign;
|
||||
import com.earth2me.essentials.signs.Signs;
|
||||
import com.earth2me.essentials.textreader.IText;
|
||||
@@ -13,10 +15,10 @@ import com.earth2me.essentials.utils.NumberUtil;
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.MemoryConfiguration;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
@@ -35,6 +37,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -45,10 +48,11 @@ import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class Settings implements net.ess3.api.ISettings {
|
||||
private static final Logger logger = Logger.getLogger("Essentials");
|
||||
private static final BigDecimal MAXMONEY = new BigDecimal("10000000000000");
|
||||
private static final BigDecimal MINMONEY = new BigDecimal("-10000000000000");
|
||||
private final transient EssentialsConf config;
|
||||
private static final BigDecimal DEFAULT_MAX_MONEY = new BigDecimal("10000000000000");
|
||||
private static final BigDecimal DEFAULT_MIN_MONEY = new BigDecimal("-10000000000000");
|
||||
private final transient EssentialsConfiguration config;
|
||||
private final transient IEssentials ess;
|
||||
private final transient AtomicInteger reloadCount = new AtomicInteger(0);
|
||||
private final Map<String, String> chatFormats = Collections.synchronizedMap(new HashMap<>());
|
||||
private int chatRadius = 0;
|
||||
// #easteregg
|
||||
@@ -58,7 +62,10 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
private boolean teleportSafety;
|
||||
private boolean forceDisableTeleportSafety;
|
||||
private Set<String> disabledCommands = new HashSet<>();
|
||||
private ConfigurationSection commandCosts;
|
||||
private List<String> overriddenCommands = Collections.emptyList();
|
||||
private List<String> playerCommands = Collections.emptyList();
|
||||
private final transient Map<String, Command> disabledBukkitCommands = new HashMap<>();
|
||||
private Map<String, BigDecimal> commandCosts;
|
||||
private Set<String> socialSpyCommands = new HashSet<>();
|
||||
private Set<String> muteCommands = new HashSet<>();
|
||||
private String nicknamePrefix = "~";
|
||||
@@ -71,8 +78,8 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
private boolean configDebug = false;
|
||||
// #easteregg
|
||||
private boolean economyDisabled = false;
|
||||
private BigDecimal maxMoney = MAXMONEY;
|
||||
private BigDecimal minMoney = MINMONEY;
|
||||
private BigDecimal maxMoney = DEFAULT_MAX_MONEY;
|
||||
private BigDecimal minMoney = DEFAULT_MIN_MONEY;
|
||||
private boolean economyLog = false;
|
||||
// #easteregg
|
||||
private boolean economyLogUpdate = false;
|
||||
@@ -111,17 +118,18 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
private boolean isCustomJoinMessage;
|
||||
private String customQuitMessage;
|
||||
private boolean isCustomQuitMessage;
|
||||
private String customNewUsernameMessage;
|
||||
private boolean isCustomNewUsernameMessage;
|
||||
private List<String> spawnOnJoinGroups;
|
||||
private Map<Pattern, Long> commandCooldowns;
|
||||
private boolean npcsInBalanceRanking = false;
|
||||
private NumberFormat currencyFormat;
|
||||
private List<EssentialsSign> unprotectedSigns = Collections.emptyList();
|
||||
private List<String> defaultEnabledConfirmCommands;
|
||||
private boolean teleportBackWhenFreedFromJail;
|
||||
private TeleportWhenFreePolicy teleportWhenFreePolicy;
|
||||
private boolean isCompassTowardsHomePerm;
|
||||
private boolean isAllowWorldInBroadcastworld;
|
||||
private String itemDbType; // #EasterEgg - admins can manually switch items provider if they want
|
||||
private boolean forceEnableRecipe; // https://github.com/EssentialsX/Essentials/issues/1397
|
||||
private boolean allowOldIdSigns;
|
||||
private boolean isWaterSafe;
|
||||
private boolean isSafeUsermap;
|
||||
@@ -129,14 +137,19 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
private Set<Predicate<String>> nickBlacklist;
|
||||
private double maxProjectileSpeed;
|
||||
private boolean removeEffectsOnHeal;
|
||||
private Map<String, String> worldAliases;
|
||||
|
||||
public Settings(final IEssentials ess) {
|
||||
this.ess = ess;
|
||||
config = new EssentialsConf(new File(ess.getDataFolder(), "config.yml"));
|
||||
config.setTemplateName("/config.yml");
|
||||
config = new EssentialsConfiguration(new File(ess.getDataFolder(), "config.yml"), "/config.yml");
|
||||
reloadConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getConfigFile() {
|
||||
return config.getFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRespawnAtHome() {
|
||||
return config.getBoolean("respawn-at-home", false);
|
||||
@@ -154,8 +167,8 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
|
||||
@Override
|
||||
public Set<String> getMultipleHomes() {
|
||||
final ConfigurationSection section = config.getConfigurationSection("sethome-multiple");
|
||||
return section == null ? null : section.getKeys(false);
|
||||
final CommentedConfigurationNode section = config.getSection("sethome-multiple");
|
||||
return section == null ? null : ConfigurateUtil.getKeys(section);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -276,12 +289,39 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return disabledCommands.contains(label);
|
||||
}
|
||||
|
||||
private Set<String> getDisabledCommands() {
|
||||
@Override
|
||||
public Set<String> getDisabledCommands() {
|
||||
return disabledCommands;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVerboseCommandUsages() {
|
||||
return config.getBoolean("verbose-command-usages", true);
|
||||
}
|
||||
|
||||
private void _addAlternativeCommand(final String label, final Command current) {
|
||||
Command cmd = ess.getAlternativeCommandsHandler().getAlternative(label);
|
||||
if (cmd == null) {
|
||||
for (final Map.Entry<String, Command> entry : ess.getKnownCommandsProvider().getKnownCommands().entrySet()) {
|
||||
final String[] split = entry.getKey().split(":");
|
||||
if (entry.getValue() != current && split[split.length - 1].equals(label)) {
|
||||
cmd = entry.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd != null) {
|
||||
ess.getKnownCommandsProvider().getKnownCommands().put(label, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> _getDisabledCommands() {
|
||||
final Set<String> disCommands = new HashSet<>();
|
||||
for (final String c : config.getStringList("disabled-commands")) {
|
||||
for (final String c : config.getList("disabled-commands", String.class)) {
|
||||
disCommands.add(c.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
for (final String c : config.getKeys(false)) {
|
||||
for (final String c : config.getKeys()) {
|
||||
if (c.startsWith("disable-")) {
|
||||
disCommands.add(c.substring(8).toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
@@ -289,9 +329,13 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return disCommands;
|
||||
}
|
||||
|
||||
private List<String> _getPlayerCommands() {
|
||||
return config.getList("player-commands", String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayerCommand(final String label) {
|
||||
for (final String c : config.getStringList("player-commands")) {
|
||||
for (final String c : playerCommands) {
|
||||
if (!c.equalsIgnoreCase(label)) {
|
||||
continue;
|
||||
}
|
||||
@@ -300,9 +344,13 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<String> _getOverriddenCommands() {
|
||||
return config.getList("overridden-commands", String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommandOverridden(final String name) {
|
||||
for (final String c : config.getStringList("overridden-commands")) {
|
||||
for (final String c : overriddenCommands) {
|
||||
if (!c.equalsIgnoreCase(name)) {
|
||||
continue;
|
||||
}
|
||||
@@ -316,32 +364,34 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return getCommandCost(cmd.getName());
|
||||
}
|
||||
|
||||
private ConfigurationSection _getCommandCosts() {
|
||||
if (config.isConfigurationSection("command-costs")) {
|
||||
final ConfigurationSection section = config.getConfigurationSection("command-costs");
|
||||
final ConfigurationSection newSection = new MemoryConfiguration();
|
||||
for (final String command : section.getKeys(false)) {
|
||||
private Map<String, BigDecimal> _getCommandCosts() {
|
||||
final Map<String, CommentedConfigurationNode> section = ConfigurateUtil.getMap(config.getSection("command-costs"));
|
||||
if (!section.isEmpty()) {
|
||||
final Map<String, BigDecimal> newMap = new HashMap<>();
|
||||
for (Map.Entry<String, CommentedConfigurationNode> entry : section.entrySet()) {
|
||||
final String command = entry.getKey();
|
||||
final CommentedConfigurationNode node = entry.getValue();
|
||||
if (command.charAt(0) == '/') {
|
||||
ess.getLogger().warning("Invalid command cost. '" + command + "' should not start with '/'.");
|
||||
}
|
||||
if (section.isDouble(command)) {
|
||||
newSection.set(command.toLowerCase(Locale.ENGLISH), section.getDouble(command));
|
||||
} else if (section.isInt(command)) {
|
||||
newSection.set(command.toLowerCase(Locale.ENGLISH), (double) section.getInt(command));
|
||||
} else if (section.isString(command)) {
|
||||
final String costString = section.getString(command);
|
||||
try {
|
||||
final double cost = Double.parseDouble(costString.trim().replace(getCurrencySymbol(), "").replaceAll("\\W", ""));
|
||||
newSection.set(command.toLowerCase(Locale.ENGLISH), cost);
|
||||
} catch (final NumberFormatException ex) {
|
||||
ess.getLogger().warning("Invalid command cost for: " + command + " (" + costString + ")");
|
||||
try {
|
||||
if (ConfigurateUtil.isDouble(node)) {
|
||||
newMap.put(command.toLowerCase(Locale.ENGLISH), BigDecimal.valueOf(node.getDouble()));
|
||||
} else if (ConfigurateUtil.isInt(node)) {
|
||||
newMap.put(command.toLowerCase(Locale.ENGLISH), BigDecimal.valueOf(node.getInt()));
|
||||
} else if (ConfigurateUtil.isString(node)) {
|
||||
final String costString = node.getString();
|
||||
//noinspection ConstantConditions
|
||||
final double cost = Double.parseDouble(costString.trim().replace("$", "").replace(getCurrencySymbol(), "").replaceAll("\\W", ""));
|
||||
newMap.put(command.toLowerCase(Locale.ENGLISH), BigDecimal.valueOf(cost));
|
||||
} else {
|
||||
ess.getLogger().warning("Invalid command cost for: " + command);
|
||||
}
|
||||
|
||||
} else {
|
||||
} catch (final Exception ex) {
|
||||
ess.getLogger().warning("Invalid command cost for: " + command);
|
||||
}
|
||||
}
|
||||
return newSection;
|
||||
return newMap;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -349,8 +399,8 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
@Override
|
||||
public BigDecimal getCommandCost(String name) {
|
||||
name = name.replace('.', '_').replace('/', '_');
|
||||
if (commandCosts != null) {
|
||||
return EssentialsConf.toBigDecimal(commandCosts.getString(name), BigDecimal.ZERO);
|
||||
if (commandCosts != null && commandCosts.containsKey(name)) {
|
||||
return commandCosts.get(name);
|
||||
}
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
@@ -359,7 +409,7 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
final Set<String> socialspyCommands = new HashSet<>();
|
||||
|
||||
if (config.isList("socialspy-commands")) {
|
||||
for (final String c : config.getStringList("socialspy-commands")) {
|
||||
for (final String c : config.getList("socialspy-commands", String.class)) {
|
||||
socialspyCommands.add(c.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
} else {
|
||||
@@ -379,10 +429,15 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return config.getBoolean("socialspy-listen-muted-players", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSocialSpyMessages() {
|
||||
return config.getBoolean("socialspy-messages", true);
|
||||
}
|
||||
|
||||
private Set<String> _getMuteCommands() {
|
||||
final Set<String> muteCommands = new HashSet<>();
|
||||
if (config.isList("mute-commands")) {
|
||||
for (final String s : config.getStringList("mute-commands")) {
|
||||
for (final String s : config.getList("mute-commands", String.class)) {
|
||||
muteCommands.add(s.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
}
|
||||
@@ -415,23 +470,8 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationSection getKits() {
|
||||
return ess.getKits().getKits();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getKit(final String name) {
|
||||
return ess.getKits().getKit(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addKit(final String name, final List<String> lines, final long delay) {
|
||||
ess.getKits().addKit(name, lines, delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationSection getKitSection() {
|
||||
return config.getConfigurationSection("kits");
|
||||
public CommentedConfigurationNode getKitSection() {
|
||||
return config.getSection("kits");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -528,6 +568,7 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
mFormat = mFormat.replace("{PREFIX}", "{6}");
|
||||
mFormat = mFormat.replace("{SUFFIX}", "{7}");
|
||||
mFormat = mFormat.replace("{USERNAME}", "{8}");
|
||||
mFormat = mFormat.replace("{NICKNAME}", "{9}");
|
||||
mFormat = "§r".concat(mFormat);
|
||||
chatFormats.put(group, mFormat);
|
||||
}
|
||||
@@ -537,6 +578,24 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWorldAlias(String world) {
|
||||
return worldAliases.getOrDefault(world.toLowerCase(), world);
|
||||
}
|
||||
|
||||
private Map<String, String> _getWorldAliases() {
|
||||
final Map<String, String> map = new HashMap<>();
|
||||
final CommentedConfigurationNode section = config.getSection("chat.world-aliases");
|
||||
if (section == null) {
|
||||
return map;
|
||||
}
|
||||
|
||||
for (Map.Entry<String, CommentedConfigurationNode> entry : ConfigurateUtil.getMap(section).entrySet()) {
|
||||
map.put(entry.getKey().toLowerCase(), FormatUtil.replaceFormat(entry.getValue().getString()));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAnnounceNewPlayers() {
|
||||
return !config.getString("newbies.announce-format", "-").isEmpty();
|
||||
@@ -564,8 +623,9 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getListGroupConfig() {
|
||||
if (config.isConfigurationSection("list")) {
|
||||
final Map<String, Object> values = config.getConfigurationSection("list").getValues(false);
|
||||
final CommentedConfigurationNode node = config.getSection("list");
|
||||
if (node != null && node.isMap()) {
|
||||
final Map<String, Object> values = ConfigurateUtil.getRawMap(node);
|
||||
if (!values.isEmpty()) {
|
||||
return values;
|
||||
}
|
||||
@@ -582,7 +642,7 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
config.load();
|
||||
noGodWorlds = new HashSet<>(config.getStringList("no-god-in-worlds"));
|
||||
noGodWorlds = new HashSet<>(config.getList("no-god-in-worlds", String.class));
|
||||
enabledSigns = _getEnabledSigns();
|
||||
teleportSafety = _isTeleportSafetyEnabled();
|
||||
forceDisableTeleportSafety = _isForceDisableTeleportSafety();
|
||||
@@ -595,14 +655,66 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
getFreezeAfkPlayers = _getFreezeAfkPlayers();
|
||||
sleepIgnoresAfkPlayers = _sleepIgnoresAfkPlayers();
|
||||
afkListName = _getAfkListName();
|
||||
isAfkListName = !afkListName.equalsIgnoreCase("none");
|
||||
isAfkListName = afkListName != null && !afkListName.equalsIgnoreCase("none");
|
||||
broadcastAfkMessage = _broadcastAfkMessage();
|
||||
itemSpawnBl = _getItemSpawnBlacklist();
|
||||
loginAttackDelay = _getLoginAttackDelay();
|
||||
signUsePerSecond = _getSignUsePerSecond();
|
||||
chatFormats.clear();
|
||||
changeDisplayName = _changeDisplayName();
|
||||
disabledCommands = getDisabledCommands();
|
||||
disabledCommands = _getDisabledCommands();
|
||||
overriddenCommands = _getOverriddenCommands();
|
||||
playerCommands = _getPlayerCommands();
|
||||
|
||||
// This will be late loaded
|
||||
if (ess.getKnownCommandsProvider() != null) {
|
||||
boolean mapModified = false;
|
||||
if (!disabledBukkitCommands.isEmpty()) {
|
||||
if (isDebug()) {
|
||||
logger.log(Level.INFO, "Re-adding " + disabledBukkitCommands.size() + " disabled commands!");
|
||||
}
|
||||
ess.getKnownCommandsProvider().getKnownCommands().putAll(disabledBukkitCommands);
|
||||
disabledBukkitCommands.clear();
|
||||
mapModified = true;
|
||||
}
|
||||
|
||||
for (final String command : disabledCommands) {
|
||||
final String effectiveAlias = command.toLowerCase(Locale.ENGLISH);
|
||||
final Command toDisable = ess.getPluginCommand(effectiveAlias);
|
||||
if (toDisable != null) {
|
||||
if (isDebug()) {
|
||||
logger.log(Level.INFO, "Attempting removal of " + effectiveAlias);
|
||||
}
|
||||
final Command removed = ess.getKnownCommandsProvider().getKnownCommands().remove(effectiveAlias);
|
||||
if (removed != null) {
|
||||
if (isDebug()) {
|
||||
logger.log(Level.INFO, "Adding command " + effectiveAlias + " to disabled map!");
|
||||
}
|
||||
disabledBukkitCommands.put(effectiveAlias, removed);
|
||||
}
|
||||
|
||||
// This is 2 because Settings are reloaded twice in the startup lifecycle
|
||||
if (reloadCount.get() < 2) {
|
||||
ess.scheduleSyncDelayedTask(() -> _addAlternativeCommand(effectiveAlias, toDisable));
|
||||
} else {
|
||||
_addAlternativeCommand(effectiveAlias, toDisable);
|
||||
}
|
||||
mapModified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mapModified) {
|
||||
if (isDebug()) {
|
||||
logger.log(Level.INFO, "Syncing commands");
|
||||
}
|
||||
if (reloadCount.get() < 2) {
|
||||
ess.scheduleSyncDelayedTask(() -> ess.getSyncCommandsProvider().syncCommands());
|
||||
} else {
|
||||
ess.getSyncCommandsProvider().syncCommands();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nicknamePrefix = _getNicknamePrefix();
|
||||
operatorColor = _getOperatorColor();
|
||||
changePlayerListName = _changePlayerListName();
|
||||
@@ -630,6 +742,8 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
isCustomJoinMessage = !customJoinMessage.equals("none");
|
||||
customQuitMessage = _getCustomQuitMessage();
|
||||
isCustomQuitMessage = !customQuitMessage.equals("none");
|
||||
customNewUsernameMessage = _getCustomNewUsernameMessage();
|
||||
isCustomNewUsernameMessage = !customNewUsernameMessage.equals("none");
|
||||
muteCommands = _getMuteCommands();
|
||||
spawnOnJoinGroups = _getSpawnOnJoinGroups();
|
||||
commandCooldowns = _getCommandCooldowns();
|
||||
@@ -637,7 +751,7 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
currencyFormat = _getCurrencyFormat();
|
||||
unprotectedSigns = _getUnprotectedSign();
|
||||
defaultEnabledConfirmCommands = _getDefaultEnabledConfirmCommands();
|
||||
teleportBackWhenFreedFromJail = _isTeleportBackWhenFreedFromJail();
|
||||
teleportWhenFreePolicy = _getTeleportWhenFreePolicy();
|
||||
isCompassTowardsHomePerm = _isCompassTowardsHomePerm();
|
||||
isAllowWorldInBroadcastworld = _isAllowWorldInBroadcastworld();
|
||||
itemDbType = _getItemDbType();
|
||||
@@ -650,6 +764,10 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
removeEffectsOnHeal = _isRemovingEffectsOnHeal();
|
||||
vanishingItemPolicy = _getVanishingItemsPolicy();
|
||||
bindingItemPolicy = _getBindingItemsPolicy();
|
||||
currencySymbol = _getCurrencySymbol();
|
||||
worldAliases = _getWorldAliases();
|
||||
|
||||
reloadCount.incrementAndGet();
|
||||
}
|
||||
|
||||
void _lateLoadItemSpawnBlacklist() {
|
||||
@@ -663,6 +781,7 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
|
||||
private List<Material> _getItemSpawnBlacklist() {
|
||||
final List<Material> epItemSpwn = new ArrayList<>();
|
||||
//noinspection deprecation
|
||||
final IItemDb itemDb = ess.getItemDb();
|
||||
if (itemDb == null || !itemDb.isReady()) {
|
||||
logger.log(Level.FINE, "Skipping item spawn blacklist read; item DB not yet loaded.");
|
||||
@@ -693,7 +812,7 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
|
||||
final List<EssentialsSign> newSigns = new ArrayList<>();
|
||||
|
||||
for (String signName : config.getStringList("enabledSigns")) {
|
||||
for (String signName : config.getList("enabledSigns", String.class)) {
|
||||
signName = signName.trim().toUpperCase(Locale.ENGLISH);
|
||||
if (signName.isEmpty()) {
|
||||
continue;
|
||||
@@ -751,11 +870,20 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return config.getString("locale", "");
|
||||
}
|
||||
|
||||
//This method should always only return one character due to the implementation of the calling methods
|
||||
//If you need to use a string currency, for example "coins", use the translation key 'currency'.
|
||||
private String currencySymbol = "$";
|
||||
|
||||
// A valid currency symbol value must be one non-integer character.
|
||||
private String _getCurrencySymbol() {
|
||||
String value = config.getString("currency-symbol", "$").trim();
|
||||
if (value.length() > 1 || value.matches("\\d")) {
|
||||
value = "$";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrencySymbol() {
|
||||
return config.getString("currency-symbol", "$").concat("$").substring(0, 1).replaceAll("[0-9]", "$");
|
||||
return currencySymbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -829,7 +957,7 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
}
|
||||
|
||||
private BigDecimal _getMaxMoney() {
|
||||
return config.getBigDecimal("max-money", MAXMONEY);
|
||||
return config.getBigDecimal("max-money", DEFAULT_MAX_MONEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -838,7 +966,7 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
}
|
||||
|
||||
private BigDecimal _getMinMoney() {
|
||||
BigDecimal min = config.getBigDecimal("min-money", MINMONEY);
|
||||
BigDecimal min = config.getBigDecimal("min-money", DEFAULT_MIN_MONEY);
|
||||
if (min.signum() > 0) {
|
||||
min = min.negate();
|
||||
}
|
||||
@@ -896,6 +1024,11 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return changePlayerListName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean changeTabCompleteName() {
|
||||
return config.getBoolean("change-tab-complete-name", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useBukkitPermissions() {
|
||||
return config.getBoolean("use-bukkit-permissions", false);
|
||||
@@ -974,6 +1107,11 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return config.getBoolean("cancel-afk-on-interact", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancelAfkOnChat() {
|
||||
return config.getBoolean("cancel-afk-on-chat", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sleepIgnoresAfkPlayers() {
|
||||
return sleepIgnoresAfkPlayers;
|
||||
@@ -983,6 +1121,11 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return config.getBoolean("sleep-ignores-afk-players", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sleepIgnoresVanishedPlayers() {
|
||||
return config.getBoolean("sleep-ignores-vanished-player", true);
|
||||
}
|
||||
|
||||
public String _getAfkListName() {
|
||||
return FormatUtil.replaceFormat(config.getString("afk-list-name", "none"));
|
||||
}
|
||||
@@ -1121,6 +1264,11 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return config.getLong("tpa-accept-cancellation", 120);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTpaMaxRequests() {
|
||||
return config.getInt("tpa-max-requests", 5);
|
||||
}
|
||||
|
||||
private long _getTeleportInvulnerability() {
|
||||
return config.getLong("teleport-invulnerability", 0) * 1000;
|
||||
}
|
||||
@@ -1261,6 +1409,25 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return isCustomQuitMessage;
|
||||
}
|
||||
|
||||
public String _getCustomNewUsernameMessage() {
|
||||
return FormatUtil.replaceFormat(config.getString("custom-new-username-message", "none"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCustomNewUsernameMessage() {
|
||||
return customNewUsernameMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCustomNewUsernameMessage() {
|
||||
return isCustomNewUsernameMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCustomServerFullMessage() {
|
||||
return config.getBoolean("use-custom-server-full-message", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJoinQuitMessagePlayerCount() {
|
||||
return config.getInt("hide-join-quit-messages-above", -1);
|
||||
@@ -1335,12 +1502,12 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
|
||||
public List<String> _getSpawnOnJoinGroups() {
|
||||
final List<String> def = Collections.emptyList();
|
||||
if (config.isSet("spawn-on-join")) {
|
||||
if (config.hasProperty("spawn-on-join")) {
|
||||
if (config.isList("spawn-on-join")) {
|
||||
return new ArrayList<>(config.getStringList("spawn-on-join"));
|
||||
return new ArrayList<>(config.getList("spawn-on-join", String.class));
|
||||
} else if (config.isBoolean("spawn-on-join")) { // List of [*] to make all groups go to spawn on join.
|
||||
// This also maintains backwards compatibility with initial impl of single boolean value.
|
||||
return config.getBoolean("spawn-on-join") ? Collections.singletonList("*") : def;
|
||||
return config.getBoolean("spawn-on-join", true) ? Collections.singletonList("*") : def;
|
||||
}
|
||||
// Take whatever the value is, convert to string and add it to a list as a single value.
|
||||
final String val = config.get("spawn-on-join").toString();
|
||||
@@ -1356,7 +1523,7 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserInSpawnOnJoinGroup(final IUser user) {
|
||||
public boolean isUserInSpawnOnJoinGroup(@SuppressWarnings("deprecation") final IUser user) {
|
||||
for (final String group : this.spawnOnJoinGroups) {
|
||||
if (group.equals("*") || user.inGroup(group)) {
|
||||
return true;
|
||||
@@ -1371,12 +1538,14 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
}
|
||||
|
||||
private Map<Pattern, Long> _getCommandCooldowns() {
|
||||
if (!config.isConfigurationSection("command-cooldowns")) {
|
||||
final CommentedConfigurationNode section = config.getSection("command-cooldowns");
|
||||
if (section == null) {
|
||||
return null;
|
||||
}
|
||||
final ConfigurationSection section = config.getConfigurationSection("command-cooldowns");
|
||||
final Map<Pattern, Long> result = new LinkedHashMap<>();
|
||||
for (String cmdEntry : section.getKeys(false)) {
|
||||
for (Map.Entry<String, Object> entry : ConfigurateUtil.getRawMap(section).entrySet()) {
|
||||
String cmdEntry = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
Pattern pattern = null;
|
||||
|
||||
/* ================================
|
||||
@@ -1394,14 +1563,13 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
cmdEntry = cmdEntry.substring(1);
|
||||
}
|
||||
final String cmd = cmdEntry
|
||||
.replaceAll("\\*", ".*"); // Wildcards are accepted as asterisk * as known universally.
|
||||
.replaceAll("\\*", ".*"); // Wildcards are accepted as asterisk * as known universally.
|
||||
pattern = Pattern.compile(cmd + "( .*)?"); // This matches arguments, if present, to "ignore" them from the feature.
|
||||
}
|
||||
|
||||
/* ================================
|
||||
* >> Process cooldown value
|
||||
* ================================ */
|
||||
Object value = section.get(cmdEntry);
|
||||
if (value instanceof String) {
|
||||
try {
|
||||
value = Double.parseDouble(value.toString());
|
||||
@@ -1469,7 +1637,7 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
private NumberFormat _getCurrencyFormat() {
|
||||
final String currencyFormatString = config.getString("currency-format", "#,##0.00");
|
||||
|
||||
final String symbolLocaleString = config.getString("currency-symbol-format-locale");
|
||||
final String symbolLocaleString = config.getString("currency-symbol-format-locale", null);
|
||||
final DecimalFormatSymbols decimalFormatSymbols;
|
||||
if (symbolLocaleString != null) {
|
||||
decimalFormatSymbols = DecimalFormatSymbols.getInstance(Locale.forLanguageTag(symbolLocaleString));
|
||||
@@ -1499,7 +1667,7 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
private List<EssentialsSign> _getUnprotectedSign() {
|
||||
final List<EssentialsSign> newSigns = new ArrayList<>();
|
||||
|
||||
for (String signName : config.getStringList("unprotected-sign-names")) {
|
||||
for (String signName : config.getList("unprotected-sign-names", String.class)) {
|
||||
signName = signName.trim().toUpperCase(Locale.ENGLISH);
|
||||
if (signName.isEmpty()) {
|
||||
continue;
|
||||
@@ -1513,11 +1681,21 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return newSigns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isKitAutoEquip() {
|
||||
return config.getBoolean("kit-auto-equip", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPastebinCreateKit() {
|
||||
return config.getBoolean("pastebin-createkit", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseBetterKits() {
|
||||
return config.getBoolean("use-nbt-serialization-in-createkit", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowBulkBuySell() {
|
||||
return config.getBoolean("allow-bulk-buy-sell", false);
|
||||
@@ -1564,7 +1742,7 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
}
|
||||
|
||||
private List<String> _getDefaultEnabledConfirmCommands() {
|
||||
final List<String> commands = config.getStringList("default-enabled-confirm-commands");
|
||||
final List<String> commands = config.getList("default-enabled-confirm-commands", String.class);
|
||||
for (int i = 0; i < commands.size(); i++) {
|
||||
commands.set(i, commands.get(i).toLowerCase());
|
||||
}
|
||||
@@ -1581,13 +1759,32 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
return getDefaultEnabledConfirmCommands().contains(commandName.toLowerCase());
|
||||
}
|
||||
|
||||
private boolean _isTeleportBackWhenFreedFromJail() {
|
||||
return config.getBoolean("teleport-back-when-freed-from-jail", true);
|
||||
private TeleportWhenFreePolicy _getTeleportWhenFreePolicy() {
|
||||
if (config.hasProperty("teleport-back-when-freed-from-jail")) {
|
||||
return config.getBoolean("teleport-back-when-freed-from-jail", true) ? TeleportWhenFreePolicy.BACK : TeleportWhenFreePolicy.OFF;
|
||||
}
|
||||
|
||||
if (config.hasProperty("teleport-when-freed")) {
|
||||
// snakeyaml more like cursedyaml
|
||||
final String value = config.getString("teleport-when-freed", "back").replace("false", "off");
|
||||
try {
|
||||
return TeleportWhenFreePolicy.valueOf(value.toUpperCase(Locale.ROOT));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException("Invalid value \"" + value + "\" for config option \"teleport-when-freed\"!", e);
|
||||
}
|
||||
}
|
||||
|
||||
return TeleportWhenFreePolicy.BACK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTeleportBackWhenFreedFromJail() {
|
||||
return teleportBackWhenFreedFromJail;
|
||||
public TeleportWhenFreePolicy getTeleportWhenFreePolicy() {
|
||||
return teleportWhenFreePolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJailOnlineTime() {
|
||||
return config.getBoolean("jail-online-time", false);
|
||||
}
|
||||
|
||||
private boolean _isCompassTowardsHomePerm() {
|
||||
@@ -1659,7 +1856,7 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
private Set<Predicate<String>> _getNickBlacklist() {
|
||||
final Set<Predicate<String>> blacklist = new HashSet<>();
|
||||
|
||||
config.getStringList("nick-blacklist").forEach(entry -> {
|
||||
config.getList("nick-blacklist", String.class).forEach(entry -> {
|
||||
try {
|
||||
blacklist.add(Pattern.compile(entry).asPredicate());
|
||||
} catch (final PatternSyntaxException e) {
|
||||
@@ -1707,4 +1904,19 @@ public class Settings implements net.ess3.api.ISettings {
|
||||
public boolean infoAfterDeath() {
|
||||
return config.getBoolean("send-info-after-death", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRespawnAtBed() {
|
||||
return config.getBoolean("respawn-at-home-bed", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpdateCheckEnabled() {
|
||||
return config.getBoolean("update-check", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showZeroBaltop() {
|
||||
return config.getBoolean("show-zero-baltop", true);
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -5,6 +5,7 @@ import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
|
||||
import com.earth2me.essentials.utils.EnumUtil;
|
||||
import com.earth2me.essentials.utils.LocationUtil;
|
||||
import com.earth2me.essentials.utils.StringUtil;
|
||||
import com.earth2me.essentials.utils.VersionUtil;
|
||||
import net.ess3.api.IEssentials;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
@@ -102,7 +103,7 @@ public final class SpawnMob {
|
||||
|
||||
// This method spawns a mob at loc, owned by target
|
||||
public static void spawnmob(final IEssentials ess, final Server server, final CommandSource sender, final User target, final Location loc, final List<String> parts, final List<String> data, int mobCount) throws Exception {
|
||||
final Location sloc = LocationUtil.getSafeDestination(loc);
|
||||
final Location sloc = LocationUtil.getSafeDestination(ess, loc);
|
||||
|
||||
for (final String part : parts) {
|
||||
final Mob mob = Mob.fromName(part);
|
||||
@@ -205,6 +206,11 @@ public final class SpawnMob {
|
||||
final EntityEquipment invent = ((LivingEntity) spawned).getEquipment();
|
||||
if (inputData.contains("noarmor") || inputData.contains("noarmour")) {
|
||||
invent.clear();
|
||||
} else if (inputData.contains("netherite") && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_16_1_R01)) {
|
||||
invent.setBoots(new ItemStack(Material.NETHERITE_BOOTS, 1));
|
||||
invent.setLeggings(new ItemStack(Material.NETHERITE_LEGGINGS, 1));
|
||||
invent.setChestplate(new ItemStack(Material.NETHERITE_CHESTPLATE, 1));
|
||||
invent.setHelmet(new ItemStack(Material.NETHERITE_HELMET, 1));
|
||||
} else if (inputData.contains("diamond")) {
|
||||
invent.setBoots(new ItemStack(Material.DIAMOND_BOOTS, 1));
|
||||
invent.setLeggings(new ItemStack(Material.DIAMOND_LEGGINGS, 1));
|
||||
File renamed without changes.
+1
-1
@@ -145,7 +145,7 @@ public class Teleport implements ITeleport {
|
||||
teleportee.getBase().eject();
|
||||
}
|
||||
|
||||
if (LocationUtil.isBlockUnsafeForUser(teleportee, loc.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) {
|
||||
if (LocationUtil.isBlockUnsafeForUser(ess, teleportee, loc.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) {
|
||||
if (ess.getSettings().isTeleportSafetyEnabled()) {
|
||||
if (ess.getSettings().isForceDisableTeleportSafety()) {
|
||||
PaperLib.teleportAsync(teleportee.getBase(), loc, cause);
|
||||
File renamed without changes.
Loaded 100 of 693 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user