Compare commits

...
531 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
md678685 0584353bfa Bump version to 2.17-pre1 2019-06-26 15:32:08 +01:00
md678685 2938330222 Load and save kit use timestamps consistently
Fixes #2301.

The kit's name was previously sanitised/lowercased when accessed but not when saved. This fixes that. ensuring the kit delay will be reported correctly.

Tested on 1.14.3 - does not appear to break existing kit delays.
2019-06-26 12:54:19 +01:00
md678685 ef7393036e Update to 1.14.3 2019-06-26 11:49:10 +01:00
Josh Roy 0409f5bc4a Update 1.14.3 version string (#2624)
Closes #2624.
2019-06-26 11:48:50 +01:00
Josh Roy 8ff1ebd7c2 Fix version regex on 1.14.3 (#2622) @JRoy 2019-06-25 07:18:16 +01:00
md678685 9089fe8be3 Attempt to fall back to Material.getMaterial(int) below 1.13
Fixes #2615.
2019-06-24 09:41:33 +01:00
Johnny Cao 74d96ce624 Fixes #2121 - Allow players to teleport into a location with water if configured (#2520)
# Description of #2520
This is a continuation of #2457, accidentally hit rebase and recommitted a load of commits from the 2.x log into my repo...

I've reverted the code and added the configuration option, modifying the `LocationUtil#HOLLOW_MATERIALS` as necessary when the config is loaded.

New demo: streamable.com/pm50r
```
[16:01:00 INFO]: Server version: 1.13.2-R0.1-SNAPSHOT git-Spigot-3cb9dcb-77ca7ca (MC: 1.13.2)
[16:01:00 INFO]: EssentialsX version: 2.16.1.154
[16:01:00 INFO]: Vault is not installed. Chat and permissions may not work.
```

# Description of #2457
Fixes #2121.

Prior to the addition of this patch, teleporting from another world through commands such as `/spawn` and `/home` would cause players to be teleported to the surface of the water. After this patch, using the same command will correctly teleport them to the original location.

In seeing that the addition of water would cause the `HOLLOW_MATERIALS` set to be identical to the `TRANSPARENT_MATERIALS`, I have removed the latter's usage and simply added water to the former.

I'm not exactly sure if adding water to `HOLLOW_MATERIALS` is the right decision, but it fixes the issue, and I personally don't really see any point in not having water in the list. I imagine some people might use this as a way to drop players on the surface of the water, but they can fix that issue quite easily by actually going to the surface and setting the location there. I also can see that water is not necessarily a "safe" location because players can drown, but I really see no other alternative. 

The only reason it works like normal in the same world is because the safe location method exempts locations in the same world as the teleporting player, and thus this check is never even performed in the first place for those players anyway.

**Demo**
```
[16:22:49 INFO]: CONSOLE issued server command: /ess version
[16:22:49 INFO]: Server version: 1.13.2-R0.1-SNAPSHOT git-Paper-"16db0e6a" (MC: 1.13.2)
[16:22:49 INFO]: EssentialsX version: 2.16.1.9
[16:22:49 INFO]: LuckPerms version: 4.3.73
[16:22:49 INFO]: Vault is not installed. Chat and permissions may not work.
```
https://streamable.com/71072
2019-06-17 11:28:12 +01:00
md678685 8b7bcbb880 Don't update user activity on physical interactions
Fixes #2578.
2019-06-17 11:06:45 +01:00
md678685 dbd86155fb Only accept square recipes in /condense
Fixes #1194.
2019-06-16 13:28:02 +01:00
md678685 9b77c0802b Switch Travis to openjdk8 2019-06-16 11:25:25 +01:00
md678685 cd7fa79560 Don't warn about CloudNet SLPEs
Fixes #2592.
2019-06-16 11:13:32 +01:00
md678685 10e9879a64 Update to 1.14.x (#2510)
Add support for Spigot/Paper 1.14.2.
2019-06-16 10:15:12 +01:00
md678685 d1dcc47a27 Specify Java 8 for Travis build
Required due to BuildTools not supporting Java 9 or above for MC 1.8.x.
2019-06-16 10:12:35 +01:00
Pokechu22 7a73301a37 Add permissions for individual colors (#1441)
* Add tests for existing format behavior

* Replace formatting implementation

* Add permissions for individual color codes

Resolves #415

* Use format code names

* Fix escaping

* Mockito: test scope only

* Explicitly check the .magic permission

Once I switch to checking if a perm's set in the loop, the explicit check is needed for an * perm.

* Add support for removing individual colors

* Use `obfuscated` as the name for §k

`magic` is still accepted as the group name, so this is not a breaking change.
2019-06-09 15:56:58 +01:00
md678685 e1dec7d9e7 Fix items.json merging 2019-06-09 15:34:24 +01:00
md678685 99fefdb47d Re-add header to items.json 2019-06-09 15:18:16 +01:00
md678685 5ebce8965e Merge 1.13 and 1.14 items.json together
In 2.17.0, [essx-scripts genItemsFlat](https://github.com/md678685/essx-scripts/blob/master/src/genItemsFlat.js) is being replaced with [ItemDbGenerator](https://github.com/md678685/ItemDbGenerator). To ease migration, this is a file generated by merging the 1.14 entries from the new generator into the existing 1.13 file. This will be replaced by an items.json generated entirely by ItemDbGenerator eventually.
2019-06-09 15:10:12 +01:00
md678685 5a0b7285d4 Add FUNDING.yml Patreon link 2019-06-09 13:04:51 +01:00
md678685 829110e89a Implement missing OfflinePlayer methods 2019-06-09 12:59:32 +01:00
md678685 dc1a0b65fa Merge branch 'mc/1.14' of https://github.com/EssentialsX/Essentials into mc/1.14 2019-06-09 12:58:06 +01:00
md678685 b140826e60 Remove unused import in MaterialUtil 2019-06-09 12:21:40 +01:00
md678685 0d9387458d Remove unused import in AFK event 2019-06-09 12:21:25 +01:00
md678685 f2447a9134 Add fallbacks property to ItemData
Allows items.json to specify fallback names for materials on older versions.

Additionally make non-API methods inaccessible, as they shouldn't be needed by other plugins.
2019-05-31 15:57:51 +01:00
md678685 2ea3d8943e Update outdated meme 2019-05-30 19:34:18 +01:00
Drew Mitchell e4cc78a750 Implement PR #1682 - TPA Event (#1727) @DrewAMitchell
* Attempts to implement #1682 - TPARequestEvent
Awaiting further feedback. I've implemented the event, and elected to send a message to the requester of the TPA when the event gets cancelled.
* Fix formatting
* Fix up l18s errors, remove todos
* Clean up for merge
2019-05-30 19:17:57 +01:00
md678685 a08832cfc8 Implement /itemname command (#2573)
Implement /itemname command, across three PRs. Originally implemented by SupaHam, and updated by zsturgess and myself.
2019-05-30 19:16:43 +01:00
md678685 c97918df24 Add safe-usermap-names option to control usermap key sanitisation
This is necessary to stop players with Chinese characters in their username losing their balances.
2019-05-30 18:50:51 +01:00
Glare e9833d1cd2 Implement essentials.balancetop.exclude permission (#2499)
Closes #595.
2019-05-30 15:20:30 +01:00
md678685 111a18585d Allow clearing item names + add locale messages for /itemname 2019-05-30 15:12:52 +01:00
Zac Sturgess 155d3ec938 Update /itemname in plugin.yml
This contains changes from #2555 squashed into one commit.

Closes #2555.
2019-05-30 14:53:15 +01:00
Ali Moghnieh 8bafacbd51 Create /itemname command that names held items.
This contains changes from #672 minus messages, squashed into one commit.

Closes #672.
2019-05-30 14:53:06 +01:00
montlikadani 0e3f48ee54 Improve disposal, /bigtree and /fireball (#2461) @montlikadani
* Allow the Disposal inventory title to be configurable
* Add darkoak to `/bigtree`'s usage message
* Allow potions to be fired with `/fireball`

## Commits
* Update plugin.yml
* Update Commanddisposal.java
* Update messages.properties
* Update Commandfireball.java
* Update SignDisposal.java
* Fix import
* Remove colour code from disposal message
2019-05-30 14:03:12 +01:00
Trent Hensler b566b4a0c6 Update translations from Crowdin (#2571)
* New translations messages.properties (German)
* New translations messages.properties (Romanian)
* New translations messages.properties (Korean)
* 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)
* New translations messages.properties (Portuguese, Brazilian)
* New translations messages.properties (Russian)
* New translations messages.properties (Italian)
* New translations messages.properties (Serbian (Cyrillic))
* 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 (Turkish)
* New translations messages.properties (Japanese)
* New translations messages.properties (Icelandic)
* New translations messages.properties (Dutch)
* New translations messages.properties (Bulgarian)
* New translations messages.properties (Vietnamese)
* New translations messages.properties (French)
* New translations messages.properties (Hungarian)
* New translations messages.properties (English, United Kingdom)
* New translations messages.properties (English, United States)
* New translations messages.properties (Basque)
* New translations messages.properties (Bosnian)
* New translations messages.properties (Chinese Simplified)
* New translations messages.properties (Hebrew)
* New translations messages.properties (Chinese Traditional)
* 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 (Estonian)
* New translations messages.properties (Finnish)
* New translations messages.properties (Greek)
* New translations messages.properties (Ukrainian)
2019-05-28 17:56:17 +01:00
md678685 a9ed66d5e0 Add essentials.keepinv to plugin.yml 2019-05-28 12:24:07 +01:00
Josh Roy 94131edb32 Bump Bukkit to 1.14.2 (#2569)
* Bump to API 1.14.2

* Update v1_14_2_R01 as latest supported 1.14 build
2019-05-27 23:12:23 +01:00
md678685 e21863956c Fix checking for attached wall signs 2019-05-27 11:51:56 +01:00
md678685 4201e6ef85 Make all events async when not on primary thread
Fixes #2566, fixes #2556, fixes #2545.
2019-05-26 12:08:58 +01:00
Trent Hensler 5deb1de555 Allow AFK status test to pass. 2019-05-22 12:06:27 -07:00
md678685 c65534ebb1 Only make AfkStatusChangeEvent async when off primary thread 2019-05-22 11:39:26 +01:00
md678685 f22efce3ca Use MobCompat entries for other 1.11+ mobs 2019-05-18 23:51:40 +01:00
md678685 5f0909047d Use MobCompat.CAT throughout MobData 2019-05-18 22:45:43 +01:00
md678685 7cc4dc2f07 Make AfkStatusChangeEvent async 2019-05-18 20:56:57 +01:00
md678685 60ebe9e738 Add llama colour support; improve support for old game versions
Fixes issues with /spawnmob on older versions of the game.

(Also add llama colours, which were missing from the 1.11 update.)
2019-05-18 20:56:34 +01:00
minksuki a1297feb9d adds a permission node that keeps a player's inventory on death (#2531) @minksuki
Closes #2524.

Adds a permission node, `essentials.keepinv` so on player death their inventory will not be wiped.
2019-05-15 07:59:48 +01:00
Josh Roy 09598d0173 Update Bukkit to 1.14.1 (#2544)
* Update v1_14_1_R01 as latest supported 1.14 build

* Bump to API 1.14.1
2019-05-14 09:00:22 +01:00
md678685 35fc845040 Fix Metrics plugin name reporting 2019-05-13 19:15:33 +01:00
md678685 e59950966f Fix Metrics package name 2019-05-13 19:14:01 +01:00
md678685 98cc5b33a3 Update bStats Metrics to latest version
Now featuring server brand support!
2019-05-12 16:17:00 +01:00
Julian van Doorn d107d00ac3 Fix spawning shields with enchantments (#2515) @Argetan
* Moved comment to newline for style consistency.
* Fixed issue 2507 by checking if an enchantment is being applied.
* Added a couple newlines for readability.
* Removed faulty ifs).
2019-05-12 13:50:35 +01:00
md678685 ccc000a416 Add Villager variants, pt 2 2019-05-09 22:20:45 +01:00
md678685 7790f8818b Add Villager variants, pt 1 2019-05-09 15:12:51 +01:00
JRoy 72ca629cf1 Add 1.14 Enchantments 2019-05-09 13:36:09 +01:00
md678685 65017d7f5c Fix /kittycannon
The most important command of all!

(This hasn't been tested with 1.13 or below yet.)
2019-05-08 23:29:55 +01:00
md678685 6d4f7afc79 Improve VersionUtil prerelease handling
Actually includes updated regex this time! (I have no idea how I forgot to update it in cfba203981 - I had already written out the regex)

Incorporates part of https://github.com/EssentialsX/Essentials/pull/2523 - thanks @JRoy.
2019-05-08 23:26:40 +01:00
md678685 4fcb032791 Update FakeServer 2019-05-08 23:23:15 +01:00
md678685 0e668fa0f2 Fix plural suffixes for fish and foxes 2019-05-08 23:06:50 +01:00
md678685 68b933a501 Add Ocelot.Type fallbacks for all MobCompat.CatTypes 2019-05-08 23:06:28 +01:00
md678685 5236ad9f64 Remove redundant BABY_FOX 2019-05-08 22:56:25 +01:00
md678685 937c18fe1d Update FakeWorld 2019-05-08 22:43:57 +01:00
md678685 fb48aaba9d Initial cross-version mob compatibility
Incorporates part of https://github.com/EssentialsX/Essentials/pull/2523 - thanks @JRoy.
2019-05-08 22:40:51 +01:00
md678685 365efe4f2d Implement missing FakeWorld and OfflinePlayer methods 2019-05-08 13:49:54 +01:00
md678685 78b2dba42a Bump to API 1.14 2019-05-08 13:49:35 +01:00
Julian van Doorn f793b7607f OS X compatible buildtools.sh (#2513) @Argetan
* OS X compatible buildtools.sh

* Update buildtools.sh
2019-04-30 07:55:54 +01:00
md678685 c567bc22e9 Compile against 1.14-pre5 2019-04-24 14:30:53 +01:00
md678685 d282462547 Use MaterialUtil to check signs 2019-04-24 14:28:15 +01:00
md678685 af4cfd3fe9 Update bStats Metrics to use Gson 2019-04-24 13:54:33 +01:00
md678685 cfba203981 Add prerelease support to VersionUtil 2019-04-24 13:37:43 +01:00
Glare Masters d680ed7363 Check /tpacancel permissions before sending message (#2498)
Fixes #1354.
2019-04-23 09:22:50 +01:00
md678685 69232c0717 Fix missing formatting code in geoipCantFind 2019-04-22 15:24:31 +01:00
latiku b4baa28f01 fix geoip country returning "." if the user is joining from localhost (#2494) @latiku
Implements a check to see if the user's address is `localhost` or `127.0.0.1`, and if so return that the country is unknown.

**Edit by @md678685: fixes #2471.**
2019-04-22 09:38:06 +01:00
md678685 0aa11b58b9 Update items.json
Updated to md678685/essx-scripts@e6394a2884

* Fix overlapping armor/wooden pressure plate aliases
2019-04-19 15:10:10 +01:00
md678685 7b60b562b9 Update items.json
Update items.json to md678685/essx-scripts@581db130ef

Changes:
* Add pressure plate aliases
* Add "mushroomcow" aliases for mooshroom spawners
* Add zombie pigman spawner aliases
2019-04-19 14:49:36 +01:00
montlikadani 6377cbfb2b Remove stale messages and add/change formatting in others (#2486) 2019-04-18 13:25:25 -04:00
montlikadani 3f5f9cc717 Fixed when the mail has already cleared (#2063) 2019-04-18 13:18:42 -04:00
Johnny Cao eac1e9b574 Fixes #1928 - Auto-AFK issue: AFK timer not reset on disconnect (#2458)
Update activity regardless of cancel-afk-on-interact setting
2019-04-17 20:45:07 -04:00
Glare Masters 26d63da7aa [Feature] Implemented a message to say teleporting to home. (#2489)
[Feature] Implemented a message to say teleporting to home.
2019-04-17 19:14:44 -04:00
Joseph Hirschfeld 722181439e Merge pull request #1953 from Xeyame/#1899
Expand /exp command
2019-04-17 12:18:58 -04:00
Joseph Hirschfeld ddcb7041f1 Merge pull request #2455 from AgentTroll/patch-94
Fixes #94 - Player with same first letters conflict
2019-04-17 02:46:20 -04:00
Joseph Hirschfeld 8af33e0ae2 Merge pull request #2166 from mathiascode/commandevents
Use chat instead of dispatchCommand
2019-04-17 02:33:29 -04:00
Joseph Hirschfeld d01e12ac14 Merge pull request #2158 from pop4959/near-fix
Sort /near by nearest player.
2019-04-17 02:31:38 -04:00
Joseph Hirschfeld 8c0aa840ab Merge pull request #1949 from Ichbinjoe/2.x_feature_jail_no_teleport
[Feature] Add config optn. to disable jail free tp
2019-04-17 02:04:16 -04:00
md678685 05118e9498 Merge pull request #2484 from Xeyame/2.x
Allow using environment variable to set xmx flag in buildtools.sh
2019-04-16 15:47:23 +01:00
Xeyame 7838adf833 Allow using environment variable to set xmx flag 2019-04-16 16:34:57 +02:00
md678685 e230cee91e Add new item database API (#2472)
* Allow resolver functions to be added to item databases

* Allow resolvers to add item names to list

* Make getResolverNames package-private
2019-04-15 10:09:16 +01:00
md678685 8e4fc77244 Merge pull request #2469 from N3FS/feature/command-send
Add PlayerCommandSendEvent listener to hide commands in autocomplete
2019-04-15 10:07:49 +01:00
md678685 0d572036f8 New Crowdin translations (#2476)
* New translations messages.properties (English, United States)

* New translations messages.properties (Russian)

* New translations messages.properties (Korean)

* New translations messages.properties (Lithuanian)

* New translations messages.properties (Polish)

* New translations messages.properties (Portuguese)

* New translations messages.properties (Portuguese, Brazilian)

* New translations messages.properties (Romanian)

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

* New translations messages.properties (Italian)

* 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 (Turkish)

* New translations messages.properties (Ukrainian)

* New translations messages.properties (Japanese)

* New translations messages.properties (Hungarian)

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

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

* New translations messages.properties (German)

* New translations messages.properties (Norwegian)

* New translations messages.properties (Bulgarian)

* New translations messages.properties (Basque)

* New translations messages.properties (Bosnian)

* New translations messages.properties (Chinese Simplified)

* New translations messages.properties (Chinese Traditional)

* New translations messages.properties (Croatian)

* New translations messages.properties (Hebrew)

* New translations messages.properties (Czech)

* New translations messages.properties (Danish)

* New translations messages.properties (Dutch)

* New translations messages.properties (Estonian)

* New translations messages.properties (Finnish)

* New translations messages.properties (French)

* New translations messages.properties (Greek)

* New translations messages.properties (Vietnamese)
2019-04-07 21:21:29 +01:00
md678685 26fdd0ff6b Fix playerMutedFor[Reason] formatting codes 2019-04-07 21:19:45 +01:00
Trent Hensler 70a4aee930 New translations messages.properties (Vietnamese) 2019-04-07 13:11:55 -07:00
Trent Hensler 3631323aa7 New translations messages.properties (Greek) 2019-04-07 13:11:53 -07:00
Trent Hensler 1fd7d18056 New translations messages.properties (French) 2019-04-07 13:11:51 -07:00
Trent Hensler a60f67cd0a New translations messages.properties (Finnish) 2019-04-07 13:11:49 -07:00
Trent Hensler 5ba781d00e New translations messages.properties (Estonian) 2019-04-07 13:11:46 -07:00
Trent Hensler 17c5d25996 New translations messages.properties (Dutch) 2019-04-07 13:11:44 -07:00
Trent Hensler bd9f271eff New translations messages.properties (Danish) 2019-04-07 13:11:42 -07:00
Trent Hensler 89b4bd2405 New translations messages.properties (Czech) 2019-04-07 13:11:40 -07:00
Trent Hensler 4da9095c59 New translations messages.properties (Hebrew) 2019-04-07 13:11:37 -07:00
Trent Hensler 75e84a5797 New translations messages.properties (Croatian) 2019-04-07 13:11:35 -07:00
Trent Hensler 54d64dbb5f New translations messages.properties (Chinese Traditional) 2019-04-07 13:11:32 -07:00
Trent Hensler 03e746953c New translations messages.properties (Chinese Simplified) 2019-04-07 13:11:30 -07:00
Trent Hensler ec8a51b06c New translations messages.properties (Bosnian) 2019-04-07 13:11:28 -07:00
Trent Hensler 369c08a624 New translations messages.properties (Basque) 2019-04-07 13:11:26 -07:00
Trent Hensler 7a8e5e92d9 New translations messages.properties (Bulgarian) 2019-04-07 13:11:23 -07:00
Trent Hensler 185ec7ff2b New translations messages.properties (Norwegian) 2019-04-07 13:11:21 -07:00
Trent Hensler af986cc7b2 New translations messages.properties (German) 2019-04-07 13:11:18 -07:00
Trent Hensler 25d96ccfa7 New translations messages.properties (Chinese Traditional, Hong Kong) 2019-04-07 13:11:16 -07:00
Trent Hensler b45c42ef22 New translations messages.properties (English, United Kingdom) 2019-04-07 13:11:14 -07:00
Trent Hensler ea2ac3d483 New translations messages.properties (Hungarian) 2019-04-07 13:11:12 -07:00
Trent Hensler 873df96d0d New translations messages.properties (Japanese) 2019-04-07 13:11:10 -07:00
Trent Hensler d69495baa7 New translations messages.properties (Ukrainian) 2019-04-07 13:11:08 -07:00
Trent Hensler 06ff8f24fe New translations messages.properties (Turkish) 2019-04-07 13:11:06 -07:00
Trent Hensler b996608455 New translations messages.properties (Thai) 2019-04-07 13:11:04 -07:00
Trent Hensler 6c1c22132e New translations messages.properties (Swedish) 2019-04-07 13:11:02 -07:00
Trent Hensler 8b326d5852 New translations messages.properties (Spanish) 2019-04-07 13:11:00 -07:00
Trent Hensler dd34f65c98 New translations messages.properties (Slovak) 2019-04-07 13:10:58 -07:00
Trent Hensler 0bd0f853f3 New translations messages.properties (Serbian (Latin)) 2019-04-07 13:10:55 -07:00
Trent Hensler e7a75efaff New translations messages.properties (Italian) 2019-04-07 13:10:53 -07:00
Trent Hensler 2904b50061 New translations messages.properties (Serbian (Cyrillic)) 2019-04-07 13:10:51 -07:00
Trent Hensler 3b6ac632d9 New translations messages.properties (Romanian) 2019-04-07 13:10:48 -07:00
Trent Hensler 9ad3f0e0d7 New translations messages.properties (Portuguese, Brazilian) 2019-04-07 13:10:45 -07:00
Trent Hensler 9529a4ba02 New translations messages.properties (Portuguese) 2019-04-07 13:10:42 -07:00
Trent Hensler 69b9ab097b New translations messages.properties (Polish) 2019-04-07 13:10:40 -07:00
Trent Hensler 4b14c4bcc6 New translations messages.properties (Lithuanian) 2019-04-07 13:10:38 -07:00
Trent Hensler 5154c670c0 New translations messages.properties (Korean) 2019-04-07 13:10:36 -07:00
Trent Hensler 09b699cc9c New translations messages.properties (Russian) 2019-04-07 13:10:34 -07:00
Trent Hensler f2a212e3a4 New translations messages.properties (English, United States) 2019-04-07 13:10:31 -07:00
md678685 19ca946e3b Add Estonian alias to Crowdin config 2019-04-07 21:08:30 +01:00
md678685 e21be39c13 Add Basque alias to Crowdin config 2019-04-07 21:02:42 +01:00
md678685 8fcfff7abd Update Crowdin config 2019-04-07 21:01:22 +01:00
md678685 bcc150a014 Update l10n configs 2019-04-07 20:22:48 +01:00
md678685 3d97e93831 Implement missing OfflinePlayer location methods 2019-04-07 17:06:17 +01:00
md678685 9d93d4db54 Only log removed commands is debug enabled 2019-04-07 17:03:56 +01:00
md678685 0d8aec7eea Add PlayerCommandSendEvent listener to hide commands in autocomplete 2019-03-31 20:35:47 +01:00
md678685 7b165c6c2c Merge pull request #2450 from AgentTroll/patch-2414
Fixes #2414 - Warp signs no permission message
2019-03-15 12:11:17 +00:00
md678685 d3cee314c6 Merge pull request #2451 from AgentTroll/patch-2403
Fixes #2403 - Ability to execute /back for another player
2019-03-15 12:10:33 +00:00
md678685 4395245aab Merge pull request #2454 from AgentTroll/patch-2415
Fixes #2415 - Command for last reply message option
2019-03-15 12:10:10 +00:00
md678685 9d4b0a13c5 Merge remote-tracking branch 'origin/pr/1557' into 2.x 2019-03-15 11:59:35 +00:00
md678685 c908290c27 Simplify willMute condition 2019-03-15 11:58:30 +00:00
md678685 f5c21d1089 Merge branch '2.x' into final_mute_reason_issue#385 2019-03-15 11:52:50 +00:00
Johnny Cao 883fc75f47 Clarifies the last recipient config key 2019-03-10 01:42:10 -08:00
AgentTroll eaac3049af Fix getPlayer(...) for offline players having similar names 2019-03-09 18:50:55 -08:00
AgentTroll f68fb52af1 Add command to toggle reply player functionality 2019-03-09 15:39:45 -08:00
AgentTroll 863bd5a89e Add /back target capability 2019-03-08 22:41:59 -08:00
AgentTroll 50225624a5 Add message for failing sign warp permission check 2019-03-08 15:53:04 -08:00
md678685 25ddaef423 Merge pull request #2329 from triagonal/issue-2311
Implement config option for sleep ignoring AFK players
2019-03-08 22:15:53 +00:00
md678685 585f2bef07 Merge pull request #2310 from pop4959/command-tpauto
Implement tpauto command
2019-03-08 17:19:31 +00:00
md678685 017ea1a4fe Remove unnecessary types 2019-03-08 11:24:42 +00:00
md678685 3b4b5bcd8e Remove Lombok
Remove the (already minimal) usage of Lombok. This will ease development for people who don't already have their IDE set up for Lombok support.

It's also totally unnecessary - it took less than 60 seconds to generate the code needed to replace Lombok annotations in Jails and Spawns.
2019-03-08 11:24:42 +00:00
md678685 f57557b43a Bump version to 2.16.1 2019-03-01 22:45:25 +00:00
md678685 0711fd6f9e Add #version line to allow automatic items.json updates 2019-03-01 12:04:08 +00:00
md678685 b5ecbd1739 Remove Vault repo
Fixes Travis builds and slow builds - Maven pauses while trying to reach the repo and so Travis assumes that the build has failed.
2019-03-01 11:41:29 +00:00
md678685 dda5e4e333 Merge pull request #2402 from Techno3600/patch-1
Pull Request for #2282
2019-03-01 11:32:46 +00:00
pop4959 74b0e71015 More efficient distance calculation 2019-02-26 19:54:19 -08:00
md678685 dde4a36df0 Economy API: Attempt to find users by UUID if username not present (#2432)
Attempt to find user by UUID if username not present. Fixes (maybe) #2400.

https://github.com/EssentialsX/Essentials/issues/2400#issuecomment-466043896
2019-02-22 18:10:36 +00:00
triagonal 31b98fb9f3 allow console to use color codes when sending mail (#2435) @triagonal 2019-02-22 14:34:56 +00:00
kashike 289d34d96c Relocate PaperLib in EssentialsXSpawn too
fixes #2433
2019-02-22 09:58:02 +00:00
md678685 eafd110ed0 Update items.json
Add spawner aliases that end in "spawner".
2019-02-20 14:50:43 +00:00
md678685 e72644abf4 Update items.json
* Add mooshroom spawners
* Add new aliases for red sandstone, sandstone, stone and prismarine variants
2019-02-20 14:42:22 +00:00
md678685 b267103274 Remove getMap(short) method from FakeServer 2019-02-20 12:45:37 +00:00
DoNotSpamPls 3856a690eb Use PaperLib to load chunks and teleport players async (#2409)
* Remove outdated permission plugin handlers, minor test fixes

* Re-add PermissionEX handler

* Use PaperLib to load chunks async whenever possible

* Revert "Use PaperLib to load chunks async whenever possible"

This reverts commit db4df6f3cf.

* Use PaperLib to load chunks and teleport players async

* Resolve some PR issues

* Update PaperLib, return teleport causes

* Remove useless PaperLib usage in LocationUtil

* Fix FakeServer spacing
2019-02-20 12:25:05 +00:00
md678685 f214696664 Check Protect/AntiBuild config materials against Material enum (#2431) 2019-02-20 12:24:30 +00:00
md678685 9e73c29b40 Fix creating and using kits on legacy versions (#2428)
* Attempt to look up legacy items in Material enum
* Use name method when serializing ItemStacks
* Make name uppercase before looking up in Material enum
2019-02-20 12:24:07 +00:00
md678685 aca83bd462 Switch Vault dependency to VaultAPI (#2430)
* Switch Vault dependency to VaultAPI
* Remove direct Vault class usage from VaultEco
2019-02-20 11:28:20 +00:00
md678685 189d6a23c6 Add README section about depending on EssX 2019-02-19 21:58:43 +00:00
md678685 441f88deea Implement missing FakeServer methods 2019-02-17 19:01:47 +00:00
Wiz_Techno 6d6666dace Pull Request for #2282
"Obsolete entries in items.csv should be removed"
2019-01-31 23:14:21 -05:00
Rafał Pokrywka fb779533e6 Replace nbsp with a space when formatting messages (#2394) @ravkr 2019-01-27 12:15:03 +00:00
DoNotSpamPls 7325113a8c Remove outdated permission plugin handlers, minor test fixes (#2367) @DoNotSpamPls
* Remove outdated permission plugin handlers, minor test fixes

* Re-add PermissionEX handler

* Use PaperLib to load chunks async whenever possible

* Revert "Use PaperLib to load chunks async whenever possible"

This reverts commit db4df6f3cf.
2019-01-27 12:14:16 +00:00
Glare Masters 827217823e Add the ability to make spectator gamemode signs (#2386) @darbyjack
Fixes #2383.
2019-01-20 10:14:20 +00:00
md678685 060dfc69f4 Update items.json
Fixed regression of unspawnable items not being marked as such, impacting the alias generation process. This fix also retains the ability to specify non-item blocks in the EssentialsX Protect material lists.
2019-01-12 22:07:03 +00:00
md678685 b831713737 Check whether item is spawnable in FlatItemDb 2019-01-12 21:43:36 +00:00
md678685 7da90b3a6b Load item spawn blacklist after item DB
Partially resolves #2360.
2019-01-12 21:43:36 +00:00
md678685 32540c23ab Add IItemDb#isReady to check if item database is available 2019-01-12 21:43:36 +00:00
md678685 d24b0616f8 Hide ServerListPingEvent exceptions thrown by CB's LegacyPingHandler (#2378)
Fixes #2327.
2019-01-12 17:19:11 +00:00
md678685 9aef2ef883 Update items.json
Add several new aliases. Closes #2348.
2019-01-09 15:10:38 +00:00
md678685 727d473319 Fix Enchantments on 1.12.2 and lower 2019-01-09 14:23:55 +00:00
md678685 8225e51867 Fix XMPP metrics reporting
The XMPP config was being reported as valid when it wasn't valid.
2019-01-09 13:57:18 +00:00
md678685 1ba6c2a596 Properly fix language mappings 2019-01-08 22:19:16 +00:00
md678685 60a166aeb0 Fix language mapping in Crowdin config 2019-01-08 21:45:46 +00:00
md678685 65c2155bca Update Crowdin config
Map most locales to the existing locale files.
2019-01-08 21:36:16 +00:00
md678685 6031c01584 Update Crowdin config
Fix file placement and map locale codes to existing translations
2019-01-08 21:21:35 +00:00
md678685 da8e8c8a25 Update Crowdin config
Crowdin should only use `messages.properties` as the "source" and this file will get copied to all the other language files like `messages_de.properties` for the German translation, `messages_ro.properties` for the Romanian translation etc.
2019-01-08 21:14:56 +00:00
Trent Hensler 70a750a32d Update Crowdin configuration file 2019-01-08 12:48:25 -08:00
md678685 7c63324504 Fix allow-old-id-signs allowing creation of signs with IDs 2019-01-07 22:38:13 +00:00
md678685 dd41b10522 attempt to fix Essentials overriding Skulls (#2356) @kennyrkun 2019-01-05 18:48:33 +00:00
triagonal 7948e764d4 disallow setting bed homes in non-overworld dimensions (#2335) @triagonal 2019-01-05 18:43:27 +00:00
DoNotSpamPls 82ede4530a Lots of little fixes in the Essentials modules (#2337) @DoNotSpamPls
Look at changed files for the changes
2019-01-05 18:42:09 +00:00
md678685 e8ab2db8e8 Improve ServerListPingEvent warning handling 2019-01-05 18:12:04 +00:00
md678685 8882e0214c Add bStats metrics for each EssentialsX module (#2333)
Does what it says on the tin.
2019-01-05 17:48:44 +00:00
md678685 4adb669cdd Add support for spawners with entities on 1.13+ 2019-01-05 17:35:29 +00:00
md678685 7e1d258dd3 Cache BukkitVersion in getServerBukkitVersion 2019-01-05 16:29:11 +00:00
md678685 417fe29e21 Remove duplicated item IDs in messages 2019-01-05 16:28:53 +00:00
md678685 bd8ef2a25d Only show available warps in tab complete
Fixes #2353 by only displaying warps where the player has the permission `essentials.warps.<warp>`.
2019-01-05 15:45:34 +00:00
md678685 fd01b75c33 Wrap UnsafeValues.fromLegacy() in try/catch for older versions
Should address #2352.
2019-01-05 15:27:07 +00:00
md678685 1388755d2a Wrap Enchantment.getByKey in try/catch for older versions
Should address #2351.
2019-01-05 15:17:58 +00:00
md678685 97cc3d0066 Update items.json
* Fix wrong harming potion mapping (fixes #2349)
* Add mob spawner aliases (not complete, related to #2347)
* Closes #2348:
  - Fix log aliases mistakenly pointing to stripped logs
  - Fix sandstone alias
  - Add shorter concrete powder aliases
2019-01-05 15:04:59 +00:00
md678685 694cf7a79e Revert 1.13 API hacks in LegacyItemDb
Earlier changes broke the items.csv database on older versions - this should now be fixed.
2019-01-04 15:01:18 +00:00
md678685 da89efb79f Make VersionUtil not explode when patch is not present 2019-01-03 22:16:14 +00:00
md678685 04ec013407 Update README to reflect 1.13 support 2019-01-03 21:25:48 +00:00
md678685 023cf6a1aa Merge pull request #2278 from EssentialsX/1.13
Full 1.13 support + 2.16.0 release
2019-01-03 20:56:14 +00:00
md678685 f7cbb141f8 Release 2.16.0
🎉
2019-01-03 20:47:24 +00:00
md678685 5690952516 Implement missing OfflinePlayer methods 2019-01-03 20:42:03 +00:00
md678685 e94202c55a Use 1.8-friendly User#getItemInHand method in commands 2019-01-03 20:33:08 +00:00
md678685 aa6ad271a0 Remove redundant metricsEnabled field from Settings 2019-01-03 20:33:08 +00:00
md678685 3b41bb47b6 Improve Travis build script (#2338)
I've added a new script at `scripts/buildtools.sh` that is responsible for:
* Checking whether CraftBukkit 1.8 and 1.8.3 are already available in the local Maven repo
* Downloading BuildTools if not already present
* Running BuildTools if necessary

This improves Travis build times as it now doesn't run BuildTools twice for *every single build*, instead running it only if the Travis cache fails and CraftBukkit is missing for some other reason.
2019-01-01 16:13:50 +00:00
md678685 e7bdb7fabc Improve the wording of the README's "Building" section 2019-01-01 15:42:45 +00:00
md678685 110698223d Travis: make build prep script executable 2019-01-01 15:23:35 +00:00
md678685 437be593b9 Add new build preparation script 2019-01-01 15:10:59 +00:00
md678685 502d37b574 Update Lombok to compile on Java 9+ 2018-12-31 17:44:08 +00:00
md678685 df59f9f859 Merge remote-tracking branch 'origin/2.x' into 1.13 2018-12-31 14:59:12 +00:00
md678685 f436fbab6b Remove redundant BuildTools runs 2018-12-31 14:54:59 +00:00
seema84 8404720501 change typos (#2328) @seema84
* change typos

* format text

* remove double color
2018-12-31 13:08:57 +00:00
triagonal 3d004d2a81 change config setting name 2018-12-31 16:42:42 +11:00
triagonal d1bbebad3a updated config comments 2018-12-30 20:49:58 +11:00
triagonal 42714ff8af implement config toggle for afk users bypassing sleep 2018-12-30 20:38:34 +11:00
md678685 246fd03265 Fix typo in README 2018-12-23 23:33:46 +00:00
pop4959 64930e3771 Fix messages & add warning 2018-12-21 01:58:44 -08:00
pop4959 16381234e0 Implement tpauto command 2018-12-19 02:50:30 -08:00
md678685 22538ba7c9 Merge branch '1.13' into 2.x_feature_jail_no_teleport 2018-10-28 18:46:53 +00:00
mathias a9fe842242 Use chat instead of dispatchCommand 2018-09-18 16:39:58 +03:00
pop4959 0432546746 use less dependencies 2018-09-04 16:53:01 -07:00
pop4959 3395bab928 Sort /near by nearest player. 2018-09-02 23:09:22 -07:00
Joseph Hirschfeld 70387f73f6 [Feature] Add config optn. to disable jail free tp
Adds the teleport-back-when-freed-from-jail configuration option. When
set to true (default), as with previous versions will teleport the
player which was jailed back to their previous position when freed. When
false, Essentials will not teleport the player anywhere, leaving them
where they are.

Closes #1947
2018-04-03 01:27:09 -04:00
Xeyame 7adb931ea8 Expand /exp command 2018-04-02 14:29:43 +02:00
Taylor 5f7d226158 Merge pull request #17 from delbertina/mutes385test
Sorted messages files with the -f option and other tweaks ...
2018-01-21 17:02:26 -06:00
delbertina 0897ca57ff Removed redundant line in mute time try-catch. 2018-01-20 22:46:55 -06:00
delbertina cfcdb47529 One last tweak. New line at the end of the fr file. 2018-01-18 22:04:35 -06:00
delbertina 76f845f5f4 More tweaks. Newlines and ordering switches. 2018-01-18 22:02:39 -06:00
delbertina c65b7b6462 Fixed error in sorting with number in message name and newlines at end of files. 2018-01-18 21:52:30 -06:00
delbertina 67528b25a8 Sorted messages files with the -f option 2018-01-18 15:18:22 -06:00
CreedTheFreak b096ee9703 Merge remote-tracking branch 'delbertina/mutes385test' into final_mute_reason_issue#385
Merged changes into local branch for pushing up to the pull request of
mute reason.
2018-01-16 17:49:49 -08:00
delbertina 9e2bb0b277 Rebase with sorted messages 2018-01-16 19:27:45 -06:00
CreedTheFreak b8df59ae46 Updated the former pull request to include the specified formatting changes, and small edits to the hasMuteReason and Commandmute dealing with the muteReason. I also included the ability to see the mute reason from the seenOffline method which is identical to the seenOnline code. 2018-01-16 18:21:31 -06:00
delbertina 98f42c6974 Added reason stuff to msg command and deleted reference line in seen command. Oops! 2018-01-16 18:16:34 -06:00
delbertina db19788e21 Added 8 new messages for "...Reason" versions of mute messages and implemented em. 2018-01-16 18:16:33 -06:00
delbertina 67d17472e0 Fixed logic error in hasMuteReason and errors being thrown from seen and whois. 2018-01-16 18:04:22 -06:00
delbertina f68a6eb00d Added space before reason when a muted player tries to talk. 2018-01-16 18:04:22 -06:00
delbertina b5a6df4fe2 Added space when adding reason to string. 2018-01-16 18:04:21 -06:00
delbertina 290379651d Added space when adding reason to string. Dirty :/ 2018-01-16 17:59:14 -06:00
delbertina 6ffbb86169 Changed if else blocks to ternary operators. Not sure if way to avoid weird empty string usage. 2018-01-16 17:54:50 -06:00
delbertina d8b6f87087 Added method hasMuteReason in UserData. 2018-01-16 17:54:50 -06:00
delbertina 7aad95ec08 Changed muteFormat to muteReason.
Removed space at beginning of muteReason.
2018-01-16 17:54:49 -06:00
delbertina 574e1bc1e7 Fixed easy style issues. 2018-01-16 17:48:12 -06:00
CreedTheFreak 081c6f0263 Update plugin.yml mute command usage 2018-01-16 17:48:11 -06:00
delbertina fc590f82a2 Added check to display mute reason when notifying 2018-01-16 17:48:10 -06:00
delbertina 729af4bb4d Added mute format to all msg files 2018-01-16 17:48:09 -06:00
CreedTheFreak c8cb9b3735 fixed some wonky commit thing that happened, thus the following modifications are brought to you by Delbertina. 2018-01-16 17:21:54 -06:00
CreedTheFreak 4f8ea06db1 We have added the ability for the Mute to contain a reason, which is stored for the duration of the mute in the user's data file. Currently we need to add in the mute reason code into some other commands such as /afk and /me and /seen ect. We will also need to fix a problem with the reason when we dont add in a time frame for the mute, which should mute the player indefinatly rather then cancelling the mute and throwing a DataFormat exception. 2018-01-16 17:21:53 -06:00
CreedTheFreak 9378df0ff2 Started work on implementing the mute reason, and decided to write it to the UserData just like the Ban and TempBan reasons 2018-01-16 17:21:52 -06:00
CreedTheFreak 3444c8b0d6 Merge branch 'mute_reason_changes' into final_mute_reason_issue#385
Updating local changes made on mute_reason_changes into the final branch
2017-12-26 17:20:40 -08:00
CreedTheFreak 822315a279 Updated the former pull request to include the specified formatting changes, and small edits to the hasMuteReason and Commandmute dealing with the muteReason. I also included the ability to see the mute reason from the seenOffline method which is identical to the seenOnline code. 2017-12-26 16:09:46 -08:00
CreedTheFreak 732da86710 Merge remote-tracking branch 'magnarisa/final_mute_reason_issue#385' into mute_reason_changes
Updated a clean branch with the changes we have made so far.
2017-12-26 08:23:53 -08:00
CreedTheFreak 5fbc412542 Merge remote-tracking branch 'upstream/2.x' into final_mute_reason_issue#385 2017-12-26 08:16:46 -08:00
CreedTheFreak f0b262cbd5 Merge pull request #15 from delbertina/mutes385
Added 8 new messages for "...Reason" versions of mute messages
2017-12-23 22:13:57 -08:00
delbertina ff37ef3bc5 Added reason stuff to msg command and deleted reference line in seen command. Oops! 2017-12-24 00:03:36 -06:00
CreedTheFreak 68fab2c328 Merge branch 'mutes385' of https://github.com/delbertina/Essentials into final_mute_reason_issue#385
Testing PR Changes
2017-12-23 22:03:01 -08:00
CreedTheFreak f9d81c4302 Merge branch 'mutes385' of https://github.com/delbertina/Essentials into final_mute_reason_issue#385
Testing PR
2017-12-23 21:51:21 -08:00
delbertina 3d33bbc33d Added 8 new messages for "...Reason" versions of mute messages and implemented em. 2017-12-20 00:35:51 -06:00
CreedTheFreak 53c604c1b5 Merge pull request #14 from delbertina/mutes385
Fixed spacing
2017-12-18 18:53:57 -08:00
CreedTheFreak 2975118e5b Merge branch 'mutes385' of https://github.com/delbertina/Essentials into final_mute_reason_issue#385 2017-12-18 18:40:27 -08:00
delbertina e3ee9cb4c7 Fixed logic error in hasMuteReason and errors being thrown from seen and whois. 2017-12-18 20:37:34 -06:00
CreedTheFreak 297a616460 Merge branch 'mutes385' of https://github.com/delbertina/Essentials into final_mute_reason_issue#385 2017-12-16 23:48:27 -08:00
delbertina afe0ff0ca7 Added space before reason when a muted player tries to talk. 2017-12-17 01:46:43 -06:00
CreedTheFreak adf1bc291c Merge branch 'mutes385' of https://github.com/delbertina/Essentials into final_mute_reason_issue#385 2017-12-16 22:27:52 -08:00
delbertina 034ffbd0bc Added space when adding reason to string. 2017-12-17 00:16:06 -06:00
delbertina 127a7bb2ce Merge branch 'mutes385' of https://github.com/delbertina/Essentials into mutes385
Updated local copy
Conflicts:
	Essentials/src/com/earth2me/essentials/commands/Commandafk.java
	Essentials/src/com/earth2me/essentials/commands/Commandmail.java
	Essentials/src/com/earth2me/essentials/commands/Commandme.java
	Essentials/src/com/earth2me/essentials/commands/Commandr.java
	Essentials/src/com/earth2me/essentials/commands/Commandseen.java
	Essentials/src/com/earth2me/essentials/commands/Commandwhois.java
2017-12-17 00:02:52 -06:00
delbertina e8bfac0790 Added space when adding reason to string. Dirty :/ 2017-12-16 23:26:09 -06:00
CreedTheFreak 62d5dd3516 Merge remote-tracking branch 'magnarisa/final_mute_reason_issue#385' into final_mute_reason_issue#385
Updated my local repos for testing purposes
2017-12-16 19:43:56 -08:00
CreedTheFreak bcd66fec39 Merge pull request #12 from delbertina/mutes385
Address requested changes to formatting and logic
2017-12-16 19:40:27 -08:00
delbertina 849b329213 Changed if else blocks to ternary operators. Not sure if way to avoid weird empty string usage. 2017-12-02 20:35:44 -06:00
delbertina d555c1b081 Added method hasMuteReason in UserData. 2017-12-02 19:46:46 -06:00
delbertina 43cbab37f0 Changed muteFormat to muteReason.
Removed space at beginning of muteReason.
2017-11-26 01:32:22 -06:00
delbertina 6f7af90488 Fixed easy style issues. 2017-11-26 00:55:05 -06:00
CreedTheFreak fcda6c3b3b Merge pull request #11 from CreedTheFreak/final_mute_reason_issue#385
Update plugin.yml mute command usage
2017-09-17 15:39:01 -07:00
CreedTheFreak 910ef26c79 Update plugin.yml mute command usage 2017-09-17 15:36:06 -07:00
Taylor 1664da55a4 Merge pull request #10 from CreedTheFreak/commit_squashing
Final Implementation and the squasing of many commits
2017-09-17 16:55:14 -05:00
CreedTheFreak f8ea7f5e1f Implemented the ability to add a reason while muting a
player. The form of the mute is /mute [Player] [Time] [Reason] or /mute
[Player] [Reason] or /mute [Player] [Time] or /mute [Player]. These are
the various forms of the mute command and acts exactly like the old
command just with a reason.

The final adjustments to the MuteReason
2017-09-16 22:27:34 -07:00
delbertina b0205b9499 Added check to display mute reason when notifying 2017-09-03 23:02:56 -05:00
Taylor e05796f80e Merge pull request #4 from delbertina/msgs385
Added mute format to all msg files
2017-09-03 22:10:19 -05:00
delbertina a70fa78267 Added mute format to all msg files 2017-09-03 22:03:17 -05:00
CreedTheFreak e20693de60 Merge pull request #3 from CreedTheFreak/update_branch
Modifications Brought To you by Delbertina
2017-09-03 19:54:20 -07:00
CreedTheFreak f10a766442 fixed some wonky commit thing that happened, thus the following modifications are brought to you by Delbertina. 2017-09-03 19:49:57 -07:00
CreedTheFreak 86315fed8d Merge pull request #1 from CreedTheFreak/mute/jail_reason_issue#385
Mute reason issue#385
2017-09-03 14:46:40 -07:00
CreedTheFreak 4ff9fe8666 We have added the ability for the Mute to contain a reason, which is stored for the duration of the mute in the user's data file. Currently we need to add in the mute reason code into some other commands such as /afk and /me and /seen ect. We will also need to fix a problem with the reason when we dont add in a time frame for the mute, which should mute the player indefinatly rather then cancelling the mute and throwing a DataFormat exception. 2017-09-03 14:41:32 -07:00
CreedTheFreak 3512c4c8e6 Started work on implementing the mute reason, and decided to write it to the UserData just like the Ban and TempBan reasons 2017-09-02 20:04:25 -07:00
374 changed files with 64110 additions and 39627 deletions

No files matched your search

+13
View File
@@ -0,0 +1,13 @@
# 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
#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
#issuehunt: # Replace with a single IssueHunt username
#otechie: # Replace with a single Otechie username
#custom: # Replace with a single custom sponsorship URL
+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/
+19 -53
View File
@@ -1,53 +1,19 @@
.DS_Store
/BuildAll/nbproject/private/
/EssentialsProtect/nbproject/private/
/EssentialsChat/nbproject/private/
/EssentialsGroupBridge/nbproject/private/
/EssentialsGeoIP/nbproject/private/
/EssentialsSpawn/nbproject/private/
/EssentialsXMPP/nbproject/private/
/BuildAll/build/
/EssentialsGroupBridge/dist/
/EssentialsGroupBridge/build/
/EssentialsGeoIP/dist/
/EssentialsGeoIP/build/
/BuildAll/dist/
/EssentialsChat/build/
/EssentialsChat/dist/
/EssentialsSpawn/build/
/EssentialsSpawn/dist/
/EssentialsXMPP/dist/
/EssentialsXMPP/build/
/EssentialsProtect/dist/
/EssentialsProtect/build/
/EssentialsPermissionsCommands/nbproject/private/
/EssentialsPermissionsCommands/build/
/EssentialsPermissionsCommands/dist/
/Essentials/nbproject/private/
/Essentials/dist/
/Essentials/build/
/YamlAnnotations/
/EssentialsUpdate/nbproject/private/
/EssentialsRelease/
/EssentialsUpdate/dist/
/EssentialsUpdate/build/
/WebPush/apikey.php
/WebPush/nbproject/private
/EssentialsAntiBuild/nbproject/private/
/EssentialsAntiBuild/dist/
/EssentialsAntiBuild/build/
/jars
/out
.idea/
*.iml
*.classpath
*.project
*.settings/
target/
dependency-reduced-pom.xml
/Essentials/config.yml
/Essentials/kits.yml
/Essentials/userdata/testplayer1.yml
/Essentials/usermap.csv
/Essentials/userdata
/EssentialsGroupManager/target/
# IDE files
*.classpath
*.project
*.settings/
.idea/
*.iml
.DS_Store
# Essentials files
/Essentials/userdata
/Essentials/config.yml
/Essentials/kits.yml
/Essentials/userdata/testplayer1.yml
/Essentials/usermap.csv
# Build files
target/
jars/
out/
-23
View File
@@ -1,23 +0,0 @@
language: java
branches:
only:
- 2.x
- 1.13
cache:
directories:
- .buildtools
- $HOME/.m2
before_install:
- mkdir -p .buildtools
- cd .buildtools
- wget -O BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar
- rm -r work/
- java -jar BuildTools.jar --rev 1.8
- java -jar BuildTools.jar --rev 1.8.3
- java -jar BuildTools.jar --rev 1.9
- java -jar BuildTools.jar --rev 1.9.4
- java -jar BuildTools.jar --rev 1.13.1
- cd ..
+50 -54
View File
@@ -6,25 +6,18 @@
<parent>
<groupId>net.ess3</groupId>
<artifactId>EssentialsXParent</artifactId>
<version>2.16.0</version>
<version>2.18.0</version>
</parent>
<artifactId>EssentialsX</artifactId>
<licenses>
<license>
<name>GPLv3</name>
<url>http://www.gnu.org/copyleft/gpl.html</url>
</license>
</licenses>
<build>
<finalName>EssentialsX-${full.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<version>3.8.0</version>
<configuration>
<showDeprecation>false</showDeprecation>
</configuration>
@@ -32,7 +25,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
@@ -41,82 +34,85 @@
</goals>
</execution>
</executions>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>io.papermc.lib</pattern>
<shadedPattern>com.earth2me.essentials.paperlib</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>net.milkbowl.vault</groupId>
<artifactId>Vault</artifactId>
<version>1.5.6</version>
<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.ess3</groupId>
<artifactId>NMSProvider</artifactId>
<version>2.16.0</version>
<groupId>net.luckperms</groupId>
<artifactId>api</artifactId>
<version>5.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.papermc</groupId>
<artifactId>paperlib</artifactId>
<version>1.0.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>UpdatedMetaProvider</artifactId>
<version>2.16.0</version>
<artifactId>BaseProviders</artifactId>
<version>2.18.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>1_8_R1Provider</artifactId>
<version>2.16.0</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.16.0</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.16.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>ReflectionProvider</artifactId>
<version>2.16.0</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>FlattenedProvider</artifactId>
<version>2.16.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>vault-repo</id>
<url>http://nexus.hc.to/content/repositories/pub_releases</url>
</repository>
</repositories>
</project>
+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());
}
}
@@ -1,7 +1,5 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.NumberUtil;
import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment;
@@ -13,8 +11,9 @@ 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 {
ENCHANTMENTS.put("alldamage", Enchantment.DAMAGE_ALL);
@@ -231,10 +230,52 @@ public class Enchantments {
ALIASENCHANTMENTS.put("channel", channelling);
}
} catch (IllegalArgumentException ignored) {}
try { // 1.14
Enchantment multishot = Enchantment.getByName("MULTISHOT");
if (multishot != null) {
ENCHANTMENTS.put("multishot", multishot);
ALIASENCHANTMENTS.put("tripleshot", multishot);
}
Enchantment quickCharge = Enchantment.getByName("QUICK_CHARGE");
if (quickCharge != null) {
ENCHANTMENTS.put("quickcharge", quickCharge);
ALIASENCHANTMENTS.put("quickdraw", quickCharge);
ALIASENCHANTMENTS.put("fastcharge", quickCharge);
ALIASENCHANTMENTS.put("fastdraw", quickCharge);
}
Enchantment piercing = Enchantment.getByName("PIERCING");
if (piercing != null) {
ENCHANTMENTS.put("piercing", piercing);
}
} catch (IllegalArgumentException ignored) {}
try { // 1.16
Enchantment soulspeed = Enchantment.getByName("SOUL_SPEED");
if (soulspeed != null) {
ENCHANTMENTS.put("soulspeed", soulspeed);
ALIASENCHANTMENTS.put("soilspeed", soulspeed);
ALIASENCHANTMENTS.put("sandspeed", soulspeed);
}
} catch (IllegalArgumentException ignored) {}
try {
Class<?> namespacedKeyClass = Class.forName("org.bukkit.NamespacedKey");
Class<?> enchantmentClass = Class.forName("org.bukkit.enchantments.Enchantment");
enchantmentClass.getDeclaredMethod("getByKey", namespacedKeyClass);
isFlat = true;
} catch (ClassNotFoundException | NoSuchMethodException e) {
isFlat = false;
}
}
public static Enchantment getByName(String name) {
Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(name.toLowerCase()));
Enchantment enchantment = null;
if (isFlat) { // 1.13+ only
enchantment = Enchantment.getByKey(NamespacedKey.minecraft(name.toLowerCase()));
}
if (enchantment == null) {
enchantment = Enchantment.getByName(name.toUpperCase());
}
@@ -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,57 +189,105 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
}
forceLoadClasses();
try {
final EssentialsUpgrade upgrade = new EssentialsUpgrade(this);
upgrade.beforeSettings();
execTimer.mark("Upgrade");
confList = new ArrayList<>();
settings = new Settings(this);
confList.add(settings);
execTimer.mark("Settings");
userMap = new UserMap(this);
confList.add(userMap);
execTimer.mark("Init(Usermap)");
kits = new Kits(this);
confList.add(kits);
upgrade.convertKits();
execTimer.mark("Kits");
upgrade.afterSettings();
execTimer.mark("Upgrade2");
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();
// The item spawn blacklist is loaded with all other settings, before the item
// DB, but it depends on the item DB, so we need to reload it again here:
((Settings) settings)._lateLoadItemSpawnBlacklist();
} catch (YAMLException exception) {
if (pm.getPlugin("EssentialsUpdate") != null) {
LOGGER.log(Level.SEVERE, tl("essentialsHelp2"));
@@ -254,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);
@@ -263,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()) {
@@ -280,6 +325,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
handleCrash(ex);
throw ex;
}
getBackup().setPendingShutdown(false);
}
@Override
@@ -324,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();
@@ -360,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);
@@ -368,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
@@ -444,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);
}
@@ -476,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)});
}
@@ -496,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;
}
@@ -534,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());
@@ -612,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
@@ -731,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;
}
@@ -752,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);
}
@@ -860,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
@@ -884,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;
@@ -92,7 +95,7 @@ public class EssentialsEntityListener implements Listener {
class PowerToolInteractTask implements Runnable {
@Override
public void run() {
attacker.getServer().dispatchCommand(attacker.getBase(), command);
attacker.getBase().chat("/" + command);
LOGGER.log(Level.INFO, String.format("[PT] %s issued server command: /%s", attacker.getName(), command));
}
}
@@ -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"));
@@ -159,6 +174,66 @@ public class EssentialsEntityListener implements Listener {
}
}
@EventHandler(priority = EventPriority.LOW)
public void onPlayerDeathInvEvent(final PlayerDeathEvent event) {
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);
}
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onFoodLevelChange(final FoodLevelChangeEvent event) {
if (event.getEntity() instanceof Player) {
@@ -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,13 +8,11 @@ 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 org.bukkit.BanEntry;
import org.bukkit.BanList;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import net.ess3.api.events.AfkStatusChangeEvent;
import org.bukkit.*;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
@@ -33,12 +32,9 @@ 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.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.*;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -55,12 +51,48 @@ 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 PlayerListener1_12(), ess);
ess.getServer().getPluginManager().registerEvents(new PickupListener1_12(), ess);
} else {
ess.getServer().getPluginManager().registerEvents(new PlayerListenerPre1_12(), ess);
ess.getServer().getPluginManager().registerEvents(new PickupListenerPre1_12(), ess);
}
if (isCommandSendEvent()) {
ess.getServer().getPluginManager().registerEvents(new CommandSendListener(), ess);
}
}
@@ -80,7 +112,14 @@ public class EssentialsPlayerListener implements Listener {
final User user = ess.getUser(event.getPlayer());
if (user.isMuted()) {
event.setCancelled(true);
user.sendMessage(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()));
}
try {
@@ -148,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);
}
@@ -181,7 +221,7 @@ public class EssentialsPlayerListener implements Listener {
}
}
user.updateActivityOnInteract(false);
user.updateActivity(false, AfkStatusChangeEvent.Cause.QUIT);
if (!user.isHidden()) {
user.setLastLogout(System.currentTimeMillis());
}
@@ -193,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;
@@ -219,7 +259,7 @@ public class EssentialsPlayerListener implements Listener {
final long currentTime = System.currentTimeMillis();
dUser.checkMuteTimeout(currentTime);
dUser.updateActivityOnInteract(false);
dUser.updateActivity(false, AfkStatusChangeEvent.Cause.JOIN);
dUser.stopTransaction();
class DelayJoinTask implements Runnable {
@@ -258,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);
}
@@ -316,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();
@@ -324,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;
@@ -367,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)
@@ -420,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)) {
@@ -446,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);
}
}
@@ -480,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
@@ -499,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
@@ -550,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());
}
}
}
}
@@ -597,13 +650,18 @@ public class EssentialsPlayerListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL)
public void onPlayerInteract(final PlayerInteractEvent event) {
boolean updateActivity = true;
switch (event.getAction()) {
case RIGHT_CLICK_BLOCK:
if (!event.isCancelled() && MaterialUtil.isBed(event.getClickedBlock().getType()) && ess.getSettings().getUpdateBedAtDaytime()) {
User player = ess.getUser(event.getPlayer());
if (player.isAuthorized("essentials.sethome.bed")) {
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;
@@ -623,8 +681,16 @@ public class EssentialsPlayerListener implements Listener {
}
}
break;
case PHYSICAL:
updateActivity = false;
break;
default:
break;
}
if (updateActivity) {
ess.getUser(event.getPlayer()).updateActivityOnInteract(true);
}
}
// This method allows the /jump lock feature to work, allows teleporting while flying #EasterEgg
@@ -641,7 +707,7 @@ public class EssentialsPlayerListener implements Listener {
while (LocationUtil.isBlockDamaging(loc.getWorld(), loc.getBlockX(), loc.getBlockY() - 1, loc.getBlockZ())) {
loc.setY(loc.getY() + 1d);
}
user.getBase().teleport(loc, TeleportCause.PLUGIN);
PaperLib.teleportAsync(user.getBase(), loc, TeleportCause.PLUGIN);
}
}
ess.scheduleSyncDelayedTask(new DelayedClickJumpTask());
@@ -661,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));
@@ -671,7 +736,7 @@ public class EssentialsPlayerListener implements Listener {
class PowerToolUseTask implements Runnable {
@Override
public void run() {
user.getServer().dispatchCommand(user.getBase(), command);
user.getBase().chat("/" + command);
LOGGER.log(Level.INFO, String.format("[PT] %s issued server command: /%s", user.getName(), command));
}
}
@@ -698,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);
@@ -720,14 +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
&& 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();
@@ -737,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);
}
}
@@ -769,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();
@@ -777,36 +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 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 PlayerListenerPre1_12 implements Listener {
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);
}
@@ -814,8 +869,7 @@ public class EssentialsPlayerListener implements Listener {
}
}
private final class PlayerListener1_12 implements Listener {
private final class PickupListener1_12 implements Listener {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerPickupItem(final org.bukkit.event.entity.EntityPickupItemEvent event) {
if (ess.getSettings().getDisableItemPickupWhileAfk() && event.getEntity() instanceof Player) {
@@ -825,4 +879,46 @@ public class EssentialsPlayerListener implements Listener {
}
}
}
private final class CommandSendListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL)
public void onCommandSend(final PlayerCommandSendEvent event) {
User user = ess.getUser(event.getPlayer());
Set<PluginCommand> checked = new HashSet<>();
Set<PluginCommand> toRemove = new HashSet<>();
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()) {
ess.getLogger().info("Removed commands: " + toRemove.toString());
}
}
/**
* Returns true if all of the following are true:
* - The command is a plugin command
* - The plugin command is from a plugin in an essentials-controlled package
* - There is no known alternative OR the alternative is overridden by Essentials
*/
private boolean isEssentialsCommand(String label) {
PluginCommand command = ess.getServer().getPluginCommand(label);
return command != null
&& (command.getPlugin() == ess || command.getPlugin().getClass().getName().startsWith("com.earth2me.essentials"))
&& (ess.getSettings().isCommandOverridden(label) || (ess.getAlternativeCommandsHandler().getAlternative(label) == null));
}
}
}
@@ -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())) {
@@ -10,16 +10,23 @@ import org.bukkit.event.server.ServerListPingEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
public class EssentialsServerListener implements Listener {
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.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;
@@ -31,13 +38,13 @@ public class EssentialsServerListener implements Listener {
setSampleText = ReflUtil.getMethodCached(ServerListPingEvent.class, "setSampleText", List.class);
getSampleText = ReflUtil.getMethodCached(ServerListPingEvent.class, "getSampleText");
if (setSampleText != null && getSampleText != null) {
ess.getLogger().info("Using Paper 1.12+ ServerListPingEvent methods");
ess.getLogger().info("ServerListPingEvent: Paper 1.12.2 setSampleText API");
isPaperSample = true;
return;
}
}
ess.getLogger().info("Using Spigot 1.7.10+ ServerListPingEvent iterator");
ess.getLogger().info("ServerListPingEvent: Spigot iterator API");
isPaperSample = false;
}
@@ -46,22 +53,16 @@ public class EssentialsServerListener implements Listener {
if (isPaperSample) {
try {
List<String> playerNames = (List<String>) getSampleText.invoke(event, null);
Iterator<String> iterator = playerNames.iterator();
while (iterator.hasNext()) {
String player = iterator.next();
if (ess.getUser(player).isVanished()) {
iterator.remove();
}
}
playerNames.removeIf(player -> ess.getUser(player).isVanished());
setSampleText.invoke(event, playerNames);
} catch (IllegalAccessException | InvocationTargetException | ClassCastException e) {
if (!unsupportedLogged) {
if (!unsupportedLogged && shouldWarnSLPECaller(e)) {
ess.getLogger().log(Level.WARNING, "Unable to hide players from server list ping "
+ "using Paper 1.12+ method!", e);
+ "using Paper 1.12 method!", e);
unsupportedLogged = true;
}
} catch (NullPointerException e) {
if (!npeWarned) {
if (!npeWarned && shouldWarnSLPECaller(e)) {
npeWarned = true;
Exception ex = new Exception("A plugin has fired a ServerListPingEvent "
+ "without implementing Paper's methods. Point the author to https://git.io/v7Xzl.");
@@ -79,12 +80,38 @@ public class EssentialsServerListener implements Listener {
}
}
} catch (UnsupportedOperationException e) {
if (!unsupportedLogged) {
ess.getLogger().warning("Current server implementation does not support "
+ "hiding players from server list ping. Update or contact the maintainers.");
if (!unsupportedLogged && shouldWarnSLPECaller(e)) {
ess.getLogger().log(Level.WARNING, "Could not hide vanished players while handling " + event.getClass().getName(), e);
unsupportedLogged = true;
}
}
}
}
/**
* Should we warn about this SLPE caller, or should we silently ignore it?
* This checks against the ignoredSLPECallers strings, and if it matches one of those, we
* return false.
*
* @param throwable A throwable caught by a catch block
* @return Whether or not to send a warning about this particular caller
*/
private boolean shouldWarnSLPECaller(Throwable throwable) {
final int maxStackDepth = 20; // Limit the depth when searching through the stack trace
int depth = 0;
for (StackTraceElement element : throwable.getStackTrace()) {
depth++;
if (depth > maxStackDepth) {
break;
}
for (String ignoredString : ignoredSLPECallers) {
if (element.toString().contains(ignoredString)) {
return false; // We know about this error and should ignore it, so don't warn
}
}
}
return true; // We don't know for certain that we can ignore this, so warn just to be safe
}
}
@@ -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;
}
@@ -93,7 +92,7 @@ public class I18n implements net.ess3.api.II18n {
}
messageFormatCache.put(format, messageFormat);
}
return messageFormat.format(objects);
return messageFormat.format(objects).replace(' ', ' '); // replace nbsp with a space
}
public void updateLocale(final String loc) {
@@ -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();
@@ -185,12 +196,30 @@ public interface ISettings extends IConf {
boolean cancelAfkOnInteract();
boolean sleepIgnoresAfkPlayers();
boolean isAfkListName();
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();
@@ -235,6 +264,8 @@ public interface ISettings extends IConf {
void setEssentialsChatActive(boolean b);
long getMaxMute();
long getMaxTempban();
Map<String, Object> getListGroupConfig();
@@ -265,6 +296,8 @@ public interface ISettings extends IConf {
BigDecimal getMinimumPayAmount();
boolean isPayExcludesIgnoreList();
long getLastMessageReplyRecipientTimeout();
boolean isMilkBucketEasterEggEnabled();
@@ -283,6 +316,10 @@ public interface ISettings extends IConf {
boolean isCommandCooldownsEnabled();
boolean isWorldChangeFlyResetEnabled();
boolean isWorldChangeSpeedResetEnabled();
long getCommandCooldownMs(String label);
Entry<Pattern, Long> getCommandCooldownEntry(String label);
@@ -299,6 +336,8 @@ public interface ISettings extends IConf {
boolean isAllowBulkBuySell();
boolean isAllowSellNamedItems();
boolean isAddingPrefixInPlayerlist();
boolean isAddingSuffixInPlayerlist();
@@ -313,13 +352,32 @@ public interface ISettings extends IConf {
boolean isConfirmCommandEnabledByDefault(String commandName);
boolean isTeleportBackWhenFreedFromJail();
boolean isCompassTowardsHomePerm();
boolean isAllowWorldInBroadcastworld();
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;
@@ -22,6 +24,8 @@ public interface IUser {
boolean isAuthorized(IEssentialsCommand cmd, String permissionPrefix);
boolean isPermissionSet(String node);
void healCooldown() throws Exception;
void giveMoney(BigDecimal value) throws MaxMoneyException;
@@ -51,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();
@@ -94,7 +107,7 @@ public interface IUser {
*
* @return If the user is vanished or not
*
* @see isHidden
* @see IUser#isHidden()
*/
boolean isVanished();
@@ -184,5 +197,9 @@ public interface IUser {
void setPromptingClearConfirm(boolean prompt);
boolean isLastMessageReplyRecipient();
void setLastMessageReplyRecipient(boolean enabled);
Map<User, BigDecimal> getConfirmingPayments();
}
@@ -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"));
}
@@ -208,13 +199,19 @@ public class MetaItemStack {
stack.setItemMeta(meta);
} else if (split.length > 1 && split[0].equalsIgnoreCase("itemflags") && hasMetaPermission(sender, "itemflags", false, true, ess)) {
addItemFlags(string);
} else if (MaterialUtil.isFirework(stack.getType())) {//WARNING - Meta for fireworks will be ignored after this point.
} else if (MaterialUtil.isFirework(stack.getType())) {
//WARNING - Meta for fireworks will be ignored after this point.
addFireworkMeta(sender, false, string, ess);
} else if (MaterialUtil.isPotion(stack.getType())) { //WARNING - Meta for potions will be ignored after this point.
} else if (MaterialUtil.isPotion(stack.getType())) {
//WARNING - Meta for potions will be ignored after this point.
addPotionMeta(sender, false, string, ess);
} else if (MaterialUtil.isBanner(stack.getType())) {
//WARNING - Meta for banners will be ignored after this point.
addBannerMeta(sender, false, string, ess);
if (stack.getType().toString().equals("SHIELD") && Enchantments.getByName(split[0]) != null) {
parseEnchantmentStrings(sender, allowUnsafe, split, ess);
} else {
//WARNING - Meta for banners will be ignored after this point.
addBannerMeta(sender, false, string, ess);
}
} else if (split.length > 1 && (split[0].equalsIgnoreCase("color") || split[0].equalsIgnoreCase("colour")) && MaterialUtil.isLeatherArmor(stack.getType())) {
final String[] color = split[1].split("(\\||,)");
if (color.length == 1 && (NumberUtil.isInt(color[0]) || color[0].startsWith("#"))) {
@@ -291,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())) {
@@ -314,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())) {
@@ -378,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()) {
@@ -485,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);
}
@@ -511,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);
}
@@ -578,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);
}
}
+31 -15
View File
@@ -1,10 +1,10 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.EnumUtil;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.*;
import java.util.*;
import java.util.logging.Level;
@@ -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),
@@ -77,12 +78,25 @@ public enum Mob {
PARROT("Parrot", Enemies.NEUTRAL, "PARROT"),
TURTLE("Turtle", Enemies.NEUTRAL, "TURTLE"),
PHANTOM("Phantom", Enemies.ENEMY, "PHANTOM"),
COD("Cod", Enemies.NEUTRAL, "COD"),
SALMON("Salmon", Enemies.NEUTRAL, "SALMON"),
PUFFERFISH("Pufferfish", Enemies.NEUTRAL, "PUFFERFISH"),
TROPICAL_FISH("TropicalFish", Enemies.NEUTRAL, "TROPICAL_FISH"),
COD("Cod", Enemies.NEUTRAL, "", "COD"),
SALMON("Salmon", Enemies.NEUTRAL, "", "SALMON"),
PUFFERFISH("Pufferfish", Enemies.NEUTRAL, "", "PUFFERFISH"),
TROPICAL_FISH("TropicalFish", Enemies.NEUTRAL, "", "TROPICAL_FISH"),
DROWNED("Drowned", Enemies.ENEMY, "DROWNED"),
DOLPHIN("Dolphin", Enemies.NEUTRAL, "DOLPHIN"),
CAT("Cat", Enemies.FRIENDLY, "CAT"),
FOX("Fox", Enemies.FRIENDLY, "es", "FOX"),
PANDA("Panda", Enemies.NEUTRAL, "PANDA"),
PILLAGER("Pillager", Enemies.ENEMY, "PILLAGER"),
RAVAGER("Ravager", Enemies.ENEMY, "RAVAGER"),
TRADER_LLAMA("TraderLlama", Enemies.FRIENDLY, "TRADER_LLAMA"),
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");
@@ -100,16 +114,17 @@ public enum Mob {
this.bukkitType = type;
}
Mob(String n, Enemies en, String s, String typeName) {
this.suffix = s;
this.name = n;
this.type = en;
bukkitType = EnumUtil.getEntityType(typeName);
}
Mob(String n, Enemies en, String typeName) {
this.name = n;
this.type = en;
EntityType entityType;
try {
entityType = EntityType.valueOf(typeName);
} catch (IllegalArgumentException ignored) {
entityType = null;
}
bukkitType = entityType;
bukkitType = EnumUtil.getEntityType(typeName);
}
public String suffix = "s";
@@ -145,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;
@@ -0,0 +1,215 @@
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.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
SIAMESE("SIAMESE", "SIAMESE_CAT"),
WHITE("WHITE", "SIAMESE_CAT"),
RED("RED", "RED_CAT"),
TABBY("TABBY", "RED_CAT"),
TUXEDO("BLACK", "BLACK_CAT"),
BRITISH_SHORTHAIR("BRITISH_SHORTHAIR", "SIAMESE_CAT"),
CALICO("CALICO", "RED_CAT"),
PERSIAN("PERSIAN", "RED_CAT"),
RAGDOLL("RAGDOLL", "SIAMESE_CAT"),
JELLIE("JELLIE", "SIAMESE_CAT"),
BLACK("ALL_BLACK", "BLACK_CAT"),
;
private final String catTypeName;
private final String ocelotTypeName;
CatType(final String catTypeName, final String ocelotTypeName) {
this.catTypeName = catTypeName;
this.ocelotTypeName = ocelotTypeName;
}
}
public enum VillagerProfession {
// These are 1.14+ villager professions mapped to their respective pre-V&P profession and career
NONE("FARMER", "FARMER", "NONE"),
ARMORER("BLACKSMITH", "ARMORER"),
BUTCHER("FARMER", "BUTCHER"),
CARTOGRAPHER("LIBRARIAN", "CARTOGRAPHER"),
CLERIC("PRIEST", "CLERIC"),
FARMER("FARMER", "FARMER"),
FISHERMAN("FARMER", "FISHERMAN"),
FLETCHER("FARMER", "FLETCHER"),
LEATHERWORKER("BUTCHER", "LEATHERWORKER"),
LIBRARIAN("LIBRARIAN", "LIBRARIAN"),
MASON(null, null, "MASON"),
NITWIT("NITWIT", "NITWIT"),
SHEPHERD("FARMER", "SHEPHERD"),
TOOLSMITH("BLACKSMITH", "TOOL_SMITH", "TOOLSMITH"),
WEAPONSMITH("BLACKSMITH", "WEAPON_SMITH", "WEAPONSMITH"),
;
private final String oldProfession;
private final String oldCareer;
private final String newProfession;
VillagerProfession(final String oldProfession, final String career) {
this.oldProfession = oldProfession;
this.oldCareer = career;
this.newProfession = career;
}
VillagerProfession(final String oldProfession, final String oldCareer, final String newProfession) {
this.oldProfession = oldProfession;
this.oldCareer = oldCareer;
this.newProfession = newProfession;
}
private Villager.Profession asEnum() {
return EnumUtil.valueOf(Villager.Profession.class, newProfession, oldProfession);
}
}
// Older cats are Ocelots, whereas 1.14+ cats are Cats
public static void setCatType(final Entity entity, final CatType type) {
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 {
setCatType.invoke(entity, EnumUtil.valueOf(catType, type.catTypeName));
} catch (Exception e) {
e.printStackTrace();
}
}
}
// Older villagers have professions and careers, 1.14+ villagers only have professions
public static void setVillagerProfession(final Entity entity, final VillagerProfession profession) {
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 {
setCareer.invoke(entity, EnumUtil.valueOf(villagerCareer, profession.oldCareer));
} catch (Exception e) {
e.printStackTrace();
}
}
}
// Only 1.14+ villagers have biome variants
public static void setVillagerType(final Entity entity, final String type) {
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) {
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) {
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) {
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) {
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) {
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);
}
}
}
// 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,13 +12,16 @@ 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;
public enum MobData {
BABY_AGEABLE("baby", Ageable.class, Data.BABY, true),
ADULT_AGEABLE("adult", Ageable.class, Data.ADULT, true),
BABY_CAT("kitten", MobCompat.CAT, Data.BABY, false),
BABY_PIG("piglet", EntityType.PIG, Data.BABY, false),
BABY_WOLF("puppy", EntityType.WOLF, Data.BABY, false),
BABY_CHICKEN("chick", EntityType.CHICKEN, Data.BABY, false),
@@ -30,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),
@@ -57,13 +60,19 @@ public enum MobData {
GOLD_ARMOR_HORSE("goldarmor", EntityType.HORSE, EnumUtil.getMaterial("GOLDEN_HORSE_ARMOR", "GOLD_BARDING"), true),
DIAMOND_ARMOR_HORSE("diamondarmor", EntityType.HORSE, EnumUtil.getMaterial("DIAMOND_HORSE_ARMOR", "DIAMOND_BARDING"), true),
ARMOR_HORSE("armor", EntityType.HORSE, EnumUtil.getMaterial("IRON_HORSE_ARMOR", "IRON_BARDING"), true),
SIAMESE_CAT("siamese", EntityType.OCELOT, Ocelot.Type.SIAMESE_CAT, true),
WHITE_CAT("white", EntityType.OCELOT, Ocelot.Type.SIAMESE_CAT, false),
RED_CAT("red", EntityType.OCELOT, Ocelot.Type.RED_CAT, true),
ORANGE_CAT("orange", EntityType.OCELOT, Ocelot.Type.RED_CAT, false),
TABBY_CAT("tabby", EntityType.OCELOT, Ocelot.Type.RED_CAT, false),
BLACK_CAT("black", EntityType.OCELOT, Ocelot.Type.BLACK_CAT, true),
TUXEDO_CAT("tuxedo", EntityType.OCELOT, Ocelot.Type.BLACK_CAT, false),
SIAMESE_CAT("siamese", MobCompat.CAT, MobCompat.CatType.SIAMESE, true),
WHITE_CAT("white", MobCompat.CAT, MobCompat.CatType.WHITE, false),
RED_CAT("red", MobCompat.CAT, MobCompat.CatType.RED, true),
ORANGE_CAT("orange", MobCompat.CAT, MobCompat.CatType.RED, false),
TABBY_CAT("tabby", MobCompat.CAT, MobCompat.CatType.TABBY, true),
BLACK_CAT("black", MobCompat.CAT, MobCompat.CatType.BLACK, true),
TUXEDO_CAT("tuxedo", MobCompat.CAT, MobCompat.CatType.TUXEDO, true),
BRITISH_SHORTHAIR_CAT("britishshorthair", MobCompat.CAT, MobCompat.CatType.BRITISH_SHORTHAIR, true),
CALICO_CAT("calico", MobCompat.CAT, MobCompat.CatType.CALICO, true),
PERSIAN_CAT("persian", MobCompat.CAT, MobCompat.CatType.PERSIAN, true),
RAGDOLL_CAT("ragdoll", MobCompat.CAT, MobCompat.CatType.RAGDOLL, true),
JELLIE_CAT("jellie", MobCompat.CAT, MobCompat.CatType.JELLIE, true),
ALL_BLACK_CAT("allblack", MobCompat.CAT, MobCompat.CatType.BLACK, true),
BABY_ZOMBIE("baby", EntityType.ZOMBIE.getEntityClass(), Data.BABYZOMBIE, true),
ADULT_ZOMBIE("adult", EntityType.ZOMBIE.getEntityClass(), Data.ADULTZOMBIE, true),
DIAMOND_SWORD_ZOMBIE("diamondsword", EntityType.ZOMBIE.getEntityClass(), Material.DIAMOND_SWORD, true),
@@ -83,31 +92,77 @@ public enum MobData {
SADDLE_PIG("saddle", EntityType.PIG, Data.PIGSADDLE, true),
ANGRY_WOLF("angry", EntityType.WOLF, Data.ANGRY, true),
RABID_WOLF("rabid", EntityType.WOLF, Data.ANGRY, false),
FARMER_VILLAGER("farmer", EntityType.VILLAGER, Villager.Profession.FARMER, true),
LIBRARIAN_VILLAGER("librarian", EntityType.VILLAGER, Villager.Profession.LIBRARIAN, true),
PRIEST_VILLAGER("priest", EntityType.VILLAGER, Villager.Profession.PRIEST, true),
FATHER_VILLAGER("father", EntityType.VILLAGER, Villager.Profession.PRIEST, false),
SMITH_VILLAGER("smith", EntityType.VILLAGER, Villager.Profession.BLACKSMITH, true),
BUTCHER_VILLAGER("butcher", EntityType.VILLAGER, Villager.Profession.BUTCHER, true),
SIZE_SLIME("", "<1-100>", EntityType.SLIME.getEntityClass(), Data.SIZE, true),
NUM_EXPERIENCE_ORB("", "<1-2000000000>", EntityType.EXPERIENCE_ORB, Data.EXP, true),
RED_PARROT("red", EntityType.PARROT, Parrot.Variant.RED, true),
GREEN_PARROT("green", EntityType.PARROT, Parrot.Variant.GREEN, true),
BLUE_PARROT("blue", EntityType.PARROT, Parrot.Variant.BLUE, true),
CYAN_PARROT("cyan", EntityType.PARROT, Parrot.Variant.CYAN, true),
GRAY_PARROT("gray", EntityType.PARROT, Parrot.Variant.GRAY, true),
KOB_TROPICAL_FISH("kob", EntityType.TROPICAL_FISH, TropicalFish.Pattern.KOB, true),
SUNSTREAK_TROPICAL_FISH("sunstreak", EntityType.TROPICAL_FISH, TropicalFish.Pattern.SUNSTREAK, true),
SNOOPER_TROPICAL_FISH("snooper", EntityType.TROPICAL_FISH, TropicalFish.Pattern.SNOOPER, true),
DASHER_TROPICAL_FISH("dasher", EntityType.TROPICAL_FISH, TropicalFish.Pattern.DASHER, true),
BRINELY_TROPICAL_FISH("brinely", EntityType.TROPICAL_FISH, TropicalFish.Pattern.BRINELY, true),
SPOTTY_TROPICAL_FISH("spotty", EntityType.TROPICAL_FISH, TropicalFish.Pattern.SPOTTY, true),
FLOPPER_TROPICAL_FISH("flopper", EntityType.TROPICAL_FISH, TropicalFish.Pattern.FLOPPER, true),
STRIPEY_TROPICAL_FISH("stripey", EntityType.TROPICAL_FISH, TropicalFish.Pattern.STRIPEY, true),
GLITTER_TROPICAL_FISH("glitter", EntityType.TROPICAL_FISH, TropicalFish.Pattern.GLITTER, true),
BLOCKFISH_TROPICAL_FISH("blockfish", EntityType.TROPICAL_FISH, TropicalFish.Pattern.BLOCKFISH, true),
BETTY_TROPICAL_FISH("betty", EntityType.TROPICAL_FISH, TropicalFish.Pattern.BETTY, true),
CLAYFISH_TROPICAL_FISH("clayfish", EntityType.TROPICAL_FISH, TropicalFish.Pattern.CLAYFISH, true);
VILLAGER("villager", EntityType.VILLAGER, MobCompat.VillagerProfession.NONE, true),
ARMORER_VILLAGER("armorer", EntityType.VILLAGER, MobCompat.VillagerProfession.ARMORER, true),
BUTCHER_VILLAGER("butcher", EntityType.VILLAGER, MobCompat.VillagerProfession.BUTCHER, true),
CARTOGRAPHER_VILLAGER("cartographer", EntityType.VILLAGER, MobCompat.VillagerProfession.CARTOGRAPHER, true),
CLERIC_VILLAGER("cleric", EntityType.VILLAGER, MobCompat.VillagerProfession.CLERIC, true),
FARMER_VILLAGER("farmer", EntityType.VILLAGER, MobCompat.VillagerProfession.FARMER, true),
FISHERMAN_VILLAGER("fisherman", EntityType.VILLAGER, MobCompat.VillagerProfession.FISHERMAN, true),
FLETCHER_VILLAGER("fletcher", EntityType.VILLAGER, MobCompat.VillagerProfession.FLETCHER, true),
LEATHERWORKER_VILLAGER("leatherworker", EntityType.VILLAGER, MobCompat.VillagerProfession.LEATHERWORKER, true),
LIBRARIAN_VILLAGER("librarian", EntityType.VILLAGER, MobCompat.VillagerProfession.LIBRARIAN, true),
MASON_VILLAGER("mason", EntityType.VILLAGER, MobCompat.VillagerProfession.MASON, true),
NITWIT_VILLAGER("nitwit", EntityType.VILLAGER, MobCompat.VillagerProfession.NITWIT, true),
SHEPHERD_VILLAGER("shepherd", EntityType.VILLAGER, MobCompat.VillagerProfession.SHEPHERD, true),
TOOLSMITH_VILLAGER("toolsmith", EntityType.VILLAGER, MobCompat.VillagerProfession.TOOLSMITH, true),
WEAPONSMITH_VILLAGER("weaponsmith", EntityType.VILLAGER, MobCompat.VillagerProfession.WEAPONSMITH, true),
DESERT_VILLAGER("desert", EntityType.VILLAGER, "villagertype:DESERT", true),
JUNGLE_VILLAGER("jungle", EntityType.VILLAGER, "villagertype:JUNGLE", true),
PLAINS_VILLAGER("plains", EntityType.VILLAGER, "villagertype:PLAINS", true),
SAVANNA_VILLAGER("savanna", EntityType.VILLAGER, "villagertype:SAVANNA", true),
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("", 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),
CYAN_PARROT("cyan", MobCompat.PARROT, "parrot:CYAN", true),
GRAY_PARROT("gray", MobCompat.PARROT, "parrot:GRAY", true),
KOB_TROPICAL_FISH("kob", MobCompat.TROPICAL_FISH, "tropicalfish:KOB", true),
SUNSTREAK_TROPICAL_FISH("sunstreak", MobCompat.TROPICAL_FISH, "tropicalfish:SUNSTREAK", true),
SNOOPER_TROPICAL_FISH("snooper", MobCompat.TROPICAL_FISH, "tropicalfish:SNOOPER", true),
DASHER_TROPICAL_FISH("dasher", MobCompat.TROPICAL_FISH, "tropicalfish:DASHER", true),
BRINELY_TROPICAL_FISH("brinely", MobCompat.TROPICAL_FISH, "tropicalfish:BRINELY", true),
SPOTTY_TROPICAL_FISH("spotty", MobCompat.TROPICAL_FISH, "tropicalfish:SPOTTY", true),
FLOPPER_TROPICAL_FISH("flopper", MobCompat.TROPICAL_FISH, "tropicalfish:FLOPPER", true),
STRIPEY_TROPICAL_FISH("stripey", MobCompat.TROPICAL_FISH, "tropicalfish:STRIPEY", true),
GLITTER_TROPICAL_FISH("glitter", MobCompat.TROPICAL_FISH, "tropicalfish:GLITTER", true),
BLOCKFISH_TROPICAL_FISH("blockfish", MobCompat.TROPICAL_FISH, "tropicalfish:BLOCKFISH", true),
BETTY_TROPICAL_FISH("betty", MobCompat.TROPICAL_FISH, "tropicalfish:BETTY", true),
CLAYFISH_TROPICAL_FISH("clayfish", MobCompat.TROPICAL_FISH, "tropicalfish:CLAYFISH", true),
BROWN_MUSHROOM_COW("brown", EntityType.MUSHROOM_COW, "mooshroom:BROWN", true),
RED_MUSHROOM_COW("red", EntityType.MUSHROOM_COW, "mooshroom:RED", true),
AGGRESSIVE_PANDA_MAIN("aggressive", MobCompat.PANDA, "pandamain:AGGRESSIVE", true),
LAZY_PANDA_MAIN("lazy", MobCompat.PANDA, "pandamain:LAZY", true),
WORRIED_PANDA_MAIN("worried", MobCompat.PANDA, "pandamain:WORRIED", true),
PLAYFUL_PANDA_MAIN("playful", MobCompat.PANDA, "pandamain:PLAYFUL", true),
BROWN_PANDA_MAIN("brown", MobCompat.PANDA, "pandamain:BROWN", true),
WEAK_PANDA_MAIN("weak", MobCompat.PANDA, "pandamain:WEAK", true),
AGGRESSIVE_PANDA_HIDDEN("aggressive_hidden", MobCompat.PANDA, "pandahidden:AGGRESSIVE", true),
LAZY_PANDA_HIDDEN("lazy_hidden", MobCompat.PANDA, "pandahidden:LAZY", true),
WORRIED_PANDA_HIDDEN("worried_hidden", MobCompat.PANDA, "pandahidden:WORRIED", true),
PLAYFUL_PANDA_HIDDEN("playful_hidden", MobCompat.PANDA, "pandahidden:PLAYFUL", true),
BROWN_PANDA_HIDDEN("brown_hidden", MobCompat.PANDA, "pandahidden:BROWN", true),
WEAK_PANDA_HIDDEN("weak_hidden", MobCompat.PANDA, "pandahidden:WEAK", true),
CREAMY_LLAMA("creamy", MobCompat.LLAMA, "llama:CREAMY", true),
WHITE_LLAMA("white", MobCompat.LLAMA, "llama:WHITE", true),
BROWN_LLAMA("brown", MobCompat.LLAMA, "llama:BROWN", true),
GRAY_LLAMA("gray", MobCompat.LLAMA, "llama:GRAY", true),
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),
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),
;
@@ -124,42 +179,49 @@ 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 instanceof EntityType && spawned.getType().equals(data.type) && ((publicOnly && data.isPublic) || !publicOnly)) {
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()) && ((publicOnly && data.isPublic) || !publicOnly)) {
} else if (data.type instanceof Class && ((Class) data.type).isAssignableFrom(spawned.getClass())) {
mobList.put(data.nickname.toLowerCase(Locale.ENGLISH), data);
}
}
@@ -168,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;
}
@@ -183,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;
@@ -241,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);
@@ -250,10 +319,10 @@ public enum MobData {
((Horse) spawned).setColor((Horse.Color) this.value);
} else if (this.value instanceof Horse.Style) {
((Horse) spawned).setStyle((Horse.Style) this.value);
} else if (this.value instanceof Ocelot.Type) {
((Ocelot) spawned).setCatType((Ocelot.Type) this.value);
} else if (this.value instanceof Villager.Profession) {
((Villager) spawned).setProfession((Villager.Profession) this.value);
} else if (this.value instanceof MobCompat.CatType) {
MobCompat.setCatType(spawned, (MobCompat.CatType) this.value);
} else if (this.value instanceof MobCompat.VillagerProfession) {
MobCompat.setVillagerProfession(spawned, (MobCompat.VillagerProfession) this.value);
} else if (this.value instanceof Material) {
if (this.type.equals(EntityType.HORSE)) {
((Horse) spawned).setTamed(true);
@@ -263,10 +332,56 @@ public enum MobData {
InventoryWorkaround.setItemInMainHand(invent, new ItemStack((Material) this.value, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
}
} else if (this.value instanceof Parrot.Variant) {
((Parrot) spawned).setVariant((Parrot.Variant) this.value);
} else if (this.value instanceof TropicalFish.Pattern) {
((TropicalFish) spawned).setPattern((TropicalFish.Pattern) this.value);
} 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]) {
case "parrot":
MobCompat.setParrotVariant(spawned, split[1]);
break;
case "tropicalfish":
MobCompat.setTropicalFishPattern(spawned, split[1]);
break;
case "mooshroom":
MobCompat.setMooshroomVariant(spawned, split[1]);
break;
case "pandamain":
MobCompat.setPandaGene(spawned, split[1], true);
break;
case "pandahidden":
MobCompat.setPandaGene(spawned, split[1], false);
break;
case "llama":
MobCompat.setLlamaColor(spawned, split[1]);
break;
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());
}
}
@@ -1,13 +1,15 @@
package com.earth2me.essentials;
import com.earth2me.essentials.api.IItemDb;
import com.earth2me.essentials.commands.IEssentialsCommand;
import com.earth2me.essentials.signs.EssentialsSign;
import com.earth2me.essentials.signs.Signs;
import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.LocationUtil;
import com.earth2me.essentials.utils.NumberUtil;
import net.ess3.api.IEssentials;
import org.bukkit.ChatColor;
import org.bukkit.Material;
@@ -22,21 +24,30 @@ import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
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 static com.earth2me.essentials.I18n.tl;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import static com.earth2me.essentials.I18n.tl;
public class Settings implements net.ess3.api.ISettings {
private final transient EssentialsConf config;
private static final Logger logger = Logger.getLogger("Essentials");
private final transient IEssentials ess;
private boolean metricsEnabled = true;
public Settings(IEssentials ess) {
this.ess = ess;
@@ -146,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);
@@ -171,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) {
@@ -179,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));
}
@@ -259,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")) {
@@ -285,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));
@@ -349,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
@@ -409,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) {
@@ -428,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);
}
@@ -470,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 {
@@ -482,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();
@@ -493,8 +533,10 @@ public class Settings implements net.ess3.api.ISettings {
cancelAfkOnInteract = _cancelAfkOnInteract();
cancelAfkOnMove = _cancelAfkOnMove();
getFreezeAfkPlayers = _getFreezeAfkPlayers();
sleepIgnoresAfkPlayers = _sleepIgnoresAfkPlayers();
afkListName = _getAfkListName();
isAfkListName = !afkListName.equalsIgnoreCase("none");
broadcastAfkMessage = _broadcastAfkMessage();
itemSpawnBl = _getItemSpawnBlacklist();
loginAttackDelay = _getLoginAttackDelay();
signUsePerSecond = _getSignUsePerSecond();
@@ -535,14 +577,26 @@ public class Settings implements net.ess3.api.ISettings {
currencyFormat = _getCurrencyFormat();
unprotectedSigns = _getUnprotectedSign();
defaultEnabledConfirmCommands = _getDefaultEnabledConfirmCommands();
teleportBackWhenFreedFromJail = _isTeleportBackWhenFreedFromJail();
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();
}
private List<Material> itemSpawnBl = new ArrayList<Material>();
void _lateLoadItemSpawnBlacklist() {
itemSpawnBl = _getItemSpawnBlacklist();
}
private List<Material> itemSpawnBl = new ArrayList<>();
@Override
public List<Material> itemSpawnBlacklist() {
@@ -551,7 +605,8 @@ public class Settings implements net.ess3.api.ISettings {
private List<Material> _getItemSpawnBlacklist() {
final List<Material> epItemSpwn = new ArrayList<>();
if (ess.getItemDb() == null) {
final IItemDb itemDb = ess.getItemDb();
if (itemDb == null || !itemDb.isReady()) {
logger.log(Level.FINE, "Skipping item spawn blacklist read; item DB not yet loaded.");
return epItemSpwn;
}
@@ -561,7 +616,7 @@ public class Settings implements net.ess3.api.ISettings {
continue;
}
try {
final ItemStack iStack = ess.getItemDb().get(itemName);
final ItemStack iStack = itemDb.get(itemName);
epItemSpwn.add(iStack.getType());
} catch (Exception ex) {
logger.log(Level.SEVERE, tl("unknownItemInList", itemName, "item-spawn-blacklist"), ex);
@@ -570,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
@@ -581,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);
@@ -648,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
@@ -686,12 +746,20 @@ public class Settings implements net.ess3.api.ISettings {
if (itemName.isEmpty()) {
continue;
}
ItemStack itemStack;
try {
itemStack = ess.getItemDb().get(itemName);
list.add(itemStack.getType());
} catch (Exception ex) {
Material mat = EnumUtil.getMaterial(itemName.toUpperCase());
if (mat == null) {
try {
ItemStack itemStack = ess.getItemDb().get(itemName);
mat = itemStack.getType();
} catch (Exception ignored) {}
}
if (mat == null) {
logger.log(Level.SEVERE, tl("unknownItemInList", itemName, configName));
} else {
list.add(mat);
}
}
return list;
@@ -754,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);
}
@@ -879,6 +952,17 @@ public class Settings implements net.ess3.api.ISettings {
return config.getBoolean("cancel-afk-on-interact", true);
}
private boolean sleepIgnoresAfkPlayers;
@Override
public boolean sleepIgnoresAfkPlayers() {
return sleepIgnoresAfkPlayers;
}
private boolean _sleepIgnoresAfkPlayers() {
return config.getBoolean("sleep-ignores-afk-players", true);
}
private String afkListName;
private boolean isAfkListName;
@@ -896,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() {
@@ -1067,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
@@ -1081,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
@@ -1090,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);
@@ -1155,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);
@@ -1180,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);
}
@@ -1275,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) {
@@ -1387,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;
@@ -1403,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);
@@ -1428,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() {
@@ -1448,6 +1607,17 @@ public class Settings implements net.ess3.api.ISettings {
return getDefaultEnabledConfirmCommands().contains(commandName.toLowerCase());
}
private boolean teleportBackWhenFreedFromJail;
private boolean _isTeleportBackWhenFreedFromJail() {
return config.getBoolean("teleport-back-when-freed-from-jail", true);
}
@Override
public boolean isTeleportBackWhenFreedFromJail() {
return teleportBackWhenFreedFromJail;
}
private boolean isCompassTowardsHomePerm;
private boolean _isCompassTowardsHomePerm() {
@@ -1483,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() {
@@ -1502,4 +1663,98 @@ public class Settings implements net.ess3.api.ISettings {
public boolean allowOldIdSigns() {
return allowOldIdSigns;
}
private boolean isWaterSafe;
private boolean _isWaterSafe() {
boolean _isWaterSafe = config.getBoolean("is-water-safe", false);
LocationUtil.setIsWaterSafe(_isWaterSafe);
return _isWaterSafe;
}
@Override
public boolean isWaterSafe() {
return isWaterSafe;
}
private boolean isSafeUsermap;
private boolean _isSafeUsermap() {
return config.getBoolean("safe-usermap-names", true);
}
@Override
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) {
@@ -2,9 +2,13 @@ package com.earth2me.essentials;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.LocationUtil;
import io.papermc.lib.PaperLib;
import net.ess3.api.IEssentials;
import net.ess3.api.ITeleport;
import net.ess3.api.IUser;
import net.ess3.api.events.UserWarpEvent;
import net.ess3.api.events.teleport.PreTeleportEvent;
import net.ess3.api.events.teleport.TeleportWarmupEvent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
@@ -18,13 +22,18 @@ import java.util.GregorianCalendar;
import static com.earth2me.essentials.I18n.tl;
public class Teleport implements net.ess3.api.ITeleport {
/**
* @deprecated This API is not asynchronous. Use {@link com.earth2me.essentials.AsyncTeleport AsyncTeleport}
*/
@Deprecated
public class Teleport implements ITeleport {
private final IUser teleportOwner;
private final IEssentials ess;
private TimedTeleport timedTeleport;
private TeleportType tpType;
@Deprecated
public Teleport(IUser user, IEssentials ess) {
this.teleportOwner = user;
this.ess = ess;
@@ -37,6 +46,7 @@ public class Teleport implements net.ess3.api.ITeleport {
NORMAL
}
@Deprecated
public void cooldown(boolean check) throws Exception {
final Calendar time = new GregorianCalendar();
if (teleportOwner.getLastTeleportTimestamp() > 0) {
@@ -49,7 +59,7 @@ public class Teleport implements net.ess3.api.ITeleport {
final long earliestLong = earliestTime.getTimeInMillis();
// When was the last teleportPlayer used?
final Long lastTime = teleportOwner.getLastTeleportTimestamp();
final long lastTime = teleportOwner.getLastTeleportTimestamp();
if (lastTime > time.getTimeInMillis()) {
// This is to make sure time didn't get messed up on last teleportPlayer use.
@@ -70,6 +80,7 @@ public class Teleport implements net.ess3.api.ITeleport {
}
}
@Deprecated
private boolean cooldownApplies() {
boolean applies = true;
String globalBypassPerm = "essentials.teleport.cooldown.bypass";
@@ -89,6 +100,7 @@ public class Teleport implements net.ess3.api.ITeleport {
return applies;
}
@Deprecated
private void warnUser(final IUser user, final double delay) {
Calendar c = new GregorianCalendar();
c.add(Calendar.SECOND, (int) delay);
@@ -98,6 +110,7 @@ public class Teleport implements net.ess3.api.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);
@@ -107,6 +120,7 @@ public class Teleport implements net.ess3.api.ITeleport {
}
@Override
@Deprecated
public void now(Player entity, boolean cooldown, TeleportCause cause) throws Exception {
if (cooldown) {
cooldown(false);
@@ -116,29 +130,46 @@ public class Teleport implements net.ess3.api.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()) {
teleportee.getBase().teleport(loc, cause);
PaperLib.teleportAsync(teleportee.getBase(), loc, cause);
} else {
teleportee.getBase().teleport(LocationUtil.getSafeDestination(ess, teleportee, loc), cause);
PaperLib.teleportAsync(teleportee.getBase(), LocationUtil.getSafeDestination(ess, teleportee, loc), cause);
}
} else {
throw new Exception(tl("unsafeTeleportDestination", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
}
} else {
if (ess.getSettings().isForceDisableTeleportSafety()) {
teleportee.getBase().teleport(loc, cause);
PaperLib.teleportAsync(teleportee.getBase(), loc, cause);
} else {
if (ess.getSettings().isTeleportToCenterLocation()) {
loc = LocationUtil.getRoundedDestination(loc);
}
teleportee.getBase().teleport(loc, cause);
PaperLib.teleportAsync(teleportee.getBase(), loc, cause);
}
}
}
@@ -152,12 +183,14 @@ public class Teleport implements net.ess3.api.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()));
@@ -166,12 +199,14 @@ public class Teleport implements net.ess3.api.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);
@@ -179,9 +214,17 @@ public class Teleport implements net.ess3.api.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) {
@@ -209,10 +252,60 @@ public class Teleport implements net.ess3.api.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) {
chargeFor.isAffordableFor(teleporter);
//This code is to make sure that commandcosts are checked in the initial world, and not in the resulting world.
if (!chargeFor.getCommandCost(teleporter).equals(BigDecimal.ZERO)) {
//By converting a command cost to a regular cost, the command cost permission isn't checked when executing the charge after teleport.
cashCharge = new Trade(chargeFor.getCommandCost(teleporter), ess);
}
}
cooldown(true);
if (delay <= 0 || teleporter == null
|| teleporter.isAuthorized("essentials.teleport.timer.bypass")
|| teleportOwner.isAuthorized("essentials.teleport.timer.bypass")
|| teleportee.isAuthorized("essentials.teleport.timer.bypass")) {
cooldown(false);
now(teleportee, target, cause);
if (teleporter != null && cashCharge != null) {
cashCharge.charge(teleporter);
}
return;
}
cancel(false);
warnUser(teleportee, delay);
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false);
}
//The respawn function is a wrapper used to handle tp fallback, on /jail and /home
@Override
@Deprecated
public void respawn(final Trade chargeFor, TeleportCause cause) throws Exception {
double delay = ess.getSettings().getTeleportDelay();
TeleportWarmupEvent event = new TeleportWarmupEvent(teleportOwner, cause, null, delay);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
delay = event.getDelay();
if (chargeFor != null) {
chargeFor.isAffordableFor(teleportOwner);
}
@@ -231,7 +324,8 @@ public class Teleport implements net.ess3.api.ITeleport {
initTimer((long) (delay * 1000.0), teleportOwner, null, chargeFor, cause, true);
}
protected void respawnNow(IUser teleportee, TeleportCause cause) throws Exception {
@Deprecated
void respawnNow(IUser teleportee, TeleportCause cause) throws Exception {
final Player player = teleportee.getBase();
Location bed = player.getBedSpawnLocation();
if (bed != null) {
@@ -248,13 +342,14 @@ public class Teleport implements net.ess3.api.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()));
@@ -266,24 +361,35 @@ public class Teleport implements net.ess3.api.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();
teleportOwner.sendMessage(tl("backUsageMsg", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
teleport(teleportOwner, new LocationTarget(loc), chargeFor, TeleportCause.COMMAND);
teleportOther(teleporter, teleportOwner, new LocationTarget(loc), chargeFor, TeleportCause.COMMAND);
}
//This function is used to throw a user back after a jail sentence
@Override
@Deprecated
public void back() throws Exception {
now(teleportOwner, new LocationTarget(teleportOwner.getLastLocation()), TeleportCause.COMMAND);
}
@Deprecated
public void setTpType(TeleportType tpType) {
this.tpType = tpType;
}
//If we need to cancelTimer a pending teleportPlayer call this method
@Deprecated
private void cancel(boolean notifyUser) {
if (timedTeleport != null) {
timedTeleport.cancelTimer(notifyUser);
@@ -291,6 +397,7 @@ public class Teleport implements net.ess3.api.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,16 +9,16 @@ import java.util.UUID;
import static com.earth2me.essentials.I18n.tl;
@Deprecated
public class TimedTeleport implements Runnable {
private static final double MOVE_CONSTANT = 0.3;
private final IUser teleportOwner;
private final IEssentials ess;
private final Teleport teleport;
private final UUID timer_teleportee;
private int timer_task = -1;
private final long timer_started; // time this task was initiated
private final long timer_delay; // how long to delay the teleportPlayer
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)
@@ -32,8 +32,7 @@ public class TimedTeleport implements Runnable {
private final Trade timer_chargeFor;
private final TeleportCause timer_cause;
public TimedTeleport(IUser user, IEssentials ess, Teleport teleport, long delay, IUser teleportUser, ITarget target, Trade chargeFor, TeleportCause cause, boolean respawn) {
TimedTeleport(IUser user, IEssentials ess, Teleport teleport, long delay, IUser teleportUser, ITarget target, Trade chargeFor, TeleportCause cause, boolean respawn) {
this.teleportOwner = user;
this.ess = ess;
this.teleport = teleport;
@@ -99,19 +98,16 @@ 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 ex) {
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) {
@@ -124,7 +120,7 @@ public class TimedTeleport implements Runnable {
}
//If we need to cancelTimer a pending teleportPlayer call this method
public void cancelTimer(boolean notifyUser) {
void cancelTimer(boolean notifyUser) {
if (timer_task == -1) {
return;
}
@@ -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();
}
}
};
+155 -55
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();
}
@@ -97,6 +106,11 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return result;
}
@Override
public boolean isPermissionSet(final String node) {
return isPermSetCheck(node);
}
private boolean isAuthorizedCheck(final String node) {
if (base instanceof OfflinePlayer) {
@@ -116,6 +130,24 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
}
private boolean isPermSetCheck(final String node) {
if (base instanceof OfflinePlayer) {
return false;
}
try {
return ess.getPermissionsHandler().isPermissionSet(base, node);
} catch (Exception ex) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.SEVERE, "Permission System Error: " + ess.getPermissionsHandler().getName() + " returned: " + ex.getMessage(), ex);
} else {
ess.getLogger().log(Level.SEVERE, "Permission System Error: " + ess.getPermissionsHandler().getName() + " returned: " + ex.getMessage());
}
return false;
}
}
@Override
public void healCooldown() throws Exception {
final Calendar now = new GregorianCalendar();
@@ -139,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)));
@@ -151,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 {
@@ -172,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);
}
@@ -203,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() {
@@ -306,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();
@@ -371,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;
}
@@ -409,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();
@@ -417,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.");
@@ -424,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();
@@ -437,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);
@@ -448,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) {
@@ -459,13 +519,18 @@ 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;
}
this.getBase().setSleepingIgnored(this.isAuthorized("essentials.sleepingignored") ? true : set);
this.getBase().setSleepingIgnored(this.isAuthorized("essentials.sleepingignored") || set && ess.getSettings().sleepIgnoresAfkPlayers());
if (set && !isAfk()) {
afkPosition = this.getLocation();
this.afkSince = System.currentTimeMillis();
@@ -477,7 +542,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
_setAfk(set);
updateAfkListName();
}
private void updateAfkListName() {
if (ess.getSettings().isAfkListName()) {
if(isAfk()) {
@@ -489,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();
}
@@ -506,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());
}
}
@@ -522,13 +592,13 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
setJailed(false);
sendMessage(tl("haveBeenReleased"));
setJail(null);
try {
getTeleport().back();
} catch (Exception ex) {
try {
getTeleport().respawn(null, TeleportCause.PLUGIN);
} catch (Exception ex1) {
}
if (ess.getSettings().isTeleportBackWhenFreedFromJail()) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
getAsyncTeleport().back(future);
future.exceptionally(e -> {
getAsyncTeleport().respawn(null, TeleportCause.PLUGIN, new CompletableFuture<>());
return false;
});
}
return true;
}
@@ -539,27 +609,38 @@ 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()) {
setMuteTimeout(0);
sendMessage(tl("canTalkAgain"));
setMuted(false);
setMuteReason(null);
return true;
}
}
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);
}
}
}
@@ -568,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);
}
}
@@ -602,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);
}
}
}
@@ -629,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;
}
@@ -879,7 +963,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
* Returns the {@link ItemStack} in the main hand or off-hand. If the main hand is empty then the offhand item is returned - also nullable.
*/
public ItemStack getItemInHand() {
if (ReflUtil.getNmsVersionObject().isLowerThan(ReflUtil.V1_9_R1)) {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_9_R01)) {
return getBase().getInventory().getItemInHand();
} else {
PlayerInventory inventory = getBase().getInventory();
@@ -897,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();
}
@@ -74,6 +74,7 @@ public abstract class UserData extends PlayerExtension implements IConf {
godmode = _getGodModeEnabled();
muted = _getMuted();
muteTimeout = _getMuteTimeout();
muteReason = _getMuteReason();
jailed = _getJailed();
jailTimeout = _getJailTimeout();
lastLogin = _getLastLogin();
@@ -93,6 +94,7 @@ public abstract class UserData extends PlayerExtension implements IConf {
acceptingPay = _getAcceptingPay();
confirmPay = _getConfirmPay();
confirmClear = _getConfirmClear();
lastMessageReplyRecipient = _getLastMessageReplyRecipient();
}
private BigDecimal money;
@@ -147,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;
@@ -187,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) {
@@ -216,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() {
@@ -232,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);
@@ -247,7 +252,7 @@ public abstract class UserData extends PlayerExtension implements IConf {
return retlist;
}
public List<Material> getUnlimited() {
public Set<Material> getUnlimited() {
return unlimited;
}
@@ -256,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();
}
@@ -446,19 +458,58 @@ public abstract class UserData extends PlayerExtension implements IConf {
config.save();
}
private List<String> ignoredPlayers;
private boolean autoTeleportEnabled;
public List<String> _getIgnoredPlayers() {
return Collections.synchronizedList(config.getStringList("ignore"));
private boolean _getAutoTeleportEnabled() {
return config.getBoolean("teleportauto", false);
}
public boolean isAutoTeleportEnabled() {
return autoTeleportEnabled;
}
public void setAutoTeleportEnabled(boolean set) {
autoTeleportEnabled = set;
config.setProperty("teleportauto", set);
config.save();
}
private List<UUID> ignoredPlayers;
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();
}
@@ -473,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;
@@ -503,6 +556,7 @@ public abstract class UserData extends PlayerExtension implements IConf {
}
private boolean muted;
private String muteReason;
public boolean _getMuted() {
return config.getBoolean("muted", false);
@@ -522,6 +576,29 @@ public abstract class UserData extends PlayerExtension implements IConf {
config.save();
}
public String _getMuteReason() {
return config.getString("muteReason");
}
public String getMuteReason() {
return muteReason;
}
public void setMuteReason(String reason) {
if (reason == null) {
config.removeProperty("muteReason");
muteReason = null;
} else {
muteReason = reason;
config.setProperty("muteReason", reason);
}
config.save();
}
public boolean hasMuteReason(){
return muteReason != null;
}
private long muteTimeout;
private long _getMuteTimeout() {
@@ -745,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));
@@ -755,19 +832,20 @@ public abstract class UserData extends PlayerExtension implements IConf {
}
return timestamps;
}
return new HashMap<String, Long>();
return new HashMap<>();
}
public long getKitTimestamp(String name) {
name = name.replace('.', '_').replace('/', '_');
name = name.replace('.', '_').replace('/', '_').toLowerCase(Locale.ENGLISH);
if (kitTimestamps != null && kitTimestamps.containsKey(name)) {
return kitTimestamps.get(name);
}
return 0l;
return 0L;
}
public void setKitTimestamp(final String name, final long time) {
kitTimestamps.put(name.toLowerCase(Locale.ENGLISH), time);
public void setKitTimestamp(String name, final long time) {
name = name.replace('.', '_').replace('/', '_').toLowerCase(Locale.ENGLISH);
kitTimestamps.put(name, time);
config.setProperty("timestamps.kits", kitTimestamps);
config.save();
}
@@ -793,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;
}
@@ -941,6 +1019,22 @@ public abstract class UserData extends PlayerExtension implements IConf {
save();
}
private boolean lastMessageReplyRecipient;
private boolean _getLastMessageReplyRecipient() {
return config.getBoolean("last-message-reply-recipient", ess.getSettings().isLastMessageReplyRecipient());
}
public boolean isLastMessageReplyRecipient() {
return this.lastMessageReplyRecipient;
}
public void setLastMessageReplyRecipient(boolean enabled) {
this.lastMessageReplyRecipient = enabled;
config.setProperty("last-message-reply-recipient", enabled);
save();
}
public UUID getConfigUUID() {
return config.uuid;
}
@@ -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;
}
}
@@ -123,7 +118,7 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
if (uuid != null) {
keys.add(uuid);
if (name != null && name.length() > 0) {
final String keyName = StringUtil.safeString(name);
final String keyName = ess.getSettings().isSafeUsermap() ? StringUtil.safeString(name) : name;
if (!names.containsKey(keyName)) {
names.put(keyName, uuid);
uuidMap.writeUUIDMap();
@@ -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,8 @@ 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;
import java.math.BigDecimal;
@@ -18,7 +20,7 @@ import java.util.logging.Logger;
/**
* Instead of using this api directly, we recommend to use the register plugin: http://bit.ly/RegisterMethod
* You should use Vault instead of directly using this class.
*/
public class Economy {
public Economy() {
@@ -40,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"));
@@ -62,14 +66,42 @@ 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");
}
return ess.getUser(name);
User user = ess.getUser(name);
if (user == null) {
/*
Attempt lookup using UUID - this prevents balance resets when accessing economy
via Vault during player join.
See: https://github.com/EssentialsX/Essentials/issues/2400
*/
Player player = ess.getServer().getPlayerExact(name);
if (player != null) {
user = ess.getUser(player.getUniqueId());
if (user != null) {
logger.info(String.format("[Economy] Found player %s by UUID %s but not by their actual name - they may have changed their username", name, player.getUniqueId().toString()));
}
}
}
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
@@ -88,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
*
@@ -114,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();
}
@@ -126,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
*
@@ -151,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
@@ -171,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
*
@@ -199,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
*
@@ -223,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);
@@ -246,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
*
@@ -263,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
*
@@ -285,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
*
@@ -307,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
*
@@ -320,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;
}
/**
@@ -351,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;
@@ -33,6 +31,9 @@ public interface IItemDb {
/**
* Create a stack from the given name with the maximum stack size for that material.
*
* Note that this will always check against resolver functions from other plugins as well.
* To avoid this behaviour, use net.ess3.api.IItemDb#get(String name, boolean useResolvers).
*
* @param name Item name to look up in the database
* @return The requested item stack with the maximum stack size
* @throws Exception if the item stack cannot be created
@@ -52,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.
@@ -82,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);
@@ -127,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;
@@ -153,4 +155,11 @@ public interface IItemDb {
default Material getFromLegacy(final int id, final byte damage) {
return MaterialUtil.convertFromLegacy(id, damage);
}
/**
* Check whether the item database is loaded and ready for use.
*
* @return Whether items have finished loading
*/
boolean isReady();
}
@@ -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,13 +119,29 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void back(Trade chargeFor) throws Exception;
/**
* 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
*
* @throws Exception
*/
@Deprecated
void back(IUser teleporter, Trade chargeFor) throws Exception;
/**
* Teleport wrapper used to handle throwing user home after a jail sentence
*
* @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(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
}
@@ -1,8 +1,15 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
@@ -13,24 +20,82 @@ public class Commandback extends EssentialsCommand {
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
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, commandLabel);
return;
}
teleportBack(sender, user, commandLabel);
}
@Override
protected void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
if (args.length < 1) {
throw new NotEnoughArgumentsException();
}
this.parseCommand(server, sender, args, true, commandLabel);
}
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) {
players = server.matchPlayer(args[0].trim());
}
if (players.size() < 1) {
throw new PlayerNotFoundException();
}
for (Player player : players) {
sender.sendMessage(tl("backOther", player.getName()));
teleportBack(sender, ess.getUser(player), commandLabel);
}
}
private void teleportBack(CommandSource sender, User user, String commandLabel) throws Exception {
if (user.getLastLocation() == null) {
throw new Exception(tl("noLocationFound"));
}
String lastWorldName = user.getLastLocation().getWorld().getName();
if (user.getWorld() != user.getLastLocation().getWorld() && ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + lastWorldName)) {
throw new Exception(tl("noPerm", "essentials.worlds." + lastWorldName));
User requester = null;
if (sender.isPlayer()) {
requester = ess.getUser(sender.getPlayer());
if (user.getWorld() != user.getLastLocation().getWorld() && this.ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + lastWorldName)) {
throw new Exception(tl("noPerm", "essentials.worlds." + lastWorldName));
}
if (!requester.isAuthorized("essentials.back.into." + lastWorldName)) {
throw new Exception(tl("noPerm", "essentials.back.into." + lastWorldName));
}
}
if (!user.isAuthorized("essentials.back.into." + lastWorldName)) {
throw new Exception(tl("noPerm", "essentials.back.into." + lastWorldName));
if (requester == 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.getAsyncTeleport().back(requester, charge, getNewExceptionFuture(sender, commandLabel));
} else {
Trade charge = new Trade(this.getName(), this.ess);
charge.isAffordableFor(user);
user.getAsyncTeleport().back(charge, getNewExceptionFuture(sender, commandLabel));
}
final Trade charge = new Trade(this.getName(), ess);
charge.isAffordableFor(user);
user.getTeleport().back(charge);
throw new NoChargeException();
}
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
if (user.isAuthorized("essentials.back.others") && args.length == 1) {
return getPlayers(server, user);
} else {
return Collections.emptyList();
}
}
}
@@ -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()) {
@@ -102,22 +101,19 @@ public class Commandbalancetop extends EssentialsCommand {
// Don't list NPCs in output
continue;
}
final BigDecimal userMoney = user.getMoney();
user.updateMoneyCache(userMoney);
totalMoney = totalMoney.add(userMoney);
final String name = user.isHidden() ? user.getName() : user.getDisplayName();
balances.put(name, userMoney);
if (!user.isAuthorized("essentials.balancetop.exclude")) {
final BigDecimal userMoney = user.getMoney();
user.updateMoneyCache(userMoney);
totalMoney = totalMoney.add(userMoney);
final String name = user.isHidden() ? user.getName() : user.getDisplayName();
balances.put(name, userMoney);
}
}
}
}
final List<Map.Entry<String, BigDecimal>> sortedEntries = new ArrayList<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);
@@ -135,6 +135,10 @@ public class Commandcondense extends EssentialsCommand {
if (recipe instanceof ShapedRecipe) {
ShapedRecipe sRecipe = (ShapedRecipe) recipe;
if (sRecipe.getShape().length != sRecipe.getShape()[0].length()) {
// Only accept square recipes
return null;
}
inputList = sRecipe.getIngredientMap().values();
} else if (recipe instanceof ShapelessRecipe) {
ShapelessRecipe slRecipe = (ShapelessRecipe) recipe;
@@ -167,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) {
@@ -14,7 +14,7 @@ public class Commanddisposal extends EssentialsCommand {
@Override
protected void run(Server server, User user, String commandLabel, String[] args) throws Exception {
user.sendMessage(tl("openingDisposal"));
user.getBase().openInventory(ess.getServer().createInventory(user.getBase(), 36, "Disposal"));
user.getBase().openInventory(ess.getServer().createInventory(user.getBase(), 36, tl("disposal")));
}
}
@@ -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_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,205 +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[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");
}
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");
} 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,51 +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;
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");
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.getBase().getInventory().getItemInMainHand();
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);
@@ -33,11 +66,19 @@ public class Commandhat extends EssentialsCommand {
user.sendMessage(tl("hatRemoved"));
}
} else {
if (user.getBase().getInventory().getItemInMainHand().getType() != Material.AIR) {
final ItemStack hand = user.getBase().getInventory().getItemInMainHand();
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,35 +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);
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();
}
@@ -24,7 +24,7 @@ public class Commanditemdb extends EssentialsCommand {
if (args.length < 1) {
if (sender.isPlayer() && sender.getPlayer() != null) {
itemHeld = true;
itemStack = sender.getPlayer().getInventory().getItemInMainHand();
itemStack = ess.getUser(sender.getPlayer()).getItemInHand();
}
if (itemStack == null) {
throw new NotEnoughArgumentsException();
@@ -33,10 +33,16 @@ public class Commanditemdb extends EssentialsCommand {
itemStack = ess.getItemDb().get(args[0]);
}
sender.sendMessage(tl("itemType", itemStack.getType().toString()));
String itemId = "none";
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_13_0_R01)) {
final String itemId = itemStack.getType().getId() + ":" + itemStack.getDurability();
itemId = itemStack.getType().getId() + ":" + itemStack.getDurability();
}
sender.sendMessage(tl("itemType", itemStack.getType().toString(), itemId));
// Don't send IDs twice
if (!tl("itemType").contains("{1}") && !itemId.equals("none")) {
sender.sendMessage(tl("itemId", itemId));
}
@@ -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();
}
}
}
@@ -0,0 +1,35 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commanditemname extends EssentialsCommand {
public Commanditemname() {
super("itemname");
}
@Override
protected void run(Server server, User user, String commandLabel, String[] args) throws Exception {
ItemStack item = user.getBase().getItemInHand();
if (item.getType().name().contains("AIR")) {
user.sendMessage(tl("itemnameInvalidItem", item.getType().toString().toLowerCase(Locale.ENGLISH).replace('_', ' ')));
return;
}
String name = FormatUtil.formatString(user, "essentials.itemname", getFinalArg(args, 0)).trim();
if (name.isEmpty()) name = null;
ItemMeta im = item.getItemMeta();
im.setDisplayName(name);
item.setItemMeta(im);
user.sendMessage(name == null ? tl("itemnameClear") : tl("itemnameSuccess", name));
}
}
@@ -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)) {
@@ -4,7 +4,11 @@ import com.earth2me.essentials.Mob;
import com.earth2me.essentials.User;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Cat;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Tameable;
import java.util.Random;
@@ -18,16 +22,7 @@ public class Commandkittycannon extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final Mob cat = Mob.OCELOT;
final Ocelot ocelot = (Ocelot) cat.spawn(user.getWorld(), server, user.getBase().getEyeLocation());
if (ocelot == null) {
return;
}
final int i = random.nextInt(Ocelot.Type.values().length);
ocelot.setCatType(Ocelot.Type.values()[i]);
ocelot.setTamed(true);
ocelot.setBaby();
ocelot.setVelocity(user.getBase().getEyeLocation().getDirection().multiply(2));
final Entity ocelot = Mob.CAT.getType() == null ? spawnOcelot(user.getWorld(), server, user) : spawnCat(user.getWorld(), server, user);
class KittyCannonExplodeTask implements Runnable {
@Override
@@ -40,4 +35,32 @@ public class Commandkittycannon extends EssentialsCommand {
ess.scheduleSyncDelayedTask(new KittyCannonExplodeTask(), 20);
}
private static Ocelot spawnOcelot(World world, Server server, User user) throws Mob.MobException {
final Ocelot ocelot = (Ocelot) Mob.OCELOT.spawn(user.getWorld(), server, user.getBase().getEyeLocation());
if (ocelot == null) {
return null;
}
final int i = random.nextInt(Ocelot.Type.values().length);
ocelot.setCatType(Ocelot.Type.values()[i]);
((Tameable) ocelot).setTamed(true);
ocelot.setBaby();
ocelot.setVelocity(user.getBase().getEyeLocation().getDirection().multiply(2));
return ocelot;
}
private static Entity spawnCat(World world, Server server, User user) throws Mob.MobException {
final Cat cat = (Cat) Mob.CAT.spawn(user.getWorld(), server, user.getBase().getEyeLocation());
if (cat == null) {
return null;
}
final int i = random.nextInt(Cat.Type.values().length);
cat.setCatType(Cat.Type.values()[i]);
cat.setTamed(true);
cat.setBaby();
cat.setVelocity(user.getBase().getEyeLocation().getDirection().multiply(2));
return cat;
}
}
@@ -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(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);
@@ -87,6 +92,11 @@ public class Commandmail extends EssentialsCommand {
return;
}
if (args.length >= 1 && "clear".equalsIgnoreCase(args[0])) {
if (user.getMails() == null || user.getMails().isEmpty()) {
user.sendMessage(tl("noMail"));
throw new NoChargeException();
}
user.setMails(null);
user.sendMessage(tl("mailCleared"));
return;
@@ -105,11 +115,11 @@ public class Commandmail extends EssentialsCommand {
if (u == null) {
throw new Exception(tl("playerNeverOnServer", args[1]));
}
u.addMail(tl("mailFormat", "Server", getFinalArg(args, 2)));
u.addMail(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 2))));
sender.sendMessage(tl("mailSent"));
return;
} else if (args.length >= 2 && "sendall".equalsIgnoreCase(args[0])) {
ess.runTaskAsynchronously(new SendAll(tl("mailFormat", "Server", getFinalArg(args, 1))));
ess.runTaskAsynchronously(new SendAll(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 1)))));
sender.sendMessage(tl("mailSent"));
return;
} else if (args.length >= 2) {
@@ -118,7 +128,7 @@ public class Commandmail extends EssentialsCommand {
if (u == null) {
throw new Exception(tl("playerNeverOnServer", args[0]));
}
u.addMail(tl("mailFormat", "Server", getFinalArg(args, 1)));
u.addMail(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 1))));
sender.sendMessage(tl("mailSent"));
return;
}
@@ -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(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;
@@ -16,23 +18,38 @@ 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.getBase().getInventory().getItemInMainHand();
if (stack == null) {
final ItemStack stack = user.getItemInHand();
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(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,21 +41,40 @@ 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) ? true : !user.getMuted();
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 = getFinalArg(args, 1);
muteTimestamp = DateUtil.parseDateDiff(time, true);
if (muteReason != null) {
user.setMuteReason(muteReason.isEmpty() ? null : muteReason);
user.setMuted(true);
} else {
user.setMuted(!user.getMuted());
if (!user.getMuted()) {
user.setMuteReason(null);
}
}
user.setMuteTimeout(muteTimestamp);
final boolean muted = user.getMuted();
@@ -66,17 +86,35 @@ public class Commandmute extends EssentialsCommand {
if (muted) {
if (muteTimestamp > 0) {
sender.sendMessage(tl("mutedPlayerFor", user.getDisplayName(), muteTime));
user.sendMessage(tl("playerMutedFor", muteTime));
if (!user.hasMuteReason()) {
sender.sendMessage(tl("mutedPlayerFor", user.getDisplayName(), muteTime));
user.sendMessage(tl("playerMutedFor", muteTime));
} else {
sender.sendMessage(tl("mutedPlayerForReason", user.getDisplayName(), muteTime, user.getMuteReason()));
user.sendMessage(tl("playerMutedForReason", muteTime, user.getMuteReason()));
}
} else {
sender.sendMessage(tl("mutedPlayer", user.getDisplayName()));
user.sendMessage(tl("playerMuted"));
if (!user.hasMuteReason()) {
sender.sendMessage(tl("mutedPlayer", user.getDisplayName()));
user.sendMessage(tl("playerMuted"));
} else {
sender.sendMessage(tl("mutedPlayerReason", user.getDisplayName(), user.getMuteReason()));
user.sendMessage(tl("playerMutedReason", user.getMuteReason()));
}
}
final String message;
if (muteTimestamp > 0) {
message = tl("muteNotifyFor", sender.getSender().getName(), user.getName(), muteTime);
if (!user.hasMuteReason()) {
message = tl("muteNotifyFor", sender.getSender().getName(), user.getName(), muteTime);
} else {
message = tl("muteNotifyForReason", sender.getSender().getName(), user.getName(), muteTime, user.getMuteReason());
}
} else {
message = tl("muteNotify", sender.getSender().getName(), user.getName());
if (!user.hasMuteReason()) {
message = tl("muteNotify", sender.getSender().getName(), user.getName());
} else {
message = tl("muteNotifyReason", sender.getSender().getName(), user.getName(), user.getMuteReason());
}
}
server.getLogger().log(Level.INFO, message);
ess.broadcastMessage("essentials.mute.notify", message);
@@ -9,6 +9,8 @@ import org.bukkit.World;
import java.util.Collections;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import static com.earth2me.essentials.I18n.tl;
@@ -36,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) {
}
}
}
@@ -70,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)));
@@ -83,8 +85,10 @@ public class Commandnear extends EssentialsCommand {
final long radiusSquared = radius * radius;
boolean showHidden = user.canInteractVanished();
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;
@@ -92,13 +96,19 @@ public class Commandnear extends EssentialsCommand {
final long delta = (long) playerLoc.distanceSquared(loc);
if (delta < radiusSquared) {
if (output.length() > 0) {
output.append(", ");
}
output.append(player.getDisplayName()).append("§f(§4").append((long) Math.sqrt(delta)).append("m§f)");
nearbyPlayers.offer(player);
}
}
}
while (!nearbyPlayers.isEmpty()) {
if (output.length() > 0) {
output.append(", ");
}
User nearbyPlayer = nearbyPlayers.poll();
output.append(nearbyPlayer.getDisplayName()).append("§f(§4").append((long) nearbyPlayer.getLocation().distance(loc)).append("m§f)");
}
return output.length() > 1 ? output.toString() : tl("none");
}
@@ -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);
Loaded 100 of 374 files, more files were not shown because too many files have changed in this diff. Show more