mirror of
https://github.com/EssentialsX/Essentials.git
synced 2026-11-05 01:00:13 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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,93 @@
|
||||
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: textarea
|
||||
attributes:
|
||||
label: "`/ess version` output"
|
||||
description: Run `/ess version` in the console, then copy and paste the full output of the command into this box.
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Server startup log
|
||||
description: Upload your server startup log (from the start of `latest.log` up to where it says "Done!") to either https://paste.gg or https://gist.github.com, save and then paste the link in this box.
|
||||
placeholder: "Example: https://paste.gg/p/anonymous/109dd6a10a734a3aa430d5a351ea5210"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: EssentialsX config files
|
||||
description: Upload your EssentialsX `config.yml` (and any other relevant files like `kits.yml`) to either https://paste.gg or https://gist.github.com, save and then 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"
|
||||
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,51 @@
|
||||
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'
|
||||
|
||||
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.bukkit", module: "bukkit"
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
dependencies {
|
||||
include (dependency('io.papermc:paperlib'))
|
||||
include (dependency('org.bstats:bstats-bukkit'))
|
||||
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'))
|
||||
}
|
||||
relocate 'io.papermc.lib', 'com.earth2me.essentials.paperlib'
|
||||
relocate 'org.bstats.bukkit', 'com.earth2me.essentials.metrics'
|
||||
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;
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
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,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,106 @@
|
||||
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")) {
|
||||
return;
|
||||
}
|
||||
for (final Map.Entry<String, Command> entry : getPluginCommands(plugin).entrySet()) {
|
||||
final String commandName = entry.getKey().contains(":") ? entry.getKey().split(":")[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;
|
||||
}
|
||||
}
|
||||
+41
-13
@@ -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,13 +177,17 @@ 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 (ess.getSettings().isTeleportSafetyEnabled()) {
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
+391
-138
@@ -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,43 @@ 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.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.KnownCommandsProvider;
|
||||
import net.ess3.provider.MaterialTagProvider;
|
||||
import net.ess3.provider.PersistentDataProvider;
|
||||
import net.ess3.provider.PotionMetaProvider;
|
||||
import net.ess3.provider.SerializationProvider;
|
||||
import net.ess3.provider.ProviderListener;
|
||||
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.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.FlatSpawnEggProvider;
|
||||
import net.ess3.provider.providers.LegacyPotionMetaProvider;
|
||||
import net.ess3.provider.providers.LegacySpawnEggProvider;
|
||||
import net.ess3.provider.providers.ModernPersistentDataProvider;
|
||||
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 +92,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;
|
||||
@@ -89,19 +108,22 @@ 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 +147,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 +159,21 @@ 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 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 +208,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 +219,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 +245,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 +262,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 +273,149 @@ 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();
|
||||
|
||||
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 +430,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 +517,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 +569,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 +595,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 +619,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 +675,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 +725,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) || ((PluginIdentifiableCommand) newCmd).getPlugin() != this) {
|
||||
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 +753,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 +771,16 @@ 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));
|
||||
sender.sendMessage(tl("commandHelpLine1", commandLabel));
|
||||
sender.sendMessage(tl("commandHelpLine2", command.getDescription()));
|
||||
sender.sendMessage(tl("commandHelpLine3"));
|
||||
if (getSettings().isVerboseCommandUsages() && !cmd.getUsageStrings().isEmpty()) {
|
||||
for (Map.Entry<String, String> usage : cmd.getUsageStrings().entrySet()) {
|
||||
sender.sendMessage(tl("commandHelpLineUsage", usage.getKey().replace("<command>", commandLabel), usage.getValue()));
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(command.getUsage().replace("<command>", commandLabel));
|
||||
}
|
||||
if (!ex.getMessage().isEmpty()) {
|
||||
sender.sendMessage(ex.getMessage());
|
||||
}
|
||||
@@ -743,6 +859,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 +910,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 +1156,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 +1171,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 +1230,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 +1244,36 @@ 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 PluginCommand getPluginCommand(final String cmd) {
|
||||
return this.getCommand(cmd);
|
||||
}
|
||||
|
||||
private AbstractItemDb getItemDbFromConfig() {
|
||||
final String setting = settings.getItemDbType();
|
||||
|
||||
@@ -1050,7 +1303,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
public void onWorldLoad(final WorldLoadEvent event) {
|
||||
PermissionsDefaults.registerBackDefaultFor(event.getWorld());
|
||||
|
||||
ess.getJails().onReload();
|
||||
ess.getJails().reloadConfig();
|
||||
ess.getWarps().reloadConfig();
|
||||
for (final IConf iConf : ((Essentials) ess).confList) {
|
||||
if (iConf instanceof IEssentialsModule) {
|
||||
@@ -1061,7 +1314,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onWorldUnload(final WorldUnloadEvent event) {
|
||||
ess.getJails().onReload();
|
||||
ess.getJails().reloadConfig();
|
||||
ess.getWarps().reloadConfig();
|
||||
for (final IConf iConf : ((Essentials) ess).confList) {
|
||||
if (iConf instanceof IEssentialsModule) {
|
||||
+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.
+101
-26
@@ -6,19 +6,24 @@ 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.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;
|
||||
@@ -61,15 +66,18 @@ 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.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;
|
||||
@@ -162,7 +170,7 @@ public class EssentialsPlayerListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
user.updateActivityOnInteract(true);
|
||||
user.updateActivityOnChat(true);
|
||||
user.setDisplayNick();
|
||||
}
|
||||
|
||||
@@ -211,6 +219,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 +232,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 +313,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 +338,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,6 +388,14 @@ 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())) {
|
||||
@@ -398,6 +437,8 @@ public class EssentialsPlayerListener implements Listener {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
pendingMotdTasks.remove(user.getUUID());
|
||||
|
||||
IText tempInput = null;
|
||||
|
||||
if (!ess.getSettings().isCommandDisabled("motd")) {
|
||||
@@ -472,7 +513,9 @@ 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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,9 +560,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 +636,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.
|
||||
@@ -782,8 +846,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 +857,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 +876,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 +891,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;
|
||||
@@ -943,4 +1013,9 @@ public class EssentialsPlayerListener implements Listener {
|
||||
&& (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.getConfig();
|
||||
if (doneFile.getBoolean("kitsyml", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.info("Attempting to convert old kits in config.yml to new kits.yml");
|
||||
|
||||
final ConfigurationSection section = ess.getSettings().getKitSection();
|
||||
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.
+42
@@ -3,15 +3,28 @@ 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.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.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 +32,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 +41,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 +56,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 +92,8 @@ public interface IEssentials extends Plugin {
|
||||
|
||||
RandomTeleport getRandomTeleport();
|
||||
|
||||
UpdateChecker getUpdateChecker();
|
||||
|
||||
BukkitTask runTaskAsynchronously(Runnable run);
|
||||
|
||||
BukkitTask runTaskLaterAsynchronously(Runnable run, long delay);
|
||||
@@ -94,8 +118,12 @@ public interface IEssentials extends Plugin {
|
||||
|
||||
UserMap getUserMap();
|
||||
|
||||
BalanceTop getBalanceTop();
|
||||
|
||||
EssentialsTimer getTimer();
|
||||
|
||||
MailService getMail();
|
||||
|
||||
/**
|
||||
* Get a list of players who are vanished.
|
||||
*
|
||||
@@ -115,7 +143,21 @@ public interface IEssentials extends Plugin {
|
||||
|
||||
ServerStateProvider getServerStateProvider();
|
||||
|
||||
MaterialTagProvider getMaterialTagProvider();
|
||||
|
||||
ContainerProvider getContainerProvider();
|
||||
|
||||
KnownCommandsProvider getKnownCommandsProvider();
|
||||
|
||||
SerializationProvider getSerializationProvider();
|
||||
|
||||
FormattedCommandAliasProvider getFormattedCommandAliasProvider();
|
||||
|
||||
SyncCommandsProvider getSyncCommandsProvider();
|
||||
|
||||
PersistentDataProvider getPersistentDataProvider();
|
||||
|
||||
ReflOnlineModeProvider getOnlineModeProvider();
|
||||
|
||||
PluginCommand getPluginCommand(String cmd);
|
||||
}
|
||||
File renamed without changes.
+44
-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();
|
||||
@@ -283,6 +282,12 @@ public interface ISettings extends IConf {
|
||||
|
||||
String getCustomQuitMessage();
|
||||
|
||||
String getCustomNewUsernameMessage();
|
||||
|
||||
boolean isCustomNewUsernameMessage();
|
||||
|
||||
boolean isCustomServerFullMessage();
|
||||
|
||||
boolean isNotifyNoNewMail();
|
||||
|
||||
boolean isDropItemsIfFull();
|
||||
@@ -329,8 +334,12 @@ public interface ISettings extends IConf {
|
||||
|
||||
List<EssentialsSign> getUnprotectedSignNames();
|
||||
|
||||
boolean isKitAutoEquip();
|
||||
|
||||
boolean isPastebinCreateKit();
|
||||
|
||||
boolean isUseBetterKits();
|
||||
|
||||
boolean isAllowBulkBuySell();
|
||||
|
||||
boolean isAllowSellNamedItems();
|
||||
@@ -349,7 +358,9 @@ public interface ISettings extends IConf {
|
||||
|
||||
boolean isConfirmCommandEnabledByDefault(String commandName);
|
||||
|
||||
boolean isTeleportBackWhenFreedFromJail();
|
||||
TeleportWhenFreePolicy getTeleportWhenFreePolicy();
|
||||
|
||||
boolean isJailOnlineTime();
|
||||
|
||||
boolean isCompassTowardsHomePerm();
|
||||
|
||||
@@ -377,10 +388,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.
+28
@@ -2,15 +2,19 @@ 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 java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -145,10 +149,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 +176,7 @@ public interface IUser {
|
||||
|
||||
void setIgnoreMsg(boolean ignoreMsg);
|
||||
|
||||
@Deprecated
|
||||
void setConfigProperty(String node, Object object);
|
||||
|
||||
Set<String> getConfigKeys();
|
||||
@@ -166,8 +185,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);
|
||||
@@ -185,6 +207,8 @@ public interface IUser {
|
||||
|
||||
String getDisplayName();
|
||||
|
||||
String getFormattedNickname();
|
||||
|
||||
String getAfkMessage();
|
||||
|
||||
void setAfkMessage(final String message);
|
||||
@@ -210,4 +234,8 @@ public interface IUser {
|
||||
Map<User, BigDecimal> getConfirmingPayments();
|
||||
|
||||
Block getTargetBlock(int maxDistance);
|
||||
|
||||
void setToggleShout(boolean toggleShout);
|
||||
|
||||
boolean isToggleShout();
|
||||
}
|
||||
+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());
|
||||
}
|
||||
}
|
||||
+41
-36
@@ -1,8 +1,10 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.config.ConfigurateUtil;
|
||||
import com.earth2me.essentials.config.EssentialsConfiguration;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.MemoryConfiguration;
|
||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
@@ -14,13 +16,11 @@ 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;
|
||||
private final EssentialsConfiguration config;
|
||||
private CommentedConfigurationNode kits;
|
||||
|
||||
public Kits(final IEssentials essentials) {
|
||||
config = new EssentialsConf(new File(essentials.getDataFolder(), "kits.yml"));
|
||||
config.setTemplateName("/kits.yml");
|
||||
config = new EssentialsConfiguration(new File(essentials.getDataFolder(), "kits.yml"), "/kits.yml");
|
||||
|
||||
reloadConfig();
|
||||
}
|
||||
@@ -31,13 +31,22 @@ public class Kits implements IConf {
|
||||
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));
|
||||
public File getFile() {
|
||||
return config.getFile();
|
||||
}
|
||||
|
||||
private CommentedConfigurationNode _getKits() {
|
||||
final CommentedConfigurationNode section = config.getSection("kits");
|
||||
if (section != null) {
|
||||
final CommentedConfigurationNode newSection = config.newSection();
|
||||
for (final String kitItem : ConfigurateUtil.getKeys(section)) {
|
||||
final CommentedConfigurationNode kitSection = section.node(kitItem);
|
||||
if (kitSection.isMap()) {
|
||||
try {
|
||||
newSection.node(kitItem.toLowerCase(Locale.ENGLISH)).set(kitSection);
|
||||
} catch (SerializationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return newSection;
|
||||
@@ -45,25 +54,23 @@ public class Kits implements IConf {
|
||||
return null;
|
||||
}
|
||||
|
||||
public EssentialsConf getConfig() {
|
||||
public EssentialsConfiguration getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public ConfigurationSection getKits() {
|
||||
public CommentedConfigurationNode 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);
|
||||
final CommentedConfigurationNode kits = getKits();
|
||||
// Other parts of the codebase/3rd party plugins expect us to lowercase kit names here.
|
||||
// This isn't strictly needed for the future of Essentials, but for compatibility it's here.
|
||||
final CommentedConfigurationNode kitSection = kits.node(name.toLowerCase());
|
||||
if (!kitSection.virtual() && kitSection.isMap()) {
|
||||
return ConfigurateUtil.getRawMap(kitSection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,13 +79,11 @@ public class Kits implements IConf {
|
||||
|
||||
// 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;
|
||||
}
|
||||
final CommentedConfigurationNode section = config.getSection("kits");
|
||||
if (section != null) {
|
||||
for (final String kitName : ConfigurateUtil.getKeys(section)) {
|
||||
if (kitName.equalsIgnoreCase(name)) {
|
||||
return kitName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,23 +92,23 @@ public class Kits implements IConf {
|
||||
|
||||
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);
|
||||
config.setProperty("kits." + name + ".delay", delay);
|
||||
config.setProperty("kits." + name + ".items", lines);
|
||||
kits = _getKits();
|
||||
config.save();
|
||||
}
|
||||
|
||||
public void removeKit(final String name) {
|
||||
config.set("kits." + name, null);
|
||||
config.removeProperty("kits." + name);
|
||||
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 CommentedConfigurationNode kits = config.getSection("kits");
|
||||
final StringBuilder list = new StringBuilder();
|
||||
for (final String kitItem : kits.getKeys(false)) {
|
||||
for (final String kitItem : ConfigurateUtil.getKeys(kits)) {
|
||||
if (user == null) {
|
||||
list.append(" ").append(capitalCase(kitItem));
|
||||
} else if (user.isAuthorized("essentials.kits." + kitItem.toLowerCase(Locale.ENGLISH))) {
|
||||
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.
+128
-24
@@ -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;
|
||||
@@ -61,12 +62,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 +177,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +220,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 +238,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 +263,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 +336,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 +425,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 +450,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]));
|
||||
}
|
||||
@@ -443,25 +545,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 {
|
||||
+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.
+90
-2
@@ -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())) {
|
||||
|
||||
final String strippedNick = FormatUtil.stripFormat(user.getNickname());
|
||||
if (ess.getSettings().realNamesOnList() && strippedNick != null && !strippedNick.equals(user.getName())) {
|
||||
groupString.append(" (").append(user.getName()).append(")");
|
||||
}
|
||||
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.
+9
-9
@@ -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;
|
||||
@@ -21,15 +23,13 @@ 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 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);
|
||||
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,9 +41,9 @@ 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) {
|
||||
}
|
||||
@@ -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 {
|
||||
+295
-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"));
|
||||
}
|
||||
@@ -1261,6 +1404,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 +1497,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 +1518,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 +1533,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 +1558,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 +1632,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 +1662,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 +1676,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 +1737,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 +1754,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 +1851,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 +1899,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);
|
||||
}
|
||||
}
|
||||
+6
@@ -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;
|
||||
@@ -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.
File renamed without changes.
File renamed without changes.
+8
-1
@@ -68,7 +68,7 @@ public class Trade {
|
||||
this.ess = ess;
|
||||
}
|
||||
|
||||
public static void log(final String type, final String subtype, final String event, final String sender, final Trade charge, final String receiver, final Trade pay, final Location loc, final IEssentials ess) {
|
||||
public static void log(final String type, final String subtype, final String event, final String sender, final Trade charge, final String receiver, final Trade pay, final Location loc, final BigDecimal endBalance, final IEssentials ess) {
|
||||
//isEcoLogUpdateEnabled() - This refers to log entries with no location, ie API updates #EasterEgg
|
||||
//isEcoLogEnabled() - This refers to log entries with with location, ie /pay /sell and eco signs.
|
||||
|
||||
@@ -142,6 +142,13 @@ public class Trade {
|
||||
sb.append(loc.getBlockY()).append(",");
|
||||
sb.append(loc.getBlockZ()).append(",");
|
||||
}
|
||||
|
||||
if (endBalance == null) {
|
||||
sb.append(",");
|
||||
} else {
|
||||
sb.append(endBalance);
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append("\n");
|
||||
try {
|
||||
fw.write(sb.toString());
|
||||
File renamed without changes.
+172
-57
@@ -1,22 +1,28 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.commands.IEssentialsCommand;
|
||||
import com.earth2me.essentials.economy.EconomyLayer;
|
||||
import com.earth2me.essentials.economy.EconomyLayers;
|
||||
import com.earth2me.essentials.messaging.IMessageRecipient;
|
||||
import com.earth2me.essentials.messaging.SimpleMessageRecipient;
|
||||
import com.earth2me.essentials.register.payment.Method;
|
||||
import com.earth2me.essentials.register.payment.Methods;
|
||||
import com.earth2me.essentials.utils.DateUtil;
|
||||
import com.earth2me.essentials.utils.EnumUtil;
|
||||
import com.earth2me.essentials.utils.FormatUtil;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import com.earth2me.essentials.utils.TriState;
|
||||
import com.earth2me.essentials.utils.VersionUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.MaxMoneyException;
|
||||
import net.ess3.api.events.AfkStatusChangeEvent;
|
||||
import net.ess3.api.events.JailStatusChangeEvent;
|
||||
import net.ess3.api.events.MuteStatusChangeEvent;
|
||||
import net.ess3.api.events.UserBalanceUpdateEvent;
|
||||
import net.essentialsx.api.v2.events.TransactionEvent;
|
||||
import net.essentialsx.api.v2.services.mail.MailSender;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
@@ -40,6 +46,7 @@ import java.util.logging.Logger;
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public class User extends UserData implements Comparable<User>, IMessageRecipient, net.ess3.api.IUser {
|
||||
private static final Statistic PLAY_ONE_TICK = EnumUtil.getStatistic("PLAY_ONE_MINUTE", "PLAY_ONE_TICK");
|
||||
private static final Logger logger = Logger.getLogger("Essentials");
|
||||
private final IMessageRecipient messageRecipient;
|
||||
private transient final AsyncTeleport teleport;
|
||||
@@ -67,6 +74,8 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
private long lastNotifiedAboutMailsMs;
|
||||
private String lastHomeConfirmation;
|
||||
private long lastHomeConfirmationTimestamp;
|
||||
private boolean toggleShout = false;
|
||||
private transient final List<String> signCopy = Lists.newArrayList("", "", "", "");
|
||||
|
||||
public User(final Player base, final IEssentials ess) {
|
||||
super(base, ess);
|
||||
@@ -107,11 +116,22 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(final String node) {
|
||||
return isPermSetCheck(node);
|
||||
final boolean result = isPermSetCheck(node);
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().log(Level.INFO, "checking if " + base.getName() + " has " + node + " (set-explicit) - " + result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given permission is explicitly defined and returns its value, otherwise
|
||||
* {@link TriState#UNSET}.
|
||||
*/
|
||||
public TriState isAuthorizedExact(final String node) {
|
||||
return isAuthorizedExactCheck(node);
|
||||
}
|
||||
|
||||
private boolean isAuthorizedCheck(final String node) {
|
||||
|
||||
if (base instanceof OfflinePlayer) {
|
||||
return false;
|
||||
}
|
||||
@@ -147,6 +167,24 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
}
|
||||
}
|
||||
|
||||
private TriState isAuthorizedExactCheck(final String node) {
|
||||
if (base instanceof OfflinePlayer) {
|
||||
return TriState.UNSET;
|
||||
}
|
||||
|
||||
try {
|
||||
return ess.getPermissionsHandler().isPermissionSetExact(base, node);
|
||||
} catch (final Exception ex) {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().log(Level.SEVERE, "Permission System Error: " + ess.getPermissionsHandler().getName() + " returned: " + ex.getMessage(), ex);
|
||||
} else {
|
||||
ess.getLogger().log(Level.SEVERE, "Permission System Error: " + ess.getPermissionsHandler().getName() + " returned: " + ex.getMessage());
|
||||
}
|
||||
|
||||
return TriState.UNSET;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void healCooldown() throws Exception {
|
||||
final Calendar now = new GregorianCalendar();
|
||||
@@ -199,6 +237,8 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
reciever.setMoney(reciever.getMoney().add(value), cause);
|
||||
sendMessage(tl("moneySentTo", NumberUtil.displayCurrency(value, ess), reciever.getDisplayName()));
|
||||
reciever.sendMessage(tl("moneyRecievedFrom", NumberUtil.displayCurrency(value, ess), getDisplayName()));
|
||||
final TransactionEvent transactionEvent = new TransactionEvent(this.getSource(), reciever, value);
|
||||
ess.getServer().getPluginManager().callEvent(transactionEvent);
|
||||
} else {
|
||||
throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(value, ess)));
|
||||
}
|
||||
@@ -268,6 +308,8 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
final int id = material.getId();
|
||||
if (isAuthorized("essentials.itemspawn.item-" + id)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return isAuthorized("essentials.itemspawn.exempt") || !ess.getSettings().itemSpawnBlacklist().contains(material);
|
||||
@@ -420,6 +462,15 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
return super.getBase().getDisplayName() == null || (ess.getSettings().hideDisplayNameInVanish() && isHidden()) ? super.getBase().getName() : super.getBase().getDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFormattedNickname() {
|
||||
final String rawNickname = getNickname();
|
||||
if (rawNickname == null) {
|
||||
return null;
|
||||
}
|
||||
return FormatUtil.replaceFormat(ess.getSettings().getNicknamePrefix() + rawNickname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncTeleport getAsyncTeleport() {
|
||||
return teleport;
|
||||
@@ -465,16 +516,9 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
}
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
if (Methods.hasMethod()) {
|
||||
try {
|
||||
final Method method = Methods.getMethod();
|
||||
if (!method.hasAccount(this.getName())) {
|
||||
throw new Exception();
|
||||
}
|
||||
final Method.MethodAccount account = Methods.getMethod().getAccount(this.getName());
|
||||
return BigDecimal.valueOf(account.balance());
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
final EconomyLayer layer = EconomyLayers.getSelectedLayer();
|
||||
if (layer != null && (layer.hasAccount(getBase()) || layer.createPlayerAccount(getBase()))) {
|
||||
return layer.getBalance(getBase());
|
||||
}
|
||||
return super.getMoney();
|
||||
}
|
||||
@@ -492,31 +536,22 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
ess.getServer().getPluginManager().callEvent(updateEvent);
|
||||
final BigDecimal newBalance = updateEvent.getNewBalance();
|
||||
|
||||
if (Methods.hasMethod()) {
|
||||
try {
|
||||
final Method method = Methods.getMethod();
|
||||
if (!method.hasAccount(this.getName())) {
|
||||
throw new Exception();
|
||||
}
|
||||
final Method.MethodAccount account = Methods.getMethod().getAccount(this.getName());
|
||||
account.set(newBalance.doubleValue());
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
final EconomyLayer layer = EconomyLayers.getSelectedLayer();
|
||||
if (layer != null && (layer.hasAccount(getBase()) || layer.createPlayerAccount(getBase()))) {
|
||||
layer.set(getBase(), newBalance);
|
||||
}
|
||||
super.setMoney(newBalance, true);
|
||||
Trade.log("Update", "Set", "API", getName(), new Trade(newBalance, ess), null, null, null, ess);
|
||||
Trade.log("Update", "Set", "API", getName(), new Trade(newBalance, ess), null, null, null, newBalance, ess);
|
||||
}
|
||||
|
||||
public void updateMoneyCache(final BigDecimal value) {
|
||||
if (ess.getSettings().isEcoDisabled()) {
|
||||
if (ess.getSettings().isEcoDisabled() || !EconomyLayers.isLayerSelected() || super.getMoney().equals(value)) {
|
||||
return;
|
||||
}
|
||||
if (Methods.hasMethod() && !super.getMoney().equals(value)) {
|
||||
try {
|
||||
super.setMoney(value, false);
|
||||
} catch (final MaxMoneyException ex) {
|
||||
// We don't want to throw any errors here, just updating a cache
|
||||
}
|
||||
try {
|
||||
super.setMoney(value, false);
|
||||
} catch (final MaxMoneyException ex) {
|
||||
// We don't want to throw any errors here, just updating a cache
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,26 +625,47 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
return hidden || !player.canSee(getBase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFormattedJailTime() {
|
||||
return DateUtil.formatDateDiff(getOnlineJailedTime() > 0 ? getOnlineJailExpireTime() : getJailTimeout());
|
||||
}
|
||||
|
||||
private long getOnlineJailExpireTime() {
|
||||
return ((getOnlineJailedTime() - getBase().getStatistic(PLAY_ONE_TICK)) * 50) + System.currentTimeMillis();
|
||||
}
|
||||
|
||||
//Returns true if status expired during this check
|
||||
public boolean checkJailTimeout(final long currentTime) {
|
||||
if (getJailTimeout() > 0 && getJailTimeout() < currentTime && isJailed()) {
|
||||
final JailStatusChangeEvent event = new JailStatusChangeEvent(this, null, false);
|
||||
ess.getServer().getPluginManager().callEvent(event);
|
||||
if (getJailTimeout() > 0) {
|
||||
|
||||
if (!event.isCancelled()) {
|
||||
setJailTimeout(0);
|
||||
setJailed(false);
|
||||
sendMessage(tl("haveBeenReleased"));
|
||||
setJail(null);
|
||||
if (ess.getSettings().isTeleportBackWhenFreedFromJail()) {
|
||||
final CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||
getAsyncTeleport().back(future);
|
||||
future.exceptionally(e -> {
|
||||
getAsyncTeleport().respawn(null, TeleportCause.PLUGIN, new CompletableFuture<>());
|
||||
return false;
|
||||
});
|
||||
if (getOnlineJailedTime() > 0) {
|
||||
if (getOnlineJailedTime() > getBase().getStatistic(PLAY_ONE_TICK)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (getJailTimeout() < currentTime && isJailed()) {
|
||||
final JailStatusChangeEvent event = new JailStatusChangeEvent(this, null, false);
|
||||
ess.getServer().getPluginManager().callEvent(event);
|
||||
|
||||
if (!event.isCancelled()) {
|
||||
setJailTimeout(0);
|
||||
setOnlineJailedTime(0);
|
||||
setJailed(false);
|
||||
sendMessage(tl("haveBeenReleased"));
|
||||
setJail(null);
|
||||
if (ess.getSettings().getTeleportWhenFreePolicy() == ISettings.TeleportWhenFreePolicy.BACK) {
|
||||
final CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||
getAsyncTeleport().back(future);
|
||||
future.exceptionally(e -> {
|
||||
getAsyncTeleport().respawn(null, TeleportCause.PLUGIN, new CompletableFuture<>());
|
||||
return false;
|
||||
});
|
||||
} else if (ess.getSettings().getTeleportWhenFreePolicy() == ISettings.TeleportWhenFreePolicy.SPAWN) {
|
||||
getAsyncTeleport().respawn(null, TeleportCause.PLUGIN, new CompletableFuture<>());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -640,7 +696,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
public void updateActivity(final boolean broadcast, final AfkStatusChangeEvent.Cause cause) {
|
||||
if (isAfk()) {
|
||||
setAfk(false, cause);
|
||||
if (broadcast && !isHidden()) {
|
||||
if (broadcast && !isHidden() && !isAfk()) {
|
||||
setDisplayNick();
|
||||
final String msg = tl("userIsNotAway", getDisplayName());
|
||||
final String selfmsg = tl("userIsNotAwaySelf", getDisplayName());
|
||||
@@ -668,6 +724,15 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
}
|
||||
}
|
||||
|
||||
public void updateActivityOnChat(final boolean broadcast) {
|
||||
if (ess.getSettings().cancelAfkOnChat()) {
|
||||
//Chat happens async, make sure we have a sync context
|
||||
ess.scheduleSyncDelayedTask(() -> {
|
||||
updateActivity(broadcast, AfkStatusChangeEvent.Cause.CHAT);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void checkActivity() {
|
||||
// Graceful time before the first afk check call.
|
||||
if (System.currentTimeMillis() - lastActivity <= 10000) {
|
||||
@@ -676,23 +741,23 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
|
||||
final long autoafkkick = ess.getSettings().getAutoAfkKick();
|
||||
if (autoafkkick > 0
|
||||
&& lastActivity > 0 && (lastActivity + (autoafkkick * 1000)) < System.currentTimeMillis()
|
||||
&& !isAuthorized("essentials.kick.exempt")
|
||||
&& !isAuthorized("essentials.afk.kickexempt")) {
|
||||
&& lastActivity > 0 && (lastActivity + (autoafkkick * 1000)) < System.currentTimeMillis()
|
||||
&& !isAuthorized("essentials.kick.exempt")
|
||||
&& !isAuthorized("essentials.afk.kickexempt")) {
|
||||
final String kickReason = tl("autoAfkKickReason", autoafkkick / 60.0);
|
||||
lastActivity = 0;
|
||||
this.getBase().kickPlayer(kickReason);
|
||||
|
||||
for (final User user : ess.getOnlineUsers()) {
|
||||
if (user.isAuthorized("essentials.kick.notify")) {
|
||||
user.sendMessage(tl("playerKicked", Console.NAME, getName(), kickReason));
|
||||
user.sendMessage(tl("playerKicked", Console.DISPLAY_NAME, getName(), kickReason));
|
||||
}
|
||||
}
|
||||
}
|
||||
final long autoafk = ess.getSettings().getAutoAfk();
|
||||
if (!isAfk() && autoafk > 0 && lastActivity + autoafk * 1000 < System.currentTimeMillis() && isAuthorized("essentials.afk.auto")) {
|
||||
setAfk(true, AfkStatusChangeEvent.Cause.ACTIVITY);
|
||||
if (!isHidden()) {
|
||||
if (isAfk() && !isHidden()) {
|
||||
setDisplayNick();
|
||||
final String msg = tl("userIsAway", getDisplayName());
|
||||
final String selfmsg = tl("userIsAwaySelf", getDisplayName());
|
||||
@@ -831,6 +896,9 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
if (isAuthorized("essentials.vanish.effect")) {
|
||||
this.getBase().addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 1, false));
|
||||
}
|
||||
if (ess.getSettings().sleepIgnoresVanishedPlayers()) {
|
||||
getBase().setSleepingIgnored(true);
|
||||
}
|
||||
} else {
|
||||
for (final Player p : ess.getOnlinePlayers()) {
|
||||
p.showPlayer(getBase());
|
||||
@@ -840,6 +908,9 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
if (isAuthorized("essentials.vanish.effect")) {
|
||||
this.getBase().removePotionEffect(PotionEffectType.INVISIBILITY);
|
||||
}
|
||||
if (ess.getSettings().sleepIgnoresVanishedPlayers() && !isAuthorized("essentials.sleepingignored")) {
|
||||
getBase().setSleepingIgnored(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -917,6 +988,11 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
return this.getBase().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID() {
|
||||
return getBase().getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReachable() {
|
||||
return getBase().isOnline();
|
||||
@@ -984,12 +1060,28 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMail(MailSender sender, String message) {
|
||||
sendMail(sender, message, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMail(MailSender sender, String message, long expireAt) {
|
||||
ess.getMail().sendMail(this, sender, message, expireAt);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void addMail(String mail) {
|
||||
ess.getMail().sendLegacyMail(this, mail);
|
||||
}
|
||||
|
||||
public void notifyOfMail() {
|
||||
final List<String> mails = getMails();
|
||||
if (mails != null && !mails.isEmpty()) {
|
||||
final int unread = getUnreadMailAmount();
|
||||
if (unread != 0) {
|
||||
final int notifyPlayerOfMailCooldown = ess.getSettings().getNotifyPlayerOfMailCooldown() * 1000;
|
||||
if (System.currentTimeMillis() - lastNotifiedAboutMailsMs >= notifyPlayerOfMailCooldown) {
|
||||
sendMessage(tl("youHaveNewMail", mails.size()));
|
||||
sendMessage(tl("youHaveNewMail", unread));
|
||||
lastNotifiedAboutMailsMs = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
@@ -1011,6 +1103,19 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
this.lastHomeConfirmationTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public List<String> getSignCopy() {
|
||||
return signCopy;
|
||||
}
|
||||
|
||||
public boolean isBaltopExempt() {
|
||||
if (getBase().isOnline()) {
|
||||
final boolean exempt = isAuthorized("essentials.balancetop.exclude");
|
||||
setBaltopExemptCache(exempt);
|
||||
return exempt;
|
||||
}
|
||||
return isBaltopExcludeCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block getTargetBlock(int maxDistance) {
|
||||
final Block block;
|
||||
@@ -1019,4 +1124,14 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToggleShout(boolean toggleShout) {
|
||||
this.toggleShout = toggleShout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToggleShout() {
|
||||
return toggleShout;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,761 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.config.ConfigurateUtil;
|
||||
import com.earth2me.essentials.config.EssentialsUserConfiguration;
|
||||
import com.earth2me.essentials.config.entities.CommandCooldown;
|
||||
import com.earth2me.essentials.config.entities.LazyLocation;
|
||||
import com.earth2me.essentials.config.holders.UserConfigHolder;
|
||||
import com.earth2me.essentials.utils.NumberUtil;
|
||||
import com.earth2me.essentials.utils.StringUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.MaxMoneyException;
|
||||
import net.essentialsx.api.v2.services.mail.MailMessage;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.earth2me.essentials.I18n.tl;
|
||||
|
||||
public abstract class UserData extends PlayerExtension implements IConf {
|
||||
protected final transient IEssentials ess;
|
||||
private final EssentialsUserConfiguration config;
|
||||
private UserConfigHolder holder;
|
||||
private BigDecimal money;
|
||||
|
||||
protected UserData(final Player base, final IEssentials ess) {
|
||||
super(base);
|
||||
this.ess = ess;
|
||||
final File folder = new File(ess.getDataFolder(), "userdata");
|
||||
if (!folder.exists()) {
|
||||
folder.mkdirs();
|
||||
}
|
||||
|
||||
String filename;
|
||||
try {
|
||||
filename = base.getUniqueId().toString();
|
||||
} catch (final Throwable ex) {
|
||||
ess.getLogger().warning("Falling back to old username system for " + base.getName());
|
||||
filename = base.getName();
|
||||
}
|
||||
|
||||
config = new EssentialsUserConfiguration(base.getName(), base.getUniqueId(), new File(folder, filename + ".yml"));
|
||||
reloadConfig();
|
||||
|
||||
if (config.getUsername() == null) {
|
||||
config.setUsername(getLastAccountName());
|
||||
}
|
||||
}
|
||||
|
||||
public final void reset() {
|
||||
config.blockingSave();
|
||||
config.getFile().delete();
|
||||
if (config.getUsername() != null) {
|
||||
ess.getUserMap().removeUser(config.getUsername());
|
||||
if (isNPC()) {
|
||||
final String uuid = UUID.nameUUIDFromBytes(("NPC:" + StringUtil.safeString(config.getUsername())).getBytes(Charsets.UTF_8)).toString();
|
||||
ess.getUserMap().removeUserUUID(uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void cleanup() {
|
||||
config.blockingSave();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void reloadConfig() {
|
||||
config.load();
|
||||
try {
|
||||
holder = config.getRootNode().get(UserConfigHolder.class);
|
||||
} catch (SerializationException e) {
|
||||
ess.getLogger().log(Level.SEVERE, "Error while reading user config: " + e.getMessage(), e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
config.setSaveHook(() -> {
|
||||
try {
|
||||
config.getRootNode().set(UserConfigHolder.class, holder);
|
||||
} catch (SerializationException e) {
|
||||
ess.getLogger().log(Level.SEVERE, "Error while saving user config: " + e.getMessage(), e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
money = _getMoney();
|
||||
}
|
||||
|
||||
private BigDecimal _getMoney() {
|
||||
BigDecimal result = ess.getSettings().getStartingBalance();
|
||||
final BigDecimal maxMoney = ess.getSettings().getMaxMoney();
|
||||
final BigDecimal minMoney = ess.getSettings().getMinMoney();
|
||||
|
||||
// NPC banks are not actual player banks, as such they do not have player starting balance.
|
||||
if (isNPC()) {
|
||||
result = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
if (holder.money() != null) {
|
||||
result = holder.money();
|
||||
}
|
||||
if (result.compareTo(maxMoney) > 0) {
|
||||
result = maxMoney;
|
||||
}
|
||||
if (result.compareTo(minMoney) < 0) {
|
||||
result = minMoney;
|
||||
}
|
||||
holder.money(result);
|
||||
|
||||
return holder.money();
|
||||
}
|
||||
|
||||
public BigDecimal getMoney() {
|
||||
return money;
|
||||
}
|
||||
|
||||
public void setMoney(final BigDecimal value, final boolean throwError) throws MaxMoneyException {
|
||||
final BigDecimal maxMoney = ess.getSettings().getMaxMoney();
|
||||
final BigDecimal minMoney = ess.getSettings().getMinMoney();
|
||||
if (value.compareTo(maxMoney) > 0) {
|
||||
if (throwError) {
|
||||
throw new MaxMoneyException();
|
||||
}
|
||||
money = maxMoney;
|
||||
} else {
|
||||
money = value;
|
||||
}
|
||||
if (money.compareTo(minMoney) < 0) {
|
||||
money = minMoney;
|
||||
}
|
||||
holder.money(money);
|
||||
stopTransaction();
|
||||
}
|
||||
|
||||
private String getHomeName(String search) {
|
||||
if (NumberUtil.isInt(search)) {
|
||||
try {
|
||||
search = getHomes().get(Integer.parseInt(search) - 1);
|
||||
} catch (final NumberFormatException | IndexOutOfBoundsException ignored) {
|
||||
}
|
||||
}
|
||||
return search;
|
||||
}
|
||||
|
||||
public Location getHome(final String name) {
|
||||
final String search = getHomeName(name);
|
||||
final LazyLocation loc = holder.homes().get(search);
|
||||
return loc != null ? loc.location() : null;
|
||||
}
|
||||
|
||||
public boolean hasValidHomes() {
|
||||
for (final LazyLocation loc : holder.homes().values()) {
|
||||
if (loc != null && loc.location() != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Location getHome(final Location world) {
|
||||
if (getHomes().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
for (final String home : getHomes()) {
|
||||
final Location loc = holder.homes().get(home).location();
|
||||
if (loc != null && world.getWorld() == loc.getWorld()) {
|
||||
return loc;
|
||||
}
|
||||
|
||||
}
|
||||
return holder.homes().get(getHomes().get(0)).location();
|
||||
}
|
||||
|
||||
public List<String> getHomes() {
|
||||
return new ArrayList<>(holder.homes().keySet());
|
||||
}
|
||||
|
||||
public void setHome(String name, final Location loc) {
|
||||
//Invalid names will corrupt the yaml
|
||||
name = StringUtil.safeString(name);
|
||||
holder.homes().put(name, LazyLocation.fromLocation(loc));
|
||||
config.save();
|
||||
}
|
||||
|
||||
public void delHome(final String name) throws Exception {
|
||||
String search = getHomeName(name);
|
||||
if (!holder.homes().containsKey(search)) {
|
||||
search = StringUtil.safeString(search);
|
||||
}
|
||||
if (holder.homes().containsKey(search)) {
|
||||
holder.homes().remove(search);
|
||||
config.save();
|
||||
} else {
|
||||
throw new Exception(tl("invalidHome", search));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasHome() {
|
||||
return !holder.homes().isEmpty();
|
||||
}
|
||||
|
||||
public boolean hasHome(final String name) {
|
||||
return holder.homes().containsKey(name);
|
||||
}
|
||||
|
||||
public String getNickname() {
|
||||
return holder.nickname();
|
||||
}
|
||||
|
||||
public void setNickname(final String nick) {
|
||||
holder.nickname(nick);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public Set<Material> getUnlimited() {
|
||||
return holder.unlimited();
|
||||
}
|
||||
|
||||
public boolean hasUnlimited(final ItemStack stack) {
|
||||
return holder.unlimited().contains(stack.getType());
|
||||
}
|
||||
|
||||
public void setUnlimited(final ItemStack stack, final boolean state) {
|
||||
final boolean wasUpdated;
|
||||
if (state) {
|
||||
wasUpdated = holder.unlimited().add(stack.getType());
|
||||
} else {
|
||||
wasUpdated = holder.unlimited().remove(stack.getType());
|
||||
}
|
||||
|
||||
if (wasUpdated) {
|
||||
config.save();
|
||||
}
|
||||
}
|
||||
|
||||
public void clearAllPowertools() {
|
||||
holder.powertools().clear();
|
||||
config.save();
|
||||
}
|
||||
|
||||
public List<String> getPowertool(final ItemStack stack) {
|
||||
return getPowertool(stack.getType());
|
||||
}
|
||||
|
||||
public List<String> getPowertool(final Material material) {
|
||||
return holder.powertools().get(material.name().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
public void setPowertool(final ItemStack stack, final List<String> commandList) {
|
||||
if (commandList == null || commandList.isEmpty()) {
|
||||
holder.powertools().remove(stack.getType().name().toLowerCase(Locale.ENGLISH));
|
||||
} else {
|
||||
holder.powertools().put(stack.getType().name().toLowerCase(Locale.ENGLISH), commandList);
|
||||
}
|
||||
config.save();
|
||||
}
|
||||
|
||||
public boolean hasPowerTools() {
|
||||
return !holder.powertools().isEmpty();
|
||||
}
|
||||
|
||||
public Location getLastLocation() {
|
||||
final LazyLocation lastLocation = holder.lastLocation();
|
||||
return lastLocation != null ? lastLocation.location() : null;
|
||||
}
|
||||
|
||||
public void setLastLocation(final Location loc) {
|
||||
if (loc == null || loc.getWorld() == null) {
|
||||
return;
|
||||
}
|
||||
holder.lastLocation(loc);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public Location getLogoutLocation() {
|
||||
final LazyLocation logoutLocation = holder.logoutLocation();
|
||||
return logoutLocation != null ? logoutLocation.location() : null;
|
||||
}
|
||||
|
||||
public void setLogoutLocation(final Location loc) {
|
||||
if (loc == null || loc.getWorld() == null) {
|
||||
return;
|
||||
}
|
||||
holder.logoutLocation(loc);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public long getLastTeleportTimestamp() {
|
||||
return holder.timestamps().lastTeleport();
|
||||
}
|
||||
|
||||
public void setLastTeleportTimestamp(final long time) {
|
||||
holder.timestamps().lastTeleport(time);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public long getLastHealTimestamp() {
|
||||
return holder.timestamps().lastHeal();
|
||||
}
|
||||
|
||||
public void setLastHealTimestamp(final long time) {
|
||||
holder.timestamps().lastHeal(time);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public String getJail() {
|
||||
return holder.jail();
|
||||
}
|
||||
|
||||
public void setJail(final String jail) {
|
||||
holder.jail(jail);
|
||||
config.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Mails are no longer just strings, this method is therefore misleading.
|
||||
*/
|
||||
@Deprecated
|
||||
public List<String> getMails() {
|
||||
final List<String> list = new ArrayList<>();
|
||||
if (getMailAmount() != 0) {
|
||||
for (MailMessage mail : getMailMessages()) {
|
||||
// I hate this code btw
|
||||
list.add(mail.isLegacy() ? mail.getMessage() : ChatColor.GOLD + "[" + ChatColor.RESET + mail.getSenderUsername() + ChatColor.GOLD + "] " + ChatColor.RESET + mail.getMessage());
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method does not support the new mail system and will fail at runtime.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setMails(List<String> mails) {
|
||||
throw new UnsupportedOperationException("UserData#setMails(List<String>) is deprecated and can no longer be used. Please tell the plugin author to update this!");
|
||||
}
|
||||
|
||||
public int getMailAmount() {
|
||||
return holder.mail() == null ? 0 : holder.mail().size();
|
||||
}
|
||||
|
||||
public int getUnreadMailAmount() {
|
||||
if (holder.mail() == null || holder.mail().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unread = 0;
|
||||
for (MailMessage element : holder.mail()) {
|
||||
if (!element.isRead()) {
|
||||
unread++;
|
||||
}
|
||||
}
|
||||
return unread;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method does not support the new mail system and should not be used.
|
||||
*/
|
||||
@Deprecated
|
||||
abstract void addMail(final String mail);
|
||||
|
||||
public ArrayList<MailMessage> getMailMessages() {
|
||||
return new ArrayList<>(holder.mail());
|
||||
}
|
||||
|
||||
public void setMailList(ArrayList<MailMessage> messages) {
|
||||
holder.mail(messages);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public boolean isTeleportEnabled() {
|
||||
return holder.teleportEnabled();
|
||||
}
|
||||
|
||||
public void setTeleportEnabled(final boolean set) {
|
||||
holder.teleportEnabled(set);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public boolean isAutoTeleportEnabled() {
|
||||
return holder.teleportAuto();
|
||||
}
|
||||
|
||||
public void setAutoTeleportEnabled(final boolean set) {
|
||||
holder.teleportAuto(set);
|
||||
config.save();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setIgnoredPlayers(final List<String> players) {
|
||||
final List<UUID> uuids = new ArrayList<>();
|
||||
for (final String player : players) {
|
||||
final User user = ess.getOfflineUser(player);
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
uuids.add(user.getBase().getUniqueId());
|
||||
}
|
||||
setIgnoredPlayerUUIDs(uuids);
|
||||
}
|
||||
|
||||
public void setIgnoredPlayerUUIDs(final List<UUID> players) {
|
||||
holder.ignore(players);
|
||||
config.save();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean isIgnoredPlayer(final String userName) {
|
||||
final IUser user = ess.getUser(userName);
|
||||
if (user == null || !user.getBase().isOnline()) {
|
||||
return false;
|
||||
}
|
||||
return isIgnoredPlayer(user);
|
||||
}
|
||||
|
||||
public boolean isIgnoredPlayer(final IUser user) {
|
||||
return holder.ignore().contains(user.getBase().getUniqueId()) && !user.isIgnoreExempt();
|
||||
}
|
||||
|
||||
public List<UUID> _getIgnoredPlayers() {
|
||||
return holder.ignore();
|
||||
}
|
||||
|
||||
public void setIgnoredPlayer(final IUser user, final boolean set) {
|
||||
final UUID uuid = user.getBase().getUniqueId();
|
||||
if (set) {
|
||||
if (!holder.ignore().contains(uuid)) {
|
||||
holder.ignore().add(uuid);
|
||||
}
|
||||
} else {
|
||||
holder.ignore().remove(uuid);
|
||||
}
|
||||
config.save();
|
||||
}
|
||||
|
||||
public boolean isGodModeEnabled() {
|
||||
return holder.godMode();
|
||||
}
|
||||
|
||||
public void setGodModeEnabled(final boolean set) {
|
||||
holder.godMode(set);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public boolean getMuted() {
|
||||
return holder.muted();
|
||||
}
|
||||
|
||||
public boolean isMuted() {
|
||||
return getMuted();
|
||||
}
|
||||
|
||||
public void setMuted(final boolean set) {
|
||||
holder.muted(set);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public String getMuteReason() {
|
||||
return holder.muteReason();
|
||||
}
|
||||
|
||||
public void setMuteReason(final String reason) {
|
||||
holder.muteReason(reason);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public boolean hasMuteReason() {
|
||||
return holder.muteReason() != null;
|
||||
}
|
||||
|
||||
public long getMuteTimeout() {
|
||||
return holder.timestamps().mute();
|
||||
}
|
||||
|
||||
public void setMuteTimeout(final long time) {
|
||||
holder.timestamps().mute(time);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public boolean isJailed() {
|
||||
return holder.jailed();
|
||||
}
|
||||
|
||||
public void setJailed(final boolean set) {
|
||||
holder.jailed(set);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public boolean toggleJailed() {
|
||||
final boolean ret = !isJailed();
|
||||
setJailed(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public long getJailTimeout() {
|
||||
return holder.timestamps().jail();
|
||||
}
|
||||
|
||||
public void setJailTimeout(final long time) {
|
||||
holder.timestamps().jail(time);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public long getOnlineJailedTime() {
|
||||
return holder.timestamps().onlineJail();
|
||||
}
|
||||
|
||||
public void setOnlineJailedTime(long onlineJailed) {
|
||||
holder.timestamps().onlineJail(onlineJailed);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public long getLastLogin() {
|
||||
return holder.timestamps().login();
|
||||
}
|
||||
|
||||
public void setLastLogin(final long time) {
|
||||
holder.timestamps().login(time);
|
||||
if (base.getAddress() != null && base.getAddress().getAddress() != null) {
|
||||
holder.ipAddress(base.getAddress().getAddress().getHostAddress());
|
||||
}
|
||||
config.save();
|
||||
}
|
||||
|
||||
public long getLastLogout() {
|
||||
return holder.timestamps().logout();
|
||||
}
|
||||
|
||||
public void setLastLogout(final long time) {
|
||||
holder.timestamps().logout(time);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public String getLastLoginAddress() {
|
||||
return holder.ipAddress();
|
||||
}
|
||||
|
||||
public boolean isAfk() {
|
||||
return holder.afk();
|
||||
}
|
||||
|
||||
public void _setAfk(final boolean set) {
|
||||
holder.afk(set);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public String getGeoLocation() {
|
||||
return holder.geolocation();
|
||||
}
|
||||
|
||||
public void setGeoLocation(final String geolocation) {
|
||||
holder.geolocation(geolocation);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public boolean isSocialSpyEnabled() {
|
||||
return holder.socialSpy();
|
||||
}
|
||||
|
||||
public void setSocialSpyEnabled(final boolean status) {
|
||||
holder.socialSpy(status);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public boolean isNPC() {
|
||||
return holder.npc();
|
||||
}
|
||||
|
||||
public void setNPC(final boolean set) {
|
||||
holder.npc(set);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public String getLastAccountName() {
|
||||
return holder.lastAccountName();
|
||||
}
|
||||
|
||||
public void setLastAccountName(final String lastAccountName) {
|
||||
holder.lastAccountName(lastAccountName);
|
||||
config.save();
|
||||
ess.getUserMap().trackUUID(getConfigUUID(), lastAccountName, true);
|
||||
}
|
||||
|
||||
public boolean arePowerToolsEnabled() {
|
||||
return holder.powerToolsEnabled();
|
||||
}
|
||||
|
||||
public void setPowerToolsEnabled(final boolean set) {
|
||||
holder.powerToolsEnabled(set);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public boolean togglePowerToolsEnabled() {
|
||||
final boolean ret = !arePowerToolsEnabled();
|
||||
setPowerToolsEnabled(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public long getKitTimestamp(String name) {
|
||||
name = name.replace('.', '_').replace('/', '_').toLowerCase(Locale.ENGLISH);
|
||||
if (holder.timestamps().kits() != null && holder.timestamps().kits().containsKey(name)) {
|
||||
return holder.timestamps().kits().get(name);
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public void setKitTimestamp(String name, final long time) {
|
||||
name = name.replace('.', '_').replace('/', '_').toLowerCase(Locale.ENGLISH);
|
||||
holder.timestamps().kits().put(name, time);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public List<CommandCooldown> getCooldownsList() {
|
||||
return holder.timestamps().commandCooldowns();
|
||||
}
|
||||
|
||||
public Map<Pattern, Long> getCommandCooldowns() {
|
||||
final Map<Pattern, Long> map = new HashMap<>();
|
||||
for (final CommandCooldown c : getCooldownsList()) {
|
||||
if (c == null || c.isIncomplete()) {
|
||||
// stupid solution to stupid problem
|
||||
continue;
|
||||
}
|
||||
map.put(c.pattern(), c.value());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public Date getCommandCooldownExpiry(final String label) {
|
||||
for (CommandCooldown cooldown : getCooldownsList()) {
|
||||
if (cooldown == null || cooldown.isIncomplete()) {
|
||||
// stupid solution to stupid problem
|
||||
continue;
|
||||
}
|
||||
if (cooldown.pattern().matcher(label).matches()) {
|
||||
return new Date(cooldown.value());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addCommandCooldown(final Pattern pattern, final Date expiresAt, final boolean save) {
|
||||
final CommandCooldown cooldown = new CommandCooldown();
|
||||
cooldown.pattern(pattern);
|
||||
cooldown.value(expiresAt.getTime());
|
||||
if (cooldown.isIncomplete()) {
|
||||
return;
|
||||
}
|
||||
holder.timestamps().commandCooldowns().add(cooldown);
|
||||
if (save) {
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean clearCommandCooldown(final Pattern pattern) {
|
||||
if (holder.timestamps().commandCooldowns().isEmpty()) {
|
||||
return false; // false for no modification
|
||||
}
|
||||
|
||||
if (getCooldownsList().removeIf(cooldown -> cooldown != null && !cooldown.isIncomplete() && cooldown.pattern().equals(pattern))) {
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isAcceptingPay() {
|
||||
return holder.acceptingPay();
|
||||
}
|
||||
|
||||
public void setAcceptingPay(final boolean acceptingPay) {
|
||||
holder.acceptingPay(acceptingPay);
|
||||
save();
|
||||
}
|
||||
|
||||
public boolean isPromptingPayConfirm() {
|
||||
return holder.confirmPay() != null ? holder.confirmPay() : ess.getSettings().isConfirmCommandEnabledByDefault("pay");
|
||||
}
|
||||
|
||||
public void setPromptingPayConfirm(final boolean prompt) {
|
||||
holder.confirmPay(prompt);
|
||||
save();
|
||||
}
|
||||
|
||||
public boolean isPromptingClearConfirm() {
|
||||
return holder.confirmClear() != null ? holder.confirmClear() : ess.getSettings().isConfirmCommandEnabledByDefault("clearinventory");
|
||||
}
|
||||
|
||||
public void setPromptingClearConfirm(final boolean prompt) {
|
||||
holder.confirmClear(prompt);
|
||||
save();
|
||||
}
|
||||
|
||||
public boolean isLastMessageReplyRecipient() {
|
||||
return holder.lastMessageReplyRecipient() != null ? holder.lastMessageReplyRecipient() : ess.getSettings().isLastMessageReplyRecipient();
|
||||
}
|
||||
|
||||
public void setLastMessageReplyRecipient(final boolean enabled) {
|
||||
holder.lastMessageReplyRecipient(enabled);
|
||||
save();
|
||||
}
|
||||
|
||||
public boolean isBaltopExcludeCache() {
|
||||
return holder.baltopExempt();
|
||||
}
|
||||
|
||||
public void setBaltopExemptCache(boolean baltopExempt) {
|
||||
holder.baltopExempt(baltopExempt);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public UUID getConfigUUID() {
|
||||
return config.getUuid();
|
||||
}
|
||||
|
||||
public void save() {
|
||||
config.save();
|
||||
}
|
||||
|
||||
public void startTransaction() {
|
||||
config.startTransaction();
|
||||
}
|
||||
|
||||
public void stopTransaction() {
|
||||
config.stopTransaction();
|
||||
}
|
||||
|
||||
public void setConfigProperty(String node, Object object) {
|
||||
setConfigPropertyRaw("info." + node, object);
|
||||
}
|
||||
|
||||
public void setConfigPropertyRaw(String node, Object object) {
|
||||
config.setRaw(node, object);
|
||||
config.save();
|
||||
}
|
||||
|
||||
public Set<String> getConfigKeys() {
|
||||
return ConfigurateUtil.getKeys(config.getSection("info"));
|
||||
}
|
||||
|
||||
public Map<String, Object> getConfigMap() {
|
||||
return ConfigurateUtil.getRawMap(config.getSection("info"));
|
||||
}
|
||||
|
||||
public Map<String, Object> getConfigMap(final String node) {
|
||||
return ConfigurateUtil.getRawMap(config.getSection("info." + node));
|
||||
}
|
||||
}
|
||||
+75
-5
@@ -1,5 +1,6 @@
|
||||
package com.earth2me.essentials;
|
||||
|
||||
import com.earth2me.essentials.api.UserDoesNotExistException;
|
||||
import com.earth2me.essentials.utils.StringUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.cache.Cache;
|
||||
@@ -8,11 +9,13 @@ import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.MaxMoneyException;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -21,6 +24,7 @@ import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class UserMap extends CacheLoader<String, User> implements IConf {
|
||||
@@ -34,6 +38,8 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
|
||||
private final transient Cache<String, User> users;
|
||||
private final Pattern validUserPattern = Pattern.compile("^[a-zA-Z0-9_]{2,16}$");
|
||||
|
||||
private static final String WARN_UUID_NOT_REPLACE = "Found UUID {0} for player {1}, but player already has a UUID ({2}). Not replacing UUID in usermap.";
|
||||
|
||||
public UserMap(final IEssentials ess) {
|
||||
super();
|
||||
this.ess = ess;
|
||||
@@ -86,13 +92,21 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
|
||||
}
|
||||
|
||||
public User getUser(final String name) {
|
||||
final String sanitizedName = StringUtil.safeString(name);
|
||||
try {
|
||||
final String sanitizedName = StringUtil.safeString(name);
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().warning("Looking up username " + name + " (" + sanitizedName + ") ...");
|
||||
}
|
||||
|
||||
if (names.containsKey(sanitizedName)) {
|
||||
final UUID uuid = names.get(sanitizedName);
|
||||
return getUser(uuid);
|
||||
}
|
||||
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().warning(name + "(" + sanitizedName + ") has no known usermap entry");
|
||||
}
|
||||
|
||||
final File userFile = getUserFileFromString(sanitizedName);
|
||||
if (userFile.exists()) {
|
||||
ess.getLogger().info("Importing user " + name + " to usermap.");
|
||||
@@ -102,6 +116,9 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
|
||||
}
|
||||
return null;
|
||||
} catch (final UncheckedExecutionException ex) {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().log(Level.WARNING, ex, () -> String.format("Exception while getting user for %s (%s)", name, sanitizedName));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -114,6 +131,9 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
|
||||
return legacyCacheGet(uuid);
|
||||
}
|
||||
} catch (final ExecutionException | UncheckedExecutionException ex) {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().log(Level.WARNING, ex, () -> "Exception while getting user for " + uuid);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -126,21 +146,23 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
|
||||
if (!names.containsKey(keyName)) {
|
||||
names.put(keyName, uuid);
|
||||
uuidMap.writeUUIDMap();
|
||||
} else if (!names.get(keyName).equals(uuid)) {
|
||||
} else if (!isUUIDMatch(uuid, keyName)) {
|
||||
if (replace) {
|
||||
ess.getLogger().info("Found new UUID for " + name + ". Replacing " + names.get(keyName).toString() + " with " + uuid.toString());
|
||||
names.put(keyName, uuid);
|
||||
uuidMap.writeUUIDMap();
|
||||
} else {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info("Found old UUID for " + name + " (" + uuid.toString() + "). Not adding to usermap.");
|
||||
}
|
||||
ess.getLogger().log(Level.INFO, MessageFormat.format(WARN_UUID_NOT_REPLACE, uuid.toString(), name, names.get(keyName).toString()), new RuntimeException());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isUUIDMatch(final UUID uuid, final String name) {
|
||||
return names.containsKey(name) && names.get(name).equals(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User load(final String stringUUID) throws Exception {
|
||||
final UUID uuid = UUID.fromString(stringUUID);
|
||||
@@ -164,6 +186,50 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
|
||||
throw new Exception("User not found!");
|
||||
}
|
||||
|
||||
public User load(final org.bukkit.OfflinePlayer player) throws UserDoesNotExistException {
|
||||
if (player == null) {
|
||||
throw new IllegalArgumentException("Player cannot be null!");
|
||||
}
|
||||
|
||||
if (player instanceof Player) {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info("Loading online OfflinePlayer into user map...");
|
||||
}
|
||||
final User user = new User((Player) player, ess);
|
||||
trackUUID(player.getUniqueId(), player.getName(), true);
|
||||
return user;
|
||||
}
|
||||
|
||||
final File userFile = getUserFileFromID(player.getUniqueId());
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info("Loading OfflinePlayer into user map. Has data: " + userFile.exists() + " for " + player);
|
||||
}
|
||||
|
||||
final OfflinePlayer essPlayer = new OfflinePlayer(player.getUniqueId(), ess.getServer());
|
||||
final User user = new User(essPlayer, ess);
|
||||
if (userFile.exists()) {
|
||||
essPlayer.setName(user.getLastAccountName());
|
||||
} else {
|
||||
if (ess.getSettings().isDebug()) {
|
||||
ess.getLogger().info("OfflinePlayer usermap load saving user data for " + player);
|
||||
}
|
||||
|
||||
// this code makes me sad
|
||||
user.startTransaction();
|
||||
try {
|
||||
user.setMoney(ess.getSettings().getStartingBalance());
|
||||
} catch (MaxMoneyException e) {
|
||||
// Shouldn't happen as it would be an illegal configuration state
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
user.setLastAccountName(user.getName());
|
||||
user.stopTransaction();
|
||||
}
|
||||
|
||||
trackUUID(player.getUniqueId(), user.getName(), false);
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
getUUIDMap().forceWriteUUIDMap();
|
||||
@@ -188,6 +254,10 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
|
||||
names.remove(StringUtil.safeString(name));
|
||||
}
|
||||
|
||||
public void removeUserUUID(final String uuid) {
|
||||
users.invalidate(uuid);
|
||||
}
|
||||
|
||||
public Set<UUID> getAllUniqueUsers() {
|
||||
return Collections.unmodifiableSet(keys);
|
||||
}
|
||||
Loaded 100 of 667 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user