Compare commits

...
247 Commits
Author SHA1 Message Date
md678685 8046b8594a Release 2.18.0
🎉
2020-07-09 20:15:30 +01:00
pop4959 6c64aaefec Fix issue with /remove skeletonhorse (#3477)
Fixes a problem where skeleton trapped horses cannot be killed in commands such as `/remove skeletonhorse` (or even `/remove all`) because they are tamed by non-player entities. There is a separate command for killing tamed entities, however this kills other player-owned entities which is undesirable.

This can be replicated easily by spawning some skeleton traps like so:
`/summon skeleton_horse ~ ~ ~ {SkeletonTrap:1}`
and then attempting to run `/killall skeletonhorse`.

After this small change, any tamed skeleton horses will be retained, but non-player-owned skeleton horses will be removed as appropriate.

Closes #3475.
2020-07-09 19:36:08 +01:00
MD 07fa87dc6a Deny tpahere requests to players without permission to accept (#3478) 2020-07-09 10:45:14 -07:00
pop4959 b58c98bea0 Add jail contexts (#3476)
Someone probably wants these. Also, who in the world decided that `IJails::getList` should throw an exception?

https://user-images.githubusercontent.com/17698576/87005099-57ffc080-c173-11ea-956f-0b64a52c7f40.png

https://user-images.githubusercontent.com/17698576/87005107-5afab100-c173-11ea-8d25-6efde7ee9026.png

https://user-images.githubusercontent.com/17698576/87005382-c5135600-c173-11ea-9335-e80e322afd89.png

https://user-images.githubusercontent.com/17698576/87005299-a44b0080-c173-11ea-8789-f2f0d8b9cc4b.png
2020-07-09 08:41:25 +01:00
zml 08e553bd1a Hide EssX commands from non-core modules in autocomplete (#3473)
quick little thing so people stop complaining
2020-07-09 08:37:41 +01:00
Josh Roy e35fb82bc2 Add UserTeleportHomeEvent (#3403)
Adds an event which allows developers to see & cancel when users attempt to teleport home. This event is needed over `PreTeleportEvent` due to the fact that it would be extremely difficult to accurately filter it by the /home command.

Closes #3401
2020-07-08 19:53:32 +01:00
MD a92ca63ca9 Replace UserTeleportEvent with more sane events (#3192)
This PR replaces UserTeleportEvent with two new teleport events called at different stages:
- TeleportWarmupEvent; called before a user's teleport warmup begins and allows plugins to skip it or prevent a teleportation
- PreTeleportEvent; called after the warmup completes but before any safety checks are carried out

This is a **breaking change** as it removes UserTeleportEvent, but the previous event isn't useful or descriptive in its current form and was only recently introduced, so it's unlikely that many plugins already depend on this.

Closes #2506.
2020-07-08 19:51:00 +01:00
pop4959 cbfad7b320 Choose better elevation for random nether teleport (#3466) 2020-07-07 18:19:53 -07:00
MD c16987fb87 Add config option to hide join/quit messages above X players (#3464) 2020-07-07 15:16:20 -07:00
Flask Bot 477f5a7841 New Crowdin updates (#3462) 2020-07-07 20:41:06 +01:00
md678685 6f149224d1 Fix reporting of economy backend to bStats 2020-07-06 21:15:03 +01:00
Josh Roy 1a6ad2fdb0 Allow for specifying amount to increase itemstack in /more (#3302)
Fixes #2342.
2020-07-06 19:55:07 +01:00
pop4959 76e511a774 Implement random teleport command (#3418)
Adds `/tpr` and `/settpr` commands, which respectively allow you to teleport randomly or set teleportation parameters.

Server owners are expected to set the center with `/settpr` before players can use `/tpr`. They can also set the minimum and maximum range to be teleported from the center (default 0-1000).

Also includes an event where plugins can adjust or cancel the teleport.

Closes #3154.
2020-07-06 19:53:43 +01:00
Josh RoyandMD 9681933ec2 Add mute expiry time in mute messages (#3329)
Co-authored-by: MD <1917406+md678685@users.noreply.github.com>

Closes #1211.
2020-07-06 19:52:51 +01:00
711bfed557 Add itemlore command (#3331)
Co-authored-by: pop4959 <pop4959@gmail.com>
Co-authored-by: MD <1917406+md678685@users.noreply.github.com>

Adds a command to add to or clear an item's lore.

Closes #1911.
2020-07-06 19:46:57 +01:00
zml 016a1b3421 Handle explicitly denied permissions with no perms plugin (#3419)
to finally end the `/hat` saga, hopefully for good
2020-07-06 19:40:47 +01:00
MD 01b9ec4a42 Allow preventing bed and respawn anchor explosions in Protect (#3453)
Adds `bed-explosion` and `respawn-anchor-explosion` options to the Protect config.
2020-07-06 19:38:07 +01:00
pop4959 9b729dd091 unchange 1.13 naming 2020-07-06 11:34:43 -07:00
triagonal 0a73be2082 Add PrivateMessageSentEvent and fix PrivateMessagePreSendEvent (#3432)
This PR introduces a new private messaging related event `PrivateMessageSentEvent` and fixes a mistake made on my part during the implementation of `PrivateMessagePreSendEvent`.

Recently when attempting to use the pre-send event in order to play a sound to the recipient of a message, I found that the event was not completely adequate for my use case. Between the firing of the pre-send event and the end of the delivery attempt, the message delivery could fail for a number of reasons (e.g. messages toggled off, sender ignored, unreachable recipient) with no straightforward way of determining this using the existing event.

I believe that a second event fired after the message sending attempt has been fully processed will provide a simple method of determining whether or not a message was successfully delivered by including the [`MessageResponse`](https://github.com/EssentialsX/Essentials/blob/60f54ee37d9472848e28d2e64adc2735e10975c1/Essentials/src/com/earth2me/essentials/messaging/IMessageRecipient.java#L84) in the event.

Additionally, I found that when implementing the pre-send event, I mistakenly passed an incorrect reference for the `sender` meaning that currently there's no clean or reliable way to determine if `sender` is the `Console` or a `User` (`instanceof` doesn't work, which leaves checking by name or using reflection).
2020-07-06 19:34:13 +01:00
md678685 c668879070 Add slightly more sanity to Vault code
This subtly changes how backend permissions plugins are reported on
bStats. (Previously, somehow the LP service provider was detected as
originating from Vault...?)
2020-07-06 19:09:20 +01:00
md678685 c4d318b7d0 Deprecate TimedTeleport 2020-07-06 18:49:25 +01:00
pop4959 e7d9dbfbcf Allow preventing bed and respawn anchor explosions in EssentialsProtect 2020-07-05 18:46:23 -07:00
MD 1be3daf0b5 Update bStats Metrics and add wrapper class for new graphs (#3451)
This PR updates the version of the bStats Metrics class to the latest version, supporting plugin IDs in place of just plugin names. It also adds the following graphs:
- Active permissions backend
- Active economy backend
- Whether or not a command has been used as a bar chart (pending bStats backend implementation)
- Version history graph as a multiline graph (also pending bStats impl)

It also removes the weird `getMetrics` and `setMetrics` APIs which should never have been API in the first place.
2020-07-05 19:30:01 +01:00
Josh Roy 8f86849aec Fix 65f8883 breaking offline home listing (#3446) 2020-07-02 18:59:40 -07:00
Josh Roy 0b4ee9e73e Add hidden config to stop throwing errors for passengers (#3445) 2020-07-02 15:30:22 -07:00
Josh Roy 65f88834ba Fix further AME(s) in /home (#3444) 2020-07-02 22:58:40 +01:00
pop4959 024c56efdd Fix recipe command on Paper (#3404) 2020-07-01 15:19:42 -07:00
pop4959 9c487b0aac Match kit name in delkit (#3396)
This allows deleting kits ignoring case; fixes #3370.

I don't know if this is the ideal fix, but everything else for kits seems to nuke the letter casing. Not really sure why in `Kits.java`, the keys needs to get lowercased in a new mock `ConfigurationSection`. It just seems like this would purely make it harder to access the same section again in the real config. Instead, I just added a different method that matches the real config name of the kit (as set in `/createkit`, which currently allows uppercase).
2020-07-01 22:12:43 +01:00
pop4959 d743f928ad Ignore NPCs in EntityCombustByEntityEvent (#3389) 2020-07-01 22:06:49 +01:00
pop4959 07e2fe3af1 Improve suicide and kill commands (#3388)
Fixes #3189 

This PR makes improvements to the suicide and kill commands, namely:
1) Call `EntityDamageEvent` with damage equal to `Float.MAX_VALUE`, which is the amount that is inflicted by `/minecraft:kill`.
2) Removes the calls to `Damageable::damage` which ends up damaging the player with `DamageSource.GENERIC`, and later causing another `EntityDamageEvent` where as a result the last damage cause gets set to `EntityDamageEvent.DamageCause.CUSTOM`. Thus, the `EntityDamageEvent` that Essentials calls gets rendered useless when someone tries to get the damage cause of the player in `PlayerDeathEvent`. Setting health to zero forcibly kills the player without causing damage.
3) Add `getTabCompleteOptions` to the suicide command, as it currently incorrectly suggests players.
2020-07-01 22:04:46 +01:00
pop4959 9f384c71f3 Confirm home replacement when overwriting existing homes (#3338)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
Co-authored-by: MD <1917406+md678685@users.noreply.github.com>

Warns the player that they are trying to replace a home, if they try to set one with the same name, when `confirm-home-overwrite` is set to `true` in the config.

https://user-images.githubusercontent.com/17698576/83004206-3633eb00-9fc4-11ea-9317-fe245fed9cbb.png

Fixes #2038
Closes #2847
2020-07-01 22:03:22 +01:00
Josh Roy 7a5aea0bcf EditSign Command (#3415)
bro so epic bro
2020-07-01 21:58:11 +01:00
Josh Roy b6c9bc1439 Add command + money queues to process after items in kits (#3434)
Fixes #3431
2020-07-01 21:51:10 +01:00
Josh Roy b7f38517ef Fix some reported bugs regarding teleportation. (#3433)
Fixes #3420
Fixes #3430
2020-06-30 17:00:20 +01:00
Josh Roy 60f54ee37d Fix relocation pattern for EssentialsXSpawn (#3427) 2020-06-28 19:14:06 -07:00
Josh Roy adf1273bf9 Fix RGB support in prefixes/suffixes (#3422) 2020-06-28 16:36:17 +01:00
MD 3c79e9e59d Update items.json from generator (#3394)
This PR replaces the current `items.json` file with one generated *solely* by ItemDbGenerator.

In 1.13.x, the `items.json` shipped with EssentialsX was generated using the [genItemsFlat script and data](https://github.com/md678685/essx-scripts). For 1.14 and 1.15, this was merged with the output of [ItemDbGenerator](https://github.com/EssentialsX/ItemDbGenerator), but this is an awkward and unreliable process involving three separate tools. This has now been consolidated into a single tool, which is now on par with the old process.
2020-06-27 22:38:32 +01:00
1ab1b5713e Update to 1.16.1 (#3408)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
Co-authored-by: md678685 <1917406+md678685@users.noreply.github.com>
Co-authored-by: pop4959 <pop4959@gmail.com>
2020-06-27 12:17:35 -07:00
Flask-Bot edf2f295d1 Update Crowdin configuration file 2020-06-27 16:41:40 +01:00
pop4959 c043416b11 Fix spawner provider on 1.16 (#3412) 2020-06-24 23:25:14 -07:00
Josh Roy 4a471f0a93 Provider Rework (#3407)
Moved providers around, made them make sense, profit
2020-06-24 22:00:59 +01:00
md678685 04a1d8197f Update PaperLib to 1.0.4 2020-06-24 18:08:39 +01:00
Josh Roy d9bf099c3d Reduce sync loads for teleporting (#3102)
This PR reduces the number of sync loads occurring on any teleport caused by essentials.

Fixes #2861
Fixes #2287
Fixes #3274
Fixes #3201
Fixes #2120

Before this PR, essentials would get a block multiple times causing sync loads to check if it was safe to teleport to. Now, the target block's chunk if fetched async with PaperLib and passed along to `LocationUtil#isBlockUnsafeForUser` (which internally calls other LocationUtil methods what that chunk object) resulting in the chunk only loading once, off the main thread. The only operations remaining on the main thread is `LocationUtil#getSafeDestination`. This is due to the method's recursion which would be a pain to move async. **However:** since the chunk was already loaded async, `LocationUtil#getSafeDestination` most of the time won't cause sync chunk loads. The only time it would cause sync chunk loads is with an unsafe location near a chunk border.

-----------------------------------------

* Reduce sync teleporting loads

* Avoid argument re-assigning

* Remove async teleports when unnecessary

* Make exceptions cleaner

* Async all the things

Made an async version of every method with fallbacks for deprecated methods.

* Remove old now fallback method

* Migrate everything to the new async teleport API

* Update ITeleport javadocs

* Fix invoking via async context

* Fix /jail using deprecated method

* Fix jail join handler using deprecated method

* Rename all teleport classes to indicate async

* Remove deprecated methods

* Add (and deprecate) old teleport api

* Revert TimedTeleport.java

* Reduce Diff

* Add legacy sendToJail method

* Reduce Diff Further

* Use getNewExceptionFuture in Commandtpo

* Use getNewExceptionFuture everywhere

* Fix even more usages

* Revert LocationUtil.java

* Fix issue causing unsafe locations to not work properly

* Add deprecated notice in IUser implementation

* Use CompletableFuture#completeExceptionally for exceptions

* Use Essentials' logger in EssentialsCommand#showError

* Return implementation rather than interface

* Avoid possible deadlocks with entity ejections

* Nuke some sync loads with homes

Took 7 hours and 2 PRs to paper but it's here!

* Fix ABI and make the codestyle worse

* Make the codestyle worse because muh diff

* Further ruin the codestyle

* Fix error messages not showing in TimedTeleports

* Improve messages around beds for /home

* Fix #3274

Allow unsafe locations for different worlds + spectator mode

* Fix fly safety operators
2020-06-24 09:52:25 +01:00
Jason d2f2140be9 Fix a messages.properties message (#3391)
It's a small change but I figured more consistency could be nice
2020-06-19 17:15:52 +01:00
pop4959 04f88e460b Add missing tl keys for tempbanip (#3387) 2020-06-16 18:39:22 -07:00
pop4959 d64f73e719 Add support for translating command description and usage (#3284) 2020-06-16 13:39:48 -07:00
Josh Roy 2ab4dcbc11 Add option to remove vanishing items from keepinv users (#3328) 2020-06-15 16:22:00 -07:00
846043e9a0 Add settings to protect items from explosions (#2504)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
Co-authored-by: pop4959 <pop4959@gmail.com>

Adds protection settings to Protect to block item damage when entities such as wither skulls, fireballs, TNT and creepers explode.

Closes #2284.
2020-06-15 13:54:16 +01:00
MD ea57e4ae01 Add serialize method to ItemResolvers for custom serialization (#3307)
Add an optional `serialize` method to `ItemResolver`s which plugins can implement in order to add custom items to `/createkit`. Also improves ItemResolver docs.

Closes #3305, closes #3216.
2020-06-15 13:46:44 +01:00
Josh Roy 6aa5e5cc4a Add config option to control selling names items with /sell (#3314)
Adds an `allow-selling-named-items` config option, which allows server admins to enable/disable the ability to sell named items with `/sell`.

Closes #1988.
Closes #908.
Closes #2196.
2020-06-15 13:44:46 +01:00
oxygencraft 3e5bd4cf09 Deny teleport requests to players lacking permission to accept (#3361)
This PR will deny any teleport requests to players lacking permission to accept the request (`essentials.tpaccept`).

Closes #1259.
2020-06-15 13:36:13 +01:00
TehBrian 3d096c1f31 Fix inconsistent coloring in messages (#3366)
Fix two inconsistencies that look like this:

https://user-images.githubusercontent.com/32250137/84316124-971d0080-ab38-11ea-8297-73f978e79a57.png

The period's color at the end is out of place. This pull-request fixes that by setting the period's color to `§4` instead of `§6`.
2020-06-15 13:35:13 +01:00
Glare b5b6bce758 Ensure RemoveEffectsOnHeal config setting is actually registered (#3377) 2020-06-13 09:40:42 -07:00
Jasonandtriagonal 46ed8e954f Add config.yml note (#3359)
Co-authored-by: triagonal <10545540+triagonal@users.noreply.github.com>

"The player's bed respawn point is still set by Minecraft even if `update-bed-at-daytime` is set to `false` in config, meaning that the entire feature is indeed ineffective on Minecraft 1.15 and above."
2020-06-10 13:40:05 +01:00
pop4959 cfca2f7550 Mention setworth command in worth.yml (#3364) 2020-06-10 13:37:55 +01:00
MDandJosh Roy a09df9bf3a Add UTF8 support for .properties files (#3358)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>

Based on edaa4f6, this allows messages files to be read in UTF8 without the need for native2ascii conversion. This also removes the native2ascii-maven-plugin, previously used to convert Crowdin translations to a compatible format. I've tested this briefly and it appears to work correctly with both internal translations and custom messages.
2020-06-07 12:06:33 +01:00
Josh Roy dc2462c277 Add option to change disposal title via sign (#3269)
Closes #2628.
2020-06-05 16:16:47 +01:00
md678685 25c7ebcf39 Remove BuildTools script and update README 2020-06-05 15:22:40 +01:00
pop4959 baab65d776 Add support for permission contexts (#3320)
As discussed in #2960. Allows Essentials to register contexts with permission plugins that support them. A working implementation for LuckPerms is included in this PR. PermissionsEx 2 also has support for registering contexts, however it should probably be added at a later date, since as per zml2008 on Discord, the API is not yet stable.

https://user-images.githubusercontent.com/17698576/82718550-f5507500-9c57-11ea-970d-9d5f8bce8037.png
2020-06-03 21:36:27 +01:00
pop4959 9e2b906048 Display date diff correctly (#3292)
There is an age old issue in Essentials which causes date diffs (such as those displayed in teleportation delays, mutes, and temp bans) to display incorrectly to the user when the command is run. After looking into this a bit, it looks like the reason for this is that if there is even a 1 ms time difference between parsing the date diff and displaying it, the time displayed will be truncated by an entire second. This PR fixes this problem by adding 50 ms of buffer time to the date object *only* when it is calculating the date diff string. This is not significant enough to be noticed by users, and allows Essentials code to correctly generate the date diff string as long as it does so within 50 ms of parsing it.

As a theoretical example... lets say a user is muted for 1 year. If 1 ms passed (in code prior to this PR) between parsing and displaying the date diff, then the displayed time will be 11 months, 29 days, 23 hours. This is because 1 year - 1 ms is being truncated down and then Essentials lops off time accuracy beyond the 3 most significant terms. After this PR, the date diff will be parsed normally, but when the display string is being calculated, it will use 1 year + 50 ms (and if 1 ms passed, then that would be 1 year + 49 ms), which gets truncated to 1 year.

As a practical example:
https://user-images.githubusercontent.com/17698576/82106444-d55c0700-96d5-11ea-8290-377442e4f9fe.png

Quite often (I'd say about half of the time) before this PR, the date diff will display like this, when the example command `/mute <player> 1y` is run.

https://user-images.githubusercontent.com/17698576/82106467-063c3c00-96d6-11ea-9da2-3dc1556add14.png

After this PR, the date diff displays correctly every time.

Fixes #3349.
2020-05-30 15:18:16 +01:00
pop4959 9f3c2683ae Clean up providers a bit (#3279) 2020-05-28 12:06:03 -07:00
pop4959 9e01a1a427 Player should not be able to send empty shout/question messages (#3341) 2020-05-28 11:45:05 -07:00
pop4959 db729241c9 Fix issue with eco reset requiring 3 args (#3340) 2020-05-28 11:44:46 -07:00
d5d8c80d74 Protect Armor Stands + Item Frames (#3270)
Co-authored-by: JRoy <joshroy126@gmail.com>
Co-authored-by: AlexTheCoder <alexjmeech@gmail.com>
2020-05-27 12:36:53 -07:00
Josh Roy 4c48ccb422 Block removing hats with curse of binding (#3299) 2020-05-27 12:36:22 -07:00
Josh Roy 53e7c83254 Add tempbanip command (#3291) 2020-05-27 12:35:20 -07:00
Josh Roy fdef1062f0 Add config option to block /pay from ignored users (#3273) 2020-05-27 12:34:11 -07:00
kakd b9f8fc2e11 Option to send coordinate after death (#3207) 2020-05-27 01:58:54 -07:00
Xeyame db410fb3e7 Add missing methods to Commandexp (#3335) 2020-05-26 17:26:58 -07:00
Jason 500dadc760 Update config.yml custom join/quit message comments (#3334) 2020-05-26 16:22:38 -07:00
md678685 7d61953753 Fix spawner provider detection only working on 1.13+
This caused a seemingly-unrelated error where the 1.7/1.8 provider was being used on all versions up until 1.12. Upon further investigation, this line caused a NoSuchFieldError, and since this isn't an Exception it was caught by the outer `catch (Throwable t)` which was intended to catch throwables from the providers rather than the setup of tryProvider.
2020-05-20 19:49:45 +01:00
pop4959 5b9b76d5e7 Fix clearing specific items in clearinventory (#3263)
Fixes #2986
Closes #3050
Closes #3191

Refactors the clearinventory command code in such a way that fixes the problem of not being able to clear all of a specific item on newer server versions. Also re-adds data value support for older server versions that support it, which seemed to have been inadvertently removed in 79bc340.

Checked against 1.8.8, 1.12.2, 1.13.2, 1.15.2.
2020-05-17 21:10:12 +01:00
Josh Roy b9804d8980 Ignore CloudNet v3 SLPE (#3288)
Yet another CloudNet fix.

Fixes #3282
2020-05-17 15:35:31 +01:00
Josh Roy b960ee365a Fix improper target block handing in /tree & /bigtree (#3271) 2020-05-13 15:55:17 -07:00
Josh Roy 302f0acbaa Add permission for storing user's last location on teleportation (#3272) 2020-05-13 15:53:36 -07:00
Glare 8f5b97b9d2 Merge pull request #3277 from pop4959/remove-1.8-spawner-providers-2 2020-05-13 14:29:54 -05:00
pop4959 6371cf7517 Remove 1.8 nms spawner providers from pom 2020-05-13 12:17:37 -07:00
pop4959 e53520aef6 Remove 1.8 NMS spawner providers (#3276)
This PR removes the 1.8 R1 and R2 spawner providers. I was looking into refactoring these to use reflection instead of importing NMS code (in order to avoid requiring buildtools to compile), but after some research it looks like these are actually not even used anymore, in favor of the LegacySpawnerProvider (which Essentials appears to use for 1.8.0-1.12.2). Thus, keeping these is fairly pointless and causes more harm than good. There is no reason to continue including them, nor maintaining them. Essentials currently doesn't even officially support these versions anyway.
2020-05-13 10:56:50 +01:00
triagonal d59fd71ba5 implement PrivateMessagePreSendEvent (#3260)
This PR introduces an event to be called just before a private message is sent to a user. This event provides the message sender, the message recipient, and the contents of the message.

This event provides the possibility for greater customization of private messages, such as playing a sound or displaying a boss bar when a private message is received, or filtering private message content.

Closes #726, closes #2097.
2020-05-13 08:03:28 +01:00
Crash Cringle 4b967a749b Added a command to /eco that allows users to take percentages from pl… (#3080)
* Removed unnecessary formatting

* Fixed spacing around isPercent, removed unnecessary parenthesis, optimized conversion
2020-05-12 21:38:36 -07:00
pop4959 8f88a8dcb3 Allow 1 char name (#3264) 2020-05-12 21:27:33 -07:00
pop4959 a58ba406eb Add offhand slot to invsee equip (#3265) 2020-05-12 21:26:24 -07:00
pop4959 a93ca9b7bc Use world's sea level for depth command (#3268) 2020-05-12 21:05:57 -07:00
Josh Roy 02e6b5f1b3 Fix isStopping MethodHandle invocation on Spigot (#3267)
Fixes #3266.
2020-05-12 20:14:01 +01:00
Josh Roy 63dd5f3f64 Fix age old bug with active status in Backup manager (#3262)
I cannot even reproduce this error but I guess one other person can. Fuck this stupid feature
2020-05-11 18:09:29 -07:00
Alexander Meech a3a50e9cd5 Implement permission node to extinguish other players (#2826)
Implements a specific permission node to restrict access to extinguishing other players, so Extinguish command will match other commands with similar functionality (i.e. /feed)

Fixes #2796
2020-05-11 17:40:24 +01:00
pop4959 8e3c1aaa96 Implement rest command (#3205)
Implements a rest command based on @mart-r's suggestion in #2299. Resetting the time since rest statistic prevents phantoms from coming after you for an hour (real time). The statistic is also set to zero when using a bed. This command cannot be used pre-1.13 because the statistic does not exist (nor would it matter since there are no phantoms).

Closes #2299
2020-05-11 17:11:06 +01:00
Josh Roy 8b71437264 Improve backup functionality (#3258)
Waits for an ongoing backup task to complete in onDisable (and yells at users for `/reload`ing), and adds a `backup.always-run` option to enable always running backups even when no users have logged in since the last backup.

Fixes #3257 and closes #2646.
2020-05-11 16:55:31 +01:00
Josh Roy 61d0ed3f01 Fix invalid charge error when using suffix currency on signs (#3253)
i swear i test my code

Fixes #3252.
2020-05-11 15:20:00 +01:00
Josh Roy fc2b7b63a2 Save player logout times on shutdown (#3157)
Properly save userdata and mark the player's last logout time when the server is shutting down.

Fixes #2764.
2020-05-11 14:53:05 +01:00
kmecpp 96590a3389 Add KitClaimEvent (#3197)
Adds an event fired when a kit is expanded for a user. Fixes #3196.
2020-05-09 21:19:51 +01:00
zml a043de3e44 Add a more helpful error message for xmpp module (#3247)
Rather than spitting out a stacktrace, this gives users some instructions on what to do.

It's a bit spammy so the error messages get noticed, that could be toned down a bit if we just want to be silent on login. Unfortunately a lot of plugins haven't discovered the debug and trace log levels, so a lot of startup warnings (like this one) will get lost in the spam if there aren't other issues.
2020-05-09 13:21:02 +01:00
Josh Roy 81d3900ef6 Cleanup after UUID Ignore List PR (#3227)
Most of these are edge case fixes, but still fixes nonetheless!
2020-05-04 14:32:49 +01:00
Josh Roy fd136384a1 Add null check in ignore command (#3226)
This would only become a problem if a server owner decided to delete a bunch of their userdata. Nonetheless, it doesn't hurt to have the check.

I promise this is the last pull request regarding this 😄
2020-05-04 14:17:08 +01:00
Josh Roy dd5fe117b5 Fix null check in Username->UUID ignore list converter (#3225)
Didn't test with a username that didn't exist and didn't notice this. Null check(s) are now in their proper place.

Fixes #3223.
2020-05-04 13:48:50 +01:00
Josh Roy e9d29f789f Add default enchantment level for enchant sign (#3070)
Defaults the enchantment level on signs to `1` if one is not provided on the sign.

Closes #1497.
2020-05-04 11:10:16 +01:00
Josh Roy 1bc1f646fd Convert ignore list storage to UUID-based (#3209)
As the title describes, this PR converts the ignore list storage from username-based to UUID-based.

Fixes #239.
2020-05-04 11:06:09 +01:00
Josh Roy 8ad55cb634 Add UUID and User based economy methods (#3085)
Adds methods to the Economy API to use UUIDs and User objects. Additionally, deprecates all the username (String) based methods. Backwards compatibility has been maintained and I added User validation to UUID-based methods and null checks in User-based methods
2020-05-04 11:00:25 +01:00
mart-r b19dec120a Don't show hidden players in /balance unless exact name entered (#3218)
Fixes #2305

Not looking for hidden players within the command, yet looking for offline players.
Only matching a hidden player if the name match was exact (i.e not matching nicknames).
2020-05-04 10:36:01 +01:00
pop4959 283c088b21 Add protect option for disabling ender crystal explosions (#3210)
Closes #587.
2020-04-30 20:39:00 +01:00
pop4959 d5ffed09b4 Fix home tab completions (#3206)
Fixes #1337 😎 

This PR fixes tab completions for all of the home commands in Essentials. Prior to this PR, the behavior is approximately as follows:

- `/sethome` has no implementation for completions, and so it provides player names, which isn't very useful, and in my opinion can cause more harm than good by confusing users.
- `/home` and `/delhome` fail to provide valid completions when a user has the `essentials.home.others` permission. The argument syntax is `[player:]<name>` but it tries to complete it as `<player> <name>`. Not only does it not show you suggestions for your own homes, but it proceeds to show you invalid suggestions!

This PR provides completions that accurately reflect the syntax and real behavior of the command, including suggesting homes for player names that are partially matched. It will provide suggestions for all of your own homes, as well as providing suggestions based on how far along you are in the command (players if you haven't specified `:` yet, otherwise a specific player's homes).
2020-04-30 20:26:27 +01:00
Josh Roy b7eec09307 Add config option to make currency symbol as a suffix (#3066)
Adds `currency-symbol-suffix` config option to move the currency symbol as a suffix rather than a prefix.

Closes #2577.
2020-04-25 13:12:55 +01:00
Josh Royandmd678685 23f0f98af3 Cleanup code (#3067)
Co-Authored-By: md678685 <1917406+md678685@users.noreply.github.com>

Basically cleans up a bunch of warnings that are easily suppressed.
2020-04-25 13:08:57 +01:00
Josh Royandmd678685 6bbdbc89a6 Improve MuteStatusChangeEvent (#3068)
Co-Authored-By: md678685 <1917406+md678685@users.noreply.github.com>

Adds getTimestamp and getReason methods to MuteStatusChangeEvent with the apropriate JavaDocs explaining them.

Closes #2459.
2020-04-23 16:28:08 +01:00
zml 12c8623666 Add permissions defaults to plugin.yml for op-affecting commands (#3029)
This aims to reduce the unintended consequences of granting all Essentials permissions or giving a player op, by defaulting permissions some more permissions to false, including `essentials.hat.prevent-type.<type>`. There's also a new essentials.exempt metapermission to have one parent that controls exemption from kick/ban/mute/etc. This will change behaviour for ops to some extent.
2020-04-23 16:15:10 +01:00
mink 2bd6ebd2b1 Config option to toggle disabling flight / speed on world change (#2546)
Closes #2141.

This PR adds the option to toggle whether or not EssentialsX should handle disabling player flight / speed when they switch to a new world, in case server administrators are handling that via a third party plugin.
2020-04-23 16:13:19 +01:00
pop4959 40fb496052 OfflinePlayer getAttackCooldown (#3190)
Fix compile
2020-04-23 12:15:32 +01:00
triagonal b72d822f94 Re-add missing GeoIP license message key (#3186)
This PR re-adds the geoIpLicenseMissing key which was inadvertently removed during the recent mass locale update (#3165).
2020-04-21 19:44:54 +01:00
FourDown 6d92ac9af6 Fix book formatting (#3173) 2020-04-16 17:01:51 -07:00
Josh Roy 47f27a8016 Fix method signature breakage in versions lower than 1.14 (#3175) 2020-04-16 16:55:06 -07:00
Noahandmd678685 849d095e9a Add /ecreative alias to /gamemode (#3101)
* Proper command alias

* Update Essentials/src/plugin.yml

Co-authored-by: md678685 <1917406+md678685@users.noreply.github.com>
2020-04-14 17:30:25 +01:00
Trent Hensler 923f240aa1 New Crowdin translations (#3165)
* New translations messages.properties (Russian)

* New translations messages.properties (Portuguese)

* New translations messages.properties (Hebrew)

* New translations messages.properties (Japanese)

* New translations messages.properties (Latvian)

* New translations messages.properties (Lithuanian)

* New translations messages.properties (Norwegian)

* New translations messages.properties (Polish)

* New translations messages.properties (Portuguese, Brazilian)

* New translations messages.properties (German)

* New translations messages.properties (Romanian)

* New translations messages.properties (Serbian (Latin))

* New translations messages.properties (Slovak)

* New translations messages.properties (Spanish)

* New translations messages.properties (Swedish)

* New translations messages.properties (Thai)

* New translations messages.properties (Greek)

* New translations messages.properties (French)

* New translations messages.properties (Italian)

* New translations messages.properties (Chinese Simplified)

* New translations messages.properties (Turkish)

* New translations messages.properties (Hungarian)

* New translations messages.properties (Vietnamese)

* New translations messages.properties (Korean)

* New translations messages.properties (Basque)

* New translations messages.properties (Bulgarian)

* New translations messages.properties (Chinese Traditional)

* New translations messages.properties (Finnish)

* New translations messages.properties (Chinese Traditional, Hong Kong)

* New translations messages.properties (Croatian)

* New translations messages.properties (Czech)

* New translations messages.properties (Danish)

* New translations messages.properties (Dutch)

* New translations messages.properties (English, United Kingdom)

* New translations messages.properties (English, United States)

* New translations messages.properties (Estonian)

* New translations messages.properties (Ukrainian)
2020-04-14 17:15:19 +01:00
triagonal 8655ff2de3 Add displayname placeholders to self-AFK messages (#3164)
As a result of #2780 (oops) the self-AFK messages can no longer exactly match the regular AFK messages as the placeholder for the player's displayname was left out for the self messages.

This PR adds those placeholders so that those who would prefer that these messages are the same can simply copy their messages from the normal `userIs*Away*` keys to the new `userIs*AwaySelf*` keys.
2020-04-14 11:56:17 +01:00
triagonal 6f61010cf9 Allow toggling public broadcast of AFK messages (#2780)
(description from #2608)

So... I've implemented a system for toggling whether or not AFK messages are broadcasted to the entire server and also changed a few things along the way:

1. I added a config toggle broadcast-afk-message that will change whether AFK messages are broadcast globally or not.
2. In both cases the AFK target now recieves a "self-oriented" message instead of the global default. Basically just says "You are now/no longer AFK". This would be a change from the default behaviour.
3. I created a way to exclude certain IUsers from broadcastMessage messages using an IUser... varargs parameter. I wasn't too sure how to implement the exclusion, but this seemed like a fairly good option.

I'm not too sure if what I've come up with is an optimal solution, but it's been tested and confirmed to work as intended.

closes #2116, closes #959

---

* implement toggle for broadcasting afk message

* add "self-private" AFK messages, implement exclusion system for broadcastMessage

* remove rogue import, clarify config comment

* move excluded collection creation out of loop, use set instead

* use set instead of varargs

* ok but actually use the set this time

* address requested changes

* update missed message section

* move from Collection to Predicate for broadcast exclusion

* update Predicate variable name

* use identity comparison (cleanup)

* clean up unnecessary imports, remove extra spacing
2020-04-13 14:33:37 +01:00
md678685 5082badca4 Improve config.yml comments and structure (#3151)
This PR fixes some issues with the config.yml:
* Adds links to the EssentialsX docs where appropriate
* Moves a couple of settings into their correct locations
* Changes headers to remove the weird implications of modularity (EssentialsHelp isn't a module, it's *one* command)
* Updates support link at top
* Minor grammar nitpicks
2020-04-13 09:06:31 +01:00
Josh Roy 307bd2a35f Prevent tridents from being picked up (#3149) 2020-04-10 12:44:45 -07:00
md678685 a11552f497 Document and clean up API events 2020-04-10 12:00:01 +01:00
Jason 8556caaeb4 Update kits.yml example to be more consistent (#3148)
Follows the note using {USERNAME} instead of {player} to prevent confusion
2020-04-09 17:11:14 +01:00
md678685 7c09012b3d Update /fireball usage and description 2020-04-09 16:40:49 +01:00
Jason eb596caa00 Change {PLAYER} to {USERNAME} in kits.yml comment (#3057)
Avoids confusion between `{PLAYER}` (KeywordReplacer placeholder) and `{player}` (kit-specific placeholder).
2020-04-09 16:00:35 +01:00
HexedHero ab4501aa4c Add check for NPCs to /back listeners (#2833)
Add a check for NPCs to the PlayerTeleportEvent and PlayerDeathEvent to avoid unnecessarily tracking NPCs' `/back` locations.

Closes #2832.
2020-04-09 15:37:51 +01:00
md678685 4b766d373d Fix kit command example
Shhhhh, #2980 isn't real, it can't hurt you
2020-04-09 15:10:43 +01:00
ThatGamerBlue e3574edc5d scripts: fix buildtools script under windows git bash (#3145)
wget is nonfunctional in git bash for windows, so we should use curl instead
(no matter what you pass to wget it fails with the same error)

https://i.imgur.com/YDw68vM.png
2020-04-09 15:05:21 +01:00
Dieter Nuytemans dcb69ddc73 Set sleepingingored default to false (#3141) 2020-04-06 22:18:33 -07:00
pop4959 1d6ad297a4 Add new interface methods to FakeServer (#3140) 2020-04-05 23:13:13 -07:00
Josh Roy 85a5e517c9 Fix passenger check not working on versions below 1.11.2 (#3132) 2020-04-05 02:48:21 +11:00
Radoje17 b08d380643 Added real name boolean option for the /list command (#3117) 2020-04-02 00:06:32 -07:00
Glare ad98fc4121 Implemented uptime placeholder (#3120) 2020-04-01 11:37:55 -07:00
Josh Roy 810689c037 Add passenger dismounting for teleports (#3069)
Add passenger dismounting for teleports
2020-03-31 18:04:44 -07:00
Joe Hirschfeld c007700c59 Merge pull request #3106 from Markyroson/2.x
Make MockBukkit compatible #3105
2020-03-31 00:06:39 -07:00
Joe Hirschfeld 8cc3f6626b Merge pull request #3113 from darbyjack/200-IQ-Protect-Improvements
Fixed my PR pt2
2020-03-30 23:42:54 -07:00
darbyjack a3b8a4adc9 Version to 1.14 2020-03-31 01:40:37 -05:00
Joe Hirschfeld 8f817c089b Merge pull request #3111 from darbyjack/200-IQ-Protect-Improvements
200 IQ Essentials Protect Improvements
2020-03-30 23:32:58 -07:00
Joe Hirschfeld ed4e7794c3 Merge pull request #3063 from schlatt-co/feature/3034
Implement better AfkStatusChangeEvent
2020-03-30 23:15:34 -07:00
darbyjack 6f732d410e Fixed my stupid PR 2020-03-31 01:13:14 -05:00
Joe Hirschfeld 6c8da20883 Merge pull request #3052 from pop4959/fix-zh-CN-geoip-issue
Fix zh-CN GeoIP locale issue
2020-03-30 23:01:50 -07:00
Joe Hirschfeld c7d9ce7f7f Merge pull request #3051 from pop4959/xp-tab-complete-fix
Fix tab completion for Exp command
2020-03-30 22:58:21 -07:00
Joe Hirschfeld 4e7f639076 Merge pull request #3049 from pop4959/near-exempt
Near exclude permission
2020-03-30 22:47:36 -07:00
Joe Hirschfeld b2c3b3a99f Merge pull request #2914 from montlikadani/patch-5
Fix NPE when the user is null in the hidden players
2020-03-30 21:27:39 -07:00
Joe Hirschfeld 77338d66dc Make drop-items-if-full work on Essentials kits (#2820) 2020-03-30 21:11:56 -07:00
Xeyame e2130df596 Add different translation keys for the "me" message (#2805)
* Add different translation keys for the "me" message

* Add proper German "me" translation
2020-03-30 21:10:46 -07:00
montlikadani 2bbe6d6069 Implement message for #2640 (#2721)
* Update Essentials.java

* Update messages.properties

* Update messages.properties
2020-03-30 21:01:15 -07:00
montlikadani c8b8e505f3 Add teleport warmup event to API (#2590)
* Update Teleport.java

* Create UserTeleportEvent.java

* Update Teleport.java

* Add location to event
2020-03-30 20:38:13 -07:00
latiku 89743f9900 implement command teleporting to a player's last known logout location (#2505)
* implement /offlinetp command, teleports to a player's last known logout location

* send a message to /tp user when they try teleporting to an offline player

* getHidden is now false, you are no longer able to teleport to offline players using offline tp

* change /offlinetp to /tpoffline to match essentialsx conventions
2020-03-30 20:35:23 -07:00
latiku dbc0562fb0 permission-based jailed player interactions (#2503) 2020-03-30 20:32:12 -07:00
pop4959 76f4dff14c Fix bed message on some older versions of MC (#3048)
Fixes #3045. Some older versions of MC use "BED_BLOCK" to represent beds.
2020-03-30 08:32:44 +01:00
pop4959 baa2a2f24f Use isAuthorized for permission check 2020-03-29 13:44:33 -07:00
Pokechu22 2ca02911b3 Mention 1.15.2 in the README (#3107) 2020-03-29 12:11:44 -07:00
Markyroson cf48237049 Make MockBukkit compatible #3105 2020-03-29 10:34:16 -07:00
pop4959 adfe2c1975 Update FakeWorld (#3095) 2020-03-26 19:12:07 +11:00
triagonal a782043798 Revert "Add {PLAYER} placeholder with uppercase in kits (#2929)" (#3072)
This reverts commit 90c4a2f53c.
2020-03-14 22:49:48 -07:00
montlikadani 90c4a2f53c Add {PLAYER} placeholder with uppercase in kits (#2929) 2020-03-14 15:17:58 -07:00
pop4959 338b371e4c Implement max mute time feature (#2807) 2020-03-14 15:12:43 -07:00
Glare 347179373d Fixed double local logging (#2755) 2020-03-13 02:33:18 -07:00
montlikadani 3bb45b80b1 Add tab-completer for /spawnmob command (#2661) 2020-03-13 02:30:50 -07:00
Glare e3ec0f3b9b Added in option to remove effects on heal (#2754) 2020-03-13 02:24:29 -07:00
Joel Otero f20572b30c Add speed info to whois (#2952) 2020-03-13 01:10:44 -07:00
Josh Roy 2124cce603 Fix User::payUser(User, BigDecimal, Cause) not properly utilizing Cause (#3064) 2020-03-13 00:39:21 -07:00
JRoy ebf60c1e70 Implement better AfkStatusChangeEvent 2020-03-12 22:08:11 -04:00
pop4959 c31b6c3683 Update FakeWorld + FakeServer (#3061) 2020-03-11 17:20:46 +11:00
pop4959 ffc83343fe Fix zh-CN GeoIP locale issue 2020-03-05 01:08:55 -08:00
pop4959 2554acd304 Fix tab completion for Exp command 2020-03-05 00:31:40 -08:00
pop4959 98239114ad Near exclude permission 2020-03-04 23:23:23 -08:00
md678685 c10b39c1c7 Fix bee spawn egg aliases 2020-03-01 11:16:42 +00:00
montlikadaniandmd678685 20e11465e4 Properly fix error with fireball command (#3040)
Closes #3016.

* Update Commandfireball.java

* Update Commandfireball.java

Co-authored-by: md678685 <1917406+md678685@users.noreply.github.com>
2020-03-01 11:12:55 +00:00
pop4959 46e1b95b33 Add missing OfflinePlayer methods (#3033) 2020-02-23 18:11:57 -08:00
md678685 279d6f16e1 Bump version to 2.17.2
\o/
2020-02-22 10:05:14 +00:00
md678685 a747eccaa3 Fix /fireball on 1.8.8 (#3027)
Dragon fireballs were added in 1.9 and so this previously caused an
error. This PR fixes that (and adds tridents as throwables). Fixes #3016.
2020-02-22 10:03:43 +00:00
md678685 0bafbc3184 Reduce permission check calls in PlayerCommandSendEvent (#3026)
This reduces permissions checks by only checking each command once, not checking each command for each alias.

The impact of this is a near-tenfold reduction in permission checks during this listener, which should slightly improve performance when using LuckPerms (and provide significant improvements on older inefficient permissions plugins).
2020-02-22 10:02:53 +00:00
Edward Wang 8069370b8c Clarify easter egg config description (#3028) 2020-02-21 13:12:09 -08:00
Jason 46f4b92ff7 Update config.yml group-formats (#3025)
Since most (if not all) modern permission plugins only use lowercase group names, the examples should also be lowercase. A note has also been added explaining that group names are case-sensitive.
2020-02-21 12:24:49 +00:00
md678685 d92f5ce71c Add 1.14/1.15 item aliases and fallbacks
Short term replacement for #2897 until ItemDbGenerator is complete:

* Closes #2934 by adding 1.15 items
* Closes #2790 by adding minecraft:sign fallbacks and a "sign" alias
* Closes #2732 by adding aliases and fallbacks for cactus green/green dye, dandelion yellow/yellow dye and rose red/red dye.
2020-02-21 11:11:35 +00:00
Josh Roy 2314bf8bd4 Fix CustomItemResolver causing a StackOverflowError (#3022)
CustomItemResolver was fetching the custom item from the item database instead of the resolved custom item which caused a StackOverflowError.

Fixes #3018.
2020-02-18 20:20:53 +00:00
Jasonandmd678685 7808b21496 Explain how to add commands to kits (#2980)
* Explain how to add commands to kits

* Update Essentials/src/kits.yml

Co-Authored-By: md678685 <1917406+md678685@users.noreply.github.com>

Co-authored-by: md678685 <1917406+md678685@users.noreply.github.com>
2020-02-16 15:39:28 +00:00
triagonal 18ef412211 Add beezooka command (#3003)
This PR introduces the `/beezooka` command as suggested in #2975. The command acts similarly to `/kittycannon` with the exception of the Bee being tamed, instead flying around for a small amount of time before exploding.

Sample usage:
![beezooka](https://user-images.githubusercontent.com/10545540/74099459-11804880-4b78-11ea-9c3d-499b06d912fb.gif)

As Bees do not exist below version 1.15, an error will display when attempting to run the command on such a version:
![image](https://user-images.githubusercontent.com/10545540/74099477-4d1b1280-4b78-11ea-91c2-fa675994a85f.png)

Closes #2975.
2020-02-10 11:46:41 +00:00
md678685 0678328253 Update funding to include Ko-fi link 2020-02-10 11:34:59 +00:00
md678685 5503e1e14c Revert "Split plugin compatibility report into own class"
Revert 6fa5b80c0a, which broke `/ess version`, until this can be fixed.
2020-02-10 09:05:32 +00:00
triagonal 9e89cfa4ed Implement missing FakeWorld methods (#3002) 2020-02-08 21:10:49 -08:00
imDaniX 13f454a022 Properly escape pipe character on item lore (#2994)
Using negative lookbehind instead of negated characters set.

Fixes #2962, fixes #2984
2020-02-07 10:10:54 +00:00
pop4959 129650dade Update FakeServer (#2997) 2020-02-07 12:08:29 +11:00
md678685 6fa5b80c0a Split plugin compatibility report into own class 2020-02-01 21:46:53 +00:00
pop4959 04dfcd0965 Bump supported version to 1.15.2 2020-01-22 09:14:41 +00:00
pop4959 2e818ac709 Properly register entity transform event depending on version (#2942)
Fixes the problem mentioned in #2931 which was introduced in #2836. This is caused as a result of EntityTransformEvent being a relatively new event introduced in Spigot [856adc3e6af](https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/commits/856adc3e6afc3e9c0495ac27e38b96b144e54b1e), which was after the update to 1.13.2 in Spigot [f311182396b](https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/commits/f311182396bd74b106efebc926ea4d0b92cfba80).

Closes #2931.
2020-01-14 07:54:51 +00:00
pop4959 32ef61197f Fix bed spawn message on 1.15+ (#2943)
Closes #2893

**Tests**
![2020-01-13_14 08 12](https://user-images.githubusercontent.com/17698576/72297425-be66b480-3610-11ea-8421-1ac6881259b8.png)
![2020-01-13_14 10 02](https://user-images.githubusercontent.com/17698576/72297431-c32b6880-3610-11ea-89fc-bdda2d0cec89.png)
2020-01-14 07:50:48 +00:00
md678685 fa06cd8253 Fix Java 9 breakage causing issues on Java 8 2020-01-11 17:03:33 +00:00
pop4959 5020983af5 Update GeoIP (#2926)
This implements the fix suggested by @Bobcat00 in #2919

Users of GeoIP will now be required to register a MaxMind account and create a license to download the database required by the plugin. This license is entered into the new license-key field in the configuration.

---

* Update GeoIP

* Simplify branch

* Update old config detection

* Update geoIpLicenseMissing to point to the EssX wiki
2020-01-11 07:10:40 +00:00
pop4959 f4496b6977 Update FakeWorld again (#2925)
Spigot added some new methods.
2020-01-04 12:32:40 +00:00
montlikadani a1719d651e Update Commandlightning.java 2019-12-31 17:51:21 +01:00
montlikadani e7be2b68a3 Update PlayerList.java 2019-12-31 17:49:46 +01:00
pop4959 552dcb56a1 Improvements for delkit (#2908)
3 improvements for delkit within this PR:

1) Cleaned up unused imports
2) Show actual kit name when deleting instead of memory address (this is the reason originally for making this)
3) Implement tab completion

I've tested to make sure the changes are properly functioning. See below:

Before:
![2019-12-29_01 12 09](https://user-images.githubusercontent.com/17698576/71555204-4bd5c200-29de-11ea-9fe3-eb88db08ef48.png)

After:
![2019-12-29_01 48 50](https://user-images.githubusercontent.com/17698576/71555207-56905700-29de-11ea-9277-271bb0656d64.png)
![2019-12-29_01 48 25](https://user-images.githubusercontent.com/17698576/71555208-58f2b100-29de-11ea-8257-742fa7bb3150.png)
2019-12-31 16:10:38 +00:00
montlikadani e158a65603 Improve scheduler methods to use Java 1.8 lambdas (#2700)
* Update EssentialsPlayerListener.java

* Update Backup.java
2019-12-31 13:58:09 +00:00
CmdrKittens b694e8aaa2 Don't attempt to modify a Map value view (#2910)
md dun goofed
2019-12-29 19:41:17 +00:00
md678685 a2e09121ba Slightly nicer AntiBuild messages 2019-12-26 16:17:10 +00:00
md678685 4ce7dfa8f0 Minor refactor of permissions handlers
* Move `essentials.build` perm check from AntiBuild into default SuperPerms handler
* Don't emulate wildcards for LuckPerms or PEX
* Add `build: true` meta support for LuckPerms (+ other plugins as needed)
2019-12-26 15:08:07 +00:00
md678685 1c4ce7b4bd Don't assume primary group is always present
Fixes a potential issue with PEX 2.0 (and 1.x) where users may not have a primary group.
Closes #2901.
2019-12-26 13:08:38 +00:00
md678685 8a04c1e232 Fix custom_items.yml generation 2019-12-24 23:02:07 +00:00
md678685 6e5d378324 Add methods to set/remove custom aliases 2019-12-24 09:36:15 +00:00
md678685 8e1f3617fd Add custom_items.yml file 2019-12-24 09:36:15 +00:00
Mark Vadeikaandmd678685 2549ed830f Enable control of entity transformations in EssentialsProtect (#2836)
This allows users to prevent any of the following transformations:

- Creeper charging
- Villager infected by zombie villagers
- Villager being cured
- Villagers turning into witches
- Pigs turning into zombie pigmen
- Zombies turning into Drowned (and husks turning into Zombies)
- Mooshrooms switching colors

Configurations are in a new subsection, `protect.prevent.transformation`. All options are disabled by default.

---

* Allow for control of transformations

* Undid removal of villager checking

* Undid removal of villager checking

* Documentation for transformation configs

Co-Authored-By: md678685 <1917406+md678685@users.noreply.github.com>

* Removed duplicate configuration lines

* Updated info about husks drowning

* Changed config names

Co-authored-by: md678685 <1917406+md678685@users.noreply.github.com>
2019-12-23 13:55:05 +00:00
Josh Roy 0ebd64d314 Add a cause enum to UserBalanceUpdateEvent (#2824)
Basically, I just needed this for one of my plugins; otherwise, this could be useful for people using this event who want to see where the user's balance is being updated from.

---

* Add UserBalanceUpdateEvent.Cause
* Add special cause enum
* Add API Cause
2019-12-23 13:16:34 +00:00
Mark Vadeika 843ecb4a42 Escape pipe character on item lore (#2831)
I just adjusted the regex used to split the item lore into multiple lines in order to allow escaping of the pipe character using \|.

Fixes #2830.
2019-12-23 13:15:26 +00:00
md678685 a1a0d34940 Attempt to parse input as UUID in loop commands (#2606)
Related: #2424
2019-12-23 13:06:15 +00:00
md678685 15bb978dab Remove unused VersionUtil constants 2019-12-22 23:55:25 +00:00
md678685 6a7cf39548 Fix wrong filename in ManagedFile error message 2019-12-22 23:53:36 +00:00
pop4959 8ccb70d07d Add phantoms to protect.prevent.spawn (#2806)
Closes #2733.
2019-12-22 22:13:26 +00:00
dashaw92 45461a93b0 Correct unbanip's permission for broadcasts 2019-12-22 22:11:44 +00:00
Joe Hirschfeld b3a54a78bc Save materials in unlimited by name
There was a mistake where materials in unlimited would instead be saved
as a bukkit Material instead of its name. Instead, save it by the name.
2019-12-22 22:10:30 +00:00
AgentTroll a4182b5ff9 Correct check for command cooldowns list in userdata 2019-12-20 12:44:10 +00:00
pop4959 215dcde4b9 Update to 1.15.1 2019-12-19 12:38:18 +00:00
md678685 67b2a9a4f4 Build with GitHub Actions (#2800)
* Add GitHub Actions workflow

* Update workflow

* Run BuildTools in workflow

* Update build.yml

* Add distributionManagement to pom.xml

* Add GitHub registry Maven credentials

* Remove Travis CI config

* mkdir -p

* Remove GitHub package registry push

Didn't work anyway

* Remove distributionManagement

* Cache Maven repo

* Fix step order

* Use JitPack for VaultAPI
2019-12-16 14:23:00 +00:00
Johnny Cao 3b51b23ac2 Block gamemode changes for jailed players (#2875)
Blocks players from experiencing any gamemode changes while they are jailed.

Fixes #1996.
2019-12-12 07:37:13 +00:00
Johnny Cao e0f19f8121 Allow players to set single word AFK message - fixes #2712 (#2876)
Allows players with "essentials.afk.others" to toggle afk themselves with a single word message
2019-12-11 19:20:56 +00:00
Madis Otenurm e720fb528a Crowdin in readme (#2877)
* Crowdin for readme

* Update README.md
2019-12-11 19:04:12 +00:00
md678685 518a5454c6 Add missing FakeWorld methods 2019-12-11 08:48:45 +00:00
Josh Roy 2d9c846084 Update to 1.15 (#2873)
* Compile against 1.15

* Remove achievement related methods for OfflinePlayer

* Add 1.15 to VersionUtil

* Revert "Remove achievement related methods for OfflinePlayer"

This reverts commit d0ab84e0

* Add 1.15 Mobs

* Remove Achievement related methods from OfflinePlayer

This needs more work as this currently breaks > 1.15 support

* Actually this isn't a problem
2019-12-11 07:47:56 +00:00
md678685 59e30f05fc Merge pull request #2871 from AgentTroll/patch-mockito
Update Mockito to allow tests to pass in newer versions of Java
2019-12-10 07:48:07 +00:00
AgentTroll 0f1085a02d Update Mockito to allow tests to pass in newer versions of Java 2019-12-09 20:55:55 -05:00
Glare 882699919e Reimplement spawn-if-no-home config option (#2757)
This reimplements the `spawn-if-no-home` config option from the original Essentials plugin. If set to true, running `/home` without having set a home will send the player to spawn (previous behaviour). If set to false, running `/home` will instead show an error message and not teleport the player anywhere.

Closes #1452.
2019-10-20 09:12:53 +01:00
Ryan f6a70a542e Implements missing createExplosion methods in FakeWorld (#2818) 2019-10-13 14:35:38 -07:00
rye761 785b1fe937 Make drop-items-if-full work on Essentials kits 2019-10-13 17:00:11 -04:00
triagonal bae909ba10 implement missing OfflinePlayer methods 2019-09-24 15:51:43 +01:00
triagonal dbb9757a9f add {USERNAME} placeholder to chat format 2019-09-23 06:20:28 +01:00
md678685 deaeb46ce9 Implement missing FakeWorld methods 2019-08-28 21:14:06 +01:00
md678685 219012bc35 Set item meta in setSkullOwner before returning
*Should* address #2765.
2019-08-28 15:26:23 +01:00
md678685 5f9eb22d23 Fix player head meta on versions below 1.13 2019-08-24 10:05:26 +01:00
md678685 2c33fb6834 Correctly return null for invalid IDs when doing legacy conversion 2019-08-13 15:12:04 +01:00
md678685 8bcef6022b Add max-projectile-speed option
Projectils can load chunks pretty intensively if too fast.
2019-08-05 19:56:25 +01:00
md678685 93d36779f0 Implement regex-based nickname blacklist
Adds `nick-blacklist` list to config which takes phrases or regexes. Users with essentials.nick.blacklist.bypass can bypass the blacklist.
2019-08-05 19:01:48 +01:00
Glare 2502f5e6f2 Check if user has a permission to block putting X item on their head. (#2574)
Closes #2550. 

* Check if user has a permission to block putting X item on their head.
* Forced the material name to be lower case.
* Fixed a typo in the message.
* Updated permission node and added check to the EssentialsPlayerListener.
2019-08-05 16:19:03 +01:00
triagonal 95f2852cf3 Implement toggle for command block logging (#2599)
Just a simple config toggle for whether or not command block commands should be logged.

closes #1153, closes #162

---

* Add toggle for command block logs
* update setting name
2019-08-05 16:17:22 +01:00
md678685 ff9f712d65 Add per-projectile permissions and speed argument to /fireball 2019-08-05 16:12:32 +01:00
Mickey42302 60c4e75a1c Add Dragon Fireballs to "/fireball". 2019-08-05 16:12:32 +01:00
md678685 ccf7c48bf1 Add aliases to /delkit 2019-08-05 15:35:32 +01:00
md678685 65d81eb31e Clean up /essentials 2019-08-05 15:25:55 +01:00
md678685 b97eb12dfc Implement /delkit command
Closes #2709, closes #2719.
2019-08-05 14:06:37 +01:00
md678685 d2724d77df URGENT: critical bug fix 2019-08-02 16:05:41 +01:00
md678685 119b21ac67 Check plugin equals rather than name equals in autocomplete listener 2019-08-01 14:57:48 +01:00
md678685 1ff73b3837 Bump version to 2.17.1 2019-07-30 18:10:27 +01:00
Glare d98f8b3467 Fixed dupe on new builds. (#2696)
Fixes #2695.
2019-07-30 12:56:46 +01:00
md678685 ac8b8861cb Merge remote-tracking branch 'origin/2.x' into 2.x 2019-07-28 16:18:00 +01:00
md678685 22dc5dcebd Fix /r not showing in 1.13+ tab complete
Fixes #2659.
2019-07-28 15:00:49 +01:00
Josh Roy 3c09e72ce4 Bump supported 1.14.x version to 1.14.4 (#2681) 2019-07-20 00:48:13 -07:00
pop4959 fffc3fcac7 Implement missing methods in FakeWorld (#2679) 2019-07-18 11:56:00 -07:00
md678685 bcdbbe9546 Fix wall sign protection on 1.12.2 and below
Fixes #2635.
2019-06-27 15:50:04 +01:00
md678685 19f03cd70e Add missing /tpauto messages
Add messages from #2310 to the `messages.properties` file. Fixes #2634.
2019-06-27 12:00:47 +01:00
md678685 9b7858b830 Update README.md 2019-06-26 22:13:10 +01:00
md678685 8bc55387dd Bump version to 2.17.0 2019-06-26 16:50:11 +01:00
325 changed files with 40984 additions and 26077 deletions

No files matched your search

+1 -1
View File
@@ -1,10 +1,10 @@
# Currently used
patreon: EssentialsX
ko_fi: essentialsx
# Currently not used
#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
#open_collective: # Replace with a single Open Collective username
#ko_fi: # Replace with a single Ko-fi username
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
#liberapay: # Replace with a single Liberapay username
+38
View File
@@ -0,0 +1,38 @@
name: Build EssentialsX
on:
push:
branches:
- 2.x
- mc/*
pull_request:
branches:
- 2.x
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Git repo
uses: actions/checkout@v1
- name: Restore Maven cache
uses: actions/cache@v1
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build with Maven
run: mvn package --file pom.xml
- name: Copy artifacts
run: mkdir -p ./out/ && cp -t ./out/ **/target/Essentials*.jar
- uses: actions/upload-artifact@master
with:
name: Plugin jars
path: out/
+2 -1
View File
@@ -15,4 +15,5 @@
# Build files
target/
jars/
jars/
out/
-13
View File
@@ -1,13 +0,0 @@
language: java
jdk:
- openjdk8
cache:
directories:
- .buildtools
- $HOME/.m2
before_install:
- chmod +x scripts/buildtools.sh
- scripts/buildtools.sh
+35 -35
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>net.ess3</groupId>
<artifactId>EssentialsXParent</artifactId>
<version>2.17-pre1</version>
<version>2.18.0</version>
</parent>
<artifactId>EssentialsX</artifactId>
@@ -49,69 +49,69 @@
<dependencies>
<dependency>
<groupId>net.milkbowl.vault</groupId>
<groupId>com.github.milkbowl</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.7</version>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.luckperms</groupId>
<artifactId>api</artifactId>
<version>5.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.papermc</groupId>
<artifactId>paperlib</artifactId>
<version>1.0.2</version>
<version>1.0.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>NMSProvider</artifactId>
<version>2.17-pre1</version>
<artifactId>BaseProviders</artifactId>
<version>2.18.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>UpdatedMetaProvider</artifactId>
<version>2.17-pre1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>1_8_R1Provider</artifactId>
<version>2.17-pre1</version>
<scope>compile</scope>
<artifactId>NMSReflectionProvider</artifactId>
<version>2.18.0</version>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<artifactId>bukkit</artifactId>
</exclusion>
</exclusions>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>1_8_R2Provider</artifactId>
<version>2.17-pre1</version>
<artifactId>PaperProvider</artifactId>
<version>2.18.0</version>
<exclusions>
<exclusion>
<groupId>com.destroystokyo.paper</groupId>
<artifactId>paper-api</artifactId>
</exclusion>
</exclusions>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>1_8Provider</artifactId>
<version>2.18.0</version>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<artifactId>bukkit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>LegacyProvider</artifactId>
<version>2.17-pre1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>ReflectionProvider</artifactId>
<version>2.17-pre1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>FlattenedProvider</artifactId>
<version>2.17-pre1</version>
<scope>compile</scope>
</dependency>
</dependencies>
+3 -3
View File
@@ -13,6 +13,6 @@ Minecraft colors:
&8 &&8 &9 &&9 &a &&a &b &&b
&c &&c &d &&d &e &&e &f &&f
&0
&&k &kMagic&r &&l &lBold
&&m &mStrike&r &&n &nUline
&&o &oItalic&r &&r &rReset
&&k &kMagic&r &&l &lBold&r
&&m &mStrike&r &&n &nUline&r
&&o &oItalic&r &&r &rReset
@@ -46,15 +46,12 @@ public class AlternativeCommandsHandler {
continue;
}
for (String label : labels) {
List<PluginCommand> plugincommands = altcommands.get(label.toLowerCase(Locale.ENGLISH));
if (plugincommands == null) {
plugincommands = new ArrayList<>();
altcommands.put(label.toLowerCase(Locale.ENGLISH), plugincommands);
}
List<PluginCommand> plugincommands = altcommands.computeIfAbsent(label.toLowerCase(Locale.ENGLISH), k -> new ArrayList<>());
boolean found = false;
for (PluginCommand pc2 : plugincommands) {
if (pc2.getPlugin().equals(plugin)) {
found = true;
break;
}
}
if (!found) {
@@ -68,13 +65,7 @@ public class AlternativeCommandsHandler {
final Iterator<Map.Entry<String, List<PluginCommand>>> iterator = altcommands.entrySet().iterator();
while (iterator.hasNext()) {
final Map.Entry<String, List<PluginCommand>> entry = iterator.next();
final Iterator<PluginCommand> pcIterator = entry.getValue().iterator();
while (pcIterator.hasNext()) {
final PluginCommand pc = pcIterator.next();
if (pc.getPlugin() == null || pc.getPlugin().equals(plugin)) {
pcIterator.remove();
}
}
entry.getValue().removeIf(pc -> pc.getPlugin() == null || pc.getPlugin().equals(plugin));
if (entry.getValue().isEmpty()) {
iterator.remove();
}
@@ -0,0 +1,452 @@
package com.earth2me.essentials;
import com.earth2me.essentials.api.IAsyncTeleport;
import com.earth2me.essentials.commands.WarpNotFoundException;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.LocationUtil;
import io.papermc.lib.PaperLib;
import net.ess3.api.IEssentials;
import net.ess3.api.IUser;
import net.ess3.api.InvalidWorldException;
import net.ess3.api.events.UserWarpEvent;
import net.ess3.api.events.teleport.PreTeleportEvent;
import net.ess3.api.events.teleport.TeleportWarmupEvent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import static com.earth2me.essentials.I18n.tl;
public class AsyncTeleport implements IAsyncTeleport {
private final IUser teleportOwner;
private final IEssentials ess;
private AsyncTimedTeleport timedTeleport;
private TeleportType tpType;
public AsyncTeleport(IUser user, IEssentials ess) {
this.teleportOwner = user;
this.ess = ess;
tpType = TeleportType.NORMAL;
}
public enum TeleportType {
TPA,
BACK,
NORMAL
}
public void cooldown(boolean check) throws Throwable {
CompletableFuture<Boolean> exceptionFuture = new CompletableFuture<>();
if (cooldown(check, exceptionFuture)) {
try {
exceptionFuture.get();
} catch (ExecutionException e) {
throw e.getCause();
}
}
}
public boolean cooldown(boolean check, CompletableFuture<Boolean> future) {
final Calendar time = new GregorianCalendar();
if (teleportOwner.getLastTeleportTimestamp() > 0) {
// Take the current time, and remove the delay from it.
final double cooldown = ess.getSettings().getTeleportCooldown();
final Calendar earliestTime = new GregorianCalendar();
earliestTime.add(Calendar.SECOND, -(int) cooldown);
earliestTime.add(Calendar.MILLISECOND, -(int) ((cooldown * 1000.0) % 1000.0));
// This value contains the most recent time a teleportPlayer could have been used that would allow another use.
final long earliestLong = earliestTime.getTimeInMillis();
// When was the last teleportPlayer used?
final long lastTime = teleportOwner.getLastTeleportTimestamp();
if (lastTime > time.getTimeInMillis()) {
// This is to make sure time didn't get messed up on last teleportPlayer use.
// If this happens, let's give the user the benifit of the doubt.
teleportOwner.setLastTeleportTimestamp(time.getTimeInMillis());
return false;
} else if (lastTime > earliestLong
&& cooldownApplies()) {
time.setTimeInMillis(lastTime);
time.add(Calendar.SECOND, (int) cooldown);
time.add(Calendar.MILLISECOND, (int) ((cooldown * 1000.0) % 1000.0));
future.completeExceptionally(new Exception(tl("timeBeforeTeleport", DateUtil.formatDateDiff(time.getTimeInMillis()))));
return true;
}
}
// if justCheck is set, don't update lastTeleport; we're just checking
if (!check) {
teleportOwner.setLastTeleportTimestamp(time.getTimeInMillis());
}
return false;
}
private boolean cooldownApplies() {
boolean applies = true;
String globalBypassPerm = "essentials.teleport.cooldown.bypass";
switch (tpType) {
case NORMAL:
applies = !teleportOwner.isAuthorized(globalBypassPerm);
break;
case BACK:
applies = !(teleportOwner.isAuthorized(globalBypassPerm) &&
teleportOwner.isAuthorized("essentials.teleport.cooldown.bypass.back"));
break;
case TPA:
applies = !(teleportOwner.isAuthorized(globalBypassPerm) &&
teleportOwner.isAuthorized("essentials.teleport.cooldown.bypass.tpa"));
break;
}
return applies;
}
private void warnUser(final IUser user, final double delay) {
Calendar c = new GregorianCalendar();
c.add(Calendar.SECOND, (int) delay);
c.add(Calendar.MILLISECOND, (int) ((delay * 1000.0) % 1000.0));
user.sendMessage(tl("dontMoveMessage", DateUtil.formatDateDiff(c.getTimeInMillis())));
}
@Override
public void now(Location loc, boolean cooldown, TeleportCause cause, CompletableFuture<Boolean> future) {
if (cooldown && cooldown(false, future)) {
return;
}
final ITarget target = new LocationTarget(loc);
nowAsync(teleportOwner, target, cause, future);
}
@Override
public void now(Player entity, boolean cooldown, TeleportCause cause, CompletableFuture<Boolean> future) {
if (cooldown && cooldown(false, future)) {
future.complete(false);
return;
}
final ITarget target = new PlayerTarget(entity);
nowAsync(teleportOwner, target, cause, future);
future.thenAccept(success -> {
if (success) {
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
}
});
}
private void runOnMain(Runnable runnable) throws ExecutionException, InterruptedException {
if (Bukkit.isPrimaryThread()) {
runnable.run();
return;
}
CompletableFuture<Object> taskLock = new CompletableFuture<>();
Bukkit.getScheduler().runTask(ess, () -> {
runnable.run();
taskLock.complete(new Object());
});
taskLock.get();
}
protected void nowAsync(IUser teleportee, ITarget target, TeleportCause cause, CompletableFuture<Boolean> future) {
cancel(false);
PreTeleportEvent event = new PreTeleportEvent(teleportee, cause, target);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
teleportee.setLastLocation();
if (!ess.getSettings().isForcePassengerTeleport() && !teleportee.getBase().isEmpty()) {
if (!ess.getSettings().isTeleportPassengerDismount()) {
future.completeExceptionally(new Exception(tl("passengerTeleportFail")));
return;
}
try {
runOnMain(() -> teleportee.getBase().eject()); //EntityDismountEvent requires a sync context.
} catch (ExecutionException | InterruptedException e) {
future.completeExceptionally(e);
return;
}
}
teleportee.setLastLocation();
PaperLib.getChunkAtAsync(target.getLocation()).thenAccept(chunk -> {
Location loc = target.getLocation();
if (LocationUtil.isBlockUnsafeForUser(teleportee, chunk.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) {
if (ess.getSettings().isTeleportSafetyEnabled()) {
if (ess.getSettings().isForceDisableTeleportSafety()) {
//The chunk we're teleporting to is 100% going to be loaded here, no need to teleport async.
teleportee.getBase().teleport(loc, cause);
} else {
try {
//There's a chance the safer location is outside the loaded chunk so still teleport async here.
PaperLib.teleportAsync(teleportee.getBase(), LocationUtil.getSafeDestination(ess, teleportee, loc), cause);
} catch (Exception e) {
future.completeExceptionally(e);
return;
}
}
} else {
future.completeExceptionally(new Exception(tl("unsafeTeleportDestination", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())));
return;
}
} else {
if (ess.getSettings().isForceDisableTeleportSafety()) {
//The chunk we're teleporting to is 100% going to be loaded here, no need to teleport async.
teleportee.getBase().teleport(loc, cause);
} else {
if (ess.getSettings().isTeleportToCenterLocation()) {
loc = LocationUtil.getRoundedDestination(loc);
}
//There's a *small* chance the rounded destination produces a location outside the loaded chunk so still teleport async here.
PaperLib.teleportAsync(teleportee.getBase(), loc, cause);
}
}
future.complete(true);
});
}
@Override
public void teleport(Location loc, Trade chargeFor, TeleportCause cause, CompletableFuture<Boolean> future) {
teleport(teleportOwner, new LocationTarget(loc), chargeFor, cause, future);
}
@Override
public void teleport(Player entity, Trade chargeFor, TeleportCause cause, CompletableFuture<Boolean> future) {
teleportOwner.sendMessage(tl("teleportToPlayer", entity.getDisplayName()));
teleport(teleportOwner, new PlayerTarget(entity), chargeFor, cause, future);
}
@Override
public void teleportPlayer(IUser otherUser, Location loc, Trade chargeFor, TeleportCause cause, CompletableFuture<Boolean> future) {
teleport(otherUser, new LocationTarget(loc), chargeFor, cause, future);
}
@Override
public void teleportPlayer(IUser otherUser, Player entity, Trade chargeFor, TeleportCause cause, CompletableFuture<Boolean> future) {
ITarget target = new PlayerTarget(entity);
teleport(otherUser, target, chargeFor, cause, future);
future.thenAccept(success -> {
if (success) {
otherUser.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
}
});
}
private void teleport(IUser teleportee, ITarget target, Trade chargeFor, TeleportCause cause, CompletableFuture<Boolean> future) {
double delay = ess.getSettings().getTeleportDelay();
TeleportWarmupEvent event = new TeleportWarmupEvent(teleportee, cause, target, delay);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
delay = event.getDelay();
Trade cashCharge = chargeFor;
if (chargeFor != null) {
chargeFor.isAffordableFor(teleportOwner, future);
if (future.isCompletedExceptionally()) {
return;
}
//This code is to make sure that commandcosts are checked in the initial world, and not in the resulting world.
if (!chargeFor.getCommandCost(teleportOwner).equals(BigDecimal.ZERO)) {
//By converting a command cost to a regular cost, the command cost permission isn't checked when executing the charge after teleport.
cashCharge = new Trade(chargeFor.getCommandCost(teleportOwner), ess);
}
}
if (cooldown(true, future)) {
return;
}
if (delay <= 0 || teleportOwner.isAuthorized("essentials.teleport.timer.bypass") || teleportee.isAuthorized("essentials.teleport.timer.bypass")) {
if (cooldown(false, future)) {
return;
}
nowAsync(teleportee, target, cause, future);
if (cashCharge != null) {
cashCharge.charge(teleportOwner, future);
if (future.isCompletedExceptionally()) {
return;
}
}
return;
}
cancel(false);
warnUser(teleportee, delay);
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false);
}
private void teleportOther(IUser teleporter, IUser teleportee, ITarget target, Trade chargeFor, TeleportCause cause, CompletableFuture<Boolean> future) {
double delay = ess.getSettings().getTeleportDelay();
TeleportWarmupEvent event = new TeleportWarmupEvent(teleportee, cause, target, delay);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
delay = event.getDelay();
Trade cashCharge = chargeFor;
if (teleporter != null && chargeFor != null) {
chargeFor.isAffordableFor(teleporter, future);
if (future.isCompletedExceptionally()) {
return;
}
//This code is to make sure that commandcosts are checked in the initial world, and not in the resulting world.
if (!chargeFor.getCommandCost(teleporter).equals(BigDecimal.ZERO)) {
//By converting a command cost to a regular cost, the command cost permission isn't checked when executing the charge after teleport.
cashCharge = new Trade(chargeFor.getCommandCost(teleporter), ess);
}
}
if (cooldown(true, future)) {
return;
}
if (delay <= 0 || teleporter == null
|| teleporter.isAuthorized("essentials.teleport.timer.bypass")
|| teleportOwner.isAuthorized("essentials.teleport.timer.bypass")
|| teleportee.isAuthorized("essentials.teleport.timer.bypass")) {
if (cooldown(false, future)) {
return;
}
nowAsync(teleportee, target, cause, future);
if (teleporter != null && cashCharge != null) {
cashCharge.charge(teleporter, future);
if (future.isCompletedExceptionally()) {
return;
}
}
return;
}
cancel(false);
warnUser(teleportee, delay);
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false);
}
@Override
public void respawn(Trade chargeFor, TeleportCause cause, CompletableFuture<Boolean> future) {
double delay = ess.getSettings().getTeleportDelay();
TeleportWarmupEvent event = new TeleportWarmupEvent(teleportOwner, cause, null, delay);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
delay = event.getDelay();
if (chargeFor != null) {
chargeFor.isAffordableFor(teleportOwner, future);
if (future.isCompletedExceptionally()) {
return;
}
}
if (cooldown(true, future)) {
return;
}
if (delay <= 0 || teleportOwner.isAuthorized("essentials.teleport.timer.bypass")) {
if (cooldown(false, future)) {
return;
}
respawnNow(teleportOwner, cause, future);
if (chargeFor != null) {
chargeFor.charge(teleportOwner, future);
}
return;
}
cancel(false);
warnUser(teleportOwner, delay);
initTimer((long) (delay * 1000.0), teleportOwner, null, chargeFor, cause, true);
}
void respawnNow(IUser teleportee, TeleportCause cause, CompletableFuture<Boolean> future) {
final Player player = teleportee.getBase();
PaperLib.getBedSpawnLocationAsync(player, true).thenAccept(location -> {
if (location != null) {
nowAsync(teleportee, new LocationTarget(location), cause, future);
} else {
if (ess.getSettings().isDebug()) {
ess.getLogger().info("Could not find bed spawn, forcing respawn event.");
}
final PlayerRespawnEvent pre = new PlayerRespawnEvent(player, player.getWorld().getSpawnLocation(), false);
ess.getServer().getPluginManager().callEvent(pre);
nowAsync(teleportee, new LocationTarget(pre.getRespawnLocation()), cause, future);
}
});
}
@Override
public void warp(IUser otherUser, String warp, Trade chargeFor, TeleportCause cause, CompletableFuture<Boolean> future) {
UserWarpEvent event = new UserWarpEvent(otherUser, warp, chargeFor);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
warp = event.getWarp();
Location loc;
try {
loc = ess.getWarps().getWarp(warp);
} catch (WarpNotFoundException | InvalidWorldException e) {
future.completeExceptionally(e);
return;
}
otherUser.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
if (!otherUser.equals(teleportOwner)) {
teleportOwner.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
}
teleport(otherUser, new LocationTarget(loc), chargeFor, cause, future);
}
@Override
public void back(Trade chargeFor, CompletableFuture<Boolean> future) {
back(teleportOwner, chargeFor, future);
}
@Override
public void back(IUser teleporter, Trade chargeFor, CompletableFuture<Boolean> future) {
tpType = TeleportType.BACK;
final Location loc = teleportOwner.getLastLocation();
teleportOwner.sendMessage(tl("backUsageMsg", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
teleportOther(teleporter, teleportOwner, new LocationTarget(loc), chargeFor, TeleportCause.COMMAND, future);
}
@Override
public void back(CompletableFuture<Boolean> future) {
nowAsync(teleportOwner, new LocationTarget(teleportOwner.getLastLocation()), TeleportCause.COMMAND, future);
}
public void setTpType(TeleportType tpType) {
this.tpType = tpType;
}
//If we need to cancelTimer a pending teleportPlayer call this method
private void cancel(boolean notifyUser) {
if (timedTeleport != null) {
timedTeleport.cancelTimer(notifyUser);
timedTeleport = null;
}
}
private void initTimer(long delay, IUser teleportUser, ITarget target, Trade chargeFor, TeleportCause cause, boolean respawn) {
timedTeleport = new AsyncTimedTeleport(teleportOwner, ess, this, delay, teleportUser, target, chargeFor, cause, respawn);
}
}
@@ -0,0 +1,151 @@
package com.earth2me.essentials;
import net.ess3.api.IEssentials;
import net.ess3.api.IUser;
import org.bukkit.Location;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import static com.earth2me.essentials.I18n.tl;
public class AsyncTimedTeleport implements Runnable {
private static final double MOVE_CONSTANT = 0.3;
private final IUser teleportOwner;
private final IEssentials ess;
private final AsyncTeleport teleport;
private final UUID timer_teleportee;
private int timer_task;
private final long timer_started; // time this task was initiated
private final long timer_delay; // how long to delay the teleportPlayer
private double timer_health;
// note that I initially stored a clone of the location for reference, but...
// when comparing locations, I got incorrect mismatches (rounding errors, looked like)
// so, the X/Y/Z values are stored instead and rounded off
private final long timer_initX;
private final long timer_initY;
private final long timer_initZ;
private final ITarget timer_teleportTarget;
private final boolean timer_respawn;
private final boolean timer_canMove;
private final Trade timer_chargeFor;
private final TeleportCause timer_cause;
AsyncTimedTeleport(IUser user, IEssentials ess, AsyncTeleport teleport, long delay, IUser teleportUser, ITarget target, Trade chargeFor, TeleportCause cause, boolean respawn) {
this.teleportOwner = user;
this.ess = ess;
this.teleport = teleport;
this.timer_started = System.currentTimeMillis();
this.timer_delay = delay;
this.timer_health = teleportUser.getBase().getHealth();
this.timer_initX = Math.round(teleportUser.getBase().getLocation().getX() * MOVE_CONSTANT);
this.timer_initY = Math.round(teleportUser.getBase().getLocation().getY() * MOVE_CONSTANT);
this.timer_initZ = Math.round(teleportUser.getBase().getLocation().getZ() * MOVE_CONSTANT);
this.timer_teleportee = teleportUser.getBase().getUniqueId();
this.timer_teleportTarget = target;
this.timer_chargeFor = chargeFor;
this.timer_cause = cause;
this.timer_respawn = respawn;
this.timer_canMove = user.isAuthorized("essentials.teleport.timer.move");
timer_task = ess.runTaskTimerAsynchronously(this, 20, 20).getTaskId();
}
@Override
public void run() {
if (teleportOwner == null || !teleportOwner.getBase().isOnline() || teleportOwner.getBase().getLocation() == null) {
cancelTimer(false);
return;
}
final IUser teleportUser = ess.getUser(this.timer_teleportee);
if (teleportUser == null || !teleportUser.getBase().isOnline()) {
cancelTimer(false);
return;
}
final Location currLocation = teleportUser.getBase().getLocation();
if (currLocation == null) {
cancelTimer(false);
return;
}
if (!timer_canMove && (Math.round(currLocation.getX() * MOVE_CONSTANT) != timer_initX || Math.round(currLocation.getY() * MOVE_CONSTANT) != timer_initY || Math.round(currLocation.getZ() * MOVE_CONSTANT) != timer_initZ || teleportUser.getBase().getHealth() < timer_health)) {
// user moved, cancelTimer teleportPlayer
cancelTimer(true);
return;
}
class DelayedTeleportTask implements Runnable {
@Override
public void run() {
timer_health = teleportUser.getBase().getHealth(); // in case user healed, then later gets injured
final long now = System.currentTimeMillis();
if (now > timer_started + timer_delay) {
try {
teleport.cooldown(false);
} catch (Throwable ex) {
teleportOwner.sendMessage(tl("cooldownWithMessage", ex.getMessage()));
if (teleportOwner != teleportUser) {
teleportUser.sendMessage(tl("cooldownWithMessage", ex.getMessage()));
}
}
try {
cancelTimer(false);
teleportUser.sendMessage(tl("teleportationCommencing"));
CompletableFuture<Boolean> future = new CompletableFuture<>();
future.exceptionally(e -> {
ess.showError(teleportOwner.getSource(), e, "\\ teleport");
return false;
});
if (timer_chargeFor != null) {
timer_chargeFor.isAffordableFor(teleportOwner);
}
if (timer_respawn) {
teleport.respawnNow(teleportUser, timer_cause, future);
} else {
teleport.nowAsync(teleportUser, timer_teleportTarget, timer_cause, future);
}
future.thenAccept(success -> {
if (timer_chargeFor != null) {
try {
timer_chargeFor.charge(teleportOwner);
} catch (ChargeException ex) {
ess.showError(teleportOwner.getSource(), ex, "\\ teleport");
}
}
});
} catch (Exception ex) {
ess.showError(teleportOwner.getSource(), ex, "\\ teleport");
}
}
}
}
ess.scheduleSyncDelayedTask(new DelayedTeleportTask());
}
//If we need to cancelTimer a pending teleportPlayer call this method
void cancelTimer(boolean notifyUser) {
if (timer_task == -1) {
return;
}
try {
ess.getServer().getScheduler().cancelTask(timer_task);
if (notifyUser) {
teleportOwner.sendMessage(tl("pendingTeleportCancelled"));
if (timer_teleportee != null && !timer_teleportee.equals(teleportOwner.getBase().getUniqueId())) {
ess.getUser(timer_teleportee).sendMessage(tl("pendingTeleportCancelled"));
}
}
} finally {
timer_task = -1;
}
}
}
@@ -7,6 +7,8 @@ import org.bukkit.command.CommandSender;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -20,17 +22,14 @@ public class Backup implements Runnable {
private transient boolean running = false;
private transient int taskId = -1;
private transient boolean active = false;
private final AtomicBoolean pendingShutdown = new AtomicBoolean(false);
private transient CompletableFuture<Object> taskLock = null;
public Backup(final IEssentials ess) {
this.ess = ess;
server = ess.getServer();
if (!ess.getOnlinePlayers().isEmpty()) {
ess.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
startTask();
}
});
if (!ess.getOnlinePlayers().isEmpty() || ess.getSettings().isAlwaysRunBackup()) {
ess.runTaskAsynchronously(this::startTask);
}
}
@@ -57,20 +56,30 @@ public class Backup implements Runnable {
}
}
public CompletableFuture<Object> getTaskLock() {
return taskLock;
}
public void setPendingShutdown(boolean shutdown) {
pendingShutdown.set(shutdown);
}
@Override
public void run() {
if (active) {
return;
}
active = true;
final String command = ess.getSettings().getBackupCommand();
if (command == null || "".equals(command)) {
return;
}
active = true;
taskLock = new CompletableFuture<>();
if ("save-all".equalsIgnoreCase(command)) {
final CommandSender cs = server.getConsoleSender();
server.dispatchCommand(cs, "save-all");
active = false;
taskLock.complete(new Object());
return;
}
LOGGER.log(Level.INFO, tl("backupStarted"));
@@ -78,52 +87,44 @@ public class Backup implements Runnable {
server.dispatchCommand(cs, "save-all");
server.dispatchCommand(cs, "save-off");
ess.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
try {
final ProcessBuilder childBuilder = new ProcessBuilder(command);
childBuilder.redirectErrorStream(true);
childBuilder.directory(ess.getDataFolder().getParentFile().getParentFile());
final Process child = childBuilder.start();
ess.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
try {
final BufferedReader reader = new BufferedReader(new InputStreamReader(child.getInputStream()));
try {
String line;
do {
line = reader.readLine();
if (line != null) {
LOGGER.log(Level.INFO, line);
}
} while (line != null);
} finally {
reader.close();
ess.runTaskAsynchronously(() -> {
try {
final ProcessBuilder childBuilder = new ProcessBuilder(command);
childBuilder.redirectErrorStream(true);
childBuilder.directory(ess.getDataFolder().getParentFile().getParentFile());
final Process child = childBuilder.start();
ess.runTaskAsynchronously(() -> {
try {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(child.getInputStream()))) {
String line;
do {
line = reader.readLine();
if (line != null) {
LOGGER.log(Level.INFO, line);
}
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, null, ex);
}
}
});
child.waitFor();
} catch (InterruptedException ex) {
LOGGER.log(Level.SEVERE, null, ex);
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, null, ex);
} finally {
class BackupEnableSaveTask implements Runnable {
@Override
public void run() {
server.dispatchCommand(cs, "save-on");
if (ess.getOnlinePlayers().isEmpty()) {
stopTask();
}
active = false;
LOGGER.log(Level.INFO, tl("backupFinished"));
} while (line != null);
}
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, null, ex);
}
});
child.waitFor();
} catch (InterruptedException | IOException ex) {
LOGGER.log(Level.SEVERE, null, ex);
} finally {
class BackupEnableSaveTask implements Runnable {
@Override
public void run() {
server.dispatchCommand(cs, "save-on");
if (!ess.getSettings().isAlwaysRunBackup() && ess.getOnlinePlayers().isEmpty()) {
stopTask();
}
active = false;
taskLock.complete(new Object());
LOGGER.log(Level.INFO, tl("backupFinished"));
}
}
if (!pendingShutdown.get()) {
ess.scheduleSyncDelayedTask(new BackupEnableSaveTask());
}
}
@@ -11,8 +11,8 @@ import java.util.Set;
public class Enchantments {
private static final Map<String, Enchantment> ENCHANTMENTS = new HashMap<String, Enchantment>();
private static final Map<String, Enchantment> ALIASENCHANTMENTS = new HashMap<String, Enchantment>();
private static final Map<String, Enchantment> ENCHANTMENTS = new HashMap<>();
private static final Map<String, Enchantment> ALIASENCHANTMENTS = new HashMap<>();
private static boolean isFlat;
static {
@@ -251,6 +251,15 @@ public class Enchantments {
}
} catch (IllegalArgumentException ignored) {}
try { // 1.16
Enchantment soulspeed = Enchantment.getByName("SOUL_SPEED");
if (soulspeed != null) {
ENCHANTMENTS.put("soulspeed", soulspeed);
ALIASENCHANTMENTS.put("soilspeed", soulspeed);
ALIASENCHANTMENTS.put("sandspeed", soulspeed);
}
} catch (IllegalArgumentException ignored) {}
try {
Class<?> namespacedKeyClass = Class.forName("org.bukkit.NamespacedKey");
Class<?> enchantmentClass = Class.forName("org.bukkit.enchantments.Enchantment");
@@ -19,9 +19,10 @@ package com.earth2me.essentials;
import com.earth2me.essentials.commands.*;
import com.earth2me.essentials.items.AbstractItemDb;
import com.earth2me.essentials.items.CustomItemResolver;
import com.earth2me.essentials.items.FlatItemDb;
import com.earth2me.essentials.items.LegacyItemDb;
import com.earth2me.essentials.metrics.Metrics;
import com.earth2me.essentials.metrics.MetricsWrapper;
import com.earth2me.essentials.perm.PermissionsHandler;
import com.earth2me.essentials.register.payment.Methods;
import com.earth2me.essentials.signs.SignBlockListener;
@@ -32,35 +33,31 @@ import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import net.ess3.api.*;
import io.papermc.lib.PaperLib;
import net.ess3.api.IEssentials;
import net.ess3.api.ISettings;
import net.ess3.nms.PotionMetaProvider;
import net.ess3.nms.SpawnEggProvider;
import net.ess3.nms.SpawnerProvider;
import net.ess3.nms.flattened.FlatSpawnEggProvider;
import net.ess3.nms.legacy.LegacyPotionMetaProvider;
import net.ess3.nms.legacy.LegacySpawnEggProvider;
import net.ess3.nms.legacy.LegacySpawnerProvider;
import net.ess3.nms.refl.ReflSpawnEggProvider;
import net.ess3.nms.updatedmeta.BasePotionDataProvider;
import net.ess3.nms.updatedmeta.BlockMetaSpawnerProvider;
import net.ess3.nms.v1_8_R1.v1_8_R1SpawnerProvider;
import net.ess3.nms.v1_8_R2.v1_8_R2SpawnerProvider;
import net.ess3.providers.ProviderFactory;
import net.ess3.api.*;
import net.ess3.nms.refl.providers.ReflServerStateProvider;
import net.ess3.nms.refl.providers.ReflSpawnEggProvider;
import net.ess3.provider.PotionMetaProvider;
import net.ess3.provider.ProviderListener;
import net.ess3.provider.ServerStateProvider;
import net.ess3.provider.SpawnEggProvider;
import net.ess3.provider.SpawnerProvider;
import net.ess3.provider.providers.*;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
@@ -81,8 +78,10 @@ import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import static com.earth2me.essentials.I18n.tl;
@@ -97,37 +96,37 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
private transient List<IConf> confList;
private transient Backup backup;
private transient AbstractItemDb itemDb;
private transient CustomItemResolver customItemResolver;
private transient final Methods paymentMethod = new Methods();
private transient PermissionsHandler permissionsHandler;
private transient AlternativeCommandsHandler alternativeCommandsHandler;
private transient UserMap userMap;
private transient ExecuteTimer execTimer;
private transient I18n i18n;
private transient Metrics metrics;
private transient MetricsWrapper metrics;
private transient EssentialsTimer timer;
private final transient Set<String> vanishedPlayers = new LinkedHashSet<>();
private transient Method oldGetOnlinePlayers;
private transient SpawnerProvider spawnerProvider;
private transient SpawnEggProvider spawnEggProvider;
private transient PotionMetaProvider potionMetaProvider;
private transient ServerStateProvider serverStateProvider;
private transient ProviderListener recipeBookEventProvider;
private transient Kits kits;
private transient RandomTeleport randomTeleport;
public Essentials() {
}
protected Essentials(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) {
super(loader, description, dataFolder, file);
}
public Essentials(final Server server) {
super(new JavaPluginLoader(server), new PluginDescriptionFile("Essentials", "", "com.earth2me.essentials.Essentials"), null, null);
}
@SuppressWarnings("unused")
public void forceLoadClasses() {
try {
Class.forName(OfflinePlayer.class.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
public ISettings getSettings() {
return settings;
@@ -145,7 +144,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
i18n.onEnable();
i18n.updateLocale("en");
Console.setInstance(this);
LOGGER.log(Level.INFO, tl("usingTempFolderForTesting"));
LOGGER.log(Level.INFO, dataFolder.toString());
settings = new Settings(this);
@@ -169,7 +168,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
i18n = new I18n(this);
i18n.onEnable();
execTimer.mark("I18n1");
Console.setInstance(this);
if (!VersionUtil.isServerSupported()) {
@@ -190,8 +189,6 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
}
forceLoadClasses();
try {
final EssentialsUpgrade upgrade = new EssentialsUpgrade(this);
upgrade.beforeSettings();
@@ -216,36 +213,75 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
warps = new Warps(getServer(), this.getDataFolder());
confList.add(warps);
execTimer.mark("Init(Spawn/Warp)");
execTimer.mark("Init(Warp)");
worth = new Worth(this.getDataFolder());
confList.add(worth);
execTimer.mark("Init(Worth)");
itemDb = getItemDbFromConfig();
confList.add(itemDb);
execTimer.mark("Init(Worth/ItemDB)");
execTimer.mark("Init(ItemDB)");
randomTeleport = new RandomTeleport(this);
if (randomTeleport.getPreCache()) {
randomTeleport.cacheRandomLocations(randomTeleport.getCenter(), randomTeleport.getMinRange(), randomTeleport.getMaxRange());
}
confList.add(randomTeleport);
execTimer.mark("Init(RandomTeleport)");
customItemResolver = new CustomItemResolver(this);
try {
itemDb.registerResolver(this, "custom_items", customItemResolver);
confList.add(customItemResolver);
} catch (Exception e) {
e.printStackTrace();
customItemResolver = null;
}
execTimer.mark("Init(CustomItemResolver)");
jails = new Jails(this);
confList.add(jails);
execTimer.mark("Init(Jails)");
spawnerProvider = new ProviderFactory<>(getLogger(),
Arrays.asList(
BlockMetaSpawnerProvider.class,
v1_8_R2SpawnerProvider.class,
v1_8_R1SpawnerProvider.class,
LegacySpawnerProvider.class
), "mob spawner").getProvider();
spawnEggProvider = new ProviderFactory<>(getLogger(),
Arrays.asList(
FlatSpawnEggProvider.class,
ReflSpawnEggProvider.class,
LegacySpawnEggProvider.class
), "spawn egg").getProvider();
potionMetaProvider = new ProviderFactory<>(getLogger(),
Arrays.asList(
BasePotionDataProvider.class,
LegacyPotionMetaProvider.class
), "potion meta").getProvider();
//Spawner provider only uses one but it's here for legacy...
spawnerProvider = new BlockMetaSpawnerProvider();
//Spawn Egg Providers
if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_8_8_R01)) {
spawnEggProvider = new LegacySpawnEggProvider();
} else if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_12_2_R01)) {
spawnEggProvider = new ReflSpawnEggProvider();
} else {
spawnEggProvider = new FlatSpawnEggProvider();
}
//Potion Meta Provider
if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_8_8_R01)) {
potionMetaProvider = new LegacyPotionMetaProvider();
} else {
potionMetaProvider = new BasePotionDataProvider();
}
//Server State Provider
if (PaperLib.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_2_R01)) {
serverStateProvider = new PaperServerStateProvider();
} else {
serverStateProvider = new ReflServerStateProvider(getLogger());
}
//Event Providers
if (PaperLib.isPaper()) {
try {
Class.forName("com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent");
recipeBookEventProvider = new PaperRecipeBookListener(event -> {
if (this.getUser(((PlayerEvent) event).getPlayer()).isRecipeSee()) {
((Cancellable) event).setCancelled(true);
}
});
} catch (ClassNotFoundException ignored) {}
}
execTimer.mark("Init(Providers)");
reload();
@@ -265,6 +301,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
permissionsHandler = new PermissionsHandler(this, settings.useBukkitPermissions());
alternativeCommandsHandler = new AlternativeCommandsHandler(this);
// Register hat permissions
Commandhat.registerPermissionsIfNecessary(getServer().getPluginManager());
timer = new EssentialsTimer(this);
scheduleSyncRepeatingTask(timer, 1000, 50);
@@ -274,12 +313,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
for (World w : Bukkit.getWorlds())
addDefaultBackPermissionsToWorld(w);
metrics = new Metrics(this);
if (metrics.isEnabled()) {
getLogger().info("Starting Metrics. Opt-out using the global bStats config.");
} else {
getLogger().info("Metrics disabled per bStats config.");
}
metrics = new MetricsWrapper(this, 858, true);
final String timeroutput = execTimer.end();
if (getSettings().isDebug()) {
@@ -291,6 +325,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
handleCrash(ex);
throw ex;
}
getBackup().setPendingShutdown(false);
}
@Override
@@ -335,25 +370,49 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
pm.registerEvents(tntListener, this);
if (recipeBookEventProvider != null) {
pm.registerEvents(recipeBookEventProvider, this);
}
jails.resetListener();
}
@Override
public void onDisable() {
boolean stopping = getServerStateProvider().isStopping();
if (!stopping) {
LOGGER.log(Level.SEVERE, tl("serverReloading"));
}
getBackup().setPendingShutdown(true);
for (User user : getOnlineUsers()) {
if (user.isVanished()) {
user.setVanished(false);
user.sendMessage(tl("unvanishedReload"));
}
user.stopTransaction();
if (stopping) {
user.setLastLocation();
if (!user.isHidden()) {
user.setLastLogout(System.currentTimeMillis());
}
user.cleanup();
} else {
user.stopTransaction();
}
}
cleanupOpenInventories();
if (getBackup().getTaskLock() != null && !getBackup().getTaskLock().isDone()) {
LOGGER.log(Level.SEVERE, tl("backupInProgress"));
getBackup().getTaskLock().join();
}
if (i18n != null) {
i18n.onDisable();
}
if (backup != null) {
backup.stopTask();
}
this.getPermissionsHandler().unregisterContexts();
Economy.setEss(null);
Trade.closeLog();
getUserMap().getUUIDMap().shutdown();
@@ -371,6 +430,13 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
i18n.updateLocale(settings.getLocale());
for (String commandName : this.getDescription().getCommands().keySet()) {
Command command = this.getCommand(commandName);
if (command != null) {
command.setDescription(tl(commandName + "CommandDescription"));
command.setUsage(tl(commandName + "CommandUsage"));
}
}
final PluginManager pm = getServer().getPluginManager();
registerListeners(pm);
@@ -379,7 +445,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String commandLabel, String[] args) {
return onTabCompleteEssentials(sender, command, commandLabel, args, Essentials.class.getClassLoader(),
"com.earth2me.essentials.commands.Command", "essentials.", null);
"com.earth2me.essentials.commands.Command", "essentials.", null);
}
@Override
@@ -455,6 +521,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
@Override
public boolean onCommand(final CommandSender sender, final Command command, final String commandLabel, final String[] args) {
metrics.markCommand(command.getName(), true);
return onCommandEssentials(sender, command, commandLabel, args, Essentials.class.getClassLoader(), "com.earth2me.essentials.commands.Command", "essentials.", null);
}
@@ -487,7 +554,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
if (bSenderBlock != null) {
Bukkit.getLogger().log(Level.INFO, "CommandBlock at {0},{1},{2} issued server command: /{3} {4}", new Object[]{bSenderBlock.getX(), bSenderBlock.getY(), bSenderBlock.getZ(), commandLabel, EssentialsCommand.getFinalArg(args, 0)});
if (getSettings().logCommandBlockCommands()) {
Bukkit.getLogger().log(Level.INFO, "CommandBlock at {0},{1},{2} issued server command: /{3} {4}", new Object[]{bSenderBlock.getX(), bSenderBlock.getY(), bSenderBlock.getZ(), commandLabel, EssentialsCommand.getFinalArg(args, 0)});
}
} else if (user == null) {
Bukkit.getLogger().log(Level.INFO, "{0} issued server command: /{1} {2}", new Object[]{cSender.getName(), commandLabel, EssentialsCommand.getFinalArg(args, 0)});
}
@@ -507,6 +576,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
// Check for disabled commands
if (getSettings().isCommandDisabled(commandLabel)) {
sender.sendMessage(tl("commandDisabled", commandLabel));
return true;
}
@@ -545,9 +615,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
cmd.run(getServer(), user, commandLabel, command, args);
}
return true;
} catch (NoChargeException ex) {
return true;
} catch (QuietAbortException ex) {
} catch (NoChargeException | QuietAbortException ex) {
return true;
} catch (NotEnoughArgumentsException ex) {
sender.sendMessage(command.getDescription());
@@ -623,13 +691,8 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
@Override
public Metrics getMetrics() {
return metrics;
}
@Override
public void setMetrics(Metrics metrics) {
this.metrics = metrics;
public RandomTeleport getRandomTeleport() {
return randomTeleport;
}
@Deprecated
@@ -742,20 +805,25 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
@Override
public int broadcastMessage(final String message) {
return broadcastMessage(null, null, message, true);
return broadcastMessage(null, null, message, true, u -> false);
}
@Override
public int broadcastMessage(final IUser sender, final String message) {
return broadcastMessage(sender, null, message, false);
return broadcastMessage(sender, null, message, false, u -> false);
}
@Override
public int broadcastMessage(final IUser sender, final String message, final Predicate<IUser> shouldExclude) {
return broadcastMessage(sender, null, message, false, shouldExclude);
}
@Override
public int broadcastMessage(final String permission, final String message) {
return broadcastMessage(null, permission, message, false);
return broadcastMessage(null, permission, message, false, u -> false);
}
private int broadcastMessage(final IUser sender, final String permission, final String message, final boolean keywords) {
private int broadcastMessage(final IUser sender, final String permission, final String message, final boolean keywords, final Predicate<IUser> shouldExclude) {
if (sender != null && sender.isHidden()) {
return 0;
}
@@ -763,10 +831,12 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
IText broadcast = new SimpleTextInput(message);
final Collection<Player> players = getOnlinePlayers();
for (Player player : players) {
final User user = getUser(player);
if ((permission == null && (sender == null || !user.isIgnoredPlayer(sender))) || (permission != null && user.isAuthorized(permission))) {
if (shouldExclude.test(user)) {
continue;
}
if (keywords) {
broadcast = new KeywordReplacer(broadcast, new CommandSource(player), this, false);
}
@@ -871,13 +941,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
@Override
public Iterable<User> getOnlineUsers() {
return Iterables.transform(getOnlinePlayers(), new Function<Player, User>() {
@Override
public User apply(Player player) {
return getUser(player);
}
});
return getOnlinePlayers().stream().map(this::getUser).collect(Collectors.toList());
}
@Override
@@ -895,6 +959,16 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return potionMetaProvider;
}
@Override
public CustomItemResolver getCustomItemResolver() {
return customItemResolver;
}
@Override
public ServerStateProvider getServerStateProvider() {
return serverStateProvider;
}
private static void addDefaultBackPermissionsToWorld(World w) {
String permName = "essentials.back.into." + w.getName();
@@ -1,11 +1,9 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.LocationUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import net.ess3.api.IEssentials;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.entity.EntityType;
@@ -2,8 +2,8 @@ package com.earth2me.essentials;
import com.google.common.io.Files;
import net.ess3.api.InvalidWorldException;
import org.bukkit.*;
import org.bukkit.OfflinePlayer;
import org.bukkit.*;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
@@ -14,11 +14,13 @@ import org.bukkit.util.Vector;
import java.io.*;
import java.math.BigDecimal;
import java.math.MathContext;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -36,7 +38,7 @@ public class EssentialsConf extends YamlConfiguration {
protected static final Logger LOGGER = Logger.getLogger("Essentials");
protected final File configFile;
protected String templateName = null;
protected static final Charset UTF8 = Charset.forName("UTF-8");
protected static final Charset UTF8 = StandardCharsets.UTF_8;
private Class<?> resourceClass = EssentialsConf.class;
private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
private final AtomicInteger pendingDiskWrites = new AtomicInteger(0);
@@ -108,20 +110,21 @@ public class EssentialsConf extends YamlConfiguration {
if (length > buffer.remaining()) {
ByteBuffer resize = ByteBuffer.allocate(buffer.capacity() + length - buffer.remaining());
int resizePosition = buffer.position();
buffer.rewind();
// Fix builds compiled against Java 9+ breaking on Java 8
((Buffer) buffer).rewind();
resize.put(buffer);
resize.position(resizePosition);
buffer = resize;
}
buffer.put(bytebuffer, 0, length);
}
buffer.rewind();
((Buffer) buffer).rewind();
final CharBuffer data = CharBuffer.allocate(buffer.capacity());
CharsetDecoder decoder = UTF8.newDecoder();
CoderResult result = decoder.decode(buffer, data, true);
if (result.isError()) {
buffer.rewind();
data.clear();
((Buffer) buffer).rewind();
((Buffer) data).clear();
LOGGER.log(Level.INFO, "File " + configFile.getAbsolutePath() + " is not utf-8 encoded, trying " + Charset.defaultCharset().displayName());
decoder = Charset.defaultCharset().newDecoder();
result = decoder.decode(buffer, data, true);
@@ -134,7 +137,7 @@ public class EssentialsConf extends YamlConfiguration {
decoder.flush(data);
}
final int end = data.position();
data.rewind();
((Buffer) data).rewind();
super.loadFromString(data.subSequence(0, end).toString());
}
} catch (IOException ex) {
@@ -437,9 +440,7 @@ public class EssentialsConf extends YamlConfiguration {
} else {
try {
return new BigDecimal(input, MathContext.DECIMAL128);
} catch (NumberFormatException e) {
return def;
} catch (ArithmeticException e) {
} catch (NumberFormatException | ArithmeticException e) {
return def;
}
}
@@ -1,7 +1,10 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.api.IEssentials;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -127,7 +130,11 @@ public class EssentialsEntityListener implements Listener {
if (event.getCombuster() instanceof Arrow && event.getEntity() instanceof Player) {
Arrow combuster = (Arrow) event.getCombuster();
if (combuster.getShooter() instanceof Player) {
final User srcCombuster = ess.getUser(((Player) combuster.getShooter()).getUniqueId());
Player shooter = (Player) combuster.getShooter();
if (shooter.hasMetadata("NPC")) {
return;
}
final User srcCombuster = ess.getUser(shooter.getUniqueId());
if (srcCombuster.isGodModeEnabled() && !srcCombuster.isAuthorized("essentials.god.pvp")) {
event.setCancelled(true);
}
@@ -140,7 +147,15 @@ public class EssentialsEntityListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerDeathEvent(final PlayerDeathEvent event) {
Entity entity = event.getEntity();
if (entity.hasMetadata("NPC")) {
return;
}
final User user = ess.getUser(event.getEntity());
if (ess.getSettings().infoAfterDeath()) {
final Location loc = user.getLocation();
user.sendMessage(tl("infoAfterDeath", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
}
if (user.isAuthorized("essentials.back.ondeath") && !ess.getSettings().isCommandDisabled("back")) {
user.setLastLocation();
user.sendMessage(tl("backAfterDeath"));
@@ -164,6 +179,58 @@ public class EssentialsEntityListener implements Listener {
final User user = ess.getUser(event.getEntity());
if (user.isAuthorized("essentials.keepinv")) {
event.setKeepInventory(true);
event.getDrops().clear();
ISettings.KeepInvPolicy vanish = ess.getSettings().getVanishingItemsPolicy();
ISettings.KeepInvPolicy bind = ess.getSettings().getBindingItemsPolicy();
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_11_2_R01) && (vanish != ISettings.KeepInvPolicy.KEEP || bind != ISettings.KeepInvPolicy.KEEP)) {
for (ItemStack stack : event.getEntity().getInventory()) {
if (stack != null) {
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);
}
}
}
}
ItemStack[] armor = event.getEntity().getInventory().getArmorContents();
for (int i = 0; i < armor.length; i++) {
ItemStack stack = armor[i];
if (stack != null) {
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;
}
}
}
}
event.getEntity().getInventory().setArmorContents(armor);
}
}
}
@@ -1,5 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.commands.Commandfireball;
import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.TextInput;
@@ -7,8 +8,10 @@ import com.earth2me.essentials.textreader.TextPager;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.LocationUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.VersionUtil;
import io.papermc.lib.PaperLib;
import net.ess3.api.IEssentials;
import net.ess3.api.events.AfkStatusChangeEvent;
import org.bukkit.*;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.HumanEntity;
@@ -29,6 +32,7 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.text.NumberFormat;
import java.util.*;
import java.util.Map.Entry;
@@ -47,9 +51,40 @@ public class EssentialsPlayerListener implements Listener {
this.ess = parent;
}
private static boolean isEntityPickupEvent() {
try {
Class.forName("org.bukkit.event.entity.EntityPickupItemEvent");
return true;
} catch (ClassNotFoundException ignored) {
return false;
}
}
private static boolean isCommandSendEvent() {
try {
Class.forName("org.bukkit.event.player.PlayerCommandSendEvent");
return true;
} catch (ClassNotFoundException ignored) {
return false;
}
}
private static boolean isArrowPickupEvent() {
try {
Class.forName("org.bukkit.event.player.PlayerPickupArrowEvent");
return true;
} catch (ClassNotFoundException ignored) {
return false;
}
}
public void registerEvents() {
ess.getServer().getPluginManager().registerEvents(this, ess);
if (isArrowPickupEvent()) {
ess.getServer().getPluginManager().registerEvents(new ArrowPickupListener(), ess);
}
if (isEntityPickupEvent()) {
ess.getServer().getPluginManager().registerEvents(new PickupListener1_12(), ess);
} else {
@@ -78,7 +113,12 @@ public class EssentialsPlayerListener implements Listener {
if (user.isMuted()) {
event.setCancelled(true);
user.sendMessage(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
user.sendMessage(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
} else {
user.sendMessage(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
}
LOGGER.info(tl("mutedUserSpeaks", user.getName(), event.getMessage()));
}
@@ -147,15 +187,16 @@ public class EssentialsPlayerListener implements Listener {
public void onPlayerQuit(final PlayerQuitEvent event) {
final User user = ess.getUser(event.getPlayer());
if (ess.getSettings().allowSilentJoinQuit() && user.isAuthorized("essentials.silentquit")) {
if (hideJoinQuitMessages() || (ess.getSettings().allowSilentJoinQuit() && user.isAuthorized("essentials.silentquit"))) {
event.setQuitMessage(null);
} else if (ess.getSettings().isCustomQuitMessage() && event.getQuitMessage() != null) {
final Player player = event.getPlayer();
final String msg = ess.getSettings().getCustomQuitMessage()
.replace("{PLAYER}", player.getDisplayName())
.replace("{USERNAME}", player.getName())
.replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size()));
.replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size()))
.replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()));
event.setQuitMessage(msg.isEmpty() ? null : msg);
}
@@ -180,7 +221,7 @@ public class EssentialsPlayerListener implements Listener {
}
}
user.updateActivity(false);
user.updateActivity(false, AfkStatusChangeEvent.Cause.QUIT);
if (!user.isHidden()) {
user.setLastLogout(System.currentTimeMillis());
}
@@ -192,17 +233,17 @@ public class EssentialsPlayerListener implements Listener {
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerJoin(final PlayerJoinEvent event) {
final String joinMessage = event.getJoinMessage();
ess.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
delayedJoin(event.getPlayer(), joinMessage);
}
});
if (ess.getSettings().allowSilentJoinQuit() || ess.getSettings().isCustomJoinMessage()) {
ess.runTaskAsynchronously(() -> delayedJoin(event.getPlayer(), joinMessage));
if (hideJoinQuitMessages() || ess.getSettings().allowSilentJoinQuit() || ess.getSettings().isCustomJoinMessage()) {
event.setJoinMessage(null);
}
}
private boolean hideJoinQuitMessages() {
return ess.getSettings().hasJoinQuitMessagePlayerCount() && ess.getServer().getOnlinePlayers().size() > ess.getSettings().getJoinQuitMessagePlayerCount();
}
public void delayedJoin(final Player player, final String message) {
if (!player.isOnline()) {
return;
@@ -218,7 +259,7 @@ public class EssentialsPlayerListener implements Listener {
final long currentTime = System.currentTimeMillis();
dUser.checkMuteTimeout(currentTime);
dUser.updateActivity(false);
dUser.updateActivity(false, AfkStatusChangeEvent.Cause.JOIN);
dUser.stopTransaction();
class DelayJoinTask implements Runnable {
@@ -257,13 +298,14 @@ public class EssentialsPlayerListener implements Listener {
if (user.isAuthorized("essentials.silentjoin.vanish")) {
user.setVanished(true);
}
} else if (message == null) {
} else if (message == null || hideJoinQuitMessages()) {
//NOOP
} else if (ess.getSettings().isCustomJoinMessage()) {
String msg = ess.getSettings().getCustomJoinMessage()
.replace("{PLAYER}", player.getDisplayName()).replace("{USERNAME}", player.getName())
.replace("{UNIQUE}", NumberFormat.getInstance().format(ess.getUserMap().getUniqueUsers()))
.replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size()));
.replace("{PLAYER}", player.getDisplayName()).replace("{USERNAME}", player.getName())
.replace("{UNIQUE}", NumberFormat.getInstance().format(ess.getUserMap().getUniqueUsers()))
.replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size()))
.replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()));
if (!msg.isEmpty()) {
ess.getServer().broadcastMessage(msg);
}
@@ -315,7 +357,7 @@ public class EssentialsPlayerListener implements Listener {
user.setGodModeEnabled(false);
ess.getLogger().log(Level.INFO, "Set god mode to false for {0} because they had it enabled without permission.", user.getName());
}
user.setConfirmingClearCommand(null);
user.getConfirmingPayments().clear();
@@ -323,7 +365,7 @@ public class EssentialsPlayerListener implements Listener {
}
class DelayMotdTask implements Runnable {
private User user;
private final User user;
public DelayMotdTask(User user) {
this.user = user;
@@ -366,11 +408,14 @@ public class EssentialsPlayerListener implements Listener {
Location loc = user.getHome(user.getLocation());
if (loc == null) {
loc = user.getBase().getBedSpawnLocation();
}
if (loc != null) {
user.getBase().setCompassTarget(loc);
PaperLib.getBedSpawnLocationAsync(user.getBase(), false).thenAccept(location -> {
if (location != null) {
user.getBase().setCompassTarget(location);
}
});
return;
}
user.getBase().setCompassTarget(loc);
}
@EventHandler(priority = EventPriority.LOW)
@@ -419,9 +464,13 @@ public class EssentialsPlayerListener implements Listener {
final boolean backListener = ess.getSettings().registerBackInListener();
final boolean teleportInvulnerability = ess.getSettings().isTeleportInvulnerability();
if (backListener || teleportInvulnerability) {
final User user = ess.getUser(event.getPlayer());
Player player = event.getPlayer();
if (player.hasMetadata("NPC")) {
return;
}
final User user = ess.getUser(player);
//There is TeleportCause.COMMMAND but plugins have to actively pass the cause in on their teleports.
if (backListener && (event.getCause() == TeleportCause.PLUGIN || event.getCause() == TeleportCause.COMMAND)) {
if (user.isAuthorized("essentials.back.onteleport") && backListener && (event.getCause() == TeleportCause.PLUGIN || event.getCause() == TeleportCause.COMMAND)) {
user.setLastLocation();
}
if (teleportInvulnerability && (event.getCause() == TeleportCause.PLUGIN || event.getCause() == TeleportCause.COMMAND)) {
@@ -445,12 +494,7 @@ public class EssentialsPlayerListener implements Listener {
final User user = ess.getUser(event.getPlayer());
if (user.hasUnlimited(new ItemStack(event.getBucket()))) {
event.getItemStack().setType(event.getBucket());
ess.scheduleSyncDelayedTask(new Runnable() {
@Override
public void run() {
user.getBase().updateInventory();
}
});
ess.scheduleSyncDelayedTask(user.getBase()::updateInventory);
}
}
@@ -479,13 +523,19 @@ public class EssentialsPlayerListener implements Listener {
}
}
if (ess.getUser(player).isMuted() && (ess.getSettings().getMuteCommands().contains(cmd) || ess.getSettings().getMuteCommands().contains("*"))) {
final User user = ess.getUser(player);
if (user.isMuted() && (ess.getSettings().getMuteCommands().contains(cmd) || ess.getSettings().getMuteCommands().contains("*"))) {
event.setCancelled(true);
player.sendMessage(tl("voiceSilenced"));
String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
player.sendMessage(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
} else {
player.sendMessage(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
}
LOGGER.info(tl("mutedUserSpeaks", player.getName(), event.getMessage()));
return;
}
boolean broadcast = true; // whether to broadcast the updated activity
boolean update = true; // Only modified when the command is afk
@@ -498,22 +548,22 @@ public class EssentialsPlayerListener implements Listener {
broadcast = false;
}
}
final User user = ess.getUser(player);
if (update) {
user.updateActivityOnInteract(broadcast);
}
if (ess.getSettings().isCommandCooldownsEnabled() && pluginCommand != null
&& !user.isAuthorized("essentials.commandcooldowns.bypass")) {
&& !user.isAuthorized("essentials.commandcooldowns.bypass")) {
int argStartIndex = event.getMessage().indexOf(" ");
String args = argStartIndex == -1 ? "" // No arguments present
: " " + event.getMessage().substring(argStartIndex); // arguments start at argStartIndex; substring from there.
String args = argStartIndex == -1 ? "" // No arguments present
: " " + event.getMessage().substring(argStartIndex); // arguments start at argStartIndex; substring from there.
String fullCommand = pluginCommand.getName() + args;
// Used to determine whether a user already has an existing cooldown
// If so, no need to check for (and write) new ones.
boolean cooldownFound = false;
// Iterate over a copy of getCommandCooldowns in case of concurrent modifications
for (Entry<Pattern, Long> entry : new HashMap<>(user.getCommandCooldowns()).entrySet()) {
// Remove any expired cooldowns
@@ -549,27 +599,31 @@ public class EssentialsPlayerListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL)
public void onPlayerChangedWorldFlyReset(final PlayerChangedWorldEvent event) {
final User user = ess.getUser(event.getPlayer());
if (user.getBase().getGameMode() != GameMode.CREATIVE
// COMPAT: String compare for 1.7.10
&& !user.getBase().getGameMode().name().equals("SPECTATOR")
&& !user.isAuthorized("essentials.fly")) {
user.getBase().setFallDistance(0f);
user.getBase().setAllowFlight(false);
}
if (!user.isAuthorized("essentials.speed")) {
user.getBase().setFlySpeed(0.1f);
user.getBase().setWalkSpeed(0.2f);
} else {
if (user.getBase().getFlySpeed() > ess.getSettings().getMaxFlySpeed() && !user.isAuthorized("essentials.speed.bypass")) {
user.getBase().setFlySpeed((float) ess.getSettings().getMaxFlySpeed());
} else {
user.getBase().setFlySpeed(user.getBase().getFlySpeed() * 0.99999f);
}
if (user.getBase().getWalkSpeed() > ess.getSettings().getMaxWalkSpeed() && !user.isAuthorized("essentials.speed.bypass")) {
user.getBase().setWalkSpeed((float) ess.getSettings().getMaxWalkSpeed());
if (ess.getSettings().isWorldChangeFlyResetEnabled()) {
if (user.getBase().getGameMode() != GameMode.CREATIVE
// COMPAT: String compare for 1.7.10
&& !user.getBase().getGameMode().name().equals("SPECTATOR")
&& !user.isAuthorized("essentials.fly")) {
user.getBase().setFallDistance(0f);
user.getBase().setAllowFlight(false);
}
}
if (ess.getSettings().isWorldChangeSpeedResetEnabled()) {
if (!user.isAuthorized("essentials.speed")) {
user.getBase().setFlySpeed(0.1f);
user.getBase().setWalkSpeed(0.2f);
} else {
user.getBase().setWalkSpeed(user.getBase().getWalkSpeed() * 0.99999f);
if (user.getBase().getFlySpeed() > ess.getSettings().getMaxFlySpeed() && !user.isAuthorized("essentials.speed.bypass")) {
user.getBase().setFlySpeed((float) ess.getSettings().getMaxFlySpeed());
} else {
user.getBase().setFlySpeed(user.getBase().getFlySpeed() * 0.99999f);
}
if (user.getBase().getWalkSpeed() > ess.getSettings().getMaxWalkSpeed() && !user.isAuthorized("essentials.speed.bypass")) {
user.getBase().setWalkSpeed((float) ess.getSettings().getMaxWalkSpeed());
}
}
}
}
@@ -604,7 +658,10 @@ public class EssentialsPlayerListener implements Listener {
User player = ess.getUser(event.getPlayer());
if (player.isAuthorized("essentials.sethome.bed") && player.getWorld().getEnvironment().equals(World.Environment.NORMAL)) {
player.getBase().setBedSpawnLocation(event.getClickedBlock().getLocation());
player.sendMessage(tl("bedSet", player.getLocation().getWorld().getName(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()));
// In 1.15 and above, vanilla sends its own bed spawn message.
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_15_R01)) {
player.sendMessage(tl("bedSet", player.getLocation().getWorld().getName(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()));
}
}
}
break;
@@ -627,6 +684,8 @@ public class EssentialsPlayerListener implements Listener {
case PHYSICAL:
updateActivity = false;
break;
default:
break;
}
if (updateActivity) {
@@ -668,7 +727,6 @@ public class EssentialsPlayerListener implements Listener {
// We need to loop through each command and execute
for (final String command : commandList) {
if (command.contains("{player}")) {
continue;
} else if (command.startsWith("c:")) {
used = true;
user.getBase().chat(command.substring(2));
@@ -705,7 +763,7 @@ public class EssentialsPlayerListener implements Listener {
if (type == InventoryType.PLAYER) {
final User user = ess.getUser((Player) event.getWhoClicked());
final InventoryHolder invHolder = top.getHolder();
if (invHolder != null && invHolder instanceof HumanEntity) {
if (invHolder instanceof HumanEntity) {
final User invOwner = ess.getUser((Player) invHolder);
if (user.isInvSee() && (!user.isAuthorized("essentials.invsee.modify") || invOwner.isAuthorized("essentials.invsee.preventmodify") || !invOwner.getBase().isOnline())) {
event.setCancelled(true);
@@ -727,15 +785,15 @@ public class EssentialsPlayerListener implements Listener {
} else if (type == InventoryType.CHEST && top.getSize() == 9) {
final User user = ess.getUser((Player) event.getWhoClicked());
final InventoryHolder invHolder = top.getHolder();
if (invHolder != null && invHolder instanceof HumanEntity && user.isInvSee()) {
if (invHolder instanceof HumanEntity && user.isInvSee()) {
event.setCancelled(true);
refreshPlayer = user.getBase();
}
} else if (clickedInventory != null && clickedInventory.getType() == InventoryType.PLAYER) {
if (ess.getSettings().isDirectHatAllowed() && event.getClick() == ClickType.LEFT && event.getSlot() == 39
&& event.getCursor().getType() != Material.AIR && event.getCursor().getType().getMaxDurability() == 0
&& !MaterialUtil.isSkull(event.getCursor().getType())
&& ess.getUser(event.getWhoClicked()).isAuthorized("essentials.hat")) {
&& event.getCursor().getType() != Material.AIR && event.getCursor().getType().getMaxDurability() == 0
&& !MaterialUtil.isSkull(event.getCursor().getType())
&& ess.getUser(event.getWhoClicked()).isAuthorized("essentials.hat") && !ess.getUser(event.getWhoClicked()).isAuthorized("essentials.hat.prevent-type." + event.getCursor().getType().name().toLowerCase())) {
event.setCancelled(true);
final PlayerInventory inv = (PlayerInventory) clickedInventory;
final ItemStack head = inv.getHelmet();
@@ -745,13 +803,7 @@ public class EssentialsPlayerListener implements Listener {
}
if (refreshPlayer != null) {
final Player player = refreshPlayer;
ess.scheduleSyncDelayedTask(new Runnable() {
@Override
public void run() {
player.updateInventory();
}
}, 1);
ess.scheduleSyncDelayedTask(refreshPlayer::updateInventory, 1);
}
}
@@ -777,7 +829,7 @@ public class EssentialsPlayerListener implements Listener {
}
} else if (type == InventoryType.CHEST && top.getSize() == 9) {
final InventoryHolder invHolder = top.getHolder();
if (invHolder != null && invHolder instanceof HumanEntity) {
if (invHolder instanceof HumanEntity) {
final User user = ess.getUser((Player) event.getPlayer());
user.setInvSee(false);
refreshPlayer = user.getBase();
@@ -785,44 +837,31 @@ public class EssentialsPlayerListener implements Listener {
}
if (refreshPlayer != null) {
final Player player = refreshPlayer;
ess.scheduleSyncDelayedTask(new Runnable() {
@Override
public void run() {
player.updateInventory();
}
}, 1);
ess.scheduleSyncDelayedTask(refreshPlayer::updateInventory, 1);
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerFishEvent(final PlayerFishEvent event) {
final User user = ess.getUser(event.getPlayer());
user.updateActivityOnInteract(true);
user.updateActivityOnInteract(true);
}
private static boolean isEntityPickupEvent() {
try {
Class.forName("org.bukkit.event.entity.EntityPickupItemEvent");
return true;
} catch (ClassNotFoundException ignored) {
return false;
}
}
private static boolean isCommandSendEvent() {
try {
Class.forName("org.bukkit.event.player.PlayerCommandSendEvent");
return true;
} catch (ClassNotFoundException ignored) {
return false;
private final class ArrowPickupListener implements Listener {
@EventHandler(priority = EventPriority.LOW)
public void onArrowPickup(final org.bukkit.event.player.PlayerPickupArrowEvent event) {
if (event.getItem().hasMetadata(Commandfireball.FIREBALL_META_KEY)) {
event.setCancelled(true);
}
}
}
private final class PickupListenerPre1_12 implements Listener {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerPickupItem(final org.bukkit.event.player.PlayerPickupItemEvent event) {
if (ess.getSettings().getDisableItemPickupWhileAfk()) {
if (event.getItem().hasMetadata(Commandfireball.FIREBALL_META_KEY)) {
event.setCancelled(true);
} else if (ess.getSettings().getDisableItemPickupWhileAfk()) {
if (ess.getUser(event.getPlayer()).isAfk()) {
event.setCancelled(true);
}
@@ -846,30 +885,40 @@ public class EssentialsPlayerListener implements Listener {
public void onCommandSend(final PlayerCommandSendEvent event) {
User user = ess.getUser(event.getPlayer());
ArrayList<String> removedCmds = new ArrayList<>(event.getCommands());
Set<PluginCommand> checked = new HashSet<>();
Set<PluginCommand> toRemove = new HashSet<>();
event.getCommands().removeIf(str -> shouldHideFromUser(str, user));
event.getCommands().removeIf(label -> {
if (isEssentialsCommand(label)) {
PluginCommand command = ess.getServer().getPluginCommand(label);
if (!checked.contains(command)) {
checked.add(command);
if (!user.isAuthorized(command.getName().equals("r") ? "essentials.msg" : "essentials." + command.getName())) {
toRemove.add(command);
}
}
return toRemove.contains(command);
}
return false;
});
if (ess.getSettings().isDebug()) {
removedCmds.removeAll(event.getCommands());
ess.getLogger().info("Removed commands: " + removedCmds.toString());
ess.getLogger().info("Removed commands: " + toRemove.toString());
}
}
/**
* Returns true if all of the following are true:
* - The command is a plugin command
* - The plugin command is from Essentials
* - There is no known alternative OR the alternative is overridden by Essentials
* - The user is not allowed to perform the given Essentials command
* - The command is a plugin command
* - The plugin command is from a plugin in an essentials-controlled package
* - There is no known alternative OR the alternative is overridden by Essentials
*/
private boolean shouldHideFromUser(String commandLabel, User user) {
PluginCommand command = ess.getServer().getPluginCommand(commandLabel);
private boolean isEssentialsCommand(String label) {
PluginCommand command = ess.getServer().getPluginCommand(label);
return command != null
&& command.getPlugin().getName().equals("Essentials")
&& (ess.getSettings().isCommandOverridden(commandLabel) || (ess.getAlternativeCommandsHandler().getAlternative(commandLabel) == null))
&& !user.isAuthorized("essentials." + command.getName());
&& (command.getPlugin() == ess || command.getPlugin().getClass().getName().startsWith("com.earth2me.essentials"))
&& (ess.getSettings().isCommandOverridden(label) || (ess.getAlternativeCommandsHandler().getAlternative(label) == null));
}
}
}
@@ -36,6 +36,7 @@ public class EssentialsPluginListener implements Listener, IConf {
if (event.getPlugin().getName().equals("EssentialsChat")) {
ess.getSettings().setEssentialsChatActive(false);
}
ess.getPermissionsHandler().checkPermissions();
ess.getAlternativeCommandsHandler().removePlugin(event.getPlugin());
// Check to see if the plugin thats being disabled is the one we are using
if (ess.getPaymentMethod() != null && Methods.hasMethod() && Methods.checkDisabled(event.getPlugin())) {
@@ -17,15 +17,16 @@ import java.util.logging.Level;
public class EssentialsServerListener implements Listener {
private static List<String> ignoredSLPECallers = Arrays.asList(
private static final List<String> ignoredSLPECallers = Arrays.asList(
".LegacyPingHandler.channelRead(", // CB responding to pings from pre-Netty clients
"de.dytanic.cloudnet.bridge.BukkitBootstrap" // CloudNet v2 doing... something
"de.dytanic.cloudnet.bridge.BukkitBootstrap", // CloudNet v2 doing... something
"de.dytanic.cloudnet.ext.bridge.bukkit.BukkitCloudNetBridgePlugin" // CloudNet v3 doing... something else
);
private final transient IEssentials ess;
private boolean unsupportedLogged = false;
private boolean npeWarned = false;
private boolean isPaperSample;
private final boolean isPaperSample;
private Method setSampleText;
private Method getSampleText;
@@ -42,6 +42,56 @@ public class EssentialsUpgrade {
doneFile.load();
}
public void convertIgnoreList() {
Pattern pattern = Pattern.compile("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$");
if (doneFile.getBoolean("updateUsersIgnoreListUUID", false)) {
return;
}
LOGGER.info("Attempting to migrate ignore list to UUIDs");
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
if (!userdataFolder.exists() || !userdataFolder.isDirectory()) {
return;
}
final File[] userFiles = userdataFolder.listFiles();
for (File file : userFiles) {
if (!file.isFile() || !file.getName().endsWith(".yml")) {
continue;
}
final EssentialsConf config = new EssentialsConf(file);
try {
config.load();
if (config.hasProperty("ignore")) {
List<String> migratedIgnores = new ArrayList<>();
for (String name : Collections.synchronizedList(config.getStringList("ignore"))) {
if (name == null) {
continue;
}
if (pattern.matcher(name.trim()).matches()) {
LOGGER.info("Detected already migrated ignore list!");
return;
}
User user = ess.getOfflineUser(name);
if (user != null && user.getBase() != null) {
migratedIgnores.add(user.getBase().getUniqueId().toString());
}
}
config.removeProperty("ignore");
config.setProperty("ignore", migratedIgnores);
config.forceSave();
}
} catch (RuntimeException ex) {
LOGGER.log(Level.INFO, "File: " + file.toString());
throw ex;
}
}
doneFile.setProperty("updateUsersIgnoreListUUID", true);
doneFile.save();
LOGGER.info("Done converting ignore list.");
}
public void convertKits() {
Kits kits = ess.getKits();
EssentialsConf config = kits.getConfig();
@@ -163,7 +213,7 @@ public class EssentialsUpgrade {
try {
config.load();
if (config.hasProperty("powertools")) {
@SuppressWarnings("unchecked") final Map<String, Object> powertools = config.getConfigurationSection("powertools").getValues(false);
final Map<String, Object> powertools = config.getConfigurationSection("powertools").getValues(false);
if (powertools == null) {
continue;
}
@@ -204,7 +254,7 @@ public class EssentialsUpgrade {
config.load();
if (config.hasProperty("home") && config.hasProperty("home.default")) {
@SuppressWarnings("unchecked") final String defworld = (String) config.getProperty("home.default");
final String defworld = (String) config.getProperty("home.default");
final Location defloc = getFakeLocation(config, "home.worlds." + defworld);
if (defloc != null) {
config.setProperty("homes.home", defloc);
@@ -575,7 +625,7 @@ public class EssentialsUpgrade {
conf.load();
String banReason;
Long banTimeout;
long banTimeout;
try {
banReason = conf.getConfigurationSection("ban").getString("reason");
@@ -616,12 +666,7 @@ public class EssentialsUpgrade {
}
}
private static final FileFilter YML_FILTER = new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isFile() && pathname.getName().endsWith(".yml");
}
};
private static final FileFilter YML_FILTER = pathname -> pathname.isFile() && pathname.getName().endsWith(".yml");
private static final String PATTERN_CONFIG_UUID_REGEX = "(?mi)^uuid:\\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\s*$";
private static final Pattern PATTERN_CONFIG_UUID = Pattern.compile(PATTERN_CONFIG_UUID_REGEX);
@@ -718,5 +763,6 @@ public class EssentialsUpgrade {
banFormatChange();
warnMetrics();
repairUserMap();
convertIgnoreList();
}
}
@@ -13,7 +13,7 @@ public class ExecuteTimer {
public ExecuteTimer() {
times = new ArrayList<ExecuteRecord>();
times = new ArrayList<>();
}
public void start() {
@@ -2,12 +2,11 @@ package com.earth2me.essentials;
import net.ess3.api.IEssentials;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.*;
import java.util.logging.Level;
@@ -23,7 +22,7 @@ public class I18n implements net.ess3.api.II18n {
private transient ResourceBundle customBundle;
private transient ResourceBundle localeBundle;
private final transient ResourceBundle defaultBundle;
private transient Map<String, MessageFormat> messageFormatCache = new HashMap<String, MessageFormat>();
private transient Map<String, MessageFormat> messageFormatCache = new HashMap<>();
private final transient IEssentials ess;
private static final Pattern NODOUBLEMARK = Pattern.compile("''");
private static final ResourceBundle NULL_BUNDLE = new ResourceBundle() {
@@ -38,7 +37,7 @@ public class I18n implements net.ess3.api.II18n {
public I18n(final IEssentials ess) {
this.ess = ess;
defaultBundle = ResourceBundle.getBundle(MESSAGES, Locale.ENGLISH);
defaultBundle = ResourceBundle.getBundle(MESSAGES, Locale.ENGLISH, new UTF8PropertiesControl());
localeBundle = defaultBundle;
customBundle = NULL_BUNDLE;
}
@@ -110,17 +109,17 @@ public class I18n implements net.ess3.api.II18n {
}
}
ResourceBundle.clearCache();
messageFormatCache = new HashMap<String, MessageFormat>();
messageFormatCache = new HashMap<>();
Logger.getLogger("Essentials").log(Level.INFO, String.format("Using locale %s", currentLocale.toString()));
try {
localeBundle = ResourceBundle.getBundle(MESSAGES, currentLocale);
localeBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new UTF8PropertiesControl());
} catch (MissingResourceException ex) {
localeBundle = NULL_BUNDLE;
}
try {
customBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new FileResClassLoader(I18n.class.getClassLoader(), ess));
customBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new FileResClassLoader(I18n.class.getClassLoader(), ess), new UTF8PropertiesControl());
} catch (MissingResourceException ex) {
customBundle = NULL_BUNDLE;
}
@@ -130,7 +129,9 @@ public class I18n implements net.ess3.api.II18n {
return input == null || input.length() == 0 ? input : input.toUpperCase(Locale.ENGLISH).charAt(0) + input.toLowerCase(Locale.ENGLISH).substring(1);
}
/**
* Attempts to load properties files from the plugin directory before falling back to the jar.
*/
private static class FileResClassLoader extends ClassLoader {
private final transient File dataFolder;
@@ -145,8 +146,7 @@ public class I18n implements net.ess3.api.II18n {
if (file.exists()) {
try {
return file.toURI().toURL();
} catch (MalformedURLException ex) {
}
} catch (MalformedURLException ignored) {}
}
return null;
}
@@ -157,10 +157,42 @@ public class I18n implements net.ess3.api.II18n {
if (file.exists()) {
try {
return new FileInputStream(file);
} catch (FileNotFoundException ex) {
}
} catch (FileNotFoundException ignored) {}
}
return null;
}
}
/**
* Reads .properties files as UTF-8 instead of ISO-8859-1, which is the default on Java 8/below.
* Java 9 fixes this by defaulting to UTF-8 for .properties files.
*/
private static class UTF8PropertiesControl extends ResourceBundle.Control {
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IOException {
String resourceName = toResourceName(toBundleName(baseName, locale), "properties");
ResourceBundle bundle = null;
InputStream stream = null;
if (reload) {
URL url = loader.getResource(resourceName);
if (url != null) {
URLConnection connection = url.openConnection();
if (connection != null) {
connection.setUseCaches(false);
stream = connection.getInputStream();
}
}
} else {
stream = loader.getResourceAsStream(resourceName);
}
if (stream != null) {
try {
// use UTF-8 here, this is the important bit
bundle = new PropertyResourceBundle(new InputStreamReader(stream, StandardCharsets.UTF_8));
} finally {
stream.close();
}
}
return bundle;
}
}
}
@@ -3,10 +3,10 @@ package com.earth2me.essentials;
import com.earth2me.essentials.api.IItemDb;
import com.earth2me.essentials.api.IJails;
import com.earth2me.essentials.api.IWarps;
import com.earth2me.essentials.metrics.Metrics;
import com.earth2me.essentials.perm.PermissionsHandler;
import com.earth2me.essentials.register.payment.Methods;
import net.ess3.nms.SpawnerProvider;
import net.ess3.provider.ServerStateProvider;
import net.ess3.provider.SpawnerProvider;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
@@ -18,6 +18,7 @@ import org.bukkit.scheduler.BukkitTask;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.function.Predicate;
public interface IEssentials extends Plugin {
void addReloadListener(IConf listener);
@@ -47,6 +48,8 @@ public interface IEssentials extends Plugin {
int broadcastMessage(IUser sender, String message);
int broadcastMessage(IUser sender, String message, Predicate<IUser> shouldExclude);
int broadcastMessage(String permission, String message);
ISettings getSettings();
@@ -63,6 +66,8 @@ public interface IEssentials extends Plugin {
Kits getKits();
RandomTeleport getRandomTeleport();
Methods getPaymentMethod();
BukkitTask runTaskAsynchronously(Runnable run);
@@ -89,10 +94,6 @@ public interface IEssentials extends Plugin {
UserMap getUserMap();
Metrics getMetrics();
void setMetrics(Metrics metrics);
EssentialsTimer getTimer();
@Deprecated
@@ -103,4 +104,6 @@ public interface IEssentials extends Plugin {
Iterable<User> getOnlineUsers();
SpawnerProvider getSpawnerProvider();
ServerStateProvider getServerStateProvider();
}
@@ -3,8 +3,6 @@ package com.earth2me.essentials;
import com.earth2me.essentials.commands.IEssentialsCommand;
import com.earth2me.essentials.signs.EssentialsSign;
import com.earth2me.essentials.textreader.IText;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.event.EventPriority;
@@ -15,6 +13,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Pattern;
@@ -31,6 +30,8 @@ public interface ISettings extends IConf {
long getBackupInterval();
boolean isAlwaysRunBackup();
String getChatFormat(String group);
int getChatRadius();
@@ -47,6 +48,8 @@ public interface ISettings extends IConf {
String getCurrencySymbol();
boolean isCurrencySymbolSuffixed();
int getOversizedStackSize();
int getDefaultStackSize();
@@ -88,7 +91,7 @@ public interface ISettings extends IConf {
String getNicknamePrefix();
ChatColor getOperatorColor() throws Exception;
String getOperatorColor() throws Exception;
boolean getPerWarpPermission();
@@ -118,6 +121,12 @@ public interface ISettings extends IConf {
boolean isForceDisableTeleportSafety();
boolean isAlwaysTeleportSafety();
boolean isTeleportPassengerDismount();
boolean isForcePassengerTeleport();
double getTeleportCooldown();
double getTeleportDelay();
@@ -159,6 +168,8 @@ public interface ISettings extends IConf {
boolean isEcoLogUpdateEnabled();
boolean realNamesOnList();
boolean removeGodOnDisconnect();
boolean changeDisplayName();
@@ -191,8 +202,24 @@ public interface ISettings extends IConf {
String getAfkListName();
boolean broadcastAfkMessage();
boolean areDeathMessagesEnabled();
KeepInvPolicy getVanishingItemsPolicy();
KeepInvPolicy getBindingItemsPolicy();
int getJoinQuitMessagePlayerCount();
boolean hasJoinQuitMessagePlayerCount();
enum KeepInvPolicy {
KEEP,
DELETE,
DROP
}
void setDebug(boolean debug);
Set<String> getNoGodWorlds();
@@ -237,6 +264,8 @@ public interface ISettings extends IConf {
void setEssentialsChatActive(boolean b);
long getMaxMute();
long getMaxTempban();
Map<String, Object> getListGroupConfig();
@@ -267,6 +296,8 @@ public interface ISettings extends IConf {
BigDecimal getMinimumPayAmount();
boolean isPayExcludesIgnoreList();
long getLastMessageReplyRecipientTimeout();
boolean isMilkBucketEasterEggEnabled();
@@ -285,6 +316,10 @@ public interface ISettings extends IConf {
boolean isCommandCooldownsEnabled();
boolean isWorldChangeFlyResetEnabled();
boolean isWorldChangeSpeedResetEnabled();
long getCommandCooldownMs(String label);
Entry<Pattern, Long> getCommandCooldownEntry(String label);
@@ -301,6 +336,8 @@ public interface ISettings extends IConf {
boolean isAllowBulkBuySell();
boolean isAllowSellNamedItems();
boolean isAddingPrefixInPlayerlist();
boolean isAddingSuffixInPlayerlist();
@@ -323,11 +360,24 @@ public interface ISettings extends IConf {
String getItemDbType();
boolean isForceEnableRecipe();
boolean allowOldIdSigns();
boolean isWaterSafe();
boolean isSafeUsermap();
boolean logCommandBlockCommands();
Set<Predicate<String>> getNickBlacklist();
double getMaxProjectileSpeed();
boolean isRemovingEffectsOnHeal();
boolean isSpawnIfNoHome();
boolean isConfirmHomeOverwrite();
boolean infoAfterDeath();
}
@@ -1,8 +1,10 @@
package com.earth2me.essentials;
import com.earth2me.essentials.api.IAsyncTeleport;
import com.earth2me.essentials.commands.IEssentialsCommand;
import net.ess3.api.ITeleport;
import net.ess3.api.MaxMoneyException;
import net.ess3.api.events.AfkStatusChangeEvent;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@@ -53,21 +55,30 @@ public interface IUser {
*/
boolean hasOutstandingTeleportRequest();
/**
* @deprecated This API is not asynchronous. Use {@link com.earth2me.essentials.api.IAsyncTeleport IAsyncTeleport} with {@link IUser#getAsyncTeleport()}
*/
@Deprecated
ITeleport getTeleport();
IAsyncTeleport getAsyncTeleport();
BigDecimal getMoney();
void setMoney(final BigDecimal value) throws MaxMoneyException;
@Deprecated
void setAfk(final boolean set);
void setAfk(final boolean set, final AfkStatusChangeEvent.Cause cause);
/**
* 'Hidden' Represents when a player is hidden from others. This status includes when the player is hidden via other
* supported plugins. Use isVanished() if you want to check if a user is vanished by Essentials.
*
* @return If the user is hidden or not
*
* @see isVanished
* @see IUser#isVanished()
*/
boolean isHidden();
@@ -96,7 +107,7 @@ public interface IUser {
*
* @return If the user is vanished or not
*
* @see isHidden
* @see IUser#isHidden()
*/
boolean isVanished();
@@ -16,15 +16,13 @@ import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.*;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.plugin.PluginManager;
import java.io.File;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -71,7 +69,7 @@ public class Jails extends AsyncStorageObjectHolder<com.earth2me.essentials.sett
}
private void checkRegister() {
if (enabled == false && getCount() > 0) {
if (!enabled && getCount() > 0) {
registerListeners();
}
}
@@ -100,7 +98,7 @@ public class Jails extends AsyncStorageObjectHolder<com.earth2me.essentials.sett
if (getData().getJails() == null) {
return Collections.emptyList();
}
return new ArrayList<String>(getData().getJails().keySet());
return new ArrayList<>(getData().getJails().keySet());
} finally {
unlock();
}
@@ -119,7 +117,11 @@ public class Jails extends AsyncStorageObjectHolder<com.earth2me.essentials.sett
}
}
/**
* @deprecated This method does not use asynchronous teleportation. Use {@link Jails#sendToJail(IUser, String, CompletableFuture)}
*/
@Override
@Deprecated
public void sendToJail(final IUser user, final String jail) throws Exception {
acquireReadLock();
try {
@@ -133,12 +135,30 @@ public class Jails extends AsyncStorageObjectHolder<com.earth2me.essentials.sett
}
}
@Override
public void sendToJail(IUser user, String jail, CompletableFuture<Boolean> future) throws Exception {
acquireReadLock();
try {
if (user.getBase().isOnline()) {
Location loc = getJail(jail);
user.getAsyncTeleport().now(loc, false, TeleportCause.COMMAND, future);
future.thenAccept(success -> {
user.setJail(jail);
});
return;
}
user.setJail(jail);
} finally {
unlock();
}
}
@Override
public void setJail(final String jailName, final Location loc) throws Exception {
acquireWriteLock();
try {
if (getData().getJails() == null) {
getData().setJails(new HashMap<String, Location>());
getData().setJails(new HashMap<>());
}
getData().getJails().put(jailName.toLowerCase(Locale.ENGLISH), loc);
} finally {
@@ -160,7 +180,7 @@ public class Jails extends AsyncStorageObjectHolder<com.earth2me.essentials.sett
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailBlockBreak(final BlockBreakEvent event) {
final User user = ess.getUser(event.getPlayer());
if (user.isJailed()) {
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-break")) {
event.setCancelled(true);
}
}
@@ -168,7 +188,7 @@ public class Jails extends AsyncStorageObjectHolder<com.earth2me.essentials.sett
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailBlockPlace(final BlockPlaceEvent event) {
final User user = ess.getUser(event.getPlayer());
if (user.isJailed()) {
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-place")) {
event.setCancelled(true);
}
}
@@ -176,7 +196,7 @@ public class Jails extends AsyncStorageObjectHolder<com.earth2me.essentials.sett
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailBlockDamage(final BlockDamageEvent event) {
final User user = ess.getUser(event.getPlayer());
if (user.isJailed()) {
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-block-damage")) {
event.setCancelled(true);
}
}
@@ -197,6 +217,14 @@ public class Jails extends AsyncStorageObjectHolder<com.earth2me.essentials.sett
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailPlayerInteract(final PlayerInteractEvent event) {
final User user = ess.getUser(event.getPlayer());
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-interact")) {
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailPlayerGameModeChange(PlayerGameModeChangeEvent event) {
final User user = ess.getUser(event.getPlayer());
if (user.isJailed()) {
event.setCancelled(true);
@@ -249,16 +277,22 @@ public class Jails extends AsyncStorageObjectHolder<com.earth2me.essentials.sett
return;
}
try {
sendToJail(user, user.getJail());
} catch (Exception ex) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
future.exceptionally(ex -> {
if (ess.getSettings().isDebug()) {
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()), ex);
} else {
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()));
}
return false;
});
future.thenAccept(success -> user.sendMessage(tl("jailMessage")));
try {
sendToJail(user, user.getJail(), future);
} catch (Exception ex) {
future.completeExceptionally(ex);
}
user.sendMessage(tl("jailMessage"));
}
}
}
+57 -16
View File
@@ -7,7 +7,10 @@ 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.NumberUtil;
import net.ess3.api.IEssentials;
import net.ess3.api.events.KitClaimEvent;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
@@ -50,7 +53,6 @@ public class Kit {
long nextUse = getNextUse(user);
if (nextUse == 0L) {
return;
} else if (nextUse < 0L) {
user.sendMessage(tl("kitOnce"));
throw new NoChargeException();
@@ -122,7 +124,7 @@ public class Kit {
throw new Exception(tl("kitNotFound"));
}
try {
final List<String> itemList = new ArrayList<String>();
final List<String> itemList = new ArrayList<>();
final Object kitItems = kit.get("items");
if (kitItems instanceof List) {
for (Object item : (List) kitItems) {
@@ -141,22 +143,30 @@ public class Kit {
}
}
public void expandItems(final User user) throws Exception {
expandItems(user, getItems(user));
public boolean expandItems(final User user) throws Exception {
return expandItems(user, getItems(user));
}
public void expandItems(final User user, final List<String> items) throws Exception {
public boolean expandItems(final User user, final List<String> items) throws Exception {
try {
IText input = new SimpleTextInput(items);
IText output = new KeywordReplacer(input, user.getSource(), ess, true, true);
KitClaimEvent event = new KitClaimEvent(user, this);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return false;
}
boolean spew = false;
final boolean allowUnsafe = ess.getSettings().allowUnsafeEnchantments();
final boolean currencyIsSuffix = ess.getSettings().isCurrencySymbolSuffixed();
List<ItemStack> itemList = new ArrayList<>();
List<String> commandQueue = new ArrayList<>();
List<String> moneyQueue = new ArrayList<>();
for (String kitItem : output.getLines()) {
if (kitItem.startsWith(ess.getSettings().getCurrencySymbol())) {
BigDecimal value = new BigDecimal(kitItem.substring(ess.getSettings().getCurrencySymbol().length()).trim());
Trade t = new Trade(value, ess);
t.pay(user, OverflowType.DROP);
if (!currencyIsSuffix ? kitItem.startsWith(ess.getSettings().getCurrencySymbol()) : kitItem.endsWith(ess.getSettings().getCurrencySymbol())) {
moneyQueue.add(NumberUtil.sanitizeCurrencyString(kitItem, ess));
continue;
}
@@ -164,7 +174,7 @@ public class Kit {
String command = kitItem.substring(1);
String name = user.getName();
command = command.replace("{player}", name);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
commandQueue.add(command);
continue;
}
@@ -181,18 +191,24 @@ public class Kit {
// We pass a null sender here because kits should not do perm checks
metaStack.parseStringMeta(null, allowUnsafe, parts, 2, ess);
}
final Map<Integer, ItemStack> overfilled;
final boolean allowOversizedStacks = user.isAuthorized("essentials.oversizedstacks");
itemList.add(metaStack.getItemStack());
}
final Map<Integer, ItemStack> overfilled;
final boolean allowOversizedStacks = user.isAuthorized("essentials.oversizedstacks");
final boolean isDropItemsIfFull = ess.getSettings().isDropItemsIfFull();
if (isDropItemsIfFull) {
if (allowOversizedStacks) {
overfilled = InventoryWorkaround.addOversizedItems(user.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), metaStack.getItemStack());
overfilled = InventoryWorkaround.addOversizedItems(user.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), itemList.toArray(new ItemStack[0]));
} else {
overfilled = InventoryWorkaround.addItems(user.getBase().getInventory(), metaStack.getItemStack());
overfilled = InventoryWorkaround.addItems(user.getBase().getInventory(), itemList.toArray(new ItemStack[0]));
}
for (ItemStack itemStack : overfilled.values()) {
int spillAmount = itemStack.getAmount();
if (!allowOversizedStacks) {
itemStack.setAmount(spillAmount < itemStack.getMaxStackSize() ? spillAmount : itemStack.getMaxStackSize());
itemStack.setAmount(Math.min(spillAmount, itemStack.getMaxStackSize()));
}
while (spillAmount > 0) {
user.getWorld().dropItemNaturally(user.getLocation(), itemStack);
@@ -200,8 +216,32 @@ public class Kit {
}
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;
}
}
user.getBase().updateInventory();
// Process money & command queues
// Done after all items have been processed so commands are not run and money is not given if
// an error occurs during the item giving process
for (String valueString : moneyQueue) {
BigDecimal value = new BigDecimal(valueString.trim());
Trade t = new Trade(value, ess);
t.pay(user, OverflowType.DROP);
}
for (String cmd : commandQueue) {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd);
}
if (spew) {
user.sendMessage(tl("kitInvFull"));
}
@@ -210,5 +250,6 @@ public class Kit {
ess.getLogger().log(Level.WARNING, e.getMessage());
throw new Exception(tl("kitError2"), e);
}
return true;
}
}
@@ -64,13 +64,27 @@ public class Kits implements IConf {
// you just found if you don't toLowercase it.
if (kits.isConfigurationSection(name.toLowerCase())) {
return kits.getConfigurationSection(name.toLowerCase()).getValues(true);
} else {
}
}
return null;
}
// Tries to find an existing kit name that matches the given name, ignoring case. Returns null if no match.
public String matchKit(String name) {
if (config.isConfigurationSection("kits")) {
final ConfigurationSection section = config.getConfigurationSection("kits");
if (section != null) {
for (String kitName : section.getKeys(false)) {
if (kitName.equalsIgnoreCase(name)) {
return kitName;
}
}
}
}
return null;
}
public void addKit(String name, List<String> lines, long delay) {
// Will overwrite but w/e
config.set("kits." + name + ".delay", delay);
@@ -79,6 +93,12 @@ public class Kits implements IConf {
config.save();
}
public void removeKit(String name) {
config.set("kits." + name, null);
kits = _getKits();
config.save();
}
public String listKits(final net.ess3.api.IEssentials ess, final User user) throws Exception {
try {
final ConfigurationSection kits = config.getConfigurationSection("kits");
@@ -38,19 +38,16 @@ public class ManagedFile {
try {
copyResourceAscii("/" + filename, file);
} catch (IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, tl("itemsCsvNotLoaded"), ex);
Bukkit.getLogger().log(Level.SEVERE, tl("itemsCsvNotLoaded", filename), ex);
}
}
}
public static void copyResourceAscii(final String resourceName, final File file) throws IOException {
final InputStreamReader reader = new InputStreamReader(ManagedFile.class.getResourceAsStream(resourceName));
try {
try (InputStreamReader reader = new InputStreamReader(ManagedFile.class.getResourceAsStream(resourceName))) {
final MessageDigest digest = getDigest();
final DigestOutputStream digestStream = new DigestOutputStream(new FileOutputStream(file), digest);
try {
final OutputStreamWriter writer = new OutputStreamWriter(digestStream);
try {
try (DigestOutputStream digestStream = new DigestOutputStream(new FileOutputStream(file), digest)) {
try (OutputStreamWriter writer = new OutputStreamWriter(digestStream)) {
final char[] buffer = new char[BUFFERSIZE];
do {
final int length = reader.read(buffer);
@@ -66,14 +63,8 @@ public class ManagedFile {
digestStream.on(false);
digestStream.write('#');
digestStream.write(hashInt.toString(16).getBytes());
} finally {
writer.close();
}
} finally {
digestStream.close();
}
} finally {
reader.close();
}
}
@@ -81,8 +72,7 @@ public class ManagedFile {
if (file.length() < 33) {
return false;
}
final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
try {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
final byte[] buffer = new byte[(int) file.length()];
int position = 0;
do {
@@ -96,8 +86,7 @@ public class ManagedFile {
if (bais.skip(file.length() - 33) != file.length() - 33) {
return false;
}
final BufferedReader reader = new BufferedReader(new InputStreamReader(bais));
try {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(bais))) {
String hash = reader.readLine();
if (hash != null && hash.matches("#[a-f0-9]{32}")) {
hash = hash.substring(1);
@@ -108,8 +97,7 @@ public class ManagedFile {
if (!versioncheck.equalsIgnoreCase(version)) {
bais.reset();
final MessageDigest digest = getDigest();
final DigestInputStream digestStream = new DigestInputStream(bais, digest);
try {
try (DigestInputStream digestStream = new DigestInputStream(bais, digest)) {
final byte[] bytes = new byte[(int) file.length() - 33];
digestStream.read(bytes);
final BigInteger correct = new BigInteger(hash, 16);
@@ -119,17 +107,11 @@ public class ManagedFile {
} else {
Bukkit.getLogger().warning("File " + file.toString() + " has been modified by user and file version differs, please update the file manually.");
}
} finally {
digestStream.close();
}
}
}
}
} finally {
reader.close();
}
} finally {
bis.close();
}
return false;
}
@@ -144,9 +126,8 @@ public class ManagedFile {
public List<String> getLines() {
try {
final BufferedReader reader = new BufferedReader(new FileReader(file));
try {
final List<String> lines = new ArrayList<String>();
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
final List<String> lines = new ArrayList<>();
do {
final String line = reader.readLine();
if (line == null) {
@@ -156,8 +137,6 @@ public class ManagedFile {
}
} while (true);
return lines;
} finally {
reader.close();
}
} catch (IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
@@ -10,8 +10,6 @@ import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.base.Joiner;
import net.ess3.api.IEssentials;
import net.ess3.nms.refl.ReflUtil;
import org.apache.commons.lang.ArrayUtils;
import org.bukkit.Color;
import org.bukkit.DyeColor;
import org.bukkit.FireworkEffect;
@@ -103,16 +101,11 @@ public class MetaItemStack {
try {
ess.getServer().getUnsafe().modifyItemStack(stack.clone(), "{}");
return true;
} catch (NullPointerException npe) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "Itemstack is invalid", npe);
}
return false;
} catch (NoSuchMethodError nsme) {
return true;
} catch (Throwable throwable) {
} catch (Throwable npe) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "Itemstack is invalid", throwable);
ess.getLogger().log(Level.INFO, "Itemstack is invalid", npe);
}
return false;
}
@@ -164,22 +157,20 @@ public class MetaItemStack {
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<String>();
for (String line : split[1].split("\\|")) {
lore.add(FormatUtil.replaceFormat(line.replace('_', ' ')));
final List<String> lore = new ArrayList<>();
for (String line : split[1].split("(?<!\\\\)\\|")) {
lore.add(FormatUtil.replaceFormat(line.replace('_', ' ').replace("\\|", "|")));
}
final ItemMeta meta = stack.getItemMeta();
meta.setLore(lore);
stack.setItemMeta(meta);
} else if (split[0].equalsIgnoreCase("unbreakable") && hasMetaPermission(sender, "unbreakable", false, true, ess)) {
boolean value = split.length > 1 ? Boolean.valueOf(split[1]) : true;
boolean value = split.length <= 1 || Boolean.parseBoolean(split[1]);
setUnbreakable(stack, value);
} else if (split.length > 1 && (split[0].equalsIgnoreCase("player") || split[0].equalsIgnoreCase("owner")) && hasMetaPermission(sender, "head", false, true, ess)) {
if (MaterialUtil.isPlayerHead(stack.getType(), stack.getDurability())) {
final String owner = split[1];
final SkullMeta meta = (SkullMeta) stack.getItemMeta();
meta.setOwningPlayer(ess.getServer().getOfflinePlayer(owner));
stack.setItemMeta(meta);
setSkullOwner(ess, stack, owner);
} else {
throw new Exception(tl("onlyPlayerSkulls"));
}
@@ -297,7 +288,7 @@ public class MetaItemStack {
builder = FireworkEffect.builder();
}
List<Color> primaryColors = new ArrayList<Color>();
List<Color> primaryColors = new ArrayList<>();
String[] colors = split[1].split(",");
for (String color : colors) {
if (colorMap.containsKey(color.toUpperCase())) {
@@ -320,7 +311,7 @@ public class MetaItemStack {
builder.with(finalEffect);
}
} else if (split[0].equalsIgnoreCase("fade") || (allowShortName && split[0].equalsIgnoreCase("f"))) {
List<Color> fadeColors = new ArrayList<Color>();
List<Color> fadeColors = new ArrayList<>();
String[] colors = split[1].split(",");
for (String color : colors) {
if (colorMap.containsKey(color.toUpperCase())) {
@@ -384,7 +375,7 @@ public class MetaItemStack {
throw new Exception(tl("invalidPotionMeta", split[1]));
}
} else if (split[0].equalsIgnoreCase("splash") || (allowShortName && split[0].equalsIgnoreCase("s"))) {
isSplashPotion = Boolean.valueOf(split[1]);
isSplashPotion = Boolean.parseBoolean(split[1]);
}
if (isValidPotion()) {
@@ -491,11 +482,11 @@ public class MetaItemStack {
final BannerMeta meta = (BannerMeta) stack.getItemMeta();
if (split[0].equalsIgnoreCase("basecolor")) {
Color color = Color.fromRGB(Integer.valueOf(split[1]));
Color color = Color.fromRGB(Integer.parseInt(split[1]));
meta.setBaseColor(DyeColor.getByColor(color));
} else if (patternType != null) {
PatternType type = PatternType.valueOf(split[0]);
DyeColor color = DyeColor.getByColor(Color.fromRGB(Integer.valueOf(split[1])));
DyeColor color = DyeColor.getByColor(Color.fromRGB(Integer.parseInt(split[1])));
org.bukkit.block.banner.Pattern pattern = new org.bukkit.block.banner.Pattern(color, type);
meta.addPattern(pattern);
}
@@ -517,11 +508,11 @@ public class MetaItemStack {
BlockStateMeta meta = (BlockStateMeta) stack.getItemMeta();
Banner banner = (Banner) meta.getBlockState();
if (split[0].equalsIgnoreCase("basecolor")) {
Color color = Color.fromRGB(Integer.valueOf(split[1]));
Color color = Color.fromRGB(Integer.parseInt(split[1]));
banner.setBaseColor(DyeColor.getByColor(color));
} else if (patternType != null) {
PatternType type = PatternType.valueOf(split[0]);
DyeColor color = DyeColor.getByColor(Color.fromRGB(Integer.valueOf(split[1])));
DyeColor color = DyeColor.getByColor(Color.fromRGB(Integer.parseInt(split[1])));
org.bukkit.block.banner.Pattern pattern = new org.bukkit.block.banner.Pattern(color, type);
banner.addPattern(pattern);
}
@@ -584,4 +575,24 @@ public class MetaItemStack {
t.printStackTrace();
}
}
private static boolean useNewSkullMethod = true;
private static void setSkullOwner(final IEssentials ess, final ItemStack stack, final String owner) {
if (!(stack.getItemMeta() instanceof SkullMeta)) return;
SkullMeta meta = (SkullMeta) stack.getItemMeta();
if (useNewSkullMethod) {
try {
meta.setOwningPlayer(ess.getServer().getOfflinePlayer(owner));
stack.setItemMeta(meta);
return;
} catch (NoSuchMethodError e) {
useNewSkullMethod = false;
}
}
meta.setOwner(owner);
stack.setItemMeta(meta);
}
}
@@ -23,7 +23,8 @@ public enum Mob {
GIANT("Giant", Enemies.ENEMY, EntityType.GIANT),
HORSE("Horse", Enemies.FRIENDLY, EntityType.HORSE),
PIG("Pig", Enemies.FRIENDLY, EntityType.PIG),
PIGZOMB("PigZombie", Enemies.NEUTRAL, EntityType.PIG_ZOMBIE),
PIGZOMB("PigZombie", Enemies.NEUTRAL, MobCompat.ZOMBIFIED_PIGLIN),
ZOMBIFIED_PIGLIN("ZombifiedPiglin", Enemies.NEUTRAL, MobCompat.ZOMBIFIED_PIGLIN),
SHEEP("Sheep", Enemies.FRIENDLY, "", EntityType.SHEEP),
SKELETON("Skeleton", Enemies.ENEMY, EntityType.SKELETON),
SLIME("Slime", Enemies.ENEMY, EntityType.SLIME),
@@ -89,7 +90,13 @@ public enum Mob {
PILLAGER("Pillager", Enemies.ENEMY, "PILLAGER"),
RAVAGER("Ravager", Enemies.ENEMY, "RAVAGER"),
TRADER_LLAMA("TraderLlama", Enemies.FRIENDLY, "TRADER_LLAMA"),
WANDERING_TRADER("WanderingTrader", Enemies.FRIENDLY, "WANDERING_TRADER")
WANDERING_TRADER("WanderingTrader", Enemies.FRIENDLY, "WANDERING_TRADER"),
BEE("Bee", Enemies.NEUTRAL, "BEE"),
STRAY("Stray", Enemies.ENEMY, "STRAY"),
HOGLIN("Hoglin", Enemies.ADULT_ENEMY, "HOGLIN"),
PIGLIN("Piglin", Enemies.ADULT_ENEMY, "PIGLIN"),
STRIDER("Strider", Enemies.FRIENDLY, "STRIDER"),
ZOGLIN("Zoglin", Enemies.ENEMY, "ZOGLIN"),
;
public static final Logger logger = Logger.getLogger("Essentials");
@@ -153,7 +160,8 @@ public enum Mob {
public enum Enemies {
FRIENDLY("friendly"),
NEUTRAL("neutral"),
ENEMY("enemy");
ENEMY("enemy"),
ADULT_ENEMY("adult_enemy");
Enemies(final String type) {
this.type = type;
@@ -1,28 +1,42 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.nms.refl.ReflUtil;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Fox;
import org.bukkit.entity.Llama;
import org.bukkit.entity.MushroomCow;
import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Panda;
import org.bukkit.entity.Parrot;
import org.bukkit.entity.TropicalFish;
import org.bukkit.entity.Villager;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static com.earth2me.essentials.utils.EnumUtil.getEntityType;
public class MobCompat {
// Constants for mob interfaces added in later versions
public static final Class RAIDER = ReflUtil.getClassCached("org.bukkit.entity.Raider");
// Constants for mobs added in later versions
public static final EntityType LLAMA = getEntityType("LLAMA");
public static final EntityType PARROT = getEntityType("PARROT");
public static final EntityType TROPICAL_FISH = getEntityType("TROPICAL_FISH");
public static final EntityType PANDA = getEntityType("PANDA");
public static final EntityType TRADER_LLAMA = getEntityType("TRADER_LLAMA");
public static final EntityType SHULKER = getEntityType("SHULKER");
public static final EntityType STRAY = getEntityType("STRAY");
public static final EntityType FOX = getEntityType("FOX");
public static final EntityType PHANTOM = getEntityType("PHANTOM");
// Constants for mobs that have changed since earlier versions
public static final EntityType CAT = getEntityType("CAT", "OCELOT");
public static final EntityType ZOMBIFIED_PIGLIN = getEntityType("ZOMBIFIED_PIGLIN", "PIG_ZOMBIE");
public enum CatType {
// These are (loosely) Mojang names for the cats
@@ -64,12 +78,12 @@ public class MobCompat {
NITWIT("NITWIT", "NITWIT"),
SHEPHERD("FARMER", "SHEPHERD"),
TOOLSMITH("BLACKSMITH", "TOOL_SMITH", "TOOLSMITH"),
WEAPONSMITH("BLACKSMITH", "WEAPON_SMITH", "WEAPONSMITH")
WEAPONSMITH("BLACKSMITH", "WEAPON_SMITH", "WEAPONSMITH"),
;
private String oldProfession;
private String oldCareer;
private String newProfession;
private final String oldProfession;
private final String oldCareer;
private final String newProfession;
VillagerProfession(final String oldProfession, final String career) {
this.oldProfession = oldProfession;
@@ -89,41 +103,33 @@ public class MobCompat {
}
// Older cats are Ocelots, whereas 1.14+ cats are Cats
private static Class catClass = ReflUtil.getClassCached("org.bukkit.entity.Cat");
private static Class catTypeClass = ReflUtil.getClassCached("org.bukkit.entity.Cat.Type");
private static Method catSetTypeMethod = (catClass == null || catTypeClass == null) ? null : ReflUtil.getMethodCached(catClass, "setCatType", catTypeClass);
private static boolean isNewCat() {
return (catClass != null && catTypeClass != null && catSetTypeMethod != null);
}
public static void setCatType(final Entity entity, final CatType type) {
if (isNewCat()) {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_R01)) {
((Ocelot) entity).setCatType(Ocelot.Type.valueOf(type.ocelotTypeName));
} else {
Class cat = ReflUtil.getClassCached("org.bukkit.entity.Cat");
Class catType = ReflUtil.getClassCached("org.bukkit.entity.Cat$Type");
Method setCatType = ReflUtil.getMethodCached(cat, "setCatType", catType);
try {
catSetTypeMethod.invoke(entity, EnumUtil.valueOf(catTypeClass, type.catTypeName));
} catch (IllegalAccessException | InvocationTargetException e) {
setCatType.invoke(entity, EnumUtil.valueOf(catType, type.catTypeName));
} catch (Exception e) {
e.printStackTrace();
}
} else {
((Ocelot) entity).setCatType(Ocelot.Type.valueOf(type.ocelotTypeName));
}
}
// Older villagers have professions and careers, 1.14+ villagers only have professions
private static Class villagerCareerClass = ReflUtil.getClassCached("org.bukkit.entity.Villager.Career");
private static Method villagerSetCareerMethod = (villagerCareerClass == null) ? null : ReflUtil.getMethodCached(Villager.class, "setCareer", villagerCareerClass);
private static boolean isCareerVillager() {
return (villagerCareerClass != null && villagerSetCareerMethod != null);
}
public static void setVillagerProfession(final Entity entity, final VillagerProfession profession) {
if (!isCareerVillager()) {
((Villager) entity).setProfession(profession.asEnum());
} else {
((Villager) entity).setProfession(profession.asEnum());
if (!(entity instanceof Villager)) {
return;
}
Villager villager = (Villager) entity;
villager.setProfession(profession.asEnum());
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_R01)) {
Class villagerCareer = ReflUtil.getClassCached("org.bukkit.entity.Villager$Career");
Method setCareer = ReflUtil.getMethodCached(Villager.class, "setCareer", villagerCareer);
try {
villagerSetCareerMethod.invoke(entity, EnumUtil.valueOf(villagerCareerClass, profession.oldCareer));
setCareer.invoke(entity, EnumUtil.valueOf(villagerCareer, profession.oldCareer));
} catch (Exception e) {
e.printStackTrace();
}
@@ -132,92 +138,77 @@ public class MobCompat {
// Only 1.14+ villagers have biome variants
public static void setVillagerType(final Entity entity, final String type) {
Class typeEnum = ReflUtil.getClassCached("org.bukkit.entity.Villager.Type");
if (typeEnum == null) return;
Method villagerSetTypeMethod = ReflUtil.getMethodCached(Villager.class, "setVillagerType", typeEnum);
try {
villagerSetTypeMethod.invoke(entity, EnumUtil.valueOf(typeEnum, type));
} catch (Exception e) {
e.printStackTrace();
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_R01)) {
return;
}
if (entity instanceof Villager) {
((Villager) entity).setVillagerType(Villager.Type.valueOf(type));
}
}
// Llamas only exist in 1.11+
public static void setLlamaColor(final Entity entity, final String color) {
Class llamaClass = ReflUtil.getClassCached("org.bukkit.entity.Llama");
if (llamaClass == null) return;
Class colorEnum = ReflUtil.getClassCached("org.bukkit.entity.Llama.Color");
Method setVariantMethod = ReflUtil.getMethodCached(llamaClass, "setColor");
try {
setVariantMethod.invoke(entity, EnumUtil.valueOf(colorEnum, color));
} catch (Exception e) {
e.printStackTrace();
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_11_R01)) {
return;
}
if (entity instanceof Llama) {
((Llama) entity).setColor(Llama.Color.valueOf(color));
}
}
// Parrots only exist in 1.12+
public static void setParrotVariant(final Entity entity, final String variant) {
Class parrotClass = ReflUtil.getClassCached("org.bukkit.entity.Parrot");
if (parrotClass == null) return;
Class variantEnum = ReflUtil.getClassCached("org.bukkit.entity.Parrot.Variant");
Method setVariantMethod = ReflUtil.getMethodCached(parrotClass, "setVariant");
try {
setVariantMethod.invoke(entity, EnumUtil.valueOf(variantEnum, variant));
} catch (Exception e) {
e.printStackTrace();
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_12_0_R01)) {
return;
}
if (entity instanceof Parrot) {
((Parrot) entity).setVariant(Parrot.Variant.valueOf(variant));
}
}
// Tropical fish only exist in 1.13+
public static void setTropicalFishPattern(final Entity entity, final String pattern) {
Class tropicalFishClass = ReflUtil.getClassCached("org.bukkit.entity.TropicalFish");
if (tropicalFishClass == null) return;
Class patternEnum = ReflUtil.getClassCached("org.bukkit.entity.TropicalFish.Pattern");
Method setPatternMethod = ReflUtil.getMethodCached(tropicalFishClass, "setPattern");
try {
setPatternMethod.invoke(entity, EnumUtil.valueOf(patternEnum, pattern));
} catch (Exception e) {
e.printStackTrace();
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_12_0_R01)) {
return;
}
if (entity instanceof TropicalFish) {
((TropicalFish) entity).setPattern(TropicalFish.Pattern.valueOf(pattern));
}
}
// Mushroom cow variant API only exists in 1.14+
public static void setMooshroomVariant(final Entity entity, final String variant) {
Class mushroomCowClass = ReflUtil.getClassCached("org.bukkit.entity.MushroomCow");
Class variantEnum = ReflUtil.getClassCached("org.bukkit.entity.MushroomCow.Variant");
if (mushroomCowClass == null || variantEnum == null) return;
Method setVariantMethod = ReflUtil.getMethodCached(mushroomCowClass, "setVariant");
try {
setVariantMethod.invoke(entity, EnumUtil.valueOf(variantEnum, variant));
} catch (Exception e) {
e.printStackTrace();
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_R01)) {
return;
}
if (entity instanceof MushroomCow) {
((MushroomCow) entity).setVariant(MushroomCow.Variant.valueOf(variant));
}
}
// Pandas only exists in 1.14+
public static void setPandaGene(final Entity entity, final String gene, final boolean mainGene) {
Class pandaClass = ReflUtil.getClassCached("org.bukkit.entity.Panda");
if (pandaClass == null) return;
Class geneEnum = ReflUtil.getClassCached("org.bukkit.entity.Panda.Gene");
Method setGeneMethod;
if (mainGene) {
setGeneMethod = ReflUtil.getMethodCached(pandaClass, "setMainGene");
} else {
setGeneMethod = ReflUtil.getMethodCached(pandaClass, "setHiddenGene");
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_R01)) {
return;
}
if (entity instanceof Panda) {
Panda panda = (Panda) entity;
Panda.Gene pandaGene = Panda.Gene.valueOf(gene);
if (mainGene) {
panda.setMainGene(pandaGene);
} else {
panda.setHiddenGene(pandaGene);
}
}
}
try {
setGeneMethod.invoke(entity, EnumUtil.valueOf(geneEnum, gene));
} catch (Exception e) {
e.printStackTrace();
// Foxes only exist in 1.14+
public static void setFoxType(final Entity entity, final String type) {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_R01)) {
return;
}
if (entity instanceof Fox) {
((Fox) entity).setFoxType(Fox.Type.valueOf(type));
}
}
@@ -12,6 +12,7 @@ import org.bukkit.material.Colorable;
import java.util.*;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import static com.earth2me.essentials.I18n.tl;
@@ -32,7 +33,7 @@ public enum MobData {
TAMED_TAMEABLE("tamed", Tameable.class, Data.TAMED, true),
TAME_TAMEABLE("tame", Tameable.class, Data.TAMED, false),
RANDOM_SHEEP("random", EntityType.SHEEP, Data.COLORABLE, true),
COLORABLE_SHEEP("", StringUtil.joinList(DyeColor.values()).toLowerCase(Locale.ENGLISH), EntityType.SHEEP, Data.COLORABLE, true),
COLORABLE_SHEEP("", Arrays.stream(DyeColor.values()).map(color -> color.name().toLowerCase(Locale.ENGLISH)).collect(Collectors.toList()), EntityType.SHEEP, Data.COLORABLE, true),
POLKA_HORSE("polka", EntityType.HORSE, Horse.Style.BLACK_DOTS, true),
SOOTY_HORSE("sooty", EntityType.HORSE, Horse.Style.BLACK_DOTS, false),
BLAZE_HORSE("blaze", EntityType.HORSE, Horse.Style.WHITE, true),
@@ -113,8 +114,8 @@ public enum MobData {
SNOWY_VILLAGER("snowy", EntityType.VILLAGER, "villagertype:SNOWY", true),
SWAMP_VILLAGER("swamp", EntityType.VILLAGER, "villagertype:SWAMP", true),
TAIGA_VILLAGER("taiga", EntityType.VILLAGER, "villagertype:TAIGA", true),
SIZE_SLIME("", "<1-100>", EntityType.SLIME.getEntityClass(), Data.SIZE, true),
NUM_EXPERIENCE_ORB("", "<1-2000000000>", EntityType.EXPERIENCE_ORB, Data.EXP, true),
SIZE_SLIME("", Collections.singletonList("<1-100>"), EntityType.SLIME.getEntityClass(), Data.SIZE, true),
NUM_EXPERIENCE_ORB("", Collections.singletonList("<1-2000000000>"), EntityType.EXPERIENCE_ORB, Data.EXP, true),
RED_PARROT("red", MobCompat.PARROT, "parrot:RED", true),
GREEN_PARROT("green", MobCompat.PARROT, "parrot:GREEN", true),
BLUE_PARROT("blue", MobCompat.PARROT, "parrot:BLUE", true),
@@ -153,7 +154,15 @@ public enum MobData {
CREAMY_TRADER_LLAMA("creamy", MobCompat.TRADER_LLAMA, "llama:CREAMY", true),
WHITE_TRADER_LLAMA("white", MobCompat.TRADER_LLAMA, "llama:WHITE", true),
BROWN_TRADER_LLAMA("brown", MobCompat.TRADER_LLAMA, "llama:BROWN", true),
GRAY_TRADER_LLAMA("gray", MobCompat.TRADER_LLAMA, "llama:GRAY", true)
GRAY_TRADER_LLAMA("gray", MobCompat.TRADER_LLAMA, "llama:GRAY", true),
RANDOM_SHULKER("random", MobCompat.SHULKER, Data.COLORABLE, true),
COLORABLE_SHULKER("", Arrays.stream(DyeColor.values()).map(color -> color.name().toLowerCase(Locale.ENGLISH)).collect(Collectors.toList()), MobCompat.SHULKER, Data.COLORABLE, true),
RED_FOX("red", MobCompat.FOX, "fox:RED", true),
SNOW_FOX("snow", MobCompat.FOX, "fox:SNOW", true),
SIZE_PHANTOM("", Collections.singletonList("<1-100>"), MobCompat.PHANTOM, Data.SIZE, true),
RAID_LEADER("leader", MobCompat.RAIDER, Data.RAID_LEADER, true),
TROPICAL_FISH_BODY_COLOR("fish_body_color", Arrays.stream(DyeColor.values()).map(color -> color.name().toLowerCase(Locale.ENGLISH) + "body").collect(Collectors.toList()), MobCompat.TROPICAL_FISH, Data.FISH_BODY_COLOR, true),
TROPICAL_FISH_PATTERN_COLOR("fish_pattern_color", Arrays.stream(DyeColor.values()).map(color -> color.name().toLowerCase(Locale.ENGLISH) + "pattern").collect(Collectors.toList()), MobCompat.TROPICAL_FISH, Data.FISH_PATTERN_COLOR, true),
;
@@ -170,43 +179,46 @@ public enum MobData {
TAMED,
COLORABLE,
EXP,
SIZE
SIZE,
RAID_LEADER,
FISH_BODY_COLOR,
FISH_PATTERN_COLOR,
}
public static final Logger logger = Logger.getLogger("Essentials");
MobData(String n, Object type, Object value, boolean isPublic) {
this.nickname = n;
this.matched = n;
this.helpMessage = n;
this.type = type;
this.value = value;
this.isPublic = isPublic;
}
MobData(String n, String h, Object type, Object value, boolean isPublic) {
this.nickname = n;
this.matched = n;
this.helpMessage = h;
this.type = type;
this.value = value;
this.isPublic = isPublic;
}
final private String nickname;
final private String helpMessage;
final private List<String> suggestions;
final private Object type;
final private Object value;
final private boolean isPublic;
private String matched;
MobData(String n, Object type, Object value, boolean isPublic) {
this.nickname = n;
this.matched = n;
this.suggestions = Collections.singletonList(n);
this.type = type;
this.value = value;
this.isPublic = isPublic;
}
MobData(String n, List<String> s, Object type, Object value, boolean isPublic) {
this.nickname = n;
this.matched = n;
this.suggestions = s;
this.type = type;
this.value = value;
this.isPublic = isPublic;
}
public static LinkedHashMap<String, MobData> getPossibleData(final Entity spawned, boolean publicOnly) {
LinkedHashMap<String, MobData> mobList = new LinkedHashMap<String, MobData>();
LinkedHashMap<String, MobData> mobList = new LinkedHashMap<>();
for (MobData data : MobData.values()) {
if (data.type == null || (publicOnly && !data.isPublic)) continue;
if (data.type == null || (publicOnly && !data.isPublic)) {
continue;
}
if (data.type instanceof EntityType && spawned.getType().equals(data.type)) {
mobList.put(data.nickname.toLowerCase(Locale.ENGLISH), data);
} else if (data.type instanceof Class && ((Class) data.type).isAssignableFrom(spawned.getClass())) {
@@ -218,11 +230,11 @@ public enum MobData {
}
public static List<String> getValidHelp(final Entity spawned) {
List<String> output = new ArrayList<String>();
List<String> output = new ArrayList<>();
LinkedHashMap<String, MobData> posData = getPossibleData(spawned, true);
for (MobData data : posData.values()) {
output.add(data.helpMessage);
output.add(StringUtil.joinList(data.suggestions));
}
return output;
}
@@ -233,9 +245,11 @@ public enum MobData {
}
LinkedHashMap<String, MobData> posData = getPossibleData(spawned, false);
for (String data : posData.keySet()) {
if (name.contains(data)) {
return posData.get(data);
for (MobData data : posData.values()) {
for (String suggestion : data.suggestions) {
if (name.contains(suggestion)) {
return data;
}
}
}
return null;
@@ -291,7 +305,12 @@ public enum MobData {
}
} else if (this.value.equals(Data.SIZE)) {
try {
((Slime) spawned).setSize(Integer.parseInt(rawData));
int size = Integer.parseInt(rawData);
if (spawned instanceof Slime) {
((Slime) spawned).setSize(size);
} else if (spawned.getType() == MobCompat.PHANTOM) {
((Phantom) spawned).setSize(size);
}
this.matched = rawData;
} catch (NumberFormatException e) {
throw new Exception(tl("slimeMalformedSize"), e);
@@ -313,6 +332,26 @@ public enum MobData {
InventoryWorkaround.setItemInMainHand(invent, new ItemStack((Material) this.value, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
}
} else if (this.value.equals(Data.RAID_LEADER)) {
((Raider) spawned).setPatrolLeader(true);
} else if (this.value.equals(Data.FISH_BODY_COLOR)) {
for (String match : TROPICAL_FISH_BODY_COLOR.suggestions) {
if (rawData.contains(match)) {
this.matched = match;
final String color = match.substring(0, match.indexOf("body")).toUpperCase(Locale.ENGLISH);
((TropicalFish) spawned).setBodyColor(DyeColor.valueOf(color));
break;
}
}
} else if (this.value.equals(Data.FISH_PATTERN_COLOR)) {
for (String match : TROPICAL_FISH_PATTERN_COLOR.suggestions) {
if (rawData.contains(match)) {
this.matched = match;
final String color = match.substring(0, match.indexOf("pattern")).toUpperCase(Locale.ENGLISH);
((TropicalFish) spawned).setPatternColor(DyeColor.valueOf(color));
break;
}
}
} else if (this.value instanceof String) {
final String[] split = ((String) this.value).split(":");
switch (split[0]) {
@@ -337,6 +376,9 @@ public enum MobData {
case "villagertype":
MobCompat.setVillagerType(spawned, split[1]);
break;
case "fox":
MobCompat.setFoxType(spawned, split[1]);
break;
}
} else {
logger.warning("Unknown mob data type: " + this.toString());
@@ -1,6 +1,7 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.ChatColor;
import org.bukkit.Server;
import java.util.*;
@@ -27,6 +28,9 @@ public class PlayerList {
}
user.setDisplayNick();
groupString.append(user.getDisplayName());
if (ess.getSettings().realNamesOnList() && !ChatColor.stripColor(user.getDisplayName()).equals(user.getName())) {
groupString.append(" (").append(user.getName()).append(")");
}
groupString.append("\u00a7f");
}
return groupString.toString();
@@ -40,7 +44,7 @@ public class PlayerList {
for (User onlinePlayer : ess.getOnlineUsers()) {
if (onlinePlayer.isHidden() || (user != null && !user.getBase().canSee(onlinePlayer.getBase()))) {
playerHidden++;
if (showHidden || user.getBase().canSee(onlinePlayer.getBase())) {
if (showHidden || user != null && user.getBase().canSee(onlinePlayer.getBase())) {
hiddenCount++;
}
}
@@ -56,18 +60,13 @@ public class PlayerList {
// Build the basic player list, divided by groups.
public static Map<String, List<User>> getPlayerLists(final IEssentials ess, final User sender, final boolean showHidden) {
Server server = ess.getServer();
final Map<String, List<User>> playerList = new HashMap<String, List<User>>();
final Map<String, List<User>> playerList = new HashMap<>();
for (User onlineUser : ess.getOnlineUsers()) {
if ((sender == null && !showHidden && onlineUser.isHidden()) || (sender != null && !showHidden && !sender.getBase().canSee(onlineUser.getBase()))) {
continue;
}
final String group = FormatUtil.stripFormat(FormatUtil.stripEssentialsFormat(onlineUser.getGroup().toLowerCase()));
List<User> list = playerList.get(group);
if (list == null) {
list = new ArrayList<User>();
playerList.put(group, list);
}
List<User> list = playerList.computeIfAbsent(group, k -> new ArrayList<>());
list.add(onlineUser);
}
return playerList;
@@ -76,13 +75,13 @@ public class PlayerList {
// Handle the merging of groups
public static List<User> getMergedList(final IEssentials ess, final Map<String, List<User>> playerList, final String groupName) {
final Set<String> configGroups = ess.getSettings().getListGroupConfig().keySet();
final List<User> users = new ArrayList<User>();
final List<User> users = new ArrayList<>();
for (String configGroup : configGroups) {
if (configGroup.equalsIgnoreCase(groupName)) {
String[] groupValues = ess.getSettings().getListGroupConfig().get(configGroup).toString().trim().split(" ");
for (String groupValue : groupValues) {
groupValue = groupValue.toLowerCase(Locale.ENGLISH);
if (groupValue == null || groupValue.isEmpty()) {
if (groupValue.isEmpty()) {
continue;
}
List<User> u = playerList.get(groupValue.trim());
@@ -104,20 +103,17 @@ public class PlayerList {
if (groupUsers != null && !groupUsers.isEmpty()) {
users.addAll(groupUsers);
}
if (users == null || users.isEmpty()) {
if (users.isEmpty()) {
throw new Exception(tl("groupDoesNotExist"));
}
final StringBuilder displayGroupName = new StringBuilder();
displayGroupName.append(Character.toTitleCase(groupName.charAt(0)));
displayGroupName.append(groupName.substring(1));
return outputFormat(displayGroupName.toString(), listUsers(ess, users, ", "));
String displayGroupName = Character.toTitleCase(groupName.charAt(0)) +
groupName.substring(1);
return outputFormat(displayGroupName, listUsers(ess, users, ", "));
}
// Build the output string
public static String outputFormat(final String group, final String message) {
final StringBuilder outputString = new StringBuilder();
outputString.append(tl("listGroupTag", FormatUtil.replaceFormat(group)));
outputString.append(message);
return outputString.toString();
return tl("listGroupTag", FormatUtil.replaceFormat(group)) +
message;
}
}
@@ -0,0 +1,191 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.LocationUtil;
import com.earth2me.essentials.utils.VersionUtil;
import io.papermc.lib.PaperLib;
import net.ess3.api.InvalidWorldException;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Biome;
import java.io.File;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
public class RandomTeleport implements IConf {
private final IEssentials essentials;
private final EssentialsConf config;
private final ConcurrentLinkedQueue<Location> cachedLocations = new ConcurrentLinkedQueue<>();
private static final Random RANDOM = new Random();
private static final int HIGHEST_BLOCK_Y_OFFSET = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_R01) ? 1 : 0;
public RandomTeleport(final IEssentials essentials) {
this.essentials = essentials;
File file = new File(essentials.getDataFolder(), "tpr.yml");
config = new EssentialsConf(file);
config.setTemplateName("/tpr.yml");
config.options().copyHeader(true);
reloadConfig();
}
@Override
public void reloadConfig() {
config.load();
cachedLocations.clear();
}
public Location getCenter() {
try {
Location center = config.getLocation("center", essentials.getServer());
if (center != null) {
return center;
}
} catch (InvalidWorldException ignored) {
}
Location center = essentials.getServer().getWorlds().get(0).getWorldBorder().getCenter();
center.setY(center.getWorld().getHighestBlockYAt(center) + 1);
setCenter(center);
return center;
}
public void setCenter(Location center) {
config.setProperty("center", center);
config.save();
}
public double getMinRange() {
return config.getDouble("min-range", 0d);
}
public void setMinRange(double minRange) {
config.setProperty("min-range", minRange);
config.save();
}
public double getMaxRange() {
return config.getDouble("max-range", getCenter().getWorld().getWorldBorder().getSize() / 2);
}
public void setMaxRange(double maxRange) {
config.setProperty("max-range", maxRange);
config.save();
}
public Set<Biome> getExcludedBiomes() {
List<String> biomeNames = config.getStringList("excluded-biomes");
Set<Biome> excludedBiomes = new HashSet<>();
for (String biomeName : biomeNames) {
try {
excludedBiomes.add(Biome.valueOf(biomeName.toUpperCase()));
} catch (IllegalArgumentException ignored) {
}
}
return excludedBiomes;
}
public int getFindAttempts() {
return config.getInt("find-attempts", 10);
}
public int getCacheThreshold() {
return config.getInt("cache-threshold", 10);
}
public boolean getPreCache() {
return config.getBoolean("pre-cache", true);
}
public Queue<Location> getCachedLocations() {
return cachedLocations;
}
// Get a random location; cached if possible. Otherwise on demand.
public CompletableFuture<Location> getRandomLocation(Location center, double minRange, double maxRange) {
int findAttempts = this.getFindAttempts();
Queue<Location> cachedLocations = this.getCachedLocations();
// Try to build up the cache if it is below the threshold
if (cachedLocations.size() < this.getCacheThreshold()) {
cacheRandomLocations(center, minRange, maxRange);
}
CompletableFuture<Location> future = new CompletableFuture<>();
// Return a random location immediately if one is available, otherwise try to find one now
if (cachedLocations.isEmpty()) {
attemptRandomLocation(findAttempts, center, minRange, maxRange).thenAccept(future::complete);
} else {
future.complete(cachedLocations.poll());
}
return future;
}
// Prompts caching random valid locations, up to a maximum number of attempts
public void cacheRandomLocations(Location center, double minRange, double maxRange) {
essentials.getServer().getScheduler().scheduleSyncDelayedTask(essentials, () -> {
for (int i = 0; i < this.getFindAttempts(); ++i) {
calculateRandomLocation(center, minRange, maxRange).thenAccept(location -> {
if (isValidRandomLocation(location)) {
this.getCachedLocations().add(location);
}
});
}
});
}
// Recursively attempt to find a random location. After a maximum number of attempts, the center is returned.
private CompletableFuture<Location> attemptRandomLocation(int attempts, Location center, double minRange, double maxRange) {
CompletableFuture<Location> future = new CompletableFuture<>();
if (attempts > 0) {
calculateRandomLocation(center, minRange, maxRange).thenAccept(location -> {
if (isValidRandomLocation(location)) {
future.complete(location);
} else {
attemptRandomLocation(attempts - 1, center, minRange, maxRange).thenAccept(future::complete);
}
});
} else {
future.complete(center);
}
return future;
}
// Calculates a random location asynchronously.
private CompletableFuture<Location> calculateRandomLocation(Location center, double minRange, double maxRange) {
CompletableFuture<Location> future = new CompletableFuture<>();
final int dx = RANDOM.nextBoolean() ? 1 : -1, dz = RANDOM.nextBoolean() ? 1 : -1;
Location location = new Location(
center.getWorld(),
center.getX() + dx * (minRange + RANDOM.nextDouble() * (maxRange - minRange)),
center.getWorld().getMaxHeight(),
center.getZ() + dz * (minRange + RANDOM.nextDouble() * (maxRange - minRange)),
360 * RANDOM.nextFloat() - 180,
0
);
PaperLib.getChunkAtAsync(location).thenAccept(chunk -> {
if (World.Environment.NETHER.equals(center.getWorld().getEnvironment())) {
location.setY(getNetherYAt(location));
} else {
location.setY(center.getWorld().getHighestBlockYAt(location) + HIGHEST_BLOCK_Y_OFFSET);
}
future.complete(location);
});
return future;
}
// Returns an appropriate elevation for a given location in the nether, or -1 if none is found
private double getNetherYAt(Location location) {
for (int y = 32; y < location.getWorld().getMaxHeight() / 2; ++y) {
if (!LocationUtil.isBlockUnsafe(location.getWorld(), location.getBlockX(), y, location.getBlockZ())) {
return y;
}
}
return -1;
}
private boolean isValidRandomLocation(Location location) {
return location.getBlockY() > 0 && !this.getExcludedBiomes().contains(location.getBlock().getBiome());
}
}
@@ -35,6 +35,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
@@ -156,6 +157,21 @@ public class Settings implements net.ess3.api.ISettings {
return forceDisableTeleportSafety;
}
@Override
public boolean isAlwaysTeleportSafety() {
return config.getBoolean("force-safe-teleport-location", false);
}
@Override
public boolean isTeleportPassengerDismount() {
return config.getBoolean("teleport-passenger-dismount", true);
}
@Override
public boolean isForcePassengerTeleport() {
return config.getBoolean("force-passenger-teleportation", false);
}
@Override
public double getTeleportDelay() {
return config.getDouble("teleport-delay", 0);
@@ -181,7 +197,7 @@ public class Settings implements net.ess3.api.ISettings {
return isCommandDisabled(cmd.getName());
}
private Set<String> disabledCommands = new HashSet<String>();
private Set<String> disabledCommands = new HashSet<>();
@Override
public boolean isCommandDisabled(String label) {
@@ -189,7 +205,7 @@ public class Settings implements net.ess3.api.ISettings {
}
private Set<String> getDisabledCommands() {
Set<String> disCommands = new HashSet<String>();
Set<String> disCommands = new HashSet<>();
for (String c : config.getStringList("disabled-commands")) {
disCommands.add(c.toLowerCase(Locale.ENGLISH));
}
@@ -269,10 +285,10 @@ public class Settings implements net.ess3.api.ISettings {
return BigDecimal.ZERO;
}
private Set<String> socialSpyCommands = new HashSet<String>();
private Set<String> socialSpyCommands = new HashSet<>();
private Set<String> _getSocialSpyCommands() {
Set<String> socialspyCommands = new HashSet<String>();
Set<String> socialspyCommands = new HashSet<>();
if (config.isList("socialspy-commands")) {
for (String c : config.getStringList("socialspy-commands")) {
@@ -295,10 +311,10 @@ public class Settings implements net.ess3.api.ISettings {
return config.getBoolean("socialspy-listen-muted-players", true);
}
private Set<String> muteCommands = new HashSet<String>();
private Set<String> muteCommands = new HashSet<>();
private Set<String> _getMuteCommands() {
Set<String> muteCommands = new HashSet<String>();
Set<String> muteCommands = new HashSet<>();
if (config.isList("mute-commands")) {
for (String s : config.getStringList("mute-commands")) {
muteCommands.add(s.toLowerCase(Locale.ENGLISH));
@@ -359,29 +375,37 @@ public class Settings implements net.ess3.api.ISettings {
return config.getBoolean("skip-used-one-time-kits-from-kit-list", false);
}
private ChatColor operatorColor = null;
private String operatorColor = null;
@Override
public ChatColor getOperatorColor() {
public String getOperatorColor() {
return operatorColor;
}
private ChatColor _getOperatorColor() {
private String _getOperatorColor() {
String colorName = config.getString("ops-name-color", null);
if (colorName == null) {
return ChatColor.DARK_RED;
}
if ("none".equalsIgnoreCase(colorName) || colorName.isEmpty()) {
return ChatColor.RED.toString();
} else if (colorName.equalsIgnoreCase("none") || colorName.isEmpty()) {
return null;
}
try {
return ChatColor.valueOf(colorName.toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException ex) {
return FormatUtil.parseHexColor(colorName);
} catch (NumberFormatException ignored) {
}
return ChatColor.getByChar(colorName);
try {
return ChatColor.valueOf(colorName.toUpperCase(Locale.ENGLISH)).toString();
} catch (IllegalArgumentException ignored) {
}
ChatColor lastResort = ChatColor.getByChar(colorName);
if (lastResort != null) {
return lastResort.toString();
}
return null;
}
@Override
@@ -419,7 +443,12 @@ public class Settings implements net.ess3.api.ISettings {
return config.getString("backup.command", null);
}
private final Map<String, String> chatFormats = Collections.synchronizedMap(new HashMap<String, String>());
@Override
public boolean isAlwaysRunBackup() {
return config.getBoolean("backup.always-run", false);
}
private final Map<String, String> chatFormats = Collections.synchronizedMap(new HashMap<>());
@Override
public String getChatFormat(String group) {
@@ -438,6 +467,7 @@ public class Settings implements net.ess3.api.ISettings {
mFormat = mFormat.replace("{TEAMNAME}", "{5}");
mFormat = mFormat.replace("{PREFIX}", "{6}");
mFormat = mFormat.replace("{SUFFIX}", "{7}");
mFormat = mFormat.replace("{USERNAME}", "{8}");
mFormat = "§r".concat(mFormat);
chatFormats.put(group, mFormat);
}
@@ -480,7 +510,7 @@ public class Settings implements net.ess3.api.ISettings {
return values;
}
}
Map<String, Object> defaultMap = new HashMap<String, Object>();
Map<String, Object> defaultMap = new HashMap<>();
if (config.getBoolean("sort-list-by-groups", false)) {
defaultMap.put("ListByGroup", "ListByGroup");
} else {
@@ -492,7 +522,7 @@ public class Settings implements net.ess3.api.ISettings {
@Override
public void reloadConfig() {
config.load();
noGodWorlds = new HashSet<String>(config.getStringList("no-god-in-worlds"));
noGodWorlds = new HashSet<>(config.getStringList("no-god-in-worlds"));
enabledSigns = _getEnabledSigns();
teleportSafety = _isTeleportSafetyEnabled();
forceDisableTeleportSafety = _isForceDisableTeleportSafety();
@@ -506,6 +536,7 @@ public class Settings implements net.ess3.api.ISettings {
sleepIgnoresAfkPlayers = _sleepIgnoresAfkPlayers();
afkListName = _getAfkListName();
isAfkListName = !afkListName.equalsIgnoreCase("none");
broadcastAfkMessage = _broadcastAfkMessage();
itemSpawnBl = _getItemSpawnBlacklist();
loginAttackDelay = _getLoginAttackDelay();
signUsePerSecond = _getSignUsePerSecond();
@@ -550,10 +581,15 @@ public class Settings implements net.ess3.api.ISettings {
isCompassTowardsHomePerm = _isCompassTowardsHomePerm();
isAllowWorldInBroadcastworld = _isAllowWorldInBroadcastworld();
itemDbType = _getItemDbType();
forceEnableRecipe = _isForceEnableRecipe();
allowOldIdSigns = _allowOldIdSigns();
isWaterSafe = _isWaterSafe();
isSafeUsermap = _isSafeUsermap();
logCommandBlockCommands = _logCommandBlockCommands();
nickBlacklist = _getNickBlacklist();
maxProjectileSpeed = _getMaxProjectileSpeed();
removeEffectsOnHeal = _isRemovingEffectsOnHeal();
vanishingItemPolicy = _getVanishingItemsPolicy();
bindingItemPolicy = _getBindingItemsPolicy();
}
void _lateLoadItemSpawnBlacklist() {
@@ -589,7 +625,7 @@ public class Settings implements net.ess3.api.ISettings {
return epItemSpwn;
}
private List<EssentialsSign> enabledSigns = new ArrayList<EssentialsSign>();
private List<EssentialsSign> enabledSigns = new ArrayList<>();
private boolean signsEnabled = false;
@Override
@@ -600,7 +636,7 @@ public class Settings implements net.ess3.api.ISettings {
private List<EssentialsSign> _getEnabledSigns() {
this.signsEnabled = false; // Ensure boolean resets on reload.
List<EssentialsSign> newSigns = new ArrayList<EssentialsSign>();
List<EssentialsSign> newSigns = new ArrayList<>();
for (String signName : config.getStringList("enabledSigns")) {
signName = signName.trim().toUpperCase(Locale.ENGLISH);
@@ -667,6 +703,11 @@ public class Settings implements net.ess3.api.ISettings {
return config.getString("currency-symbol", "$").concat("$").substring(0, 1).replaceAll("[0-9]", "$");
}
@Override
public boolean isCurrencySymbolSuffixed() {
return config.getBoolean("currency-symbol-suffix", false);
}
// #easteregg
@Override
@Deprecated
@@ -781,6 +822,11 @@ public class Settings implements net.ess3.api.ISettings {
return economyLogUpdate;
}
@Override
public boolean realNamesOnList() {
return config.getBoolean("real-names-on-list", false);
}
public boolean _isEcoLogUpdateEnabled() {
return config.getBoolean("economy-log-update-enabled", false);
}
@@ -934,12 +980,55 @@ public class Settings implements net.ess3.api.ISettings {
return afkListName;
}
private boolean broadcastAfkMessage;
@Override
public boolean broadcastAfkMessage() {
return broadcastAfkMessage;
}
private boolean _broadcastAfkMessage() {
return config.getBoolean("broadcast-afk-message", true);
}
@Override
public boolean areDeathMessagesEnabled() {
return config.getBoolean("death-messages", true);
}
private Set<String> noGodWorlds = new HashSet<String>();
private KeepInvPolicy vanishingItemPolicy;
public KeepInvPolicy _getVanishingItemsPolicy() {
String value = config.getString("vanishing-items-policy", "keep").toLowerCase(Locale.ENGLISH);
try {
return KeepInvPolicy.valueOf(value.toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException e) {
return KeepInvPolicy.KEEP;
}
}
@Override
public KeepInvPolicy getVanishingItemsPolicy() {
return vanishingItemPolicy;
}
private KeepInvPolicy bindingItemPolicy;
public KeepInvPolicy _getBindingItemsPolicy() {
String value = config.getString("binding-items-policy", "keep").toLowerCase(Locale.ENGLISH);
try {
return KeepInvPolicy.valueOf(value.toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException e) {
return KeepInvPolicy.KEEP;
}
}
@Override
public KeepInvPolicy getBindingItemsPolicy() {
return bindingItemPolicy;
}
private Set<String> noGodWorlds = new HashSet<>();
@Override
public Set<String> getNoGodWorlds() {
@@ -1105,8 +1194,7 @@ public class Settings implements net.ess3.api.ISettings {
private long _getEconomyLagWarning() {
// Default to 25ms
final long value = (long) (config.getDouble("economy-lag-warning", 25.0) * 1000000);
return value;
return (long) (config.getDouble("economy-lag-warning", 25.0) * 1000000);
}
@Override
@@ -1119,8 +1207,7 @@ public class Settings implements net.ess3.api.ISettings {
private long _getPermissionsLagWarning() {
// Default to 25ms
final long value = (long) (config.getDouble("permissions-lag-warning", 25.0) * 1000000);
return value;
return (long) (config.getDouble("permissions-lag-warning", 25.0) * 1000000);
}
@Override
@@ -1128,6 +1215,11 @@ public class Settings implements net.ess3.api.ISettings {
return permissionsLagWarning;
}
@Override
public long getMaxMute() {
return config.getLong("max-mute-time", -1);
}
@Override
public long getMaxTempban() {
return config.getLong("max-tempban-time", -1);
@@ -1193,6 +1285,16 @@ public class Settings implements net.ess3.api.ISettings {
return isCustomQuitMessage;
}
@Override
public int getJoinQuitMessagePlayerCount() {
return config.getInt("hide-join-quit-messages-above", -1);
}
@Override
public boolean hasJoinQuitMessagePlayerCount() {
return getJoinQuitMessagePlayerCount() >= 0;
}
@Override
public boolean isNotifyNoNewMail() {
return config.getBoolean("notify-no-new-mail", true);
@@ -1218,6 +1320,11 @@ public class Settings implements net.ess3.api.ISettings {
return new BigDecimal(config.getString("minimum-pay-amount", "0.001"));
}
@Override
public boolean isPayExcludesIgnoreList() {
return config.getBoolean("pay-excludes-ignore-list", false);
}
@Override public long getLastMessageReplyRecipientTimeout() {
return config.getLong("last-message-reply-recipient-timeout", 180);
}
@@ -1313,7 +1420,7 @@ public class Settings implements net.ess3.api.ISettings {
* >> Process cooldown value
* ================================ */
Object value = section.get(cmdEntry);
if (!(value instanceof Number) && value instanceof String) {
if (value instanceof String) {
try {
value = Double.parseDouble(value.toString());
} catch (NumberFormatException ignored) {
@@ -1425,7 +1532,6 @@ public class Settings implements net.ess3.api.ISettings {
newSigns.add(Signs.valueOf(signName).getSign());
} catch (Exception ex) {
logger.log(Level.SEVERE, tl("unknownItemInList", signName, "unprotected-sign-names"));
continue;
}
}
return newSigns;
@@ -1441,6 +1547,11 @@ public class Settings implements net.ess3.api.ISettings {
return config.getBoolean("allow-bulk-buy-sell", false);
}
@Override
public boolean isAllowSellNamedItems() {
return config.getBoolean("allow-selling-named-items", false);
}
@Override
public boolean isAddingPrefixInPlayerlist() {
return config.getBoolean("add-prefix-in-playerlist", false);
@@ -1466,6 +1577,16 @@ public class Settings implements net.ess3.api.ISettings {
return config.getBoolean("allow-direct-hat", true);
}
@Override
public boolean isWorldChangeFlyResetEnabled() {
return config.getBoolean("world-change-fly-reset", true);
}
@Override
public boolean isWorldChangeSpeedResetEnabled() {
return config.getBoolean("world-change-speed-reset", true);
}
private List<String> defaultEnabledConfirmCommands;
private List<String> _getDefaultEnabledConfirmCommands() {
@@ -1532,15 +1653,6 @@ public class Settings implements net.ess3.api.ISettings {
private boolean forceEnableRecipe; // https://github.com/EssentialsX/Essentials/issues/1397
private boolean _isForceEnableRecipe() {
return config.getBoolean("force-enable-recipe", false);
}
@Override
public boolean isForceEnableRecipe() {
return forceEnableRecipe;
}
private boolean allowOldIdSigns;
private boolean _allowOldIdSigns() {
@@ -1576,4 +1688,73 @@ public class Settings implements net.ess3.api.ISettings {
public boolean isSafeUsermap() {
return isSafeUsermap;
}
private boolean logCommandBlockCommands;
private boolean _logCommandBlockCommands() {
return config.getBoolean("log-command-block-commands", true);
}
@Override
public boolean logCommandBlockCommands() {
return logCommandBlockCommands;
}
private Set<Predicate<String>> nickBlacklist;
private Set<Predicate<String>> _getNickBlacklist() {
Set<Predicate<String>> blacklist = new HashSet<>();
config.getStringList("nick-blacklist").forEach(entry -> {
try {
blacklist.add(Pattern.compile(entry).asPredicate());
} catch (PatternSyntaxException e) {
logger.warning("Invalid nickname blacklist regex: " + entry);
}
});
return blacklist;
}
@Override
public Set<Predicate<String>> getNickBlacklist() {
return nickBlacklist;
}
private double maxProjectileSpeed;
private double _getMaxProjectileSpeed() {
return config.getDouble("max-projectile-speed", 8);
}
@Override
public double getMaxProjectileSpeed() {
return maxProjectileSpeed;
}
private boolean removeEffectsOnHeal;
private boolean _isRemovingEffectsOnHeal() {
return config.getBoolean("remove-effects-on-heal", true);
}
@Override
public boolean isRemovingEffectsOnHeal() {
return removeEffectsOnHeal;
}
@Override
public boolean isSpawnIfNoHome() {
return config.getBoolean("spawn-if-no-home", true);
}
@Override
public boolean isConfirmHomeOverwrite() {
return config.getBoolean("confirm-home-overwrite", false);
}
@Override
public boolean infoAfterDeath() {
return config.getBoolean("send-info-after-death", false);
}
}
@@ -29,7 +29,7 @@ public class SpawnMob {
public static String mobList(final User user) {
final Set<String> mobList = Mob.getMobList();
final Set<String> availableList = new HashSet<String>();
final Set<String> availableList = new HashSet<>();
for (String mob : mobList) {
if (user.isAuthorized("essentials.spawnmob." + mob.toLowerCase(Locale.ENGLISH))) {
availableList.add(mob);
@@ -44,7 +44,7 @@ public class SpawnMob {
public static List<String> mobParts(final String mobString) {
String[] mobParts = mobString.split(",");
List<String> mobs = new ArrayList<String>();
List<String> mobs = new ArrayList<>();
for (String mobPart : mobParts) {
String[] mobDatas = mobPart.split(":");
@@ -56,7 +56,7 @@ public class SpawnMob {
public static List<String> mobData(final String mobString) {
String[] mobParts = mobString.split(",");
List<String> mobData = new ArrayList<String>();
List<String> mobData = new ArrayList<>();
for (String mobPart : mobParts) {
String[] mobDatas = mobPart.split(":");
@@ -92,8 +92,8 @@ public class SpawnMob {
public static void spawnmob(final IEssentials ess, final Server server, final CommandSource sender, final User target, final Location loc, final List<String> parts, final List<String> data, int mobCount) throws Exception {
final Location sloc = LocationUtil.getSafeDestination(loc);
for (int i = 0; i < parts.size(); i++) {
Mob mob = Mob.fromName(parts.get(i));
for (String part : parts) {
Mob mob = Mob.fromName(part);
checkSpawnable(ess, sender, mob);
}
@@ -235,30 +235,20 @@ public class SpawnMob {
final EntityEquipment invent = ((LivingEntity) spawned).getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack(Material.BOW, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
invent.setBoots(new ItemStack(GOLDEN_BOOTS, 1));
invent.setBootsDropChance(0.0f);
}
if (type == EntityType.PIG_ZOMBIE) {
if (type == MobCompat.ZOMBIFIED_PIGLIN) {
final PigZombie zombie = ((PigZombie) spawned);
setVillager(zombie, false);
final EntityEquipment invent = zombie.getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack(GOLDEN_SWORD, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
invent.setBoots(new ItemStack(GOLDEN_BOOTS, 1));
invent.setBootsDropChance(0.0f);
}
if (type == EntityType.ZOMBIE) {
final Zombie zombie = ((Zombie) spawned);
setVillager(zombie, false);
final EntityEquipment invent = zombie.getEquipment();
invent.setBoots(new ItemStack(GOLDEN_BOOTS, 1));
invent.setBootsDropChance(0.0f);
}
if (type == EntityType.HORSE) {
@@ -7,6 +7,8 @@ import net.ess3.api.IEssentials;
import net.ess3.api.ITeleport;
import net.ess3.api.IUser;
import net.ess3.api.events.UserWarpEvent;
import net.ess3.api.events.teleport.PreTeleportEvent;
import net.ess3.api.events.teleport.TeleportWarmupEvent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
@@ -20,6 +22,10 @@ import java.util.GregorianCalendar;
import static com.earth2me.essentials.I18n.tl;
/**
* @deprecated This API is not asynchronous. Use {@link com.earth2me.essentials.AsyncTeleport AsyncTeleport}
*/
@Deprecated
public class Teleport implements ITeleport {
private final IUser teleportOwner;
private final IEssentials ess;
@@ -27,6 +33,7 @@ public class Teleport implements ITeleport {
private TeleportType tpType;
@Deprecated
public Teleport(IUser user, IEssentials ess) {
this.teleportOwner = user;
this.ess = ess;
@@ -39,6 +46,7 @@ public class Teleport implements ITeleport {
NORMAL
}
@Deprecated
public void cooldown(boolean check) throws Exception {
final Calendar time = new GregorianCalendar();
if (teleportOwner.getLastTeleportTimestamp() > 0) {
@@ -72,6 +80,7 @@ public class Teleport implements ITeleport {
}
}
@Deprecated
private boolean cooldownApplies() {
boolean applies = true;
String globalBypassPerm = "essentials.teleport.cooldown.bypass";
@@ -91,6 +100,7 @@ public class Teleport implements ITeleport {
return applies;
}
@Deprecated
private void warnUser(final IUser user, final double delay) {
Calendar c = new GregorianCalendar();
c.add(Calendar.SECOND, (int) delay);
@@ -100,6 +110,7 @@ public class Teleport implements ITeleport {
//The now function is used when you want to skip tp delay when teleporting someone to a location or player.
@Override
@Deprecated
public void now(Location loc, boolean cooldown, TeleportCause cause) throws Exception {
if (cooldown) {
cooldown(false);
@@ -109,6 +120,7 @@ public class Teleport implements ITeleport {
}
@Override
@Deprecated
public void now(Player entity, boolean cooldown, TeleportCause cause) throws Exception {
if (cooldown) {
cooldown(false);
@@ -118,11 +130,28 @@ public class Teleport implements ITeleport {
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
}
@Deprecated
protected void now(IUser teleportee, ITarget target, TeleportCause cause) throws Exception {
cancel(false);
teleportee.setLastLocation();
Location loc = target.getLocation();
PreTeleportEvent event = new PreTeleportEvent(teleportee, cause, target);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
if (teleportee.isAuthorized("essentials.back.onteleport")) {
teleportee.setLastLocation();
}
if (!teleportee.getBase().isEmpty()) {
if (!ess.getSettings().isTeleportPassengerDismount()) {
throw new Exception(tl("passengerTeleportFail"));
}
teleportee.getBase().eject();
}
if (LocationUtil.isBlockUnsafeForUser(teleportee, loc.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) {
if (ess.getSettings().isTeleportSafetyEnabled()) {
if (ess.getSettings().isForceDisableTeleportSafety()) {
@@ -154,12 +183,14 @@ public class Teleport implements ITeleport {
}
@Override
@Deprecated
public void teleport(Location loc, Trade chargeFor, TeleportCause cause) throws Exception {
teleport(teleportOwner, new LocationTarget(loc), chargeFor, cause);
}
//This is used when teleporting to a player
@Override
@Deprecated
public void teleport(Player entity, Trade chargeFor, TeleportCause cause) throws Exception {
ITarget target = new PlayerTarget(entity);
teleportOwner.sendMessage(tl("teleportToPlayer", entity.getDisplayName()));
@@ -168,12 +199,14 @@ public class Teleport implements ITeleport {
//This is used when teleporting to stored location
@Override
@Deprecated
public void teleportPlayer(IUser teleportee, Location loc, Trade chargeFor, TeleportCause cause) throws Exception {
teleport(teleportee, new LocationTarget(loc), chargeFor, cause);
}
//This is used on /tphere
@Override
@Deprecated
public void teleportPlayer(IUser teleportee, Player entity, Trade chargeFor, TeleportCause cause) throws Exception {
ITarget target = new PlayerTarget(entity);
teleport(teleportee, target, chargeFor, cause);
@@ -181,9 +214,17 @@ public class Teleport implements ITeleport {
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
}
@Deprecated
private void teleport(IUser teleportee, ITarget target, Trade chargeFor, TeleportCause cause) throws Exception {
double delay = ess.getSettings().getTeleportDelay();
TeleportWarmupEvent event = new TeleportWarmupEvent(teleportee, cause, target, delay);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
delay = event.getDelay();
Trade cashCharge = chargeFor;
if (chargeFor != null) {
@@ -211,9 +252,17 @@ public class Teleport implements ITeleport {
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false);
}
@Deprecated
private void teleportOther(IUser teleporter, IUser teleportee, ITarget target, Trade chargeFor, TeleportCause cause) throws Exception {
double delay = ess.getSettings().getTeleportDelay();
TeleportWarmupEvent event = new TeleportWarmupEvent(teleporter, teleportee, cause, target, delay);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
delay = event.getDelay();
Trade cashCharge = chargeFor;
if (teleporter != null && chargeFor != null) {
@@ -246,8 +295,17 @@ public class Teleport implements ITeleport {
//The respawn function is a wrapper used to handle tp fallback, on /jail and /home
@Override
@Deprecated
public void respawn(final Trade chargeFor, TeleportCause cause) throws Exception {
double delay = ess.getSettings().getTeleportDelay();
TeleportWarmupEvent event = new TeleportWarmupEvent(teleportOwner, cause, null, delay);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
delay = event.getDelay();
if (chargeFor != null) {
chargeFor.isAffordableFor(teleportOwner);
}
@@ -266,6 +324,7 @@ public class Teleport implements ITeleport {
initTimer((long) (delay * 1000.0), teleportOwner, null, chargeFor, cause, true);
}
@Deprecated
void respawnNow(IUser teleportee, TeleportCause cause) throws Exception {
final Player player = teleportee.getBase();
Location bed = player.getBedSpawnLocation();
@@ -283,13 +342,14 @@ public class Teleport implements ITeleport {
//The warp function is a wrapper used to teleportPlayer a player to a /warp
@Override
@Deprecated
public void warp(IUser teleportee, String warp, Trade chargeFor, TeleportCause cause) throws Exception {
UserWarpEvent event = new UserWarpEvent(teleportee, warp, chargeFor);
Bukkit.getServer().getPluginManager().callEvent(event);
if(event.isCancelled()) {
if (event.isCancelled()) {
return;
}
warp = event.getWarp();
Location loc = ess.getWarps().getWarp(warp);
teleportee.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
@@ -301,12 +361,14 @@ public class Teleport implements ITeleport {
//The back function is a wrapper used to teleportPlayer a player /back to their previous location.
@Override
@Deprecated
public void back(Trade chargeFor) throws Exception {
back(teleportOwner, chargeFor);
}
//This function is a wrapper over the other back function for cases where another player performs back for them
@Override
@Deprecated
public void back(IUser teleporter, Trade chargeFor) throws Exception {
tpType = TeleportType.BACK;
final Location loc = teleportOwner.getLastLocation();
@@ -316,15 +378,18 @@ public class Teleport implements ITeleport {
//This function is used to throw a user back after a jail sentence
@Override
@Deprecated
public void back() throws Exception {
now(teleportOwner, new LocationTarget(teleportOwner.getLastLocation()), TeleportCause.COMMAND);
}
@Deprecated
public void setTpType(TeleportType tpType) {
this.tpType = tpType;
}
//If we need to cancelTimer a pending teleportPlayer call this method
@Deprecated
private void cancel(boolean notifyUser) {
if (timedTeleport != null) {
timedTeleport.cancelTimer(notifyUser);
@@ -332,6 +397,7 @@ public class Teleport implements ITeleport {
}
}
@Deprecated
private void initTimer(long delay, IUser teleportUser, ITarget target, Trade chargeFor, TeleportCause cause, boolean respawn) {
timedTeleport = new TimedTeleport(teleportOwner, ess, this, delay, teleportUser, target, chargeFor, cause, respawn);
}
@@ -9,7 +9,7 @@ import java.util.UUID;
import static com.earth2me.essentials.I18n.tl;
@Deprecated
public class TimedTeleport implements Runnable {
private static final double MOVE_CONSTANT = 0.3;
private final IUser teleportOwner;
@@ -98,19 +98,17 @@ public class TimedTeleport implements Runnable {
cancelTimer(false);
teleportUser.sendMessage(tl("teleportationCommencing"));
try {
if (timer_chargeFor != null) {
timer_chargeFor.isAffordableFor(teleportOwner);
}
if (timer_respawn) {
teleport.respawnNow(teleportUser, timer_cause);
} else {
teleport.now(teleportUser, timer_teleportTarget, timer_cause);
}
if (timer_chargeFor != null) {
timer_chargeFor.charge(teleportOwner);
}
} catch (Exception ignored) {}
if (timer_chargeFor != null) {
timer_chargeFor.isAffordableFor(teleportOwner);
}
if (timer_respawn) {
teleport.respawnNow(teleportUser, timer_cause);
} else {
teleport.now(teleportUser, timer_teleportTarget, timer_cause);
}
if (timer_chargeFor != null) {
timer_chargeFor.charge(teleportOwner);
}
} catch (Exception ex) {
ess.showError(teleportOwner.getSource(), ex, "\\ teleport");
@@ -18,6 +18,8 @@ import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -81,26 +83,43 @@ public class Trade {
}
public void isAffordableFor(final IUser user) throws ChargeException {
CompletableFuture<Boolean> future = new CompletableFuture<>();
isAffordableFor(user, future);
if (future.isCompletedExceptionally()) {
try {
future.get();
} catch (InterruptedException e) { //If this happens, we have bigger problems...
e.printStackTrace();
} catch (ExecutionException e) {
throw (ChargeException) e.getCause();
}
}
}
public void isAffordableFor(final IUser user, CompletableFuture<Boolean> future) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "checking if " + user.getName() + " can afford charge.");
}
if (getMoney() != null && getMoney().signum() > 0 && !user.canAfford(getMoney())) {
throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess)));
future.completeExceptionally(new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess))));
return;
}
if (getItemStack() != null && !user.getBase().getInventory().containsAtLeast(itemStack, itemStack.getAmount())) {
throw new ChargeException(tl("missingItems", getItemStack().getAmount(), ess.getItemDb().name(getItemStack())));
future.completeExceptionally(new ChargeException(tl("missingItems", getItemStack().getAmount(), ess.getItemDb().name(getItemStack()))));
return;
}
BigDecimal money;
if (command != null && !command.isEmpty() && (money = getCommandCost(user)).signum() > 0 && !user.canAfford(money)) {
throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(money, ess)));
future.completeExceptionally(new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(money, ess))));
return;
}
if (exp != null && exp > 0 && SetExpFix.getTotalExperience(user.getBase()) < exp) {
throw new ChargeException(tl("notEnoughExperience"));
future.completeExceptionally(new ChargeException(tl("notEnoughExperience")));
}
}
@@ -175,6 +194,20 @@ public class Trade {
}
public void charge(final IUser user) throws ChargeException {
CompletableFuture<Boolean> future = new CompletableFuture<>();
charge(user, future);
if (future.isCompletedExceptionally()) {
try {
future.get();
} catch (InterruptedException e) { //If this happens, we have bigger problems...
e.printStackTrace();
} catch (ExecutionException e) {
throw (ChargeException) e.getCause();
}
}
}
public void charge(final IUser user, CompletableFuture<Boolean> future) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "attempting to charge user " + user.getName());
}
@@ -183,7 +216,8 @@ public class Trade {
ess.getLogger().log(Level.INFO, "charging user " + user.getName() + " money " + getMoney().toPlainString());
}
if (!user.canAfford(getMoney()) && getMoney().signum() > 0) {
throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess)));
future.completeExceptionally(new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess))));
return;
}
user.takeMoney(getMoney());
}
@@ -192,7 +226,8 @@ public class Trade {
ess.getLogger().log(Level.INFO, "charging user " + user.getName() + " itemstack " + getItemStack().toString());
}
if (!user.getBase().getInventory().containsAtLeast(getItemStack(), getItemStack().getAmount())) {
throw new ChargeException(tl("missingItems", getItemStack().getAmount(), getItemStack().getType().toString().toLowerCase(Locale.ENGLISH).replace("_", " ")));
future.completeExceptionally(new ChargeException(tl("missingItems", getItemStack().getAmount(), getItemStack().getType().toString().toLowerCase(Locale.ENGLISH).replace("_", " "))));
return;
}
user.getBase().getInventory().removeItem(getItemStack());
user.getBase().updateInventory();
@@ -200,7 +235,8 @@ public class Trade {
if (command != null) {
final BigDecimal cost = getCommandCost(user);
if (!user.canAfford(cost) && cost.signum() > 0) {
throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(cost, ess)));
future.completeExceptionally(new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(cost, ess))));
return;
}
user.takeMoney(cost);
}
@@ -210,7 +246,8 @@ public class Trade {
}
final int experience = SetExpFix.getTotalExperience(user.getBase());
if (experience < getExperience() && getExperience() > 0) {
throw new ChargeException(tl("notEnoughExperience"));
future.completeExceptionally(new ChargeException(tl("notEnoughExperience")));
return;
}
SetExpFix.setTotalExperience(user.getBase(), experience - getExperience());
}
@@ -15,7 +15,7 @@ import java.util.regex.Pattern;
public class UUIDMap {
private final transient net.ess3.api.IEssentials ess;
private File userList;
private final File userList;
private final transient Pattern splitPattern = Pattern.compile(",");
private static boolean pendingWrite;
@@ -28,15 +28,12 @@ public class UUIDMap {
this.ess = ess;
userList = new File(ess.getDataFolder(), "usermap.csv");
pendingWrite = false;
writeTaskRunnable = new Runnable() {
@Override
public void run() {
if (pendingWrite) {
try {
new WriteRunner(ess.getDataFolder(), userList, ess.getUserMap().getNames()).run();
} catch (Throwable t) { // bad code to prevent task from being suppressed
t.printStackTrace();
}
writeTaskRunnable = () -> {
if (pendingWrite) {
try {
new WriteRunner(ess.getDataFolder(), userList, ess.getUserMap().getNames()).run();
} catch (Throwable t) { // bad code to prevent task from being suppressed
t.printStackTrace();
}
}
};
+128 -54
View File
@@ -16,8 +16,6 @@ import net.ess3.api.events.JailStatusChangeEvent;
import net.ess3.api.events.MuteStatusChangeEvent;
import net.ess3.api.events.UserBalanceUpdateEvent;
import net.ess3.nms.refl.ReflUtil;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@@ -28,7 +26,14 @@ import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import java.math.BigDecimal;
import java.util.*;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.WeakHashMap;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -37,12 +42,13 @@ import static com.earth2me.essentials.I18n.tl;
public class User extends UserData implements Comparable<User>, IMessageRecipient, net.ess3.api.IUser {
private static final Logger logger = Logger.getLogger("Essentials");
private IMessageRecipient messageRecipient;
private final IMessageRecipient messageRecipient;
private transient UUID teleportRequester;
private transient boolean teleportRequestHere;
private transient Location teleportLocation;
private transient boolean vanished;
private transient final Teleport teleport;
private transient final AsyncTeleport teleport;
private transient final Teleport legacyTeleport;
private transient long teleportRequestTime;
private transient long lastOnlineActivity;
private transient long lastThrottledAction;
@@ -57,13 +63,16 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
private boolean ignoreMsg = false;
private String afkMessage;
private long afkSince;
private Map<User, BigDecimal> confirmingPayments = new WeakHashMap<>();
private final Map<User, BigDecimal> confirmingPayments = new WeakHashMap<>();
private String confirmingClearCommand;
private long lastNotifiedAboutMailsMs;
private String lastHomeConfirmation;
private long lastHomeConfirmationTimestamp;
public User(final Player base, final IEssentials ess) {
super(base, ess);
teleport = new Teleport(this, ess);
teleport = new AsyncTeleport(this, ess);
legacyTeleport = new Teleport(this, ess);
if (isAfk()) {
afkPosition = this.getLocation();
}
@@ -162,10 +171,14 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
@Override
public void giveMoney(final BigDecimal value, final CommandSource initiator) throws MaxMoneyException {
giveMoney(value, initiator, UserBalanceUpdateEvent.Cause.UNKNOWN);
}
public void giveMoney(final BigDecimal value, final CommandSource initiator, UserBalanceUpdateEvent.Cause cause) throws MaxMoneyException {
if (value.signum() == 0) {
return;
}
setMoney(getMoney().add(value));
setMoney(getMoney().add(value), cause);
sendMessage(tl("addedToAccount", NumberUtil.displayCurrency(value, ess)));
if (initiator != null) {
initiator.sendMessage(tl("addedToOthersAccount", NumberUtil.displayCurrency(value, ess), this.getDisplayName(), NumberUtil.displayCurrency(getMoney(), ess)));
@@ -174,13 +187,17 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
@Override
public void payUser(final User reciever, final BigDecimal value) throws Exception {
payUser(reciever, value, UserBalanceUpdateEvent.Cause.UNKNOWN);
}
public void payUser(final User reciever, final BigDecimal value, UserBalanceUpdateEvent.Cause cause) throws Exception {
if (value.compareTo(BigDecimal.ZERO) < 1) {
throw new Exception(tl("payMustBePositive"));
}
if (canAfford(value)) {
setMoney(getMoney().subtract(value));
reciever.setMoney(reciever.getMoney().add(value));
setMoney(getMoney().subtract(value), cause);
reciever.setMoney(reciever.getMoney().add(value), cause);
sendMessage(tl("moneySentTo", NumberUtil.displayCurrency(value, ess), reciever.getDisplayName()));
reciever.sendMessage(tl("moneyRecievedFrom", NumberUtil.displayCurrency(value, ess), getDisplayName()));
} else {
@@ -195,11 +212,15 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
@Override
public void takeMoney(final BigDecimal value, final CommandSource initiator) {
takeMoney(value, initiator, UserBalanceUpdateEvent.Cause.UNKNOWN);
}
public void takeMoney(final BigDecimal value, final CommandSource initiator, UserBalanceUpdateEvent.Cause cause) {
if (value.signum() == 0) {
return;
}
try {
setMoney(getMoney().subtract(value));
setMoney(getMoney().subtract(value), cause);
} catch (MaxMoneyException ex) {
ess.getLogger().log(Level.WARNING, "Invalid call to takeMoney, total balance can't be more than the max-money limit.", ex);
}
@@ -226,12 +247,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
public void dispose() {
ess.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
_dispose();
}
});
ess.runTaskAsynchronously(this::_dispose);
}
private void _dispose() {
@@ -329,26 +345,34 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
if (this.getBase().isOp()) {
try {
final ChatColor opPrefix = ess.getSettings().getOperatorColor();
if (opPrefix != null && opPrefix.toString().length() > 0) {
prefix.insert(0, opPrefix.toString());
final String opPrefix = ess.getSettings().getOperatorColor();
if (opPrefix != null && !opPrefix.isEmpty()) {
prefix.insert(0, opPrefix);
suffix = "§r";
}
} catch (Exception e) {
if (ess.getSettings().isDebug()) {
e.printStackTrace();
}
}
}
if (ess.getSettings().addPrefixSuffix()) {
//These two extra toggles are not documented, because they are mostly redundant #EasterEgg
if (withPrefix || !ess.getSettings().disablePrefix()) {
final String ptext = ess.getPermissionsHandler().getPrefix(base).replace('&', '§');
final String ptext = FormatUtil.replaceFormat(ess.getPermissionsHandler().getPrefix(base));
prefix.insert(0, ptext);
suffix = "§r";
}
if (withSuffix || !ess.getSettings().disableSuffix()) {
final String stext = ess.getPermissionsHandler().getSuffix(base).replace('&', '§');
final String stext = FormatUtil.replaceFormat(ess.getPermissionsHandler().getSuffix(base));
suffix = stext + "§r";
suffix = suffix.replace("§f§f", "§f").replace("§f§r", "§r").replace("§r§r", "§r");
// :YEP: WHAT ARE THEY DOING?
// :YEP: STILL. LEGACY CODE.
// :YEP: BUT WHY?
// :YEP: I CAN'T BELIEVE THIS!
// Code from 1542 BC #EasterEgg
suffix = suffix.replace("§f§r", "§r").replace("§r§r", "§r");
}
}
final String strPrefix = prefix.toString();
@@ -394,10 +418,19 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
@Override
public Teleport getTeleport() {
public AsyncTeleport getAsyncTeleport() {
return teleport;
}
/**
* @deprecated This API is not asynchronous. Use {@link User#getAsyncTeleport()}
*/
@Override
@Deprecated
public Teleport getTeleport() {
return legacyTeleport;
}
public long getLastOnlineActivity() {
return lastOnlineActivity;
}
@@ -432,7 +465,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
final Method.MethodAccount account = Methods.getMethod().getAccount(this.getName());
return BigDecimal.valueOf(account.balance());
} catch (Exception ex) {
} catch (Exception ignored) {
}
}
return super.getMoney();
@@ -440,6 +473,10 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
@Override
public void setMoney(final BigDecimal value) throws MaxMoneyException {
setMoney(value, UserBalanceUpdateEvent.Cause.UNKNOWN);
}
public void setMoney(final BigDecimal value, UserBalanceUpdateEvent.Cause cause) throws MaxMoneyException {
if (ess.getSettings().isEcoDisabled()) {
if (ess.getSettings().isDebug()) {
ess.getLogger().info("Internal economy functions disabled, aborting balance change.");
@@ -447,11 +484,11 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return;
}
final BigDecimal oldBalance = _getMoney();
UserBalanceUpdateEvent updateEvent = new UserBalanceUpdateEvent(this.getBase(), oldBalance, value);
UserBalanceUpdateEvent updateEvent = new UserBalanceUpdateEvent(this.getBase(), oldBalance, value, cause);
ess.getServer().getPluginManager().callEvent(updateEvent);
BigDecimal newBalance = updateEvent.getNewBalance();
if (Methods.hasMethod()) {
try {
final Method method = Methods.getMethod();
@@ -460,7 +497,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
final Method.MethodAccount account = Methods.getMethod().getAccount(this.getName());
account.set(newBalance.doubleValue());
} catch (Exception ex) {
} catch (Exception ignored) {
}
}
super.setMoney(newBalance, true);
@@ -471,7 +508,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
if (ess.getSettings().isEcoDisabled()) {
return;
}
if (Methods.hasMethod() && super.getMoney() != value) {
if (Methods.hasMethod() && !super.getMoney().equals(value)) {
try {
super.setMoney(value, false);
} catch (MaxMoneyException ex) {
@@ -482,7 +519,12 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
@Override
public void setAfk(final boolean set) {
final AfkStatusChangeEvent afkEvent = new AfkStatusChangeEvent(this, set);
setAfk(set, AfkStatusChangeEvent.Cause.UNKNOWN);
}
@Override
public void setAfk(boolean set, AfkStatusChangeEvent.Cause cause) {
final AfkStatusChangeEvent afkEvent = new AfkStatusChangeEvent(this, set, cause);
ess.getServer().getPluginManager().callEvent(afkEvent);
if (afkEvent.isCancelled()) {
return;
@@ -500,7 +542,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
_setAfk(set);
updateAfkListName();
}
private void updateAfkListName() {
if (ess.getSettings().isAfkListName()) {
if(isAfk()) {
@@ -512,8 +554,13 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
}
@Deprecated
public boolean toggleAfk() {
setAfk(!isAfk());
return toggleAfk(AfkStatusChangeEvent.Cause.UNKNOWN);
}
public boolean toggleAfk(AfkStatusChangeEvent.Cause cause) {
setAfk(!isAfk(), cause);
return isAfk();
}
@@ -529,7 +576,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
@Override
public void setHidden(final boolean hidden) {
this.hidden = hidden;
if (hidden == true) {
if (hidden) {
setLastLogout(getLastOnlineActivity());
}
}
@@ -546,14 +593,12 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
sendMessage(tl("haveBeenReleased"));
setJail(null);
if (ess.getSettings().isTeleportBackWhenFreedFromJail()) {
try {
getTeleport().back();
} catch (Exception ex) {
try {
getTeleport().respawn(null, TeleportCause.PLUGIN);
} catch (Exception ex1) {
}
}
CompletableFuture<Boolean> future = new CompletableFuture<>();
getAsyncTeleport().back(future);
future.exceptionally(e -> {
getAsyncTeleport().respawn(null, TeleportCause.PLUGIN, new CompletableFuture<>());
return false;
});
}
return true;
}
@@ -564,7 +609,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
//Returns true if status expired during this check
public boolean checkMuteTimeout(final long currentTime) {
if (getMuteTimeout() > 0 && getMuteTimeout() < currentTime && isMuted()) {
final MuteStatusChangeEvent event = new MuteStatusChangeEvent(this, null, false);
final MuteStatusChangeEvent event = new MuteStatusChangeEvent(this, null, false, getMuteTimeout(), getMuteReason());
ess.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
@@ -578,14 +623,24 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return false;
}
@Deprecated
public void updateActivity(final boolean broadcast) {
updateActivity(broadcast, AfkStatusChangeEvent.Cause.UNKNOWN);
}
public void updateActivity(final boolean broadcast, AfkStatusChangeEvent.Cause cause) {
if (isAfk()) {
setAfk(false);
setAfk(false, cause);
if (broadcast && !isHidden()) {
setDisplayNick();
final String msg = tl("userIsNotAway", getDisplayName());
if (!msg.isEmpty()) {
ess.broadcastMessage(this, msg);
final String selfmsg = tl("userIsNotAwaySelf", getDisplayName());
if (!msg.isEmpty() && ess.getSettings().broadcastAfkMessage()) {
// exclude user from receiving general AFK announcement in favor of personal message
ess.broadcastMessage(this, msg, u -> u == this);
}
if (!selfmsg.isEmpty()) {
this.sendMessage(selfmsg);
}
}
}
@@ -594,13 +649,13 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
public void updateActivityOnMove(final boolean broadcast) {
if(ess.getSettings().cancelAfkOnMove()) {
updateActivity(broadcast);
updateActivity(broadcast, AfkStatusChangeEvent.Cause.MOVE);
}
}
public void updateActivityOnInteract(final boolean broadcast) {
if(ess.getSettings().cancelAfkOnInteract()) {
updateActivity(broadcast);
updateActivity(broadcast, AfkStatusChangeEvent.Cause.INTERACT);
}
}
@@ -628,12 +683,17 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
final long autoafk = ess.getSettings().getAutoAfk();
if (!isAfk() && autoafk > 0 && lastActivity + autoafk * 1000 < System.currentTimeMillis() && isAuthorized("essentials.afk.auto")) {
setAfk(true);
setAfk(true, AfkStatusChangeEvent.Cause.ACTIVITY);
if (!isHidden()) {
setDisplayNick();
final String msg = tl("userIsAway", getDisplayName());
if (!msg.isEmpty()) {
ess.broadcastMessage(this, msg);
final String selfmsg = tl("userIsAwaySelf", getDisplayName());
if (!msg.isEmpty() && ess.getSettings().broadcastAfkMessage()) {
// exclude user from receiving general AFK announcement in favor of personal message
ess.broadcastMessage(this, msg, u -> u == this);
}
if (!selfmsg.isEmpty()) {
this.sendMessage(selfmsg);
}
}
}
@@ -655,9 +715,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
if (isAfk()) {
// Protect AFK players by representing them in a god mode state to render them invulnerable to damage.
if (ess.getSettings().getFreezeAfkPlayers()) {
return true;
}
return ess.getSettings().getFreezeAfkPlayers();
}
return false;
}
@@ -923,4 +981,20 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
}
}
public String getLastHomeConfirmation() {
return lastHomeConfirmation;
}
public void setLastHomeConfirmation(String lastHomeConfirmation) {
this.lastHomeConfirmation = lastHomeConfirmation;
}
public long getLastHomeConfirmationTimestamp() {
return lastHomeConfirmationTimestamp;
}
public void setLastHomeConfirmationTimestamp() {
this.lastHomeConfirmationTimestamp = System.currentTimeMillis();
}
}
@@ -17,6 +17,7 @@ import java.math.BigDecimal;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.earth2me.essentials.I18n.tl;
@@ -24,12 +25,11 @@ import static com.earth2me.essentials.I18n.tl;
public abstract class UserData extends PlayerExtension implements IConf {
protected final transient IEssentials ess;
private final EssentialsUserConf config;
private final File folder;
protected UserData(Player base, IEssentials ess) {
super(base);
this.ess = ess;
folder = new File(ess.getDataFolder(), "userdata");
File folder = new File(ess.getDataFolder(), "userdata");
if (!folder.exists()) {
folder.mkdirs();
}
@@ -149,15 +149,14 @@ public abstract class UserData extends PlayerExtension implements IConf {
if (config.isConfigurationSection("homes")) {
return config.getConfigurationSection("homes").getValues(false);
}
return new HashMap<String, Object>();
return new HashMap<>();
}
private String getHomeName(String search) {
if (NumberUtil.isInt(search)) {
try {
search = getHomes().get(Integer.parseInt(search) - 1);
} catch (NumberFormatException e) {
} catch (IndexOutOfBoundsException e) {
} catch (NumberFormatException | IndexOutOfBoundsException ignored) {
}
}
return search;
@@ -189,7 +188,7 @@ public abstract class UserData extends PlayerExtension implements IConf {
}
public List<String> getHomes() {
return new ArrayList<String>(homes.keySet());
return new ArrayList<>(homes.keySet());
}
public void setHome(String name, Location loc) {
@@ -218,6 +217,10 @@ public abstract class UserData extends PlayerExtension implements IConf {
return config.hasProperty("home");
}
public boolean hasHome(String name) {
return config.hasProperty("homes." + name);
}
private String nickname;
public String _getNickname() {
@@ -234,10 +237,10 @@ public abstract class UserData extends PlayerExtension implements IConf {
config.save();
}
private List<Material> unlimited;
private Set<Material> unlimited;
private List<Material> _getUnlimited() {
List<Material> retlist = new ArrayList<>();
private Set<Material> _getUnlimited() {
Set<Material> retlist = new HashSet<>();
List<String> configList = config.getStringList("unlimited");
for(String s : configList) {
Material mat = Material.matchMaterial(s);
@@ -249,7 +252,7 @@ public abstract class UserData extends PlayerExtension implements IConf {
return retlist;
}
public List<Material> getUnlimited() {
public Set<Material> getUnlimited() {
return unlimited;
}
@@ -258,13 +261,20 @@ public abstract class UserData extends PlayerExtension implements IConf {
}
public void setUnlimited(ItemStack stack, boolean state) {
if (unlimited.contains(stack.getType())) {
unlimited.remove(stack.getType());
}
boolean wasUpdated;
if (state) {
unlimited.add(stack.getType());
wasUpdated = unlimited.add(stack.getType());
} else {
wasUpdated = unlimited.remove(stack.getType());
}
config.setProperty("unlimited", unlimited);
if (wasUpdated) {
applyUnlimited();
}
}
private void applyUnlimited() {
config.setProperty("unlimited", unlimited.stream().map(Enum::name).collect(Collectors.toList()));
config.save();
}
@@ -464,19 +474,42 @@ public abstract class UserData extends PlayerExtension implements IConf {
config.save();
}
private List<String> ignoredPlayers;
private List<UUID> ignoredPlayers;
public List<String> _getIgnoredPlayers() {
return Collections.synchronizedList(config.getStringList("ignore"));
public List<UUID> _getIgnoredPlayers() {
List<UUID> players = new ArrayList<>();
for (String uuid : config.getStringList("ignore")) {
try {
players.add(UUID.fromString(uuid));
} catch (IllegalArgumentException ignored) {}
}
return Collections.synchronizedList(players);
}
@Deprecated
public void setIgnoredPlayers(List<String> players) {
List<UUID> uuids = new ArrayList<>();
for (String player : players) {
User user = ess.getOfflineUser(player);
if (user == null) {
return;
}
uuids.add(user.getBase().getUniqueId());
}
setIgnoredPlayerUUIDs(uuids);
}
public void setIgnoredPlayerUUIDs(List<UUID> players) {
if (players == null || players.isEmpty()) {
ignoredPlayers = Collections.synchronizedList(new ArrayList<String>());
ignoredPlayers = Collections.synchronizedList(new ArrayList<>());
config.removeProperty("ignore");
} else {
ignoredPlayers = players;
config.setProperty("ignore", players);
List<String> uuids = new ArrayList<>();
for (UUID uuid : players) {
uuids.add(uuid.toString());
}
config.setProperty("ignore", uuids);
}
config.save();
}
@@ -491,17 +524,19 @@ public abstract class UserData extends PlayerExtension implements IConf {
}
public boolean isIgnoredPlayer(IUser user) {
return (ignoredPlayers.contains(user.getName().toLowerCase(Locale.ENGLISH)) && !user.isIgnoreExempt());
return ignoredPlayers.contains(user.getBase().getUniqueId()) && !user.isIgnoreExempt();
}
public void setIgnoredPlayer(IUser user, boolean set) {
final String entry = user.getName().toLowerCase(Locale.ENGLISH);
UUID uuid = user.getBase().getUniqueId();
if (set) {
if (!ignoredPlayers.contains(entry)) ignoredPlayers.add(entry);
if (!ignoredPlayers.contains(uuid)) {
ignoredPlayers.add(uuid);
}
} else {
ignoredPlayers.remove(entry);
ignoredPlayers.remove(uuid);
}
setIgnoredPlayers(ignoredPlayers);
setIgnoredPlayerUUIDs(ignoredPlayers);
}
private boolean godmode;
@@ -787,7 +822,7 @@ public abstract class UserData extends PlayerExtension implements IConf {
if (config.isConfigurationSection("timestamps.kits")) {
final ConfigurationSection section = config.getConfigurationSection("timestamps.kits");
final Map<String, Long> timestamps = new HashMap<String, Long>();
final Map<String, Long> timestamps = new HashMap<>();
for (String command : section.getKeys(false)) {
if (section.isLong(command)) {
timestamps.put(command.toLowerCase(Locale.ENGLISH), section.getLong(command));
@@ -797,7 +832,7 @@ public abstract class UserData extends PlayerExtension implements IConf {
}
return timestamps;
}
return new HashMap<String, Long>();
return new HashMap<>();
}
public long getKitTimestamp(String name) {
@@ -836,28 +871,28 @@ public abstract class UserData extends PlayerExtension implements IConf {
if (config.isConfigurationSection("info")) {
return config.getConfigurationSection("info").getKeys(true);
}
return new HashSet<String>();
return new HashSet<>();
}
public Map<String, Object> getConfigMap() {
if (config.isConfigurationSection("info")) {
return config.getConfigurationSection("info").getValues(true);
}
return new HashMap<String, Object>();
return new HashMap<>();
}
public Map<String, Object> getConfigMap(String node) {
if (config.isConfigurationSection("info." + node)) {
return config.getConfigurationSection("info." + node).getValues(true);
}
return new HashMap<String, Object>();
return new HashMap<>();
}
// Pattern, Date. Pattern for less pattern creations
private Map<Pattern, Long> commandCooldowns;
private Map<Pattern, Long> _getCommandCooldowns() {
if (!config.isConfigurationSection("timestamps.command-cooldowns")) {
if (!config.contains("timestamps.command-cooldowns")) {
return null;
}
@@ -25,7 +25,7 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
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 UUIDMap uuidMap;
private final UUIDMap uuidMap;
private final transient Cache<String, User> users;
private static boolean legacy = false;
@@ -53,29 +53,26 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
}
private void loadAllUsersAsync(final IEssentials ess) {
ess.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
synchronized (users) {
final File userdir = new File(ess.getDataFolder(), "userdata");
if (!userdir.exists()) {
return;
}
keys.clear();
users.invalidateAll();
for (String string : userdir.list()) {
if (!string.endsWith(".yml")) {
continue;
}
final String name = string.substring(0, string.length() - 4);
try {
keys.add(UUID.fromString(name));
} catch (IllegalArgumentException ex) {
//Ignore these users till they rejoin.
}
}
uuidMap.loadAllUsers(names, history);
ess.runTaskAsynchronously(() -> {
synchronized (users) {
final File userdir = new File(ess.getDataFolder(), "userdata");
if (!userdir.exists()) {
return;
}
keys.clear();
users.invalidateAll();
for (String string : userdir.list()) {
if (!string.endsWith(".yml")) {
continue;
}
final String name = string.substring(0, string.length() - 4);
try {
keys.add(UUID.fromString(name));
} catch (IllegalArgumentException ex) {
//Ignore these users till they rejoin.
}
}
uuidMap.loadAllUsers(names, history);
}
});
}
@@ -112,9 +109,7 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
} else {
return legacyCacheGet(uuid);
}
} catch (ExecutionException ex) {
return null;
} catch (UncheckedExecutionException ex) {
} catch (ExecutionException | UncheckedExecutionException ex) {
return null;
}
}
@@ -16,7 +16,7 @@ import static com.earth2me.essentials.I18n.tl;
public class Warps implements IConf, net.ess3.api.IWarps {
private static final Logger logger = Logger.getLogger("Essentials");
private final Map<StringIgnoreCase, EssentialsConf> warpPoints = new HashMap<StringIgnoreCase, EssentialsConf>();
private final Map<StringIgnoreCase, EssentialsConf> warpPoints = new HashMap<>();
private final File warpsFolder;
private final Server server;
@@ -36,11 +36,11 @@ public class Warps implements IConf, net.ess3.api.IWarps {
@Override
public Collection<String> getList() {
final List<String> keys = new ArrayList<String>();
final List<String> keys = new ArrayList<>();
for (StringIgnoreCase stringIgnoreCase : warpPoints.keySet()) {
keys.add(stringIgnoreCase.getString());
}
Collections.sort(keys, String.CASE_INSENSITIVE_ORDER);
keys.sort(String.CASE_INSENSITIVE_ORDER);
return keys;
}
@@ -90,7 +90,7 @@ public class Warps implements IConf, net.ess3.api.IWarps {
try {
uuid = UUID.fromString(conf.getString("lastowner"));
}
catch (Exception ex) {}
catch (Exception ignored) {}
return uuid;
}
@@ -111,11 +111,11 @@ public class Warps implements IConf, net.ess3.api.IWarps {
warpPoints.clear();
File[] listOfFiles = warpsFolder.listFiles();
if (listOfFiles.length >= 1) {
for (int i = 0; i < listOfFiles.length; i++) {
String filename = listOfFiles[i].getName();
if (listOfFiles[i].isFile() && filename.endsWith(".yml")) {
for (File listOfFile : listOfFiles) {
String filename = listOfFile.getName();
if (listOfFile.isFile() && filename.endsWith(".yml")) {
try {
EssentialsConf conf = new EssentialsConf(listOfFiles[i]);
EssentialsConf conf = new EssentialsConf(listOfFile);
conf.load();
String name = conf.getString("name");
if (name != null) {
@@ -8,6 +8,7 @@ import com.earth2me.essentials.utils.StringUtil;
import com.google.common.base.Charsets;
import net.ess3.api.IEssentials;
import net.ess3.api.MaxMoneyException;
import net.ess3.api.events.UserBalanceUpdateEvent;
import org.bukkit.entity.Player;
import java.io.File;
@@ -41,7 +42,9 @@ public class Economy {
File folder = new File(ess.getDataFolder(), "userdata");
name = StringUtil.safeString(name);
if (!folder.exists()) {
folder.mkdirs();
if (!folder.mkdirs()) {
throw new RuntimeException("Error while creating userdata directory!");
}
}
UUID npcUUID = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
EssentialsUserConf npcConfig = new EssentialsUserConf(name, npcUUID, new File(folder, npcUUID.toString() + ".yml"));
@@ -63,7 +66,7 @@ public class Economy {
throw new RuntimeException(noCallBeforeLoad);
}
if (name == null) {
throw new RuntimeException("Economy username cannot be null");
throw new IllegalArgumentException("Economy username cannot be null");
}
User user = ess.getUser(name);
@@ -85,9 +88,20 @@ public class Economy {
return user;
}
private static User getUserByUUID(UUID uuid) {
if (ess == null) {
throw new RuntimeException(noCallBeforeLoad);
}
if (uuid == null) {
throw new IllegalArgumentException("Economy uuid cannot be null");
}
return ess.getUser(uuid);
}
/**
* Returns the balance of a user
*
* @deprecated Use {@link Economy#getMoneyExact(UUID)} or {@link Economy#getMoneyExact(User)}
* @param name Name of the user
*
* @return balance
@@ -106,17 +120,41 @@ public class Economy {
return amount;
}
/**
* @deprecated Usernames can change, use {@link Economy#getMoneyExact(UUID)} or {@link Economy#getMoneyExact(User)}
* @param name Name of user
* @return Exact balance of user
* @throws UserDoesNotExistException
*/
@Deprecated
public static BigDecimal getMoneyExact(String name) throws UserDoesNotExistException {
User user = getUserByName(name);
if (user == null) {
throw new UserDoesNotExistException(name);
}
return getMoneyExact(user);
}
public static BigDecimal getMoneyExact(UUID uuid) throws UserDoesNotExistException {
User user = getUserByUUID(uuid);
if (user == null) {
throw new UserDoesNotExistException(uuid);
}
return getMoneyExact(user);
}
public static BigDecimal getMoneyExact(User user) {
if (user == null) {
throw new IllegalArgumentException("Economy user cannot be null");
}
return user.getMoney();
}
/**
* Sets the balance of a user
*
* @deprecated Use {@link Economy#setMoney(UUID, BigDecimal)} or {@link Economy#setMoney(User, BigDecimal)}
*
* @param name Name of the user
* @param balance The balance you want to set
*
@@ -132,11 +170,55 @@ public class Economy {
}
}
/**
* Sets the balance of a user
*
* @deprecated Usernames can change use {@link Economy#setMoney(UUID, BigDecimal)} or {@link Economy#setMoney(User, BigDecimal)}
*
* @param name Name of user
* @param balance The balance you want to set
*
* @throws UserDoesNotExistException If a user by that name does not exist
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
*/
@Deprecated
public static void setMoney(String name, BigDecimal balance) throws UserDoesNotExistException, NoLoanPermittedException {
User user = getUserByName(name);
if (user == null) {
throw new UserDoesNotExistException(name);
}
setMoney(user, balance);
}
/**
* Sets the balance of a user
*
* @param uuid UUID of user
* @param balance The balance you want to set
*
* @throws UserDoesNotExistException If a user by that uuid does not exist
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
*/
public static void setMoney(UUID uuid, BigDecimal balance) throws NoLoanPermittedException, UserDoesNotExistException {
User user = getUserByUUID(uuid);
if (user == null) {
throw new UserDoesNotExistException(uuid);
}
setMoney(user, balance);
}
/**
* Sets the balance of a user
*
* @param user User
* @param balance The balance you want to set
*
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
*/
public static void setMoney(User user, BigDecimal balance) throws NoLoanPermittedException {
if (user == null) {
throw new IllegalArgumentException("Economy user cannot be null");
}
if (balance.compareTo(ess.getSettings().getMinMoney()) < 0) {
throw new NoLoanPermittedException();
}
@@ -144,16 +226,18 @@ public class Economy {
throw new NoLoanPermittedException();
}
try {
user.setMoney(balance);
user.setMoney(balance, UserBalanceUpdateEvent.Cause.API);
} catch (MaxMoneyException ex) {
//TODO: Update API to show max balance errors
}
Trade.log("API", "Set", "API", name, new Trade(balance, ess), null, null, null, ess);
Trade.log("API", "Set", "API", user.getName(), new Trade(balance, ess), null, null, null, ess);
}
/**
* Adds money to the balance of a user
*
* Use {@link Economy#add(UUID, BigDecimal)} or {@link Economy#add(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The money you want to add
*
@@ -169,17 +253,72 @@ public class Economy {
}
}
/**
* Adds money to the balance of a user
*
* @deprecated Usernames can change, use {@link Economy#add(UUID, BigDecimal)} or {@link Economy#add(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The amount of money to be added to the user's account
*
* @throws UserDoesNotExistException If a user by that name does not exist
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
* @throws ArithmeticException
*/
@Deprecated
public static void add(String name, BigDecimal amount) throws UserDoesNotExistException, NoLoanPermittedException, ArithmeticException {
BigDecimal result = getMoneyExact(name).add(amount, MATH_CONTEXT);
setMoney(name, result);
Trade.log("API", "Add", "API", name, new Trade(amount, ess), null, null, null, ess);
User user = getUserByName(name);
if (user == null) {
throw new UserDoesNotExistException(name);
}
add(user, amount);
}
/**
* Substracts money from the balance of a user
* Adds money to the balance of a user
*
* @param uuid UUID of the user
* @param amount The money you want to add
*
* @throws UserDoesNotExistException If a user by that uuid does not exist
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
* @throws ArithmeticException
*/
public static void add(UUID uuid, BigDecimal amount) throws NoLoanPermittedException, ArithmeticException, UserDoesNotExistException {
User user = getUserByUUID(uuid);
if (user == null) {
throw new UserDoesNotExistException(uuid);
}
add(user, amount);
}
/**
* Adds money to the balance of a user
*
* @deprecated Usernames can change, use {@link Economy#add(UUID, BigDecimal)} or {@link Economy#add(User, BigDecimal)}
*
* @param user User
* @param amount The money you want to add
*
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
* @throws ArithmeticException
*/
public static void add(User user, BigDecimal amount) throws NoLoanPermittedException, ArithmeticException {
if (user == null) {
throw new IllegalArgumentException("Economy user cannot be null");
}
BigDecimal result = getMoneyExact(user).add(amount, MATH_CONTEXT);
setMoney(user, result);
Trade.log("API", "Add", "API", user.getName(), new Trade(amount, ess), null, null, null, ess);
}
/**
* Subtracts money from the balance of a user
*
* @deprecated Use {@link Economy#subtract(UUID, BigDecimal)} or {@link Economy#subtract(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The money you want to substract
* @param amount The money you want to subtract
*
* @throws UserDoesNotExistException If a user by that name does not exists
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
@@ -189,19 +328,70 @@ public class Economy {
try {
substract(name, BigDecimal.valueOf(amount));
} catch (ArithmeticException e) {
logger.log(Level.WARNING, "Failed to substract " + amount + " of balance of " + name + ": " + e.getMessage(), e);
logger.log(Level.WARNING, "Failed to subtract " + amount + " of balance of " + name + ": " + e.getMessage(), e);
}
}
/**
* Subtracts money from the balance of a user
*
* @deprecated Usernames can change, use {@link Economy#subtract(UUID, BigDecimal)} or {@link Economy#subtract(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The money you want to subtract
*
* @throws UserDoesNotExistException If a user by that name does not exist
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
* @throws ArithmeticException
*/
@Deprecated
public static void substract(String name, BigDecimal amount) throws UserDoesNotExistException, NoLoanPermittedException, ArithmeticException {
BigDecimal result = getMoneyExact(name).subtract(amount, MATH_CONTEXT);
setMoney(name, result);
Trade.log("API", "Subtract", "API", name, new Trade(amount, ess), null, null, null, ess);
}
/**
* Subtracts money from the balance of a user
*
* @param uuid UUID of the user
* @param amount The money you want to subtract
*
* @throws UserDoesNotExistException If a user by that UUID does not exist
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
* @throws ArithmeticException
*/
public static void subtract(UUID uuid, BigDecimal amount) throws NoLoanPermittedException, ArithmeticException, UserDoesNotExistException {
User user = getUserByUUID(uuid);
if (user == null) {
throw new UserDoesNotExistException(uuid);
}
subtract(user, amount);
}
/**
* Subtracts money from the balance of a user
*
* @param user User
* @param amount The money you want to subtract
*
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
* @throws ArithmeticException
*/
public static void subtract(User user, BigDecimal amount) throws NoLoanPermittedException, ArithmeticException {
if (user == null) {
throw new IllegalArgumentException("Economy user cannot be null");
}
BigDecimal result = getMoneyExact(user).subtract(amount, MATH_CONTEXT);
setMoney(user, result);
Trade.log("API", "Subtract", "API", user.getName(), new Trade(amount, ess), null, null, null, ess);
}
/**
* Divides the balance of a user by a value
*
* @deprecated Use {@link Economy#divide(UUID, BigDecimal)} or {@link Economy#divide(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The balance is divided by this value
*
@@ -217,15 +407,68 @@ public class Economy {
}
}
/**
* Divides the balance of a user by a value
*
* @deprecated Usernames can change, use {@link Economy#divide(UUID, BigDecimal)} or {@link Economy#divide(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The balance is divided by this value
*
* @throws UserDoesNotExistException If a user by that name does not exist
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
* @throws ArithmeticException
*/
@Deprecated
public static void divide(String name, BigDecimal amount) throws UserDoesNotExistException, NoLoanPermittedException, ArithmeticException {
BigDecimal result = getMoneyExact(name).divide(amount, MATH_CONTEXT);
setMoney(name, result);
Trade.log("API", "Divide", "API", name, new Trade(amount, ess), null, null, null, ess);
User user = getUserByName(name);
if (user == null) {
throw new UserDoesNotExistException(name);
}
divide(user, amount);
}
/**
* Divides the balance of a user by a value
*
* @param uuid Name of the user
* @param amount The balance is divided by this value
*
* @throws UserDoesNotExistException If a user by that UUID does not exist
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
* @throws ArithmeticException
*/
public static void divide(UUID uuid, BigDecimal amount) throws NoLoanPermittedException, ArithmeticException, UserDoesNotExistException {
User user = getUserByUUID(uuid);
if (user == null) {
throw new UserDoesNotExistException(uuid);
}
divide(user, amount);
}
/**
* Divides the balance of a user by a value
*
* @param user Name of the user
* @param amount The balance is divided by this value
*
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
* @throws ArithmeticException
*/
public static void divide(User user, BigDecimal amount) throws NoLoanPermittedException, ArithmeticException {
if (user == null) {
throw new IllegalArgumentException("Economy user cannot be null");
}
BigDecimal result = getMoneyExact(user).divide(amount, MATH_CONTEXT);
setMoney(user, result);
Trade.log("API", "Divide", "API", user.getName(), new Trade(amount, ess), null, null, null, ess);
}
/**
* Multiplies the balance of a user by a value
*
* @deprecated Use {@link Economy#multiply(UUID, BigDecimal)} or {@link Economy#multiply(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The balance is multiplied by this value
*
@@ -241,20 +484,74 @@ public class Economy {
}
}
/**
* Multiplies the balance of a user by a value
*
* @deprecated Usernames can change, use {@link Economy#multiply(UUID, BigDecimal)} or {@link Economy#multiply(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The balance is multiplied by the this value
*
* @throws UserDoesNotExistException If a user by that name does not exist
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
* @throws ArithmeticException
*/
@Deprecated
public static void multiply(String name, BigDecimal amount) throws UserDoesNotExistException, NoLoanPermittedException, ArithmeticException {
BigDecimal result = getMoneyExact(name).multiply(amount, MATH_CONTEXT);
setMoney(name, result);
Trade.log("API", "Multiply", "API", name, new Trade(amount, ess), null, null, null, ess);
User user = getUserByName(name);
if (user == null) {
throw new UserDoesNotExistException(name);
}
multiply(user, amount);
}
/**
* Multiplies the balance of a user by a value
*
* @param uuid Name of the user
* @param amount The balance is multiplied by the this value
*
* @throws UserDoesNotExistException If a user by that uuid does not exist
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
* @throws ArithmeticException
*/
public static void multiply(UUID uuid, BigDecimal amount) throws NoLoanPermittedException, ArithmeticException, UserDoesNotExistException {
User user = getUserByUUID(uuid);
if (user == null) {
throw new UserDoesNotExistException(uuid);
}
multiply(user, amount);
}
/**
* Multiplies the balance of a user by a value
*
* @param user Name of the user
* @param amount The balance is multiplied by the this value
*
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
* @throws ArithmeticException
*/
public static void multiply(User user, BigDecimal amount) throws NoLoanPermittedException, ArithmeticException {
if (user == null) {
throw new IllegalArgumentException("Economy user cannot be null");
}
BigDecimal result = getMoneyExact(user).multiply(amount, MATH_CONTEXT);
setMoney(user, result);
Trade.log("API", "Multiply", "API", user.getName(), new Trade(amount, ess), null, null, null, ess);
}
/**
* Resets the balance of a user to the starting balance
*
* @deprecated Usernames can change, use {@link Economy#resetBalance(UUID)} or {@link Economy#resetBalance(User)}
*
* @param name Name of the user
*
* @throws UserDoesNotExistException If a user by that name does not exists
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
*/
@Deprecated
public static void resetBalance(String name) throws UserDoesNotExistException, NoLoanPermittedException {
if (ess == null) {
throw new RuntimeException(noCallBeforeLoad);
@@ -264,6 +561,42 @@ public class Economy {
}
/**
* Resets the balance of a user to the starting balance
*
* @param uuid UUID of the user
*
* @throws UserDoesNotExistException If a user by that UUID does not exists
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
*/
public static void resetBalance(UUID uuid) throws NoLoanPermittedException, UserDoesNotExistException {
User user = getUserByUUID(uuid);
if (user == null) {
throw new UserDoesNotExistException(uuid);
}
resetBalance(user);
}
/**
* Resets the balance of a user to the starting balance
*
* @param user User
*
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
*/
public static void resetBalance(User user) throws NoLoanPermittedException {
if (ess == null) {
throw new RuntimeException(noCallBeforeLoad);
}
if (user == null) {
throw new IllegalArgumentException("Economy user cannot be null");
}
setMoney(user, ess.getSettings().getStartingBalance());
Trade.log("API", "Reset", "API", user.getName(), new Trade(BigDecimal.ZERO, ess), null, null, null, ess);
}
/**
* @deprecated Use {@link Economy#hasEnough(UUID, BigDecimal)} or {@link Economy#hasEnough(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The amount of money the user should have
*
@@ -281,11 +614,60 @@ public class Economy {
}
}
/**
* @deprecated Usernames can change, use {@link Economy#hasEnough(UUID, BigDecimal)} or {@link Economy#hasEnough(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The amount of money the user should have
*
* @return true, if the user has more or an equal amount of money
*
* @throws UserDoesNotExistException If a user by that name does not exist
* @throws ArithmeticException
*/
public static boolean hasEnough(String name, BigDecimal amount) throws UserDoesNotExistException, ArithmeticException {
return amount.compareTo(getMoneyExact(name)) <= 0;
User user = getUserByName(name);
if (user == null) {
throw new UserDoesNotExistException(name);
}
return hasEnough(user, amount);
}
/**
* @param uuid UUID of the user
* @param amount The amount of money the user should have
*
* @return true, if the user has more or an equal amount of money
*
* @throws UserDoesNotExistException If a user by that UUID does not exist
* @throws ArithmeticException
*/
public static boolean hasEnough(UUID uuid, BigDecimal amount) throws ArithmeticException, UserDoesNotExistException {
User user = getUserByUUID(uuid);
if (user == null) {
throw new UserDoesNotExistException(uuid);
}
return hasEnough(user, amount);
}
/**
* @param user User
* @param amount The amount of money the user should have
*
* @return true, if the user has more or an equal amount of money
*
* @throws ArithmeticException
*/
public static boolean hasEnough(User user, BigDecimal amount) throws ArithmeticException {
if (user == null) {
throw new IllegalArgumentException("Economy user cannot be null");
}
return amount.compareTo(getMoneyExact(user)) <= 0;
}
/**
* @deprecated Use {@link Economy#hasMore(UUID, BigDecimal)} or {@link Economy#hasMore(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The amount of money the user should have
*
@@ -303,11 +685,61 @@ public class Economy {
}
}
/**
* @deprecated Usernames can change, use {@link Economy#hasMore(UUID, BigDecimal)} or {@link Economy#hasMore(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The amount of money the user should have
*
* @return true, if the user has more money
*
* @throws UserDoesNotExistException If a user by that name does not exists
* @throws ArithmeticException
*/
@Deprecated
public static boolean hasMore(String name, BigDecimal amount) throws UserDoesNotExistException, ArithmeticException {
return amount.compareTo(getMoneyExact(name)) < 0;
User user = getUserByName(name);
if (user == null) {
throw new UserDoesNotExistException(name);
}
return hasMore(user, amount);
}
/**
* @param uuid UUID of the user
* @param amount The amount of money the user should have
*
* @return true, if the user has more money
*
* @throws UserDoesNotExistException If a user by that UUID does not exists
* @throws ArithmeticException
*/
public static boolean hasMore(UUID uuid, BigDecimal amount) throws ArithmeticException, UserDoesNotExistException {
User user = getUserByUUID(uuid);
if (user == null) {
throw new UserDoesNotExistException(uuid);
}
return hasMore(user, amount);
}
/**
* @param user User
* @param amount The amount of money the user should have
*
* @return true, if the user has more money
*
* @throws ArithmeticException
*/
public static boolean hasMore(User user, BigDecimal amount) throws ArithmeticException {
if (user == null) {
throw new IllegalArgumentException("Economy user cannot be null");
}
return amount.compareTo(getMoneyExact(user)) < 0;
}
/**
* @deprecated Use {@link Economy#hasLess(UUID, BigDecimal)} or {@link Economy#hasLess(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The amount of money the user should not have
*
@@ -325,12 +757,62 @@ public class Economy {
}
}
/**
* @deprecated Usernames can change, use {@link Economy#hasLess(UUID, BigDecimal)} or {@link Economy#hasLess(User, BigDecimal)}
*
* @param name Name of the user
* @param amount The amount of money the user should not have
*
* @return true, if the user has less money
*
* @throws UserDoesNotExistException If a user by that name does not exist
* @throws ArithmeticException
*/
@Deprecated
public static boolean hasLess(String name, BigDecimal amount) throws UserDoesNotExistException, ArithmeticException {
return amount.compareTo(getMoneyExact(name)) > 0;
User user = getUserByName(name);
if (user == null) {
throw new UserDoesNotExistException(name);
}
return hasLess(user, amount);
}
/**
* @param uuid UUID of the user
* @param amount The amount of money the user should not have
*
* @return true, if the user has less money
*
* @throws UserDoesNotExistException If a user by that UUID does not exist
* @throws ArithmeticException
*/
public static boolean hasLess(UUID uuid, BigDecimal amount) throws ArithmeticException, UserDoesNotExistException {
User user = getUserByUUID(uuid);
if (user == null) {
throw new UserDoesNotExistException(uuid);
}
return hasLess(user, amount);
}
/**
* @param user User
* @param amount The amount of money the user should not have
*
* @return true, if the user has less money
*
* @throws ArithmeticException
*/
public static boolean hasLess(User user, BigDecimal amount) throws ArithmeticException {
if (user == null) {
throw new IllegalArgumentException("Economy user cannot be null");
}
return amount.compareTo(getMoneyExact(user)) > 0;
}
/**
* Test if the user has a negative balance
*
* @deprecated Usernames can change, use {@link Economy#isNegative(UUID)} or {@link Economy#isNegative(User)}
*
* @param name Name of the user
*
@@ -338,8 +820,44 @@ public class Economy {
*
* @throws UserDoesNotExistException If a user by that name does not exists
*/
@Deprecated
public static boolean isNegative(String name) throws UserDoesNotExistException {
return getMoneyExact(name).signum() < 0;
User user = getUserByName(name);
if (user == null) {
throw new UserDoesNotExistException(name);
}
return isNegative(user);
}
/**
* Test if the user has a negative balance
*
* @param uuid UUID of the user
*
* @return true, if the user has a negative balance
*
* @throws UserDoesNotExistException If a user by that UUID does not exists
*/
public static boolean isNegative(UUID uuid) throws UserDoesNotExistException {
User user = getUserByUUID(uuid);
if (user == null) {
throw new UserDoesNotExistException(uuid);
}
return isNegative(user);
}
/**
* Test if the user has a negative balance
*
* @param user User
*
* @return true, if the user has a negative balance
*/
public static boolean isNegative(User user) {
if (user == null) {
throw new IllegalArgumentException("Economy user cannot be null");
}
return getMoneyExact(user).signum() < 0;
}
/**
@@ -369,14 +887,28 @@ public class Economy {
/**
* Test if a player exists to avoid the UserDoesNotExistException
*
* @deprecated Essentials is moving away from username based economy methods. This may be removed in the future.
*
* @param name Name of the user
*
* @return true, if the user exists
*/
@Deprecated
public static boolean playerExists(String name) {
return getUserByName(name) != null;
}
/**
* Test if a player exists to avoid the UserDoesNotExistException
*
* @param uuid UUID of the user
*
* @return true, if the user exists
*/
public static boolean playerExists(UUID uuid) {
return getUserByUUID(uuid) != null;
}
/**
* Test if a player is a npc
*
@@ -0,0 +1,123 @@
package com.earth2me.essentials.api;
import com.earth2me.essentials.Trade;
import net.ess3.api.IUser;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent;
import java.util.concurrent.CompletableFuture;
public interface IAsyncTeleport {
/**
* Used to skip teleportPlayer delay when teleporting someone to a location or player.
*
* @param loc - Where should the player end up
* @param cooldown - If cooldown should be enforced
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void now(Location loc, boolean cooldown, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Used to skip teleportPlayer delay when teleporting someone to a location or player.
*
* @param entity - Where should the player end up
* @param cooldown - If cooldown should be enforced
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void now(Player entity, boolean cooldown, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport a player to a specific location
*
* @param loc - Where should the player end up
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param cause - The reported teleportPlayer cause.
* @param future - Future which is completed with the success status of the execution
*/
void teleport(Location loc, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport a player to a specific player
*
* @param entity - Where should the player end up
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void teleport(Player entity, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport a player to a specific location
*
* @param otherUser - Which user will be teleported
* @param loc - Where should the player end up
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void teleportPlayer(IUser otherUser, Location loc, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport a player to a specific player
*
* @param otherUser - Which user will be teleported
* @param entity - Where should the player end up
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void teleportPlayer(IUser otherUser, Player entity, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport wrapper used to handle tp fallback on /jail and /home
*
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void respawn(final Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport wrapper used to handle /warp teleports
*
* @param otherUser - Which user will be teleported
* @param warp - The name of the warp the user will be teleported too.
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void warp(IUser otherUser, String warp, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport wrapper used to handle /back teleports
*
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param future - Future which is completed with the success status of the execution
*/
void back(Trade chargeFor, CompletableFuture<Boolean> future);
/**
* Teleport wrapper used to handle /back teleports that
* are executed by a different player with this
* instance of teleport as a target.
*
* @param teleporter - The user performing the /back command.
* This value may be {@code null} to indicate console.
* @param chargeFor - What the {@code teleporter} will be charged if teleportPlayer is successful
* @param future - Future which is completed with the success status of the execution
*/
void back(IUser teleporter, Trade chargeFor, CompletableFuture<Boolean> future);
/**
* Teleport wrapper used to handle throwing user home after a jail sentence
*
* @param future - Future which is completed with the success status of the execution
*/
void back(CompletableFuture<Boolean> future);
}
@@ -1,11 +1,9 @@
package com.earth2me.essentials.api;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import net.ess3.api.IEssentials;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
@@ -55,7 +53,7 @@ public interface IItemDb {
nameList = nameList.subList(0, 14);
}
return StringUtil.joinList(", ", nameList);
};
}
/**
* Get a List of all aliases for the given item stack.
@@ -85,13 +83,12 @@ public interface IItemDb {
List<ItemStack> getMatching(User user, String[] args) throws Exception;
/**
* Serialise an ItemStack into a format that can be decoded by
* {@link #get(String) get} and
* {@link com.earth2me.essentials.MetaItemStack#parseStringMeta(CommandSource, boolean, String[], int, IEssentials)} MetaItemStack#parseStringMeta}.
* Used to encode items for kits.
* Converts the given {@link ItemStack} to a string representation that can be saved.
* This is typically used for /createkit but can be used by other plugins for various purposes too.
* Note that this will try registered resolvers first - to avoid this, use {@link net.ess3.api.IItemDb#serialize(ItemStack, boolean)} instead.
*
* @param is Stack to serialise
* @return Serialised stack
* @param is The stack to serialize
* @return A string representing the given stack
*/
String serialize(ItemStack is);
@@ -130,11 +127,13 @@ public interface IItemDb {
* item IDs to modern names.
*
* @param item Legacy ID in colon syntax.
* @return
* @return Material if an appropriate material exists, else null.
*/
default Material getFromLegacy(String item) {
final String[] split = item.split(":");
if (!NumberUtil.isInt(split[0])) return null;
final int id = Integer.parseInt(split[0]);
byte damage = 0;
@@ -4,6 +4,7 @@ import net.ess3.api.IUser;
import org.bukkit.Location;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
public interface IJails extends IReload {
@@ -46,13 +47,27 @@ public interface IJails extends IReload {
/**
* Attempts to send the given user to the given jail
*
* @deprecated Use {@link IJails#sendToJail(IUser, String, CompletableFuture)}
*
* @param user the user to send to jail
* @param jail the jail to send the user to
*
* @throws Exception if the user is offline or jail does not exist
*/
@Deprecated
void sendToJail(IUser user, String jail) throws Exception;
/**
* Attempts to send the given user to the given jail
*
* @param user the user to send to jail
* @param jail the jail to send the user to
* @param future Future which is completed with the success status of the execution
*
* @throws Exception if the user is offline or jail does not exist
*/
void sendToJail(IUser user, String jail, CompletableFuture<Boolean> future) throws Exception;
/**
* Set a new jail with the given name and location
*
@@ -7,6 +7,9 @@ import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent;
/**
* @deprecated This API is not asynchronous. Use {@link com.earth2me.essentials.api.IAsyncTeleport IAsyncTeleport}
*/
public interface ITeleport {
/**
* Used to skip teleportPlayer delay when teleporting someone to a location or player.
@@ -17,6 +20,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void now(Location loc, boolean cooldown, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -28,6 +32,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void now(Player entity, boolean cooldown, PlayerTeleportEvent.TeleportCause cause) throws Exception;
@Deprecated
@@ -42,6 +47,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void teleport(Location loc, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -53,6 +59,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void teleport(Player entity, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -65,6 +72,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void teleportPlayer(IUser otherUser, Location loc, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -77,6 +85,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void teleportPlayer(IUser otherUser, Player entity, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -87,6 +96,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void respawn(final Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -99,6 +109,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void warp(IUser otherUser, String warp, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -108,6 +119,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void back(Trade chargeFor) throws Exception;
/**
@@ -117,10 +129,11 @@ public interface ITeleport {
*
* @param teleporter - The user performing the /back command.
* This value may be {@code null} to indicate console.
* @param chargeFor - What the {@code teleporter} will be charged if teleportPlayer is successful
* @param chargeFor - What the {@code teleporter} will be charged if teleportPlayer is successful
*
* @throws Exception
*/
@Deprecated
void back(IUser teleporter, Trade chargeFor) throws Exception;
/**
@@ -128,6 +141,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void back() throws Exception;
}
@@ -70,7 +70,7 @@ public interface IWarps extends IConf {
/**
* Gets Lastowner UUID
*
* @param name - Name of warp
* @param warp - Name of warp
*
* @throws WarpNotFoundException
*/
@@ -1,5 +1,7 @@
package com.earth2me.essentials.api;
import java.util.UUID;
import static com.earth2me.essentials.I18n.tl;
@@ -7,4 +9,8 @@ public class UserDoesNotExistException extends Exception {
public UserDoesNotExistException(String name) {
super(tl("userDoesNotExist", name));
}
public UserDoesNotExistException(UUID uuid) {
super(tl("uuidDoesNotExist", uuid.toString()));
}
}
@@ -2,6 +2,8 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.DateUtil;
import net.ess3.api.events.AfkStatusChangeEvent;
import org.bukkit.Server;
import java.util.Collections;
@@ -24,10 +26,6 @@ public class Commandafk extends EssentialsCommand {
afkUser = getPlayer(server, user, args, 0);
message = args.length > 1 ? getFinalArg(args, 1) : null;
} catch (PlayerNotFoundException e) {
// If only one arg is passed, assume the command executor is targeting another player.
if (args.length == 1) {
throw e;
}
message = getFinalArg(args, 0);
}
toggleAfk(user, afkUser, message);
@@ -51,7 +49,11 @@ public class Commandafk extends EssentialsCommand {
private void toggleAfk(User sender, User user, String message) throws Exception {
if (message != null && sender != null) {
if (sender.isMuted()) {
throw new Exception(sender.hasMuteReason() ? tl("voiceSilencedReason", sender.getMuteReason()) : tl("voiceSilenced"));
String dateDiff = sender.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(sender.getMuteTimeout()) : null;
if (dateDiff == null) {
throw new Exception(sender.hasMuteReason() ? tl("voiceSilencedReason", sender.getMuteReason()) : tl("voiceSilenced"));
}
throw new Exception(sender.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, sender.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
}
if (!sender.isAuthorized("essentials.afk.message")) {
throw new Exception(tl("noPermToAFKMessage"));
@@ -59,25 +61,31 @@ public class Commandafk extends EssentialsCommand {
}
user.setDisplayNick();
String msg = "";
if (!user.toggleAfk()) {
//user.sendMessage(_("markedAsNotAway"));
String selfmsg = "";
if (!user.toggleAfk(AfkStatusChangeEvent.Cause.COMMAND)) {
if (!user.isHidden()) {
msg = tl("userIsNotAway", user.getDisplayName());
selfmsg = tl("userIsNotAwaySelf", user.getDisplayName());
}
user.updateActivity(false);
user.updateActivity(false, AfkStatusChangeEvent.Cause.COMMAND);
} else {
//user.sendMessage(_("markedAsAway"));
if (!user.isHidden()) {
if (message != null) {
msg = tl("userIsAwayWithMessage", user.getDisplayName(), message);
selfmsg = tl("userIsAwaySelfWithMessage", user.getDisplayName(), message);
} else {
msg = tl("userIsAway", user.getDisplayName());
selfmsg = tl("userIsAwaySelf", user.getDisplayName());
}
}
user.setAfkMessage(message);
}
if (!msg.isEmpty()) {
ess.broadcastMessage(user, msg);
if (!msg.isEmpty() && ess.getSettings().broadcastAfkMessage()) {
// exclude user from receiving general AFK announcement in favor of personal message
ess.broadcastMessage(user, msg, u -> u == user);
}
if (!selfmsg.isEmpty()) {
user.sendMessage(selfmsg);
}
user.setDisplayNick(); // Set this again after toggling
}
@@ -23,11 +23,11 @@ public class Commandback extends EssentialsCommand {
protected void run(Server server, User user, String commandLabel, String[] args) throws Exception {
CommandSource sender = user.getSource();
if (args.length > 0 && user.isAuthorized("essentials.back.others")) {
this.parseCommand(server, sender, args, true);
this.parseCommand(server, sender, args, true, commandLabel);
return;
}
teleportBack(sender, user);
teleportBack(sender, user, commandLabel);
}
@Override
@@ -36,10 +36,10 @@ public class Commandback extends EssentialsCommand {
throw new NotEnoughArgumentsException();
}
this.parseCommand(server, sender, args, true);
this.parseCommand(server, sender, args, true, commandLabel);
}
private void parseCommand(Server server, CommandSource sender, String[] args, boolean allowOthers) throws Exception {
private void parseCommand(Server server, CommandSource sender, String[] args, boolean allowOthers, String commandLabel) throws Exception {
Collection<Player> players = new ArrayList<>();
if (allowOthers && args.length > 0 && args[0].trim().length() > 2) {
@@ -52,11 +52,11 @@ public class Commandback extends EssentialsCommand {
for (Player player : players) {
sender.sendMessage(tl("backOther", player.getName()));
teleportBack(sender, ess.getUser(player));
teleportBack(sender, ess.getUser(player), commandLabel);
}
}
private void teleportBack(CommandSource sender, User user) throws Exception {
private void teleportBack(CommandSource sender, User user, String commandLabel) throws Exception {
if (user.getLastLocation() == null) {
throw new Exception(tl("noLocationFound"));
}
@@ -77,15 +77,15 @@ public class Commandback extends EssentialsCommand {
}
if (requester == null) {
user.getTeleport().back(null, null);
user.getAsyncTeleport().back(null, null, getNewExceptionFuture(sender, commandLabel));
} else if (!requester.equals(user)) {
Trade charge = new Trade(this.getName(), this.ess);
charge.isAffordableFor(requester);
user.getTeleport().back(requester, charge);
user.getAsyncTeleport().back(requester, charge, getNewExceptionFuture(sender, commandLabel));
} else {
Trade charge = new Trade(this.getName(), this.ess);
charge.isAffordableFor(user);
user.getTeleport().back(charge);
user.getAsyncTeleport().back(charge, getNewExceptionFuture(sender, commandLabel));
}
throw new NoChargeException();
}
@@ -23,7 +23,7 @@ public class Commandbalance extends EssentialsCommand {
throw new NotEnoughArgumentsException();
}
User target = getPlayer(server, args, 0, true, true);
User target = getPlayer(server, args, 0, false, true);
sender.sendMessage(tl("balanceOther", target.isHidden() ? target.getName() : target.getDisplayName(), NumberUtil.displayCurrency(target.getMoney(), ess)));
}
@@ -11,7 +11,6 @@ import org.bukkit.Server;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import static com.earth2me.essentials.I18n.tl;
@@ -88,7 +87,7 @@ public class Commandbalancetop extends EssentialsCommand {
try {
if (force || cacheage <= System.currentTimeMillis() - CACHETIME) {
cache.getLines().clear();
final Map<String, BigDecimal> balances = new HashMap<String, BigDecimal>();
final Map<String, BigDecimal> balances = new HashMap<>();
BigDecimal totalMoney = BigDecimal.ZERO;
if (ess.getSettings().isEcoDisabled()) {
if (ess.getSettings().isDebug()) {
@@ -113,13 +112,8 @@ public class Commandbalancetop extends EssentialsCommand {
}
}
final List<Map.Entry<String, BigDecimal>> sortedEntries = new ArrayList<Map.Entry<String, BigDecimal>>(balances.entrySet());
Collections.sort(sortedEntries, new Comparator<Map.Entry<String, BigDecimal>>() {
@Override
public int compare(final Entry<String, BigDecimal> entry1, final Entry<String, BigDecimal> entry2) {
return entry2.getValue().compareTo(entry1.getValue());
}
});
final List<Map.Entry<String, BigDecimal>> sortedEntries = new ArrayList<>(balances.entrySet());
sortedEntries.sort((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue()));
cache.getLines().add(tl("serverTotal", NumberUtil.displayCurrency(totalMoney, ess)));
int pos = 1;
@@ -0,0 +1,35 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.Mob;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.entity.Entity;
import static com.earth2me.essentials.I18n.tl;
public class Commandbeezooka extends EssentialsCommand {
public Commandbeezooka() {
super("beezooka");
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_15_R01)) {
user.sendMessage(tl("unsupportedFeature"));
return;
}
final Entity bee = Mob.BEE.spawn(user.getWorld(), server, user.getBase().getEyeLocation());
bee.setVelocity(user.getBase().getEyeLocation().getDirection().multiply(2));
ess.scheduleSyncDelayedTask(() -> {
final Location loc = bee.getLocation();
bee.remove();
loc.getWorld().createExplosion(loc, 0F);
}, 20);
}
}
@@ -33,9 +33,11 @@ public class Commandbigtree extends EssentialsCommand {
throw new NotEnoughArgumentsException();
}
final Location loc = LocationUtil.getTarget(user.getBase());
final Location safeLocation = LocationUtil.getSafeDestination(loc);
final boolean success = user.getWorld().generateTree(safeLocation, tree);
final Location loc = LocationUtil.getTarget(user.getBase()).add(0, 1, 0);
if (!user.getWorld().getBlockAt(loc).isPassable()) {
throw new Exception(tl("bigTreeFailure"));
}
final boolean success = user.getWorld().generateTree(loc, tree);
if (success) {
user.sendMessage(tl("bigTreeSuccess"));
} else {
@@ -6,8 +6,6 @@ import org.bukkit.Server;
import org.bukkit.block.Block;
import org.bukkit.event.block.BlockBreakEvent;
import java.util.Set;
import static com.earth2me.essentials.I18n.tl;
@@ -19,7 +17,7 @@ public class Commandbreak extends EssentialsCommand {
//TODO: Switch to use util class
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final Block block = user.getBase().getTargetBlock((Set<Material>) null, 20);
final Block block = user.getBase().getTargetBlock(null, 20);
if (block == null) {
throw new NoChargeException();
}
@@ -1,13 +1,11 @@
package com.earth2me.essentials.commands;
import static com.earth2me.essentials.I18n.tl;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.entity.Player;
@@ -15,6 +13,8 @@ import org.bukkit.inventory.ItemStack;
import java.util.*;
import static com.earth2me.essentials.I18n.tl;
public class Commandclearinventory extends EssentialsCommand {
@@ -38,10 +38,10 @@ public class Commandclearinventory extends EssentialsCommand {
private void parseCommand(Server server, CommandSource sender, String commandLabel, String[] args, boolean allowOthers, boolean allowAll)
throws Exception {
Collection<Player> players = new ArrayList<Player>();
Collection<Player> players = new ArrayList<>();
User senderUser = ess.getUser(sender.getPlayer());
String previousClearCommand = "";
int offset = 0;
if (sender.isPlayer()) {
@@ -80,39 +80,65 @@ public class Commandclearinventory extends EssentialsCommand {
}
}
protected void clearHandler(CommandSource sender, Player player, String[] args, int offset, boolean showExtended) throws Exception {
short data = -1;
int type = -1;
private static class Item {
private Material material;
private short data;
public Item(Material material, short data) {
this.material = material;
this.data = data;
}
public Material getMaterial() {
return material;
}
public short getData() {
return data;
}
}
private enum ClearHandlerType {
ALL_EXCEPT_ARMOR, ALL_INCLUDING_ARMOR, SPECIFIC_ITEM
}
protected void clearHandler(CommandSource sender, Player player, String[] args, int offset, boolean showExtended) {
ClearHandlerType type = ClearHandlerType.ALL_EXCEPT_ARMOR;
final Set<Item> items = new HashSet<>();
int amount = -1;
final Set<Material> mats = new HashSet<>();
if (args.length > (offset + 1) && NumberUtil.isInt(args[(offset + 1)])) {
amount = Integer.parseInt(args[(offset + 1)]);
}
if (args.length > offset) {
if (args[offset].equalsIgnoreCase("**")) {
type = -2;
type = ClearHandlerType.ALL_INCLUDING_ARMOR;
} else if (!args[offset].equalsIgnoreCase("*")) {
final String[] split = args[offset].split(",");
for (String name : split) {
for (String item : split) {
final String[] itemParts = item.split(":");
short data;
try {
mats.add(ess.getItemDb().get(name).getType());
data = Short.parseShort(itemParts[1]);
} catch (Exception e) {
data = 0;
}
try {
items.add(new Item(ess.getItemDb().get(itemParts[0]).getType(), data));
} catch (Exception ignored) {}
}
type = 1;
type = ClearHandlerType.SPECIFIC_ITEM;
}
}
if (type == -1) // type -1 represents wildcard or all items
if (type == ClearHandlerType.ALL_EXCEPT_ARMOR)
{
if (showExtended) {
sender.sendMessage(tl("inventoryClearingAllItems", player.getDisplayName()));
}
InventoryWorkaround.clearInventoryNoArmor(player.getInventory());
InventoryWorkaround.setItemInOffHand(player, null);
} else if (type == -2) // type -2 represents double wildcard or all items and armor
} else if (type == ClearHandlerType.ALL_INCLUDING_ARMOR)
{
if (showExtended) {
sender.sendMessage(tl("inventoryClearingAllArmor", player.getDisplayName()));
@@ -121,20 +147,21 @@ public class Commandclearinventory extends EssentialsCommand {
InventoryWorkaround.setItemInOffHand(player, null);
player.getInventory().setArmorContents(null);
} else {
for (Material mat : mats) {
for (Item item : items) {
ItemStack stack = new ItemStack(item.getMaterial());
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_13_0_R01)) {
stack.setDurability(item.getData());
}
if (amount == -1) // amount -1 means all items will be cleared
{
ItemStack stack = new ItemStack(mat, BASE_AMOUNT, data);
stack.setAmount(BASE_AMOUNT);
ItemStack removedStack = player.getInventory().removeItem(stack).get(0);
final int removedAmount = (BASE_AMOUNT - removedStack.getAmount());
if (removedAmount > 0 || showExtended) {
sender.sendMessage(tl("inventoryClearingStack", removedAmount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName()));
}
} else {
if (amount < 0) {
amount = 1;
}
ItemStack stack = new ItemStack(mat, amount);
stack.setAmount(amount < 0 ? 1 : amount);
if (player.getInventory().containsAtLeast(stack, amount)) {
sender.sendMessage(tl("inventoryClearingStack", amount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName()));
player.getInventory().removeItem(stack);
@@ -195,6 +222,6 @@ public class Commandclearinventory extends EssentialsCommand {
}
private String formatCommand(String commandLabel, String[] args) {
return "/" + commandLabel + " " + StringUtil.joinList(" ", (Object[]) args);
return "/" + commandLabel + " " + StringUtil.joinList(" ", args);
}
}
@@ -22,7 +22,7 @@ public class Commandcondense extends EssentialsCommand {
super("condense");
}
private Map<ItemStack, SimpleRecipe> condenseList = new HashMap<>();
private final Map<ItemStack, SimpleRecipe> condenseList = new HashMap<>();
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
@@ -120,7 +120,7 @@ public class Commandcondense extends EssentialsCommand {
}
if (!bestRecipes.isEmpty()) {
if (bestRecipes.size() > 1) {
Collections.sort(bestRecipes, SimpleRecipeComparator.INSTANCE);
bestRecipes.sort(SimpleRecipeComparator.INSTANCE);
}
SimpleRecipe recipe = bestRecipes.get(0);
condenseList.put(stack, recipe);
@@ -171,9 +171,9 @@ public class Commandcondense extends EssentialsCommand {
}
private class SimpleRecipe implements Recipe {
private ItemStack result;
private ItemStack input;
private static class SimpleRecipe implements Recipe {
private final ItemStack result;
private final ItemStack input;
private SimpleRecipe(ItemStack result, ItemStack input) {
this.result = result;
@@ -57,7 +57,7 @@ public class Commandcreatekit extends EssentialsCommand {
}
// Command handler will auto fail if this fails.
long delay = Long.valueOf(args[1]);
long delay = Long.parseLong(args[1]);
String kitname = args[0];
ItemStack[] items = user.getBase().getInventory().getContents();
List<String> list = new ArrayList<>();
@@ -85,46 +85,43 @@ public class Commandcreatekit extends EssentialsCommand {
}
private void uploadPaste(final CommandSource sender, final String kitName, final long delay, final String contents) {
executorService.submit(new Runnable() {
@Override
public void run() {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(PASTE_UPLOAD_URL).openConnection();
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("User-Agent", "EssentialsX plugin");
try (OutputStream os = connection.getOutputStream()) {
os.write(contents.getBytes(Charsets.UTF_8));
}
// Error
if (connection.getResponseCode() >= 400) {
sender.sendMessage(tl("createKitFailed", kitName));
String message = CharStreams.toString(new InputStreamReader(connection.getErrorStream(), Charsets.UTF_8));
ess.getLogger().severe("Error creating kit: " + message);
return;
}
// Read URL
JsonObject object = GSON.fromJson(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8), JsonObject.class);
String pasteUrl = PASTE_URL + object.get("key").getAsString();
connection.disconnect();
String separator = tl("createKitSeparator");
String delayFormat = "0";
if (delay > 0) {
delayFormat = DateUtil.formatDateDiff(System.currentTimeMillis() + (delay * 1000));
}
sender.sendMessage(separator);
sender.sendMessage(tl("createKitSuccess", kitName, delayFormat, pasteUrl));
sender.sendMessage(separator);
if (ess.getSettings().isDebug()) {
ess.getLogger().info(sender.getSender().getName() + " created a kit: " + pasteUrl);
}
} catch (Exception e) {
sender.sendMessage(tl("createKitFailed", kitName));
e.printStackTrace();
executorService.submit(() -> {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(PASTE_UPLOAD_URL).openConnection();
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("User-Agent", "EssentialsX plugin");
try (OutputStream os = connection.getOutputStream()) {
os.write(contents.getBytes(Charsets.UTF_8));
}
// Error
if (connection.getResponseCode() >= 400) {
sender.sendMessage(tl("createKitFailed", kitName));
String message = CharStreams.toString(new InputStreamReader(connection.getErrorStream(), Charsets.UTF_8));
ess.getLogger().severe("Error creating kit: " + message);
return;
}
// Read URL
JsonObject object = GSON.fromJson(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8), JsonObject.class);
String pasteUrl = PASTE_URL + object.get("key").getAsString();
connection.disconnect();
String separator = tl("createKitSeparator");
String delayFormat = "0";
if (delay > 0) {
delayFormat = DateUtil.formatDateDiff(System.currentTimeMillis() + (delay * 1000));
}
sender.sendMessage(separator);
sender.sendMessage(tl("createKitSuccess", kitName, delayFormat, pasteUrl));
sender.sendMessage(separator);
if (ess.getSettings().isDebug()) {
ess.getLogger().info(sender.getSender().getName() + " created a kit: " + pasteUrl);
}
} catch (Exception e) {
sender.sendMessage(tl("createKitFailed", kitName));
e.printStackTrace();
}
});
}
@@ -55,22 +55,25 @@ public class Commanddelhome extends EssentialsCommand {
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
User user = ess.getUser(sender.getPlayer());
boolean canDelOthers = (user == null || user.isAuthorized("essentials.delhome.others"));
boolean canDelOthers = user == null || user.isAuthorized("essentials.delhome.others");
if (args.length == 1) {
List<String> homes = user == null ? new ArrayList<>() : user.getHomes();
if (canDelOthers) {
return getPlayers(server, sender);
} else {
return user.getHomes();
}
} else if (args.length == 2 && canDelOthers) {
try {
user = getPlayer(server, args, 0, true, true);
return user.getHomes();
} catch (Exception ex) {
// No such user
return Collections.emptyList();
int sepIndex = args[0].indexOf(':');
if (sepIndex < 0) {
getPlayers(server, sender).forEach(player -> homes.add(player + ":"));
} else {
String namePart = args[0].substring(0, sepIndex);
User otherUser;
try {
otherUser = getPlayer(server, new String[]{namePart}, 0, true, true);
} catch (Exception ex) {
return homes;
}
otherUser.getHomes().forEach(home -> homes.add(namePart + ":" + home));
}
}
return homes;
} else {
return Collections.emptyList();
}
@@ -0,0 +1,45 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Kit;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commanddelkit extends EssentialsCommand {
public Commanddelkit() {
super("delkit");
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
final String kitList = ess.getKits().listKits(ess, null);
sender.sendMessage(kitList.length() > 0 ? tl("kits", kitList) : tl("noKits"));
throw new NoChargeException();
} else {
final String kitName = ess.getKits().matchKit(args[0]);
final Kit kit = new Kit(kitName, ess);
if (sender.getPlayer() != null) {
kit.checkPerms(ess.getUser(sender.getPlayer()));
}
ess.getKits().removeKit(kitName);
sender.sendMessage(tl("deleteKit", kitName));
}
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
return Lists.newArrayList(ess.getKits().getKits().getKeys(false));
}
return Collections.emptyList();
}
}
@@ -13,7 +13,7 @@ public class Commanddepth extends EssentialsCommand {
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final int depth = user.getLocation().getBlockY() - 63;
final int depth = user.getLocation().getBlockY() - user.getWorld().getSeaLevel();
if (depth > 0) {
user.sendMessage(tl("depthAboveSea", depth));
} else if (depth < 0) {
@@ -6,6 +6,7 @@ import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import net.ess3.api.MaxMoneyException;
import net.ess3.api.events.UserBalanceUpdateEvent;
import org.bukkit.Server;
import java.math.BigDecimal;
@@ -19,6 +20,7 @@ import static com.earth2me.essentials.I18n.tl;
public class Commandeco extends EssentialsLoopCommand {
Commandeco.EcoCommands cmd;
BigDecimal amount;
boolean isPercent;
public Commandeco() {
super("eco");
@@ -34,6 +36,7 @@ public class Commandeco extends EssentialsLoopCommand {
try {
cmd = Commandeco.EcoCommands.valueOf(args[0].toUpperCase(Locale.ENGLISH));
isPercent = cmd != EcoCommands.RESET && args[2].endsWith("%");
amount = (cmd == Commandeco.EcoCommands.RESET) ? startingBalance : new BigDecimal(args[2].replaceAll("[^0-9\\.]", ""));
} catch (Exception ex) {
throw new NotEnoughArgumentsException(ex);
@@ -52,9 +55,12 @@ public class Commandeco extends EssentialsLoopCommand {
@Override
protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) throws NotEnoughArgumentsException, ChargeException, MaxMoneyException {
if (isPercent && cmd != EcoCommands.RESET) {
amount = player.getMoney().multiply(amount).scaleByPowerOfTen(-2);
}
switch (cmd) {
case GIVE:
player.giveMoney(amount, sender);
player.giveMoney(amount, sender, UserBalanceUpdateEvent.Cause.COMMAND_ECO);
break;
case TAKE:
@@ -72,10 +78,10 @@ public class Commandeco extends EssentialsLoopCommand {
BigDecimal money = player.getMoney();
BigDecimal minBalance = ess.getSettings().getMinMoney();
if (money.subtract(amount).compareTo(minBalance) >= 0) {
player.takeMoney(amount, sender);
player.takeMoney(amount, sender, UserBalanceUpdateEvent.Cause.COMMAND_ECO);
} else if (sender == null) {
try {
player.setMoney(minBalance);
player.setMoney(minBalance, UserBalanceUpdateEvent.Cause.COMMAND_ECO);
} catch (MaxMoneyException ex) {
// Take shouldn't be able to throw a max money exception
}
@@ -90,7 +96,7 @@ public class Commandeco extends EssentialsLoopCommand {
BigDecimal maxBalance = ess.getSettings().getMaxMoney();
boolean underMinimum = (amount.compareTo(minBalance) < 0);
boolean aboveMax = (amount.compareTo(maxBalance) > 0);
player.setMoney(underMinimum ? minBalance : aboveMax ? maxBalance : amount);
player.setMoney(underMinimum ? minBalance : aboveMax ? maxBalance : amount, UserBalanceUpdateEvent.Cause.COMMAND_ECO);
player.sendMessage(tl("setBal", NumberUtil.displayCurrency(player.getMoney(), ess)));
if (sender != null) {
sender.sendMessage(tl("setBalOthers", player.getDisplayName(), NumberUtil.displayCurrency(player.getMoney(), ess)));
@@ -0,0 +1,74 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.ChatColor;
import org.bukkit.Server;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandeditsign extends EssentialsCommand {
public Commandeditsign() {
super("editsign");
}
@Override
protected void run(Server server, User user, String commandLabel, String[] args) throws Exception {
if (args.length == 0 || (args.length > 1 && !NumberUtil.isInt(args[1]))) {
throw new NotEnoughArgumentsException();
}
Block target = user.getBase().getTargetBlock(null, 5); //5 is a good number
if (!(target.getState() instanceof Sign)) {
throw new Exception(tl("editsignCommandTarget"));
}
Sign sign = (Sign) target.getState();
try {
if (args[0].equalsIgnoreCase("set") && args.length > 2) {
int line = Integer.parseInt(args[1]) - 1;
String text = FormatUtil.formatString(user, "essentials.editsign", getFinalArg(args, 2)).trim();
if (ChatColor.stripColor(text).length() > 15 && !user.isAuthorized("essentials.editsign.unlimited")) {
throw new Exception(tl("editsignCommandLimit"));
}
sign.setLine(line, text);
sign.update();
user.sendMessage(tl("editsignCommandSetSuccess", line + 1, text));
} else if (args[0].equalsIgnoreCase("clear")) {
if (args.length == 1) {
for (int i = 0; i < 4; i++) { // A whole one line of line savings!
sign.setLine(i, "");
}
sign.update();
user.sendMessage(tl("editsignCommandClear"));
} else {
int line = Integer.parseInt(args[1]) - 1;
sign.setLine(line, "");
sign.update();
user.sendMessage(tl("editsignCommandClearLine", line + 1));
}
} else {
throw new NotEnoughArgumentsException();
}
} catch (IndexOutOfBoundsException e) {
throw new Exception(tl("editsignCommandNoLine"));
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
if (args.length == 1) {
return Lists.newArrayList("set", "clear");
} else if (args.length == 2) {
return Lists.newArrayList("1", "2", "3", "4");
} else {
return Collections.emptyList();
}
}
}
@@ -6,96 +6,144 @@ import com.earth2me.essentials.User;
import com.earth2me.essentials.UserMap;
import com.earth2me.essentials.utils.*;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
import java.util.function.Supplier;
import static com.earth2me.essentials.I18n.tl;
// This command has 4 undocumented behaviours #EasterEgg
public class Commandessentials extends EssentialsCommand {
private final Sound NOTE_HARP = EnumUtil.valueOf(Sound.class, "BLOCK_NOTE_BLOCK_HARP", "BLOCK_NOTE_HARP", "NOTE_PIANO");
private static final Sound NOTE_HARP = EnumUtil.valueOf(Sound.class, "BLOCK_NOTE_BLOCK_HARP", "BLOCK_NOTE_HARP", "NOTE_PIANO");
private static final Sound MOO_SOUND = EnumUtil.valueOf(Sound.class, "COW_IDLE", "ENTITY_COW_MILK");
private static final String NYAN_TUNE = "1D#,1E,2F#,,2A#,1E,1D#,1E,2F#,2B,2D#,2E,2D#,2A#,2B,,2F#,,1D#,1E,2F#,2B,2C#,2A#,2B,2C#,2E,2D#,2E,2C#,,2F#,,2G#,,1D,1D#,,1C#,1D,1C#,1B,,1B,,1C#,,1D,,1D,1C#,1B,1C#,1D#,2F#,2G#,1D#,2F#,1C#,1D#,1B,1C#,1B,1D#,,2F#,,2G#,1D#,2F#,1C#,1D#,1B,1D,1D#,1D,1C#,1B,1C#,1D,,1B,1C#,1D#,2F#,1C#,1D,1C#,1B,1C#,,1B,,1C#,,2F#,,2G#,,1D,1D#,,1C#,1D,1C#,1B,,1B,,1C#,,1D,,1D,1C#,1B,1C#,1D#,2F#,2G#,1D#,2F#,1C#,1D#,1B,1C#,1B,1D#,,2F#,,2G#,1D#,2F#,1C#,1D#,1B,1D,1D#,1D,1C#,1B,1C#,1D,,1B,1C#,1D#,2F#,1C#,1D,1C#,1B,1C#,,1B,,1B,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1B,,";
private static final String[] CONSOLE_MOO = new String[]{" (__)", " (oo)", " /------\\/", " / | ||", " * /\\---/\\", " ~~ ~~", "....\"Have you mooed today?\"..."};
private static final String[] PLAYER_MOO = new String[]{" (__)", " (oo)", " /------\\/", " / | | |", " * /\\---/\\", " ~~ ~~", "....\"Have you mooed today?\"..."};
public Commandessentials() {
super("essentials");
}
private transient int taskid;
private final transient Map<Player, Block> noteBlocks = new HashMap<Player, Block>();
private transient TuneRunnable currentTune = null;
private final List<String> versionPlugins = Arrays.asList(
"Vault",
"LuckPerms",
"PermissionsEx",
"GroupManager"
private static final List<String> versionPlugins = Arrays.asList(
"Vault", // API
"Reserve", // API
"PlaceholderAPI", // API
"CMI", // potential for issues
"Towny", // past issues; admins should ensure latest
"ChestShop", // past issues; admins should ensure latest
"Citizens", // fires player events
"LuckPerms", // permissions (recommended)
"UltraPermissions",
"PermissionsEx", // permissions (unsupported)
"GroupManager", // permissions (unsupported)
"bPermissions" // permissions (unsupported)
);
private final List<String> officialPlugins = Arrays.asList(
"EssentialsAntiBuild",
"EssentialsChat",
"EssentialsGeoIP",
"EssentialsProtect",
"EssentialsSpawn",
"EssentialsXMPP"
private static final List<String> officialPlugins = Arrays.asList(
"EssentialsAntiBuild",
"EssentialsChat",
"EssentialsGeoIP",
"EssentialsProtect",
"EssentialsSpawn",
"EssentialsXMPP"
);
private final List<String> warnPlugins = Arrays.asList(
"PermissionsEx",
"GroupManager"
private static final List<String> warnPlugins = Arrays.asList(
"PermissionsEx",
"GroupManager",
"bPremissions"
);
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length == 0) {
run_disabled(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("debug")) {
run_debug(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("nya")) {
run_nya(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("moo")) {
run_moo(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("reset")) {
run_reset(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("cleanup")) {
run_cleanup(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("uuidconvert")) {
run_uuidconvert(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("uuidtest")) {
run_uuidtest(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("version")) {
run_version(server, sender, commandLabel, args);
} else {
run_reload(server, sender, commandLabel, args);
showUsage(sender);
}
switch(args[0]) {
// Info commands
case "debug":
case "verbose":
runDebug(server, sender, commandLabel, args);
break;
case "ver":
case "version":
runVersion(server, sender, commandLabel, args);
break;
case "cmd":
case "commands":
runCommands(server, sender, commandLabel, args);
break;
// Data commands
case "reload":
runReload(server, sender, commandLabel, args);
break;
case "reset":
runReset(server, sender, commandLabel, args);
break;
case "cleanup":
runCleanup(server, sender, commandLabel, args);
break;
case "uuidconvert":
runUUIDConvert(server, sender, commandLabel, args);
break;
case "uuidtest":
runUUIDTest(server, sender, commandLabel, args);
break;
// "#EasterEgg"
case "nya":
case "nyan":
runNya(server, sender, commandLabel, args);
break;
case "moo":
runMoo(server, sender, commandLabel, args);
break;
default:
showUsage(sender);
}
}
//If you do not supply an argument this command will list 'overridden' commands.
private void run_disabled(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
sender.sendMessage("/<command> <reload/debug>");
// Displays the command's usage.
private void showUsage(final CommandSource sender) throws Exception {
throw new NotEnoughArgumentsException("/<command> <reload/debug/commands>");
}
// Lists commands that are being handed over to other plugins.
private void runCommands(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
final StringBuilder disabledCommands = new StringBuilder();
for (Map.Entry<String, String> entry : ess.getAlternativeCommandsHandler().disabledCommands().entrySet()) {
if (disabledCommands.length() > 0) {
disabledCommands.append(", ");
disabledCommands.append("\n");
}
disabledCommands.append(entry.getKey()).append(" => ").append(entry.getValue());
}
if (disabledCommands.length() > 0) {
sender.sendMessage(tl("blockList"));
sender.sendMessage(disabledCommands.toString());
} else {
sender.sendMessage(tl("blockListEmpty"));
}
}
private void run_reset(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
// Resets the given player's user data.
private void runReset(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 2) {
throw new Exception("/<command> reset <player>");
}
@@ -104,108 +152,59 @@ public class Commandessentials extends EssentialsCommand {
sender.sendMessage("Reset Essentials userdata for player: " + user.getDisplayName());
}
private void run_debug(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
// Toggles debug mode.
private void runDebug(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
ess.getSettings().setDebug(!ess.getSettings().isDebug());
sender.sendMessage("Essentials " + ess.getDescription().getVersion() + " debug mode " + (ess.getSettings().isDebug() ? "enabled" : "disabled"));
}
private void run_reload(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
// Reloads all reloadable configs.
private void runReload(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
ess.reload();
sender.sendMessage(tl("essentialsReload", ess.getDescription().getVersion()));
}
private void run_nya(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
final Map<String, Float> noteMap = new HashMap<String, Float>();
noteMap.put("1F#", 0.5f);
noteMap.put("1G", 0.53f);
noteMap.put("1G#", 0.56f);
noteMap.put("1A", 0.6f);
noteMap.put("1A#", 0.63f);
noteMap.put("1B", 0.67f);
noteMap.put("1C", 0.7f);
noteMap.put("1C#", 0.76f);
noteMap.put("1D", 0.8f);
noteMap.put("1D#", 0.84f);
noteMap.put("1E", 0.9f);
noteMap.put("1F", 0.94f);
noteMap.put("2F#", 1.0f);
noteMap.put("2G", 1.06f);
noteMap.put("2G#", 1.12f);
noteMap.put("2A", 1.18f);
noteMap.put("2A#", 1.26f);
noteMap.put("2B", 1.34f);
noteMap.put("2C", 1.42f);
noteMap.put("2C#", 1.5f);
noteMap.put("2D", 1.6f);
noteMap.put("2D#", 1.68f);
noteMap.put("2E", 1.78f);
noteMap.put("2F", 1.88f);
final String tuneStr = "1D#,1E,2F#,,2A#,1E,1D#,1E,2F#,2B,2D#,2E,2D#,2A#,2B,,2F#,,1D#,1E,2F#,2B,2C#,2A#,2B,2C#,2E,2D#,2E,2C#,,2F#,,2G#,,1D,1D#,,1C#,1D,1C#,1B,,1B,,1C#,,1D,,1D,1C#,1B,1C#,1D#,2F#,2G#,1D#,2F#,1C#,1D#,1B,1C#,1B,1D#,,2F#,,2G#,1D#,2F#,1C#,1D#,1B,1D,1D#,1D,1C#,1B,1C#,1D,,1B,1C#,1D#,2F#,1C#,1D,1C#,1B,1C#,,1B,,1C#,,2F#,,2G#,,1D,1D#,,1C#,1D,1C#,1B,,1B,,1C#,,1D,,1D,1C#,1B,1C#,1D#,2F#,2G#,1D#,2F#,1C#,1D#,1B,1C#,1B,1D#,,2F#,,2G#,1D#,2F#,1C#,1D#,1B,1D,1D#,1D,1C#,1B,1C#,1D,,1B,1C#,1D#,2F#,1C#,1D,1C#,1B,1C#,,1B,,1B,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1B,,";
final String[] tune = tuneStr.split(",");
taskid = ess.scheduleSyncRepeatingTask(new Runnable() {
int i = 0;
@Override
public void run() {
final String note = tune[i];
i++;
if (i >= tune.length) {
Commandessentials.this.stopTune();
}
if (note == null || note.isEmpty()) {
return;
}
for (Player onlinePlayer : ess.getOnlinePlayers()) {
onlinePlayer.playSound(onlinePlayer.getLocation(), NOTE_HARP, 1, noteMap.get(note));
}
}
}, 20, 2);
}
private void stopTune() {
ess.getScheduler().cancelTask(taskid);
for (Block block : noteBlocks.values()) {
if (block.getType() == Material.NOTE_BLOCK) {
block.setType(Material.AIR);
}
// Pop tarts.
private void runNya(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (currentTune != null) {
currentTune.cancel();
}
noteBlocks.clear();
currentTune = new TuneRunnable(NYAN_TUNE, NOTE_HARP, ess::getOnlinePlayers);
currentTune.runTaskTimer(ess, 20, 2);
}
private final String[] consoleMoo = new String[]{" (__)", " (oo)", " /------\\/", " / | ||", " * /\\---/\\", " ~~ ~~", "....\"Have you mooed today?\"..."};
private final String[] playerMoo = new String[]{" (__)", " (oo)", " /------\\/", " / | | |", " * /\\---/\\", " ~~ ~~", "....\"Have you mooed today?\"..."};
private void run_moo(final Server server, final CommandSource sender, final String command, final String args[]) {
Sound moo = EnumUtil.valueOf(Sound.class, "COW_IDLE", "ENTITY_COW_MILK");
// Cow farts.
private void runMoo(final Server server, final CommandSource sender, final String command, final String[] args) {
if (args.length == 2 && args[1].equals("moo")) {
for (String s : consoleMoo) {
for (String s : CONSOLE_MOO) {
logger.info(s);
}
for (Player player : ess.getOnlinePlayers()) {
player.sendMessage(playerMoo);
player.playSound(player.getLocation(), moo, 1, 1.0f);
player.sendMessage(PLAYER_MOO);
player.playSound(player.getLocation(), MOO_SOUND, 1, 1.0f);
}
} else {
if (sender.isPlayer()) {
sender.getSender().sendMessage(playerMoo);
sender.getSender().sendMessage(PLAYER_MOO);
final Player player = sender.getPlayer();
player.playSound(player.getLocation(), moo, 1, 1.0f);
player.playSound(player.getLocation(), MOO_SOUND, 1, 1.0f);
} else {
sender.getSender().sendMessage(consoleMoo);
sender.getSender().sendMessage(CONSOLE_MOO);
}
}
}
private void run_cleanup(final Server server, final CommandSource sender, final String command, final String args[]) throws Exception {
// Cleans up inactive users.
private void runCleanup(final Server server, final CommandSource sender, final String command, final String[] args) throws Exception {
if (args.length < 2 || !NumberUtil.isInt(args[1])) {
sender.sendMessage("This sub-command will delete users who havent logged in in the last <days> days.");
sender.sendMessage("Optional parameters define the minium amount required to prevent deletion.");
sender.sendMessage("Unless you define larger default values, this command wil ignore people who have more than 0 money/homes.");
sender.sendMessage("This sub-command will delete users who haven't logged in in the last <days> days.");
sender.sendMessage("Optional parameters define the minimum amount required to prevent deletion.");
sender.sendMessage("Unless you define larger default values, this command will ignore people who have more than 0 money/homes.");
throw new Exception("/<command> cleanup <days> [money] [homes]");
}
sender.sendMessage(tl("cleaning"));
final long daysArg = Long.parseLong(args[1]);
@@ -213,59 +212,58 @@ public class Commandessentials extends EssentialsCommand {
final int homesArg = args.length >= 4 && NumberUtil.isInt(args[3]) ? Integer.parseInt(args[3]) : 0;
final UserMap userMap = ess.getUserMap();
ess.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
Long currTime = System.currentTimeMillis();
for (UUID u : userMap.getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
if (user == null) {
continue;
}
long lastLog = user.getLastLogout();
if (lastLog == 0) {
lastLog = user.getLastLogin();
}
if (lastLog == 0) {
user.setLastLogin(currTime);
}
if (user.isNPC()) {
continue;
}
long timeDiff = currTime - lastLog;
long milliDays = daysArg * 24L * 60L * 60L * 1000L;
int homeCount = user.getHomes().size();
double moneyCount = user.getMoney().doubleValue();
if ((lastLog == 0) || (timeDiff < milliDays) || (homeCount > homesArg) || (moneyCount > moneyArg)) {
continue;
}
if (ess.getSettings().isDebug()) {
ess.getLogger().info("Deleting user: " + user.getName() + " Money: " + moneyCount + " Homes: " + homeCount + " Last seen: " + DateUtil.formatDateDiff(lastLog));
}
user.reset();
ess.runTaskAsynchronously(() -> {
long currTime = System.currentTimeMillis();
for (UUID u : userMap.getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
if (user == null) {
continue;
}
sender.sendMessage(tl("cleaned"));
long lastLog = user.getLastLogout();
if (lastLog == 0) {
lastLog = user.getLastLogin();
}
if (lastLog == 0) {
user.setLastLogin(currTime);
}
if (user.isNPC()) {
continue;
}
long timeDiff = currTime - lastLog;
long milliDays = daysArg * 24L * 60L * 60L * 1000L;
int homeCount = user.getHomes().size();
double moneyCount = user.getMoney().doubleValue();
if ((lastLog == 0) || (timeDiff < milliDays) || (homeCount > homesArg) || (moneyCount > moneyArg)) {
continue;
}
if (ess.getSettings().isDebug()) {
ess.getLogger().info("Deleting user: " + user.getName() + " Money: " + moneyCount + " Homes: " + homeCount + " Last seen: " + DateUtil.formatDateDiff(lastLog));
}
user.reset();
}
sender.sendMessage(tl("cleaned"));
});
}
private void run_uuidconvert(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.");
// Forces a rerun of userdata UUID conversion.
private void runUUIDConvert(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
sender.sendMessage("Starting Essentials UUID userdata conversion; this may lag the server.");
Boolean ignoreUFCache = (args.length > 2 && args[1].toLowerCase(Locale.ENGLISH).contains("ignore"));
EssentialsUpgrade.uuidFileConvert(ess, ignoreUFCache);
sender.sendMessage("UUID conversion complete, check your server log for more information.");
sender.sendMessage("UUID conversion complete. Check your server log for more information.");
}
private void run_uuidtest(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
// 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>");
}
@@ -302,7 +300,8 @@ public class Commandessentials extends EssentialsCommand {
sender.sendMessage("Offline Mode UUID: " + offlineuuid.toString());
}
private void run_version(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
// Displays versions of EssentialsX and related plugins.
private void runVersion(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.version")) return;
boolean isMismatched = false;
@@ -369,47 +368,101 @@ public class Commandessentials extends EssentialsCommand {
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
List<String> options = Lists.newArrayList();
options.add("reload");
options.add("debug");
//options.add("nya");
//options.add("moo");
options.add("commands");
options.add("version");
options.add("reload");
options.add("reset");
options.add("cleanup");
//options.add("uuidconvert");
//options.add("uuidtest");
options.add("version");
//options.add("nya");
//options.add("moo");
return options;
} else if (args[0].equalsIgnoreCase("debug")) {
// No args
} else if (args[0].equalsIgnoreCase("nya")) {
// No args
} else if (args[0].equalsIgnoreCase("moo")) {
if (args.length == 2) {
return Lists.newArrayList("moo");
}
} else if (args[0].equalsIgnoreCase("reset")) {
if (args.length == 2) {
return getPlayers(server, sender);
}
} else if (args[0].equalsIgnoreCase("cleanup")) {
if (args.length == 2) {
return COMMON_DURATIONS;
} else if (args.length == 3 || args.length == 4) {
return Lists.newArrayList("-1", "0");
}
} else if (args[0].equalsIgnoreCase("uuidconvert")) {
if (args.length == 2) {
return Lists.newArrayList("ignoreUFCache");
}
} else if (args[0].equalsIgnoreCase("uuidtest")) {
if (args.length == 2) {
return getPlayers(server, sender);
}
} else if (args[0].equalsIgnoreCase("version")) {
// No args
} else {
// No args
}
switch (args[0]) {
case "moo":
if (args.length == 2) {
return Lists.newArrayList("moo");
}
break;
case "reset":
case "uuidtest":
if (args.length == 2) {
return getPlayers(server, sender);
}
break;
case "cleanup":
if (args.length == 2) {
return COMMON_DURATIONS;
} else if (args.length == 3 || args.length == 4) {
return Lists.newArrayList("-1", "0");
}
break;
case "uuidconvert":
if (args.length == 2) {
return Lists.newArrayList("ignoreUFCache");
}
break;
}
return Collections.emptyList();
}
private static class TuneRunnable extends BukkitRunnable {
private static final Map<String, Float> noteMap = ImmutableMap.<String, Float>builder()
.put("1F#", 0.5f)
.put("1G", 0.53f)
.put("1G#", 0.56f)
.put("1A", 0.6f)
.put("1A#", 0.63f)
.put("1B", 0.67f)
.put("1C", 0.7f)
.put("1C#", 0.76f)
.put("1D", 0.8f)
.put("1D#", 0.84f)
.put("1E", 0.9f)
.put("1F", 0.94f)
.put("2F#", 1.0f)
.put("2G", 1.06f)
.put("2G#", 1.12f)
.put("2A", 1.18f)
.put("2A#", 1.26f)
.put("2B", 1.34f)
.put("2C", 1.42f)
.put("2C#", 1.5f)
.put("2D", 1.6f)
.put("2D#", 1.68f)
.put("2E", 1.78f)
.put("2F", 1.88f)
.build();
private final String[] tune;
private final Sound sound;
private final Supplier<Collection<Player>> players;
private int i = 0;
TuneRunnable(final String tuneStr, final Sound sound, final Supplier<Collection<Player>> players) {
this.tune = tuneStr.split(",");
this.sound = sound;
this.players = players;
}
@Override
public void run() {
final String note = tune[i];
i++;
if (i >= tune.length) {
cancel();
}
if (note == null || note.isEmpty()) {
return;
}
for (Player onlinePlayer : players.get()) {
onlinePlayer.playSound(onlinePlayer.getLocation(), sound, 1, noteMap.get(note));
}
}
}
}
@@ -1,223 +1,226 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.SetExpFix;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commandexp extends EssentialsCommand {
public Commandexp() {
super("exp");
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length == 0) {
showExp(user.getSource(), user);
} else if (args.length > 1 && args[0].equalsIgnoreCase("set") && user.isAuthorized("essentials.exp.set")) {
if (args.length == 3 && user.isAuthorized("essentials.exp.set.others")) {
expMatch(server, user.getSource(), args[1], args[2], false);
} else {
setExp(user.getSource(), user, args[1], false);
}
} else if (args.length > 1 && args[0].equalsIgnoreCase("give") && user.isAuthorized("essentials.exp.give")) {
if (args.length == 3 && user.isAuthorized("essentials.exp.give.others")) {
expMatch(server, user.getSource(), args[1], args[2], true);
} else {
setExp(user.getSource(), user, args[1], true);
}
} else if (args.length > 1 && args[0].equalsIgnoreCase("take") && user.isAuthorized("essentials.exp.take")) {
if (args.length == 3 && user.isAuthorized("essentials.exp.take.others")) {
expMatch(server, user.getSource(), args[1], "-" + args[2], true);
} else {
setExp(user.getSource(), user, "-" + args[1], true);
}
} else if (args.length < 3 && args[0].equalsIgnoreCase("reset") && user.isAuthorized("essentials.exp.reset")) {
if (args.length == 2 && user.isAuthorized("essentials.exp.reset.others")) {
expMatch(server, user.getSource(), args[1], "0", false);
} else {
setExp(user.getSource(), user, "0", false);
}
} else if (args[0].equalsIgnoreCase("show")) {
if (args.length >= 2 && user.isAuthorized("essentials.exp.others")) {
String match = args[1].trim();
showMatch(server, user.getSource(), match);
} else {
showExp(user.getSource(), user);
}
} else {
if (args.length >= 1 && NumberUtil.isInt(args[0].toLowerCase(Locale.ENGLISH).replace("l", "")) && user.isAuthorized("essentials.exp.give")) {
if (args.length >= 2 && user.isAuthorized("essentials.exp.give.others")) {
expMatch(server, user.getSource(), args[1], args[0], true);
} else {
setExp(user.getSource(), user, args[0], true);
}
} else if (args.length >= 1 && user.isAuthorized("essentials.exp.others")) {
String match = args[0].trim();
showMatch(server, user.getSource(), match);
} else {
showExp(user.getSource(), user);
}
}
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
throw new NotEnoughArgumentsException();
} else if (args.length > 2 && args[0].equalsIgnoreCase("set")) {
expMatch(server, sender, args[1], args[2], false);
} else if (args.length > 2 && args[0].equalsIgnoreCase("give")) {
expMatch(server, sender, args[1], args[2], true);
} else {
String match = args[0].trim();
if (args.length >= 2 && NumberUtil.isInt(args[0].toLowerCase(Locale.ENGLISH).replace("l", ""))) {
match = args[1].trim();
expMatch(server, sender, match, args[0], true);
} else if (args.length == 1) {
match = args[0].trim();
}
showMatch(server, sender, match);
}
}
private void showMatch(final Server server, final CommandSource sender, final String match) throws PlayerNotFoundException {
boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished();
boolean foundUser = false;
final List<Player> matchedPlayers = server.matchPlayer(match);
for (Player matchPlayer : matchedPlayers) {
final User player = ess.getUser(matchPlayer);
if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) {
continue;
}
foundUser = true;
showExp(sender, player);
}
if (!foundUser) {
throw new PlayerNotFoundException();
}
}
private void expMatch(final Server server, final CommandSource sender, final String match, String amount, final boolean give) throws NotEnoughArgumentsException, PlayerNotFoundException {
boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished();
boolean foundUser = false;
final List<Player> matchedPlayers = server.matchPlayer(match);
for (Player matchPlayer : matchedPlayers) {
final User player = ess.getUser(matchPlayer);
if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) {
continue;
}
foundUser = true;
setExp(sender, player, amount, give);
}
if (!foundUser) {
throw new PlayerNotFoundException();
}
}
private void showExp(final CommandSource sender, final User target) {
sender.sendMessage(tl("exp", target.getDisplayName(), SetExpFix.getTotalExperience(target.getBase()), target.getBase().getLevel(), SetExpFix.getExpUntilNextLevel(target.getBase())));
}
//TODO: Limit who can give negative exp?
private void setExp(final CommandSource sender, final User target, String strAmount, final boolean give) throws NotEnoughArgumentsException {
long amount;
strAmount = strAmount.toLowerCase(Locale.ENGLISH);
if (strAmount.contains("l")) {
strAmount = strAmount.replaceAll("l", "");
int neededLevel = Integer.parseInt(strAmount);
if (give) {
neededLevel += target.getBase().getLevel();
}
amount = (long) SetExpFix.getExpToLevel(neededLevel);
SetExpFix.setTotalExperience(target.getBase(), 0);
} else {
amount = Long.parseLong(strAmount);
if (amount > Integer.MAX_VALUE || amount < Integer.MIN_VALUE) {
throw new NotEnoughArgumentsException();
}
}
if (give) {
amount += SetExpFix.getTotalExperience(target.getBase());
}
if (amount > Integer.MAX_VALUE) {
amount = (long) Integer.MAX_VALUE;
}
if (amount < 0l) {
amount = 0l;
}
SetExpFix.setTotalExperience(target.getBase(), (int) amount);
sender.sendMessage(tl("expSet", target.getDisplayName(), amount));
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
if (args.length == 1) {
List<String> options = Lists.newArrayList("show");
if (user.isAuthorized("essentials.exp.set")) {
options.add("set");
}
if (user.isAuthorized("essentials.exp.give")) {
options.add("give");
}
if (user.isAuthorized("essentials.exp.take")) {
options.add("take");
}
if (user.isAuthorized("essentials.exp.reset")) {
options.add("reset");
}
return options;
} else if (args.length == 2) {
if ((args[0].equalsIgnoreCase("set") && user.isAuthorized("essentials.exp.set")) || (args[0].equalsIgnoreCase("give") && user.isAuthorized("essentials.exp.give"))) {
String levellessArg = args[1].toLowerCase(Locale.ENGLISH).replace("l", "");
if (NumberUtil.isInt(levellessArg)) {
return Lists.newArrayList(levellessArg, args[1] + "l");
} else {
return Collections.emptyList();
}
} else if (args[0].equalsIgnoreCase("show") && user.isAuthorized("essentials.exp.others")) {
return getPlayers(server, user);
} else {
return Collections.emptyList();
}
} else if (args.length == 3 && (args[0].equalsIgnoreCase("set") && user.isAuthorized("essentials.exp.set.others")) || (args[0].equalsIgnoreCase("give") && user.isAuthorized("essentials.exp.give.others"))) {
return getPlayers(server, user);
} else {
return Collections.emptyList();
}
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
// TODO: This seems somewhat buggy, both setting and showing - right now, ignoring that
return Lists.newArrayList("set", "give", "show", "take", "reset");
} else if (args.length == 2) {
if (args[0].equalsIgnoreCase("set") || args[0].equalsIgnoreCase("give")) {
String levellessArg = args[1].toLowerCase(Locale.ENGLISH).replace("l", "");
if (NumberUtil.isInt(levellessArg)) {
return Lists.newArrayList(levellessArg, args[1] + "l");
} else {
return Collections.emptyList();
}
} else { // even without 'show'
return getPlayers(server, sender);
}
} else if (args.length == 3 && (args[0].equalsIgnoreCase("set") || args[0].equalsIgnoreCase("give"))) {
return getPlayers(server, sender);
} else {
return Collections.emptyList();
}
}
}
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.SetExpFix;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commandexp extends EssentialsCommand {
public Commandexp() {
super("exp");
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length == 0) {
showExp(user.getSource(), user);
} else if (args.length > 1 && args[0].equalsIgnoreCase("set") && user.isAuthorized("essentials.exp.set")) {
if (args.length == 3 && user.isAuthorized("essentials.exp.set.others")) {
expMatch(server, user.getSource(), args[1], args[2], false);
} else {
setExp(user.getSource(), user, args[1], false);
}
} else if (args.length > 1 && args[0].equalsIgnoreCase("give") && user.isAuthorized("essentials.exp.give")) {
if (args.length == 3 && user.isAuthorized("essentials.exp.give.others")) {
expMatch(server, user.getSource(), args[1], args[2], true);
} else {
setExp(user.getSource(), user, args[1], true);
}
} else if (args.length > 1 && args[0].equalsIgnoreCase("take") && user.isAuthorized("essentials.exp.take")) {
if (args.length == 3 && user.isAuthorized("essentials.exp.take.others")) {
expMatch(server, user.getSource(), args[1], "-" + args[2], true);
} else {
setExp(user.getSource(), user, "-" + args[1], true);
}
} else if (args.length < 3 && args[0].equalsIgnoreCase("reset") && user.isAuthorized("essentials.exp.reset")) {
if (args.length == 2 && user.isAuthorized("essentials.exp.reset.others")) {
expMatch(server, user.getSource(), args[1], "0", false);
} else {
setExp(user.getSource(), user, "0", false);
}
} else if (args[0].equalsIgnoreCase("show")) {
if (args.length >= 2 && user.isAuthorized("essentials.exp.others")) {
String match = args[1].trim();
showMatch(server, user.getSource(), match);
} else {
showExp(user.getSource(), user);
}
} else {
if (args.length >= 1 && NumberUtil.isInt(args[0].toLowerCase(Locale.ENGLISH).replace("l", "")) && user.isAuthorized("essentials.exp.give")) {
if (args.length >= 2 && user.isAuthorized("essentials.exp.give.others")) {
expMatch(server, user.getSource(), args[1], args[0], true);
} else {
setExp(user.getSource(), user, args[0], true);
}
} else if (args.length >= 1 && user.isAuthorized("essentials.exp.others")) {
String match = args[0].trim();
showMatch(server, user.getSource(), match);
} else {
showExp(user.getSource(), user);
}
}
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
throw new NotEnoughArgumentsException();
} else if (args.length > 2 && args[0].equalsIgnoreCase("set")) {
expMatch(server, sender, args[1], args[2], false);
} else if (args.length > 2 && args[0].equalsIgnoreCase("give")) {
expMatch(server, sender, args[1], args[2], true);
} else if (args.length > 2 && args[0].equalsIgnoreCase("take")) {
expMatch(server, sender, args[1], "-" + args[2], true);
} else if (args.length > 2 && args[0].equalsIgnoreCase("reset")) {
expMatch(server, sender, args[1], "0", false);
} else {
String match = args[0].trim();
if (args.length >= 2 && NumberUtil.isInt(args[0].toLowerCase(Locale.ENGLISH).replace("l", ""))) {
match = args[1].trim();
expMatch(server, sender, match, args[0], true);
} else if (args.length == 1) {
match = args[0].trim();
}
showMatch(server, sender, match);
}
}
private void showMatch(final Server server, final CommandSource sender, final String match) throws PlayerNotFoundException {
boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished();
boolean foundUser = false;
final List<Player> matchedPlayers = server.matchPlayer(match);
for (Player matchPlayer : matchedPlayers) {
final User player = ess.getUser(matchPlayer);
if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) {
continue;
}
foundUser = true;
showExp(sender, player);
}
if (!foundUser) {
throw new PlayerNotFoundException();
}
}
private void expMatch(final Server server, final CommandSource sender, final String match, String amount, final boolean give) throws NotEnoughArgumentsException, PlayerNotFoundException {
boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished();
boolean foundUser = false;
final List<Player> matchedPlayers = server.matchPlayer(match);
for (Player matchPlayer : matchedPlayers) {
final User player = ess.getUser(matchPlayer);
if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) {
continue;
}
foundUser = true;
setExp(sender, player, amount, give);
}
if (!foundUser) {
throw new PlayerNotFoundException();
}
}
private void showExp(final CommandSource sender, final User target) {
sender.sendMessage(tl("exp", target.getDisplayName(), SetExpFix.getTotalExperience(target.getBase()), target.getBase().getLevel(), SetExpFix.getExpUntilNextLevel(target.getBase())));
}
//TODO: Limit who can give negative exp?
private void setExp(final CommandSource sender, final User target, String strAmount, final boolean give) throws NotEnoughArgumentsException {
long amount;
strAmount = strAmount.toLowerCase(Locale.ENGLISH);
if (strAmount.contains("l")) {
strAmount = strAmount.replaceAll("l", "");
int neededLevel = Integer.parseInt(strAmount);
if (give) {
neededLevel += target.getBase().getLevel();
}
amount = SetExpFix.getExpToLevel(neededLevel);
SetExpFix.setTotalExperience(target.getBase(), 0);
} else {
amount = Long.parseLong(strAmount);
if (amount > Integer.MAX_VALUE || amount < Integer.MIN_VALUE) {
throw new NotEnoughArgumentsException();
}
}
if (give) {
amount += SetExpFix.getTotalExperience(target.getBase());
}
if (amount > Integer.MAX_VALUE) {
amount = Integer.MAX_VALUE;
}
if (amount < 0L) {
amount = 0L;
}
SetExpFix.setTotalExperience(target.getBase(), (int) amount);
sender.sendMessage(tl("expSet", target.getDisplayName(), amount));
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
if (args.length == 1) {
List<String> options = Lists.newArrayList("show");
if (user.isAuthorized("essentials.exp.set")) {
options.add("set");
}
if (user.isAuthorized("essentials.exp.give")) {
options.add("give");
}
if (user.isAuthorized("essentials.exp.take")) {
options.add("take");
}
if (user.isAuthorized("essentials.exp.reset")) {
options.add("reset");
}
return options;
} else if (args.length == 2) {
if ((args[0].equalsIgnoreCase("set") && user.isAuthorized("essentials.exp.set")) || (args[0].equalsIgnoreCase("give") && user.isAuthorized("essentials.exp.give")) || (args[0].equalsIgnoreCase("take") && user.isAuthorized("essentials.exp.take"))) {
String levellessArg = args[1].toLowerCase(Locale.ENGLISH).replaceAll("l", "");
if (NumberUtil.isInt(levellessArg)) {
return Lists.newArrayList(levellessArg + "l");
}
}
if (user.isAuthorized("essentials.exp.others")) {
return getPlayers(server, user);
}
} else if (args.length == 3 && !(args[0].equalsIgnoreCase("show") || args[0].equalsIgnoreCase("reset"))) {
String levellessArg = args[2].toLowerCase(Locale.ENGLISH).replaceAll("l", "");
if (NumberUtil.isInt(levellessArg)) {
return Lists.newArrayList(levellessArg + "l");
}
}
return Collections.emptyList();
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
// TODO: This seems somewhat buggy, both setting and showing - right now, ignoring that
return Lists.newArrayList("set", "give", "show", "take", "reset");
} else if (args.length == 2) {
if (args[0].equalsIgnoreCase("set") || args[0].equalsIgnoreCase("give")) {
String levellessArg = args[1].toLowerCase(Locale.ENGLISH).replace("l", "");
if (NumberUtil.isInt(levellessArg)) {
return Lists.newArrayList(levellessArg, args[1] + "l");
} else {
return Collections.emptyList();
}
} else { // even without 'show'
return getPlayers(server, sender);
}
} else if (args.length == 3 && (args[0].equalsIgnoreCase("set") || args[0].equalsIgnoreCase("give"))) {
return getPlayers(server, sender);
} else {
return Collections.emptyList();
}
}
}
@@ -27,13 +27,13 @@ public class Commandext extends EssentialsLoopCommand {
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
extPlayer(user.getBase());
user.sendMessage(tl("extinguish"));
if (args.length > 0 && user.isAuthorized("essentials.ext.others")) {
loopOnlinePlayers(server, user.getSource(), true, true, args[0], null);
return;
}
loopOnlinePlayers(server, user.getSource(), true, true, args[0], null);
extPlayer(user.getBase());
user.sendMessage(tl("extinguish"));
}
@Override
@@ -60,7 +60,7 @@ public class Commandfeed extends EssentialsLoopCommand {
throw new QuietAbortException();
}
player.setFoodLevel(flce.getFoodLevel() > 20 ? 20 : flce.getFoodLevel());
player.setFoodLevel(Math.min(flce.getFoodLevel(), 20));
player.setSaturation(10);
player.setExhaustion(0F);
}
@@ -1,55 +1,101 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FloatUtil;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import org.bukkit.entity.*;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.util.Vector;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.earth2me.essentials.I18n.tl;
public class Commandfireball extends EssentialsCommand {
public static final String FIREBALL_META_KEY = "ess_fireball_proj";
private static final Map<String, Class<? extends Projectile>> types;
static {
ImmutableMap.Builder<String, Class<? extends Projectile>> builder = ImmutableMap.<String, Class<? extends Projectile>>builder()
.put("fireball", Fireball.class)
.put("small", SmallFireball.class)
.put("large", LargeFireball.class)
.put("arrow", Arrow.class)
.put("skull", WitherSkull.class)
.put("egg", Egg.class)
.put("snowball", Snowball.class)
.put("expbottle", ThrownExpBottle.class);
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_9_R01)) {
builder.put("dragon", DragonFireball.class)
.put("splashpotion", SplashPotion.class)
.put("lingeringpotion", LingeringPotion.class);
}
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_13_0_R01)) {
builder.put("trident", Trident.class);
}
types = builder.build();
}
public Commandfireball() {
super("fireball");
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
Class<? extends Entity> type = Fireball.class;
Projectile projectile;
int speed = 2;
if (args.length > 0) {
if (args[0].equalsIgnoreCase("small")) {
type = SmallFireball.class;
} else if (args[0].equalsIgnoreCase("arrow")) {
type = Arrow.class;
} else if (args[0].equalsIgnoreCase("skull")) {
type = WitherSkull.class;
} else if (args[0].equalsIgnoreCase("egg")) {
type = Egg.class;
} else if (args[0].equalsIgnoreCase("snowball")) {
type = Snowball.class;
} else if (args[0].equalsIgnoreCase("expbottle")) {
type = ThrownExpBottle.class;
} else if (args[0].equalsIgnoreCase("large")) {
type = LargeFireball.class;
} else if (args[0].equalsIgnoreCase("splashpotion")) {
type = SplashPotion.class;
} else if (args[0].equalsIgnoreCase("lingeringpotion")) {
type = LingeringPotion.class;
String type = "fireball";
double speed = 2;
boolean ride = false;
if (args.length > 0 && types.containsKey(args[0])) {
type = args[0];
}
if (args.length > 1) {
try {
speed = FloatUtil.parseDouble(args[1]);
speed = Double.max(0, Double.min(speed, ess.getSettings().getMaxProjectileSpeed()));
} catch (Exception ignored) {
}
}
if (args.length > 2 && args[2].equalsIgnoreCase("ride") && user.isAuthorized("essentials.fireball.ride")) {
ride = true;
}
if (!user.isAuthorized("essentials.fireball." + type)) {
throw new Exception(tl("noPerm", "essentials.fireball." + type));
}
final Vector direction = user.getBase().getEyeLocation().getDirection().multiply(speed);
projectile = (Projectile) user.getWorld().spawn(user.getBase().getEyeLocation().add(direction.getX(), direction.getY(), direction.getZ()), type);
Projectile projectile = user.getWorld().spawn(user.getBase().getEyeLocation().add(direction.getX(), direction.getY(), direction.getZ()), types.get(type));
projectile.setShooter(user.getBase());
projectile.setVelocity(direction);
projectile.setMetadata(FIREBALL_META_KEY, new FixedMetadataValue(ess, true));
if (ride) {
projectile.addPassenger(user.getBase());
}
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
if (args.length == 1) {
return Lists.newArrayList("small", "arrow", "skull", "egg", "snowball", "expbottle", "large", "splashpotion", "lingeringpotion");
return types.keySet().stream()
.filter(type -> user.isAuthorized("essentials.fireball." + type))
.collect(Collectors.toList());
} else if (args.length == 2) {
return Lists.newArrayList("1", "2", "3", "4", "5");
} else {
return Collections.emptyList();
}
@@ -1,178 +1,177 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.DyeColor;
import org.bukkit.FireworkEffect;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Firework;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.FireworkMeta;
import org.bukkit.util.Vector;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
//This command has quite a complicated syntax, in theory it has 4 seperate syntaxes which are all variable:
//
//1: /firework clear - This clears all of the effects on a firework stack
//
//2: /firework power <int> - This changes the base power of a firework
//
//3: /firework fire - This 'fires' a copy of the firework held.
//3: /firework fire <int> - This 'fires' a number of copies of the firework held.
//3: /firework fire <other> - This 'fires' a copy of the firework held, in the direction you are looking, #easteregg
//
//4: /firework [meta] - This will add an effect to the firework stack held
//4: /firework color:<color> - The minimum you need to set an effect is 'color'
//4: Full Syntax: color:<color[,color,..]> [fade:<color[,color,..]>] [shape:<shape>] [effect:<effect[,effect]>]
//4: Possible Shapes: star, ball, large, creeper, burst
//4: Possible Effects trail, twinkle
public class Commandfirework extends EssentialsCommand {
public Commandfirework() {
super("firework");
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final ItemStack stack = user.getItemInHand();
if (MaterialUtil.isFirework(stack.getType())) {
if (args.length > 0) {
if (args[0].equalsIgnoreCase("clear")) {
FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
fmeta.clearEffects();
stack.setItemMeta(fmeta);
user.sendMessage(tl("fireworkEffectsCleared"));
} else if (args.length > 1 && (args[0].equalsIgnoreCase("power") || (args[0].equalsIgnoreCase("p")))) {
FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
try {
int power = Integer.parseInt(args[1]);
fmeta.setPower(power > 3 ? 4 : power);
} catch (NumberFormatException e) {
throw new Exception(tl("invalidFireworkFormat", args[1], args[0]));
}
stack.setItemMeta(fmeta);
} else if ((args[0].equalsIgnoreCase("fire") || (args[0].equalsIgnoreCase("f"))) && user.isAuthorized("essentials.firework.fire")) {
int amount = 1;
boolean direction = false;
if (args.length > 1) {
if (NumberUtil.isInt(args[1])) {
final int serverLimit = ess.getSettings().getSpawnMobLimit();
amount = Integer.parseInt(args[1]);
if (amount > serverLimit) {
amount = serverLimit;
user.sendMessage(tl("mobSpawnLimit"));
}
} else {
direction = true;
}
}
for (int i = 0; i < amount; i++) {
Firework firework = (Firework) user.getWorld().spawnEntity(user.getLocation(), EntityType.FIREWORK);
FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
if (direction) {
final Vector vector = user.getBase().getEyeLocation().getDirection().multiply(0.070);
if (fmeta.getPower() > 1) {
fmeta.setPower(1);
}
firework.setVelocity(vector);
}
firework.setFireworkMeta(fmeta);
}
} else {
final MetaItemStack mStack = new MetaItemStack(stack);
for (String arg : args) {
try {
mStack.addFireworkMeta(user.getSource(), true, arg, ess);
} catch (Exception e) {
user.sendMessage(tl("fireworkSyntax"));
throw e;
}
}
if (mStack.isValidFirework()) {
FireworkMeta fmeta = (FireworkMeta) mStack.getItemStack().getItemMeta();
FireworkEffect effect = mStack.getFireworkBuilder().build();
if (fmeta.getEffects().size() > 0 && !user.isAuthorized("essentials.firework.multiple")) {
throw new Exception(tl("multipleCharges"));
}
fmeta.addEffect(effect);
stack.setItemMeta(fmeta);
} else {
user.sendMessage(tl("fireworkSyntax"));
throw new Exception(tl("fireworkColor"));
}
}
} else {
throw new NotEnoughArgumentsException();
}
} else {
throw new Exception(tl("holdFirework"));
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
// Note: this enforces an order of color fade shape effect, which the actual command doesn't have. But that's fine.
if (args.length == 1) {
List<String> options = Lists.newArrayList();
if (args[0].startsWith("color:")) {
String prefix;
if (args[0].contains(",")) {
prefix = args[0].substring(0, args[0].lastIndexOf(',') + 1);
} else {
prefix = "color:";
}
for (DyeColor color : DyeColor.values()) {
options.add(prefix + color.name().toLowerCase() + ",");
}
return options;
}
options.add("clear");
options.add("power");
options.add("color:");
if (user.isAuthorized("essentials.firework.fire")) {
options.add("fire");
}
return options;
} else if (args.length == 2) {
if (args[0].equals("power")) {
return Lists.newArrayList("1", "2", "3", "4");
} else if (args[0].equals("fire")) {
return Lists.newArrayList("1");
} else if (args[0].startsWith("color:")) {
List<String> options = Lists.newArrayList();
if (!args[1].startsWith("fade:")) {
args[1] = "fade:";
}
String prefix;
if (args[1].contains(",")) {
prefix = args[1].substring(0, args[1].lastIndexOf(',') + 1);
} else {
prefix = "fade:";
}
for (DyeColor color : DyeColor.values()) {
options.add(prefix + color.name().toLowerCase() + ",");
}
return options;
} else {
return Collections.emptyList();
}
} else if (args.length == 3 && args[0].startsWith("color:")) {
return Lists.newArrayList("shape:star", "shape:ball", "shape:large", "shape:creeper", "shape:burst");
} else if (args.length == 4 && args[0].startsWith("color:")) {
return Lists.newArrayList("effect:trail", "effect:twinkle", "effect:trail,twinkle", "effect:twinkle,trail");
} else {
return Collections.emptyList();
}
}
}
package com.earth2me.essentials.commands;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.DyeColor;
import org.bukkit.FireworkEffect;
import org.bukkit.Server;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Firework;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.FireworkMeta;
import org.bukkit.util.Vector;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
//This command has quite a complicated syntax, in theory it has 4 seperate syntaxes which are all variable:
//
//1: /firework clear - This clears all of the effects on a firework stack
//
//2: /firework power <int> - This changes the base power of a firework
//
//3: /firework fire - This 'fires' a copy of the firework held.
//3: /firework fire <int> - This 'fires' a number of copies of the firework held.
//3: /firework fire <other> - This 'fires' a copy of the firework held, in the direction you are looking, #easteregg
//
//4: /firework [meta] - This will add an effect to the firework stack held
//4: /firework color:<color> - The minimum you need to set an effect is 'color'
//4: Full Syntax: color:<color[,color,..]> [fade:<color[,color,..]>] [shape:<shape>] [effect:<effect[,effect]>]
//4: Possible Shapes: star, ball, large, creeper, burst
//4: Possible Effects trail, twinkle
public class Commandfirework extends EssentialsCommand {
public Commandfirework() {
super("firework");
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final ItemStack stack = user.getItemInHand();
if (MaterialUtil.isFirework(stack.getType())) {
if (args.length > 0) {
if (args[0].equalsIgnoreCase("clear")) {
FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
fmeta.clearEffects();
stack.setItemMeta(fmeta);
user.sendMessage(tl("fireworkEffectsCleared"));
} else if (args.length > 1 && (args[0].equalsIgnoreCase("power") || (args[0].equalsIgnoreCase("p")))) {
FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
try {
int power = Integer.parseInt(args[1]);
fmeta.setPower(power > 3 ? 4 : power);
} catch (NumberFormatException e) {
throw new Exception(tl("invalidFireworkFormat", args[1], args[0]));
}
stack.setItemMeta(fmeta);
} else if ((args[0].equalsIgnoreCase("fire") || (args[0].equalsIgnoreCase("f"))) && user.isAuthorized("essentials.firework.fire")) {
int amount = 1;
boolean direction = false;
if (args.length > 1) {
if (NumberUtil.isInt(args[1])) {
final int serverLimit = ess.getSettings().getSpawnMobLimit();
amount = Integer.parseInt(args[1]);
if (amount > serverLimit) {
amount = serverLimit;
user.sendMessage(tl("mobSpawnLimit"));
}
} else {
direction = true;
}
}
for (int i = 0; i < amount; i++) {
Firework firework = (Firework) user.getWorld().spawnEntity(user.getLocation(), EntityType.FIREWORK);
FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
if (direction) {
final Vector vector = user.getBase().getEyeLocation().getDirection().multiply(0.070);
if (fmeta.getPower() > 1) {
fmeta.setPower(1);
}
firework.setVelocity(vector);
}
firework.setFireworkMeta(fmeta);
}
} else {
final MetaItemStack mStack = new MetaItemStack(stack);
for (String arg : args) {
try {
mStack.addFireworkMeta(user.getSource(), true, arg, ess);
} catch (Exception e) {
user.sendMessage(tl("fireworkSyntax"));
throw e;
}
}
if (mStack.isValidFirework()) {
FireworkMeta fmeta = (FireworkMeta) mStack.getItemStack().getItemMeta();
FireworkEffect effect = mStack.getFireworkBuilder().build();
if (fmeta.getEffects().size() > 0 && !user.isAuthorized("essentials.firework.multiple")) {
throw new Exception(tl("multipleCharges"));
}
fmeta.addEffect(effect);
stack.setItemMeta(fmeta);
} else {
user.sendMessage(tl("fireworkSyntax"));
throw new Exception(tl("fireworkColor"));
}
}
} else {
throw new NotEnoughArgumentsException();
}
} else {
throw new Exception(tl("holdFirework"));
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
// Note: this enforces an order of color fade shape effect, which the actual command doesn't have. But that's fine.
if (args.length == 1) {
List<String> options = Lists.newArrayList();
if (args[0].startsWith("color:")) {
String prefix;
if (args[0].contains(",")) {
prefix = args[0].substring(0, args[0].lastIndexOf(',') + 1);
} else {
prefix = "color:";
}
for (DyeColor color : DyeColor.values()) {
options.add(prefix + color.name().toLowerCase() + ",");
}
return options;
}
options.add("clear");
options.add("power");
options.add("color:");
if (user.isAuthorized("essentials.firework.fire")) {
options.add("fire");
}
return options;
} else if (args.length == 2) {
if (args[0].equals("power")) {
return Lists.newArrayList("1", "2", "3", "4");
} else if (args[0].equals("fire")) {
return Lists.newArrayList("1");
} else if (args[0].startsWith("color:")) {
List<String> options = Lists.newArrayList();
if (!args[1].startsWith("fade:")) {
args[1] = "fade:";
}
String prefix;
if (args[1].contains(",")) {
prefix = args[1].substring(0, args[1].lastIndexOf(',') + 1);
} else {
prefix = "fade:";
}
for (DyeColor color : DyeColor.values()) {
options.add(prefix + color.name().toLowerCase() + ",");
}
return options;
} else {
return Collections.emptyList();
}
} else if (args.length == 3 && args[0].startsWith("color:")) {
return Lists.newArrayList("shape:star", "shape:ball", "shape:large", "shape:creeper", "shape:burst");
} else if (args.length == 4 && args[0].startsWith("color:")) {
return Lists.newArrayList("effect:trail", "effect:twinkle", "effect:trail,twinkle", "effect:twinkle,trail");
} else {
return Collections.emptyList();
}
}
}
@@ -119,7 +119,7 @@ public class Commandgamemode extends EssentialsCommand {
return mode;
}
private List<String> STANDARD_OPTIONS = ImmutableList.of("creative", "survival", "adventure", "spectator", "toggle");
private final List<String> STANDARD_OPTIONS = ImmutableList.of("creative", "survival", "adventure", "spectator", "toggle");
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
@@ -2,11 +2,17 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.PluginManager;
import java.util.Collections;
import java.util.List;
@@ -19,6 +25,31 @@ public class Commandhat extends EssentialsCommand {
super("hat");
}
/**
* The prefix for hat prevention commands
*/
private static final String PERM_PREFIX = "essentials.hat.prevent-type.";
/**
* Register permissions used by this command.
*
* @param toRegister The plugin manager to register permissions in.
*/
public static void registerPermissionsIfNecessary(PluginManager toRegister) {
Permission hatPerm = toRegister.getPermission(PERM_PREFIX + "*");
if (hatPerm != null) {
return;
}
ImmutableMap.Builder<String, Boolean> children = ImmutableMap.builder();
for (Material mat : Material.values()) {
final String matPerm = PERM_PREFIX + mat.name().toLowerCase();
children.put(matPerm, true);
toRegister.addPermission(new Permission(matPerm, "Prevent using " + mat + " as a type of hat.", PermissionDefault.FALSE));
}
toRegister.addPermission(new Permission(PERM_PREFIX + "*", "Prevent all types of hats", PermissionDefault.FALSE, children.build()));
}
@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"))) {
@@ -26,6 +57,8 @@ public class Commandhat extends EssentialsCommand {
final ItemStack head = inv.getHelmet();
if (head == null || head.getType() == Material.AIR) {
user.sendMessage(tl("hatEmpty"));
} else if (VersionUtil.getServerBukkitVersion().isHigherThan(VersionUtil.v1_9_4_R01) && head.getEnchantments().containsKey(Enchantment.BINDING_CURSE) && !user.isAuthorized("essentials.hat.ignore-binding")) {
user.sendMessage(tl("hatCurse"));
} else {
final ItemStack air = new ItemStack(Material.AIR);
inv.setHelmet(air);
@@ -35,9 +68,17 @@ public class Commandhat extends EssentialsCommand {
} else {
final ItemStack hand = user.getItemInHand();
if (hand != null && hand.getType() != Material.AIR) {
if (user.isAuthorized("essentials.hat.prevent-type." + hand.getType().name().toLowerCase())) {
user.sendMessage(tl("hatFail"));
return;
}
if (hand.getType().getMaxDurability() == 0) {
final PlayerInventory inv = user.getBase().getInventory();
final ItemStack head = inv.getHelmet();
if (VersionUtil.getServerBukkitVersion().isHigherThan(VersionUtil.v1_9_4_R01) && head != null && head.getEnchantments().containsKey(Enchantment.BINDING_CURSE) && !user.isAuthorized("essentials.hat.ignore-binding")) {
user.sendMessage(tl("hatCurse"));
return;
}
inv.setHelmet(hand);
inv.setItemInHand(head);
user.sendMessage(tl("hatPlaced"));
@@ -75,8 +75,10 @@ public class Commandheal extends EssentialsLoopCommand {
player.setFoodLevel(20);
player.setFireTicks(0);
user.sendMessage(tl("heal"));
for (PotionEffect effect : player.getActivePotionEffects()) {
player.removePotionEffect(effect.getType());
if (ess.getSettings().isRemovingEffectsOnHeal()) {
for (PotionEffect effect : player.getActivePotionEffects()) {
player.removePotionEffect(effect.getType());
}
}
}
@@ -1,16 +1,19 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.OfflinePlayer;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.StringUtil;
import io.papermc.lib.PaperLib;
import net.ess3.api.events.UserTeleportHomeEvent;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import static com.earth2me.essentials.I18n.tl;
@@ -40,37 +43,71 @@ public class Commandhome extends EssentialsCommand {
}
try {
if ("bed".equalsIgnoreCase(homeName) && user.isAuthorized("essentials.home.bed")) {
final Location bed = player.getBase().getBedSpawnLocation();
if (bed != null) {
user.getTeleport().teleport(bed, charge, TeleportCause.COMMAND);
throw new NoChargeException();
} else {
throw new Exception(tl("bedMissing"));
if (!player.getBase().isOnline() || player.getBase() instanceof OfflinePlayer) {
throw new Exception(tl("bedOffline"));
}
}
goHome(user, player, homeName.toLowerCase(Locale.ENGLISH), charge);
} catch (NotEnoughArgumentsException e) {
Location bed = player.getBase().getBedSpawnLocation();
final List<String> homes = player.getHomes();
if (homes.isEmpty() && player.equals(user)) {
user.getTeleport().respawn(charge, TeleportCause.COMMAND);
} else if (homes.isEmpty()) {
throw new Exception(tl("noHomeSetPlayer"));
} else if (homes.size() == 1 && player.equals(user)) {
goHome(user, player, homes.get(0), charge);
} else {
final int count = homes.size();
if (user.isAuthorized("essentials.home.bed")) {
if (bed != null) {
homes.add(tl("bed"));
PaperLib.getBedSpawnLocationAsync(player.getBase(), true).thenAccept(location -> {
CompletableFuture<Boolean> future = getNewExceptionFuture(user.getSource(), commandLabel);
if (location != null) {
UserTeleportHomeEvent event = new UserTeleportHomeEvent(user, "bed", location, UserTeleportHomeEvent.HomeType.BED);
server.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
future.thenAccept(success -> {
if (success) {
user.sendMessage(tl("teleportHome", "bed"));
}
});
user.getAsyncTeleport().teleport(location, charge, TeleportCause.COMMAND, future);
} else {
homes.add(tl("bedNull"));
showError(user.getBase(), new Exception(tl("bedMissing")), commandLabel);
}
}
user.sendMessage(tl("homes", StringUtil.joinList(homes), count, getHomeLimit(player)));
});
return;
}
goHome(user, player, homeName.toLowerCase(Locale.ENGLISH), charge, getNewExceptionFuture(user.getSource(), commandLabel));
} catch (NotEnoughArgumentsException e) {
final User finalPlayer = player;
CompletableFuture<Location> message = new CompletableFuture<>();
message.thenAccept(bed -> {
final List<String> homes = finalPlayer.getHomes();
if (homes.isEmpty() && finalPlayer.equals(user)) {
if (ess.getSettings().isSpawnIfNoHome()) {
UserTeleportHomeEvent event = new UserTeleportHomeEvent(user, null, bed != null ? bed : finalPlayer.getWorld().getSpawnLocation(), bed != null ? UserTeleportHomeEvent.HomeType.BED : UserTeleportHomeEvent.HomeType.SPAWN);
server.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
user.getAsyncTeleport().respawn(charge, TeleportCause.COMMAND, getNewExceptionFuture(user.getSource(), commandLabel));
}
} else {
showError(user.getBase(), new Exception(tl("noHomeSetPlayer")), commandLabel);
}
} else if (homes.isEmpty()) {
showError(user.getBase(), new Exception(tl("noHomeSetPlayer")), commandLabel);
} else if (homes.size() == 1 && finalPlayer.equals(user)) {
try {
goHome(user, finalPlayer, homes.get(0), charge, getNewExceptionFuture(user.getSource(), commandLabel));
} catch (Exception exception) {
showError(user.getBase(), exception, commandLabel);
}
} else {
final int count = homes.size();
if (user.isAuthorized("essentials.home.bed")) {
if (bed != null) {
homes.add(tl("bed"));
} else {
homes.add(tl("bedNull"));
}
}
user.sendMessage(tl("homes", StringUtil.joinList(homes), count, getHomeLimit(finalPlayer)));
}
});
if (!player.getBase().isOnline() || player.getBase() instanceof OfflinePlayer) {
message.complete(null);
return;
}
PaperLib.getBedSpawnLocationAsync(player.getBase(), true).thenAccept(message::complete);
}
throw new NoChargeException();
}
private String getHomeLimit(final User player) {
@@ -83,7 +120,7 @@ public class Commandhome extends EssentialsCommand {
return Integer.toString(ess.getSettings().getHomeLimit(player));
}
private void goHome(final User user, final User player, final String home, final Trade charge) throws Exception {
private void goHome(final User user, final User player, final String home, final Trade charge, CompletableFuture<Boolean> future) throws Exception {
if (home.length() < 1) {
throw new NotEnoughArgumentsException();
}
@@ -94,36 +131,46 @@ public class Commandhome extends EssentialsCommand {
if (user.getWorld() != loc.getWorld() && ess.getSettings().isWorldHomePermissions() && !user.isAuthorized("essentials.worlds." + loc.getWorld().getName())) {
throw new Exception(tl("noPerm", "essentials.worlds." + loc.getWorld().getName()));
}
user.getTeleport().teleport(loc, charge, TeleportCause.COMMAND);
user.sendMessage(tl("teleportHome", home));
UserTeleportHomeEvent event = new UserTeleportHomeEvent(user, home, loc, UserTeleportHomeEvent.HomeType.HOME);
user.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
user.getAsyncTeleport().teleport(loc, charge, TeleportCause.COMMAND, future);
future.thenAccept(success -> {
if (success) {
user.sendMessage(tl("teleportHome", home));
}
});
}
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
boolean canVisitOthers = user.isAuthorized("essentials.home.others");
boolean canVisitBed = user.isAuthorized("essentials.home.bed");
if (args.length == 1) {
List<String> homes = user.getHomes();
if (canVisitBed) {
homes.add("bed");
}
if (canVisitOthers) {
return getPlayers(server, user);
} else {
List<String> homes = user.getHomes();
if (user.isAuthorized("essentials.home.bed")) {
homes.add("bed");
int sepIndex = args[0].indexOf(':');
if (sepIndex < 0) {
getPlayers(server, user).forEach(player -> homes.add(player + ":"));
} else {
String namePart = args[0].substring(0, sepIndex);
User otherUser;
try {
otherUser = getPlayer(server, new String[]{namePart}, 0, true, true);
} catch (Exception ex) {
return homes;
}
otherUser.getHomes().forEach(home -> homes.add(namePart + ":" + home));
if (canVisitBed) {
homes.add(namePart + ":bed");
}
}
return homes;
}
} else if (args.length == 2 && canVisitOthers) {
try {
User otherUser = getPlayer(server, args, 0, true, true);
List<String> homes = otherUser.getHomes();
if (user.isAuthorized("essentials.home.bed")) {
homes.add("bed");
}
return homes;
} catch (Exception ex) {
// No such user
return Collections.emptyList();
}
return homes;
} else {
return Collections.emptyList();
}
@@ -5,6 +5,7 @@ import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import static com.earth2me.essentials.I18n.tl;
@@ -18,8 +19,11 @@ public class Commandignore extends EssentialsCommand {
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
StringBuilder sb = new StringBuilder();
for (String s : user._getIgnoredPlayers()) {
sb.append(s).append(" ");
for (UUID uuid : user._getIgnoredPlayers()) {
User curUser = ess.getUser(uuid);
if (curUser != null && curUser.getName() != null && !curUser.getName().trim().isEmpty()) {
sb.append(curUser.getName()).append(" ");
}
}
String ignoredList = sb.toString().trim();
user.sendMessage(ignoredList.length() > 0 ? tl("ignoredList", ignoredList) : tl("noIgnored"));
@@ -1,6 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.Server;
import org.bukkit.inventory.Inventory;
@@ -25,6 +26,9 @@ public class Commandinvsee extends EssentialsCommand {
if (args.length > 1 && user.isAuthorized("essentials.invsee.equip")) {
inv = server.createInventory(invUser.getBase(), 9, "Equipped");
inv.setContents(invUser.getBase().getInventory().getArmorContents());
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_9_4_R01)) {
inv.setItem(4, invUser.getBase().getInventory().getItemInOffHand());
}
} else {
inv = invUser.getBase().getInventory();
}
@@ -0,0 +1,75 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commanditemlore extends EssentialsCommand {
public Commanditemlore() {
super("itemlore");
}
@Override
protected void run(Server server, User user, String commandLabel, String[] args) throws Exception {
ItemStack item = user.getBase().getItemInHand();
if (item.getType().name().contains("AIR")) {
throw new Exception(tl("itemloreInvalidItem"));
}
if (args.length == 0) {
throw new NotEnoughArgumentsException();
}
ItemMeta im = item.getItemMeta();
if (args[0].equalsIgnoreCase("add") && args.length > 1) {
String line = FormatUtil.formatString(user, "essentials.itemlore", getFinalArg(args, 1)).trim();
List<String> lore = im.hasLore() ? im.getLore() : new ArrayList<>();
lore.add(line);
im.setLore(lore);
item.setItemMeta(im);
user.sendMessage(tl("itemloreSuccess", line));
} else if (args[0].equalsIgnoreCase("clear")) {
im.setLore(new ArrayList<>());
item.setItemMeta(im);
user.sendMessage(tl("itemloreClear"));
} else if (args[0].equalsIgnoreCase("set") && args.length > 2 && NumberUtil.isInt(args[1])) {
if (!im.hasLore()) {
throw new Exception(tl("itemloreNoLore"));
}
int line = Integer.parseInt(args[1]);
String newLine = FormatUtil.formatString(user, "essentials.itemlore", getFinalArg(args, 2)).trim();
List<String> lore = im.getLore();
try {
lore.set(line - 1, newLine);
} catch (Exception e) {
throw new Exception(tl("itemloreNoLine", line), e);
}
im.setLore(lore);
item.setItemMeta(im);
user.sendMessage(tl("itemloreSuccessLore", line, newLine));
} else {
throw new NotEnoughArgumentsException();
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
if (args.length == 1) {
return Lists.newArrayList("add", "set", "clear");
} else {
return Collections.emptyList();
}
}
}
@@ -1,20 +1,15 @@
package com.earth2me.essentials.commands;
import static com.earth2me.essentials.I18n.tl;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.I18n;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commanditemname extends EssentialsCommand {
public Commanditemname() {
@@ -4,8 +4,6 @@ import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.utils.StringUtil;
import org.bukkit.Server;
import java.util.Collection;
import static com.earth2me.essentials.I18n.tl;
@@ -46,8 +46,7 @@ public class Commandjump extends EssentialsCommand {
final Trade charge = new Trade(this.getName(), ess);
charge.isAffordableFor(user);
user.getTeleport().teleport(loc, charge, TeleportCause.COMMAND);
throw new NoChargeException();
user.getAsyncTeleport().teleport(loc, charge, TeleportCause.COMMAND, getNewExceptionFuture(user.getSource(), commandLabel));
}
@Override
@@ -32,18 +32,13 @@ public class Commandkill extends EssentialsLoopCommand {
if (sender.isPlayer() && user.isAuthorized("essentials.kill.exempt") && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.kill.force")) {
throw new PlayerExemptException(tl("killExempt", matchPlayer.getDisplayName()));
}
final EntityDamageEvent ede = new EntityDamageEvent(matchPlayer, sender.isPlayer() && sender.getPlayer().getName().equals(matchPlayer.getName()) ? EntityDamageEvent.DamageCause.SUICIDE : EntityDamageEvent.DamageCause.CUSTOM, Short.MAX_VALUE);
final EntityDamageEvent ede = new EntityDamageEvent(matchPlayer, sender.isPlayer() && sender.getPlayer().getName().equals(matchPlayer.getName()) ? EntityDamageEvent.DamageCause.SUICIDE : EntityDamageEvent.DamageCause.CUSTOM, Float.MAX_VALUE);
server.getPluginManager().callEvent(ede);
if (ede.isCancelled() && sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.kill.force")) {
return;
}
ede.getEntity().setLastDamageCause(ede);
matchPlayer.damage(Short.MAX_VALUE);
if (matchPlayer.getHealth() > 0) {
matchPlayer.setHealth(0);
}
matchPlayer.setHealth(0);
sender.sendMessage(tl("kill", matchPlayer.getDisplayName()));
}
@@ -62,7 +62,7 @@ public class Commandkit extends EssentialsCommand {
}
String[] kitList = kitNames.split(",");
List<Kit> kits = new ArrayList<Kit>();
List<Kit> kits = new ArrayList<>();
for (final String kitName : kitList) {
if (kitName.isEmpty()) {
@@ -81,8 +81,9 @@ public class Commandkit extends EssentialsCommand {
kit.checkDelay(userFrom);
kit.checkAffordable(userFrom);
if (!kit.expandItems(userTo))
continue;
kit.setTime(userFrom);
kit.expandItems(userTo);
kit.chargeUser(userTo);
if (!userFrom.equals(userTo)) {
@@ -24,11 +24,10 @@ public class Commandlightning extends EssentialsLoopCommand {
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
User user;
if (sender.isPlayer()) {
user = ess.getUser(sender.getPlayer());
if ((args.length < 1 || user != null && !user.isAuthorized("essentials.lightning.others"))) {
user.getWorld().strikeLightning(user.getBase().getTargetBlock((Set<Material>) null, 600).getLocation());
User user = ess.getUser(sender.getPlayer());
if ((args.length < 1 || !user.isAuthorized("essentials.lightning.others"))) {
user.getWorld().strikeLightning(user.getBase().getTargetBlock(null, 600).getLocation());
return;
}
}
@@ -36,7 +35,7 @@ public class Commandlightning extends EssentialsLoopCommand {
if (args.length > 1) {
try {
power = Integer.parseInt(args[1]);
} catch (NumberFormatException ex) {
} catch (NumberFormatException ignored) {
}
}
loopOnlinePlayers(server, sender, true, true, args[0], null);
@@ -64,6 +63,7 @@ public class Commandlightning extends EssentialsLoopCommand {
return super.getTabCompleteOptions(server, user, commandLabel, args);
}
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
@@ -57,14 +57,14 @@ public class Commandlist extends EssentialsCommand {
continue;
}
List<User> outputUserList = new ArrayList<>();
List<User> outputUserList;
final List<User> matchedList = playerList.get(configGroup);
// If the group value is an int, then we might need to truncate it
if (NumberUtil.isInt(groupValue)) {
if (matchedList != null && !matchedList.isEmpty()) {
playerList.remove(configGroup);
outputUserList.addAll(matchedList);
outputUserList = new ArrayList<>(matchedList);
int limit = Integer.parseInt(groupValue);
if (matchedList.size() > limit) {
sender.sendMessage(PlayerList.outputFormat(oConfigGroup, tl("groupNumber", matchedList.size(), commandLabel, FormatUtil.stripFormat(configGroup))));
@@ -86,7 +86,7 @@ public class Commandlist extends EssentialsCommand {
}
Set<String> var = playerList.keySet();
String[] onlineGroups = var.toArray(new String[var.size()]);
String[] onlineGroups = var.toArray(new String[0]);
Arrays.sort(onlineGroups, String.CASE_INSENSITIVE_ORDER);
// If we have an asterisk group, then merge all remaining groups
@@ -98,7 +98,7 @@ public class Commandlist extends EssentialsCommand {
for (String key : asterisk) {
playerList.put(key, asteriskUsers);
}
onlineGroups = asterisk.toArray(new String[asterisk.size()]);
onlineGroups = asterisk.toArray(new String[0]);
}
// If we have any groups remaining after the custom groups loop through and display them
@@ -5,6 +5,7 @@ import com.earth2me.essentials.User;
import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.textreader.TextPager;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.collect.Lists;
@@ -48,7 +49,11 @@ public class Commandmail extends EssentialsCommand {
}
if (user.isMuted()) {
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
}
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
}
User u = getPlayer(server, args[1], true, true);
@@ -2,6 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -24,7 +25,11 @@ public class Commandme extends EssentialsCommand {
@Override
public void run(Server server, User user, String commandLabel, String[] args) throws Exception {
if (user.isMuted()) {
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
}
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
}
if (args.length < 1) {
@@ -1,6 +1,8 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.NumberUtil;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
@@ -17,22 +19,37 @@ public class Commandmore extends EssentialsCommand {
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final ItemStack stack = user.getItemInHand();
if (stack == null) {
if (stack == null || stack.getType() == Material.AIR) {
throw new Exception(tl("cantSpawnItem", "Air"));
}
if (stack.getAmount() >= ((user.isAuthorized("essentials.oversizedstacks")) ? ess.getSettings().getOversizedStackSize() : stack.getMaxStackSize())) {
boolean canOversized = user.isAuthorized("essentials.oversizedstacks");
if (stack.getAmount() >= ((canOversized) ? ess.getSettings().getOversizedStackSize() : stack.getMaxStackSize())) {
throw new Exception(tl("fullStack"));
}
final String itemname = stack.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", "");
if (!user.canSpawnItem(stack.getType())) {
throw new Exception(tl("cantSpawnItem", itemname));
}
if (user.isAuthorized("essentials.oversizedstacks")) {
stack.setAmount(ess.getSettings().getOversizedStackSize());
int newStackSize = stack.getAmount();
if (args.length >= 1) {
if (!NumberUtil.isPositiveInt(args[0])) {
throw new Exception(tl("nonZeroPosNumber"));
}
newStackSize += Integer.parseInt(args[0]);
if (newStackSize > ((canOversized) ? ess.getSettings().getOversizedStackSize() : stack.getMaxStackSize())) {
user.sendMessage(tl(canOversized ? "fullStackDefaultOversize" : "fullStackDefault", canOversized ? ess.getSettings().getOversizedStackSize() : stack.getMaxStackSize()));
newStackSize = canOversized ? ess.getSettings().getOversizedStackSize() : stack.getMaxStackSize();
}
} else if (canOversized) {
newStackSize = ess.getSettings().getOversizedStackSize();
} else {
stack.setAmount(stack.getMaxStackSize());
newStackSize = stack.getMaxStackSize();
}
stack.setAmount(newStackSize);
user.getBase().updateInventory();
}
}
}
@@ -1,17 +1,17 @@
package com.earth2me.essentials.commands;
import static com.earth2me.essentials.I18n.tl;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Console;
import com.earth2me.essentials.User;
import com.earth2me.essentials.messaging.IMessageRecipient;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.Server;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandmsg extends EssentialsLoopCommand {
public Commandmsg() {
@@ -20,7 +20,7 @@ public class Commandmsg extends EssentialsLoopCommand {
@Override
public void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
if (args.length < 2 || args[0].trim().length() < 2 || args[1].trim().isEmpty()) {
if (args.length < 2 || args[0].trim().isEmpty() || args[1].trim().isEmpty()) {
throw new NotEnoughArgumentsException();
}
@@ -29,7 +29,11 @@ public class Commandmsg extends EssentialsLoopCommand {
if (sender.isPlayer()) {
User user = ess.getUser(sender.getPlayer());
if (user.isMuted()) {
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
}
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
}
message = FormatUtil.formatMessage(user, "essentials.msg", message);
canWildcard = user.isAuthorized("essentials.msg.multiple");
@@ -7,6 +7,7 @@ import com.earth2me.essentials.utils.DateUtil;
import net.ess3.api.events.MuteStatusChangeEvent;
import org.bukkit.Server;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.logging.Level;
@@ -40,25 +41,33 @@ public class Commandmute extends EssentialsCommand {
throw new Exception(tl("muteExempt"));
}
}
long muteTimestamp = 0;
String time;
String muteReason = null;
if (args.length > 1) {
time = args[1];
try {
muteTimestamp = DateUtil.parseDateDiff(time, true);
muteReason = getFinalArg(args, 2);
} catch (Exception e) {
muteReason = getFinalArg(args, 1);
}
final long maxMuteLength = ess.getSettings().getMaxMute() * 1000;
if (maxMuteLength > 0 && ((muteTimestamp - GregorianCalendar.getInstance().getTimeInMillis()) > maxMuteLength) && sender.isPlayer() && !(ess.getUser(sender.getPlayer()).isAuthorized("essentials.mute.unlimited"))) {
sender.sendMessage(tl("oversizedMute"));
throw new NoChargeException();
}
}
final boolean willMute = (args.length > 1) || !user.getMuted();
final User controller = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null;
final MuteStatusChangeEvent event = new MuteStatusChangeEvent(user, controller, willMute);
final MuteStatusChangeEvent event = new MuteStatusChangeEvent(user, controller, willMute, muteTimestamp, muteReason);
ess.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
long muteTimestamp = 0;
if (args.length > 1) {
final String time = args[1];
String muteReason;
try {
muteTimestamp = DateUtil.parseDateDiff(time, true);
muteReason = getFinalArg(args, 2);
} catch (Exception e) {
muteReason = getFinalArg(args, 1);
}
if (muteReason != null) {
user.setMuteReason(muteReason.isEmpty() ? null : muteReason);
user.setMuted(true);
} else {
@@ -38,13 +38,13 @@ public class Commandnear extends EssentialsCommand {
} catch (NumberFormatException e) {
try {
otherUser = getPlayer(server, user, args, 0);
} catch (Exception ex) {
} catch (Exception ignored) {
}
}
if (args.length > 1 && otherUser != null) {
try {
radius = Long.parseLong(args[1]);
} catch (NumberFormatException e) {
} catch (NumberFormatException ignored) {
}
}
}
@@ -72,7 +72,7 @@ public class Commandnear extends EssentialsCommand {
if (args.length > 1) {
try {
radius = Long.parseLong(args[1]);
} catch (NumberFormatException e) {
} catch (NumberFormatException ignored) {
}
}
sender.sendMessage(tl("nearbyPlayers", getLocal(server, otherUser, radius)));
@@ -88,7 +88,7 @@ public class Commandnear extends EssentialsCommand {
Queue<User> nearbyPlayers = new PriorityQueue<>((o1, o2) -> (int) (o1.getLocation().distanceSquared(loc) - o2.getLocation().distanceSquared(loc)));
for (User player : ess.getOnlineUsers()) {
if (!player.equals(user) && (!player.isHidden(user.getBase()) || showHidden || user.getBase().canSee(player.getBase()))) {
if (!player.equals(user) && !player.isAuthorized("essentials.near.exclude") && (!player.isHidden(user.getBase()) || showHidden || user.getBase().canSee(player.getBase()))) {
final Location playerLoc = player.getLocation();
if (playerLoc.getWorld() != world) {
continue;
@@ -83,10 +83,17 @@ public class Commandnick extends EssentialsLoopCommand {
throw new Exception(tl("nickNamesAlpha"));
} else if (user != null && (user.isAuthorized("essentials.nick.changecolors") && !user.isAuthorized("essentials.nick.changecolors.bypass")) && !FormatUtil.stripFormat(newNick).equals(user.getName())) {
throw new Exception(tl("nickNamesOnlyColorChanges"));
} else if (user != null && !user.isAuthorized("essentials.nick.blacklist.bypass") && isNickBanned(newNick)) {
throw new Exception(tl("nickNameBlacklist", nick));
}
return newNick;
}
private boolean isNickBanned(String newNick) {
return ess.getSettings().getNickBlacklist().stream()
.anyMatch(entry -> entry.test(newNick));
}
private int getNickLength(final String nick) {
return ess.getSettings().ignoreColorsInMaxLength() ? ChatColor.stripColor(nick).length() : nick.length();
}
@@ -9,6 +9,7 @@ import com.earth2me.essentials.utils.StringUtil;
import com.google.common.collect.Lists;
import net.ess3.api.MaxMoneyException;
import net.ess3.api.events.UserBalanceUpdateEvent;
import org.bukkit.Server;
import java.math.BigDecimal;
@@ -49,7 +50,7 @@ public class Commandpay extends EssentialsLoopCommand {
}
loopOnlinePlayers(server, user.getSource(), false, user.isAuthorized("essentials.pay.multiple"), args[0], args);
if (informToConfirm) {
String cmd = "/" + commandLabel + " " + StringUtil.joinList(" ", (Object[]) args);
String cmd = "/" + commandLabel + " " + StringUtil.joinList(" ", args);
user.sendMessage(tl("confirmPayment", NumberUtil.displayCurrency(amount, ess), cmd));
}
}
@@ -58,7 +59,7 @@ public class Commandpay extends EssentialsLoopCommand {
protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) throws ChargeException {
User user = ess.getUser(sender.getPlayer());
try {
if (!player.isAcceptingPay()) {
if (!player.isAcceptingPay() || (ess.getSettings().isPayExcludesIgnoreList() && player.isIgnoredPlayer(user))) {
sender.sendMessage(tl("notAcceptingPay", player.getDisplayName()));
return;
}
@@ -73,7 +74,7 @@ public class Commandpay extends EssentialsLoopCommand {
user.getConfirmingPayments().put(player, amount);
return;
}
user.payUser(player, amount);
user.payUser(player, amount, UserBalanceUpdateEvent.Cause.COMMAND_PAY);
user.getConfirmingPayments().remove(player);
Trade.log("Command", "Pay", "Player", user.getName(), new Trade(amount, ess), player.getName(), new Trade(amount, ess), user.getLocation(), ess);
} catch (MaxMoneyException ex) {
@@ -1,12 +1,10 @@
package com.earth2me.essentials.commands;
import static com.earth2me.essentials.I18n.tl;
import com.earth2me.essentials.I18n;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import static com.earth2me.essentials.I18n.tl;
public class Commandpaytoggle extends EssentialsCommand {
public Commandpaytoggle() {
@@ -1,31 +1,22 @@
package com.earth2me.essentials.commands;
import org.bukkit.DyeColor;
import com.google.common.collect.Lists;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.Potions;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.collect.Lists;
import net.ess3.nms.refl.ReflUtil;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionData;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.*;
import static com.earth2me.essentials.I18n.tl;
import net.ess3.nms.refl.ReflUtil;
public class Commandpotion extends EssentialsCommand {
public Commandpotion() {
@@ -85,7 +85,7 @@ public class Commandpowertool extends EssentialsCommand {
// Replace all commands with this one
powertools.clear();
} else {
powertools = new ArrayList<String>();
powertools = new ArrayList<>();
}
powertools.add(command);
@@ -122,7 +122,7 @@ public class Commandpowertool extends EssentialsCommand {
for (String tool : powertools) {
options.add("r:" + tool);
}
} catch (Exception e) {}
} catch (Exception ignored) {}
return options;
} else if (args[0].startsWith("a:")) {
return tabCompleteCommand(user.getSource(), server, args[0].substring(2), args, 1);
@@ -151,7 +151,7 @@ public class Commandpowertool extends EssentialsCommand {
for (String tool : powertools) {
options.add("r:" + tool);
}
} catch (Exception e) {}
} catch (Exception ignored) {}
return options;
} else if (args[2].startsWith("a:")) {
return tabCompleteCommand(sender, server, args[2].substring(2), args, 3);
@@ -4,6 +4,7 @@ import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Console;
import com.earth2me.essentials.User;
import com.earth2me.essentials.messaging.IMessageRecipient;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.Server;
@@ -28,7 +29,11 @@ public class Commandr extends EssentialsCommand {
User user = ess.getUser(sender.getPlayer());
if (user.isMuted()) {
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
}
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
}
message = FormatUtil.formatMessage(user, "essentials.msg", message);
@@ -1,195 +1,193 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.*;
import java.util.HashMap;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static com.earth2me.essentials.I18n.tl;
import net.ess3.nms.refl.ReflUtil;
public class Commandrecipe extends EssentialsCommand {
private static final Material FIREWORK_ROCKET = EnumUtil.getMaterial("FIREWORK_ROCKET", "FIREWORK");
private static final Material FIREWORK_STAR = EnumUtil.getMaterial("FIREWORK_STAR", "FIREWORK_CHARGE");
private static final Material GUNPOWDER = EnumUtil.getMaterial("GUNPOWDER", "SULPHUR");
public Commandrecipe() {
super("recipe");
}
private void disableCommandForVersion1_12() throws Exception {
VersionUtil.BukkitVersion version = VersionUtil.getServerBukkitVersion();
if (version.isHigherThanOrEqualTo(VersionUtil.v1_12_0_R01)
&& !ess.getSettings().isForceEnableRecipe()) {
throw new Exception("Please use the recipe book in your inventory.");
}
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
disableCommandForVersion1_12();
if (args.length < 1) {
throw new NotEnoughArgumentsException();
}
final ItemStack itemType = ess.getItemDb().get(args[0]);
int recipeNo = 0;
if (args.length > 1) {
if (NumberUtil.isInt(args[1])) {
recipeNo = Integer.parseInt(args[1]) - 1;
} else {
throw new Exception(tl("invalidNumber"));
}
}
final List<Recipe> recipesOfType = ess.getServer().getRecipesFor(itemType);
if (recipesOfType.size() < 1) {
throw new Exception(tl("recipeNone", getMaterialName(itemType)));
}
if (recipeNo < 0 || recipeNo >= recipesOfType.size()) {
throw new Exception(tl("recipeBadIndex"));
}
final Recipe selectedRecipe = recipesOfType.get(recipeNo);
sender.sendMessage(tl("recipe", getMaterialName(itemType), recipeNo + 1, recipesOfType.size()));
if (selectedRecipe instanceof FurnaceRecipe) {
furnaceRecipe(sender, (FurnaceRecipe) selectedRecipe);
} else if (selectedRecipe instanceof ShapedRecipe) {
shapedRecipe(sender, (ShapedRecipe) selectedRecipe, sender.isPlayer());
} else if (selectedRecipe instanceof ShapelessRecipe) {
if (recipesOfType.size() == 1 && (itemType.getType() == FIREWORK_ROCKET)) {
ShapelessRecipe shapelessRecipe = new ShapelessRecipe(itemType);
shapelessRecipe.addIngredient(GUNPOWDER);
shapelessRecipe.addIngredient(Material.PAPER);
shapelessRecipe.addIngredient(FIREWORK_STAR);
shapelessRecipe(sender, shapelessRecipe, sender.isPlayer());
} else {
shapelessRecipe(sender, (ShapelessRecipe) selectedRecipe, sender.isPlayer());
}
}
if (recipesOfType.size() > 1 && args.length == 1) {
sender.sendMessage(tl("recipeMore", commandLabel, args[0], getMaterialName(itemType)));
}
}
public void furnaceRecipe(final CommandSource sender, final FurnaceRecipe recipe) {
sender.sendMessage(tl("recipeFurnace", getMaterialName(recipe.getInput())));
}
public void shapedRecipe(final CommandSource sender, final ShapedRecipe recipe, final boolean showWindow) {
final Map<Character, ItemStack> recipeMap = recipe.getIngredientMap();
if (showWindow) {
final User user = ess.getUser(sender.getPlayer());
user.getBase().closeInventory();
user.setRecipeSee(true);
final InventoryView view = user.getBase().openWorkbench(null, true);
final String[] recipeShape = recipe.getShape();
final Map<Character, ItemStack> ingredientMap = recipe.getIngredientMap();
for (int j = 0; j < recipeShape.length; j++) {
for (int k = 0; k < recipeShape[j].length(); k++) {
final ItemStack item = ingredientMap.get(recipeShape[j].toCharArray()[k]);
if (item == null) {
continue;
}
if (item.getDurability() == Short.MAX_VALUE) {
item.setDurability((short) 0);
}
view.getTopInventory().setItem(j * 3 + k + 1, item);
}
}
} else {
final HashMap<Material, String> colorMap = new HashMap<>();
int i = 1;
for (Character c : "abcdefghi".toCharArray()) {
ItemStack item = recipeMap.get(c);
if (!colorMap.containsKey(item == null ? null : item.getType())) {
colorMap.put(item == null ? null : item.getType(), String.valueOf(i++));
}
}
final Material[][] materials = new Material[3][3];
for (int j = 0; j < recipe.getShape().length; j++) {
for (int k = 0; k < recipe.getShape()[j].length(); k++) {
ItemStack item = recipe.getIngredientMap().get(recipe.getShape()[j].toCharArray()[k]);
materials[j][k] = item == null ? null : item.getType();
}
}
sender.sendMessage(tl("recipeGrid", colorMap.get(materials[0][0]), colorMap.get(materials[0][1]), colorMap.get(materials[0][2])));
sender.sendMessage(tl("recipeGrid", colorMap.get(materials[1][0]), colorMap.get(materials[1][1]), colorMap.get(materials[1][2])));
sender.sendMessage(tl("recipeGrid", colorMap.get(materials[2][0]), colorMap.get(materials[2][1]), colorMap.get(materials[2][2])));
StringBuilder s = new StringBuilder();
for (Material items : colorMap.keySet().toArray(new Material[colorMap.size()])) {
s.append(tl("recipeGridItem", colorMap.get(items), getMaterialName(items)));
}
sender.sendMessage(tl("recipeWhere", s.toString()));
}
}
public void shapelessRecipe(final CommandSource sender, final ShapelessRecipe recipe, final boolean showWindow) {
final List<ItemStack> ingredients = recipe.getIngredientList();
if (showWindow) {
final User user = ess.getUser(sender.getPlayer());
user.setRecipeSee(true);
final InventoryView view = user.getBase().openWorkbench(null, true);
for (int i = 0; i < ingredients.size(); i++) {
final ItemStack item = ingredients.get(i);
if (item.getDurability() == Short.MAX_VALUE) {
item.setDurability((short) 0);
}
view.setItem(i + 1, item);
}
} else {
StringBuilder s = new StringBuilder();
for (int i = 0; i < ingredients.size(); i++) {
s.append(getMaterialName(ingredients.get(i)));
if (i != ingredients.size() - 1) {
s.append(",");
}
s.append(" ");
}
sender.sendMessage(tl("recipeShapeless", s.toString()));
}
}
public String getMaterialName(final ItemStack stack) {
if (stack == null) {
return tl("recipeNothing");
}
return getMaterialName(stack.getType());
}
public String getMaterialName(final Material type) {
if (type == null) {
return tl("recipeNothing");
}
return type.toString().replace("_", " ").toLowerCase(Locale.ENGLISH);
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
return getItems();
} else {
return Collections.emptyList();
}
}
}
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.*;
import java.util.HashMap;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static com.earth2me.essentials.I18n.tl;
public class Commandrecipe extends EssentialsCommand {
private static final Material FIREWORK_ROCKET = EnumUtil.getMaterial("FIREWORK_ROCKET", "FIREWORK");
private static final Material FIREWORK_STAR = EnumUtil.getMaterial("FIREWORK_STAR", "FIREWORK_CHARGE");
private static final Material GUNPOWDER = EnumUtil.getMaterial("GUNPOWDER", "SULPHUR");
public Commandrecipe() {
super("recipe");
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
// On versions at or above 1.12, we need recipe book API
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_12_0_R01)) {
try {
Class.forName("com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent");
} catch (ClassNotFoundException e) {
sender.sendMessage(tl("unsupportedFeature"));
return;
}
}
if (args.length < 1) {
throw new NotEnoughArgumentsException();
}
final ItemStack itemType = ess.getItemDb().get(args[0]);
int recipeNo = 0;
if (args.length > 1) {
if (NumberUtil.isInt(args[1])) {
recipeNo = Integer.parseInt(args[1]) - 1;
} else {
throw new Exception(tl("invalidNumber"));
}
}
final List<Recipe> recipesOfType = ess.getServer().getRecipesFor(itemType);
if (recipesOfType.size() < 1) {
throw new Exception(tl("recipeNone", getMaterialName(itemType)));
}
if (recipeNo < 0 || recipeNo >= recipesOfType.size()) {
throw new Exception(tl("recipeBadIndex"));
}
final Recipe selectedRecipe = recipesOfType.get(recipeNo);
sender.sendMessage(tl("recipe", getMaterialName(itemType), recipeNo + 1, recipesOfType.size()));
if (selectedRecipe instanceof FurnaceRecipe) {
furnaceRecipe(sender, (FurnaceRecipe) selectedRecipe);
} else if (selectedRecipe instanceof ShapedRecipe) {
shapedRecipe(sender, (ShapedRecipe) selectedRecipe, sender.isPlayer());
} else if (selectedRecipe instanceof ShapelessRecipe) {
if (recipesOfType.size() == 1 && (itemType.getType() == FIREWORK_ROCKET)) {
ShapelessRecipe shapelessRecipe = new ShapelessRecipe(itemType);
shapelessRecipe.addIngredient(GUNPOWDER);
shapelessRecipe.addIngredient(Material.PAPER);
shapelessRecipe.addIngredient(FIREWORK_STAR);
shapelessRecipe(sender, shapelessRecipe, sender.isPlayer());
} else {
shapelessRecipe(sender, (ShapelessRecipe) selectedRecipe, sender.isPlayer());
}
}
if (recipesOfType.size() > 1 && args.length == 1) {
sender.sendMessage(tl("recipeMore", commandLabel, args[0], getMaterialName(itemType)));
}
}
public void furnaceRecipe(final CommandSource sender, final FurnaceRecipe recipe) {
sender.sendMessage(tl("recipeFurnace", getMaterialName(recipe.getInput())));
}
public void shapedRecipe(final CommandSource sender, final ShapedRecipe recipe, final boolean showWindow) {
final Map<Character, ItemStack> recipeMap = recipe.getIngredientMap();
if (showWindow) {
final User user = ess.getUser(sender.getPlayer());
user.getBase().closeInventory();
user.setRecipeSee(true);
final InventoryView view = user.getBase().openWorkbench(null, true);
final String[] recipeShape = recipe.getShape();
final Map<Character, ItemStack> ingredientMap = recipe.getIngredientMap();
for (int j = 0; j < recipeShape.length; j++) {
for (int k = 0; k < recipeShape[j].length(); k++) {
final ItemStack item = ingredientMap.get(recipeShape[j].toCharArray()[k]);
if (item == null) {
continue;
}
if (item.getDurability() == Short.MAX_VALUE) {
item.setDurability((short) 0);
}
view.getTopInventory().setItem(j * 3 + k + 1, item);
}
}
} else {
final HashMap<Material, String> colorMap = new HashMap<>();
int i = 1;
for (Character c : "abcdefghi".toCharArray()) {
ItemStack item = recipeMap.get(c);
if (!colorMap.containsKey(item == null ? null : item.getType())) {
colorMap.put(item == null ? null : item.getType(), String.valueOf(i++));
}
}
final Material[][] materials = new Material[3][3];
for (int j = 0; j < recipe.getShape().length; j++) {
for (int k = 0; k < recipe.getShape()[j].length(); k++) {
ItemStack item = recipe.getIngredientMap().get(recipe.getShape()[j].toCharArray()[k]);
materials[j][k] = item == null ? null : item.getType();
}
}
sender.sendMessage(tl("recipeGrid", colorMap.get(materials[0][0]), colorMap.get(materials[0][1]), colorMap.get(materials[0][2])));
sender.sendMessage(tl("recipeGrid", colorMap.get(materials[1][0]), colorMap.get(materials[1][1]), colorMap.get(materials[1][2])));
sender.sendMessage(tl("recipeGrid", colorMap.get(materials[2][0]), colorMap.get(materials[2][1]), colorMap.get(materials[2][2])));
StringBuilder s = new StringBuilder();
for (Material items : colorMap.keySet().toArray(new Material[0])) {
s.append(tl("recipeGridItem", colorMap.get(items), getMaterialName(items)));
}
sender.sendMessage(tl("recipeWhere", s.toString()));
}
}
public void shapelessRecipe(final CommandSource sender, final ShapelessRecipe recipe, final boolean showWindow) {
final List<ItemStack> ingredients = recipe.getIngredientList();
if (showWindow) {
final User user = ess.getUser(sender.getPlayer());
user.setRecipeSee(true);
final InventoryView view = user.getBase().openWorkbench(null, true);
for (int i = 0; i < ingredients.size(); i++) {
final ItemStack item = ingredients.get(i);
if (item.getDurability() == Short.MAX_VALUE) {
item.setDurability((short) 0);
}
view.setItem(i + 1, item);
}
} else {
StringBuilder s = new StringBuilder();
for (int i = 0; i < ingredients.size(); i++) {
s.append(getMaterialName(ingredients.get(i)));
if (i != ingredients.size() - 1) {
s.append(",");
}
s.append(" ");
}
sender.sendMessage(tl("recipeShapeless", s.toString()));
}
}
public String getMaterialName(final ItemStack stack) {
if (stack == null) {
return tl("recipeNothing");
}
return getMaterialName(stack.getType());
}
public String getMaterialName(final Material type) {
if (type == null) {
return tl("recipeNothing");
}
return type.toString().replace("_", " ").toLowerCase(Locale.ENGLISH);
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
return getItems();
} else {
return Collections.emptyList();
}
}
}
@@ -6,6 +6,7 @@ import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Mob;
import com.earth2me.essentials.User;
import org.bukkit.Chunk;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.*;
@@ -126,8 +127,8 @@ public class Commandremove extends EssentialsCommand {
for (ToRemove toRemove : removeTypes) {
// We should skip any TAMED animals unless we are specifially targetting them.
if (e instanceof Tameable && ((Tameable) e).isTamed() && !removeTypes.contains(ToRemove.TAMED)) {
// We should skip any animals tamed by players unless we are specifially targetting them.
if (e instanceof Tameable && ((Tameable) e).isTamed() && (((Tameable) e).getOwner() instanceof Player || ((Tameable) e).getOwner() instanceof OfflinePlayer) && !removeTypes.contains(ToRemove.TAMED)) {
continue;
}
Loaded 100 of 325 files, more files were not shown because too many files have changed in this diff. Show more