Compare commits

...
129 Commits
Author SHA1 Message Date
Josh Roy 6d2a8ffba4 Release 2.20.1 2023-08-05 18:59:32 +01:00
Josh Roy b781c1e924 Add /ess usermap cache sub-command
Allows to view the number of known UUIDs as
well as name to UUID pairs.
2023-08-05 16:48:23 +01:00
Josh Roy 19d6db0b4c Don't cache previously known offline names
This can lead to the potential that a UUID can
be mapped to the improper name. This logic should
be handled the join logic.
2023-08-05 16:48:23 +01:00
Josh Roy 02ced188c8 Always populate last known name into cache
In theory this should never be an issue but
somehow is?
2023-08-05 16:48:23 +01:00
Josh Roy 7f3b62a180 Remove extraneous manual user cache loading
The usermap will already do this on its own,
and we should really avoid doing this outside
the usermap to avoid unforeseen behavior changes.
2023-08-05 16:48:23 +01:00
Josh Roy 908b06570f Remove extraneous offline name update code
This exact code exists in ModernUserMap#getUser(String)
2023-08-05 16:48:23 +01:00
Josh Roy d7e5c10b51 Fix remaining offline visibility checks (#5466)
Purpur added a new self-referencing method that
we don't implement with our stub class. This will
prevent Player#canSee from being called for
offline players (it would be false anyway).
2023-08-05 11:44:40 -04:00
Josh Roy b2ae28b450 Fix discord module console relay not filtering all color codes (#5454) 2023-07-26 14:22:30 -04:00
Josh Roy e558e7365a Fix trade signs not working with currency suffix (#5441) 2023-07-25 21:16:50 +00:00
Josh Roy c32a0f975e Revert duel hand behavior of /book command 2023-07-25 17:10:20 -04:00
Josh Roy ae1f1583c2 Fix enchant not working with offhand 2023-07-25 17:10:20 -04:00
Flask Bot 58eea1724f New Crowdin updates (#5424) 2023-07-23 20:55:40 +00:00
Josh Roy 52c9ca8197 Fix inaccurate online player count for Discord leave message (#5440)
fixes #5256
2023-07-23 15:10:46 +01:00
Josh Roy f26e1b2e29 Fix invalid unlimited items preventing userdata to load
Invalid material names would previously return a null value
when deserializing. This raises an exception from within
Configurate because they use an EnumSet internally during
deserialization which doesn't support null elements.
2023-07-22 22:53:26 +01:00
Josh Roy f84a311c2b Ensure user data deserialization exceptions include file name
More than just a SerializationException can happen I guess
2023-07-22 22:53:26 +01:00
MDandJosh Roy 60129594a6 Rename OfflinePlayer to OfflinePlayerStub (#5417)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2023-07-04 09:45:58 -04:00
Flask BotandJosh Roy 563d3fab4e New Crowdin updates (#5370)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2023-07-04 09:36:32 -04:00
1022f7a3ab Add KitPreExpandItemsEvent (#5407)
Co-authored-by: YanisBft <yanis.briffaut@gmail.com>
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2023-07-01 17:51:58 -04:00
Josh Roy d57094c0bc Add link module to /ess dump 2023-07-01 17:45:07 -04:00
Josh Roy 863b9cffc5 Add backoff and skip for Discord console relay 2023-07-01 17:45:07 -04:00
Josh Roy 1921abd310 Shorten logger names for Discord module console relay 2023-07-01 17:45:07 -04:00
Josh Roy 803d800bdd Fix Discord module webhook closing incorrectly 2023-07-01 17:45:07 -04:00
Josh Roy 5276204cf2 Increase Discord module console relay message limit 2023-07-01 17:45:07 -04:00
Josh Roy 697128bcf2 Update Discord Module to JDA 5 2023-07-01 17:45:07 -04:00
Josh RoyandMD a1fa1e38f8 Don't do visibility checks for OfflinePlayers (#5375)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2023-07-01 16:41:56 -04:00
Flask Bot ed41790712 Update items.json for 1.20 2023-07-01 20:37:21 +01:00
Josh Roy 834ef4ea57 Update to Minecraft 1.20 2023-07-01 20:37:21 +01:00
Josh Roy 03ed9a5b41 Fix roles/groups not being removed instantly upon unlink 2023-06-18 21:57:27 +01:00
Josh Roy d67dd46cdc Clean up link policy code
Also error when new link policy types are added
so we remember to write out the behavior here
2023-06-18 21:57:27 +01:00
Josh Roy 694ed6e66f Use removeAccount return value for AccountLinkManager#unlinkAccount 2023-06-18 21:57:27 +01:00
Josh Roy 8a0526b1e5 Fix discord link data being rewritten when no data was changed 2023-06-18 21:57:27 +01:00
MD a116e8630d Update Gradle, build plugins and GitHub Actions (#5383) 2023-06-14 19:27:01 -04:00
Josh Roy 8b2c7d7ad1 Fix regression in #5378 (#5379) 2023-06-03 23:13:09 +01:00
Josh Roy 8d07c4bb0f Fix regression w/empty strings with KeywordReplacer (#5378) 2023-06-02 22:54:30 +00:00
Josh Roy fc3dabf8f5 Fix keywords in kit commands not working (#5377)
Don't process b64 item through keyword replacer
and don't replace spaces on command strings
2023-06-01 21:14:41 -04:00
Josh Roy cdd277da92 Fix config BigDecimal parsing returning null on error (#5373)
Also add some more exception logging for parse issues.
2023-05-31 19:46:19 -04:00
Charles DeLancey 0d322e2c6b Fix typo in Discord docs (#5371) 2023-05-30 07:46:09 -04:00
646b60a90b Add ability to get recipe of item in hand (#5346)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
Co-authored-by: pop4959 <pop4959@gmail.com>
2023-05-28 18:27:18 +00:00
Flask Bot 357cd6b246 New Crowdin updates (#5357) 2023-05-27 02:00:11 +00:00
Josh Roy a4fb02f3e6 Don't run AntiBuild checks on NPCs (#5365) 2023-05-26 21:54:46 -04:00
Josh Roy 2828901927 Fix variables in kits having underscores replaced with spaces (#5366) 2023-05-27 01:51:11 +00:00
Josh Roy 1e0f7cb984 Fix question and shout prefixes with toggle shout (#5367) 2023-05-26 21:48:10 -04:00
Josh Roy 52a4dd2c60 Fix NPE during first join for LuckPerms contexts (#5364) 2023-05-26 19:29:37 -04:00
Josh Roy 8323b47e40 Prepare for 2.20.1 dev builds (#5355) 2023-05-23 11:32:12 -04:00
Josh Roy 14cdde009c Release 2.20.0 (#5336) 2023-05-23 11:18:21 -04:00
Flask Bot 1883e6adbc New Crowdin updates (#5348) 2023-05-22 00:49:43 +00:00
Josh Roy 2f9659e7fc Fix NPE during reload when deleted warps directory (#5353) 2023-05-20 10:03:24 -07:00
Josh Roy 1a4f63915f Fix SignChangeEvent never actually being called (#5341)
Fixes #5340. Caused by a regression in #5304 which reverted the behaviour introduced in #5304.
2023-05-09 00:26:28 +01:00
Flask Bot dd3f4c2921 New Crowdin updates (#5334) 2023-05-07 04:57:44 +00:00
Josh Roy 7ebb6359e5 Fix offline player consumer returning null users (#5339) 2023-05-06 19:13:44 -04:00
Josh Roy 069ebfcd5b Fix NPE while syncing offline users for discord line module (#5338)
Only would happen for users who haven't joined
(or been loaded by different parts of the plugin)
since the last restart. This change first of all switches to a method to fetch users which will update the User base to the UUIDPlayer dummy base. Secondly, this change will not update the base of a User to a UUIDPlayer dummy unless the base is currently null (which would be the case in the condition described above).
2023-05-06 18:31:23 -04:00
pop4959 991bc61b0c Expire UserMap cache more aggressively and add cache debugging (#5331) 2023-05-05 18:44:22 -04:00
Flask Bot 8194d1f747 New Crowdin updates (#5303) 2023-05-05 06:40:58 +00:00
Josh RoyandMD ee7ea2ae39 Fire SignChangeEvent in /editsign (#5304)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2023-05-02 16:13:50 -04:00
Josh Roy 3d23916ad5 Add HomeModifyEvent for home create/delete/rename/set (#5216)
Implements #5213.
2023-05-02 20:48:28 +01:00
Sasha SorokinandJosh Roy e5b0c4c855 Add support for local and global chats in Discord (#4684)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2023-04-30 21:30:11 -04:00
Josh RoyandMD 84fd45bd09 Bump JDA 4 version (#5328)
Bumping this for 2.20 release as  JDA 5 still not out of beta

Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2023-04-29 18:14:36 +00:00
Josh Roy 01883a6b18 Truncate command and argument descriptions (#5314)
Fixes #5315.
2023-04-29 19:00:40 +01:00
Josh Roy fd49b70a69 Fix top command not sending messages (#5302)
my three year old refactors still haunt me
2023-04-13 06:22:47 +00:00
Josh Roy 3a737480ec Remove unneeded sanitization in webhook names (#5311)
Regression from 384f63bf92
2023-04-13 07:15:48 +01:00
diademiemiandJosh Roy 384f63bf92 Allow configuring Discord webhook name (#5159)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2023-04-10 00:27:36 +00:00
Joel OteroandJosh Roy 77dc87bb8e Add /bottom command (#5292)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2023-04-09 21:05:53 +00:00
MD c716fc8236 Bump runServer task to Paper 1.19.4 (#5269) 2023-04-06 00:15:15 +00:00
Flask Bot c52c1fea9d New Crowdin updates (#5244) 2023-04-04 21:49:43 -07:00
Josh Roy e7c56b32a4 Fix sulk sensors detecting vanished players (#5262) 2023-04-02 22:29:29 +00:00
Josh Roy 11e6d3ca7b Fix /mail sendall not working (#5263) 2023-04-02 22:12:04 +00:00
Josh Roy 75481925f7 Update display names before formatting chat messages (#5282) 2023-04-02 22:08:38 +00:00
Josh Roy ecb1850451 Add message for unknown last location for /tpo (#5290) 2023-04-02 22:04:36 +00:00
Josh Roy 0f4af9e735 Use strict comparison for potions in trade signs (#5260) 2023-04-02 21:45:46 +00:00
Josh RoyandMD bf14b88600 Bump to 1.19.4 (#5273)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2023-03-17 18:54:33 +00:00
Josh Roy 43d84de2b2 Move feature requests back to issues (#5251)
* Create request-a-feature.yml

* Update config.yml
2023-02-17 12:11:21 +00:00
25ad8ac9bd Add per-command command cooldown bypass permissions (#4759)
Adds the permission `essentials.commandcooldowns.bypass.<command name>` to bypass the cooldown for a specific command.

Closes #4747.

Co-authored-by: pop4959 <pop4959@gmail.com>
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2023-02-13 23:19:52 +00:00
17051eab73 Add separate events for local and global chat (#4683)
This commit adds two new events: GlobalChatEvent and LocalChatEvent,
which allow other plugin developers to know whether the message sent is
a global or local one and act accordingly. If either of those events is
cancelled, then the source event is cancelled too.

Since all chat-related events share the same structure, a new abstract
class ChatEvent is created with change made for LocalChatSpyEvent to use
it without breaking its API.

Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2023-02-13 23:15:15 +00:00
Flask Bot 4dc994df3c New Crowdin updates (#5051) 2023-02-05 04:58:49 -08:00
Warrior 996285c0e3 Fix doubles not working in console for /tppos (#5231)
Closes https://github.com/EssentialsX/Essentials/issues/5230
2023-01-22 16:32:47 -05:00
Josh Roy 312d1699a8 Use metadata for tnt from /nuke (#5222)
Fixes https://github.com/EssentialsX/Essentials/issues/5219
2023-01-12 10:51:13 -05:00
Josh Roy b3238605cc Fix inventory size for 1.8.8 servers (#5212) 2023-01-05 19:13:16 +00:00
Josh Roy b7a4bea52e Revert dual hand behavior from /hat (#5205)
Fixes https://github.com/EssentialsX/Essentials/issues/5202
2022-12-30 18:30:52 -05:00
Josh Roy ca71d93963 Fix discord permission issues with link module (#5197) 2022-12-27 21:07:47 +00:00
Josh Roy 0936fe80bd Discord Link Module 2022-12-26 01:24:17 +00:00
Josh Roy 520e8f991f Add DiscordService#getInviteUrl 2022-12-26 01:24:17 +00:00
Josh Roy 3131cadf65 Add UserMailEvent 2022-12-26 01:24:17 +00:00
Josh Roy bfae6c5c69 Add IPermissionsHandler#addToGroup & IPermissionsHandler#removeFromGroup 2022-12-26 01:24:17 +00:00
Josh Roy 52c500ee6d Add InteractionRole#getAsMention + InteractionRole#canInteract 2022-12-26 01:24:17 +00:00
Josh Roy ba5a8becfc Add support for role arguments in slash commands 2022-12-26 01:24:17 +00:00
Josh Roy 2a1957229f Add InteractionMember#hasRole convince methods 2022-12-26 01:24:17 +00:00
Josh Roy e6af246170 Add IPermissionsHandler#getGroups to fetch all groups 2022-12-26 01:24:17 +00:00
Josh Roy 939e5c5a55 Add InteractionRole#isPublicRole 2022-12-26 01:24:17 +00:00
Josh Roy 80bbf8c55b Add DiscordService#getRole & DiscordService#modifyMemberRoles 2022-12-26 01:24:17 +00:00
Josh Roy 376abc4aab Add DiscordService#getMemberById 2022-12-26 01:24:17 +00:00
Josh Roy a7f4d6b16b Add InteractionMember#getAsMention 2022-12-26 01:24:17 +00:00
Josh Roy e0d6040662 Add IUser#isFreeze & IUser#setFreeze 2022-12-26 01:24:17 +00:00
Josh Roy 6ec4c97ddd Rewrite Inventory Handling (#5021)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

Complete refactor of inventory handling across the plugin. This simplifies various commands, and aims to resolve issues aon various different MC versions and inconsistencies between parts of the plugin.

Fixes https://github.com/EssentialsX/Essentials/issues/3810
Fixes https://github.com/EssentialsX/Essentials/issues/4248
2022-12-24 17:58:51 +00:00
diademiemiandJosh Roy db10678095 Add first join message type for Discord (#5160)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>

Add a new message type for when a player has joined for the first time.
2022-12-24 14:59:00 +00:00
Josh Roy 582a357752 Bump to 1.19.3 (#5179) 2022-12-07 21:47:13 -05:00
Bobcat00andBobcat00 8a1e7019a7 Fix incorect play time in /whois (#5177)
Co-authored-by: Bobcat00 <Bobcat00@users.noreply.github.com>
2022-12-06 09:02:20 -05:00
Josh Roy 4414eea513 Close discord webhook clients on shutdown (#5165) 2022-11-27 19:29:36 +00:00
Josh Roy 6e931b2b3b Fix ConsoleInjector not getting reinjecting on reload (#5149) 2022-11-11 15:28:55 -08:00
Warrior 22a0d53cf2 Improve uuid cache load times (#5143) 2022-11-03 20:14:18 -04:00
20011b9996 Added permission node for Nickname Prefix bypass (#4995)
Allow a permission to determine whether the nickname prefix gets applied to a group or user. It also removes a statement that is not true in the essentials config, the nickname prefix is NOT included in the nickname max length.

Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2022-10-25 07:44:05 +01:00
879e70fb6b Ignore NPCs in JailListener (#5130)
Co-authored-by: pop4959 <pop4959@gmail.com>
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

Citizens NPCs cannot be jailed. This change prevents unnecessary lookups of NPC users.
2022-10-20 14:19:22 -04:00
Josh Royandpop4959 f91dfed5b4 Improve PlayerTarget code (#5131)
Co-authored-by: pop4959 <pop4959@gmail.com>
2022-10-15 00:41:21 +00:00
Josh Roy 767185ec32 Auto complete /mail clear indices (#5132) 2022-10-15 00:32:47 +00:00
Noah van der AaandJosh Roy 4aa93a43db Add mutable "viewers" list to DiscordRelayEvent (#5080)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2022-10-14 22:26:01 +00:00
Lax 57529c4b7d Update Bukkit wiki links in config (#5094) 2022-10-14 22:15:35 +00:00
MDandJosh Roy dc7fb91939 Make usermap non-player warnings configurable (#5125)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2022-10-11 01:06:54 +00:00
Josh Roy e91ce0c44c Fix Essentials#getUser not caching newly created NPC users (#5129) 2022-10-11 00:36:33 +00:00
Nassim Jahnke f7cbc7b0d3 Add renamehome command (#5121) 2022-10-04 08:40:18 -04:00
MD 28d7abe642 Close any open inventories before showing shapeless recipes (#5122) 2022-10-02 18:43:13 -04:00
0ca58ce4ba Rewrite User storage and UUID cache (#4581)
Co-authored-by: triagonal <10545540+triagonal@users.noreply.github.com>
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2022-09-09 15:49:43 -04:00
Josh Roy d75d3cd001 Bump to 2.20 dev
Fourth time's a charm
2022-09-09 15:49:40 -04:00
MD 1eb5d8a459 Use Netlify CLI directly to deploy Javadocs 2022-09-05 18:46:09 +01:00
Josh Roy b808511efe Update discord bot authorization tutorial (#5098) 2022-09-02 09:43:09 -04:00
MD 0897ef71f2 Bump to 2.19.8 dev (#5085) 2022-08-22 10:17:33 -04:00
Josh Roy f176893940 Release 2.19.7 2022-08-21 16:48:14 -04:00
Josh Roy af18afad7a Fix discord url link message (#5079) 2022-08-18 20:42:57 -07:00
Josh Roy bdc5f4c830 Fix baltop not working in command blocks (#5078) 2022-08-18 18:37:15 +00:00
Josh Roy 0be056b9c2 Improve error messages in Backup 2022-08-18 14:14:29 -04:00
Josh Roy 5f5d65c463 Fix null log messages causing an NPE 2022-08-18 14:14:29 -04:00
Josh Roy ca4077b204 Fix rgb color codes getting stripped in some cases (#5076) 2022-08-18 17:29:12 +00:00
Josh Roy 4ab3e20a0c Fix remaining uses of Bukkit's logger (#5075)
Fixes #5056
2022-08-18 17:35:53 +01:00
Josh Roy 576866540e Fix gson incompatibility on 1.8.8 (#5067) 2022-08-17 06:52:38 +00:00
Josh Roy dfcb9a1c52 Update Checkstyle IDEA config (#5047) 2022-08-16 08:18:12 +00:00
Josh Roy a7a9cbc034 Bump down to 2.19.7 (#5064)
Never ending cycle
2022-08-15 14:26:52 +01:00
MDandJosh Roy 2f4f555923 Fix issues with chat preview refactor (#5062)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2022-08-14 18:49:02 -04:00
MD 1c22edbb1b Prevent players opening their own inventories in /invsee (#5061) 2022-08-14 16:31:23 -04:00
Josh Roy b71fb520aa Prepare for 2.20.0 dev builds 2022-08-12 22:30:18 +01:00
Josh Roy 8f7b7d0a5f Release 2.19.6 2022-08-12 16:59:48 -04:00
Josh Roy f379323d7a Fix mappings in ReflOnlineModeProvider 2022-08-12 16:59:02 -04:00
239 changed files with 11531 additions and 2368 deletions

No files matched your search

+1 -4
View File
@@ -7,14 +7,11 @@ contact_links:
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
url: https://github.com/EssentialsX/Essentials/issues?q=is%3Aissue+label%3A%22type%3A+enhancement%22
about: Visit the Feature Suggestions forum to view and discuss existing feature suggestions.
- name: Create help request
url: https://github.com/EssentialsX/Essentials/discussions/new?category=q-a
about: Create a support ticket to get help from developers.
- name: 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: Join the MOSS Discord for community-powered EssentialsX support!
@@ -0,0 +1,40 @@
name: Request a feature
description: Suggest a feature you want to see in EssentialsX!
labels: 'type: enhancement'
body:
- type: markdown
attributes:
value: |
If you have a feature suggestion for EssentialsX, read the following tips:
1. Fill out the template.
This will help us understand what you're requesting and why you want us
to add it.
2. Keep it simple.
Make sure it's easy to understand what you're requesting. A good way is
to keep it to one request per GitHub issue, as we can then easily track
feature requests.
3. Check whether it has already been asked or added.
You can search the issue tracker to see if your feature has already been
requested at https://github.com/EssentialsX/Essentials/issues. You can
also check the changelogs to see if the feature was recently added:
https://github.com/EssentialsX/Essentials/releases
4. Ask yourself: "Does this belong in EssentialsX?"
There are lots of features that we reject because most servers won't
need or use them. If your feature is very specific or already exists in
another plugin, it might not be a good fit for EssentialsX.
- type: textarea
attributes:
label: Feature description
description: Explain what you should expect to happen.
placeholder: |
What feature are you suggesting?
validations:
required: true
- type: textarea
attributes:
label: How the feature is useful
description: Explain what actually happens.
placeholder: |
How is the feature useful to players, server owners and/or developers?
validations:
required: true
+37 -21
View File
@@ -5,6 +5,9 @@ on:
branches:
- 2.x
- dev/*
release:
types:
- published
jobs:
build:
@@ -13,26 +16,18 @@ jobs:
steps:
- name: Checkout Git repo
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Restore Gradle cache
uses: actions/cache@v2
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-
distribution: 'temurin'
java-version: 17
- 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: Setup Gradle
uses: gradle/gradle-build-action@v2
- name: Build with Gradle
run: |
@@ -40,7 +35,7 @@ jobs:
./gradlew build --stacktrace
- name: Archive plugin jars on GitHub
uses: actions/upload-artifact@master
uses: actions/upload-artifact@v3
with:
name: EssentialsX plugin jars
path: jars/
@@ -54,22 +49,43 @@ jobs:
./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 EssentialsDiscordLink/build/docs/javadoc/ javadocs/EssentialsDiscordLink/
cp -r EssentialsGeoIP/build/docs/javadoc/ javadocs/EssentialsGeoIP/
cp -r EssentialsProtect/build/docs/javadoc/ javadocs/EssentialsProtect/
cp -r EssentialsSpawn/build/docs/javadoc/ javadocs/EssentialsSpawn/
cp -r EssentialsXMPP/build/docs/javadoc/ javadocs/EssentialsXMPP/
- name: Deploy Javadocs
if: ${{ success() && github.event_name == 'push' && github.repository == 'EssentialsX/Essentials' && github.ref == 'refs/heads/2.x' }}
uses: netlify/actions/cli@master
- name: Archive Javadocs
uses: actions/upload-artifact@v3
with:
args: deploy --dir=javadocs/ --prod --message="GitHubActionsDeploy"
name: javadocs
path: javadocs/
publish-jd:
name: Publish Javadocs
needs: build
if: ${{ github.event_name == 'push' && github.repository == 'EssentialsX/Essentials' && github.ref == 'refs/heads/2.x' }}
runs-on: ubuntu-latest
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16
- name: Download Javadocs
uses: actions/download-artifact@v3
with:
name: javadocs
path: javadocs/
- name: Deploy Javadocs
run: npx netlify-cli deploy --dir=javadocs/ --prod --message="GitHubActionsDeploy"
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_JD_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_JD_2X_SITE_ID }}
+8 -16
View File
@@ -18,26 +18,18 @@ jobs:
steps:
- name: Checkout Git repo
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Restore Gradle cache
uses: actions/cache@v2
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-
distribution: 'temurin'
java-version: 17
- 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: Setup Gradle
uses: gradle/gradle-build-action@v2
- name: Build with Gradle
run: |
@@ -45,7 +37,7 @@ jobs:
./gradlew build --stacktrace
- name: Archive plugin jars on GitHub
uses: actions/upload-artifact@master
uses: actions/upload-artifact@v3
with:
name: EssentialsX plugin jars
path: jars/
+2
View File
@@ -15,6 +15,8 @@
/Essentials/kits.yml
/Essentials/userdata/testplayer1.yml
/Essentials/usermap.csv
/Essentials/usermap.bin
/Essentials/uuids.bin
# Build files
.gradle/
+22 -14
View File
@@ -1,19 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CheckStyle-IDEA">
<option name="configuration">
<map>
<entry key="active-configuration" value="PROJECT_RELATIVE:$PROJECT_DIR$/.checkstyle/checkstyle.xml:EssentialsX" />
<entry key="checkstyle-version" value="8.36.2" />
<entry key="copy-libs" value="true" />
<entry key="location-0" value="BUNDLED:(bundled):Sun Checks" />
<entry key="location-1" value="BUNDLED:(bundled):Google Checks" />
<entry key="location-2" value="PROJECT_RELATIVE:$PROJECT_DIR$/.checkstyle/checkstyle.xml:EssentialsX" />
<entry key="property-2.configDirectory" value=".checkstyle/" />
<entry key="scan-before-checkin" value="true" />
<entry key="scanscope" value="JavaOnly" />
<entry key="suppress-errors" value="false" />
</map>
<component name="CheckStyle-IDEA" serialisationVersion="2">
<checkstyleVersion>8.36.2</checkstyleVersion>
<scanScope>JavaOnly</scanScope>
<copyLibs>true</copyLibs>
<scanBeforeCheckin>true</scanBeforeCheckin>
<option name="thirdPartyClasspath" />
<option name="activeLocationIds">
<option value="321e5753-4201-4d2c-bf31-6232011122fd" />
</option>
<option name="locations">
<list>
<ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">(bundled)</ConfigurationLocation>
<ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">(bundled)</ConfigurationLocation>
<ConfigurationLocation id="321e5753-4201-4d2c-bf31-6232011122fd" type="PROJECT_RELATIVE" scope="All" description="EssentialsX">
$PROJECT_DIR$/.checkstyle/checkstyle.xml
<option name="properties">
<map>
<entry key="configDirectory" value=".checkstyle/" />
</map>
</option>
</ConfigurationLocation>
</list>
</option>
</component>
</project>
+4
View File
@@ -29,6 +29,10 @@ dependencies {
}
}
test {
testLogging.showStandardStreams = true
}
shadowJar {
dependencies {
include (dependency('io.papermc:paperlib'))
@@ -102,12 +102,12 @@ public class Backup implements Runnable {
} while (line != null);
}
} catch (final IOException ex) {
ess.getLogger().log(Level.SEVERE, null, ex);
ess.getLogger().log(Level.SEVERE, "An error occurred while reading backup child process", ex);
}
});
child.waitFor();
} catch (final InterruptedException | IOException ex) {
ess.getLogger().log(Level.SEVERE, null, ex);
ess.getLogger().log(Level.SEVERE, "An error occurred while building the backup child process", ex);
} finally {
class BackupEnableSaveTask implements Runnable {
@Override
@@ -28,8 +28,8 @@ public class BalanceTopImpl implements BalanceTop {
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);
for (UUID u : ess.getUsers().getAllUserUUIDs()) {
final User user = ess.getUsers().loadUncachedUser(u);
if (user != null) {
if (!ess.getSettings().isNpcsInBalanceRanking() && user.isNPC()) {
// Don't list NPCs in output
@@ -40,7 +40,7 @@ public class BalanceTopImpl implements BalanceTop {
user.updateMoneyCache(userMoney);
newTotal = newTotal.add(userMoney);
final String name;
if (user.getBase() instanceof OfflinePlayer) {
if (user.getBase() instanceof OfflinePlayerStub) {
name = user.getLastAccountName();
} else if (user.isHidden()) {
name = user.getName();
@@ -39,6 +39,7 @@ import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.updatecheck.UpdateChecker;
import com.earth2me.essentials.userstorage.ModernUserMap;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.VersionUtil;
import io.papermc.lib.PaperLib;
@@ -143,7 +144,7 @@ import static com.earth2me.essentials.I18n.tl;
public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
private static final Logger BUKKIT_LOGGER = Logger.getLogger("Essentials");
private static Logger LOGGER = null;
private final transient TNTExplodeListener tntListener = new TNTExplodeListener(this);
private final transient TNTExplodeListener tntListener = new TNTExplodeListener();
private final transient Set<String> vanishedPlayers = new LinkedHashSet<>();
private transient ISettings settings;
private transient Jails jails;
@@ -155,7 +156,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
private transient CustomItemResolver customItemResolver;
private transient PermissionsHandler permissionsHandler;
private transient AlternativeCommandsHandler alternativeCommandsHandler;
private transient UserMap userMap;
@Deprecated
private transient UserMap legacyUserMap;
private transient ModernUserMap userMap;
private transient BalanceTopImpl balanceTop;
private transient ExecuteTimer execTimer;
private transient MailService mail;
@@ -222,7 +225,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
LOGGER.log(Level.INFO, dataFolder.toString());
settings = new Settings(this);
mail = new MailServiceImpl(this);
userMap = new UserMap(this);
userMap = new ModernUserMap(this);
balanceTop = new BalanceTopImpl(this);
permissionsHandler = new PermissionsHandler(this, false);
Economy.setEss(this);
@@ -301,11 +304,14 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
confList.add(settings);
execTimer.mark("Settings");
upgrade.preModules();
execTimer.mark("Upgrade2");
mail = new MailServiceImpl(this);
execTimer.mark("Init(Mail)");
userMap = new UserMap(this);
confList.add(userMap);
userMap = new ModernUserMap(this);
legacyUserMap = new UserMap(userMap);
execTimer.mark("Init(Usermap)");
balanceTop = new BalanceTopImpl(this);
@@ -317,7 +323,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
execTimer.mark("Kits");
upgrade.afterSettings();
execTimer.mark("Upgrade2");
execTimer.mark("Upgrade3");
warps = new Warps(this.getDataFolder());
confList.add(warps);
@@ -588,7 +594,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
Economy.setEss(null);
Trade.closeLog();
getUserMap().getUUIDMap().shutdown();
getUsers().shutdown();
HandlerList.unregisterAll(this);
}
@@ -948,17 +954,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
//This will return null if there is not a match.
@Override
public User getOfflineUser(final String name) {
final User user = userMap.getUser(name);
if (user != null && user.getBase() instanceof OfflinePlayer) {
//This code should attempt to use the last known name of a user, if Bukkit returns name as null.
final String lastName = user.getLastAccountName();
if (lastName != null) {
((OfflinePlayer) user.getBase()).setName(lastName);
} else {
((OfflinePlayer) user.getBase()).setName(name);
}
}
return user;
return userMap.getUser(name);
}
@Override
@@ -1046,7 +1042,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return true;
}
return interactor.getBase().canSee(interactee.getBase());
return !interactee.isHiddenFrom(interactor.getBase());
}
//This will create a new user if there is not a match.
@@ -1061,14 +1057,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return null;
}
User user = userMap.getUser(base.getUniqueId());
final User user = userMap.getUser(base);
if (user == null) {
if (getSettings().isDebug()) {
LOGGER.log(Level.INFO, "Constructing new userfile from base player " + base.getName());
}
user = new User(base, this);
} else {
if (base.getClass() != UUIDPlayer.class || user.getBase() == null) {
user.update(base);
}
return user;
@@ -1182,11 +1173,6 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return this.getScheduler().scheduleSyncRepeatingTask(this, run, delay, period);
}
@Override
public TNTExplodeListener getTNTListener() {
return tntListener;
}
@Override
public PermissionsHandler getPermissionsHandler() {
return permissionsHandler;
@@ -1203,7 +1189,13 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
@Override
@Deprecated
public UserMap getUserMap() {
return legacyUserMap;
}
@Override
public ModernUserMap getUsers() {
return userMap;
}
@@ -1,5 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.MaterialUtil;
import net.ess3.api.IEssentials;
import org.bukkit.GameMode;
@@ -45,7 +46,7 @@ public class EssentialsBlockListener implements Listener {
if (is != null && is.getType() != null && !MaterialUtil.isAir(is.getType())) {
final ItemStack cloneIs = is.clone();
cloneIs.setAmount(1);
user.getBase().getInventory().addItem(cloneIs);
Inventories.addItem(user.getBase(), cloneIs);
user.getBase().updateInventory();
}
});
@@ -1,6 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.api.IEssentials;
import org.bukkit.Location;
@@ -52,12 +52,12 @@ public class EssentialsEntityListener implements Listener {
if (eDefend instanceof Player) {
onPlayerVsPlayerDamage(event, (Player) eDefend, attacker);
} else if (eDefend instanceof Ageable) {
final ItemStack hand = attacker.getBase().getItemInHand();
final ItemStack hand = Inventories.getItemInMainHand(attacker.getBase());
if (ess.getSettings().isMilkBucketEasterEggEnabled()
&& hand != null && hand.getType() == Material.MILK_BUCKET) {
((Ageable) eDefend).setBaby();
hand.setType(Material.BUCKET);
attacker.getBase().setItemInHand(hand);
Inventories.setItemInMainHand(attacker.getBase(), hand);
attacker.getBase().updateInventory();
event.setCancelled(true);
}
@@ -98,7 +98,7 @@ public class EssentialsEntityListener implements Listener {
}
private void onPlayerVsPlayerPowertool(final EntityDamageByEntityEvent event, final Player defender, final User attacker) {
final List<String> commandList = attacker.getPowertool(attacker.getBase().getItemInHand());
final List<String> commandList = attacker.getPowertool(Inventories.getItemInHand(attacker.getBase()));
if (commandList != null && !commandList.isEmpty()) {
for (final String tempCommand : commandList) {
final String command = powertoolPlayer.matcher(tempCommand).replaceAll(defender.getName());
@@ -196,73 +196,23 @@ public class EssentialsEntityListener implements Listener {
final ISettings.KeepInvPolicy vanish = ess.getSettings().getVanishingItemsPolicy();
final ISettings.KeepInvPolicy bind = ess.getSettings().getBindingItemsPolicy();
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_11_2_R01) && (vanish != ISettings.KeepInvPolicy.KEEP || bind != ISettings.KeepInvPolicy.KEEP)) {
for (final ItemStack stack : event.getEntity().getInventory()) {
if (stack != null && !MaterialUtil.isAir(stack.getType())) {
if (stack.getEnchantments().containsKey(Enchantment.VANISHING_CURSE)) {
if (vanish == ISettings.KeepInvPolicy.DELETE) {
event.getEntity().getInventory().remove(stack);
} else if (vanish == ISettings.KeepInvPolicy.DROP) {
event.getDrops().add(stack);
event.getEntity().getInventory().remove(stack);
}
}
if (stack.getEnchantments().containsKey(Enchantment.BINDING_CURSE)) {
if (bind == ISettings.KeepInvPolicy.DELETE) {
event.getEntity().getInventory().remove(stack);
} else if (bind == ISettings.KeepInvPolicy.DROP) {
event.getEntity().getInventory().remove(stack);
event.getDrops().add(stack);
}
Inventories.removeItems(user.getBase(), stack -> {
if (vanish != ISettings.KeepInvPolicy.KEEP && stack.getEnchantments().containsKey(Enchantment.VANISHING_CURSE)) {
if (vanish == ISettings.KeepInvPolicy.DROP) {
event.getDrops().add(stack.clone());
}
return true;
}
}
// Now check armor
final ItemStack[] armor = event.getEntity().getInventory().getArmorContents();
for (int i = 0; i < armor.length; i++) {
final ItemStack stack = armor[i];
if (stack != null && !MaterialUtil.isAir(stack.getType())) {
if (stack.getEnchantments().containsKey(Enchantment.VANISHING_CURSE)) {
if (vanish == ISettings.KeepInvPolicy.DELETE) {
armor[i] = null;
} else if (vanish == ISettings.KeepInvPolicy.DROP) {
if (!event.getDrops().contains(stack)) {
event.getDrops().add(stack);
}
armor[i] = null;
}
}
if (stack.getEnchantments().containsKey(Enchantment.BINDING_CURSE)) {
if (bind == ISettings.KeepInvPolicy.DELETE) {
armor[i] = null;
} else if (bind == ISettings.KeepInvPolicy.DROP) {
if (!event.getDrops().contains(stack)) {
event.getDrops().add(stack);
}
armor[i] = null;
}
if (bind != ISettings.KeepInvPolicy.KEEP && stack.getEnchantments().containsKey(Enchantment.BINDING_CURSE)) {
if (bind == ISettings.KeepInvPolicy.DROP) {
event.getDrops().add(stack.clone());
}
return true;
}
}
event.getEntity().getInventory().setArmorContents(armor);
// Now check offhand
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_9_R01)) {
final ItemStack stack = event.getEntity().getInventory().getItemInOffHand();
//noinspection ConstantConditions
if (stack != null && !MaterialUtil.isAir(stack.getType())) {
final boolean isVanish = stack.getEnchantments().containsKey(Enchantment.VANISHING_CURSE);
final boolean isBind = stack.getEnchantments().containsKey(Enchantment.BINDING_CURSE);
if (isVanish || isBind) {
event.getEntity().getInventory().setItemInOffHand(null);
if ((isVanish && vanish == ISettings.KeepInvPolicy.DROP) || (isBind && bind == ISettings.KeepInvPolicy.DROP)) {
if (!event.getDrops().contains(stack)) {
event.getDrops().add(stack);
}
}
}
}
}
return false;
}, true);
}
}
}
@@ -1,6 +1,7 @@
package com.earth2me.essentials;
import com.earth2me.essentials.commands.Commandfireball;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.TextInput;
@@ -120,6 +121,15 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
}
}
private static boolean isGameEventEvent() {
try {
Class.forName("org.bukkit.event.block.BlockReceiveGameEvent");
return true;
} catch (final ClassNotFoundException ignored) {
return false;
}
}
public void registerEvents() {
ess.getServer().getPluginManager().registerEvents(this, ess);
@@ -127,6 +137,10 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
ess.getServer().getPluginManager().registerEvents(new ArrowPickupListener(), ess);
}
if (isGameEventEvent()) {
ess.getServer().getPluginManager().registerEvents(new SculkListener1_17(), ess);
}
if (isEntityPickupEvent()) {
ess.getServer().getPluginManager().registerEvents(new PickupListener1_12(), ess);
} else {
@@ -192,17 +206,26 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
return;
}
if (!ess.getSettings().cancelAfkOnMove() && !ess.getSettings().getFreezeAfkPlayers()) {
event.getHandlers().unregister(this);
final User user = ess.getUser(event.getPlayer());
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "Unregistering move listener");
if (user.isFreeze()) {
final Location from = event.getFrom();
final Location to = event.getTo().clone();
to.setX(from.getX());
to.setY(from.getY());
to.setZ(from.getZ());
try {
event.setTo(LocationUtil.getSafeDestination(ess, to));
} catch (final Exception ex) {
event.setTo(to);
}
return;
}
final User user = ess.getUser(event.getPlayer());
if (!ess.getSettings().cancelAfkOnMove() && !ess.getSettings().getFreezeAfkPlayers()) {
return;
}
if (user.isAfk() && ess.getSettings().getFreezeAfkPlayers()) {
final Location from = event.getFrom();
final Location origTo = event.getTo();
@@ -308,6 +331,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
ess.getBackup().onPlayerJoin();
final User dUser = ess.getUser(player);
dUser.update(player);
dUser.startTransaction();
if (dUser.isNPC()) {
@@ -367,7 +391,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
} else if (ess.getSettings().isCustomJoinMessage()) {
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("{UNIQUE}", NumberFormat.getInstance().format(ess.getUsers().getUserCount()))
.replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size()))
.replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()))
.replace("{PREFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getPrefix(player)))
@@ -527,6 +551,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
public void onPlayerLogin(final PlayerLoginEvent event) {
if (event.getResult() == Result.KICK_FULL) {
final User kfuser = ess.getUser(event.getPlayer());
kfuser.update(event.getPlayer());
if (kfuser.isAuthorized("essentials.joinfullserver")) {
event.allow();
return;
@@ -557,7 +582,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
final User user = ess.getUser(event.getPlayer());
final ItemStack stack = new ItemStack(Material.EGG, 1);
if (user.hasUnlimited(stack)) {
user.getBase().getInventory().addItem(stack);
Inventories.addItem(user.getBase(), stack);
user.getBase().updateInventory();
}
}
@@ -650,7 +675,8 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
}
if (ess.getSettings().isCommandCooldownsEnabled()
&& !user.isAuthorized("essentials.commandcooldowns.bypass")) {
&& !user.isAuthorized("essentials.commandcooldowns.bypass")
&& (pluginCommand == null || !user.isAuthorized("essentials.commandcooldowns.bypass." + pluginCommand.getName()))) {
final int argStartIndex = effectiveCommand.indexOf(" ");
final String args = argStartIndex == -1 ? "" // No arguments present
: " " + effectiveCommand.substring(argStartIndex); // arguments start at argStartIndex; substring from there.
@@ -988,6 +1014,15 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
}
}
private final class SculkListener1_17 implements Listener {
@EventHandler
public void onGameEvent(final org.bukkit.event.block.BlockReceiveGameEvent event) {
if (event.getEntity() instanceof Player && ess.getUser((Player) event.getEntity()).isVanished()) {
event.setCancelled(true);
}
}
}
private final class CommandSendFilter implements CommandSendListenerProvider.Filter {
@Override
public Predicate<String> apply(Player player) {
@@ -4,9 +4,9 @@ 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.userstorage.ModernUUIDCache;
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;
@@ -31,10 +31,10 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -47,13 +47,12 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.earth2me.essentials.I18n.tl;
public class EssentialsUpgrade {
private static final FileFilter YML_FILTER = pathname -> pathname.isFile() && pathname.getName().endsWith(".yml");
public static final FileFilter YML_FILTER = pathname -> pathname.isFile() && pathname.getName().endsWith(".yml");
private static final String PATTERN_CONFIG_UUID_REGEX = "(?mi)^uuid:\\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\s*$";
private static final Pattern PATTERN_CONFIG_UUID = Pattern.compile(PATTERN_CONFIG_UUID_REGEX);
private static final String PATTERN_CONFIG_NAME_REGEX = "(?mi)^lastAccountName:\\s*[\"\']?(\\w+)[\"\']?\\s*$";
@@ -93,7 +92,6 @@ public class EssentialsUpgrade {
final int showProgress = countFiles % 250;
if (showProgress == 0) {
ess.getUserMap().getUUIDMap().forceWriteUUIDMap();
ess.getLogger().info("Converted " + countFiles + "/" + userdir.list().length);
}
@@ -103,7 +101,8 @@ public class EssentialsUpgrade {
final EssentialsUserConfiguration config;
UUID uuid = null;
try {
uuid = UUID.fromString(name);
//noinspection ResultOfMethodCallIgnored
UUID.fromString(name);
} catch (final IllegalArgumentException ex) {
final File file = new File(userdir, string);
final EssentialsConfiguration conf = new EssentialsConfiguration(file);
@@ -115,6 +114,7 @@ public class EssentialsUpgrade {
final String uuidString = conf.getString(uuidConf, null);
//noinspection ConstantConditions
for (int i = 0; i < 4; i++) {
try {
uuid = UUID.fromString(uuidString);
@@ -122,7 +122,7 @@ public class EssentialsUpgrade {
break;
} catch (final Exception ex2) {
if (conf.getBoolean("npc", false)) {
uuid = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
uuid = UUID.nameUUIDFromBytes(("NPC:" + (ess.getSettings().isSafeUsermap() ? StringUtil.safeString(name) : name)).getBytes(Charsets.UTF_8));
break;
}
@@ -130,23 +130,24 @@ public class EssentialsUpgrade {
uuid = player.getUniqueId();
}
//noinspection ConstantConditions
if (uuid != null) {
countBukkit++;
break;
}
}
//noinspection ConstantConditions
if (uuid != null) {
conf.blockingSave();
config = new EssentialsUserConfiguration(name, uuid, new File(userdir, uuid + ".yml"));
config.convertLegacyFile();
ess.getUserMap().trackUUID(uuid, name, false);
ess.getUsers().loadUncachedUser(uuid);
continue;
}
countFails++;
}
}
ess.getUserMap().getUUIDMap().forceWriteUUIDMap();
ess.getLogger().info("Converted " + countFiles + "/" + countFiles + ". Conversion complete.");
ess.getLogger().info("Converted via cache: " + countEssCache + " :: Converted via lookup: " + countBukkit + " :: Failed to convert: " + countFails);
@@ -913,74 +914,76 @@ public class EssentialsUpgrade {
Bukkit.getBanList(BanList.Type.NAME).addBan(playerName, banReason, banTimeout == 0 ? null : new Date(banTimeout), Console.NAME);
}
private void repairUserMap() {
if (doneFile.getBoolean("userMapRepaired", false)) {
public void generateUidCache() {
if (doneFile.getBoolean("newUidCacheBuilt", false)) {
return;
}
ess.getLogger().info("Starting usermap repair");
final File usermapFile = new File(ess.getDataFolder(), "usermap.bin");
final File uidsFile = new File(ess.getDataFolder(), "uuids.bin");
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
if (!userdataFolder.isDirectory()) {
if (!userdataFolder.isDirectory() || usermapFile.exists() || uidsFile.exists()) {
ess.getLogger().warning("Missing userdata folder, aborting");
doneFile.setProperty("newUidCacheBuilt", true);
doneFile.save();
return;
}
final File[] files = userdataFolder.listFiles(YML_FILTER);
final DecimalFormat format = new DecimalFormat("#0.00");
final Map<String, UUID> names = Maps.newHashMap();
for (int index = 0; index < files.length; index++) {
final File file = files[index];
try {
UUID uuid = null;
final String filename = file.getName();
final String configData = new String(java.nio.file.Files.readAllBytes(file.toPath()), Charsets.UTF_8);
if (filename.length() > 36) {
try {
// ".yml" ending has 4 chars...
uuid = UUID.fromString(filename.substring(0, filename.length() - 4));
} catch (final IllegalArgumentException ignored) {
}
}
final Matcher uuidMatcher = PATTERN_CONFIG_UUID.matcher(configData);
if (uuidMatcher.find()) {
try {
uuid = UUID.fromString(uuidMatcher.group(1));
} catch (final IllegalArgumentException ignored) {
}
}
if (uuid == null) {
// Don't import
continue;
}
final Matcher nameMatcher = PATTERN_CONFIG_NAME.matcher(configData);
if (nameMatcher.find()) {
final String username = nameMatcher.group(1);
if (username != null && username.length() > 0) {
names.put(StringUtil.safeString(username), uuid);
}
}
if (index % 1000 == 0) {
ess.getLogger().info("Reading: " + format.format((100d * (double) index) / files.length)
+ "%");
}
} catch (final IOException e) {
ess.getLogger().log(Level.SEVERE, "Error while reading file: ", e);
try {
if (!usermapFile.createNewFile() || !uidsFile.createNewFile()) {
ess.getLogger().warning("Couldn't create usermap.bin or uuids.bin, aborting");
return;
}
final Map<UUID, Long> uuids = new HashMap<>();
final Map<String, UUID> nameToUuidMap = new HashMap<>();
final File[] files = userdataFolder.listFiles(YML_FILTER);
if (files != null) {
for (final File file : files) {
try {
final String fileName = file.getName();
final UUID uuid = UUID.fromString(fileName.substring(0, fileName.length() - 4));
final EssentialsConfiguration config = new EssentialsConfiguration(file);
config.load();
String name = config.getString("last-account-name", null);
name = ess.getSettings().isSafeUsermap() ? StringUtil.safeString(name) : name;
final long time = config.getLong("timestamps.logout", 0L);
if (name != null) {
if (nameToUuidMap.containsKey(name)) {
final UUID oldUuid = nameToUuidMap.get(name);
if (oldUuid.version() < uuid.version() || (oldUuid.version() == uuid.version() && uuids.get(oldUuid) < time)) {
ess.getLogger().warning("New UUID found for " + name + ": " + uuid + " (old: " + oldUuid + "). Replacing.");
uuids.remove(oldUuid);
} else {
ess.getLogger().warning("Found UUID for " + name + ": " + uuid + " (old: " + oldUuid + "). Skipping.");
continue;
}
}
uuids.put(uuid, time);
nameToUuidMap.put(name, uuid);
}
} catch (IllegalArgumentException | IndexOutOfBoundsException ignored) {
}
}
}
if (!nameToUuidMap.isEmpty()) {
ModernUUIDCache.writeNameUuidMap(usermapFile, nameToUuidMap);
}
if (!uuids.isEmpty()) {
ModernUUIDCache.writeUuidCache(uidsFile, uuids.keySet());
}
doneFile.setProperty("newUidCacheBuilt", true);
doneFile.save();
} catch (final IOException e) {
ess.getLogger().log(Level.SEVERE, "Error while generating initial uuids/names cache", e);
}
ess.getUserMap().getNames().putAll(names);
ess.getUserMap().reloadConfig();
doneFile.setProperty("userMapRepaired", true);
doneFile.save();
ess.getLogger().info("Completed usermap repair.");
}
public void beforeSettings() {
@@ -991,6 +994,10 @@ public class EssentialsUpgrade {
moveMotdRulesToFile("rules");
}
public void preModules() {
generateUidCache();
}
public void afterSettings() {
sanitizeAllUserFilenames();
updateUsersPowerToolsFormat();
@@ -1001,7 +1008,6 @@ public class EssentialsUpgrade {
uuidFileChange();
banFormatChange();
warnMetrics();
repairUserMap();
convertIgnoreList();
convertStupidCamelCaseUserdataKeys();
convertMailList();
@@ -7,6 +7,7 @@ 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 com.earth2me.essentials.userstorage.IUserMap;
import net.ess3.nms.refl.providers.ReflOnlineModeProvider;
import net.ess3.provider.ContainerProvider;
import net.ess3.provider.FormattedCommandAliasProvider;
@@ -109,8 +110,6 @@ public interface IEssentials extends Plugin {
int scheduleSyncRepeatingTask(Runnable run, long delay, long period);
TNTExplodeListener getTNTListener();
PermissionsHandler getPermissionsHandler();
AlternativeCommandsHandler getAlternativeCommandsHandler();
@@ -119,6 +118,9 @@ public interface IEssentials extends Plugin {
IItemDb getItemDb();
IUserMap getUsers();
@Deprecated
UserMap getUserMap();
BalanceTop getBalanceTop();
@@ -282,6 +282,8 @@ public interface ISettings extends IConf {
int getMaxUserCacheCount();
long getMaxUserCacheValueExpiry();
boolean allowSilentJoinQuit();
boolean isCustomJoinMessage();
@@ -155,6 +155,8 @@ public interface IUser {
void delHome(String name) throws Exception;
void renameHome(String name, String newName) throws Exception;
boolean hasHome();
Location getLastLocation();
@@ -330,4 +332,12 @@ public interface IUser {
this.time = time;
}
}
List<String> getPastUsernames();
void addPastUsername(String username);
boolean isFreeze();
void setFreeze(boolean freeze);
}
@@ -203,6 +203,10 @@ public class Jails implements net.ess3.api.IJails {
private class JailListener implements Listener {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailBlockBreak(final BlockBreakEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-break")) {
event.setCancelled(true);
@@ -211,6 +215,10 @@ public class Jails implements net.ess3.api.IJails {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailBlockPlace(final BlockPlaceEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-place")) {
event.setCancelled(true);
@@ -219,6 +227,10 @@ public class Jails implements net.ess3.api.IJails {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailBlockDamage(final BlockDamageEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-block-damage")) {
event.setCancelled(true);
@@ -232,6 +244,9 @@ public class Jails implements net.ess3.api.IJails {
}
final Entity damager = event.getDamager();
if (damager.getType() == EntityType.PLAYER) {
if (shouldIgnore((Player) damager)) {
return;
}
final User user = ess.getUser((Player) damager);
if (user != null && user.isJailed()) {
event.setCancelled(true);
@@ -241,6 +256,10 @@ public class Jails implements net.ess3.api.IJails {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailPlayerInteract(final PlayerInteractEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-interact")) {
event.setCancelled(true);
@@ -249,6 +268,10 @@ public class Jails implements net.ess3.api.IJails {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailPlayerGameModeChange(final PlayerGameModeChangeEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (user.isJailed()) {
event.setCancelled(true);
@@ -257,6 +280,10 @@ public class Jails implements net.ess3.api.IJails {
@EventHandler(priority = EventPriority.HIGHEST)
public void onJailPlayerRespawn(final PlayerRespawnEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (!user.isJailed() || user.getJail() == null || user.getJail().isEmpty()) {
return;
@@ -275,6 +302,10 @@ public class Jails implements net.ess3.api.IJails {
@EventHandler(priority = EventPriority.HIGH)
public void onJailPlayerTeleport(final PlayerTeleportEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (!user.isJailed() || user.getJail() == null || user.getJail().isEmpty()) {
return;
@@ -294,6 +325,10 @@ public class Jails implements net.ess3.api.IJails {
@EventHandler(priority = EventPriority.HIGHEST)
public void onJailPlayerJoin(final PlayerJoinEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
final long currentTime = System.currentTimeMillis();
user.checkJailTimeout(currentTime);
@@ -318,5 +353,10 @@ public class Jails implements net.ess3.api.IJails {
future.completeExceptionally(ex);
}
}
private boolean shouldIgnore(final Player base) {
// Ignore Citizens NPCs
return base.getUniqueId().version() == 2 || base.hasMetadata("NPC");
}
}
}
@@ -2,23 +2,23 @@ package com.earth2me.essentials;
import com.earth2me.essentials.Trade.OverflowType;
import com.earth2me.essentials.commands.NoChargeException;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
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 net.essentialsx.api.v2.events.KitPreExpandItemsEvent;
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;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
@@ -214,57 +214,38 @@ public class Kit {
stack = metaStack.getItemStack();
}
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(stack);
}
final Map<Integer, ItemStack> overfilled;
final boolean allowOversizedStacks = user.isAuthorized("essentials.oversizedstacks");
final int maxStackSize = user.isAuthorized("essentials.oversizedstacks") ? ess.getSettings().getOversizedStackSize() : 0;
final boolean isDropItemsIfFull = ess.getSettings().isDropItemsIfFull();
if (isDropItemsIfFull) {
if (allowOversizedStacks) {
overfilled = InventoryWorkaround.addOversizedItems(user.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), itemList.toArray(new ItemStack[0]));
} else {
overfilled = InventoryWorkaround.addItems(user.getBase().getInventory(), itemList.toArray(new ItemStack[0]));
final KitPreExpandItemsEvent itemsEvent = new KitPreExpandItemsEvent(user, kitName, itemList);
Bukkit.getPluginManager().callEvent(itemsEvent);
final ItemStack[] itemArray = itemList.toArray(new ItemStack[0]);
if (!isDropItemsIfFull && !Inventories.hasSpace(user.getBase(), maxStackSize, autoEquip, itemArray)) {
user.sendMessage(tl("kitInvFullNoDrop"));
return false;
}
final Map<Integer, ItemStack> leftover = Inventories.addItem(user.getBase(), maxStackSize, autoEquip, itemArray);
if (!isDropItemsIfFull && !leftover.isEmpty()) {
// Inventories#hasSpace should prevent this state from EVER being reached; If it does, something has gone terribly wrong, and we should just give up and hope people report it :(
throw new IllegalStateException("Something has gone terribly wrong while adding items to the user's inventory. Please report this to the EssentialsX developers. Items left over: " + leftover + ". Original items: " + Arrays.toString(itemArray));
}
for (final ItemStack itemStack : leftover.values()) {
int spillAmount = itemStack.getAmount();
if (maxStackSize != 0) {
itemStack.setAmount(Math.min(spillAmount, itemStack.getMaxStackSize()));
}
for (final ItemStack itemStack : overfilled.values()) {
int spillAmount = itemStack.getAmount();
if (!allowOversizedStacks) {
itemStack.setAmount(Math.min(spillAmount, itemStack.getMaxStackSize()));
}
while (spillAmount > 0) {
user.getWorld().dropItemNaturally(user.getLocation(), itemStack);
spillAmount -= itemStack.getAmount();
}
spew = true;
}
} else {
if (allowOversizedStacks) {
overfilled = InventoryWorkaround.addAllOversizedItems(user.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), itemList.toArray(new ItemStack[0]));
} else {
overfilled = InventoryWorkaround.addAllItems(user.getBase().getInventory(), itemList.toArray(new ItemStack[0]));
}
if (overfilled != null) {
user.sendMessage(tl("kitInvFullNoDrop"));
return false;
while (spillAmount > 0) {
user.getWorld().dropItemNaturally(user.getLocation(), itemStack);
spillAmount -= itemStack.getAmount();
}
spew = true;
}
user.getBase().updateInventory();
@@ -291,8 +272,4 @@ public class Kit {
}
return true;
}
private boolean isEmptyStack(ItemStack stack) {
return stack == null || MaterialUtil.isAir(stack.getType());
}
}
@@ -1,9 +1,11 @@
package com.earth2me.essentials;
import net.ess3.api.IUser;
import net.essentialsx.api.v2.services.mail.MailService;
import net.essentialsx.api.v2.events.UserMailEvent;
import net.essentialsx.api.v2.services.mail.MailMessage;
import net.essentialsx.api.v2.services.mail.MailSender;
import net.essentialsx.api.v2.services.mail.MailService;
import org.bukkit.Bukkit;
import org.bukkit.plugin.ServicePriority;
import java.text.SimpleDateFormat;
@@ -35,6 +37,12 @@ public class MailServiceImpl implements MailService {
}
private void sendMail(IUser recipient, MailMessage message) {
final UserMailEvent event = new UserMailEvent(recipient, message);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
final ArrayList<MailMessage> messages = recipient.getMailMessages();
messages.add(0, message);
recipient.setMailList(messages);
@@ -194,14 +194,14 @@ public class MetaItemStack {
final Material WRITTEN_BOOK = EnumUtil.getMaterial("WRITTEN_BOOK");
if (split.length > 1 && split[0].equalsIgnoreCase("name") && hasMetaPermission(sender, "name", false, true, ess)) {
final String displayName = FormatUtil.replaceFormat(split[1].replace('_', ' '));
final String displayName = FormatUtil.replaceFormat(split[1].replaceAll("(?<!\\\\)_", " ").replace("\\_", "_"));
final ItemMeta meta = stack.getItemMeta();
meta.setDisplayName(displayName);
stack.setItemMeta(meta);
} else if (split.length > 1 && (split[0].equalsIgnoreCase("lore") || split[0].equalsIgnoreCase("desc")) && hasMetaPermission(sender, "lore", false, true, ess)) {
final List<String> lore = new ArrayList<>();
for (final String line : split[1].split("(?<!\\\\)\\|")) {
lore.add(FormatUtil.replaceFormat(line.replace('_', ' ').replace("\\|", "|")));
lore.add(FormatUtil.replaceFormat(line.replaceAll("(?<!\\\\)_", " ").replace("\\_", "_").replace("\\|", "|")));
}
final ItemMeta meta = stack.getItemMeta();
meta.setLore(lore);
@@ -230,7 +230,7 @@ public class MetaItemStack {
meta.setAuthor(author);
stack.setItemMeta(meta);
} else if (split.length > 1 && split[0].equalsIgnoreCase("title") && stack.getType() == WRITTEN_BOOK && hasMetaPermission(sender, "title", false, true, ess)) {
final String title = FormatUtil.replaceFormat(split[1].replace('_', ' '));
final String title = FormatUtil.replaceFormat(split[1].replaceAll("(?<!\\\\)_", " ").replace("\\_", "_"));
final BookMeta meta = (BookMeta) stack.getItemMeta();
meta.setTitle(title);
stack.setItemMeta(meta);
@@ -240,7 +240,7 @@ public class MetaItemStack {
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("\\|", "|")));
lines.add(FormatUtil.replaceFormat(line.replaceAll("(?<!\\\\)_", " ").replace("\\_", "_").replace("\\|", "|")));
}
final String content = String.join("\n", lines);
if (page >= pages.size()) {
@@ -109,6 +109,8 @@ public enum Mob {
TADPOLE("Tadpole", Enemies.FRIENDLY, "TADPOLE"),
WARDEN("Warden", Enemies.ENEMY, "WARDEN"),
CHEST_BOAT("ChestBoat", Enemies.NEUTRAL, "CHEST_BOAT"),
CAMEL("Camel", Enemies.FRIENDLY, "CAMEL"),
SNIFFER("Sniffer", Enemies.FRIENDLY, "SNIFFER"),
;
private static final Map<String, Mob> hashMap = new HashMap<>();
@@ -3,9 +3,11 @@ 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.Material;
import org.bukkit.TreeSpecies;
import org.bukkit.entity.Axolotl;
import org.bukkit.entity.Boat;
import org.bukkit.entity.Camel;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Fox;
@@ -15,8 +17,10 @@ import org.bukkit.entity.MushroomCow;
import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Panda;
import org.bukkit.entity.Parrot;
import org.bukkit.entity.Player;
import org.bukkit.entity.TropicalFish;
import org.bukkit.entity.Villager;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.Method;
@@ -41,6 +45,7 @@ public final class MobCompat {
public static final EntityType AXOLOTL = getEntityType("AXOLOTL");
public static final EntityType GOAT = getEntityType("GOAT");
public static final EntityType FROG = getEntityType("FROG");
public static final EntityType CAMEL = getEntityType("CAMEL");
// Constants for mobs that have changed since earlier versions
public static final EntityType CAT = getEntityType("CAT", "OCELOT");
@@ -195,6 +200,19 @@ public final class MobCompat {
}
}
public static void setCamelSaddle(final Entity entity, final Player target) {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_20_1_R01)) {
return;
}
if (entity instanceof Camel) {
final Camel camel = (Camel) entity;
camel.setTamed(true);
camel.setOwner(target);
camel.getInventory().setSaddle(new ItemStack(Material.SADDLE, 1));
}
}
public enum CatType {
// These are (loosely) Mojang names for the cats
SIAMESE("SIAMESE", "SIAMESE_CAT"),
@@ -1,6 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.earth2me.essentials.utils.VersionUtil;
@@ -209,6 +209,7 @@ public enum MobData {
MANGROVE_BOAT("mangrove", Boat.class, MobCompat.BoatVariant.MANGROVE, true),
OAK_BOAT("oak", Boat.class, MobCompat.BoatVariant.OAK, true),
SPRUCE_BOAT("spruce", Boat.class, MobCompat.BoatVariant.SPRUCE, true),
SADDLE_CAMEL("saddle", MobCompat.CAMEL, Data.CAMELSADDLE, true),
;
final private String nickname;
@@ -362,8 +363,8 @@ public enum MobData {
((Horse) spawned).getInventory().setArmor(new ItemStack((Material) this.value, 1));
} else if (this.type.equals(EntityType.ZOMBIE.getEntityClass()) || this.type.equals(EntityType.SKELETON)) {
final EntityEquipment invent = ((LivingEntity) spawned).getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack((Material) this.value, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
Inventories.setItemInMainHand(invent, new ItemStack((Material) this.value, 1));
Inventories.setItemInMainHandDropChance(invent, 0.1f);
}
} else if (this.value.equals(Data.RAID_LEADER)) {
((Raider) spawned).setPatrolLeader(true);
@@ -387,6 +388,8 @@ public enum MobData {
}
} else if (this.value.equals(Data.GOAT_SCREAMING)) {
((Goat) spawned).setScreaming(true);
} else if (this.value.equals(Data.CAMELSADDLE)) {
MobCompat.setCamelSaddle(spawned, target);
} else if (this.value instanceof MobCompat.BoatVariant) {
MobCompat.setBoatVariant(spawned, (MobCompat.BoatVariant) this.value);
} else if (this.value instanceof String) {
@@ -446,5 +449,6 @@ public enum MobData {
FISH_BODY_COLOR,
FISH_PATTERN_COLOR,
GOAT_SCREAMING,
CAMELSADDLE,
}
}
@@ -55,9 +55,9 @@ public final class PlayerList {
int playerHidden = 0;
int hiddenCount = 0;
for (final User onlinePlayer : ess.getOnlineUsers()) {
if (onlinePlayer.isHidden() || (user != null && !user.getBase().canSee(onlinePlayer.getBase()))) {
if (onlinePlayer.isHidden() || (user != null && onlinePlayer.isHiddenFrom(user.getBase()))) {
playerHidden++;
if (showHidden || user != null && user.getBase().canSee(onlinePlayer.getBase())) {
if (showHidden || user != null && !onlinePlayer.isHiddenFrom(user.getBase())) {
hiddenCount++;
}
}
@@ -75,7 +75,7 @@ public final class PlayerList {
public static Map<String, List<User>> getPlayerLists(final IEssentials ess, final IUser sender, final boolean showHidden) {
final Map<String, List<User>> playerList = new HashMap<>();
for (final User onlineUser : ess.getOnlineUsers()) {
if ((sender == null && !showHidden && onlineUser.isHidden()) || (sender != null && !showHidden && !sender.getBase().canSee(onlineUser.getBase()))) {
if ((sender == null && !showHidden && onlineUser.isHidden()) || (sender != null && !showHidden && onlineUser.isHiddenFrom(sender.getBase()))) {
continue;
}
final String group = FormatUtil.stripFormat(FormatUtil.stripEssentialsFormat(onlineUser.getGroup().toLowerCase()));
@@ -4,15 +4,17 @@ import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import java.util.UUID;
public class PlayerTarget implements ITarget {
private final String name;
private final UUID uuid;
public PlayerTarget(final Player entity) {
this.name = entity.getName();
this.uuid = entity.getUniqueId();
}
@Override
public Location getLocation() {
return Bukkit.getServer().getPlayerExact(name).getLocation();
return Bukkit.getPlayer(uuid).getLocation();
}
}
@@ -1469,10 +1469,16 @@ public class Settings implements net.ess3.api.ISettings {
// #easteregg
@Override
public int getMaxUserCacheCount() {
final long count = Runtime.getRuntime().maxMemory() / 1024 / 96;
final long count = Runtime.getRuntime().maxMemory() / 1024 / 1024;
return config.getInt("max-user-cache-count", (int) count);
}
// #easteregg
@Override
public long getMaxUserCacheValueExpiry() {
return config.getLong("max-user-cache-value-expiry", 600);
}
@Override
public boolean isLastMessageReplyRecipient() {
return config.getBoolean("last-message-reply-recipient", false);
@@ -1,7 +1,7 @@
package com.earth2me.essentials;
import com.earth2me.essentials.Mob.MobException;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.LocationUtil;
import com.earth2me.essentials.utils.StringUtil;
@@ -251,8 +251,8 @@ public final class SpawnMob {
private static void defaultMobData(final EntityType type, final Entity spawned) {
if (type == EntityType.SKELETON) {
final EntityEquipment invent = ((LivingEntity) spawned).getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack(Material.BOW, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
Inventories.setItemInMainHand(invent, new ItemStack(Material.BOW, 1));
Inventories.setItemInMainHandDropChance(invent, 0.1f);
}
if (type == MobCompat.ZOMBIFIED_PIGLIN) {
@@ -260,8 +260,8 @@ public final class SpawnMob {
setVillager(zombie, false);
final EntityEquipment invent = zombie.getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack(GOLDEN_SWORD, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
Inventories.setItemInMainHand(invent, new ItemStack(GOLDEN_SWORD, 1));
Inventories.setItemInMainHandDropChance(invent, 0.1f);
}
if (type == EntityType.ZOMBIE) {
@@ -1,51 +1,22 @@
package com.earth2me.essentials;
import net.ess3.api.IEssentials;
import org.bukkit.entity.LivingEntity;
import com.earth2me.essentials.commands.Commandnuke;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent;
public class TNTExplodeListener implements Listener, Runnable {
private final transient IEssentials ess;
private transient boolean enabled = false;
private transient int timer = -1;
public TNTExplodeListener(final IEssentials ess) {
super();
this.ess = ess;
}
public void enable() {
if (!enabled) {
enabled = true;
timer = ess.scheduleSyncDelayedTask(this, 200);
return;
}
if (timer != -1) {
ess.getScheduler().cancelTask(timer);
timer = ess.scheduleSyncDelayedTask(this, 200);
}
}
public class TNTExplodeListener implements Listener {
@EventHandler(priority = EventPriority.LOW)
public void onEntityExplode(final EntityExplodeEvent event) {
if (!enabled) {
if (!(event.getEntity() instanceof TNTPrimed)) {
return;
}
if (event.getEntity() instanceof LivingEntity) {
return;
}
if (event.blockList().size() < 1) {
if (!event.getEntity().hasMetadata(Commandnuke.NUKE_META_KEY)) {
return;
}
event.setCancelled(true);
event.getLocation().getWorld().createExplosion(event.getLocation(), 0F);
}
@Override
public void run() {
enabled = false;
}
}
@@ -1,6 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.craftbukkit.SetExpFix;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.VersionUtil;
@@ -8,7 +8,6 @@ import net.ess3.api.IEssentials;
import net.ess3.api.IUser;
import net.ess3.api.MaxMoneyException;
import org.bukkit.Location;
import org.bukkit.entity.Item;
import org.bukkit.inventory.ItemStack;
import java.io.File;
@@ -16,6 +15,7 @@ import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
@@ -197,7 +197,7 @@ public class Trade {
return;
}
if (getItemStack() != null && !user.getBase().getInventory().containsAtLeast(itemStack, itemStack.getAmount())) {
if (getItemStack() != null && !Inventories.containsAtLeast(user.getBase(), itemStack, itemStack.getAmount())) {
future.completeExceptionally(new ChargeException(tl("missingItems", getItemStack().getAmount(), ess.getItemDb().name(getItemStack()))));
return;
}
@@ -225,52 +225,33 @@ public class Trade {
user.giveMoney(getMoney());
}
if (getItemStack() != null) {
// This stores the would be overflow
final Map<Integer, ItemStack> overFlow = InventoryWorkaround.addAllItems(user.getBase().getInventory(), getItemStack());
if (type == OverflowType.ABORT && !Inventories.hasSpace(user.getBase(), 0, false, getItemStack())) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "abort paying " + user.getName() + " itemstack " + getItemStack().toString() + " due to lack of inventory space ");
}
return Collections.singletonMap(0, getItemStack());
}
if (overFlow != null) {
switch (type) {
case ABORT:
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "abort paying " + user.getName() + " itemstack " + getItemStack().toString() + " due to lack of inventory space ");
final Map<Integer, ItemStack> leftover = Inventories.addItem(user.getBase(), getItemStack());
user.getBase().updateInventory();
if (!leftover.isEmpty()) {
if (type == OverflowType.RETURN) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " with overflow " + leftover.get(0).toString());
}
return leftover;
} else {
for (final ItemStack itemStack : leftover.values()) {
int spillAmount = itemStack.getAmount();
itemStack.setAmount(Math.min(spillAmount, itemStack.getMaxStackSize()));
while (spillAmount > 0) {
user.getBase().getWorld().dropItemNaturally(user.getBase().getLocation(), itemStack);
spillAmount -= itemStack.getAmount();
}
return overFlow;
case RETURN:
// Pay the user the items, and return overflow
final Map<Integer, ItemStack> returnStack = InventoryWorkaround.addItems(user.getBase().getInventory(), getItemStack());
user.getBase().updateInventory();
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " with overflow " + returnStack.get(0).toString());
}
return returnStack;
case DROP:
// Pay the users the items directly, and drop the rest, will always return no overflow.
final Map<Integer, ItemStack> leftOver = InventoryWorkaround.addItems(user.getBase().getInventory(), getItemStack());
final Location loc = user.getBase().getLocation();
for (final ItemStack loStack : leftOver.values()) {
final int maxStackSize = loStack.getType().getMaxStackSize();
final int stacks = loStack.getAmount() / maxStackSize;
final int leftover = loStack.getAmount() % maxStackSize;
final Item[] itemStacks = new Item[stacks + (leftover > 0 ? 1 : 0)];
for (int i = 0; i < stacks; i++) {
final ItemStack stack = loStack.clone();
stack.setAmount(maxStackSize);
itemStacks[i] = loc.getWorld().dropItem(loc, stack);
}
if (leftover > 0) {
final ItemStack stack = loStack.clone();
stack.setAmount(leftover);
itemStacks[stacks] = loc.getWorld().dropItem(loc, stack);
}
}
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " and dropping overflow " + leftOver.get(0).toString());
}
break;
}
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " and dropping overflow " + leftover.get(0).toString());
}
}
} else if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " itemstack " + getItemStack().toString());
@@ -315,11 +296,11 @@ public class Trade {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "charging user " + user.getName() + " itemstack " + getItemStack().toString());
}
if (!user.getBase().getInventory().containsAtLeast(getItemStack(), getItemStack().getAmount())) {
if (!Inventories.containsAtLeast(user.getBase(), getItemStack(), getItemStack().getAmount())) {
future.completeExceptionally(new ChargeException(tl("missingItems", getItemStack().getAmount(), getItemStack().getType().toString().toLowerCase(Locale.ENGLISH).replace("_", " "))));
return;
}
user.getBase().getInventory().removeItem(getItemStack());
Inventories.removeItemAmount(user.getBase(), getItemStack(), getItemStack().getAmount());
user.getBase().updateInventory();
}
if (command != null) {
@@ -1,155 +1,19 @@
package com.earth2me.essentials;
import com.google.common.io.Files;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.regex.Pattern;
@Deprecated
public class UUIDMap {
private static final ScheduledExecutorService writeScheduler = Executors.newScheduledThreadPool(1);
private static boolean pendingWrite;
private static boolean loading = false;
private final transient net.ess3.api.IEssentials ess;
private final File userList;
private final transient Pattern splitPattern = Pattern.compile(",");
private final Runnable writeTaskRunnable;
public UUIDMap(final net.ess3.api.IEssentials ess) {
this.ess = ess;
userList = new File(ess.getDataFolder(), "usermap.csv");
pendingWrite = false;
writeTaskRunnable = () -> {
if (pendingWrite) {
try {
new WriteRunner(ess.getDataFolder(), userList, ess.getUserMap().getNames()).run();
} catch (final Throwable t) { // bad code to prevent task from being suppressed
t.printStackTrace();
}
}
};
writeScheduler.scheduleWithFixedDelay(writeTaskRunnable, 5, 5, TimeUnit.SECONDS);
}
public void loadAllUsers(final ConcurrentSkipListMap<String, UUID> names, final ConcurrentSkipListMap<UUID, ArrayList<String>> history) {
try {
if (!userList.exists()) {
userList.createNewFile();
}
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "Reading usermap from disk");
}
if (loading) {
return;
}
names.clear();
history.clear();
loading = true;
try (final BufferedReader reader = new BufferedReader(new FileReader(userList))) {
while (true) {
final String line = reader.readLine();
if (line == null) {
break;
} else {
final String[] values = splitPattern.split(line);
if (values.length == 2) {
final String name = values[0];
final UUID uuid = UUID.fromString(values[1]);
names.put(name, uuid);
if (!history.containsKey(uuid)) {
final ArrayList<String> list = new ArrayList<>();
list.add(name);
history.put(uuid, list);
} else {
final ArrayList<String> list = history.get(uuid);
if (!list.contains(name)) {
list.add(name);
}
}
}
}
}
}
loading = false;
} catch (final IOException ex) {
Essentials.getWrappedLogger().log(Level.SEVERE, ex.getMessage(), ex);
}
public UUIDMap() {
}
public void writeUUIDMap() {
pendingWrite = true;
//no-op
}
public void forceWriteUUIDMap() {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "Forcing usermap write to disk");
}
pendingWrite = true;
writeTaskRunnable.run();
//no-op
}
public void shutdown() {
writeScheduler.submit(writeTaskRunnable);
writeScheduler.shutdown();
}
private static final class WriteRunner implements Runnable {
private final File location;
private final File endFile;
private final Map<String, UUID> names;
private WriteRunner(final File location, final File endFile, final Map<String, UUID> names) {
this.location = location;
this.endFile = endFile;
this.names = new HashMap<>(names);
}
@Override
public void run() {
pendingWrite = false;
if (loading || names.isEmpty()) {
return;
}
File configFile = null;
try {
configFile = File.createTempFile("usermap", ".tmp.csv", location);
final BufferedWriter bWriter = new BufferedWriter(new FileWriter(configFile));
for (final Map.Entry<String, UUID> entry : names.entrySet()) {
bWriter.write(entry.getKey() + "," + entry.getValue().toString());
bWriter.newLine();
}
bWriter.close();
Files.move(configFile, endFile);
} catch (final IOException ex) {
try {
if (configFile != null && configFile.exists()) {
Files.move(configFile, new File(endFile.getParentFile(), "usermap.bak.csv"));
}
} catch (final Exception ex2) {
Essentials.getWrappedLogger().log(Level.SEVERE, ex2.getMessage(), ex2);
}
Essentials.getWrappedLogger().log(Level.WARNING, ex.getMessage(), ex);
}
}
//no-op
}
}
@@ -1,6 +1,7 @@
package com.earth2me.essentials;
import com.earth2me.essentials.commands.IEssentialsCommand;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.economy.EconomyLayer;
import com.earth2me.essentials.economy.EconomyLayers;
import com.earth2me.essentials.messaging.IMessageRecipient;
@@ -27,7 +28,6 @@ import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
@@ -90,6 +90,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
private String lastHomeConfirmation;
private long lastHomeConfirmationTimestamp;
private Boolean toggleShout;
private boolean freeze = false;
private transient final List<String> signCopy = Lists.newArrayList("", "", "", "");
private transient long lastVanishTime = System.currentTimeMillis();
@@ -106,7 +107,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
this.messageRecipient = new SimpleMessageRecipient(ess, this);
}
void update(final Player base) {
public void update(final Player base) {
setBase(base);
}
@@ -151,7 +152,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
private boolean isAuthorizedCheck(final String node) {
if (base instanceof OfflinePlayer) {
if (base instanceof OfflinePlayerStub) {
return false;
}
@@ -169,7 +170,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
private boolean isPermSetCheck(final String node) {
if (base instanceof OfflinePlayer) {
if (base instanceof OfflinePlayerStub) {
return false;
}
@@ -187,7 +188,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
private TriState isAuthorizedExactCheck(final String node) {
if (base instanceof OfflinePlayer) {
if (base instanceof OfflinePlayerStub) {
return TriState.UNSET;
}
@@ -310,7 +311,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
private void _dispose() {
if (!base.isOnline()) {
this.base = new OfflinePlayer(getConfigUUID(), ess.getServer());
this.base = new OfflinePlayerStub(getConfigUUID(), ess.getServer());
}
cleanup();
}
@@ -464,7 +465,11 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
} else if (nick.equalsIgnoreCase(getName())) {
nickname = nick;
} else {
nickname = FormatUtil.replaceFormat(ess.getSettings().getNicknamePrefix()) + nick;
if (isAuthorized("essentials.nick.hideprefix")) {
nickname = nick;
} else {
nickname = FormatUtil.replaceFormat(ess.getSettings().getNicknamePrefix()) + nick;
}
suffix = "§r";
}
@@ -674,6 +679,9 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
@Override
public boolean isHiddenFrom(Player player) {
if (getBase() instanceof OfflinePlayerStub || player instanceof OfflinePlayerStub) {
return true;
}
return !player.canSee(getBase());
}
@@ -701,7 +709,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
public boolean isHidden(final Player player) {
return hidden || !player.canSee(getBase());
return hidden || isHiddenFrom(player);
}
@Override
@@ -1137,12 +1145,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
* Returns the {@link ItemStack} in the main hand or off-hand. If the main hand is empty then the offhand item is returned - also nullable.
*/
public ItemStack getItemInHand() {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_9_R01)) {
return getBase().getInventory().getItemInHand();
} else {
final PlayerInventory inventory = getBase().getInventory();
return inventory.getItemInMainHand() != null ? inventory.getItemInMainHand() : inventory.getItemInOffHand();
}
return Inventories.getItemInHand(getBase());
}
@Override
@@ -1192,6 +1195,16 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return signCopy;
}
@Override
public boolean isFreeze() {
return freeze;
}
@Override
public void setFreeze(boolean freeze) {
this.freeze = freeze;
}
public boolean isBaltopExempt() {
if (getBase().isOnline()) {
final boolean exempt = isAuthorized("essentials.balancetop.exclude");
@@ -5,6 +5,7 @@ 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.userstorage.ModernUserMap;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.base.Charsets;
@@ -16,7 +17,6 @@ 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;
@@ -43,19 +43,14 @@ public abstract class UserData extends PlayerExtension implements IConf {
super(base);
this.ess = ess;
final File folder = new File(ess.getDataFolder(), "userdata");
if (!folder.exists()) {
folder.mkdirs();
if (!folder.exists() && !folder.mkdirs()) {
throw new RuntimeException("Unable to create userdata folder!");
}
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"));
config = new EssentialsUserConfiguration(base.getName(), base.getUniqueId(), new File(folder, base.getUniqueId() + ".yml"));
config.setSaveHook(() -> {
config.setRootHolder(UserConfigHolder.class, holder);
});
reloadConfig();
if (config.getUsername() == null) {
@@ -65,12 +60,15 @@ public abstract class UserData extends PlayerExtension implements IConf {
public final void reset() {
config.blockingSave();
config.getFile().delete();
if (!config.getFile().delete()) {
ess.getLogger().warning("Unable to delete data file for " + config.getFile().getName());
}
if (config.getUsername() != null) {
ess.getUserMap().removeUser(config.getUsername());
final ModernUserMap users = (ModernUserMap) ess.getUsers();
users.invalidate(config.getUuid());
if (isNPC()) {
final String uuid = UUID.nameUUIDFromBytes(("NPC:" + StringUtil.safeString(config.getUsername())).getBytes(Charsets.UTF_8)).toString();
ess.getUserMap().removeUserUUID(uuid);
final String name = ess.getSettings().isSafeUsermap() ? StringUtil.safeString(config.getUsername()) : config.getUsername();
users.invalidate(UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8)));
}
}
}
@@ -84,18 +82,10 @@ public abstract class UserData extends PlayerExtension implements IConf {
config.load();
try {
holder = config.getRootNode().get(UserConfigHolder.class);
} catch (SerializationException e) {
} catch (Throwable e) {
ess.getLogger().log(Level.SEVERE, "Error while reading user config: " + config.getFile().getName(), 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: " + config.getFile().getName(), e);
throw new RuntimeException(e);
}
});
money = _getMoney();
}
@@ -208,6 +198,16 @@ public abstract class UserData extends PlayerExtension implements IConf {
}
}
public void renameHome(final String name, final String newName) throws Exception {
final LazyLocation location = holder.homes().remove(name);
if (location != null) {
holder.homes().put(StringUtil.safeString(newName), location);
config.save();
} else {
throw new Exception(tl("invalidHome", name));
}
}
public boolean hasHome() {
return !holder.homes().isEmpty();
}
@@ -589,9 +589,13 @@ public abstract class UserData extends PlayerExtension implements IConf {
}
public void setLastAccountName(final String lastAccountName) {
if (getLastAccountName() != null && !getLastAccountName().equals(lastAccountName)) {
final List<String> usernames = holder.pastUsernames();
usernames.add(0, getLastAccountName());
holder.pastUsernames(usernames);
}
holder.lastAccountName(lastAccountName);
config.save();
ess.getUserMap().trackUUID(getConfigUUID(), lastAccountName, true);
}
public boolean arePowerToolsEnabled() {
@@ -722,6 +726,17 @@ public abstract class UserData extends PlayerExtension implements IConf {
config.save();
}
public List<String> getPastUsernames() {
return holder.pastUsernames();
}
public void addPastUsername(String username) {
final List<String> usernames = holder.pastUsernames();
usernames.add(0, username);
holder.pastUsernames(usernames);
config.save();
}
public boolean isShouting() {
if (holder.shouting() == null) {
holder.shouting(ess.getSettings().isShoutDefault());
@@ -1,383 +1,70 @@
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;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import net.ess3.api.IEssentials;
import net.ess3.api.MaxMoneyException;
import com.earth2me.essentials.userstorage.ModernUserMap;
import org.bukkit.Bukkit;
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;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.regex.Pattern;
public class UserMap extends CacheLoader<String, User> implements IConf {
private static boolean legacy = false;
private static Method getLegacy;
private final transient IEssentials ess;
private final transient ConcurrentSkipListSet<UUID> keys = new ConcurrentSkipListSet<>();
private final transient ConcurrentSkipListMap<String, UUID> names = new ConcurrentSkipListMap<>();
private final transient ConcurrentSkipListMap<UUID, ArrayList<String>> history = new ConcurrentSkipListMap<>();
private final UUIDMap uuidMap;
private final transient Cache<String, User> users;
private final Pattern validUserPattern = Pattern.compile("^[a-zA-Z0-9_]{2,16}$");
@Deprecated
public class UserMap {
private final transient ModernUserMap userMap;
private final transient UUIDMap uuidMap;
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;
uuidMap = new UUIDMap(ess);
//RemovalListener<UUID, User> remListener = new UserMapRemovalListener();
//users = CacheBuilder.newBuilder().maximumSize(ess.getSettings().getMaxUserCacheCount()).softValues().removalListener(remListener).build(this);
final CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder();
final int maxCount = ess.getSettings().getMaxUserCacheCount();
try {
cacheBuilder.maximumSize(maxCount);
} catch (final NoSuchMethodError nsme) {
legacy = true;
legacyMaximumSize(cacheBuilder, maxCount);
}
cacheBuilder.softValues();
if (!legacy) {
users = cacheBuilder.build(this);
} else {
users = legacyBuild(cacheBuilder);
}
}
private void loadAllUsersAsync(final IEssentials ess) {
ess.runTaskAsynchronously(() -> {
synchronized (users) {
final File userdir = new File(ess.getDataFolder(), "userdata");
if (!userdir.exists()) {
return;
}
keys.clear();
users.invalidateAll();
for (final String string : userdir.list()) {
if (!string.endsWith(".yml")) {
continue;
}
final String name = string.substring(0, string.length() - 4);
try {
keys.add(UUID.fromString(name));
} catch (final IllegalArgumentException ex) {
//Ignore these users till they rejoin.
}
}
uuidMap.loadAllUsers(names, history);
}
});
}
public boolean userExists(final UUID uuid) {
return keys.contains(uuid);
public UserMap(final ModernUserMap userMap) {
this.userMap = userMap;
this.uuidMap = new UUIDMap();
}
public User getUser(final String name) {
final String sanitizedName = StringUtil.safeString(name);
try {
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.");
final User user = new User(new OfflinePlayer(sanitizedName, ess.getServer()), ess);
trackUUID(user.getBase().getUniqueId(), user.getName(), true);
return user;
}
return null;
} catch (final UncheckedExecutionException ex) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.WARNING, ex, () -> String.format("Exception while getting user for %s (%s)", name, sanitizedName));
}
return null;
}
return userMap.getUser(name);
}
public User getUser(final UUID uuid) {
try {
if (!legacy) {
return ((LoadingCache<String, User>) users).get(uuid.toString());
} else {
return legacyCacheGet(uuid);
}
} catch (final ExecutionException | UncheckedExecutionException ex) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.WARNING, ex, () -> "Exception while getting user for " + uuid);
}
return null;
}
return userMap.getUser(uuid);
}
public void trackUUID(final UUID uuid, final String name, final boolean replace) {
if (uuid != null) {
keys.add(uuid);
if (name != null && name.length() > 0) {
final String keyName = ess.getSettings().isSafeUsermap() ? StringUtil.safeString(name) : name;
if (!names.containsKey(keyName)) {
names.put(keyName, uuid);
uuidMap.writeUUIDMap();
} else if (!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 {
ess.getLogger().log(Level.INFO, MessageFormat.format(WARN_UUID_NOT_REPLACE, uuid.toString(), name, names.get(keyName).toString()), new RuntimeException());
}
}
}
}
// no-op
}
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);
Player player = ess.getServer().getPlayer(uuid);
if (player != null) {
final User user = new User(player, ess);
trackUUID(uuid, user.getName(), true);
return user;
}
final File userFile = getUserFileFromID(uuid);
if (userFile.exists()) {
player = new OfflinePlayer(uuid, ess.getServer());
final User user = new User(player, ess);
((OfflinePlayer) player).setName(user.getLastAccountName());
trackUUID(uuid, user.getName(), false);
return user;
}
throw new Exception("User not found!");
return userMap.load(UUID.fromString(stringUUID));
}
public User load(final org.bukkit.OfflinePlayer player) throws UserDoesNotExistException {
if (player == null) {
throw new IllegalArgumentException("Player cannot be null!");
}
final Player userPlayer;
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());
userPlayer = (Player) player;
} 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();
final OfflinePlayerStub essPlayer = new OfflinePlayerStub(player.getUniqueId(), Bukkit.getServer());
essPlayer.setName(player.getName());
userPlayer = essPlayer;
}
trackUUID(player.getUniqueId(), user.getName(), false);
final User user = userMap.getUser(userPlayer);
if (user == null) {
throw new UserDoesNotExistException("User not found");
}
return user;
}
@Override
public void reloadConfig() {
getUUIDMap().forceWriteUUIDMap();
loadAllUsersAsync(ess);
}
public void invalidateAll() {
users.invalidateAll();
}
public void removeUser(final String name) {
if (names == null) {
ess.getLogger().warning("Name collection is null, cannot remove user.");
return;
}
final UUID uuid = names.get(name);
if (uuid != null) {
keys.remove(uuid);
users.invalidate(uuid.toString());
}
names.remove(name);
names.remove(StringUtil.safeString(name));
}
public void removeUserUUID(final String uuid) {
users.invalidate(uuid);
}
public Set<UUID> getAllUniqueUsers() {
return Collections.unmodifiableSet(keys);
return userMap.getAllUserUUIDs();
}
public int getUniqueUsers() {
return keys.size();
return userMap.getUserCount();
}
protected ConcurrentSkipListMap<String, UUID> getNames() {
return names;
}
protected ConcurrentSkipListMap<UUID, ArrayList<String>> getHistory() {
return history;
}
public List<String> getUserHistory(final UUID uuid) {
return history.get(uuid);
return new ConcurrentSkipListMap<>(userMap.getNameCache());
}
public UUIDMap getUUIDMap() {
return uuidMap;
}
// class UserMapRemovalListener implements RemovalListener
// {
// @Override
// public void onRemoval(final RemovalNotification notification)
// {
// Object value = notification.getValue();
// if (value != null)
// {
// ((User)value).cleanup();
// }
// }
// }
private File getUserFileFromID(final UUID uuid) {
final File userFolder = new File(ess.getDataFolder(), "userdata");
return new File(userFolder, uuid.toString() + ".yml");
}
public File getUserFileFromString(final String name) {
final File userFolder = new File(ess.getDataFolder(), "userdata");
return new File(userFolder, StringUtil.sanitizeFileName(name) + ".yml");
}
@SuppressWarnings("deprecation")
public User getUserFromBukkit(String name) {
name = StringUtil.safeString(name);
if (ess.getSettings().isDebug()) {
ess.getLogger().warning("Using potentially blocking Bukkit UUID lookup for: " + name);
}
// Don't attempt to look up entirely invalid usernames
if (name == null || !validUserPattern.matcher(name).matches()) {
return null;
}
final org.bukkit.OfflinePlayer offlinePlayer = ess.getServer().getOfflinePlayer(name);
if (offlinePlayer == null) {
return null;
}
final UUID uuid;
try {
uuid = offlinePlayer.getUniqueId();
} catch (final UnsupportedOperationException | NullPointerException e) {
return null;
}
// This is how Bukkit generates fake UUIDs
if (UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)).equals(uuid)) {
return null;
} else {
names.put(name, uuid);
return getUser(uuid);
}
}
private User legacyCacheGet(final UUID uuid) {
if (getLegacy == null) {
final Class<?> usersClass = users.getClass();
for (final Method m : usersClass.getDeclaredMethods()) {
if (m.getName().equals("get")) {
getLegacy = m;
getLegacy.setAccessible(true);
break;
}
}
}
try {
return (User) getLegacy.invoke(users, uuid.toString());
} catch (final IllegalAccessException | InvocationTargetException e) {
return null;
}
}
private void legacyMaximumSize(final CacheBuilder builder, final int maxCount) {
try {
final Method maxSizeLegacy = builder.getClass().getDeclaredMethod("maximumSize", Integer.TYPE);
maxSizeLegacy.setAccessible(true);
maxSizeLegacy.invoke(builder, maxCount);
} catch (final NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
private Cache<String, User> legacyBuild(final CacheBuilder builder) {
Method build = null;
for (final Method method : builder.getClass().getDeclaredMethods()) {
if (method.getName().equals("build")) {
build = method;
break;
}
}
Cache<String, User> legacyUsers;
try {
assert build != null;
build.setAccessible(true);
legacyUsers = (Cache<String, User>) build.invoke(builder, this);
} catch (final IllegalAccessException | InvocationTargetException e) {
legacyUsers = null;
}
return legacyUsers;
}
}
@@ -121,7 +121,7 @@ public class Warps implements IConf, net.ess3.api.IWarps {
public final void reloadConfig() {
warpPoints.clear();
final File[] listOfFiles = warpsFolder.listFiles();
if (listOfFiles.length >= 1) {
if (listOfFiles != null) {
for (final File listOfFile : listOfFiles) {
final String filename = listOfFile.getName();
if (listOfFile.isFile() && filename.endsWith(".yml")) {
@@ -3,6 +3,7 @@ package com.earth2me.essentials;
import com.earth2me.essentials.commands.NotEnoughArgumentsException;
import com.earth2me.essentials.config.ConfigurateUtil;
import com.earth2me.essentials.config.EssentialsConfiguration;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
@@ -101,7 +102,7 @@ public class Worth implements IConf {
}
int max = 0;
for (final ItemStack s : user.getBase().getInventory().getContents()) {
for (final ItemStack s : Inventories.getInventory(user.getBase(), false)) {
if (s == null || !s.isSimilar(is)) {
continue;
}
@@ -3,6 +3,7 @@ package com.earth2me.essentials.api;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.config.EssentialsUserConfiguration;
import com.earth2me.essentials.userstorage.ModernUserMap;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.base.Charsets;
@@ -41,9 +42,9 @@ public class Economy {
ess = aEss;
}
private static void createNPCFile(String name) {
private static void createNPCFile(final String unsanitizedName) {
final File folder = new File(ess.getDataFolder(), "userdata");
name = StringUtil.safeString(name);
final String name = ess.getSettings().isSafeUsermap() ? StringUtil.safeString(unsanitizedName) : unsanitizedName;
if (!folder.exists()) {
if (!folder.mkdirs()) {
throw new RuntimeException("Error while creating userdata directory!");
@@ -59,9 +60,12 @@ public class Economy {
npcConfig.load();
npcConfig.setProperty("npc", true);
npcConfig.setProperty("last-account-name", name);
npcConfig.setProperty("npc-name", unsanitizedName);
npcConfig.setProperty("money", ess.getSettings().getStartingBalance());
npcConfig.blockingSave();
ess.getUserMap().trackUUID(npcUUID, name, false);
// This will load the NPC into the UserMap + UUID cache
((ModernUserMap) ess.getUsers()).addCachedNpcName(npcUUID, name);
ess.getUsers().getUser(npcUUID);
}
private static void deleteNPC(final String name) {
@@ -7,6 +7,7 @@ import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import net.essentialsx.api.v2.services.BalanceTop;
import org.bukkit.Server;
import org.bukkit.command.BlockCommandSender;
import java.math.BigDecimal;
import java.text.DateFormat;
@@ -32,8 +33,15 @@ public class Commandbalancetop extends EssentialsCommand {
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(ess.getBalanceTop().getCacheAge());
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);
final Runnable runnable = () -> {
sender.sendMessage(tl("balanceTop", format.format(cal.getTime())));
new TextPager(cache).showPage(Integer.toString(page), null, "balancetop", sender);
};
if (sender.getSender() instanceof BlockCommandSender) {
ess.scheduleSyncDelayedTask(runnable);
} else {
runnable.run();
}
}
@Override
@@ -56,8 +64,8 @@ public class Commandbalancetop extends EssentialsCommand {
}
// If there are less than 50 users in our usermap, there is no need to display a warning as these calculations should be done quickly
if (ess.getUserMap().getUniqueUsers() > MINUSERS) {
sender.sendMessage(tl("orderBalances", ess.getUserMap().getUniqueUsers()));
if (ess.getUsers().getUserCount() > MINUSERS) {
sender.sendMessage(tl("orderBalances", ess.getUsers().getUserCount()));
}
ess.runTaskAsynchronously(new Viewer(sender, page, force));
@@ -2,7 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Console;
import com.earth2me.essentials.OfflinePlayer;
import com.earth2me.essentials.OfflinePlayerStub;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.BanList;
@@ -30,7 +30,7 @@ public class Commandban extends EssentialsCommand {
user = getPlayer(server, args, 0, true, true);
} catch (final PlayerNotFoundException e) {
nomatch = true;
user = ess.getUser(new OfflinePlayer(args[0], ess.getServer()));
user = ess.getUser(new OfflinePlayerStub(args[0], ess.getServer()));
}
if (!user.getBase().isOnline()) {
if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.ban.offline")) {
@@ -54,7 +54,7 @@ public class Commandban extends EssentialsCommand {
final String banDisplay = tl("banFormat", banReason, senderDisplayName);
user.getBase().kickPlayer(banDisplay);
server.getLogger().log(Level.INFO, tl("playerBanned", senderDisplayName, user.getName(), banDisplay));
ess.getLogger().log(Level.INFO, tl("playerBanned", senderDisplayName, user.getName(), banDisplay));
if (nomatch) {
sender.sendMessage(tl("userUnknown", user.getName()));
@@ -54,7 +54,7 @@ public class Commandbanip extends EssentialsCommand {
final String banDisplay = tl("banFormat", banReason, senderDisplayName);
ess.getServer().getBanList(BanList.Type.IP).addBan(ipAddress, banReason, null, senderName);
server.getLogger().log(Level.INFO, tl("playerBanIpAddress", senderDisplayName, ipAddress, banReason));
ess.getLogger().log(Level.INFO, tl("playerBanIpAddress", senderDisplayName, ipAddress, banReason));
for (final Player player : ess.getServer().getOnlinePlayers()) {
if (player.getAddress().getAddress().getHostAddress().equalsIgnoreCase(ipAddress)) {
@@ -2,7 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.EnumUtil;
import com.google.common.collect.Lists;
import org.bukkit.Material;
@@ -25,7 +25,7 @@ public class Commandbook extends EssentialsCommand {
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final ItemStack item = user.getItemInHand();
final ItemStack item = Inventories.getItemInMainHand(user.getBase());
final String player = user.getName();
if (item.getType() == Material.WRITTEN_BOOK) {
final BookMeta bmeta = (BookMeta) item.getItemMeta();
@@ -52,7 +52,7 @@ public class Commandbook extends EssentialsCommand {
if (isAuthor(bmeta, player) || user.isAuthorized("essentials.book.others")) {
final ItemStack newItem = new ItemStack(WRITABLE_BOOK, item.getAmount());
newItem.setItemMeta(bmeta);
InventoryWorkaround.setItemInMainHand(user.getBase(), newItem);
Inventories.setItemInMainHand(user.getBase(), newItem);
user.sendMessage(tl("editBookContents"));
} else {
throw new Exception(tl("denyBookEdit"));
@@ -65,7 +65,7 @@ public class Commandbook extends EssentialsCommand {
}
final ItemStack newItem = new ItemStack(Material.WRITTEN_BOOK, item.getAmount());
newItem.setItemMeta(bmeta);
InventoryWorkaround.setItemInMainHand(user.getBase(), newItem);
Inventories.setItemInMainHand(user.getBase(), newItem);
user.sendMessage(tl("bookLocked"));
} else {
throw new Exception(tl("holdBook"));
@@ -0,0 +1,36 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.LocationUtil;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.event.player.PlayerTeleportEvent;
import java.util.concurrent.CompletableFuture;
import static com.earth2me.essentials.I18n.tl;
public class Commandbottom extends EssentialsCommand {
public Commandbottom() {
super("bottom");
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final int bottomX = user.getLocation().getBlockX();
final int bottomZ = user.getLocation().getBlockZ();
final float pitch = user.getLocation().getPitch();
final float yaw = user.getLocation().getYaw();
final Location unsafe = new Location(user.getWorld(), bottomX, ess.getWorldInfoProvider().getMinHeight(user.getWorld()), bottomZ, yaw, pitch);
final Location safe = LocationUtil.getSafeDestination(ess, unsafe);
final CompletableFuture<Boolean> future = getNewExceptionFuture(user.getSource(), commandLabel);
future.thenAccept(success -> {
if (success) {
user.sendMessage(tl("teleportBottom", safe.getWorld().getName(), safe.getBlockX(), safe.getBlockY(), safe.getBlockZ()));
}
});
user.getAsyncTeleport().teleport(safe, new Trade(this.getName(), ess), PlayerTeleportEvent.TeleportCause.COMMAND, future);
}
}
@@ -2,7 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.earth2me.essentials.utils.VersionUtil;
@@ -22,8 +22,6 @@ import java.util.Set;
import static com.earth2me.essentials.I18n.tl;
public class Commandclearinventory extends EssentialsCommand {
private static final int BASE_AMOUNT = 100000;
private static final int EXTENDED_CAP = 8;
public Commandclearinventory() {
@@ -114,38 +112,30 @@ public class Commandclearinventory extends EssentialsCommand {
}
}
if (type == ClearHandlerType.ALL_EXCEPT_ARMOR) {
if (type != ClearHandlerType.SPECIFIC_ITEM) {
final boolean armor = type == ClearHandlerType.ALL_INCLUDING_ARMOR;
if (showExtended) {
sender.sendMessage(tl("inventoryClearingAllItems", player.getDisplayName()));
sender.sendMessage(tl(armor ? "inventoryClearingAllArmor" : "inventoryClearingAllItems", player.getDisplayName()));
}
InventoryWorkaround.clearInventoryNoArmor(player.getInventory());
InventoryWorkaround.setItemInOffHand(player, null);
} else if (type == ClearHandlerType.ALL_INCLUDING_ARMOR) {
if (showExtended) {
sender.sendMessage(tl("inventoryClearingAllArmor", player.getDisplayName()));
}
InventoryWorkaround.clearInventoryNoArmor(player.getInventory());
InventoryWorkaround.setItemInOffHand(player, null);
player.getInventory().setArmorContents(null);
Inventories.removeItems(player, item -> true, armor);
} else {
for (final Item item : items) {
final ItemStack stack = new ItemStack(item.getMaterial());
if (VersionUtil.PRE_FLATTENING) {
//noinspection deprecation
stack.setDurability(item.getData());
}
// amount -1 means all items will be cleared
if (amount == -1) {
stack.setAmount(BASE_AMOUNT);
final ItemStack removedStack = player.getInventory().removeItem(stack).get(0);
final int removedAmount = BASE_AMOUNT - removedStack.getAmount() + InventoryWorkaround.clearItemInOffHand(player, stack);
final int removedAmount = Inventories.removeItemSimilar(player, stack, true);
if (removedAmount > 0 || showExtended) {
sender.sendMessage(tl("inventoryClearingStack", removedAmount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName()));
}
} else {
stack.setAmount(amount < 0 ? 1 : amount);
if (player.getInventory().containsAtLeast(stack, amount)) {
if (Inventories.removeItemAmount(player, stack, amount)) {
sender.sendMessage(tl("inventoryClearingStack", amount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName()));
player.getInventory().removeItem(stack);
} else {
if (showExtended) {
sender.sendMessage(tl("inventoryClearFail", player.getDisplayName(), amount, stack.getType().toString().toLowerCase(Locale.ENGLISH)));
@@ -203,7 +193,7 @@ public class Commandclearinventory extends EssentialsCommand {
}
private String formatCommand(final String commandLabel, final String[] args) {
return "/" + commandLabel + " " + StringUtil.joinList(" ", args);
return "/" + commandLabel + " " + StringUtil.joinList(" ", (Object[]) args);
}
private enum ClearHandlerType {
@@ -4,6 +4,7 @@ import com.earth2me.essentials.ChargeException;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.Trade.OverflowType;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.api.MaxMoneyException;
import org.bukkit.Material;
@@ -39,7 +40,7 @@ public class Commandcondense extends EssentialsCommand {
if (args.length > 0) {
is = ess.getItemDb().getMatching(user, args);
} else {
for (final ItemStack stack : user.getBase().getInventory().getContents()) {
for (final ItemStack stack : Inventories.getInventory(user.getBase(), false)) {
if (stack == null || stack.getType() == Material.AIR) {
continue;
}
@@ -85,7 +86,7 @@ public class Commandcondense extends EssentialsCommand {
int amount = 0;
for (final ItemStack contents : user.getBase().getInventory().getContents()) {
for (final ItemStack contents : Inventories.getInventory(user.getBase(), false)) {
if (contents != null && contents.isSimilar(stack)) {
amount += contents.getAmount();
}
@@ -2,6 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.PasteUtil;
import org.bukkit.Material;
@@ -37,7 +38,7 @@ public class Commandcreatekit extends EssentialsCommand {
// 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 ItemStack[] items = Inventories.getInventory(user.getBase(), true);
final List<String> list = new ArrayList<>();
boolean useSerializationProvider = ess.getSettings().isUseBetterKits();
@@ -3,6 +3,8 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.IUser;
import com.earth2me.essentials.User;
import net.essentialsx.api.v2.events.HomeModifyEvent;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import java.util.ArrayList;
@@ -37,18 +39,27 @@ public class Commanddelhome extends EssentialsCommand {
if (expandedArg.length > 1 && (user == null || user.isAuthorized("essentials.delhome.others"))) {
user = getPlayer(server, expandedArg, 0, true, true);
name = expandedArg[1];
name = expandedArg[1].toLowerCase(Locale.ENGLISH);
} else if (user == null) {
throw new NotEnoughArgumentsException();
} else {
name = expandedArg[0];
name = expandedArg[0].toLowerCase(Locale.ENGLISH);
}
if (name.equalsIgnoreCase("bed")) {
if (name.equals("bed")) {
throw new Exception(tl("invalidHomeName"));
}
user.delHome(name.toLowerCase(Locale.ENGLISH));
final HomeModifyEvent event = new HomeModifyEvent(sender.getUser(ess), user, name, user.getHome(name), false);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
if (ess.getSettings().isDebug()) {
ess.getLogger().info("HomeModifyEvent canceled for /delhome execution by " + sender.getDisplayName());
}
return;
}
user.delHome(name);
sender.sendMessage(tl("deleteHome", name));
}
@@ -3,11 +3,22 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.Lists;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Server;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.HangingSign;
import org.bukkit.block.data.type.WallHangingSign;
import org.bukkit.block.data.type.WallSign;
import org.bukkit.block.sign.Side;
import org.bukkit.entity.Player;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.util.Vector;
import java.util.Collections;
import java.util.List;
@@ -29,48 +40,74 @@ public class Commandeditsign extends EssentialsCommand {
if (!(target.getState() instanceof Sign)) {
throw new Exception(tl("editsignCommandTarget"));
}
final Sign sign = (Sign) target.getState();
final ModifiableSign sign = wrapSign((Sign) target.getState(), user);
try {
if (args[0].equalsIgnoreCase("set") && args.length > 2) {
final String[] existingLines = sign.getLines();
final int line = Integer.parseInt(args[1]) - 1;
final String text = FormatUtil.formatString(user, "essentials.editsign", getFinalArg(args, 2)).trim();
if (ChatColor.stripColor(text).length() > 15 && !user.isAuthorized("essentials.editsign.unlimited")) {
throw new Exception(tl("editsignCommandLimit"));
}
sign.setLine(line, text);
sign.update();
existingLines[line] = text;
if (callSignEvent(sign, user.getBase(), existingLines)) {
return;
}
user.sendMessage(tl("editsignCommandSetSuccess", line + 1, text));
} else if (args[0].equalsIgnoreCase("clear")) {
if (args.length == 1) {
final String[] existingLines = sign.getLines();
for (int i = 0; i < 4; i++) { // A whole one line of line savings!
sign.setLine(i, "");
existingLines[i] = "";
}
sign.update();
if (callSignEvent(sign, user.getBase(), existingLines)) {
return;
}
user.sendMessage(tl("editsignCommandClear"));
} else {
final String[] existingLines = sign.getLines();
final int line = Integer.parseInt(args[1]) - 1;
sign.setLine(line, "");
sign.update();
existingLines[line] = "";
if (callSignEvent(sign, user.getBase(), existingLines)) {
return;
}
user.sendMessage(tl("editsignCommandClearLine", line + 1));
}
} else if (args[0].equalsIgnoreCase("copy") || args[0].equalsIgnoreCase("paste")) {
final boolean copy = args[0].equalsIgnoreCase("copy");
final String tlPrefix = copy ? "editsignCopy" : "editsignPaste";
} else if (args[0].equalsIgnoreCase("copy")) {
final int line = args.length == 1 ? -1 : Integer.parseInt(args[1]) - 1;
if (line == -1) {
for (int i = 0; i < 4; i++) {
processSignCopyPaste(user, sign, i, copy);
// We use unformat here to prevent players from copying signs with colors that they do not have permission to use.
user.getSignCopy().set(i, FormatUtil.unformatString(user, "essentials.editsign", sign.getLine(i)));
}
user.sendMessage(tl(tlPrefix, commandLabel));
user.sendMessage(tl("editsignCopy", commandLabel));
} else {
processSignCopyPaste(user, sign, line, copy);
user.sendMessage(tl(tlPrefix + "Line", line + 1, commandLabel));
// We use unformat here to prevent players from copying signs with colors that they do not have permission to use.
user.getSignCopy().set(line, FormatUtil.unformatString(user, "essentials.editsign", sign.getLine(line)));
user.sendMessage(tl("editsignCopyLine", line + 1, commandLabel));
}
if (!copy) {
sign.update();
} else if (args[0].equalsIgnoreCase("paste")) {
final int line = args.length == 1 ? -1 : Integer.parseInt(args[1]) - 1;
final String[] existingLines = sign.getLines();
if (line == -1) {
for (int i = 0; i < 4; i++) {
existingLines[i] = FormatUtil.formatString(user, "essentials.editsign", user.getSignCopy().get(i));
}
user.sendMessage(tl("editsignPaste", commandLabel));
} else {
existingLines[line] = FormatUtil.formatString(user, "essentials.editsign", user.getSignCopy().get(line));
user.sendMessage(tl("editsignPasteLine", line + 1, commandLabel));
}
callSignEvent(sign, user.getBase(), existingLines);
} else {
throw new NotEnoughArgumentsException();
}
@@ -79,15 +116,28 @@ public class Commandeditsign extends EssentialsCommand {
}
}
private void processSignCopyPaste(final User user, final Sign sign, final int index, final boolean copy) {
if (copy) {
// We use unformat here to prevent players from copying signs with colors that they do not have permission to use.
user.getSignCopy().set(index, FormatUtil.unformatString(user, "essentials.editsign", sign.getLine(index)));
return;
private boolean callSignEvent(final ModifiableSign sign, final Player player, final String[] lines) {
final SignChangeEvent event;
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_20_1_R01)) {
event = new SignChangeEvent(sign.getBlock(), player, lines, sign.isFront() ? Side.FRONT : Side.BACK);
} else {
//noinspection deprecation
event = new SignChangeEvent(sign.getBlock(), player, lines);
}
final String line = FormatUtil.formatString(user, "essentials.editsign", user.getSignCopy().get(index));
sign.setLine(index, line == null ? "" : line);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
if (ess.getSettings().isDebug()) {
ess.getLogger().info("SignChangeEvent canceled for /editsign execution by " + player.getName());
}
return true;
}
for (int i = 0; i < 4; i++) {
sign.setLine(i, lines[i]);
}
sign.update();
return false;
}
@Override
@@ -100,7 +150,7 @@ public class Commandeditsign extends EssentialsCommand {
final int line = Integer.parseInt(args[1]);
final Block target = user.getTargetBlock(5);
if (target.getState() instanceof Sign && line <= 4) {
final Sign sign = (Sign) target.getState();
final ModifiableSign sign = wrapSign((Sign) target.getState(), user);
return Lists.newArrayList(FormatUtil.unformatString(user, "essentials.editsign", sign.getLine(line - 1)));
}
return Collections.emptyList();
@@ -108,4 +158,93 @@ public class Commandeditsign extends EssentialsCommand {
return Collections.emptyList();
}
}
private ModifiableSign wrapSign(final Sign sign, final User user) {
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_20_1_R01)) {
final Vector eyeLocLessSign = user.getBase().getEyeLocation().toVector().subtract(sign.getLocation().add(.5, .5, .5).toVector());
final BlockData signBlockData = sign.getBlockData();
final BlockFace signDirection;
if (signBlockData instanceof org.bukkit.block.data.type.Sign) {
signDirection = ((org.bukkit.block.data.type.Sign) signBlockData).getRotation();
} else if (signBlockData instanceof WallSign) {
signDirection = ((WallSign) signBlockData).getFacing();
} else if (signBlockData instanceof HangingSign) {
signDirection = ((HangingSign) signBlockData).getRotation();
} else if (signBlockData instanceof WallHangingSign) {
signDirection = ((WallHangingSign) signBlockData).getFacing();
} else {
throw new IllegalStateException("Unknown block data for sign: " + signBlockData.getClass());
}
final Side side = eyeLocLessSign.dot(signDirection.getDirection()) > 0 ? Side.FRONT : Side.BACK;
return new ModifiableSign(sign) {
@Override
String[] getLines() {
return sign.getSide(side).getLines();
}
@Override
String getLine(int line) {
return sign.getSide(side).getLine(line);
}
@Override
void setLine(int line, String text) {
sign.getSide(side).setLine(line, text);
}
@Override
boolean isFront() {
return side == Side.FRONT;
}
};
}
return new ModifiableSign(sign) {
@Override
String[] getLines() {
return sign.getLines();
}
@Override
String getLine(int line) {
return sign.getLine(line);
}
@Override
void setLine(int line, String text) {
sign.setLine(line, text);
}
@Override
boolean isFront() {
return true;
}
};
}
private abstract static class ModifiableSign {
protected final Sign sign;
protected ModifiableSign(final Sign sign) {
this.sign = sign;
}
abstract String getLine(int line);
abstract String[] getLines();
abstract void setLine(int line, String text);
abstract boolean isFront();
Block getBlock() {
return sign.getBlock();
}
void update() {
sign.update();
}
}
}
@@ -3,7 +3,6 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.Enchantments;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.collect.Lists;
import org.bukkit.Material;
@@ -57,7 +56,7 @@ public class Commandenchant extends EssentialsCommand {
final MetaItemStack metaStack = new MetaItemStack(stack);
final Enchantment enchantment = metaStack.getEnchantment(user, args[0]);
metaStack.addEnchantment(user.getSource(), ess.getSettings().allowUnsafeEnchantments() && user.isAuthorized("essentials.enchantments.allowunsafe"), enchantment, level);
InventoryWorkaround.setItemInMainHand(user.getBase(), metaStack.getItemStack());
stack.setItemMeta(metaStack.getItemStack().getItemMeta());
user.getBase().updateInventory();
final String enchantName = enchantment.getName().toLowerCase(Locale.ENGLISH).replace('_', ' ');
if (level == 0) {
@@ -3,9 +3,10 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.EssentialsUpgrade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.UserMap;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.economy.EconomyLayer;
import com.earth2me.essentials.economy.EconomyLayers;
import com.earth2me.essentials.userstorage.ModernUserMap;
import com.earth2me.essentials.utils.CommandMapUtil;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.EnumUtil;
@@ -13,7 +14,6 @@ import com.earth2me.essentials.utils.FloatUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.PasteUtil;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.gson.JsonArray;
@@ -23,16 +23,19 @@ import com.google.gson.JsonPrimitive;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.nio.charset.StandardCharsets;
@@ -45,12 +48,15 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.stream.Collectors;
import static com.earth2me.essentials.I18n.tl;
@@ -90,6 +96,7 @@ public class Commandessentials extends EssentialsCommand {
"EssentialsAntiBuild",
"EssentialsChat",
"EssentialsDiscord",
"EssentialsDiscordLink",
"EssentialsGeoIP",
"EssentialsProtect",
"EssentialsSpawn",
@@ -147,11 +154,12 @@ public class Commandessentials extends EssentialsCommand {
case "homes":
runHomes(server, sender, commandLabel, args);
break;
case "uuidconvert":
runUUIDConvert(server, sender, commandLabel, args);
case "usermap":
runUserMap(sender, args);
break;
case "uuidtest":
runUUIDTest(server, sender, commandLabel, args);
case "itemtest":
runItemTest(server, sender, commandLabel, args);
break;
// "#EasterEgg"
@@ -168,6 +176,56 @@ public class Commandessentials extends EssentialsCommand {
}
}
public void runItemTest(Server server, CommandSource sender, String commandLabel, String[] args) {
if (!sender.isAuthorized("essentials.itemtest", ess) || args.length < 2 || !sender.isPlayer()) {
return;
}
final Player player = sender.getPlayer();
assert player != null;
switch (args[1]) {
case "slot": {
if (args.length < 3) {
return;
}
player.getInventory().setItem(Integer.parseInt(args[2]), new ItemStack(Material.DIRT));
break;
}
case "overfill": {
sender.sendMessage(Inventories.addItem(player, 42, false, new ItemStack(Material.DIAMOND_SWORD, 1), new ItemStack(Material.DIRT, 32), new ItemStack(Material.DIRT, 32)).toString());
break;
}
case "overfill2": {
if (args.length < 4) {
return;
}
final boolean armor = Boolean.parseBoolean(args[2]);
final boolean add = Boolean.parseBoolean(args[3]);
final ItemStack[] items = new ItemStack[]{new ItemStack(Material.DIAMOND_SWORD, 1), new ItemStack(Material.DIRT, 32), new ItemStack(Material.DIRT, 32), new ItemStack(Material.DIAMOND_HELMET, 4), new ItemStack(Material.CHAINMAIL_LEGGINGS, 1)};
if (Inventories.hasSpace(player, 0, armor, items)) {
if (add) {
sender.sendMessage(Inventories.addItem(player, 0, armor, items).toString());
}
sender.sendMessage("SO MUCH SPACE!");
} else {
sender.sendMessage("No space!");
}
break;
}
case "remove": {
if (args.length < 3) {
return;
}
Inventories.removeItemExact(player, new ItemStack(Material.PUMPKIN, 1), Boolean.parseBoolean(args[2]));
break;
}
default: {
break;
}
}
}
// Displays the command's usage.
private void showUsage(final CommandSource sender) throws Exception {
throw new NotEnoughArgumentsException();
@@ -270,6 +328,7 @@ public class Commandessentials extends EssentialsCommand {
files.add(new PasteUtil.PasteFile("dump.json", dump.toString()));
final Plugin essDiscord = Bukkit.getPluginManager().getPlugin("EssentialsDiscord");
final Plugin essDiscordLink = Bukkit.getPluginManager().getPlugin("EssentialsDiscordLink");
final Plugin essSpawn = Bukkit.getPluginManager().getPlugin("EssentialsSpawn");
final Map<String, Command> knownCommandsCopy = new HashMap<>(ess.getKnownCommandsProvider().getKnownCommands());
@@ -331,6 +390,15 @@ public class Commandessentials extends EssentialsCommand {
} catch (IOException e) {
sender.sendMessage(tl("dumpErrorUpload", "discord-config.yml", e.getMessage()));
}
if (essDiscordLink != null) {
try {
files.add(new PasteUtil.PasteFile("discord-link-config.yml",
new String(Files.readAllBytes(essDiscordLink.getDataFolder().toPath().resolve("config.yml")), StandardCharsets.UTF_8)));
} catch (IOException e) {
sender.sendMessage(tl("dumpErrorUpload", "discord-link-config.yml", e.getMessage()));
}
}
}
if (kits) {
@@ -473,12 +541,11 @@ public class Commandessentials extends EssentialsCommand {
final long daysArg = Long.parseLong(args[1]);
final double moneyArg = args.length >= 3 ? FloatUtil.parseDouble(args[2].replaceAll("[^0-9\\.]", "")) : 0;
final int homesArg = args.length >= 4 && NumberUtil.isInt(args[3]) ? Integer.parseInt(args[3]) : 0;
final UserMap userMap = ess.getUserMap();
ess.runTaskAsynchronously(() -> {
final long currTime = System.currentTimeMillis();
for (final UUID u : userMap.getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
for (final UUID u : ess.getUsers().getAllUserUUIDs()) {
final User user = ess.getUsers().loadUncachedUser(u);
if (user == null) {
continue;
}
@@ -523,13 +590,12 @@ public class Commandessentials extends EssentialsCommand {
throw new Exception(HOMES_USAGE);
}
final UserMap userMap = ess.getUserMap();
switch (args[1]) {
case "fix":
sender.sendMessage(tl("fixingHomes"));
ess.runTaskAsynchronously(() -> {
for (final UUID u : userMap.getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
for (final UUID u : ess.getUsers().getAllUserUUIDs()) {
final User user = ess.getUsers().loadUncachedUser(u);
if (user == null) {
continue;
}
@@ -553,8 +619,8 @@ public class Commandessentials extends EssentialsCommand {
}
sender.sendMessage(filterByWorld ? tl("deletingHomesWorld", args[2]) : tl("deletingHomes"));
ess.runTaskAsynchronously(() -> {
for (final UUID u : userMap.getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
for (final UUID u : ess.getUsers().getAllUserUUIDs()) {
final User user = ess.getUsers().loadUncachedUser(u);
if (user == null) {
continue;
}
@@ -577,52 +643,79 @@ public class Commandessentials extends EssentialsCommand {
}
}
// Forces a rerun of userdata UUID conversion.
private void runUUIDConvert(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
sender.sendMessage("Starting Essentials UUID userdata conversion; this may lag the server.");
final Boolean ignoreUFCache = args.length > 2 && args[1].toLowerCase(Locale.ENGLISH).contains("ignore");
EssentialsUpgrade.uuidFileConvert(ess, ignoreUFCache);
sender.sendMessage("UUID conversion complete. Check your server log for more information.");
}
// Looks up various UUIDs for a user.
private void runUUIDTest(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 2) {
throw new Exception("/<command> uuidtest <name>");
// Gets information about cached users
private void runUserMap(final CommandSource sender, final String[] args) {
if (!sender.isAuthorized("essentials.usermap", ess)) {
return;
}
final String name = args[1];
sender.sendMessage("Looking up UUID for " + name);
UUID onlineUUID = null;
final ModernUserMap userMap = (ModernUserMap) ess.getUsers();
sender.sendMessage(tl("usermapSize", userMap.getCachedCount(), userMap.getUserCount(), ess.getSettings().getMaxUserCacheCount()));
if (args.length > 1) {
if (args[1].equals("full")) {
for (final Map.Entry<String, UUID> entry : userMap.getNameCache().entrySet()) {
sender.sendMessage(tl("usermapEntry", entry.getKey(), entry.getValue().toString()));
}
} else if (args[1].equals("purge")) {
final boolean seppuku = args.length > 2 && args[2].equals("iknowwhatimdoing");
for (final Player player : ess.getOnlinePlayers()) {
if (player.getName().equalsIgnoreCase(name)) {
onlineUUID = player.getUniqueId();
break;
sender.sendMessage(tl("usermapPurge", String.valueOf(seppuku)));
final Set<UUID> uuids = new HashSet<>(ess.getUsers().getAllUserUUIDs());
ess.runTaskAsynchronously(() -> {
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
final File backupFolder = new File(ess.getDataFolder(), "userdata-npc-backup-boogaloo-" + System.currentTimeMillis());
if (!userdataFolder.isDirectory()) {
ess.getLogger().warning("Missing userdata folder, aborting usermap purge.");
return;
}
if (seppuku && !backupFolder.mkdir()) {
ess.getLogger().warning("Unable to create backup folder, aborting usermap purge.");
return;
}
int total = 0;
final File[] files = userdataFolder.listFiles(EssentialsUpgrade.YML_FILTER);
if (files != null) {
for (final File file : files) {
try {
final String fileName = file.getName();
final UUID uuid = UUID.fromString(fileName.substring(0, fileName.length() - 4));
if (!uuids.contains(uuid)) {
total++;
ess.getLogger().warning("Found orphaned userdata file: " + file.getName());
if (seppuku) {
try {
com.google.common.io.Files.move(file, new File(backupFolder, file.getName()));
} catch (IOException e) {
ess.getLogger().log(Level.WARNING, "Unable to move orphaned userdata file: " + file.getName(), e);
}
}
}
} catch (IllegalArgumentException ignored) {
}
}
}
ess.getLogger().info("Found " + total + " orphaned userdata files.");
});
} else if (args[1].equalsIgnoreCase("cache")) {
sender.sendMessage(tl("usermapKnown", ess.getUsers().getAllUserUUIDs().size(), ess.getUsers().getNameCache().size()));
} else {
try {
final UUID uuid = UUID.fromString(args[1]);
for (final Map.Entry<String, UUID> entry : userMap.getNameCache().entrySet()) {
if (entry.getValue().equals(uuid)) {
sender.sendMessage(tl("usermapEntry", entry.getKey(), args[1]));
}
}
} catch (IllegalArgumentException ignored) {
final String sanitizedName = userMap.getSanitizedName(args[1]);
sender.sendMessage(tl("usermapEntry", sanitizedName, userMap.getNameCache().get(sanitizedName).toString()));
}
}
}
final UUID essUUID = ess.getUserMap().getUser(name).getConfigUUID();
final org.bukkit.OfflinePlayer player = ess.getServer().getOfflinePlayer(name);
final UUID bukkituuid = player.getUniqueId();
sender.sendMessage("Bukkit Lookup: " + bukkituuid.toString());
if (onlineUUID != null && onlineUUID != bukkituuid) {
sender.sendMessage("Online player: " + onlineUUID.toString());
}
if (essUUID != null && essUUID != bukkituuid) {
sender.sendMessage("Essentials config: " + essUUID.toString());
}
final UUID npcuuid = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
sender.sendMessage("NPC UUID: " + npcuuid.toString());
final UUID offlineuuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8));
sender.sendMessage("Offline Mode UUID: " + offlineuuid.toString());
}
// Displays versions of EssentialsX and related plugins.
@@ -750,7 +843,6 @@ public class Commandessentials extends EssentialsCommand {
options.add("cleanup");
options.add("homes");
//options.add("uuidconvert");
//options.add("uuidtest");
//options.add("nya");
//options.add("moo");
return options;
@@ -763,7 +855,6 @@ public class Commandessentials extends EssentialsCommand {
}
break;
case "reset":
case "uuidtest":
if (args.length == 2) {
return getPlayers(server, sender);
}
@@ -782,11 +873,6 @@ public class Commandessentials extends EssentialsCommand {
return server.getWorlds().stream().map(World::getName).collect(Collectors.toList());
}
break;
case "uuidconvert":
if (args.length == 2) {
return Lists.newArrayList("ignoreUFCache");
}
break;
case "dump":
final List<String> list = Lists.newArrayList("config", "kits", "log", "discord", "worth", "tpr", "spawns", "commands", "all");
for (String arg : args) {
@@ -3,7 +3,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.Lists;
@@ -81,13 +81,8 @@ public class Commandgive extends EssentialsLoopCommand {
final ItemStack finalStack = stack;
loopOnlinePlayersConsumer(server, sender, false, true, args[0], player -> {
sender.sendMessage(tl("giveSpawn", finalStack.getAmount(), itemName, player.getDisplayName()));
final Map<Integer, ItemStack> leftovers;
if (player.isAuthorized("essentials.oversizedstacks")) {
leftovers = InventoryWorkaround.addOversizedItems(player.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), finalStack);
} else {
leftovers = InventoryWorkaround.addItems(player.getBase().getInventory(), finalStack);
}
final Map<Integer, ItemStack> leftovers = Inventories.addItem(player.getBase(), player.isAuthorized("essentials.oversizedstacks") ? ess.getSettings().getOversizedStackSize() : 0, finalStack);
for (final ItemStack item : leftovers.values()) {
if (isDropItemsIfFull) {
@@ -1,7 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.TriState;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.Lists;
@@ -28,7 +28,7 @@ public class Commandhat extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length == 0 || (!args[0].contains("rem") && !args[0].contains("off") && !args[0].equalsIgnoreCase("0"))) {
final ItemStack hand = user.getItemInHand();
final ItemStack hand = Inventories.getItemInMainHand(user.getBase());
if (hand == null || hand.getType() == Material.AIR) {
user.sendMessage(tl("hatFail"));
return;
@@ -53,7 +53,7 @@ public class Commandhat extends EssentialsCommand {
return;
}
inv.setHelmet(hand);
inv.setItemInHand(head);
Inventories.setItemInMainHand(user.getBase(), head);
user.sendMessage(tl("hatPlaced"));
return;
}
@@ -67,7 +67,7 @@ public class Commandhat extends EssentialsCommand {
} else {
final ItemStack air = new ItemStack(Material.AIR);
inv.setHelmet(air);
InventoryWorkaround.addItems(user.getBase().getInventory(), head);
Inventories.addItem(user.getBase(), head);
user.sendMessage(tl("hatRemoved"));
}
}
@@ -36,7 +36,7 @@ public class Commandhelpop extends EssentialsCommand {
throw new NotEnoughArgumentsException();
}
final String message = tl("helpOp", from, FormatUtil.stripFormat(getFinalArg(args, 0)));
server.getLogger().log(Level.INFO, message);
ess.getLogger().log(Level.INFO, message);
ess.broadcastMessage("essentials.helpop.receive", message);
return message;
}
@@ -1,6 +1,6 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.OfflinePlayer;
import com.earth2me.essentials.OfflinePlayerStub;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.StringUtil;
@@ -42,7 +42,7 @@ public class Commandhome extends EssentialsCommand {
}
try {
if ("bed".equalsIgnoreCase(homeName) && user.isAuthorized("essentials.home.bed")) {
if (!player.getBase().isOnline() || player.getBase() instanceof OfflinePlayer) {
if (!player.getBase().isOnline() || player.getBase() instanceof OfflinePlayerStub) {
throw new Exception(tl("bedOffline"));
}
PaperLib.getBedSpawnLocationAsync(player.getBase(), true).thenAccept(location -> {
@@ -101,7 +101,7 @@ public class Commandhome extends EssentialsCommand {
user.sendMessage(tl("homes", StringUtil.joinList(homes), count, getHomeLimit(finalPlayer)));
}
});
if (!player.getBase().isOnline() || player.getBase() instanceof OfflinePlayer) {
if (!player.getBase().isOnline() || player.getBase() instanceof OfflinePlayerStub) {
message.complete(null);
return;
}
@@ -8,6 +8,8 @@ import org.bukkit.inventory.Inventory;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandinvsee extends EssentialsCommand {
public Commandinvsee() {
super("invsee");
@@ -21,6 +23,11 @@ public class Commandinvsee extends EssentialsCommand {
}
final User invUser = getPlayer(server, user, args, 0);
if (user == invUser) {
user.sendMessage(tl("invseeNoSelf"));
throw new NoChargeException();
}
final Inventory inv;
if (args.length > 1 && user.isAuthorized("essentials.invsee.equip")) {
@@ -40,7 +47,9 @@ public class Commandinvsee extends EssentialsCommand {
@Override
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
if (args.length == 1) {
return getPlayers(server, user);
final List<String> suggestions = getPlayers(server, user);
suggestions.remove(user.getName());
return suggestions;
} else {
//if (args.length == 2) {
// return Lists.newArrayList("equipped");
@@ -2,7 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.google.common.collect.Lists;
import org.bukkit.Material;
import org.bukkit.Server;
@@ -63,11 +63,7 @@ public class Commanditem extends EssentialsCommand {
final String displayName = stack.getType().toString().toLowerCase(Locale.ENGLISH).replace('_', ' ');
user.sendMessage(tl("itemSpawn", stack.getAmount(), displayName));
if (user.isAuthorized("essentials.oversizedstacks")) {
InventoryWorkaround.addOversizedItems(user.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), stack);
} else {
InventoryWorkaround.addItems(user.getBase().getInventory(), stack);
}
Inventories.addItem(user.getBase(), user.isAuthorized("essentials.oversizedstacks") ? ess.getSettings().getOversizedStackSize() : 0, stack);
user.getBase().updateInventory();
}
@@ -1,6 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
@@ -24,8 +25,8 @@ public class Commanditemlore extends EssentialsCommand {
@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 (MaterialUtil.isAir(item.getType())) {
final ItemStack item = Inventories.getItemInHand(user.getBase());
if (item == null || MaterialUtil.isAir(item.getType())) {
throw new Exception(tl("itemloreInvalidItem"));
}
@@ -73,8 +74,8 @@ public class Commanditemlore extends EssentialsCommand {
} else if (args.length == 2) {
switch (args[0].toLowerCase(Locale.ENGLISH)) {
case "set": {
final ItemStack item = user.getBase().getItemInHand();
if (!MaterialUtil.isAir(item.getType()) && item.hasItemMeta() && item.getItemMeta().hasLore()) {
final ItemStack item = Inventories.getItemInHand(user.getBase());
if (item != null && !MaterialUtil.isAir(item.getType()) && item.hasItemMeta() && item.getItemMeta().hasLore()) {
final List<String> lineNumbers = new ArrayList<>();
for (int i = 1; i <= item.getItemMeta().getLore().size(); i++) {
lineNumbers.add(String.valueOf(i));
@@ -92,8 +93,8 @@ public class Commanditemlore extends EssentialsCommand {
} else if (args.length == 3) {
if (args[0].equalsIgnoreCase("set") && NumberUtil.isInt(args[1])) {
final int i = Integer.parseInt(args[1]);
final ItemStack item = user.getBase().getItemInHand();
if (!MaterialUtil.isAir(item.getType()) && item.hasItemMeta() && item.getItemMeta().hasLore() && item.getItemMeta().getLore().size() >= i) {
final ItemStack item = Inventories.getItemInHand(user.getBase());
if (item != null && !MaterialUtil.isAir(item.getType()) && item.hasItemMeta() && item.getItemMeta().hasLore() && item.getItemMeta().getLore().size() >= i) {
return Lists.newArrayList(FormatUtil.unformatString(user, "essentials.itemlore", item.getItemMeta().getLore().get(i - 1)));
}
}
@@ -1,6 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.TriState;
@@ -23,8 +24,8 @@ public class Commanditemname extends EssentialsCommand {
@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 (MaterialUtil.isAir(item.getType())) {
final ItemStack item = Inventories.getItemInHand(user.getBase());
if (item == null || MaterialUtil.isAir(item.getType())) {
user.sendMessage(tl("itemnameInvalidItem"));
return;
}
@@ -50,8 +51,8 @@ public class Commanditemname extends EssentialsCommand {
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
if (args.length == 1) {
final ItemStack item = user.getBase().getItemInHand();
if (!MaterialUtil.isAir(item.getType()) && item.hasItemMeta() && item.getItemMeta().hasDisplayName()) {
final ItemStack item = Inventories.getItemInHand(user.getBase());
if (item != null && !MaterialUtil.isAir(item.getType()) && item.hasItemMeta() && item.getItemMeta().hasDisplayName()) {
return Lists.newArrayList(FormatUtil.unformatString(user, "essentials.itemname", item.getItemMeta().getDisplayName()));
}
}
@@ -28,7 +28,7 @@ public class Commandkick extends EssentialsCommand {
final User user = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null;
if (user != null) {
if (target.isHidden(sender.getPlayer()) && !user.canInteractVanished() && !sender.getPlayer().canSee(target.getBase())) {
if (target.isHidden(sender.getPlayer()) && !user.canInteractVanished() && target.isHiddenFrom(sender.getPlayer())) {
throw new PlayerNotFoundException();
}
@@ -51,7 +51,7 @@ public class Commandkick extends EssentialsCommand {
target.getBase().kickPlayer(kickReason);
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.DISPLAY_NAME;
server.getLogger().log(Level.INFO, tl("playerKicked", senderDisplayName, target.getName(), kickReason));
ess.getLogger().log(Level.INFO, tl("playerKicked", senderDisplayName, target.getName(), kickReason));
ess.broadcastMessage("essentials.kick.notify", tl("playerKicked", senderDisplayName, target.getName(), kickReason));
}
@@ -261,8 +261,8 @@ public class Commandmail extends EssentialsCommand {
@Override
public void run() {
for (UUID userid : ess.getUserMap().getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(userid);
for (final UUID u : ess.getUsers().getAllUserUUIDs()) {
final User user = ess.getUsers().loadUncachedUser(u);
if (user != null) {
user.sendMail(messageRecipient, message, dateDiff);
}
@@ -298,9 +298,21 @@ public class Commandmail extends EssentialsCommand {
if (pages == 0) {
return Lists.newArrayList("0");
} else {
final List<String> options = Lists.newArrayList("1");
if (pages > 1) {
options.add(String.valueOf(pages));
final List<String> options = new ArrayList<>();
for (int i = 0; i < pages; i++) {
options.add(String.valueOf(i + 1));
}
return options;
}
} else if (args[0].equalsIgnoreCase("clear")) {
final ArrayList<MailMessage> mail = user.getMailMessages();
// We show up to 9 mails on a page, we don't need to autocomplete more than that...
if (mail.size() >= 9) {
return Lists.newArrayList("1", "2", "3", "4", "5", "6", "7", "8", "9");
} else {
final List<String> options = new ArrayList<>();
for (int i = 0; i < mail.size(); i++) {
options.add(String.valueOf(i + 1));
}
return options;
}
@@ -1,7 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.OfflinePlayer;
import com.earth2me.essentials.OfflinePlayerStub;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.DateUtil;
import net.ess3.api.events.MuteStatusChangeEvent;
@@ -29,7 +29,7 @@ public class Commandmute extends EssentialsCommand {
user = getPlayer(server, args, 0, true, true);
} catch (final PlayerNotFoundException e) {
nomatch = true;
user = ess.getUser(new OfflinePlayer(args[0], ess.getServer()));
user = ess.getUser(new OfflinePlayerStub(args[0], ess.getServer()));
}
if (!user.getBase().isOnline() && sender.isPlayer()) {
if (!sender.isAuthorized("essentials.mute.offline", ess)) {
@@ -113,7 +113,7 @@ public class Commandmute extends EssentialsCommand {
message = tl("muteNotifyReason", sender.getSender().getName(), user.getName(), user.getMuteReason());
}
}
server.getLogger().log(Level.INFO, message);
ess.getLogger().log(Level.INFO, message);
ess.broadcastMessage("essentials.mute.notify", message);
} else {
sender.sendMessage(tl("unmutedPlayer", user.getDisplayName()));
@@ -87,7 +87,7 @@ public class Commandnear extends EssentialsCommand {
final Queue<User> nearbyPlayers = new PriorityQueue<>((o1, o2) -> (int) (o1.getLocation().distanceSquared(loc) - o2.getLocation().distanceSquared(loc)));
for (final User player : ess.getOnlineUsers()) {
if (!player.equals(user) && !player.isAuthorized("essentials.near.exclude") && (!player.isHidden(user.getBase()) || showHidden || user.getBase().canSee(player.getBase()))) {
if (!player.equals(user) && !player.isAuthorized("essentials.near.exclude") && (!player.isHidden(user.getBase()) || showHidden || !player.isHiddenFrom(user.getBase()))) {
final Location playerLoc = player.getLocation();
if (playerLoc.getWorld() != world) {
continue;
@@ -6,6 +6,7 @@ import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.metadata.FixedMetadataValue;
import java.util.ArrayList;
import java.util.Collection;
@@ -15,6 +16,9 @@ import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandnuke extends EssentialsCommand {
public static final String NUKE_META_KEY = "ess_tnt_proj";
public Commandnuke() {
super("nuke");
}
@@ -30,7 +34,6 @@ public class Commandnuke extends EssentialsCommand {
} else {
targets = ess.getOnlinePlayers();
}
ess.getTNTListener().enable();
for (final Player player : targets) {
if (player == null) {
continue;
@@ -38,9 +41,12 @@ public class Commandnuke extends EssentialsCommand {
player.sendMessage(tl("nuke"));
final Location loc = player.getLocation();
final World world = loc.getWorld();
for (int x = -10; x <= 10; x += 5) {
for (int z = -10; z <= 10; z += 5) {
world.spawn(new Location(world, loc.getBlockX() + x, world.getHighestBlockYAt(loc) + 64, loc.getBlockZ() + z), TNTPrimed.class);
if (world != null) {
for (int x = -10; x <= 10; x += 5) {
for (int z = -10; z <= 10; z += 5) {
final TNTPrimed entity = world.spawn(new Location(world, loc.getBlockX() + x, world.getHighestBlockYAt(loc) + 64, loc.getBlockZ() + z), TNTPrimed.class);
entity.setMetadata(NUKE_META_KEY, new FixedMetadataValue(ess, true));
}
}
}
}
@@ -2,6 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.collect.Lists;
import org.bukkit.Material;
@@ -22,7 +23,7 @@ public class Commandpowertool extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final String command = getFinalArg(args, 0);
final ItemStack itemStack = user.getBase().getItemInHand();
final ItemStack itemStack = Inventories.getItemInHand(user.getBase());
powertool(user.getSource(), user, itemStack, command);
}
@@ -111,7 +112,7 @@ public class Commandpowertool extends EssentialsCommand {
}
try {
final ItemStack itemStack = user.getBase().getItemInHand();
final ItemStack itemStack = Inventories.getItemInHand(user.getBase());
final List<String> powertools = user.getPowertool(itemStack);
for (final String tool : powertools) {
options.add("r:" + tool);
@@ -25,7 +25,7 @@ public class Commandrealname extends EssentialsCommand {
final boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished();
boolean foundUser = false;
for (final User u : ess.getOnlineUsers()) {
if (skipHidden && u.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(u.getBase())) {
if (skipHidden && u.isHidden(sender.getPlayer()) && u.isHiddenFrom(sender.getPlayer())) {
continue;
}
u.setDisplayNick();
@@ -2,6 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.VersionUtil;
@@ -53,7 +54,18 @@ public class Commandrecipe extends EssentialsCommand {
throw new NotEnoughArgumentsException();
}
final ItemStack itemType = ess.getItemDb().get(args[0]);
final ItemStack itemType;
if (args[0].equalsIgnoreCase("hand")) {
if (!sender.isPlayer()) {
throw new Exception(tl("consoleCannotUseCommand"));
}
itemType = Inventories.getItemInHand(sender.getPlayer());
} else {
itemType = ess.getItemDb().get(args[0]);
}
int recipeNo = 0;
if (args.length > 1) {
@@ -155,6 +167,7 @@ public class Commandrecipe extends EssentialsCommand {
final List<ItemStack> ingredients = recipe.getIngredientList();
if (showWindow) {
final User user = ess.getUser(sender.getPlayer());
user.getBase().closeInventory();
user.setRecipeSee(true);
final InventoryView view = user.getBase().openWorkbench(null, true);
for (int i = 0; i < ingredients.size(); i++) {
@@ -0,0 +1,107 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.NumberUtil;
import net.ess3.api.IUser;
import net.essentialsx.api.v2.events.HomeModifyEvent;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commandrenamehome extends EssentialsCommand {
public Commandrenamehome() {
super("renamehome");
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
User usersHome = user;
final String oldName;
final String newName;
// Allowing both formats /renamehome jroy home1 home | /sethome jroy:home1 home
if (args.length == 2) {
final String[] nameParts = args[0].split(":", 2);
newName = args[1].toLowerCase(Locale.ENGLISH);
if (nameParts.length == 2) {
oldName = nameParts[1].toLowerCase(Locale.ENGLISH);
if (user.isAuthorized("essentials.renamehome.others")) {
usersHome = getPlayer(server, nameParts[0], true, true);
if (usersHome == null) {
throw new PlayerNotFoundException();
}
}
} else {
oldName = args[0].toLowerCase(Locale.ENGLISH);
}
} else if (args.length == 3) {
if (!user.isAuthorized("essentials.renamehome.others")) {
throw new NotEnoughArgumentsException();
}
usersHome = getPlayer(server, args[0], true, true);
if (usersHome == null) {
throw new PlayerNotFoundException();
}
oldName = args[1].toLowerCase(Locale.ENGLISH);
newName = args[2].toLowerCase(Locale.ENGLISH);
} else {
throw new NotEnoughArgumentsException();
}
if ("bed".equals(newName) || NumberUtil.isInt(newName) || "bed".equals(oldName) || NumberUtil.isInt(oldName)) {
throw new NoSuchFieldException(tl("invalidHomeName"));
}
final HomeModifyEvent event = new HomeModifyEvent(user, usersHome, oldName, newName, usersHome.getHome(oldName));
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
if (ess.getSettings().isDebug()) {
ess.getLogger().info("HomeModifyEvent canceled for /renamehome execution by " + user.getDisplayName());
}
return;
}
usersHome.renameHome(oldName, newName);
user.sendMessage(tl("homeRenamed", oldName, newName));
usersHome.setLastHomeConfirmation(null);
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
final IUser user = sender.getUser(ess);
if (args.length != 1) {
return Collections.emptyList();
}
final List<String> homes = user == null ? new ArrayList<>() : user.getHomes();
final boolean canRenameOthers = sender.isAuthorized("essentials.renamehome.others", ess);
if (canRenameOthers) {
final int sepIndex = args[0].indexOf(':');
if (sepIndex < 0) {
getPlayers(server, sender).forEach(player -> homes.add(player + ":"));
} else {
final String namePart = args[0].substring(0, sepIndex);
final User otherUser;
try {
otherUser = getPlayer(server, new String[]{namePart}, 0, true, true);
} catch (final Exception ex) {
return homes;
}
otherUser.getHomes().forEach(home -> homes.add(namePart + ":" + home));
}
}
return homes;
}
}
@@ -3,6 +3,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.ChargeException;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.earth2me.essentials.utils.VersionUtil;
@@ -62,7 +63,7 @@ public class Commandrepair extends EssentialsCommand {
public void repairAll(final User user) throws Exception {
final List<String> repaired = new ArrayList<>();
repairItems(user.getBase().getInventory().getContents(), user, repaired);
repairItems(Inventories.getInventory(user.getBase(), false), user, repaired);
if (user.isAuthorized("essentials.repair.armor")) {
repairItems(user.getBase().getInventory().getArmorContents(), user, repaired);
@@ -2,7 +2,6 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.UserMap;
import com.earth2me.essentials.craftbukkit.BanLookup;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.FormatUtil;
@@ -63,7 +62,7 @@ public class Commandseen extends EssentialsCommand {
ess.getScheduler().runTaskAsynchronously(ess, new Runnable() {
@Override
public void run() {
final User userFromBukkit = ess.getUserMap().getUserFromBukkit(args[0]);
final User userFromBukkit = ess.getUsers().getUser(args[0]);
try {
if (userFromBukkit != null) {
showUserSeen(userFromBukkit);
@@ -103,8 +102,8 @@ public class Commandseen extends EssentialsCommand {
user.setDisplayNick();
sender.sendMessage(tl("seenOnline", user.getDisplayName(), DateUtil.formatDateDiff(user.getLastLogin())));
final List<String> history = ess.getUserMap().getUserHistory(user.getBase().getUniqueId());
if (history != null && history.size() > 1) {
final List<String> history = user.getPastUsernames();
if (history != null && !history.isEmpty()) {
sender.sendMessage(tl("seenAccounts", StringUtil.joinListSkip(", ", user.getName(), history)));
}
@@ -139,7 +138,7 @@ public class Commandseen extends EssentialsCommand {
user.setDisplayNick();
if (user.getLastLogout() > 0) {
sender.sendMessage(tl("seenOffline", user.getName(), DateUtil.formatDateDiff(user.getLastLogout())));
final List<String> history = ess.getUserMap().getUserHistory(user.getBase().getUniqueId());
final List<String> history = user.getPastUsernames();
if (history != null && history.size() > 1) {
sender.sendMessage(tl("seenAccounts", StringUtil.joinListSkip(", ", user.getName(), history)));
}
@@ -192,14 +191,12 @@ public class Commandseen extends EssentialsCommand {
}
private void seenIP(final CommandSource sender, final String ipAddress, final String display) {
final UserMap userMap = ess.getUserMap();
sender.sendMessage(tl("runningPlayerMatch", display));
ess.runTaskAsynchronously(() -> {
final List<String> matches = new ArrayList<>();
for (final UUID u : userMap.getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
for (final UUID u : ess.getUsers().getAllUserUUIDs()) {
final User user = ess.getUsers().loadUncachedUser(u);
if (user == null) {
continue;
}
@@ -2,6 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import net.ess3.api.events.UserBalanceUpdateEvent;
@@ -108,11 +109,11 @@ public class Commandsell extends EssentialsCommand {
//TODO: Prices for Enchantments
final ItemStack ris = is.clone();
ris.setAmount(amount);
if (!user.getBase().getInventory().containsAtLeast(ris, amount)) {
if (!Inventories.containsAtLeast(user.getBase(), ris, amount)) {
// This should never happen.
throw new IllegalStateException("Trying to remove more items than are available.");
}
user.getBase().getInventory().removeItem(ris);
Inventories.removeItemAmount(user.getBase(), ris, ris.getAmount());
user.getBase().updateInventory();
Trade.log("Command", "Sell", "Item", user.getName(), new Trade(ris, ess), user.getName(), new Trade(result, ess), user.getLocation(), user.getMoney(), ess);
user.giveMoney(result, null, UserBalanceUpdateEvent.Cause.COMMAND_SELL);
@@ -4,6 +4,8 @@ import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.LocationUtil;
import com.earth2me.essentials.utils.NumberUtil;
import net.essentialsx.api.v2.events.HomeModifyEvent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
@@ -62,8 +64,25 @@ public class Commandsethome extends EssentialsCommand {
return;
}
final Location prevHomeLoc = usersHome.getHome(name);
final HomeModifyEvent event;
if (prevHomeLoc == null) {
event = new HomeModifyEvent(user, usersHome, name, location, true);
} else {
event = new HomeModifyEvent(user, usersHome, name, prevHomeLoc, location);
}
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
if (ess.getSettings().isDebug()) {
ess.getLogger().info("HomeModifyEvent canceled for /sethome execution by " + user.getDisplayName());
}
return;
}
usersHome.setHome(name, location);
user.sendMessage(tl("homeSet", user.getLocation().getWorld().getName(), user.getLocation().getBlockX(), user.getLocation().getBlockY(), user.getLocation().getBlockZ(), name));
user.sendMessage(tl("homeSet", location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ(), name));
usersHome.setLastHomeConfirmation(null);
}
@@ -22,7 +22,7 @@ public class Commandsetworth extends EssentialsCommand {
final ItemStack stack;
final String price;
if (args.length == 1) {
stack = user.getBase().getInventory().getItemInHand();
stack = user.getItemInHand();
price = args[0];
} else {
stack = ess.getItemDb().get(args[0]);
@@ -1,7 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import com.google.common.collect.Lists;
@@ -9,7 +9,6 @@ import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Collections;
import java.util.List;
@@ -60,26 +59,21 @@ public class Commandskull extends EssentialsCommand {
}
private void editSkull(final User user, final ItemStack stack, final SkullMeta skullMeta, final String owner, final boolean spawn) {
new BukkitRunnable() {
@Override
public void run() {
//Run this stuff async because SkullMeta#setOwner causes a http request.
skullMeta.setDisplayName("§fSkull of " + owner);
skullMeta.setOwner(owner);
new BukkitRunnable() {
@Override
public void run() {
stack.setItemMeta(skullMeta);
if (spawn) {
InventoryWorkaround.addItems(user.getBase().getInventory(), stack);
user.sendMessage(tl("givenSkull", owner));
return;
}
user.sendMessage(tl("skullChanged", owner));
}
}.runTask(ess);
}
}.runTaskAsynchronously(ess);
ess.runTaskAsynchronously(() -> {
//Run this stuff async because SkullMeta#setOwner causes a http request.
skullMeta.setDisplayName("§fSkull of " + owner);
//noinspection deprecation
skullMeta.setOwner(owner);
ess.scheduleSyncDelayedTask(() -> {
stack.setItemMeta(skullMeta);
if (spawn) {
Inventories.addItem(user.getBase(), stack);
user.sendMessage(tl("givenSkull", owner));
return;
}
user.sendMessage(tl("skullChanged", owner));
});
});
}
@Override
@@ -67,7 +67,7 @@ public class Commandspeed extends EssentialsCommand {
final List<Player> matchedPlayers = server.matchPlayer(name);
for (final Player matchPlayer : matchedPlayers) {
final User player = ess.getUser(matchPlayer);
if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) {
if (skipHidden && player.isHidden(sender.getPlayer()) && player.isHiddenFrom(sender.getPlayer())) {
continue;
}
foundUser = true;
@@ -54,7 +54,7 @@ public class Commandtempban extends EssentialsCommand {
user.getBase().kickPlayer(tl("tempBanned", expiry, senderDisplayName, banReason));
final String message = tl("playerTempBanned", senderDisplayName, user.getName(), expiry, banReason);
server.getLogger().log(Level.INFO, message);
ess.getLogger().log(Level.INFO, message);
ess.broadcastMessage("essentials.ban.notify", message);
}
@@ -71,7 +71,7 @@ public class Commandtempbanip extends EssentialsCommand {
final String message = tl("playerTempBanIpAddress", senderDisplayName, ipAddress,
DateUtil.formatDateDiff(banTimestamp), banReason);
server.getLogger().log(Level.INFO, message);
ess.getLogger().log(Level.INFO, message);
ess.broadcastMessage("essentials.banip.notify", message);
}
@@ -87,7 +87,7 @@ public class Commandtogglejail extends EssentialsCommand {
sender.sendMessage(timeDiff > 0 ? tl("playerJailedFor", player.getName(), DateUtil.formatDateDiff(finalDisplayTime)) : tl("playerJailed", player.getName()));
final String notifyMessage = timeDiff > 0 ? tl("jailNotifyJailedFor", player.getName(), DateUtil.formatDateDiff(finalDisplayTime), sender.getSender().getName()) : tl("jailNotifyJailed", player.getName(), sender.getSender().getName());
server.getLogger().log(Level.INFO, notifyMessage);
ess.getLogger().log(Level.INFO, notifyMessage);
ess.broadcastMessage("essentials.jail.notify", notifyMessage);
}
});
@@ -114,7 +114,7 @@ public class Commandtogglejail extends EssentialsCommand {
sender.sendMessage(tl("jailSentenceExtended", DateUtil.formatDateDiff(displayTimeDiff)));
final String notifyMessage = tl("jailNotifySentenceExtended", player.getName(), DateUtil.formatDateDiff(displayTimeDiff), sender.getSender().getName());
server.getLogger().log(Level.INFO, notifyMessage);
ess.getLogger().log(Level.INFO, notifyMessage);
ess.broadcastMessage("essentials.jail.notify", notifyMessage);
return;
}
@@ -24,12 +24,12 @@ public class Commandtop extends EssentialsCommand {
final float yaw = user.getLocation().getYaw();
final Location unsafe = new Location(user.getWorld(), topX, ess.getWorldInfoProvider().getMaxHeight(user.getWorld()), topZ, yaw, pitch);
final Location safe = LocationUtil.getSafeDestination(ess, unsafe);
final CompletableFuture<Boolean> future = new CompletableFuture<>();
final CompletableFuture<Boolean> future = getNewExceptionFuture(user.getSource(), commandLabel);
future.thenAccept(success -> {
if (success) {
user.sendMessage(tl("teleportTop", safe.getWorld().getName(), safe.getBlockX(), safe.getBlockY(), safe.getBlockZ()));
}
});
user.getAsyncTeleport().teleport(safe, new Trade(this.getName(), ess), TeleportCause.COMMAND, getNewExceptionFuture(user.getSource(), commandLabel));
user.getAsyncTeleport().teleport(safe, new Trade(this.getName(), ess), TeleportCause.COMMAND, future);
}
}
@@ -21,6 +21,11 @@ public class Commandtpoffline extends EssentialsCommand {
final User target = getPlayer(server, args, 0, true, true);
final Location logout = target.getLogoutLocation();
if (logout == null) {
user.sendMessage(tl("teleportOfflineUnknown", user.getDisplayName()));
throw new NoChargeException();
}
if (user.getWorld() != logout.getWorld() && ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + logout.getWorld().getName())) {
throw new Exception(tl("noPerm", "essentials.worlds." + logout.getWorld().getName()));
}
@@ -66,9 +66,9 @@ public class Commandtppos extends EssentialsCommand {
}
final User user = getPlayer(server, args, 0, true, false);
final double x = args[1].startsWith("~") ? user.getLocation().getX() + (args[1].length() > 1 ? Integer.parseInt(args[1].substring(1)) : 0) : Integer.parseInt(args[1]);
final double y = args[2].startsWith("~") ? user.getLocation().getY() + (args[2].length() > 1 ? Integer.parseInt(args[2].substring(1)) : 0) : Integer.parseInt(args[2]);
final double z = args[3].startsWith("~") ? user.getLocation().getZ() + (args[3].length() > 1 ? Integer.parseInt(args[3].substring(1)) : 0) : Integer.parseInt(args[3]);
final double x = args[1].startsWith("~") ? user.getLocation().getX() + (args[1].length() > 1 ? Double.parseDouble(args[1].substring(1)) : 0) : Double.parseDouble(args[1]);
final double y = args[2].startsWith("~") ? user.getLocation().getY() + (args[2].length() > 1 ? Double.parseDouble(args[2].substring(1)) : 0) : Double.parseDouble(args[2]);
final double z = args[3].startsWith("~") ? user.getLocation().getZ() + (args[3].length() > 1 ? Double.parseDouble(args[3].substring(1)) : 0) : Double.parseDouble(args[3]);
final Location loc = new Location(user.getWorld(), x, y, z, user.getLocation().getYaw(), user.getLocation().getPitch());
if (args.length == 5) {
loc.setWorld(ess.getWorld(args[4]));
@@ -37,7 +37,7 @@ public class Commandunban extends EssentialsCommand {
}
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.DISPLAY_NAME;
server.getLogger().log(Level.INFO, tl("playerUnbanned", senderDisplayName, name));
ess.getLogger().log(Level.INFO, tl("playerUnbanned", senderDisplayName, name));
ess.broadcastMessage("essentials.ban.notify", tl("playerUnbanned", senderDisplayName, name));
}
@@ -40,7 +40,7 @@ public class Commandunbanip extends EssentialsCommand {
ess.getServer().getBanList(BanList.Type.IP).pardon(ipAddress);
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.DISPLAY_NAME;
server.getLogger().log(Level.INFO, tl("playerUnbanIpAddress", senderDisplayName, ipAddress));
ess.getLogger().log(Level.INFO, tl("playerUnbanIpAddress", senderDisplayName, ipAddress));
ess.broadcastMessage("essentials.banip.notify", tl("playerUnbanIpAddress", senderDisplayName, ipAddress));
}
@@ -1,6 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
@@ -75,8 +76,8 @@ public class Commandunlimited extends EssentialsCommand {
if (!target.hasUnlimited(stack)) {
message = "enableUnlimited";
enableUnlimited = true;
if (!target.getBase().getInventory().containsAtLeast(stack, stack.getAmount())) {
target.getBase().getInventory().addItem(stack);
if (!Inventories.containsAtLeast(target.getBase(), stack, stack.getAmount())) {
Inventories.addItem(target.getBase(), stack);
}
}
@@ -40,7 +40,7 @@ public class Commandwhois extends EssentialsCommand {
sender.sendMessage(tl("whoisHunger", user.getBase().getFoodLevel(), user.getBase().getSaturation()));
sender.sendMessage(tl("whoisExp", SetExpFix.getTotalExperience(user.getBase()), user.getBase().getLevel()));
sender.sendMessage(tl("whoisLocation", user.getLocation().getWorld().getName(), user.getLocation().getBlockX(), user.getLocation().getBlockY(), user.getLocation().getBlockZ()));
final long playtimeMs = System.currentTimeMillis() - (user.getBase().getStatistic(PLAY_ONE_TICK) * 50);
final long playtimeMs = System.currentTimeMillis() - (user.getBase().getStatistic(PLAY_ONE_TICK) * 50L);
sender.sendMessage(tl("whoisPlaytime", DateUtil.formatDateDiff(playtimeMs)));
if (!ess.getSettings().isEcoDisabled()) {
sender.sendMessage(tl("whoisMoney", NumberUtil.displayCurrency(user.getMoney(), ess)));
@@ -30,16 +30,21 @@ public abstract class EssentialsLoopCommand extends EssentialsCommand {
final UUID uuid = StringUtil.toUUID(searchTerm);
if (uuid != null) {
final User matchedUser = ess.getUser(uuid);
if (matchedUser == null) {
throw new PlayerNotFoundException();
}
userConsumer.accept(matchedUser);
} else if (matchWildcards && searchTerm.contentEquals("**")) {
for (final UUID sUser : ess.getUserMap().getAllUniqueUsers()) {
final User matchedUser = ess.getUser(sUser);
userConsumer.accept(matchedUser);
for (final UUID u : ess.getUsers().getAllUserUUIDs()) {
final User user = ess.getUsers().loadUncachedUser(u);
if (user != null) {
userConsumer.accept(user);
}
}
} else if (matchWildcards && searchTerm.contentEquals("*")) {
final boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished();
for (final User onlineUser : ess.getOnlineUsers()) {
if (skipHidden && onlineUser.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(onlineUser.getBase())) {
if (skipHidden && onlineUser.isHidden(sender.getPlayer()) && onlineUser.isHiddenFrom(sender.getPlayer())) {
continue;
}
userConsumer.accept(onlineUser);
@@ -76,7 +81,7 @@ public abstract class EssentialsLoopCommand extends EssentialsCommand {
if (matchWildcards && (searchTerm.contentEquals("**") || searchTerm.contentEquals("*"))) {
for (final User onlineUser : ess.getOnlineUsers()) {
if (skipHidden && onlineUser.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(onlineUser.getBase())) {
if (skipHidden && onlineUser.isHidden(sender.getPlayer()) && onlineUser.isHiddenFrom(sender.getPlayer())) {
continue;
}
userConsumer.accept(onlineUser);
@@ -91,7 +96,7 @@ public abstract class EssentialsLoopCommand extends EssentialsCommand {
if (matchedPlayers.isEmpty()) {
final String matchText = searchTerm.toLowerCase(Locale.ENGLISH);
for (final User player : ess.getOnlineUsers()) {
if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(player.getBase())) {
if (skipHidden && player.isHidden(sender.getPlayer()) && player.isHiddenFrom(sender.getPlayer())) {
continue;
}
final String displayName = FormatUtil.stripFormat(player.getDisplayName()).toLowerCase(Locale.ENGLISH);
@@ -103,7 +108,7 @@ public abstract class EssentialsLoopCommand extends EssentialsCommand {
} else {
for (final Player matchPlayer : matchedPlayers) {
final User player = ess.getUser(matchPlayer);
if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) {
if (skipHidden && player.isHidden(sender.getPlayer()) && player.isHiddenFrom(sender.getPlayer())) {
continue;
}
foundUser = true;
@@ -51,7 +51,7 @@ public abstract class EssentialsToggleCommand extends EssentialsCommand {
final List<Player> matchedPlayers = server.matchPlayer(args[0]);
for (final Player matchPlayer : matchedPlayers) {
final User player = ess.getUser(matchPlayer);
if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) {
if (skipHidden && player.isHidden(sender.getPlayer()) && player.isHiddenFrom(sender.getPlayer())) {
continue;
}
foundUser = true;
@@ -33,7 +33,9 @@ import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -103,6 +105,15 @@ public class EssentialsConfiguration {
return configurationNode;
}
public void setRootHolder(final Class<?> holderClass, final Object holder) {
try {
getRootNode().set(holderClass, holder);
} catch (SerializationException e) {
Essentials.getWrappedLogger().log(Level.SEVERE, "Error while saving user config: " + configFile.getName(), e);
throw new RuntimeException(e);
}
}
public File getFile() {
return configFile;
}
@@ -120,6 +131,7 @@ public class EssentialsConfiguration {
try {
return node.get(LazyLocation.class);
} catch (SerializationException e) {
Essentials.getWrappedLogger().log(Level.SEVERE, e.getMessage(), e);
return null;
}
}
@@ -261,7 +273,8 @@ public class EssentialsConfiguration {
try {
return node.get(BigDecimal.class);
} catch (SerializationException e) {
return null;
Essentials.getWrappedLogger().log(Level.SEVERE, e.getMessage(), e);
return def;
}
}
@@ -294,6 +307,19 @@ public class EssentialsConfiguration {
return ConfigurateUtil.getMap(configurationNode);
}
public Map<String, String> getStringMap(String path) {
final CommentedConfigurationNode node = getInternal(path);
if (node == null || !node.isMap()) {
return Collections.emptyMap();
}
final Map<String, String> map = new LinkedHashMap<>();
for (Map.Entry<Object, CommentedConfigurationNode> entry : node.childrenMap().entrySet()) {
map.put(String.valueOf(entry.getKey()), String.valueOf(entry.getValue().rawScalar()));
}
return map;
}
public void removeProperty(String path) {
final CommentedConfigurationNode node = getInternal(path);
if (node != null) {
@@ -366,10 +392,10 @@ public class EssentialsConfiguration {
} catch (final ParsingException e) {
final File broken = new File(configFile.getAbsolutePath() + ".broken." + System.currentTimeMillis());
if (configFile.renameTo(broken)) {
Essentials.getWrappedLogger().log(Level.SEVERE, "The file " + configFile.toString() + " is broken, it has been renamed to " + broken.toString(), e.getCause());
Essentials.getWrappedLogger().log(Level.SEVERE, "The file " + configFile + " is broken, it has been renamed to " + broken, e.getCause());
return;
}
Essentials.getWrappedLogger().log(Level.SEVERE, "The file " + configFile.toString() + " is broken. A backup file has failed to be created", e.getCause());
Essentials.getWrappedLogger().log(Level.SEVERE, "The file " + configFile + " is broken. A backup file has failed to be created", e.getCause());
} catch (final ConfigurateException e) {
Essentials.getWrappedLogger().log(Level.SEVERE, e.getMessage(), e);
} finally {
@@ -420,6 +446,10 @@ public class EssentialsConfiguration {
}
}
public boolean isTransaction() {
return transaction.get();
}
public void setSaveHook(Runnable saveHook) {
this.saveHook = saveHook;
}
@@ -52,7 +52,7 @@ public class EssentialsUserConfiguration extends EssentialsConfiguration {
private File getAltFile() {
final UUID fn = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username.toLowerCase(Locale.ENGLISH)).getBytes(Charsets.UTF_8));
return new File(configFile.getParentFile(), fn.toString() + ".yml");
return new File(configFile.getParentFile(), fn + ".yml");
}
@Override
@@ -262,6 +262,16 @@ public class UserConfigHolder {
this.lastAccountName = value;
}
private @MonotonicNonNull String npcName;
public String npcName() {
return this.npcName;
}
public void npcName(final String value) {
this.npcName = value;
}
private boolean powertoolsenabled = true;
public boolean powerToolsEnabled() {
@@ -332,6 +342,20 @@ public class UserConfigHolder {
this.shouting = value;
}
@DeleteOnEmpty
private @MonotonicNonNull List<String> pastUsernames;
public List<String> pastUsernames() {
if (this.pastUsernames == null) {
this.pastUsernames = new ArrayList<>();
}
return this.pastUsernames;
}
public void pastUsernames(List<String> value) {
this.pastUsernames = value;
}
private @NonNull Timestamps timestamps = new Timestamps();
public Timestamps timestamps() {
@@ -17,7 +17,9 @@ public class MaterialTypeSerializer extends ScalarSerializer<Material> {
if (obj instanceof String) {
return Material.matchMaterial((String) obj);
}
return null;
// Configurate will use an EnumSet to deserialize, which doesn't support null types. Default to air.
return Material.AIR;
}
@Override
@@ -21,8 +21,9 @@ public final class BanLookup {
}
public static BanEntry getBanEntry(final IEssentials ess, final String name) {
final Set<BanEntry> benteries = ess.getServer().getBanList(BanList.Type.NAME).getBanEntries();
for (final BanEntry banEnt : benteries) {
final Set benteries = ess.getServer().getBanList(BanList.Type.NAME).getBanEntries();
for (final Object ob : benteries) {
final BanEntry banEnt = (BanEntry) ob;
if (banEnt.getTarget().equals(name)) {
return banEnt;
}
@@ -0,0 +1,405 @@
package com.earth2me.essentials.craftbukkit;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
public final class Inventories {
private static final int HELM_SLOT = 39;
private static final int CHEST_SLOT = 38;
private static final int LEG_SLOT = 37;
private static final int BOOT_SLOT = 36;
private static final boolean HAS_OFFHAND = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_9_R01);
private static final int INVENTORY_SIZE = HAS_OFFHAND ? 41 : 40;
private Inventories() {
}
public static ItemStack getItemInHand(final Player player) {
if (!HAS_OFFHAND) {
//noinspection deprecation
return player.getInventory().getItemInHand();
}
final PlayerInventory inventory = player.getInventory();
final ItemStack main = inventory.getItemInMainHand();
return !isEmpty(main) ? main : inventory.getItemInOffHand();
}
public static ItemStack getItemInMainHand(final Player player) {
if (!HAS_OFFHAND) {
//noinspection deprecation
return player.getInventory().getItemInHand();
}
return player.getInventory().getItemInMainHand();
}
public static void setItemInMainHand(final Player player, final ItemStack stack) {
if (HAS_OFFHAND) {
player.getInventory().setItemInMainHand(stack);
} else {
//noinspection deprecation
player.setItemInHand(stack);
}
}
public static void setItemInMainHand(final EntityEquipment entityEquipment, final ItemStack stack) {
if (HAS_OFFHAND) {
entityEquipment.setItemInMainHand(stack);
} else {
//noinspection deprecation
entityEquipment.setItemInHand(stack);
}
}
public static void setItemInMainHandDropChance(final EntityEquipment entityEquipment, final float chance) {
if (HAS_OFFHAND) {
entityEquipment.setItemInMainHandDropChance(chance);
} else {
//noinspection deprecation
entityEquipment.setItemInHandDropChance(chance);
}
}
public static boolean containsAtLeast(final Player player, final ItemStack item, int amount) {
for (final ItemStack invItem : player.getInventory().getContents()) {
if (isEmpty(invItem)) {
continue;
}
if (invItem.isSimilar(item)) {
amount -= invItem.getAmount();
if (amount <= 0) {
return true;
}
}
}
return false;
}
public static boolean hasSpace(final Player player, final int maxStack, final boolean includeArmor, ItemStack... items) {
items = normalizeItems(cloneItems(items));
final InventoryData inventoryData = parseInventoryData(player.getInventory(), items, maxStack, includeArmor);
final List<Integer> emptySlots = inventoryData.getEmptySlots();
for (final ItemStack item : items) {
if (isEmpty(item)) {
continue;
}
final int itemMax = Math.max(maxStack, item.getMaxStackSize());
final List<Integer> partialSlots = inventoryData.getPartialSlots().get(item);
while (true) {
if (partialSlots == null || partialSlots.isEmpty()) {
if (emptySlots.isEmpty()) {
return false;
}
emptySlots.remove(0);
if (item.getAmount() > itemMax) {
item.setAmount(item.getAmount() - itemMax);
} else {
break;
}
} else {
final int slot = partialSlots.remove(0);
ItemStack existing = player.getInventory().getItem(slot);
if (isEmpty(existing)) {
existing = item.clone();
existing.setAmount(0);
}
final int amount = item.getAmount();
final int existingAmount = existing.getAmount();
if (amount + existingAmount <= itemMax) {
break;
} else {
item.setAmount(amount + existingAmount - itemMax);
}
}
}
}
return true;
}
public static Map<Integer, ItemStack> addItem(final Player player, final ItemStack... items) {
return addItem(player, 0, false, items);
}
public static Map<Integer, ItemStack> addItem(final Player player, final int maxStack, final ItemStack... items) {
return addItem(player, maxStack, false, items);
}
public static Map<Integer, ItemStack> addItem(final Player player, final int maxStack, final boolean allowArmor, ItemStack... items) {
items = normalizeItems(cloneItems(items));
final Map<Integer, ItemStack> leftover = new HashMap<>();
final InventoryData inventoryData = parseInventoryData(player.getInventory(), items, maxStack, allowArmor);
final List<Integer> emptySlots = inventoryData.getEmptySlots();
for (int i = 0; i < items.length; i++) {
final ItemStack item = items[i];
if (isEmpty(item)) {
continue;
}
final int itemMax = Math.max(maxStack, item.getMaxStackSize());
final List<Integer> partialSlots = inventoryData.getPartialSlots().get(item);
while (true) {
if (partialSlots == null || partialSlots.isEmpty()) {
if (emptySlots.isEmpty()) {
leftover.put(i, item);
break;
}
final int slot = emptySlots.remove(0);
if (item.getAmount() > itemMax) {
final ItemStack split = item.clone();
split.setAmount(itemMax);
player.getInventory().setItem(slot, split);
item.setAmount(item.getAmount() - itemMax);
} else {
player.getInventory().setItem(slot, item);
break;
}
} else {
final int slot = partialSlots.remove(0);
ItemStack existing = player.getInventory().getItem(slot);
if (isEmpty(existing)) {
existing = item.clone();
existing.setAmount(0);
}
final int amount = item.getAmount();
final int existingAmount = existing.getAmount();
if (amount + existingAmount <= itemMax) {
existing.setAmount(amount + existingAmount);
player.getInventory().setItem(slot, existing);
break;
} else {
existing.setAmount(itemMax);
player.getInventory().setItem(slot, existing);
item.setAmount(amount + existingAmount - itemMax);
}
}
}
}
return leftover;
}
public static ItemStack[] getInventory(final Player player, final boolean includeArmor) {
final ItemStack[] items = new ItemStack[INVENTORY_SIZE];
for (int i = 0; i < items.length; i++) {
if (!includeArmor && isArmorSlot(i)) {
items[i] = null;
continue;
}
items[i] = player.getInventory().getItem(i);
}
return items;
}
public static void removeItemExact(final Player player, final ItemStack toRemove, final boolean includeArmor) {
removeItems(player, itemStack -> itemStack.equals(toRemove), includeArmor);
}
public static int removeItemSimilar(final Player player, final ItemStack toRemove, final boolean includeArmor) {
return removeItems(player, itemStack -> itemStack.isSimilar(toRemove), includeArmor);
}
public static int removeItems(final Player player, final Predicate<ItemStack> removePredicate, final boolean includeArmor) {
int removedAmount = 0;
final ItemStack[] items = player.getInventory().getContents();
for (int i = 0; i < items.length; i++) {
if (!includeArmor && isArmorSlot(i)) {
continue;
}
final ItemStack item = items[i];
if (isEmpty(item)) {
continue;
}
if (removePredicate.test(item)) {
removedAmount += item.getAmount();
item.setAmount(0);
player.getInventory().setItem(i, item);
}
}
return removedAmount;
}
public static boolean removeItemAmount(final Player player, final ItemStack toRemove, int amount) {
final List<Integer> clearSlots = new ArrayList<>();
final ItemStack[] items = player.getInventory().getContents();
for (int i = 0; i < items.length; i++) {
final ItemStack item = items[i];
if (isEmpty(item)) {
continue;
}
if (item.isSimilar(toRemove)) {
if (item.getAmount() >= amount) {
item.setAmount(item.getAmount() - amount);
player.getInventory().setItem(i, item);
for (final int slot : clearSlots) {
clearSlot(player, slot);
}
return true;
} else {
amount -= item.getAmount();
clearSlots.add(i);
}
if (amount == 0) {
for (final int slot : clearSlots) {
clearSlot(player, slot);
}
return true;
}
}
}
return false;
}
public static void clearSlot(final Player player, final int slot) {
final ItemStack item = player.getInventory().getItem(slot);
if (!isEmpty(item)) {
item.setAmount(0);
player.getInventory().setItem(slot, item);
}
}
public static void setSlot(final Player inventory, final int slot, final ItemStack item) {
inventory.getInventory().setItem(slot, item);
}
private static ItemStack[] normalizeItems(final ItemStack[] items) {
if (items.length <= 1) {
return items;
}
final ItemStack[] normalizedItems = new ItemStack[items.length];
int nextNormalizedIndex = 0;
inputLoop:
for (final ItemStack item : items) {
if (isEmpty(item)) {
continue;
}
for (int j = 0; j < nextNormalizedIndex; j++) {
final ItemStack normalizedItem = normalizedItems[j];
if (isEmpty(normalizedItem)) {
continue;
}
if (item.isSimilar(normalizedItem)) {
normalizedItem.setAmount(normalizedItem.getAmount() + item.getAmount());
continue inputLoop;
}
}
normalizedItems[nextNormalizedIndex++] = item;
}
return normalizedItems;
}
private static ItemStack[] cloneItems(final ItemStack[] items) {
final ItemStack[] clonedItems = new ItemStack[items.length];
for (int i = 0; i < items.length; i++) {
final ItemStack item = items[i];
if (isEmpty(item)) {
continue;
}
clonedItems[i] = item.clone();
}
return clonedItems;
}
private static InventoryData parseInventoryData(final Inventory inventory, final ItemStack[] items, final int maxStack, final boolean includeArmor) {
final ItemStack[] inventoryContents = inventory.getContents();
final List<Integer> emptySlots = new ArrayList<>();
final HashMap<ItemStack, List<Integer>> partialSlots = new HashMap<>();
for (int i = 0; i < inventoryContents.length; i++) {
if (!includeArmor && isArmorSlot(i)) {
continue;
}
final ItemStack invItem = inventoryContents[i];
if (isEmpty(invItem)) {
emptySlots.add(i);
} else {
for (final ItemStack newItem : items) {
if (invItem.getAmount() < Math.max(maxStack, invItem.getMaxStackSize()) && invItem.isSimilar(newItem)) {
partialSlots.computeIfAbsent(newItem, k -> new ArrayList<>()).add(i);
}
}
}
}
// Convert empty armor slots to partial slots if we have armor items in the inventory, otherwise remove them from the empty slots.
if (includeArmor) {
ItemStack helm = null;
ItemStack chest = null;
ItemStack legs = null;
ItemStack boots = null;
for (final ItemStack item : items) {
if (isEmpty(item)) {
continue;
}
if (helm == null && MaterialUtil.isHelmet(item.getType())) {
helm = item;
if (emptySlots.contains(HELM_SLOT)) {
partialSlots.computeIfAbsent(helm, k -> new ArrayList<>()).add(HELM_SLOT);
}
} else if (chest == null && MaterialUtil.isChestplate(item.getType())) {
chest = item;
if (emptySlots.contains(CHEST_SLOT)) {
partialSlots.computeIfAbsent(chest, k -> new ArrayList<>()).add(CHEST_SLOT);
}
} else if (legs == null && MaterialUtil.isLeggings(item.getType())) {
legs = item;
if (emptySlots.contains(LEG_SLOT)) {
partialSlots.computeIfAbsent(legs, k -> new ArrayList<>()).add(LEG_SLOT);
}
} else if (boots == null && MaterialUtil.isBoots(item.getType())) {
boots = item;
if (emptySlots.contains(BOOT_SLOT)) {
partialSlots.computeIfAbsent(boots, k -> new ArrayList<>()).add(BOOT_SLOT);
}
}
}
emptySlots.remove((Object) HELM_SLOT);
emptySlots.remove((Object) CHEST_SLOT);
emptySlots.remove((Object) LEG_SLOT);
emptySlots.remove((Object) BOOT_SLOT);
}
return new InventoryData(emptySlots, partialSlots);
}
private static boolean isEmpty(final ItemStack stack) {
return stack == null || MaterialUtil.isAir(stack.getType());
}
private static boolean isArmorSlot(final int slot) {
return slot == HELM_SLOT || slot == CHEST_SLOT || slot == LEG_SLOT || slot == BOOT_SLOT;
}
}
@@ -0,0 +1,24 @@
package com.earth2me.essentials.craftbukkit;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.List;
public class InventoryData {
private final List<Integer> emptySlots;
private final HashMap<ItemStack, List<Integer>> partialSlots;
public InventoryData(List<Integer> emptySlots, HashMap<ItemStack, List<Integer>> partialSlots) {
this.emptySlots = emptySlots;
this.partialSlots = partialSlots;
}
public List<Integer> getEmptySlots() {
return emptySlots;
}
public HashMap<ItemStack, List<Integer>> getPartialSlots() {
return partialSlots;
}
}
@@ -1,245 +0,0 @@
package com.earth2me.essentials.craftbukkit;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/*
* This class can be removed when https://github.com/Bukkit/CraftBukkit/pull/193 is accepted to CraftBukkit
*/
public final class InventoryWorkaround {
/*
Spigot 1.9, for whatever reason, decided to merge the armor and main player inventories without providing a way
to access the main inventory. There's lots of ugly code in here to work around that.
*/
private static final int USABLE_PLAYER_INV_SIZE = 36;
private static final boolean IS_OFFHAND = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_9_R01);
private InventoryWorkaround() {
}
private static int firstPartial(final Inventory inventory, final ItemStack item, final int maxAmount) {
if (item == null) {
return -1;
}
final ItemStack[] stacks = inventory.getContents();
for (int i = 0; i < stacks.length; i++) {
final ItemStack cItem = stacks[i];
if (cItem != null && cItem.getAmount() < maxAmount && cItem.isSimilar(item)) {
return i;
}
}
return -1;
}
private static boolean isCombinedInventory(final Inventory inventory) {
return inventory instanceof PlayerInventory && inventory.getContents().length > USABLE_PLAYER_INV_SIZE;
}
// Clears inventory without clearing armor
public static void clearInventoryNoArmor(final PlayerInventory inventory) {
if (isCombinedInventory(inventory)) {
for (int i = 0; i < USABLE_PLAYER_INV_SIZE; i++) {
inventory.setItem(i, null);
}
} else {
inventory.clear();
}
}
private static Inventory makeTruncatedPlayerInventory(final PlayerInventory playerInventory) {
final Inventory fakeInventory = Bukkit.getServer().createInventory(null, USABLE_PLAYER_INV_SIZE);
fakeInventory.setContents(Arrays.copyOf(playerInventory.getContents(), fakeInventory.getSize()));
return fakeInventory;
}
// Returns what it couldn't store
// This will will abort if it couldn't store all items
public static Map<Integer, ItemStack> addAllItems(final Inventory inventory, final ItemStack... items) {
final ItemStack[] contents = inventory.getContents();
final Inventory fakeInventory;
if (isCombinedInventory(inventory)) {
fakeInventory = makeTruncatedPlayerInventory((PlayerInventory) inventory);
} else {
fakeInventory = Bukkit.getServer().createInventory(null, inventory.getType());
fakeInventory.setContents(contents);
}
final Map<Integer, ItemStack> overflow = addItems(fakeInventory, items);
if (overflow.isEmpty()) {
addItems(inventory, items);
return null;
}
return addItems(fakeInventory, items);
}
public static Map<Integer, ItemStack> addAllOversizedItems(final Inventory inventory, final int oversizedStacks, final ItemStack... items) {
final ItemStack[] contents = inventory.getContents();
final Inventory fakeInventory;
if (isCombinedInventory(inventory)) {
fakeInventory = makeTruncatedPlayerInventory((PlayerInventory) inventory);
} else {
fakeInventory = Bukkit.getServer().createInventory(null, inventory.getType());
fakeInventory.setContents(contents);
}
final Map<Integer, ItemStack> overflow = addOversizedItems(fakeInventory, oversizedStacks, items);
if (overflow.isEmpty()) {
addOversizedItems(inventory, oversizedStacks, items);
return null;
}
return overflow;
}
// Returns what it couldn't store
public static Map<Integer, ItemStack> addItems(final Inventory inventory, final ItemStack... items) {
return addOversizedItems(inventory, 0, items);
}
// Returns what it couldn't store
// Set oversizedStack to below normal stack size to disable oversized stacks
public static Map<Integer, ItemStack> addOversizedItems(final Inventory inventory, final int oversizedStacks, final ItemStack... items) {
if (isCombinedInventory(inventory)) {
final Inventory fakeInventory = makeTruncatedPlayerInventory((PlayerInventory) inventory);
final Map<Integer, ItemStack> overflow = addOversizedItems(fakeInventory, oversizedStacks, items);
for (int i = 0; i < fakeInventory.getContents().length; i++) {
inventory.setItem(i, fakeInventory.getContents()[i]);
}
return overflow;
}
final Map<Integer, ItemStack> leftover = new HashMap<>();
/*
* TODO: some optimization - Create a 'firstPartial' with a 'fromIndex' - Record the lastPartial per Material -
* Cache firstEmpty result
*/
// combine items
final ItemStack[] combined = new ItemStack[items.length];
for (final ItemStack item : items) {
if (item == null || item.getAmount() < 1) {
continue;
}
for (int j = 0; j < combined.length; j++) {
if (combined[j] == null) {
combined[j] = item.clone();
break;
}
if (combined[j].isSimilar(item)) {
combined[j].setAmount(combined[j].getAmount() + item.getAmount());
break;
}
}
}
for (int i = 0; i < combined.length; i++) {
final ItemStack item = combined[i];
if (item == null || item.getType() == Material.AIR) {
continue;
}
while (true) {
// Do we already have a stack of it?
final int maxAmount = Math.max(oversizedStacks, item.getType().getMaxStackSize());
final int firstPartial = firstPartial(inventory, item, maxAmount);
// Drat! no partial stack
if (firstPartial == -1) {
// Find a free spot!
final int firstFree = inventory.firstEmpty();
if (firstFree == -1) {
// No space at all!
leftover.put(i, item);
break;
} else {
// More than a single stack!
if (item.getAmount() > maxAmount) {
final ItemStack stack = item.clone();
stack.setAmount(maxAmount);
inventory.setItem(firstFree, stack);
item.setAmount(item.getAmount() - maxAmount);
} else {
// Just store it
inventory.setItem(firstFree, item);
break;
}
}
} else {
// So, apparently it might only partially fit, well lets do just that
final ItemStack partialItem = inventory.getItem(firstPartial);
final int amount = item.getAmount();
final int partialAmount = partialItem.getAmount();
// Check if it fully fits
if (amount + partialAmount <= maxAmount) {
partialItem.setAmount(amount + partialAmount);
break;
}
// It fits partially
partialItem.setAmount(maxAmount);
item.setAmount(amount + partialAmount - maxAmount);
}
}
}
return leftover;
}
@SuppressWarnings("deprecation")
public static void setItemInMainHand(final Player p, final ItemStack item) {
if (IS_OFFHAND) {
p.getInventory().setItemInMainHand(item);
} else {
p.setItemInHand(item);
}
}
@SuppressWarnings("deprecation")
public static void setItemInMainHand(final EntityEquipment invent, final ItemStack item) {
if (IS_OFFHAND) {
invent.setItemInMainHand(item);
} else {
invent.setItemInHand(item);
}
}
@SuppressWarnings("deprecation")
public static void setItemInMainHandDropChance(final EntityEquipment invent, final float chance) {
if (IS_OFFHAND) {
invent.setItemInMainHandDropChance(chance);
} else {
invent.setItemInHandDropChance(chance);
}
}
public static void setItemInOffHand(final Player p, final ItemStack item) {
if (IS_OFFHAND) {
p.getInventory().setItemInOffHand(item);
}
}
public static int clearItemInOffHand(final Player p, final ItemStack item) {
if (IS_OFFHAND) {
int removedAmount = 0;
if (p.getInventory().getItemInOffHand().getType().equals(item.getType())) {
removedAmount = p.getInventory().getItemInOffHand().getAmount();
p.getInventory().setItemInOffHand(null);
}
return removedAmount;
}
return 0;
}
}
@@ -1,6 +1,7 @@
package com.earth2me.essentials.economy.vault;
import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.OfflinePlayerStub;
import com.earth2me.essentials.api.NoLoanPermittedException;
import com.earth2me.essentials.api.UserDoesNotExistException;
import com.earth2me.essentials.config.EssentialsUserConfiguration;
@@ -11,6 +12,7 @@ import net.ess3.api.MaxMoneyException;
import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.economy.EconomyResponse;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import java.io.File;
import java.math.BigDecimal;
@@ -308,21 +310,27 @@ public class VaultEconomyProvider implements Economy {
npcConfig.setProperty("last-account-name", player.getName());
npcConfig.setProperty("money", ess.getSettings().getStartingBalance());
npcConfig.blockingSave();
ess.getUserMap().trackUUID(player.getUniqueId(), player.getName(), false);
// This will load the NPC into the UserMap + UUID cache
ess.getUsers().addCachedNpcName(player.getUniqueId(), player.getName());
ess.getUsers().getUser(player.getUniqueId());
return true;
}
// Loading a v4 UUID that we somehow didn't track, mark it as a normal player and hope for the best, vault sucks :/
try {
if (ess.getSettings().isDebug()) {
ess.getLogger().info("Vault requested a player account creation for a v4 UUID: " + player);
}
ess.getUserMap().load(player);
return true;
} catch (UserDoesNotExistException e) {
e.printStackTrace();
return false;
if (ess.getSettings().isDebug()) {
ess.getLogger().info("Vault requested a player account creation for a v4 UUID: " + player);
}
final Player userPlayer;
if (player instanceof Player) {
userPlayer = (Player) player;
} else {
final OfflinePlayerStub essPlayer = new OfflinePlayerStub(player.getUniqueId(), ess.getServer());
essPlayer.setName(player.getName());
userPlayer = essPlayer;
}
ess.getUsers().getUser(userPlayer);
return true;
}
@Override
@@ -2,6 +2,7 @@ package com.earth2me.essentials.items;
import com.earth2me.essentials.IConf;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.VersionUtil;
@@ -156,14 +157,14 @@ public abstract class AbstractItemDb implements IConf, net.ess3.api.IItemDb {
} else if (args[0].equalsIgnoreCase("hand")) {
is.add(user.getItemInHand().clone());
} else if (args[0].equalsIgnoreCase("inventory") || args[0].equalsIgnoreCase("invent") || args[0].equalsIgnoreCase("all")) {
for (final ItemStack stack : user.getBase().getInventory().getContents()) {
for (final ItemStack stack : Inventories.getInventory(user.getBase(), true)) {
if (stack == null || stack.getType() == Material.AIR) {
continue;
}
is.add(stack.clone());
}
} else if (args[0].equalsIgnoreCase("blocks")) {
for (final ItemStack stack : user.getBase().getInventory().getContents()) {
for (final ItemStack stack : Inventories.getInventory(user.getBase(), true)) {
if (stack == null || stack.getType() == Material.AIR || !stack.getType().isBlock()) {
continue;
}
@@ -3,6 +3,7 @@ package com.earth2me.essentials.perm;
import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.TriState;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import java.util.List;
@@ -10,9 +11,15 @@ import java.util.function.Function;
import java.util.function.Supplier;
public interface IPermissionsHandler {
String getGroup(Player base);
boolean addToGroup(OfflinePlayer base, String group);
List<String> getGroups(Player base);
boolean removeFromGroup(OfflinePlayer base, String group);
String getGroup(OfflinePlayer base);
List<String> getGroups(OfflinePlayer base);
List<String> getGroups();
boolean canBuild(Player base, String group);
@@ -10,8 +10,10 @@ import com.earth2me.essentials.perm.impl.ModernVaultHandler;
import com.earth2me.essentials.perm.impl.SuperpermsHandler;
import com.earth2me.essentials.utils.TriState;
import com.google.common.collect.ImmutableSet;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -34,7 +36,7 @@ public class PermissionsHandler implements IPermissionsHandler {
}
@Override
public String getGroup(final Player base) {
public String getGroup(final OfflinePlayer base) {
final long start = System.nanoTime();
String group = handler.getGroup(base);
if (group == null) {
@@ -45,16 +47,42 @@ public class PermissionsHandler implements IPermissionsHandler {
}
@Override
public List<String> getGroups(final Player base) {
public List<String> getGroups(final OfflinePlayer base) {
final long start = System.nanoTime();
List<String> groups = handler.getGroups(base);
final List<String> groups = new ArrayList<>();
groups.add(defaultGroup);
groups.addAll(handler.getGroups(base));
checkPermLag(start, String.format("Getting groups for %s", base.getName()));
return Collections.unmodifiableList(groups);
}
@Override
public List<String> getGroups() {
final long start = System.nanoTime();
List<String> groups = handler.getGroups();
if (groups == null || groups.isEmpty()) {
groups = Collections.singletonList(defaultGroup);
}
checkPermLag(start, String.format("Getting groups for %s", base.getName()));
checkPermLag(start, "Getting all groups");
return Collections.unmodifiableList(groups);
}
@Override
public boolean addToGroup(OfflinePlayer base, String group) {
final long start = System.nanoTime();
final boolean result = handler.addToGroup(base, group);
checkPermLag(start, String.format("Adding group to %s", base.getName()));
return result;
}
@Override
public boolean removeFromGroup(OfflinePlayer base, String group) {
final long start = System.nanoTime();
final boolean result = handler.removeFromGroup(base, group);
checkPermLag(start, String.format("Removing group from %s", base.getName()));
return result;
}
@Override
public boolean canBuild(final Player base, final String group) {
return handler.canBuild(base, group);
@@ -3,6 +3,7 @@ package com.earth2me.essentials.perm.impl;
import net.milkbowl.vault.chat.Chat;
import net.milkbowl.vault.permission.Permission;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
@@ -32,13 +33,34 @@ public abstract class AbstractVaultHandler extends SuperpermsHandler {
}
@Override
public String getGroup(final Player base) {
return perms.getPrimaryGroup(base);
public String getGroup(final OfflinePlayer base) {
if (base.isOnline()) {
return perms.getPrimaryGroup(base.getPlayer());
}
return perms.getPrimaryGroup(null, base);
}
@Override
public List<String> getGroups(final Player base) {
return Arrays.asList(perms.getPlayerGroups(base));
public List<String> getGroups(final OfflinePlayer base) {
if (base.isOnline()) {
return Arrays.asList(perms.getPlayerGroups(base.getPlayer()));
}
return Arrays.asList(perms.getPlayerGroups(null, base));
}
@Override
public List<String> getGroups() {
return Arrays.asList(perms.getGroups());
}
@Override
public boolean addToGroup(OfflinePlayer base, String group) {
return perms.playerAddGroup(null, base, group);
}
@Override
public boolean removeFromGroup(OfflinePlayer base, String group) {
return perms.playerRemoveGroup(null, base, group);
}
@Override
@@ -70,11 +70,19 @@ public class LuckPermsHandler extends ModernVaultHandler {
// If the player doesn't exist in the UserMap, just skip
// Ess will cause performance problems for permissions checks if it attempts to
// perform i/o to load the user data otherwise.
if (!ess.getUserMap().userExists(target.getUniqueId())) {
if (!ess.getUsers().getAllUserUUIDs().contains(target.getUniqueId())) {
return;
}
final User user = ess.getUsers().loadUncachedUser(target.getUniqueId());
// This will occur for first time players during join,
// None of our contexts would apply to that kind of person anyway,
// lets just skip :O
if (user == null) {
return;
}
final User user = ess.getUser(target);
for (Calculator calculator : this.calculators) {
calculator.function.apply(user).forEach(value -> consumer.accept(calculator.id, value));
}
@@ -5,6 +5,7 @@ import com.earth2me.essentials.User;
import com.earth2me.essentials.perm.IPermissionsHandler;
import com.earth2me.essentials.utils.TriState;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachmentInfo;
@@ -21,12 +22,27 @@ public class SuperpermsHandler implements IPermissionsHandler {
}
@Override
public String getGroup(final Player base) {
public boolean addToGroup(OfflinePlayer base, String group) {
return false;
}
@Override
public boolean removeFromGroup(OfflinePlayer base, String group) {
return false;
}
@Override
public String getGroup(final OfflinePlayer base) {
return null;
}
@Override
public List<String> getGroups(final Player base) {
public List<String> getGroups(final OfflinePlayer base) {
return null;
}
@Override
public List<String> getGroups() {
return null;
}
Loaded 100 of 239 files, more files were not shown because too many files have changed in this diff. Show more