Compare commits

...
205 Commits
Author SHA1 Message Date
md678685 c8dc874a56 Release 2.18.1 2020-08-23 17:18:31 +01:00
Josh Roy b3a6307052 Fix miscellaneous command permission bugs (#3616)
Fixes #3612, in which `/list`'s tab complete previously revealed the presence of vanished players in certain groups, and fixes #3613 in which `/time set` did not properly check whether the player had permission to change the time.
2020-08-22 20:07:21 +01:00
pop4959 3ca0181b79 Update block damaging checks in teleportation safety (#3537)
This PR updates and improves LocationUtil#isBlockDamaging. Notably, the lava check is fixed (it was not working on older versions of Minecraft), many newer materials that were missing damage checks have been added, and the code is a bit cleaner. I've tested this code on MC 1.8 and 1.16 and everything should work correctly.
2020-08-22 18:37:15 +01:00
pop4959 98557dcecf Add world border checking to teleportation safety (#3536)
Fixes #3499. Please see that issue for discussion about the bug.

Fix demonstration with `/tppos`: https://imgur.com/a/Mo4okQa
2020-08-22 17:51:23 +01:00
MD 3351092c79 Add "amplifier" potion meta attribute (#3614)
Adds an `amplifier:<value>` potion meta attribute to MetaItemStack that applies a raw amplifier value, instead of translating inputs between 1 and 3 to match their vanilla names like `power:<value>` does. This matches the Mojang `/effect` command, which doesn't translate any potion effect amplifiers, and allows for creation of level IV potions (using `amplifier:3` instead of a `power` value) through EssentialsX without breaking existing usages of `power:<value>`.

More context for this commit can be found at https://github.com/EssentialsX/Essentials/pull/3592#issuecomment-678656107.

Closes #3592 and fixes #3589.
2020-08-22 17:40:40 +01:00
pop4959 68cd509d41 Fix /bigtree command on versions 1.12 and prior (#3569)
Fixes #3549.

Replaces the `Block#isPassable` check with `Material#isSolid`, which is compatible with all versions through 1.8 to 1.16.
2020-08-22 17:01:50 +01:00
xtomyserrax 5fa65b42ae Fix creeper player damage being cancelled incorrectly (#3604)
Previously, disabling creeper explosion block damage with the `protect.prevent.creeper-explosion` setting would also prevent players getting hurt. This fixes this, meaning servers can disable creeper block damage while still allowing players to take damage from creeper explosions.
2020-08-22 16:55:32 +01:00
Andre_601 bdae259a1d Update links in readme (#3596)
This PR updates several links:

- https://essentialsx.cf -> https://essentialsx.net
- Wiki links (Either github.io links or GitHub Wiki links) now point to their corresponding pages on the actual wiki (https://essentialsx.net/wiki/Home.html)
2020-08-22 16:49:50 +01:00
Jason fea86ea70e Add config note regarding displayname (#3535) 2020-08-22 14:15:24 +01:00
Josh Roy 1133770aeb Fix changing players' gamemodes from the console (#3590)
Fixes #3587 which was introduced by #3337.
2020-08-21 16:37:54 +01:00
MD 2c462106bc Fix blacklisted blocks being pulled by pistons (#3610)
Closes #3609.
2020-08-21 16:31:34 +01:00
triagonal bd1e624c91 clarify piston blacklist config comment 2020-08-21 23:00:56 +10:00
triagonal 6875fa4c7e fix blacklisted blocks being pulled by sticky piston 2020-08-21 23:00:18 +10:00
pop4959 def5f2155d Fix compilation issues on latest Spigot/Paper (#3607) 2020-08-20 19:24:42 +01:00
triagonal 73d2457fea Fix regression with teleportation commands where command cost gets charged twice (#3601) 2020-08-16 14:40:58 -07:00
MD bc52ca856e Update to 1.16.2 (#3586) 2020-08-11 23:12:41 +01:00
Flask Bot 18ccea320a Update items.json from generator
Note: this action was performed by a human (@md678685) under the
Flask-Bot account.
2020-08-11 23:06:07 +01:00
Josh Roy f6cb9ff470 Improve command codestyle (#3337)
Co-authored-by: MD <1917406+md678685@users.noreply.github.com>

Fixes #3579 (async `/skull` command)
Fixes #3336 (improve codestyle of commands)
Partially addresses #3339 (`/spawn` and `/setspawn` are now hidden from tabcomplete)
Closes #3087 (`/paytoggle` is now a loop command)
2020-08-11 19:09:22 +01:00
pop4959 14c6c2a055 Fix spawner delay feature (#3239)
Closes #1332

The spawner delay feature has been broken in Essentials for as long as anyone can remember. The reasons for this are mentioned in the issue above.

This PR fixes this by changing the command to utilize new API for setting the minimum and maximum spawn delay on spawners. This API was added in 1.12.2, so all supported versions before that (1.8.8 thru 1.12.1) require NMS to function properly. I'm aware that Essentials avoids NMS for maintainability reasons, however that should not be of much concern here since all versions 1.12.2 and later are going to be using the Bukkit API. Hence, no NMS updates will be necessary.

Also let me know if you want the NMS code refactored somewhere else. I saw the net.ess3.nms packages, but I wasn't sure where this would fit into the organisation of that.

Tested on:
1.8.8, 1.9.4, 1.10.2, 1.11.2 (NMS)
1.12.2, 1.15.2 (Bukkit API)
2020-08-05 20:47:42 +01:00
pop4959 68d0aa9688 Improve GeoIP errors/warnings (#3568)
Aims to provide a better and less confusing error for users of GeoIP who have not configured properly (which is more common now after the license key requirement). Seems like a lot of people miss the initial error on startup, and so this may help a bit.

Closes #3561.
2020-08-04 16:22:14 +01:00
MD 1ef4e15a4d Fix regression in /tpaccept (#3567)
d9bf099c3d introduced a regression where `/tpaccept` no longer unconditionally cancels the teleportation request when it is accepted. This restores the previous request cancellation behaviour.

Fixes #3563.
2020-08-04 16:20:24 +01:00
latiku d35b4b9128 Don't send chat messages if they only contain formatting codes (#3505)
Closes #3442.

When a player with the appropriate permission node to use color formatting codes sends a message with nothing but valid formatting code, a message with an empty line is sent. This PR solves this issue by checking if the final formatted message is just a color code, and if so, cancels the event.

Below are some attached screenshots with debug messages containing the event's raw message, the event message after it is formatted, and in the case of the "before" screenshot, the message sent in-game. 

Before: https://user-images.githubusercontent.com/47498808/87505823-7a8c5080-c62f-11ea-99b4-29fc6eaff042.png

After: https://user-images.githubusercontent.com/47498808/87505857-8c6df380-c62f-11ea-95f8-dd59dadaf27c.png
2020-08-04 15:38:53 +01:00
Zefferis 6995be7dbd Updated website in plugin.yml files (#3528)
Replaced "http://tiny.cc/EssentialsCommands" with "https://essentialsx.net"
2020-08-04 15:35:34 +01:00
uf0h f9de6763d3 Use playerNeverOnServer message where appropriate (#3489)
### Use `playerNeverOnServer` message where it should be used:

### https://github.com/EssentialsX/Essentials/pull/3489/commits/309e1c470d4bcfe2a2186f9720ce33f26441b802 
`playerNeverOnServer=\u00a74Player\u00a7c {0} \u00a74was never on this server.` is currently used in the **Commandmail** class at [Line 61](https://github.com/EssentialsX/Essentials/blob/2.x/Essentials/src/com/earth2me/essentials/commands/Commandmail.java#L61), [Line 116](https://github.com/EssentialsX/Essentials/blob/2.x/Essentials/src/com/earth2me/essentials/commands/Commandmail.java#L116) and [Line 129](https://github.com/EssentialsX/Essentials/blob/2.x/Essentials/src/com/earth2me/essentials/commands/Commandmail.java#L129) however is **not called** as PlayerNotFoundException is thrown by `#getPlayer` breaking current execution (below).
```
Commandmail#run() throws Exception {
...
    User u = getPlayer(server, args[1], true, true); // throws PlayerNotFoundException
        if (u == null) {
            throw new Exception(tl("playerNeverOnServer", args[1]));
    } 
...
}
```

Before changes:
![bm](https://user-images.githubusercontent.com/24858857/87236993-6b679180-c3e8-11ea-83a7-002194f5c467.png)
After changes:
![mailafter](https://user-images.githubusercontent.com/24858857/87237060-3576dd00-c3e9-11ea-8020-d5a80a958ca0.png)

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

**Commandseen** currently throws the default PlayerNotFoundException `playerNotFound` message for players that have not logged on to the server where it would be more appropriate to use the `playerNeverOnServer` message.

```
Commandseen#run throws Exception {
...
    AsyncRunnable#run() {
        User userFromBukkit = ess.getUserMap().getUserFromBukkit(args[0]);  <-- ***
        try {
            if (userFromBukkit != null) {                             <--- ***
                showUserSeen(userFromBukkit);
            } else {
                showUserSeen(getPlayer(server, sender, args, 0)); <--- ***
            }
        } catch (Exception e) {
            ess.showError(sender, e, commandLabel);
        }
    }
    private void showUserSeen(User user) throws Exception {
        if (user == null) {                                    <--- ***
            throw new PlayerNotFoundException();
        }
        showSeenMessage(server, sender, user, showBan, showIp, showLocation);
    }
...
}
```

**`<-- ***`:**
`usersFromBukkit` null check is performed before `#showUserSeen` so there is no need for another null check.
`EssentialsCommand#getPlayer` throws **NotEnoughArguementsException** or **PlayerNotFoundException** after [arg checks](https://github.com/EssentialsX/Essentials/blob/2.x/Essentials/src/com/earth2me/essentials/commands/EssentialsCommand.java#L88) and [player checks](https://github.com/EssentialsX/Essentials/blob/2.x/Essentials/src/com/earth2me/essentials/commands/EssentialsCommand.java#L103). https://github.com/EssentialsX/Essentials/pull/3489#issuecomment-657138524

Before changes:
![sb](https://user-images.githubusercontent.com/24858857/87237038-e9c43380-c3e8-11ea-8294-8f91e8b6f25d.png)
After changes:
![seenafter](https://user-images.githubusercontent.com/24858857/87237067-53444200-c3e9-11ea-92c5-1784b4dcd739.png)

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

### 725128e
Catch more specfic exception `PlayerNotFoundException`.

Before changes:
![banbefore](https://user-images.githubusercontent.com/24858857/87237021-c1d4d000-c3e8-11ea-99e4-eb97b5a5ba6d.png)
After changes:
![afterunban](https://user-images.githubusercontent.com/24858857/87237081-8d154880-c3e9-11ea-9d35-a25b8c105969.png)
2020-08-04 15:30:05 +01:00
pop4959 dfce971565 Fix stale tpaccept 2020-08-04 02:37:37 -07:00
Olivia 97e3f32d7f Fix some minor errors in config/docs (#3566) 2020-08-04 01:13:09 -07:00
Cameron Seid c86e1a5973 Update backup comments in config.yml to be less ambiguous (#3553) 2020-07-30 21:58:19 -07:00
md678685 ab545dc44c Fix rare ConcurrentModificationException in quit handler
Copies the list of viewers before iterating over it to fix a rare CME that is *sometimes* thrown. It's not clear *why* this broke - Spigot seems to have changed behaviour in late 1.15 or 1.16?
2020-07-30 14:23:22 +01:00
Josh Roy 11cd57e8fb Add sign text tab completion in editsign command (#3497) 2020-07-28 13:12:07 -07:00
pop4959 b7c18d0785 Add missing getRecipe(NamespacedKey) method to FakeServer (#3530) 2020-07-22 12:02:00 -07:00
Josh Roy 9aec89f381 Properly handle jail respawn in togglejail (#3522) 2020-07-21 16:22:20 -07:00
Josh Roy e34984513d Add config option to respawn at respawn anchors (#3498) 2020-07-17 14:13:30 -07:00
Tim S cedd42f411 Fix how random teleport picks a location (#3480) 2020-07-17 13:56:48 -07:00
untuned c9b75aabb2 include new sign types in definitions (#3487) 2020-07-11 15:21:33 -07:00
pop4959 41ae12ed3d Disable random tp pre-cache by default (#3496) 2020-07-11 12:35:19 -07:00
JakeTS dba35f043d Typo, should be "match" not "maths". (#3488) 2020-07-10 21:10:12 -07:00
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
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
rye761 785b1fe937 Make drop-items-if-full work on Essentials kits 2019-10-13 17:00:11 -04:00
363 changed files with 45767 additions and 31617 deletions

No files matched your search

-3
View File
@@ -28,9 +28,6 @@ jobs:
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Run BuildTools
if: steps.cache.outputs.cache-hit != 'true'
run: chmod +x scripts/buildtools.sh && ./scripts/buildtools.sh
- name: Build with Maven
run: mvn package --file pom.xml
- name: Copy artifacts
+2 -1
View File
@@ -15,4 +15,5 @@
# Build files
target/
jars/
jars/
out/
+34 -34
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>net.ess3</groupId>
<artifactId>EssentialsXParent</artifactId>
<version>2.17.2</version>
<version>2.18.1</version>
</parent>
<artifactId>EssentialsX</artifactId>
@@ -52,66 +52,66 @@
<groupId>com.github.milkbowl</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.7</version>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.luckperms</groupId>
<artifactId>api</artifactId>
<version>5.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.papermc</groupId>
<artifactId>paperlib</artifactId>
<version>1.0.2</version>
<version>1.0.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>NMSProvider</artifactId>
<version>2.17.2</version>
<artifactId>BaseProviders</artifactId>
<version>2.18.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>UpdatedMetaProvider</artifactId>
<version>2.17.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>1_8_R1Provider</artifactId>
<version>2.17.2</version>
<scope>compile</scope>
<artifactId>NMSReflectionProvider</artifactId>
<version>2.18.1</version>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<artifactId>bukkit</artifactId>
</exclusion>
</exclusions>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>1_8_R2Provider</artifactId>
<version>2.17.2</version>
<artifactId>PaperProvider</artifactId>
<version>2.18.1</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.1</version>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<artifactId>bukkit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>LegacyProvider</artifactId>
<version>2.17.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>ReflectionProvider</artifactId>
<version>2.17.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>FlattenedProvider</artifactId>
<version>2.17.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
+3 -3
View File
@@ -13,6 +13,6 @@ Minecraft colors:
&8 &&8 &9 &&9 &a &&a &b &&b
&c &&c &d &&d &e &&e &f &&f
&0
&&k &kMagic&r &&l &lBold
&&m &mStrike&r &&n &nUline
&&o &oItalic&r &&r &rReset
&&k &kMagic&r &&l &lBold&r
&&m &mStrike&r &&n &nUline&r
&&o &oItalic&r &&r &rReset
@@ -46,15 +46,12 @@ public class AlternativeCommandsHandler {
continue;
}
for (String label : labels) {
List<PluginCommand> plugincommands = altcommands.get(label.toLowerCase(Locale.ENGLISH));
if (plugincommands == null) {
plugincommands = new ArrayList<>();
altcommands.put(label.toLowerCase(Locale.ENGLISH), plugincommands);
}
List<PluginCommand> plugincommands = altcommands.computeIfAbsent(label.toLowerCase(Locale.ENGLISH), k -> new ArrayList<>());
boolean found = false;
for (PluginCommand pc2 : plugincommands) {
if (pc2.getPlugin().equals(plugin)) {
found = true;
break;
}
}
if (!found) {
@@ -68,13 +65,7 @@ public class AlternativeCommandsHandler {
final Iterator<Map.Entry<String, List<PluginCommand>>> iterator = altcommands.entrySet().iterator();
while (iterator.hasNext()) {
final Map.Entry<String, List<PluginCommand>> entry = iterator.next();
final Iterator<PluginCommand> pcIterator = entry.getValue().iterator();
while (pcIterator.hasNext()) {
final PluginCommand pc = pcIterator.next();
if (pc.getPlugin() == null || pc.getPlugin().equals(plugin)) {
pcIterator.remove();
}
}
entry.getValue().removeIf(pc -> pc.getPlugin() == null || pc.getPlugin().equals(plugin));
if (entry.getValue().isEmpty()) {
iterator.remove();
}
@@ -0,0 +1,457 @@
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();
final Location targetLoc = target.getLocation();
if (ess.getSettings().isTeleportSafetyEnabled() && LocationUtil.isBlockOutsideWorldBorder(targetLoc.getWorld(), targetLoc.getBlockX(), targetLoc.getBlockZ())) {
targetLoc.setX(LocationUtil.getXInsideWorldBorder(targetLoc.getWorld(), targetLoc.getBlockX()));
targetLoc.setZ(LocationUtil.getZInsideWorldBorder(targetLoc.getWorld(), targetLoc.getBlockZ()));
}
PaperLib.getChunkAtAsync(targetLoc).thenAccept(chunk -> {
Location loc = targetLoc;
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,11 +22,13 @@ 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()) {
if (!ess.getOnlinePlayers().isEmpty() || ess.getSettings().isAlwaysRunBackup()) {
ess.runTaskAsynchronously(this::startTask);
}
}
@@ -52,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"));
@@ -73,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());
}
}
@@ -22,8 +22,15 @@ public class CommandSource {
return null;
}
public final net.ess3.api.IUser getUser(IEssentials ess) {
if (sender instanceof Player) {
return ess.getUser((Player) sender);
}
return null;
}
public final boolean isPlayer() {
return (sender instanceof Player);
return sender instanceof Player;
}
public final CommandSender setSender(final CommandSender base) {
@@ -36,4 +43,12 @@ public class CommandSource {
sender.sendMessage(message);
}
}
public boolean isAuthorized(String permission, IEssentials ess) {
return !(sender instanceof Player) || getUser(ess).isAuthorized(permission);
}
public String getSelfSelector() {
return sender instanceof Player ? getPlayer().getName() : "*";
}
}
@@ -11,8 +11,8 @@ import java.util.Set;
public class Enchantments {
private static final Map<String, Enchantment> ENCHANTMENTS = new HashMap<String, Enchantment>();
private static final Map<String, Enchantment> ALIASENCHANTMENTS = new HashMap<String, Enchantment>();
private static final Map<String, Enchantment> ENCHANTMENTS = new HashMap<>();
private static final Map<String, Enchantment> ALIASENCHANTMENTS = new HashMap<>();
private static boolean isFlat;
static {
@@ -251,6 +251,15 @@ public class Enchantments {
}
} catch (IllegalArgumentException ignored) {}
try { // 1.16
Enchantment soulspeed = Enchantment.getByName("SOUL_SPEED");
if (soulspeed != null) {
ENCHANTMENTS.put("soulspeed", soulspeed);
ALIASENCHANTMENTS.put("soilspeed", soulspeed);
ALIASENCHANTMENTS.put("sandspeed", soulspeed);
}
} catch (IllegalArgumentException ignored) {}
try {
Class<?> namespacedKeyClass = Class.forName("org.bukkit.NamespacedKey");
Class<?> enchantmentClass = Class.forName("org.bukkit.enchantments.Enchantment");
@@ -22,7 +22,7 @@ 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;
@@ -33,41 +33,32 @@ 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.Throwables;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import io.papermc.lib.PaperLib;
import net.ess3.api.IEssentials;
import net.ess3.api.ISettings;
import net.ess3.api.*;
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.nms.refl.providers.ReflServerStateProvider;
import net.ess3.nms.refl.providers.ReflSpawnEggProvider;
import net.ess3.nms.refl.providers.ReflSpawnerBlockProvider;
import net.ess3.provider.PotionMetaProvider;
import net.ess3.provider.ProviderListener;
import net.ess3.provider.ServerStateProvider;
import net.ess3.provider.SpawnEggProvider;
import net.ess3.provider.SpawnerBlockProvider;
import net.ess3.provider.SpawnerItemProvider;
import net.ess3.provider.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;
@@ -83,6 +74,13 @@ import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import org.yaml.snakeyaml.error.YAMLException;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.earth2me.essentials.I18n.tl;
@@ -103,31 +101,30 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
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 SpawnerItemProvider spawnerItemProvider;
private transient SpawnerBlockProvider spawnerBlockProvider;
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 +142,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 +166,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()) {
@@ -183,15 +180,6 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
}
for (Method method : Server.class.getDeclaredMethods()) {
if (method.getName().endsWith("getOnlinePlayers") && method.getReturnType() == Player[].class) {
oldGetOnlinePlayers = method;
break;
}
}
forceLoadClasses();
try {
final EssentialsUpgrade upgrade = new EssentialsUpgrade(this);
upgrade.beforeSettings();
@@ -226,6 +214,13 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
confList.add(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);
@@ -240,24 +235,51 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
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 item provider only uses one but it's here for legacy...
spawnerItemProvider = new BlockMetaSpawnerItemProvider();
//Spawner block providers
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_12_0_R01)) {
spawnerBlockProvider = new ReflSpawnerBlockProvider();
} else {
spawnerBlockProvider = new BukkitSpawnerBlockProvider();
}
//Spawn Egg Providers
if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_8_8_R01)) {
spawnEggProvider = new LegacySpawnEggProvider();
} else if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_12_2_R01)) {
spawnEggProvider = new ReflSpawnEggProvider();
} else {
spawnEggProvider = new FlatSpawnEggProvider();
}
//Potion Meta Provider
if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_8_8_R01)) {
potionMetaProvider = new LegacyPotionMetaProvider();
} else {
potionMetaProvider = new BasePotionDataProvider();
}
//Server State Provider
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();
@@ -277,6 +299,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);
@@ -286,12 +311,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()) {
@@ -303,6 +323,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
handleCrash(ex);
throw ex;
}
getBackup().setPendingShutdown(false);
}
@Override
@@ -347,25 +368,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();
@@ -383,6 +428,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);
@@ -391,7 +443,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
@@ -467,6 +519,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);
}
@@ -521,6 +574,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;
}
@@ -559,9 +613,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());
@@ -569,6 +621,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
if (!ex.getMessage().isEmpty()) {
sender.sendMessage(ex.getMessage());
}
if (ex.getCause() != null && settings.isDebug()) {
ex.getCause().printStackTrace();
}
return true;
} catch (Exception ex) {
showError(sender, ex, commandLabel);
@@ -637,13 +692,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
@@ -756,20 +806,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;
}
@@ -777,10 +832,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);
}
@@ -870,27 +927,26 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
@Override
public Collection<Player> getOnlinePlayers() {
try {
return (Collection<Player>) getServer().getOnlinePlayers(); // Needed for sanity here, the Bukkit API is a bit broken in the sense it only allows subclasses of Player to this list
} catch (NoSuchMethodError ex) {
try {
return Arrays.asList((Player[]) oldGetOnlinePlayers.invoke(getServer()));
} catch (InvocationTargetException ex1) {
throw Throwables.propagate(ex.getCause());
} catch (IllegalAccessException ex1) {
throw new RuntimeException("Error invoking oldGetOnlinePlayers", ex1);
}
return (Collection<Player>) getServer().getOnlinePlayers();
}
@Override
public List<User> getOnlineUsers() {
List<User> onlineUsers = new ArrayList<>();
for (Player player : getOnlinePlayers()) {
onlineUsers.add(getUser(player));
}
return onlineUsers;
}
@Override
public Iterable<User> getOnlineUsers() {
return getOnlinePlayers().stream().map(this::getUser).collect(Collectors.toList());
public SpawnerItemProvider getSpawnerItemProvider() {
return spawnerItemProvider;
}
@Override
public SpawnerProvider getSpawnerProvider() {
return spawnerProvider;
public SpawnerBlockProvider getSpawnerBlockProvider() {
return spawnerBlockProvider;
}
@Override
@@ -908,6 +964,11 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
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;
@@ -39,7 +37,7 @@ public class EssentialsBlockListener implements Listener {
final BlockState blockState = event.getBlockPlaced().getState();
if (blockState instanceof CreatureSpawner) {
final CreatureSpawner spawner = (CreatureSpawner) blockState;
final EntityType type = ess.getSpawnerProvider().getEntityType(event.getItemInHand());
final EntityType type = ess.getSpawnerItemProvider().getEntityType(event.getItemInHand());
if (type != null && Mob.fromBukkitType(type) != null) {
if (ess.getUser(event.getPlayer()).isAuthorized("essentials.spawnerconvert." + Mob.fromBukkitType(type).name().toLowerCase(Locale.ENGLISH))) {
spawner.setSpawnedType(type);
@@ -1,16 +1,17 @@
package com.earth2me.essentials;
import static com.earth2me.essentials.I18n.tl;
import com.google.common.io.Files;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import net.ess3.api.InvalidWorldException;
import org.bukkit.OfflinePlayer;
import org.bukkit.*;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import java.io.*;
import java.math.BigDecimal;
import java.math.MathContext;
import java.nio.Buffer;
@@ -19,13 +20,8 @@ import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -34,25 +30,15 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.ess3.api.InvalidWorldException;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import static com.earth2me.essentials.I18n.tl;
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);
@@ -454,9 +440,7 @@ public class EssentialsConf extends YamlConfiguration {
} else {
try {
return new BigDecimal(input, MathContext.DECIMAL128);
} catch (NumberFormatException e) {
return def;
} catch (ArithmeticException e) {
} catch (NumberFormatException | ArithmeticException e) {
return def;
}
}
@@ -1,7 +1,10 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.api.IEssentials;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -127,7 +130,11 @@ public class EssentialsEntityListener implements Listener {
if (event.getCombuster() instanceof Arrow && event.getEntity() instanceof Player) {
Arrow combuster = (Arrow) event.getCombuster();
if (combuster.getShooter() instanceof Player) {
final User srcCombuster = ess.getUser(((Player) combuster.getShooter()).getUniqueId());
Player shooter = (Player) combuster.getShooter();
if (shooter.hasMetadata("NPC")) {
return;
}
final User srcCombuster = ess.getUser(shooter.getUniqueId());
if (srcCombuster.isGodModeEnabled() && !srcCombuster.isAuthorized("essentials.god.pvp")) {
event.setCancelled(true);
}
@@ -140,7 +147,15 @@ public class EssentialsEntityListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerDeathEvent(final PlayerDeathEvent event) {
Entity entity = event.getEntity();
if (entity.hasMetadata("NPC")) {
return;
}
final User user = ess.getUser(event.getEntity());
if (ess.getSettings().infoAfterDeath()) {
final Location loc = user.getLocation();
user.sendMessage(tl("infoAfterDeath", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
}
if (user.isAuthorized("essentials.back.ondeath") && !ess.getSettings().isCommandDisabled("back")) {
user.setLastLocation();
user.sendMessage(tl("backAfterDeath"));
@@ -165,6 +180,57 @@ public class EssentialsEntityListener implements Listener {
if (user.isAuthorized("essentials.keepinv")) {
event.setKeepInventory(true);
event.getDrops().clear();
ISettings.KeepInvPolicy vanish = ess.getSettings().getVanishingItemsPolicy();
ISettings.KeepInvPolicy bind = ess.getSettings().getBindingItemsPolicy();
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_11_2_R01) && (vanish != ISettings.KeepInvPolicy.KEEP || bind != ISettings.KeepInvPolicy.KEEP)) {
for (ItemStack stack : event.getEntity().getInventory()) {
if (stack != null) {
if (stack.getEnchantments().containsKey(Enchantment.VANISHING_CURSE)) {
if (vanish == ISettings.KeepInvPolicy.DELETE) {
event.getEntity().getInventory().remove(stack);
} else if (vanish == ISettings.KeepInvPolicy.DROP) {
event.getDrops().add(stack);
event.getEntity().getInventory().remove(stack);
}
}
if (stack.getEnchantments().containsKey(Enchantment.BINDING_CURSE)) {
if (bind == ISettings.KeepInvPolicy.DELETE) {
event.getEntity().getInventory().remove(stack);
} else if (bind == ISettings.KeepInvPolicy.DROP) {
event.getEntity().getInventory().remove(stack);
event.getDrops().add(stack);
}
}
}
}
ItemStack[] armor = event.getEntity().getInventory().getArmorContents();
for (int i = 0; i < armor.length; i++) {
ItemStack stack = armor[i];
if (stack != null) {
if (stack.getEnchantments().containsKey(Enchantment.VANISHING_CURSE)) {
if (vanish == ISettings.KeepInvPolicy.DELETE) {
armor[i] = null;
} else if (vanish == ISettings.KeepInvPolicy.DROP) {
if (!event.getDrops().contains(stack)) {
event.getDrops().add(stack);
}
armor[i] = null;
}
}
if (stack.getEnchantments().containsKey(Enchantment.BINDING_CURSE)) {
if (bind == ISettings.KeepInvPolicy.DELETE) {
armor[i] = null;
} else if (bind == ISettings.KeepInvPolicy.DROP) {
if (!event.getDrops().contains(stack)) {
event.getDrops().add(stack);
}
armor[i] = null;
}
}
}
}
event.getEntity().getInventory().setArmorContents(armor);
}
}
}
@@ -1,5 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.commands.Commandfireball;
import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.TextInput;
@@ -10,6 +11,7 @@ import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.VersionUtil;
import io.papermc.lib.PaperLib;
import net.ess3.api.IEssentials;
import net.ess3.api.events.AfkStatusChangeEvent;
import org.bukkit.*;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.HumanEntity;
@@ -30,6 +32,7 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.text.NumberFormat;
import java.util.*;
import java.util.Map.Entry;
@@ -66,9 +69,22 @@ public class EssentialsPlayerListener implements Listener {
}
}
private static boolean isArrowPickupEvent() {
try {
Class.forName("org.bukkit.event.player.PlayerPickupArrowEvent");
return true;
} catch (ClassNotFoundException ignored) {
return false;
}
}
public void registerEvents() {
ess.getServer().getPluginManager().registerEvents(this, ess);
if (isArrowPickupEvent()) {
ess.getServer().getPluginManager().registerEvents(new ArrowPickupListener(), ess);
}
if (isEntityPickupEvent()) {
ess.getServer().getPluginManager().registerEvents(new PickupListener1_12(), ess);
} else {
@@ -97,7 +113,12 @@ public class EssentialsPlayerListener implements Listener {
if (user.isMuted()) {
event.setCancelled(true);
user.sendMessage(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
user.sendMessage(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
} else {
user.sendMessage(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
}
LOGGER.info(tl("mutedUserSpeaks", user.getName(), event.getMessage()));
}
@@ -166,14 +187,15 @@ 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);
}
@@ -190,7 +212,8 @@ public class EssentialsPlayerListener implements Listener {
user.getBase().getOpenInventory().getTopInventory().clear();
}
for (HumanEntity viewer : user.getBase().getInventory().getViewers()) {
ArrayList<HumanEntity> viewers = new ArrayList<>(user.getBase().getInventory().getViewers());
for (HumanEntity viewer : viewers) {
if (viewer instanceof Player) {
User uviewer = ess.getUser((Player) viewer);
if (uviewer.isInvSee()) {
@@ -199,7 +222,7 @@ public class EssentialsPlayerListener implements Listener {
}
}
user.updateActivity(false);
user.updateActivity(false, AfkStatusChangeEvent.Cause.QUIT);
if (!user.isHidden()) {
user.setLastLogout(System.currentTimeMillis());
}
@@ -213,11 +236,15 @@ public class EssentialsPlayerListener implements Listener {
final String joinMessage = event.getJoinMessage();
ess.runTaskAsynchronously(() -> delayedJoin(event.getPlayer(), joinMessage));
if (ess.getSettings().allowSilentJoinQuit() || ess.getSettings().isCustomJoinMessage()) {
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;
@@ -233,7 +260,7 @@ public class EssentialsPlayerListener implements Listener {
final long currentTime = System.currentTimeMillis();
dUser.checkMuteTimeout(currentTime);
dUser.updateActivity(false);
dUser.updateActivity(false, AfkStatusChangeEvent.Cause.JOIN);
dUser.stopTransaction();
class DelayJoinTask implements Runnable {
@@ -272,13 +299,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("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size()))
.replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()));
if (!msg.isEmpty()) {
ess.getServer().broadcastMessage(msg);
}
@@ -338,7 +366,7 @@ public class EssentialsPlayerListener implements Listener {
}
class DelayMotdTask implements Runnable {
private User user;
private final User user;
public DelayMotdTask(User user) {
this.user = user;
@@ -381,11 +409,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)
@@ -434,9 +465,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)) {
@@ -489,9 +524,15 @@ 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;
}
@@ -508,7 +549,7 @@ public class EssentialsPlayerListener implements Listener {
broadcast = false;
}
}
final User user = ess.getUser(player);
if (update) {
user.updateActivityOnInteract(broadcast);
}
@@ -559,27 +600,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());
}
}
}
}
@@ -683,7 +728,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));
@@ -720,7 +764,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);
@@ -742,7 +786,7 @@ 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();
}
@@ -760,8 +804,7 @@ public class EssentialsPlayerListener implements Listener {
}
if (refreshPlayer != null) {
final Player player = refreshPlayer;
ess.scheduleSyncDelayedTask(player::updateInventory, 1);
ess.scheduleSyncDelayedTask(refreshPlayer::updateInventory, 1);
}
}
@@ -787,7 +830,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();
@@ -795,8 +838,7 @@ public class EssentialsPlayerListener implements Listener {
}
if (refreshPlayer != null) {
final Player player = refreshPlayer;
ess.scheduleSyncDelayedTask(player::updateInventory, 1);
ess.scheduleSyncDelayedTask(refreshPlayer::updateInventory, 1);
}
}
@@ -806,10 +848,21 @@ public class EssentialsPlayerListener implements Listener {
user.updateActivityOnInteract(true);
}
private final class ArrowPickupListener implements Listener {
@EventHandler(priority = EventPriority.LOW)
public void onArrowPickup(final org.bukkit.event.player.PlayerPickupArrowEvent event) {
if (event.getItem().hasMetadata(Commandfireball.FIREBALL_META_KEY)) {
event.setCancelled(true);
}
}
}
private final class PickupListenerPre1_12 implements Listener {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerPickupItem(final org.bukkit.event.player.PlayerPickupItemEvent event) {
if (ess.getSettings().getDisableItemPickupWhileAfk()) {
if (event.getItem().hasMetadata(Commandfireball.FIREBALL_META_KEY)) {
event.setCancelled(true);
} else if (ess.getSettings().getDisableItemPickupWhileAfk()) {
if (ess.getUser(event.getPlayer()).isAfk()) {
event.setCancelled(true);
}
@@ -858,14 +911,14 @@ public class EssentialsPlayerListener implements Listener {
/**
* Returns true if all of the following are true:
* - The command is a plugin command
* - The plugin command is from Essentials
* - 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() == ess || command.getPlugin().getClass().getName().startsWith("com.earth2me.essentials"))
&& (ess.getSettings().isCommandOverridden(label) || (ess.getAlternativeCommandsHandler().getAlternative(label) == null));
}
}
@@ -36,6 +36,7 @@ public class EssentialsPluginListener implements Listener, IConf {
if (event.getPlugin().getName().equals("EssentialsChat")) {
ess.getSettings().setEssentialsChatActive(false);
}
ess.getPermissionsHandler().checkPermissions();
ess.getAlternativeCommandsHandler().removePlugin(event.getPlugin());
// Check to see if the plugin thats being disabled is the one we are using
if (ess.getPaymentMethod() != null && Methods.hasMethod() && Methods.checkDisabled(event.getPlugin())) {
@@ -17,15 +17,16 @@ import java.util.logging.Level;
public class EssentialsServerListener implements Listener {
private static List<String> ignoredSLPECallers = Arrays.asList(
private static final List<String> ignoredSLPECallers = Arrays.asList(
".LegacyPingHandler.channelRead(", // CB responding to pings from pre-Netty clients
"de.dytanic.cloudnet.bridge.BukkitBootstrap" // CloudNet v2 doing... something
"de.dytanic.cloudnet.bridge.BukkitBootstrap", // CloudNet v2 doing... something
"de.dytanic.cloudnet.ext.bridge.bukkit.BukkitCloudNetBridgePlugin" // CloudNet v3 doing... something else
);
private final transient IEssentials ess;
private boolean unsupportedLogged = false;
private boolean npeWarned = false;
private boolean isPaperSample;
private final boolean isPaperSample;
private Method setSampleText;
private Method getSampleText;
@@ -42,6 +42,56 @@ public class EssentialsUpgrade {
doneFile.load();
}
public void convertIgnoreList() {
Pattern pattern = Pattern.compile("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$");
if (doneFile.getBoolean("updateUsersIgnoreListUUID", false)) {
return;
}
LOGGER.info("Attempting to migrate ignore list to UUIDs");
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
if (!userdataFolder.exists() || !userdataFolder.isDirectory()) {
return;
}
final File[] userFiles = userdataFolder.listFiles();
for (File file : userFiles) {
if (!file.isFile() || !file.getName().endsWith(".yml")) {
continue;
}
final EssentialsConf config = new EssentialsConf(file);
try {
config.load();
if (config.hasProperty("ignore")) {
List<String> migratedIgnores = new ArrayList<>();
for (String name : Collections.synchronizedList(config.getStringList("ignore"))) {
if (name == null) {
continue;
}
if (pattern.matcher(name.trim()).matches()) {
LOGGER.info("Detected already migrated ignore list!");
return;
}
User user = ess.getOfflineUser(name);
if (user != null && user.getBase() != null) {
migratedIgnores.add(user.getBase().getUniqueId().toString());
}
}
config.removeProperty("ignore");
config.setProperty("ignore", migratedIgnores);
config.forceSave();
}
} catch (RuntimeException ex) {
LOGGER.log(Level.INFO, "File: " + file.toString());
throw ex;
}
}
doneFile.setProperty("updateUsersIgnoreListUUID", true);
doneFile.save();
LOGGER.info("Done converting ignore list.");
}
public void convertKits() {
Kits kits = ess.getKits();
EssentialsConf config = kits.getConfig();
@@ -163,7 +213,7 @@ public class EssentialsUpgrade {
try {
config.load();
if (config.hasProperty("powertools")) {
@SuppressWarnings("unchecked") final Map<String, Object> powertools = config.getConfigurationSection("powertools").getValues(false);
final Map<String, Object> powertools = config.getConfigurationSection("powertools").getValues(false);
if (powertools == null) {
continue;
}
@@ -204,7 +254,7 @@ public class EssentialsUpgrade {
config.load();
if (config.hasProperty("home") && config.hasProperty("home.default")) {
@SuppressWarnings("unchecked") final String defworld = (String) config.getProperty("home.default");
final String defworld = (String) config.getProperty("home.default");
final Location defloc = getFakeLocation(config, "home.worlds." + defworld);
if (defloc != null) {
config.setProperty("homes.home", defloc);
@@ -575,7 +625,7 @@ public class EssentialsUpgrade {
conf.load();
String banReason;
Long banTimeout;
long banTimeout;
try {
banReason = conf.getConfigurationSection("ban").getString("reason");
@@ -616,12 +666,7 @@ public class EssentialsUpgrade {
}
}
private static final FileFilter YML_FILTER = new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isFile() && pathname.getName().endsWith(".yml");
}
};
private static final FileFilter YML_FILTER = pathname -> pathname.isFile() && pathname.getName().endsWith(".yml");
private static final String PATTERN_CONFIG_UUID_REGEX = "(?mi)^uuid:\\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\s*$";
private static final Pattern PATTERN_CONFIG_UUID = Pattern.compile(PATTERN_CONFIG_UUID_REGEX);
@@ -718,5 +763,6 @@ public class EssentialsUpgrade {
banFormatChange();
warnMetrics();
repairUserMap();
convertIgnoreList();
}
}
@@ -13,7 +13,7 @@ public class ExecuteTimer {
public ExecuteTimer() {
times = new ArrayList<ExecuteRecord>();
times = new ArrayList<>();
}
public void start() {
@@ -2,12 +2,11 @@ package com.earth2me.essentials;
import net.ess3.api.IEssentials;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.*;
import java.util.logging.Level;
@@ -23,7 +22,7 @@ public class I18n implements net.ess3.api.II18n {
private transient ResourceBundle customBundle;
private transient ResourceBundle localeBundle;
private final transient ResourceBundle defaultBundle;
private transient Map<String, MessageFormat> messageFormatCache = new HashMap<String, MessageFormat>();
private transient Map<String, MessageFormat> messageFormatCache = new HashMap<>();
private final transient IEssentials ess;
private static final Pattern NODOUBLEMARK = Pattern.compile("''");
private static final ResourceBundle NULL_BUNDLE = new ResourceBundle() {
@@ -38,7 +37,7 @@ public class I18n implements net.ess3.api.II18n {
public I18n(final IEssentials ess) {
this.ess = ess;
defaultBundle = ResourceBundle.getBundle(MESSAGES, Locale.ENGLISH);
defaultBundle = ResourceBundle.getBundle(MESSAGES, Locale.ENGLISH, new UTF8PropertiesControl());
localeBundle = defaultBundle;
customBundle = NULL_BUNDLE;
}
@@ -110,17 +109,17 @@ public class I18n implements net.ess3.api.II18n {
}
}
ResourceBundle.clearCache();
messageFormatCache = new HashMap<String, MessageFormat>();
messageFormatCache = new HashMap<>();
Logger.getLogger("Essentials").log(Level.INFO, String.format("Using locale %s", currentLocale.toString()));
try {
localeBundle = ResourceBundle.getBundle(MESSAGES, currentLocale);
localeBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new UTF8PropertiesControl());
} catch (MissingResourceException ex) {
localeBundle = NULL_BUNDLE;
}
try {
customBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new FileResClassLoader(I18n.class.getClassLoader(), ess));
customBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new FileResClassLoader(I18n.class.getClassLoader(), ess), new UTF8PropertiesControl());
} catch (MissingResourceException ex) {
customBundle = NULL_BUNDLE;
}
@@ -130,7 +129,9 @@ public class I18n implements net.ess3.api.II18n {
return input == null || input.length() == 0 ? input : input.toUpperCase(Locale.ENGLISH).charAt(0) + input.toLowerCase(Locale.ENGLISH).substring(1);
}
/**
* Attempts to load properties files from the plugin directory before falling back to the jar.
*/
private static class FileResClassLoader extends ClassLoader {
private final transient File dataFolder;
@@ -145,8 +146,7 @@ public class I18n implements net.ess3.api.II18n {
if (file.exists()) {
try {
return file.toURI().toURL();
} catch (MalformedURLException ex) {
}
} catch (MalformedURLException ignored) {}
}
return null;
}
@@ -157,10 +157,42 @@ public class I18n implements net.ess3.api.II18n {
if (file.exists()) {
try {
return new FileInputStream(file);
} catch (FileNotFoundException ex) {
}
} catch (FileNotFoundException ignored) {}
}
return null;
}
}
/**
* Reads .properties files as UTF-8 instead of ISO-8859-1, which is the default on Java 8/below.
* Java 9 fixes this by defaulting to UTF-8 for .properties files.
*/
private static class UTF8PropertiesControl extends ResourceBundle.Control {
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IOException {
String resourceName = toResourceName(toBundleName(baseName, locale), "properties");
ResourceBundle bundle = null;
InputStream stream = null;
if (reload) {
URL url = loader.getResource(resourceName);
if (url != null) {
URLConnection connection = url.openConnection();
if (connection != null) {
connection.setUseCaches(false);
stream = connection.getInputStream();
}
}
} else {
stream = loader.getResourceAsStream(resourceName);
}
if (stream != null) {
try {
// use UTF-8 here, this is the important bit
bundle = new PropertyResourceBundle(new InputStreamReader(stream, StandardCharsets.UTF_8));
} finally {
stream.close();
}
}
return bundle;
}
}
}
@@ -3,10 +3,11 @@ 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.SpawnerBlockProvider;
import net.ess3.provider.SpawnerItemProvider;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
@@ -18,6 +19,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 +49,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 +67,8 @@ public interface IEssentials extends Plugin {
Kits getKits();
RandomTeleport getRandomTeleport();
Methods getPaymentMethod();
BukkitTask runTaskAsynchronously(Runnable run);
@@ -89,10 +95,6 @@ public interface IEssentials extends Plugin {
UserMap getUserMap();
Metrics getMetrics();
void setMetrics(Metrics metrics);
EssentialsTimer getTimer();
@Deprecated
@@ -100,7 +102,11 @@ public interface IEssentials extends Plugin {
Collection<Player> getOnlinePlayers();
Iterable<User> getOnlineUsers();
Collection<User> getOnlineUsers();
SpawnerProvider getSpawnerProvider();
SpawnerItemProvider getSpawnerItemProvider();
SpawnerBlockProvider getSpawnerBlockProvider();
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;
@@ -32,6 +30,8 @@ public interface ISettings extends IConf {
long getBackupInterval();
boolean isAlwaysRunBackup();
String getChatFormat(String group);
int getChatRadius();
@@ -48,6 +48,8 @@ public interface ISettings extends IConf {
String getCurrencySymbol();
boolean isCurrencySymbolSuffixed();
int getOversizedStackSize();
int getDefaultStackSize();
@@ -89,7 +91,7 @@ public interface ISettings extends IConf {
String getNicknamePrefix();
ChatColor getOperatorColor() throws Exception;
String getOperatorColor() throws Exception;
boolean getPerWarpPermission();
@@ -105,6 +107,8 @@ public interface ISettings extends IConf {
boolean getRespawnAtHome();
boolean isRespawnAtAnchor();
Set getMultipleHomes();
int getHomeLimit(String set);
@@ -119,6 +123,12 @@ public interface ISettings extends IConf {
boolean isForceDisableTeleportSafety();
boolean isAlwaysTeleportSafety();
boolean isTeleportPassengerDismount();
boolean isForcePassengerTeleport();
double getTeleportCooldown();
double getTeleportDelay();
@@ -160,6 +170,8 @@ public interface ISettings extends IConf {
boolean isEcoLogUpdateEnabled();
boolean realNamesOnList();
boolean removeGodOnDisconnect();
boolean changeDisplayName();
@@ -192,8 +204,24 @@ public interface ISettings extends IConf {
String getAfkListName();
boolean broadcastAfkMessage();
boolean areDeathMessagesEnabled();
KeepInvPolicy getVanishingItemsPolicy();
KeepInvPolicy getBindingItemsPolicy();
int getJoinQuitMessagePlayerCount();
boolean hasJoinQuitMessagePlayerCount();
enum KeepInvPolicy {
KEEP,
DELETE,
DROP
}
void setDebug(boolean debug);
Set<String> getNoGodWorlds();
@@ -238,6 +266,8 @@ public interface ISettings extends IConf {
void setEssentialsChatActive(boolean b);
long getMaxMute();
long getMaxTempban();
Map<String, Object> getListGroupConfig();
@@ -268,6 +298,8 @@ public interface ISettings extends IConf {
BigDecimal getMinimumPayAmount();
boolean isPayExcludesIgnoreList();
long getLastMessageReplyRecipientTimeout();
boolean isMilkBucketEasterEggEnabled();
@@ -286,6 +318,10 @@ public interface ISettings extends IConf {
boolean isCommandCooldownsEnabled();
boolean isWorldChangeFlyResetEnabled();
boolean isWorldChangeSpeedResetEnabled();
long getCommandCooldownMs(String label);
Entry<Pattern, Long> getCommandCooldownEntry(String label);
@@ -302,6 +338,8 @@ public interface ISettings extends IConf {
boolean isAllowBulkBuySell();
boolean isAllowSellNamedItems();
boolean isAddingPrefixInPlayerlist();
boolean isAddingSuffixInPlayerlist();
@@ -324,8 +362,6 @@ public interface ISettings extends IConf {
String getItemDbType();
boolean isForceEnableRecipe();
boolean allowOldIdSigns();
boolean isWaterSafe();
@@ -338,5 +374,12 @@ public interface ISettings extends IConf {
double getMaxProjectileSpeed();
boolean isRemovingEffectsOnHeal();
boolean isSpawnIfNoHome();
boolean isConfirmHomeOverwrite();
boolean infoAfterDeath();
}
@@ -1,8 +1,10 @@
package com.earth2me.essentials;
import com.earth2me.essentials.api.IAsyncTeleport;
import com.earth2me.essentials.commands.IEssentialsCommand;
import net.ess3.api.ITeleport;
import net.ess3.api.MaxMoneyException;
import net.ess3.api.events.AfkStatusChangeEvent;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@@ -53,21 +55,30 @@ public interface IUser {
*/
boolean hasOutstandingTeleportRequest();
/**
* @deprecated This API is not asynchronous. Use {@link com.earth2me.essentials.api.IAsyncTeleport IAsyncTeleport} with {@link IUser#getAsyncTeleport()}
*/
@Deprecated
ITeleport getTeleport();
IAsyncTeleport getAsyncTeleport();
BigDecimal getMoney();
void setMoney(final BigDecimal value) throws MaxMoneyException;
@Deprecated
void setAfk(final boolean set);
void setAfk(final boolean set, final AfkStatusChangeEvent.Cause cause);
/**
* 'Hidden' Represents when a player is hidden from others. This status includes when the player is hidden via other
* supported plugins. Use isVanished() if you want to check if a user is vanished by Essentials.
*
* @return If the user is hidden or not
*
* @see isVanished
* @see IUser#isVanished()
*/
boolean isHidden();
@@ -96,7 +107,7 @@ public interface IUser {
*
* @return If the user is vanished or not
*
* @see isHidden
* @see IUser#isHidden()
*/
boolean isVanished();
@@ -168,6 +179,8 @@ public interface IUser {
String getName();
String getDisplayName();
String getAfkMessage();
void setAfkMessage(final String message);
@@ -22,6 +22,7 @@ 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;
@@ -68,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();
}
}
@@ -97,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();
}
@@ -116,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 {
@@ -130,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 {
@@ -157,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);
}
}
@@ -165,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);
}
}
@@ -173,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);
}
}
@@ -195,7 +218,7 @@ 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()) {
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-interact")) {
event.setCancelled(true);
}
}
@@ -254,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);
@@ -1,5 +1,8 @@
package com.earth2me.essentials;
import net.ess3.api.IEssentials;
import org.bukkit.Bukkit;
import java.io.*;
import java.math.BigInteger;
import java.security.DigestInputStream;
@@ -10,9 +13,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.stream.Collectors;
import net.ess3.api.IEssentials;
import org.bukkit.Bukkit;
import static com.earth2me.essentials.I18n.tl;
@@ -44,13 +44,10 @@ public class ManagedFile {
}
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);
@@ -8,10 +8,6 @@ import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.base.Joiner;
import java.lang.reflect.Method;
import java.util.*;
import java.util.logging.Level;
import java.util.regex.Pattern;
import net.ess3.api.IEssentials;
import net.ess3.nms.refl.ReflUtil;
import org.bukkit.Color;
@@ -28,6 +24,11 @@ import org.bukkit.potion.Potion;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import java.lang.reflect.Method;
import java.util.*;
import java.util.logging.Level;
import java.util.regex.Pattern;
import static com.earth2me.essentials.I18n.tl;
@@ -100,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;
}
@@ -161,7 +157,7 @@ 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>();
final List<String> lore = new ArrayList<>();
for (String line : split[1].split("(?<!\\\\)\\|")) {
lore.add(FormatUtil.replaceFormat(line.replace('_', ' ').replace("\\|", "|")));
}
@@ -169,7 +165,7 @@ public class MetaItemStack {
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())) {
@@ -292,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())) {
@@ -315,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())) {
@@ -371,6 +367,13 @@ public class MetaItemStack {
} else {
throw new Exception(tl("invalidPotionMeta", split[1]));
}
} else if (split[0].equalsIgnoreCase("amplifier") || (allowShortName && split[0].equalsIgnoreCase("a"))) {
if (NumberUtil.isInt(split[1])) {
validPotionPower = true;
power = Integer.parseInt(split[1]);
} else {
throw new Exception(tl("invalidPotionMeta", split[1]));
}
} else if (split[0].equalsIgnoreCase("duration") || (allowShortName && split[0].equalsIgnoreCase("d"))) {
if (NumberUtil.isInt(split[1])) {
validPotionDuration = true;
@@ -379,7 +382,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()) {
@@ -486,11 +489,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);
}
@@ -512,11 +515,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);
}
@@ -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),
@@ -90,7 +91,13 @@ public enum Mob {
RAVAGER("Ravager", Enemies.ENEMY, "RAVAGER"),
TRADER_LLAMA("TraderLlama", Enemies.FRIENDLY, "TRADER_LLAMA"),
WANDERING_TRADER("WanderingTrader", Enemies.FRIENDLY, "WANDERING_TRADER"),
BEE("Bee", Enemies.NEUTRAL, "BEE")
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"),
PIGLIN_BRUTE("PiglinBrute", Enemies.ADULT_ENEMY, "PIGLIN_BRUTE"),
;
public static final Logger logger = Logger.getLogger("Essentials");
@@ -154,7 +161,8 @@ public enum Mob {
public enum Enemies {
FRIENDLY("friendly"),
NEUTRAL("neutral"),
ENEMY("enemy");
ENEMY("enemy"),
ADULT_ENEMY("adult_enemy");
Enemies(final String type) {
this.type = type;
@@ -1,28 +1,42 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.nms.refl.ReflUtil;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Fox;
import org.bukkit.entity.Llama;
import org.bukkit.entity.MushroomCow;
import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Panda;
import org.bukkit.entity.Parrot;
import org.bukkit.entity.TropicalFish;
import org.bukkit.entity.Villager;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static com.earth2me.essentials.utils.EnumUtil.getEntityType;
public class MobCompat {
// Constants for mob interfaces added in later versions
public static final Class RAIDER = ReflUtil.getClassCached("org.bukkit.entity.Raider");
// Constants for mobs added in later versions
public static final EntityType LLAMA = getEntityType("LLAMA");
public static final EntityType PARROT = getEntityType("PARROT");
public static final EntityType TROPICAL_FISH = getEntityType("TROPICAL_FISH");
public static final EntityType PANDA = getEntityType("PANDA");
public static final EntityType TRADER_LLAMA = getEntityType("TRADER_LLAMA");
public static final EntityType SHULKER = getEntityType("SHULKER");
public static final EntityType STRAY = getEntityType("STRAY");
public static final EntityType FOX = getEntityType("FOX");
public static final EntityType PHANTOM = getEntityType("PHANTOM");
// Constants for mobs that have changed since earlier versions
public static final EntityType CAT = getEntityType("CAT", "OCELOT");
public static final EntityType ZOMBIFIED_PIGLIN = getEntityType("ZOMBIFIED_PIGLIN", "PIG_ZOMBIE");
public enum CatType {
// These are (loosely) Mojang names for the cats
@@ -64,12 +78,12 @@ public class MobCompat {
NITWIT("NITWIT", "NITWIT"),
SHEPHERD("FARMER", "SHEPHERD"),
TOOLSMITH("BLACKSMITH", "TOOL_SMITH", "TOOLSMITH"),
WEAPONSMITH("BLACKSMITH", "WEAPON_SMITH", "WEAPONSMITH")
WEAPONSMITH("BLACKSMITH", "WEAPON_SMITH", "WEAPONSMITH"),
;
private String oldProfession;
private String oldCareer;
private String newProfession;
private final String oldProfession;
private final String oldCareer;
private final String newProfession;
VillagerProfession(final String oldProfession, final String career) {
this.oldProfession = oldProfession;
@@ -89,41 +103,33 @@ public class MobCompat {
}
// Older cats are Ocelots, whereas 1.14+ cats are Cats
private static Class catClass = ReflUtil.getClassCached("org.bukkit.entity.Cat");
private static Class catTypeClass = ReflUtil.getClassCached("org.bukkit.entity.Cat.Type");
private static Method catSetTypeMethod = (catClass == null || catTypeClass == null) ? null : ReflUtil.getMethodCached(catClass, "setCatType", catTypeClass);
private static boolean isNewCat() {
return (catClass != null && catTypeClass != null && catSetTypeMethod != null);
}
public static void setCatType(final Entity entity, final CatType type) {
if (isNewCat()) {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_R01)) {
((Ocelot) entity).setCatType(Ocelot.Type.valueOf(type.ocelotTypeName));
} else {
Class cat = ReflUtil.getClassCached("org.bukkit.entity.Cat");
Class catType = ReflUtil.getClassCached("org.bukkit.entity.Cat$Type");
Method setCatType = ReflUtil.getMethodCached(cat, "setCatType", catType);
try {
catSetTypeMethod.invoke(entity, EnumUtil.valueOf(catTypeClass, type.catTypeName));
} catch (IllegalAccessException | InvocationTargetException e) {
setCatType.invoke(entity, EnumUtil.valueOf(catType, type.catTypeName));
} catch (Exception e) {
e.printStackTrace();
}
} else {
((Ocelot) entity).setCatType(Ocelot.Type.valueOf(type.ocelotTypeName));
}
}
// Older villagers have professions and careers, 1.14+ villagers only have professions
private static Class villagerCareerClass = ReflUtil.getClassCached("org.bukkit.entity.Villager.Career");
private static Method villagerSetCareerMethod = (villagerCareerClass == null) ? null : ReflUtil.getMethodCached(Villager.class, "setCareer", villagerCareerClass);
private static boolean isCareerVillager() {
return (villagerCareerClass != null && villagerSetCareerMethod != null);
}
public static void setVillagerProfession(final Entity entity, final VillagerProfession profession) {
if (!isCareerVillager()) {
((Villager) entity).setProfession(profession.asEnum());
} else {
((Villager) entity).setProfession(profession.asEnum());
if (!(entity instanceof Villager)) {
return;
}
Villager villager = (Villager) entity;
villager.setProfession(profession.asEnum());
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_R01)) {
Class villagerCareer = ReflUtil.getClassCached("org.bukkit.entity.Villager$Career");
Method setCareer = ReflUtil.getMethodCached(Villager.class, "setCareer", villagerCareer);
try {
villagerSetCareerMethod.invoke(entity, EnumUtil.valueOf(villagerCareerClass, profession.oldCareer));
setCareer.invoke(entity, EnumUtil.valueOf(villagerCareer, profession.oldCareer));
} catch (Exception e) {
e.printStackTrace();
}
@@ -132,92 +138,77 @@ public class MobCompat {
// Only 1.14+ villagers have biome variants
public static void setVillagerType(final Entity entity, final String type) {
Class typeEnum = ReflUtil.getClassCached("org.bukkit.entity.Villager.Type");
if (typeEnum == null) return;
Method villagerSetTypeMethod = ReflUtil.getMethodCached(Villager.class, "setVillagerType", typeEnum);
try {
villagerSetTypeMethod.invoke(entity, EnumUtil.valueOf(typeEnum, type));
} catch (Exception e) {
e.printStackTrace();
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_R01)) {
return;
}
if (entity instanceof Villager) {
((Villager) entity).setVillagerType(Villager.Type.valueOf(type));
}
}
// Llamas only exist in 1.11+
public static void setLlamaColor(final Entity entity, final String color) {
Class llamaClass = ReflUtil.getClassCached("org.bukkit.entity.Llama");
if (llamaClass == null) return;
Class colorEnum = ReflUtil.getClassCached("org.bukkit.entity.Llama.Color");
Method setVariantMethod = ReflUtil.getMethodCached(llamaClass, "setColor");
try {
setVariantMethod.invoke(entity, EnumUtil.valueOf(colorEnum, color));
} catch (Exception e) {
e.printStackTrace();
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_11_R01)) {
return;
}
if (entity instanceof Llama) {
((Llama) entity).setColor(Llama.Color.valueOf(color));
}
}
// Parrots only exist in 1.12+
public static void setParrotVariant(final Entity entity, final String variant) {
Class parrotClass = ReflUtil.getClassCached("org.bukkit.entity.Parrot");
if (parrotClass == null) return;
Class variantEnum = ReflUtil.getClassCached("org.bukkit.entity.Parrot.Variant");
Method setVariantMethod = ReflUtil.getMethodCached(parrotClass, "setVariant");
try {
setVariantMethod.invoke(entity, EnumUtil.valueOf(variantEnum, variant));
} catch (Exception e) {
e.printStackTrace();
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_12_0_R01)) {
return;
}
if (entity instanceof Parrot) {
((Parrot) entity).setVariant(Parrot.Variant.valueOf(variant));
}
}
// Tropical fish only exist in 1.13+
public static void setTropicalFishPattern(final Entity entity, final String pattern) {
Class tropicalFishClass = ReflUtil.getClassCached("org.bukkit.entity.TropicalFish");
if (tropicalFishClass == null) return;
Class patternEnum = ReflUtil.getClassCached("org.bukkit.entity.TropicalFish.Pattern");
Method setPatternMethod = ReflUtil.getMethodCached(tropicalFishClass, "setPattern");
try {
setPatternMethod.invoke(entity, EnumUtil.valueOf(patternEnum, pattern));
} catch (Exception e) {
e.printStackTrace();
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_12_0_R01)) {
return;
}
if (entity instanceof TropicalFish) {
((TropicalFish) entity).setPattern(TropicalFish.Pattern.valueOf(pattern));
}
}
// Mushroom cow variant API only exists in 1.14+
public static void setMooshroomVariant(final Entity entity, final String variant) {
Class mushroomCowClass = ReflUtil.getClassCached("org.bukkit.entity.MushroomCow");
Class variantEnum = ReflUtil.getClassCached("org.bukkit.entity.MushroomCow.Variant");
if (mushroomCowClass == null || variantEnum == null) return;
Method setVariantMethod = ReflUtil.getMethodCached(mushroomCowClass, "setVariant");
try {
setVariantMethod.invoke(entity, EnumUtil.valueOf(variantEnum, variant));
} catch (Exception e) {
e.printStackTrace();
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_R01)) {
return;
}
if (entity instanceof MushroomCow) {
((MushroomCow) entity).setVariant(MushroomCow.Variant.valueOf(variant));
}
}
// Pandas only exists in 1.14+
public static void setPandaGene(final Entity entity, final String gene, final boolean mainGene) {
Class pandaClass = ReflUtil.getClassCached("org.bukkit.entity.Panda");
if (pandaClass == null) return;
Class geneEnum = ReflUtil.getClassCached("org.bukkit.entity.Panda.Gene");
Method setGeneMethod;
if (mainGene) {
setGeneMethod = ReflUtil.getMethodCached(pandaClass, "setMainGene");
} else {
setGeneMethod = ReflUtil.getMethodCached(pandaClass, "setHiddenGene");
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_R01)) {
return;
}
if (entity instanceof Panda) {
Panda panda = (Panda) entity;
Panda.Gene pandaGene = Panda.Gene.valueOf(gene);
if (mainGene) {
panda.setMainGene(pandaGene);
} else {
panda.setHiddenGene(pandaGene);
}
}
}
try {
setGeneMethod.invoke(entity, EnumUtil.valueOf(geneEnum, gene));
} catch (Exception e) {
e.printStackTrace();
// Foxes only exist in 1.14+
public static void setFoxType(final Entity entity, final String type) {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_R01)) {
return;
}
if (entity instanceof Fox) {
((Fox) entity).setFoxType(Fox.Type.valueOf(type));
}
}
@@ -12,6 +12,7 @@ import org.bukkit.material.Colorable;
import java.util.*;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import static com.earth2me.essentials.I18n.tl;
@@ -32,7 +33,7 @@ public enum MobData {
TAMED_TAMEABLE("tamed", Tameable.class, Data.TAMED, true),
TAME_TAMEABLE("tame", Tameable.class, Data.TAMED, false),
RANDOM_SHEEP("random", EntityType.SHEEP, Data.COLORABLE, true),
COLORABLE_SHEEP("", StringUtil.joinList(DyeColor.values()).toLowerCase(Locale.ENGLISH), EntityType.SHEEP, Data.COLORABLE, true),
COLORABLE_SHEEP("", Arrays.stream(DyeColor.values()).map(color -> color.name().toLowerCase(Locale.ENGLISH)).collect(Collectors.toList()), EntityType.SHEEP, Data.COLORABLE, true),
POLKA_HORSE("polka", EntityType.HORSE, Horse.Style.BLACK_DOTS, true),
SOOTY_HORSE("sooty", EntityType.HORSE, Horse.Style.BLACK_DOTS, false),
BLAZE_HORSE("blaze", EntityType.HORSE, Horse.Style.WHITE, true),
@@ -113,8 +114,8 @@ public enum MobData {
SNOWY_VILLAGER("snowy", EntityType.VILLAGER, "villagertype:SNOWY", true),
SWAMP_VILLAGER("swamp", EntityType.VILLAGER, "villagertype:SWAMP", true),
TAIGA_VILLAGER("taiga", EntityType.VILLAGER, "villagertype:TAIGA", true),
SIZE_SLIME("", "<1-100>", EntityType.SLIME.getEntityClass(), Data.SIZE, true),
NUM_EXPERIENCE_ORB("", "<1-2000000000>", EntityType.EXPERIENCE_ORB, Data.EXP, true),
SIZE_SLIME("", Collections.singletonList("<1-100>"), EntityType.SLIME.getEntityClass(), Data.SIZE, true),
NUM_EXPERIENCE_ORB("", Collections.singletonList("<1-2000000000>"), EntityType.EXPERIENCE_ORB, Data.EXP, true),
RED_PARROT("red", MobCompat.PARROT, "parrot:RED", true),
GREEN_PARROT("green", MobCompat.PARROT, "parrot:GREEN", true),
BLUE_PARROT("blue", MobCompat.PARROT, "parrot:BLUE", true),
@@ -153,7 +154,15 @@ public enum MobData {
CREAMY_TRADER_LLAMA("creamy", MobCompat.TRADER_LLAMA, "llama:CREAMY", true),
WHITE_TRADER_LLAMA("white", MobCompat.TRADER_LLAMA, "llama:WHITE", true),
BROWN_TRADER_LLAMA("brown", MobCompat.TRADER_LLAMA, "llama:BROWN", true),
GRAY_TRADER_LLAMA("gray", MobCompat.TRADER_LLAMA, "llama:GRAY", true)
GRAY_TRADER_LLAMA("gray", MobCompat.TRADER_LLAMA, "llama:GRAY", true),
RANDOM_SHULKER("random", MobCompat.SHULKER, Data.COLORABLE, true),
COLORABLE_SHULKER("", Arrays.stream(DyeColor.values()).map(color -> color.name().toLowerCase(Locale.ENGLISH)).collect(Collectors.toList()), MobCompat.SHULKER, Data.COLORABLE, true),
RED_FOX("red", MobCompat.FOX, "fox:RED", true),
SNOW_FOX("snow", MobCompat.FOX, "fox:SNOW", true),
SIZE_PHANTOM("", Collections.singletonList("<1-100>"), MobCompat.PHANTOM, Data.SIZE, true),
RAID_LEADER("leader", MobCompat.RAIDER, Data.RAID_LEADER, true),
TROPICAL_FISH_BODY_COLOR("fish_body_color", Arrays.stream(DyeColor.values()).map(color -> color.name().toLowerCase(Locale.ENGLISH) + "body").collect(Collectors.toList()), MobCompat.TROPICAL_FISH, Data.FISH_BODY_COLOR, true),
TROPICAL_FISH_PATTERN_COLOR("fish_pattern_color", Arrays.stream(DyeColor.values()).map(color -> color.name().toLowerCase(Locale.ENGLISH) + "pattern").collect(Collectors.toList()), MobCompat.TROPICAL_FISH, Data.FISH_PATTERN_COLOR, true),
;
@@ -170,43 +179,46 @@ public enum MobData {
TAMED,
COLORABLE,
EXP,
SIZE
SIZE,
RAID_LEADER,
FISH_BODY_COLOR,
FISH_PATTERN_COLOR,
}
public static final Logger logger = Logger.getLogger("Essentials");
MobData(String n, Object type, Object value, boolean isPublic) {
this.nickname = n;
this.matched = n;
this.helpMessage = n;
this.type = type;
this.value = value;
this.isPublic = isPublic;
}
MobData(String n, String h, Object type, Object value, boolean isPublic) {
this.nickname = n;
this.matched = n;
this.helpMessage = h;
this.type = type;
this.value = value;
this.isPublic = isPublic;
}
final private String nickname;
final private String helpMessage;
final private List<String> suggestions;
final private Object type;
final private Object value;
final private boolean isPublic;
private String matched;
MobData(String n, Object type, Object value, boolean isPublic) {
this.nickname = n;
this.matched = n;
this.suggestions = Collections.singletonList(n);
this.type = type;
this.value = value;
this.isPublic = isPublic;
}
MobData(String n, List<String> s, Object type, Object value, boolean isPublic) {
this.nickname = n;
this.matched = n;
this.suggestions = s;
this.type = type;
this.value = value;
this.isPublic = isPublic;
}
public static LinkedHashMap<String, MobData> getPossibleData(final Entity spawned, boolean publicOnly) {
LinkedHashMap<String, MobData> mobList = new LinkedHashMap<String, MobData>();
LinkedHashMap<String, MobData> mobList = new LinkedHashMap<>();
for (MobData data : MobData.values()) {
if (data.type == null || (publicOnly && !data.isPublic)) continue;
if (data.type == null || (publicOnly && !data.isPublic)) {
continue;
}
if (data.type instanceof EntityType && spawned.getType().equals(data.type)) {
mobList.put(data.nickname.toLowerCase(Locale.ENGLISH), data);
} else if (data.type instanceof Class && ((Class) data.type).isAssignableFrom(spawned.getClass())) {
@@ -218,11 +230,11 @@ public enum MobData {
}
public static List<String> getValidHelp(final Entity spawned) {
List<String> output = new ArrayList<String>();
List<String> output = new ArrayList<>();
LinkedHashMap<String, MobData> posData = getPossibleData(spawned, true);
for (MobData data : posData.values()) {
output.add(data.helpMessage);
output.add(StringUtil.joinList(data.suggestions));
}
return output;
}
@@ -233,9 +245,11 @@ public enum MobData {
}
LinkedHashMap<String, MobData> posData = getPossibleData(spawned, false);
for (String data : posData.keySet()) {
if (name.contains(data)) {
return posData.get(data);
for (MobData data : posData.values()) {
for (String suggestion : data.suggestions) {
if (name.contains(suggestion)) {
return data;
}
}
}
return null;
@@ -291,7 +305,12 @@ public enum MobData {
}
} else if (this.value.equals(Data.SIZE)) {
try {
((Slime) spawned).setSize(Integer.parseInt(rawData));
int size = Integer.parseInt(rawData);
if (spawned instanceof Slime) {
((Slime) spawned).setSize(size);
} else if (spawned.getType() == MobCompat.PHANTOM) {
((Phantom) spawned).setSize(size);
}
this.matched = rawData;
} catch (NumberFormatException e) {
throw new Exception(tl("slimeMalformedSize"), e);
@@ -313,6 +332,26 @@ public enum MobData {
InventoryWorkaround.setItemInMainHand(invent, new ItemStack((Material) this.value, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
}
} else if (this.value.equals(Data.RAID_LEADER)) {
((Raider) spawned).setPatrolLeader(true);
} else if (this.value.equals(Data.FISH_BODY_COLOR)) {
for (String match : TROPICAL_FISH_BODY_COLOR.suggestions) {
if (rawData.contains(match)) {
this.matched = match;
final String color = match.substring(0, match.indexOf("body")).toUpperCase(Locale.ENGLISH);
((TropicalFish) spawned).setBodyColor(DyeColor.valueOf(color));
break;
}
}
} else if (this.value.equals(Data.FISH_PATTERN_COLOR)) {
for (String match : TROPICAL_FISH_PATTERN_COLOR.suggestions) {
if (rawData.contains(match)) {
this.matched = match;
final String color = match.substring(0, match.indexOf("pattern")).toUpperCase(Locale.ENGLISH);
((TropicalFish) spawned).setPatternColor(DyeColor.valueOf(color));
break;
}
}
} else if (this.value instanceof String) {
final String[] split = ((String) this.value).split(":");
switch (split[0]) {
@@ -337,6 +376,9 @@ public enum MobData {
case "villagertype":
MobCompat.setVillagerType(spawned, split[1]);
break;
case "fox":
MobCompat.setFoxType(spawned, split[1]);
break;
}
} else {
logger.warning("Unknown mob data type: " + this.toString());
@@ -1,6 +1,7 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.ChatColor;
import org.bukkit.Server;
import java.util.*;
@@ -27,6 +28,9 @@ public class PlayerList {
}
user.setDisplayNick();
groupString.append(user.getDisplayName());
if (ess.getSettings().realNamesOnList() && !ChatColor.stripColor(user.getDisplayName()).equals(user.getName())) {
groupString.append(" (").append(user.getName()).append(")");
}
groupString.append("\u00a7f");
}
return groupString.toString();
@@ -40,7 +44,7 @@ public class PlayerList {
for (User onlinePlayer : ess.getOnlineUsers()) {
if (onlinePlayer.isHidden() || (user != null && !user.getBase().canSee(onlinePlayer.getBase()))) {
playerHidden++;
if (showHidden || user.getBase().canSee(onlinePlayer.getBase())) {
if (showHidden || user != null && user.getBase().canSee(onlinePlayer.getBase())) {
hiddenCount++;
}
}
@@ -55,19 +59,14 @@ 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>>();
public static Map<String, List<User>> getPlayerLists(final IEssentials ess, final IUser sender, final boolean showHidden) {
final Map<String, List<User>> playerList = new HashMap<>();
for (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,208 @@
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", false);
}
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<>();
// Find an equally distributed offset by randomly rotating a point inside a rectangle about the origin
double rectX = RANDOM.nextDouble() * (maxRange - minRange) + minRange;
double rectZ = RANDOM.nextDouble() * (maxRange + minRange) - minRange;
double offsetX, offsetZ;
int transform = RANDOM.nextInt(4);
if (transform == 0) {
offsetX = rectX;
offsetZ = rectZ;
} else if (transform == 1) {
offsetX = -rectZ;
offsetZ = rectX;
} else if (transform == 2) {
offsetX = -rectX;
offsetZ = -rectZ;
} else {
offsetX = rectZ;
offsetZ = -rectX;
}
Location location = new Location(
center.getWorld(),
center.getX() + offsetX,
center.getWorld().getMaxHeight(),
center.getZ() + offsetZ,
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());
}
}
@@ -61,6 +61,11 @@ public class Settings implements net.ess3.api.ISettings {
return config.getBoolean("respawn-at-home", false);
}
@Override
public boolean isRespawnAtAnchor() {
return config.getBoolean("respawn-at-anchor", false);
}
@Override
public boolean getUpdateBedAtDaytime() {
return config.getBoolean("update-bed-at-daytime", true);
@@ -157,6 +162,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);
@@ -182,7 +202,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) {
@@ -190,7 +210,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));
}
@@ -270,10 +290,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")) {
@@ -296,10 +316,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));
@@ -360,29 +380,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
@@ -420,7 +448,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) {
@@ -482,7 +515,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 {
@@ -494,7 +527,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();
@@ -508,6 +541,7 @@ public class Settings implements net.ess3.api.ISettings {
sleepIgnoresAfkPlayers = _sleepIgnoresAfkPlayers();
afkListName = _getAfkListName();
isAfkListName = !afkListName.equalsIgnoreCase("none");
broadcastAfkMessage = _broadcastAfkMessage();
itemSpawnBl = _getItemSpawnBlacklist();
loginAttackDelay = _getLoginAttackDelay();
signUsePerSecond = _getSignUsePerSecond();
@@ -552,13 +586,15 @@ public class Settings implements net.ess3.api.ISettings {
isCompassTowardsHomePerm = _isCompassTowardsHomePerm();
isAllowWorldInBroadcastworld = _isAllowWorldInBroadcastworld();
itemDbType = _getItemDbType();
forceEnableRecipe = _isForceEnableRecipe();
allowOldIdSigns = _allowOldIdSigns();
isWaterSafe = _isWaterSafe();
isSafeUsermap = _isSafeUsermap();
logCommandBlockCommands = _logCommandBlockCommands();
nickBlacklist = _getNickBlacklist();
maxProjectileSpeed = _getMaxProjectileSpeed();
removeEffectsOnHeal = _isRemovingEffectsOnHeal();
vanishingItemPolicy = _getVanishingItemsPolicy();
bindingItemPolicy = _getBindingItemsPolicy();
}
void _lateLoadItemSpawnBlacklist() {
@@ -594,7 +630,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
@@ -605,7 +641,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);
@@ -672,6 +708,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
@@ -786,6 +827,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);
}
@@ -939,12 +985,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() {
@@ -1110,8 +1199,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
@@ -1124,8 +1212,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
@@ -1133,6 +1220,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);
@@ -1198,6 +1290,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);
@@ -1223,6 +1325,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);
}
@@ -1318,7 +1425,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) {
@@ -1430,7 +1537,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;
@@ -1446,6 +1552,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);
@@ -1471,6 +1582,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() {
@@ -1537,15 +1658,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() {
@@ -1625,8 +1737,29 @@ public class Settings implements net.ess3.api.ISettings {
return maxProjectileSpeed;
}
private boolean removeEffectsOnHeal;
private boolean _isRemovingEffectsOnHeal() {
return config.getBoolean("remove-effects-on-heal", true);
}
@Override
public boolean isRemovingEffectsOnHeal() {
return removeEffectsOnHeal;
}
@Override
public boolean isSpawnIfNoHome() {
return config.getBoolean("spawn-if-no-home", true);
}
@Override
public boolean isConfirmHomeOverwrite() {
return config.getBoolean("confirm-home-overwrite", false);
}
@Override
public boolean infoAfterDeath() {
return config.getBoolean("send-info-after-death", false);
}
}
@@ -29,7 +29,7 @@ public class SpawnMob {
public static String mobList(final User user) {
final Set<String> mobList = Mob.getMobList();
final Set<String> availableList = new HashSet<String>();
final Set<String> availableList = new HashSet<>();
for (String mob : mobList) {
if (user.isAuthorized("essentials.spawnmob." + mob.toLowerCase(Locale.ENGLISH))) {
availableList.add(mob);
@@ -44,7 +44,7 @@ public class SpawnMob {
public static List<String> mobParts(final String mobString) {
String[] mobParts = mobString.split(",");
List<String> mobs = new ArrayList<String>();
List<String> mobs = new ArrayList<>();
for (String mobPart : mobParts) {
String[] mobDatas = mobPart.split(":");
@@ -56,7 +56,7 @@ public class SpawnMob {
public static List<String> mobData(final String mobString) {
String[] mobParts = mobString.split(",");
List<String> mobData = new ArrayList<String>();
List<String> mobData = new ArrayList<>();
for (String mobPart : mobParts) {
String[] mobDatas = mobPart.split(":");
@@ -92,8 +92,8 @@ public class SpawnMob {
public static void spawnmob(final IEssentials ess, final Server server, final CommandSource sender, final User target, final Location loc, final List<String> parts, final List<String> data, int mobCount) throws Exception {
final Location sloc = LocationUtil.getSafeDestination(loc);
for (int i = 0; i < parts.size(); i++) {
Mob mob = Mob.fromName(parts.get(i));
for (String part : parts) {
Mob mob = Mob.fromName(part);
checkSpawnable(ess, sender, mob);
}
@@ -235,30 +235,20 @@ public class SpawnMob {
final EntityEquipment invent = ((LivingEntity) spawned).getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack(Material.BOW, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
invent.setBoots(new ItemStack(GOLDEN_BOOTS, 1));
invent.setBootsDropChance(0.0f);
}
if (type == EntityType.PIG_ZOMBIE) {
if (type == MobCompat.ZOMBIFIED_PIGLIN) {
final PigZombie zombie = ((PigZombie) spawned);
setVillager(zombie, false);
final EntityEquipment invent = zombie.getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack(GOLDEN_SWORD, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
invent.setBoots(new ItemStack(GOLDEN_BOOTS, 1));
invent.setBootsDropChance(0.0f);
}
if (type == EntityType.ZOMBIE) {
final Zombie zombie = ((Zombie) spawned);
setVillager(zombie, false);
final EntityEquipment invent = zombie.getEquipment();
invent.setBoots(new ItemStack(GOLDEN_BOOTS, 1));
invent.setBootsDropChance(0.0f);
}
if (type == EntityType.HORSE) {
@@ -7,6 +7,8 @@ import net.ess3.api.IEssentials;
import net.ess3.api.ITeleport;
import net.ess3.api.IUser;
import net.ess3.api.events.UserWarpEvent;
import net.ess3.api.events.teleport.PreTeleportEvent;
import net.ess3.api.events.teleport.TeleportWarmupEvent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
@@ -20,6 +22,10 @@ import java.util.GregorianCalendar;
import static com.earth2me.essentials.I18n.tl;
/**
* @deprecated This API is not asynchronous. Use {@link com.earth2me.essentials.AsyncTeleport AsyncTeleport}
*/
@Deprecated
public class Teleport implements ITeleport {
private final IUser teleportOwner;
private final IEssentials ess;
@@ -27,6 +33,7 @@ public class Teleport implements ITeleport {
private TeleportType tpType;
@Deprecated
public Teleport(IUser user, IEssentials ess) {
this.teleportOwner = user;
this.ess = ess;
@@ -39,6 +46,7 @@ public class Teleport implements ITeleport {
NORMAL
}
@Deprecated
public void cooldown(boolean check) throws Exception {
final Calendar time = new GregorianCalendar();
if (teleportOwner.getLastTeleportTimestamp() > 0) {
@@ -72,6 +80,7 @@ public class Teleport implements ITeleport {
}
}
@Deprecated
private boolean cooldownApplies() {
boolean applies = true;
String globalBypassPerm = "essentials.teleport.cooldown.bypass";
@@ -91,6 +100,7 @@ public class Teleport implements ITeleport {
return applies;
}
@Deprecated
private void warnUser(final IUser user, final double delay) {
Calendar c = new GregorianCalendar();
c.add(Calendar.SECOND, (int) delay);
@@ -100,6 +110,7 @@ public class Teleport implements ITeleport {
//The now function is used when you want to skip tp delay when teleporting someone to a location or player.
@Override
@Deprecated
public void now(Location loc, boolean cooldown, TeleportCause cause) throws Exception {
if (cooldown) {
cooldown(false);
@@ -109,6 +120,7 @@ public class Teleport implements ITeleport {
}
@Override
@Deprecated
public void now(Player entity, boolean cooldown, TeleportCause cause) throws Exception {
if (cooldown) {
cooldown(false);
@@ -118,11 +130,28 @@ public class Teleport implements ITeleport {
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
}
@Deprecated
protected void now(IUser teleportee, ITarget target, TeleportCause cause) throws Exception {
cancel(false);
teleportee.setLastLocation();
Location loc = target.getLocation();
PreTeleportEvent event = new PreTeleportEvent(teleportee, cause, target);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
if (teleportee.isAuthorized("essentials.back.onteleport")) {
teleportee.setLastLocation();
}
if (!teleportee.getBase().isEmpty()) {
if (!ess.getSettings().isTeleportPassengerDismount()) {
throw new Exception(tl("passengerTeleportFail"));
}
teleportee.getBase().eject();
}
if (LocationUtil.isBlockUnsafeForUser(teleportee, loc.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) {
if (ess.getSettings().isTeleportSafetyEnabled()) {
if (ess.getSettings().isForceDisableTeleportSafety()) {
@@ -154,12 +183,14 @@ public class Teleport implements ITeleport {
}
@Override
@Deprecated
public void teleport(Location loc, Trade chargeFor, TeleportCause cause) throws Exception {
teleport(teleportOwner, new LocationTarget(loc), chargeFor, cause);
}
//This is used when teleporting to a player
@Override
@Deprecated
public void teleport(Player entity, Trade chargeFor, TeleportCause cause) throws Exception {
ITarget target = new PlayerTarget(entity);
teleportOwner.sendMessage(tl("teleportToPlayer", entity.getDisplayName()));
@@ -168,12 +199,14 @@ public class Teleport implements ITeleport {
//This is used when teleporting to stored location
@Override
@Deprecated
public void teleportPlayer(IUser teleportee, Location loc, Trade chargeFor, TeleportCause cause) throws Exception {
teleport(teleportee, new LocationTarget(loc), chargeFor, cause);
}
//This is used on /tphere
@Override
@Deprecated
public void teleportPlayer(IUser teleportee, Player entity, Trade chargeFor, TeleportCause cause) throws Exception {
ITarget target = new PlayerTarget(entity);
teleport(teleportee, target, chargeFor, cause);
@@ -181,9 +214,17 @@ public class Teleport implements ITeleport {
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
}
@Deprecated
private void teleport(IUser teleportee, ITarget target, Trade chargeFor, TeleportCause cause) throws Exception {
double delay = ess.getSettings().getTeleportDelay();
TeleportWarmupEvent event = new TeleportWarmupEvent(teleportee, cause, target, delay);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
delay = event.getDelay();
Trade cashCharge = chargeFor;
if (chargeFor != null) {
@@ -211,9 +252,17 @@ public class Teleport implements ITeleport {
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false);
}
@Deprecated
private void teleportOther(IUser teleporter, IUser teleportee, ITarget target, Trade chargeFor, TeleportCause cause) throws Exception {
double delay = ess.getSettings().getTeleportDelay();
TeleportWarmupEvent event = new TeleportWarmupEvent(teleporter, teleportee, cause, target, delay);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
delay = event.getDelay();
Trade cashCharge = chargeFor;
if (teleporter != null && chargeFor != null) {
@@ -246,8 +295,17 @@ public class Teleport implements ITeleport {
//The respawn function is a wrapper used to handle tp fallback, on /jail and /home
@Override
@Deprecated
public void respawn(final Trade chargeFor, TeleportCause cause) throws Exception {
double delay = ess.getSettings().getTeleportDelay();
TeleportWarmupEvent event = new TeleportWarmupEvent(teleportOwner, cause, null, delay);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
delay = event.getDelay();
if (chargeFor != null) {
chargeFor.isAffordableFor(teleportOwner);
}
@@ -266,6 +324,7 @@ public class Teleport implements ITeleport {
initTimer((long) (delay * 1000.0), teleportOwner, null, chargeFor, cause, true);
}
@Deprecated
void respawnNow(IUser teleportee, TeleportCause cause) throws Exception {
final Player player = teleportee.getBase();
Location bed = player.getBedSpawnLocation();
@@ -283,13 +342,14 @@ public class Teleport implements ITeleport {
//The warp function is a wrapper used to teleportPlayer a player to a /warp
@Override
@Deprecated
public void warp(IUser teleportee, String warp, Trade chargeFor, TeleportCause cause) throws Exception {
UserWarpEvent event = new UserWarpEvent(teleportee, warp, chargeFor);
Bukkit.getServer().getPluginManager().callEvent(event);
if(event.isCancelled()) {
if (event.isCancelled()) {
return;
}
warp = event.getWarp();
Location loc = ess.getWarps().getWarp(warp);
teleportee.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
@@ -301,12 +361,14 @@ public class Teleport implements ITeleport {
//The back function is a wrapper used to teleportPlayer a player /back to their previous location.
@Override
@Deprecated
public void back(Trade chargeFor) throws Exception {
back(teleportOwner, chargeFor);
}
//This function is a wrapper over the other back function for cases where another player performs back for them
@Override
@Deprecated
public void back(IUser teleporter, Trade chargeFor) throws Exception {
tpType = TeleportType.BACK;
final Location loc = teleportOwner.getLastLocation();
@@ -316,15 +378,18 @@ public class Teleport implements ITeleport {
//This function is used to throw a user back after a jail sentence
@Override
@Deprecated
public void back() throws Exception {
now(teleportOwner, new LocationTarget(teleportOwner.getLastLocation()), TeleportCause.COMMAND);
}
@Deprecated
public void setTpType(TeleportType tpType) {
this.tpType = tpType;
}
//If we need to cancelTimer a pending teleportPlayer call this method
@Deprecated
private void cancel(boolean notifyUser) {
if (timedTeleport != null) {
timedTeleport.cancelTimer(notifyUser);
@@ -332,6 +397,7 @@ public class Teleport implements ITeleport {
}
}
@Deprecated
private void initTimer(long delay, IUser teleportUser, ITarget target, Trade chargeFor, TeleportCause cause, boolean respawn) {
timedTeleport = new TimedTeleport(teleportOwner, ess, this, delay, teleportUser, target, chargeFor, cause, respawn);
}
@@ -9,7 +9,7 @@ import java.util.UUID;
import static com.earth2me.essentials.I18n.tl;
@Deprecated
public class TimedTeleport implements Runnable {
private static final double MOVE_CONSTANT = 0.3;
private final IUser teleportOwner;
@@ -98,19 +98,17 @@ public class TimedTeleport implements Runnable {
cancelTimer(false);
teleportUser.sendMessage(tl("teleportationCommencing"));
try {
if (timer_chargeFor != null) {
timer_chargeFor.isAffordableFor(teleportOwner);
}
if (timer_respawn) {
teleport.respawnNow(teleportUser, timer_cause);
} else {
teleport.now(teleportUser, timer_teleportTarget, timer_cause);
}
if (timer_chargeFor != null) {
timer_chargeFor.charge(teleportOwner);
}
} catch (Exception ignored) {}
if (timer_chargeFor != null) {
timer_chargeFor.isAffordableFor(teleportOwner);
}
if (timer_respawn) {
teleport.respawnNow(teleportUser, timer_cause);
} else {
teleport.now(teleportUser, timer_teleportTarget, timer_cause);
}
if (timer_chargeFor != null) {
timer_chargeFor.charge(teleportOwner);
}
} catch (Exception ex) {
ess.showError(teleportOwner.getSource(), ex, "\\ teleport");
@@ -18,6 +18,8 @@ import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -81,26 +83,43 @@ public class Trade {
}
public void isAffordableFor(final IUser user) throws ChargeException {
CompletableFuture<Boolean> future = new CompletableFuture<>();
isAffordableFor(user, future);
if (future.isCompletedExceptionally()) {
try {
future.get();
} catch (InterruptedException e) { //If this happens, we have bigger problems...
e.printStackTrace();
} catch (ExecutionException e) {
throw (ChargeException) e.getCause();
}
}
}
public void isAffordableFor(final IUser user, CompletableFuture<Boolean> future) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "checking if " + user.getName() + " can afford charge.");
}
if (getMoney() != null && getMoney().signum() > 0 && !user.canAfford(getMoney())) {
throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess)));
future.completeExceptionally(new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess))));
return;
}
if (getItemStack() != null && !user.getBase().getInventory().containsAtLeast(itemStack, itemStack.getAmount())) {
throw new ChargeException(tl("missingItems", getItemStack().getAmount(), ess.getItemDb().name(getItemStack())));
future.completeExceptionally(new ChargeException(tl("missingItems", getItemStack().getAmount(), ess.getItemDb().name(getItemStack()))));
return;
}
BigDecimal money;
if (command != null && !command.isEmpty() && (money = getCommandCost(user)).signum() > 0 && !user.canAfford(money)) {
throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(money, ess)));
future.completeExceptionally(new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(money, ess))));
return;
}
if (exp != null && exp > 0 && SetExpFix.getTotalExperience(user.getBase()) < exp) {
throw new ChargeException(tl("notEnoughExperience"));
future.completeExceptionally(new ChargeException(tl("notEnoughExperience")));
}
}
@@ -175,6 +194,20 @@ public class Trade {
}
public void charge(final IUser user) throws ChargeException {
CompletableFuture<Boolean> future = new CompletableFuture<>();
charge(user, future);
if (future.isCompletedExceptionally()) {
try {
future.get();
} catch (InterruptedException e) { //If this happens, we have bigger problems...
e.printStackTrace();
} catch (ExecutionException e) {
throw (ChargeException) e.getCause();
}
}
}
public void charge(final IUser user, CompletableFuture<Boolean> future) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "attempting to charge user " + user.getName());
}
@@ -183,7 +216,8 @@ public class Trade {
ess.getLogger().log(Level.INFO, "charging user " + user.getName() + " money " + getMoney().toPlainString());
}
if (!user.canAfford(getMoney()) && getMoney().signum() > 0) {
throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess)));
future.completeExceptionally(new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess))));
return;
}
user.takeMoney(getMoney());
}
@@ -192,7 +226,8 @@ public class Trade {
ess.getLogger().log(Level.INFO, "charging user " + user.getName() + " itemstack " + getItemStack().toString());
}
if (!user.getBase().getInventory().containsAtLeast(getItemStack(), getItemStack().getAmount())) {
throw new ChargeException(tl("missingItems", getItemStack().getAmount(), getItemStack().getType().toString().toLowerCase(Locale.ENGLISH).replace("_", " ")));
future.completeExceptionally(new ChargeException(tl("missingItems", getItemStack().getAmount(), getItemStack().getType().toString().toLowerCase(Locale.ENGLISH).replace("_", " "))));
return;
}
user.getBase().getInventory().removeItem(getItemStack());
user.getBase().updateInventory();
@@ -200,7 +235,8 @@ public class Trade {
if (command != null) {
final BigDecimal cost = getCommandCost(user);
if (!user.canAfford(cost) && cost.signum() > 0) {
throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(cost, ess)));
future.completeExceptionally(new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(cost, ess))));
return;
}
user.takeMoney(cost);
}
@@ -210,7 +246,8 @@ public class Trade {
}
final int experience = SetExpFix.getTotalExperience(user.getBase());
if (experience < getExperience() && getExperience() > 0) {
throw new ChargeException(tl("notEnoughExperience"));
future.completeExceptionally(new ChargeException(tl("notEnoughExperience")));
return;
}
SetExpFix.setTotalExperience(user.getBase(), experience - getExperience());
}
@@ -15,7 +15,7 @@ import java.util.regex.Pattern;
public class UUIDMap {
private final transient net.ess3.api.IEssentials ess;
private File userList;
private final File userList;
private final transient Pattern splitPattern = Pattern.compile(",");
private static boolean pendingWrite;
@@ -28,15 +28,12 @@ public class UUIDMap {
this.ess = ess;
userList = new File(ess.getDataFolder(), "usermap.csv");
pendingWrite = false;
writeTaskRunnable = new Runnable() {
@Override
public void run() {
if (pendingWrite) {
try {
new WriteRunner(ess.getDataFolder(), userList, ess.getUserMap().getNames()).run();
} catch (Throwable t) { // bad code to prevent task from being suppressed
t.printStackTrace();
}
writeTaskRunnable = () -> {
if (pendingWrite) {
try {
new WriteRunner(ess.getDataFolder(), userList, ess.getUserMap().getNames()).run();
} catch (Throwable t) { // bad code to prevent task from being suppressed
t.printStackTrace();
}
}
};
+126 -66
View File
@@ -15,9 +15,6 @@ import net.ess3.api.events.AfkStatusChangeEvent;
import net.ess3.api.events.JailStatusChangeEvent;
import net.ess3.api.events.MuteStatusChangeEvent;
import net.ess3.api.events.UserBalanceUpdateEvent;
import net.ess3.nms.refl.ReflUtil;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@@ -28,7 +25,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 +41,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 +62,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();
}
@@ -187,8 +195,8 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
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 {
@@ -238,12 +246,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() {
@@ -321,11 +324,25 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return teleportLocation;
}
public String getNick(final boolean longnick) {
return getNick(longnick, true, true);
public String getNick() {
return getNick(true, true);
}
public String getNick(final boolean longnick, final boolean withPrefix, final boolean withSuffix) {
/**
* Needed for backwards compatibility.
*/
public String getNick(final boolean longnick) {
return getNick(true, true);
}
/**
* Needed for backwards compatibility.
*/
public String getNick(boolean longnick, final boolean withPrefix, final boolean withSuffix) {
return getNick(withPrefix, withSuffix);
}
public String getNick(final boolean withPrefix, final boolean withSuffix) {
final StringBuilder prefix = new StringBuilder();
String nickname;
String suffix = "";
@@ -341,39 +358,38 @@ 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();
String output = strPrefix + nickname + suffix;
if (!longnick && output.length() > 16) {
output = strPrefix + nickname;
}
if (!longnick && output.length() > 16) {
output = FormatUtil.lastCode(strPrefix) + nickname;
}
if (!longnick && output.length() > 16) {
output = FormatUtil.lastCode(strPrefix) + nickname.substring(0, 14);
}
if (output.charAt(output.length() - 1) == '§') {
output = output.substring(0, output.length() - 1);
}
@@ -386,10 +402,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
if (isAfk()) {
updateAfkListName();
} else if (ess.getSettings().changePlayerListName()) {
// 1.8 enabled player list-names longer than 16 characters.
// If the server is on 1.8 or higher, provide that functionality. Otherwise, keep prior functionality.
boolean higherOrEqualTo1_8 = ReflUtil.getNmsVersionObject().isHigherThanOrEqualTo(ReflUtil.V1_8_R1);
String name = getNick(higherOrEqualTo1_8, ess.getSettings().isAddingPrefixInPlayerlist(), ess.getSettings().isAddingSuffixInPlayerlist());
String name = getNick(ess.getSettings().isAddingPrefixInPlayerlist(), ess.getSettings().isAddingSuffixInPlayerlist());
try {
this.getBase().setPlayerListName(name);
} catch (IllegalArgumentException e) {
@@ -401,15 +414,25 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
}
@Override
public String getDisplayName() {
return super.getBase().getDisplayName() == null || (ess.getSettings().hideDisplayNameInVanish() && isHidden()) ? super.getBase().getName() : super.getBase().getDisplayName();
}
@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;
}
@@ -444,7 +467,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();
@@ -476,7 +499,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);
@@ -487,7 +510,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) {
@@ -498,7 +521,12 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
@Override
public void setAfk(final boolean set) {
final AfkStatusChangeEvent afkEvent = new AfkStatusChangeEvent(this, set);
setAfk(set, AfkStatusChangeEvent.Cause.UNKNOWN);
}
@Override
public void setAfk(boolean set, AfkStatusChangeEvent.Cause cause) {
final AfkStatusChangeEvent afkEvent = new AfkStatusChangeEvent(this, set, cause);
ess.getServer().getPluginManager().callEvent(afkEvent);
if (afkEvent.isCancelled()) {
return;
@@ -516,7 +544,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
_setAfk(set);
updateAfkListName();
}
private void updateAfkListName() {
if (ess.getSettings().isAfkListName()) {
if(isAfk()) {
@@ -528,8 +556,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();
}
@@ -545,7 +578,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());
}
}
@@ -562,14 +595,12 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
sendMessage(tl("haveBeenReleased"));
setJail(null);
if (ess.getSettings().isTeleportBackWhenFreedFromJail()) {
try {
getTeleport().back();
} catch (Exception ex) {
try {
getTeleport().respawn(null, TeleportCause.PLUGIN);
} catch (Exception ex1) {
}
}
CompletableFuture<Boolean> future = new CompletableFuture<>();
getAsyncTeleport().back(future);
future.exceptionally(e -> {
getAsyncTeleport().respawn(null, TeleportCause.PLUGIN, new CompletableFuture<>());
return false;
});
}
return true;
}
@@ -580,7 +611,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
//Returns true if status expired during this check
public boolean checkMuteTimeout(final long currentTime) {
if (getMuteTimeout() > 0 && getMuteTimeout() < currentTime && isMuted()) {
final MuteStatusChangeEvent event = new MuteStatusChangeEvent(this, null, false);
final MuteStatusChangeEvent event = new MuteStatusChangeEvent(this, null, false, getMuteTimeout(), getMuteReason());
ess.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
@@ -594,14 +625,24 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return false;
}
@Deprecated
public void updateActivity(final boolean broadcast) {
updateActivity(broadcast, AfkStatusChangeEvent.Cause.UNKNOWN);
}
public void updateActivity(final boolean broadcast, AfkStatusChangeEvent.Cause cause) {
if (isAfk()) {
setAfk(false);
setAfk(false, cause);
if (broadcast && !isHidden()) {
setDisplayNick();
final String msg = tl("userIsNotAway", getDisplayName());
if (!msg.isEmpty()) {
ess.broadcastMessage(this, msg);
final String selfmsg = tl("userIsNotAwaySelf", getDisplayName());
if (!msg.isEmpty() && ess.getSettings().broadcastAfkMessage()) {
// exclude user from receiving general AFK announcement in favor of personal message
ess.broadcastMessage(this, msg, u -> u == this);
}
if (!selfmsg.isEmpty()) {
this.sendMessage(selfmsg);
}
}
}
@@ -610,13 +651,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);
}
}
@@ -644,12 +685,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);
}
}
}
@@ -671,9 +717,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;
}
@@ -939,4 +983,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();
}
}
@@ -25,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();
}
@@ -150,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;
@@ -190,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) {
@@ -219,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() {
@@ -472,19 +474,42 @@ public abstract class UserData extends PlayerExtension implements IConf {
config.save();
}
private List<String> ignoredPlayers;
private List<UUID> ignoredPlayers;
public List<String> _getIgnoredPlayers() {
return Collections.synchronizedList(config.getStringList("ignore"));
public List<UUID> _getIgnoredPlayers() {
List<UUID> players = new ArrayList<>();
for (String uuid : config.getStringList("ignore")) {
try {
players.add(UUID.fromString(uuid));
} catch (IllegalArgumentException ignored) {}
}
return Collections.synchronizedList(players);
}
@Deprecated
public void setIgnoredPlayers(List<String> players) {
List<UUID> uuids = new ArrayList<>();
for (String player : players) {
User user = ess.getOfflineUser(player);
if (user == null) {
return;
}
uuids.add(user.getBase().getUniqueId());
}
setIgnoredPlayerUUIDs(uuids);
}
public void setIgnoredPlayerUUIDs(List<UUID> players) {
if (players == null || players.isEmpty()) {
ignoredPlayers = Collections.synchronizedList(new ArrayList<String>());
ignoredPlayers = Collections.synchronizedList(new ArrayList<>());
config.removeProperty("ignore");
} else {
ignoredPlayers = players;
config.setProperty("ignore", players);
List<String> uuids = new ArrayList<>();
for (UUID uuid : players) {
uuids.add(uuid.toString());
}
config.setProperty("ignore", uuids);
}
config.save();
}
@@ -499,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;
@@ -795,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));
@@ -805,7 +832,7 @@ public abstract class UserData extends PlayerExtension implements IConf {
}
return timestamps;
}
return new HashMap<String, Long>();
return new HashMap<>();
}
public long getKitTimestamp(String name) {
@@ -844,21 +871,21 @@ 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
@@ -25,7 +25,7 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
private final transient ConcurrentSkipListSet<UUID> keys = new ConcurrentSkipListSet<>();
private final transient ConcurrentSkipListMap<String, UUID> names = new ConcurrentSkipListMap<>();
private final transient ConcurrentSkipListMap<UUID, ArrayList<String>> history = new ConcurrentSkipListMap<>();
private UUIDMap uuidMap;
private final UUIDMap uuidMap;
private final transient Cache<String, User> users;
private static boolean legacy = false;
@@ -53,29 +53,26 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
}
private void loadAllUsersAsync(final IEssentials ess) {
ess.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
synchronized (users) {
final File userdir = new File(ess.getDataFolder(), "userdata");
if (!userdir.exists()) {
return;
}
keys.clear();
users.invalidateAll();
for (String string : userdir.list()) {
if (!string.endsWith(".yml")) {
continue;
}
final String name = string.substring(0, string.length() - 4);
try {
keys.add(UUID.fromString(name));
} catch (IllegalArgumentException ex) {
//Ignore these users till they rejoin.
}
}
uuidMap.loadAllUsers(names, history);
ess.runTaskAsynchronously(() -> {
synchronized (users) {
final File userdir = new File(ess.getDataFolder(), "userdata");
if (!userdir.exists()) {
return;
}
keys.clear();
users.invalidateAll();
for (String string : userdir.list()) {
if (!string.endsWith(".yml")) {
continue;
}
final String name = string.substring(0, string.length() - 4);
try {
keys.add(UUID.fromString(name));
} catch (IllegalArgumentException ex) {
//Ignore these users till they rejoin.
}
}
uuidMap.loadAllUsers(names, history);
}
});
}
@@ -112,9 +109,7 @@ public class UserMap extends CacheLoader<String, User> implements IConf {
} else {
return legacyCacheGet(uuid);
}
} catch (ExecutionException ex) {
return null;
} catch (UncheckedExecutionException ex) {
} catch (ExecutionException | UncheckedExecutionException ex) {
return null;
}
}
@@ -16,7 +16,7 @@ import static com.earth2me.essentials.I18n.tl;
public class Warps implements IConf, net.ess3.api.IWarps {
private static final Logger logger = Logger.getLogger("Essentials");
private final Map<StringIgnoreCase, EssentialsConf> warpPoints = new HashMap<StringIgnoreCase, EssentialsConf>();
private final Map<StringIgnoreCase, EssentialsConf> warpPoints = new HashMap<>();
private final File warpsFolder;
private final Server server;
@@ -36,11 +36,11 @@ public class Warps implements IConf, net.ess3.api.IWarps {
@Override
public Collection<String> getList() {
final List<String> keys = new ArrayList<String>();
final List<String> keys = new ArrayList<>();
for (StringIgnoreCase stringIgnoreCase : warpPoints.keySet()) {
keys.add(stringIgnoreCase.getString());
}
Collections.sort(keys, String.CASE_INSENSITIVE_ORDER);
keys.sort(String.CASE_INSENSITIVE_ORDER);
return keys;
}
@@ -90,7 +90,7 @@ public class Warps implements IConf, net.ess3.api.IWarps {
try {
uuid = UUID.fromString(conf.getString("lastowner"));
}
catch (Exception ex) {}
catch (Exception ignored) {}
return uuid;
}
@@ -111,11 +111,11 @@ public class Warps implements IConf, net.ess3.api.IWarps {
warpPoints.clear();
File[] listOfFiles = warpsFolder.listFiles();
if (listOfFiles.length >= 1) {
for (int i = 0; i < listOfFiles.length; i++) {
String filename = listOfFiles[i].getName();
if (listOfFiles[i].isFile() && filename.endsWith(".yml")) {
for (File listOfFile : listOfFiles) {
String filename = listOfFile.getName();
if (listOfFile.isFile() && filename.endsWith(".yml")) {
try {
EssentialsConf conf = new EssentialsConf(listOfFiles[i]);
EssentialsConf conf = new EssentialsConf(listOfFile);
conf.load();
String name = conf.getString("name");
if (name != null) {
@@ -42,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"));
@@ -64,7 +66,7 @@ public class Economy {
throw new RuntimeException(noCallBeforeLoad);
}
if (name == null) {
throw new RuntimeException("Economy username cannot be null");
throw new IllegalArgumentException("Economy username cannot be null");
}
User user = ess.getUser(name);
@@ -86,9 +88,20 @@ public class Economy {
return user;
}
private static User getUserByUUID(UUID uuid) {
if (ess == null) {
throw new RuntimeException(noCallBeforeLoad);
}
if (uuid == null) {
throw new IllegalArgumentException("Economy uuid cannot be null");
}
return ess.getUser(uuid);
}
/**
* Returns the balance of a user
*
* @deprecated Use {@link Economy#getMoneyExact(UUID)} or {@link Economy#getMoneyExact(User)}
* @param name Name of the user
*
* @return balance
@@ -107,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
*
@@ -133,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();
}
@@ -149,12 +230,14 @@ public class Economy {
} 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
*
@@ -170,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
@@ -190,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
*
@@ -218,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
*
@@ -242,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);
@@ -265,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
*
@@ -282,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
*
@@ -304,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
*
@@ -326,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
*
@@ -339,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;
}
/**
@@ -370,14 +887,28 @@ public class Economy {
/**
* Test if a player exists to avoid the UserDoesNotExistException
*
* @deprecated Essentials is moving away from username based economy methods. This may be removed in the future.
*
* @param name Name of the user
*
* @return true, if the user exists
*/
@Deprecated
public static boolean playerExists(String name) {
return getUserByName(name) != null;
}
/**
* Test if a player exists to avoid the UserDoesNotExistException
*
* @param uuid UUID of the user
*
* @return true, if the user exists
*/
public static boolean playerExists(UUID uuid) {
return getUserByUUID(uuid) != null;
}
/**
* Test if a player is a npc
*
@@ -0,0 +1,123 @@
package com.earth2me.essentials.api;
import com.earth2me.essentials.Trade;
import net.ess3.api.IUser;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent;
import java.util.concurrent.CompletableFuture;
public interface IAsyncTeleport {
/**
* Used to skip teleportPlayer delay when teleporting someone to a location or player.
*
* @param loc - Where should the player end up
* @param cooldown - If cooldown should be enforced
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void now(Location loc, boolean cooldown, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Used to skip teleportPlayer delay when teleporting someone to a location or player.
*
* @param entity - Where should the player end up
* @param cooldown - If cooldown should be enforced
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void now(Player entity, boolean cooldown, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport a player to a specific location
*
* @param loc - Where should the player end up
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param cause - The reported teleportPlayer cause.
* @param future - Future which is completed with the success status of the execution
*/
void teleport(Location loc, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport a player to a specific player
*
* @param entity - Where should the player end up
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void teleport(Player entity, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport a player to a specific location
*
* @param otherUser - Which user will be teleported
* @param loc - Where should the player end up
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void teleportPlayer(IUser otherUser, Location loc, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport a player to a specific player
*
* @param otherUser - Which user will be teleported
* @param entity - Where should the player end up
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void teleportPlayer(IUser otherUser, Player entity, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport wrapper used to handle tp fallback on /jail and /home
*
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void respawn(final Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport wrapper used to handle /warp teleports
*
* @param otherUser - Which user will be teleported
* @param warp - The name of the warp the user will be teleported too.
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param cause - The reported teleportPlayer cause
* @param future - Future which is completed with the success status of the execution
*/
void warp(IUser otherUser, String warp, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause, CompletableFuture<Boolean> future);
/**
* Teleport wrapper used to handle /back teleports
*
* @param chargeFor - What the user will be charged if teleportPlayer is successful
* @param future - Future which is completed with the success status of the execution
*/
void back(Trade chargeFor, CompletableFuture<Boolean> future);
/**
* Teleport wrapper used to handle /back teleports that
* are executed by a different player with this
* instance of teleport as a target.
*
* @param teleporter - The user performing the /back command.
* This value may be {@code null} to indicate console.
* @param chargeFor - What the {@code teleporter} will be charged if teleportPlayer is successful
* @param future - Future which is completed with the success status of the execution
*/
void back(IUser teleporter, Trade chargeFor, CompletableFuture<Boolean> future);
/**
* Teleport wrapper used to handle throwing user home after a jail sentence
*
* @param future - Future which is completed with the success status of the execution
*/
void back(CompletableFuture<Boolean> future);
}
@@ -1,11 +1,9 @@
package com.earth2me.essentials.api;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import net.ess3.api.IEssentials;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
@@ -55,7 +53,7 @@ public interface IItemDb {
nameList = nameList.subList(0, 14);
}
return StringUtil.joinList(", ", nameList);
};
}
/**
* Get a List of all aliases for the given item stack.
@@ -85,13 +83,12 @@ public interface IItemDb {
List<ItemStack> getMatching(User user, String[] args) throws Exception;
/**
* Serialise an ItemStack into a format that can be decoded by
* {@link #get(String) get} and
* {@link com.earth2me.essentials.MetaItemStack#parseStringMeta(CommandSource, boolean, String[], int, IEssentials)} MetaItemStack#parseStringMeta}.
* Used to encode items for kits.
* Converts the given {@link ItemStack} to a string representation that can be saved.
* This is typically used for /createkit but can be used by other plugins for various purposes too.
* Note that this will try registered resolvers first - to avoid this, use {@link net.ess3.api.IItemDb#serialize(ItemStack, boolean)} instead.
*
* @param is Stack to serialise
* @return Serialised stack
* @param is The stack to serialize
* @return A string representing the given stack
*/
String serialize(ItemStack is);
@@ -4,6 +4,7 @@ import net.ess3.api.IUser;
import org.bukkit.Location;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
public interface IJails extends IReload {
@@ -46,13 +47,27 @@ public interface IJails extends IReload {
/**
* Attempts to send the given user to the given jail
*
* @deprecated Use {@link IJails#sendToJail(IUser, String, CompletableFuture)}
*
* @param user the user to send to jail
* @param jail the jail to send the user to
*
* @throws Exception if the user is offline or jail does not exist
*/
@Deprecated
void sendToJail(IUser user, String jail) throws Exception;
/**
* Attempts to send the given user to the given jail
*
* @param user the user to send to jail
* @param jail the jail to send the user to
* @param future Future which is completed with the success status of the execution
*
* @throws Exception if the user is offline or jail does not exist
*/
void sendToJail(IUser user, String jail, CompletableFuture<Boolean> future) throws Exception;
/**
* Set a new jail with the given name and location
*
@@ -7,6 +7,9 @@ import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent;
/**
* @deprecated This API is not asynchronous. Use {@link com.earth2me.essentials.api.IAsyncTeleport IAsyncTeleport}
*/
public interface ITeleport {
/**
* Used to skip teleportPlayer delay when teleporting someone to a location or player.
@@ -17,6 +20,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void now(Location loc, boolean cooldown, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -28,6 +32,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void now(Player entity, boolean cooldown, PlayerTeleportEvent.TeleportCause cause) throws Exception;
@Deprecated
@@ -42,6 +47,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void teleport(Location loc, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -53,6 +59,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void teleport(Player entity, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -65,6 +72,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void teleportPlayer(IUser otherUser, Location loc, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -77,6 +85,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void teleportPlayer(IUser otherUser, Player entity, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -87,6 +96,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void respawn(final Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -99,6 +109,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void warp(IUser otherUser, String warp, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception;
/**
@@ -108,6 +119,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void back(Trade chargeFor) throws Exception;
/**
@@ -117,10 +129,11 @@ public interface ITeleport {
*
* @param teleporter - The user performing the /back command.
* This value may be {@code null} to indicate console.
* @param chargeFor - What the {@code teleporter} will be charged if teleportPlayer is successful
* @param chargeFor - What the {@code teleporter} will be charged if teleportPlayer is successful
*
* @throws Exception
*/
@Deprecated
void back(IUser teleporter, Trade chargeFor) throws Exception;
/**
@@ -128,6 +141,7 @@ public interface ITeleport {
*
* @throws Exception
*/
@Deprecated
void back() throws Exception;
}
@@ -70,7 +70,7 @@ public interface IWarps extends IConf {
/**
* Gets Lastowner UUID
*
* @param name - Name of warp
* @param warp - Name of warp
*
* @throws WarpNotFoundException
*/
@@ -1,5 +1,7 @@
package com.earth2me.essentials.api;
import java.util.UUID;
import static com.earth2me.essentials.I18n.tl;
@@ -7,4 +9,8 @@ public class UserDoesNotExistException extends Exception {
public UserDoesNotExistException(String name) {
super(tl("userDoesNotExist", name));
}
public UserDoesNotExistException(UUID uuid) {
super(tl("uuidDoesNotExist", uuid.toString()));
}
}
@@ -2,6 +2,8 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.DateUtil;
import net.ess3.api.events.AfkStatusChangeEvent;
import org.bukkit.Server;
import java.util.Collections;
@@ -47,7 +49,11 @@ public class Commandafk extends EssentialsCommand {
private void toggleAfk(User sender, User user, String message) throws Exception {
if (message != null && sender != null) {
if (sender.isMuted()) {
throw new Exception(sender.hasMuteReason() ? tl("voiceSilencedReason", sender.getMuteReason()) : tl("voiceSilenced"));
String dateDiff = sender.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(sender.getMuteTimeout()) : null;
if (dateDiff == null) {
throw new Exception(sender.hasMuteReason() ? tl("voiceSilencedReason", sender.getMuteReason()) : tl("voiceSilenced"));
}
throw new Exception(sender.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, sender.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
}
if (!sender.isAuthorized("essentials.afk.message")) {
throw new Exception(tl("noPermToAFKMessage"));
@@ -55,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
}
@@ -4,10 +4,7 @@ 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;
@@ -23,40 +20,29 @@ public class Commandback extends EssentialsCommand {
protected void run(Server server, User user, String commandLabel, String[] args) throws Exception {
CommandSource sender = user.getSource();
if (args.length > 0 && user.isAuthorized("essentials.back.others")) {
this.parseCommand(server, sender, args, true);
parseOthers(server, sender, args, commandLabel);
return;
}
teleportBack(sender, user);
teleportBack(sender, user, commandLabel);
}
@Override
protected void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
if (args.length < 1) {
if (args.length == 0) {
throw new NotEnoughArgumentsException();
}
this.parseCommand(server, sender, args, true);
parseOthers(server, sender, args, commandLabel);
}
private void parseCommand(Server server, CommandSource sender, String[] args, boolean allowOthers) 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));
}
private void parseOthers(Server server, CommandSource sender, String[] args, String commandLabel) throws Exception {
User player = getPlayer(server, args, 0, true, false);
sender.sendMessage(tl("backOther", player.getName()));
teleportBack(sender, player, commandLabel);
}
private void teleportBack(CommandSource sender, User user) throws Exception {
private void teleportBack(CommandSource sender, User user, String commandLabel) throws Exception {
if (user.getLastLocation() == null) {
throw new Exception(tl("noLocationFound"));
}
@@ -77,15 +63,15 @@ public class Commandback extends EssentialsCommand {
}
if (requester == null) {
user.getTeleport().back(null, null);
user.getAsyncTeleport().back(null, null, getNewExceptionFuture(sender, commandLabel));
} else if (!requester.equals(user)) {
Trade charge = new Trade(this.getName(), this.ess);
charge.isAffordableFor(requester);
user.getTeleport().back(requester, charge);
user.getAsyncTeleport().back(requester, charge, getNewExceptionFuture(sender, commandLabel));
} else {
Trade charge = new Trade(this.getName(), this.ess);
charge.isAffordableFor(user);
user.getTeleport().back(charge);
user.getAsyncTeleport().back(charge, getNewExceptionFuture(sender, commandLabel));
}
throw new NoChargeException();
}
@@ -5,7 +5,6 @@ import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.NumberUtil;
import org.bukkit.Server;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
@@ -19,11 +18,11 @@ public class Commandbalance extends EssentialsCommand {
@Override
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
if (args.length == 0) {
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)));
}
@@ -31,11 +30,9 @@ public class Commandbalance extends EssentialsCommand {
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length == 1 && user.isAuthorized("essentials.balance.others")) {
final User target = getPlayer(server, args, 0, true, true);
final BigDecimal bal = target.getMoney();
user.sendMessage(tl("balanceOther", target.isHidden() ? target.getName() : target.getDisplayName(), NumberUtil.displayCurrency(bal, ess)));
user.sendMessage(tl("balanceOther", target.isHidden() ? target.getName() : target.getDisplayName(), NumberUtil.displayCurrency(target.getMoney(), ess)));
} else if (args.length < 2) {
final BigDecimal bal = user.getMoney();
user.sendMessage(tl("balance", NumberUtil.displayCurrency(bal, ess)));
user.sendMessage(tl("balance", NumberUtil.displayCurrency(user.getMoney(), ess)));
} else {
throw new NotEnoughArgumentsException();
}
@@ -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;
@@ -45,7 +44,7 @@ public class Commandbalancetop extends EssentialsCommand {
if (!force && lock.readLock().tryLock()) {
try {
if (cacheage > System.currentTimeMillis() - CACHETIME) {
outputCache(sender, commandLabel, page);
outputCache(sender, page);
return;
}
if (ess.getUserMap().getUniqueUsers() > MINUSERS) {
@@ -54,17 +53,16 @@ public class Commandbalancetop extends EssentialsCommand {
} finally {
lock.readLock().unlock();
}
ess.runTaskAsynchronously(new Viewer(sender, commandLabel, page, force));
} else {
if (ess.getUserMap().getUniqueUsers() > MINUSERS) {
sender.sendMessage(tl("orderBalances", ess.getUserMap().getUniqueUsers()));
}
ess.runTaskAsynchronously(new Viewer(sender, commandLabel, page, force));
}
ess.runTaskAsynchronously(new Viewer(sender, commandLabel, page, force));
}
private static void outputCache(final CommandSource sender, String command, int page) {
private static void outputCache(final CommandSource sender, int page) {
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(cacheage);
final DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
@@ -88,7 +86,7 @@ public class Commandbalancetop extends EssentialsCommand {
try {
if (force || cacheage <= System.currentTimeMillis() - CACHETIME) {
cache.getLines().clear();
final Map<String, BigDecimal> balances = new HashMap<String, BigDecimal>();
final Map<String, BigDecimal> balances = new HashMap<>();
BigDecimal totalMoney = BigDecimal.ZERO;
if (ess.getSettings().isEcoDisabled()) {
if (ess.getSettings().isDebug()) {
@@ -113,13 +111,8 @@ public class Commandbalancetop extends EssentialsCommand {
}
}
final List<Map.Entry<String, BigDecimal>> sortedEntries = new ArrayList<Map.Entry<String, BigDecimal>>(balances.entrySet());
Collections.sort(sortedEntries, new Comparator<Map.Entry<String, BigDecimal>>() {
@Override
public int compare(final Entry<String, BigDecimal> entry1, final Entry<String, BigDecimal> entry2) {
return entry2.getValue().compareTo(entry1.getValue());
}
});
final List<Map.Entry<String, BigDecimal>> sortedEntries = new ArrayList<>(balances.entrySet());
sortedEntries.sort((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue()));
cache.getLines().add(tl("serverTotal", NumberUtil.displayCurrency(totalMoney, ess)));
int pos = 1;
@@ -155,7 +148,7 @@ public class Commandbalancetop extends EssentialsCommand {
lock.readLock().lock();
try {
if (!force && cacheage > System.currentTimeMillis() - CACHETIME) {
outputCache(sender, commandLabel, page);
outputCache(sender, page);
return;
}
} finally {
@@ -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 (loc.getBlock().getType().isSolid()) {
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,10 +17,8 @@ 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);
if (block == null) {
throw new NoChargeException();
}
final Block block = user.getBase().getTargetBlock(null, 20);
if (block.getType() == Material.AIR) {
throw new NoChargeException();
}
@@ -1,7 +1,5 @@
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.textreader.IText;
@@ -9,7 +7,6 @@ import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.utils.FormatUtil;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Player;
@@ -18,6 +15,8 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandbroadcastworld extends EssentialsCommand {
@@ -27,12 +26,13 @@ public class Commandbroadcastworld extends EssentialsCommand {
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length == 0) {
throw new NotEnoughArgumentsException();
}
World world = user.getWorld();
String message = getFinalArg(args, 0);
if (args.length < 1) {
throw new NotEnoughArgumentsException();
} else if (args.length > 1 && ess.getSettings().isAllowWorldInBroadcastworld()) {
if (args.length > 1 && ess.getSettings().isAllowWorldInBroadcastworld()) {
World argWorld = ess.getWorld(args[0]);
if (argWorld != null) {
world = argWorld;
@@ -40,12 +40,7 @@ public class Commandbroadcastworld extends EssentialsCommand {
}
}
if (world == null) {
world = user.getWorld();
message = getFinalArg(args, 0);
}
sendBroadcast(world.getName(), user.getDisplayName(), message);
sendBroadcast(world, user.getDisplayName(), message);
}
@Override
@@ -53,14 +48,15 @@ public class Commandbroadcastworld extends EssentialsCommand {
if (args.length < 2) {
throw new NotEnoughArgumentsException("world");
}
sendBroadcast(args[0], sender.getSender().getName(), getFinalArg(args, 1));
}
private void sendBroadcast(final String worldName, final String name, final String message) throws Exception {
World world = ess.getWorld(worldName);
World world = ess.getWorld(args[0]);
if (world == null) {
throw new Exception(tl("invalidWorld"));
}
sendBroadcast(world, sender.getSender().getName(), getFinalArg(args, 1));
}
private void sendBroadcast(final World world, final String name, final String message) throws Exception {
if (message.isEmpty()) {
throw new NotEnoughArgumentsException();
}
@@ -21,10 +21,6 @@ public class Commandburn extends EssentialsCommand {
throw new NotEnoughArgumentsException();
}
if (args[0].trim().length() < 2) {
throw new NotEnoughArgumentsException();
}
User user = getPlayer(server, sender, args, 0);
user.getBase().setFireTicks(Integer.parseInt(args[1]) * 20);
sender.sendMessage(tl("burnMsg", user.getDisplayName(), Integer.parseInt(args[1])));
@@ -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,133 +13,135 @@ import org.bukkit.inventory.ItemStack;
import java.util.*;
import static com.earth2me.essentials.I18n.tl;
public class Commandclearinventory extends EssentialsCommand {
public class Commandclearinventory extends EssentialsLoopCommand {
public Commandclearinventory() {
super("clearinventory");
}
private static final int BASE_AMOUNT = 100000;
private static final int EXTENDED_CAP = 8;
@Override
public void run(Server server, User user, String commandLabel, String[] args) throws Exception {
parseCommand(server, user.getSource(), commandLabel, args, user.isAuthorized("essentials.clearinventory.others"),
user.isAuthorized("essentials.clearinventory.all") || user.isAuthorized("essentials.clearinventory.multiple"));
}
final String previousClearCommand = user.getConfirmingClearCommand();
user.setConfirmingClearCommand(null);
@Override
protected void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
parseCommand(server, sender, commandLabel, args, true, true);
}
private void parseCommand(Server server, CommandSource sender, String commandLabel, String[] args, boolean allowOthers, boolean allowAll)
throws Exception {
Collection<Player> players = new ArrayList<Player>();
User senderUser = ess.getUser(sender.getPlayer());
String previousClearCommand = "";
int offset = 0;
if (sender.isPlayer()) {
players.add(sender.getPlayer());
// Clear previous command execution before potential errors to reset confirmation.
previousClearCommand = senderUser.getConfirmingClearCommand();
senderUser.setConfirmingClearCommand(null);
}
if (allowAll && args.length > 0 && args[0].contentEquals("*")) {
sender.sendMessage(tl("inventoryClearingFromAll"));
offset = 1;
players = ess.getOnlinePlayers();
} else if (allowOthers && args.length > 0 && args[0].trim().length() > 2) {
offset = 1;
players = server.matchPlayer(args[0].trim());
}
if (players.size() < 1) {
throw new PlayerNotFoundException();
}
// Confirm
String formattedCommand = formatCommand(commandLabel, args);
if (senderUser != null && senderUser.isPromptingClearConfirm()) {
if (user.isPromptingClearConfirm()) {
if (!formattedCommand.equals(previousClearCommand)) {
senderUser.setConfirmingClearCommand(formattedCommand);
senderUser.sendMessage(tl("confirmClear", formattedCommand));
user.setConfirmingClearCommand(formattedCommand);
user.sendMessage(tl("confirmClear", formattedCommand));
return;
}
}
for (Player player : players) {
clearHandler(sender, player, args, offset, players.size() < EXTENDED_CAP);
if (args.length == 0 || (!args[0].contains("*") && server.matchPlayer(args[0]).isEmpty())) {
clearHandler(user.getSource(), user.getBase(), args, 0);
return;
}
if (user.isAuthorized("essentials.clearinventory.others")) {
loopOnlinePlayers(server, user.getSource(), false, true, args[0], args);
return;
}
throw new PlayerNotFoundException();
}
@Override
protected void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
if (args.length == 0) {
throw new NotEnoughArgumentsException();
}
loopOnlinePlayers(server, sender, false, true, args[0], args);
}
@Override
protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) {
clearHandler(sender, player.getBase(), args, 1);
}
private static class Item {
private final Material material;
private final short data;
public Item(Material material, short data) {
this.material = material;
this.data = data;
}
public Material getMaterial() {
return material;
}
public short getData() {
return data;
}
}
protected void clearHandler(CommandSource sender, Player player, String[] args, int offset, boolean showExtended) throws Exception {
short data = -1;
int type = -1;
private enum ClearHandlerType {
ALL_EXCEPT_ARMOR, ALL_INCLUDING_ARMOR, SPECIFIC_ITEM
}
protected void clearHandler(CommandSource sender, Player player, String[] args, int offset) {
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 (showExtended) {
sender.sendMessage(tl("inventoryClearingAllItems", player.getDisplayName()));
}
if (type == ClearHandlerType.ALL_EXCEPT_ARMOR) {
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
{
if (showExtended) {
sender.sendMessage(tl("inventoryClearingAllArmor", player.getDisplayName()));
}
} else if (type == ClearHandlerType.ALL_INCLUDING_ARMOR) {
sender.sendMessage(tl("inventoryClearingAllArmor", player.getDisplayName()));
InventoryWorkaround.clearInventoryNoArmor(player.getInventory());
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) {
if (removedAmount > 0) {
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);
} else {
if (showExtended) {
sender.sendMessage(tl("inventoryClearFail", player.getDisplayName(), amount, stack.getType().toString().toLowerCase(Locale.ENGLISH)));
}
}
}
}
@@ -195,6 +195,6 @@ public class Commandclearinventory extends EssentialsCommand {
}
private String formatCommand(String commandLabel, String[] args) {
return "/" + commandLabel + " " + StringUtil.joinList(" ", (Object[]) args);
return "/" + commandLabel + " " + StringUtil.joinList(" ", args);
}
}
@@ -22,7 +22,7 @@ public class Commandcondense extends EssentialsCommand {
super("condense");
}
private Map<ItemStack, SimpleRecipe> condenseList = new HashMap<>();
private final Map<ItemStack, SimpleRecipe> condenseList = new HashMap<>();
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
@@ -120,7 +120,7 @@ public class Commandcondense extends EssentialsCommand {
}
if (!bestRecipes.isEmpty()) {
if (bestRecipes.size() > 1) {
Collections.sort(bestRecipes, SimpleRecipeComparator.INSTANCE);
bestRecipes.sort(SimpleRecipeComparator.INSTANCE);
}
SimpleRecipe recipe = bestRecipes.get(0);
condenseList.put(stack, recipe);
@@ -171,9 +171,9 @@ public class Commandcondense extends EssentialsCommand {
}
private class SimpleRecipe implements Recipe {
private ItemStack result;
private ItemStack input;
private static class SimpleRecipe implements Recipe {
private final ItemStack result;
private final ItemStack input;
private SimpleRecipe(ItemStack result, ItemStack input) {
this.result = result;
@@ -57,7 +57,7 @@ public class Commandcreatekit extends EssentialsCommand {
}
// Command handler will auto fail if this fails.
long delay = Long.valueOf(args[1]);
long delay = Long.parseLong(args[1]);
String kitname = args[0];
ItemStack[] items = user.getBase().getInventory().getContents();
List<String> list = new ArrayList<>();
@@ -85,46 +85,43 @@ public class Commandcreatekit extends EssentialsCommand {
}
private void uploadPaste(final CommandSource sender, final String kitName, final long delay, final String contents) {
executorService.submit(new Runnable() {
@Override
public void run() {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(PASTE_UPLOAD_URL).openConnection();
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("User-Agent", "EssentialsX plugin");
try (OutputStream os = connection.getOutputStream()) {
os.write(contents.getBytes(Charsets.UTF_8));
}
// Error
if (connection.getResponseCode() >= 400) {
sender.sendMessage(tl("createKitFailed", kitName));
String message = CharStreams.toString(new InputStreamReader(connection.getErrorStream(), Charsets.UTF_8));
ess.getLogger().severe("Error creating kit: " + message);
return;
}
// Read URL
JsonObject object = GSON.fromJson(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8), JsonObject.class);
String pasteUrl = PASTE_URL + object.get("key").getAsString();
connection.disconnect();
String separator = tl("createKitSeparator");
String delayFormat = "0";
if (delay > 0) {
delayFormat = DateUtil.formatDateDiff(System.currentTimeMillis() + (delay * 1000));
}
sender.sendMessage(separator);
sender.sendMessage(tl("createKitSuccess", kitName, delayFormat, pasteUrl));
sender.sendMessage(separator);
if (ess.getSettings().isDebug()) {
ess.getLogger().info(sender.getSender().getName() + " created a kit: " + pasteUrl);
}
} catch (Exception e) {
sender.sendMessage(tl("createKitFailed", kitName));
e.printStackTrace();
executorService.submit(() -> {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(PASTE_UPLOAD_URL).openConnection();
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("User-Agent", "EssentialsX plugin");
try (OutputStream os = connection.getOutputStream()) {
os.write(contents.getBytes(Charsets.UTF_8));
}
// Error
if (connection.getResponseCode() >= 400) {
sender.sendMessage(tl("createKitFailed", kitName));
String message = CharStreams.toString(new InputStreamReader(connection.getErrorStream(), Charsets.UTF_8));
ess.getLogger().severe("Error creating kit: " + message);
return;
}
// Read URL
JsonObject object = GSON.fromJson(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8), JsonObject.class);
String pasteUrl = PASTE_URL + object.get("key").getAsString();
connection.disconnect();
String separator = tl("createKitSeparator");
String delayFormat = "0";
if (delay > 0) {
delayFormat = DateUtil.formatDateDiff(System.currentTimeMillis() + (delay * 1000));
}
sender.sendMessage(separator);
sender.sendMessage(tl("createKitSuccess", kitName, delayFormat, pasteUrl));
sender.sendMessage(separator);
if (ess.getSettings().isDebug()) {
ess.getLogger().info(sender.getSender().getName() + " created a kit: " + pasteUrl);
}
} catch (Exception e) {
sender.sendMessage(tl("createKitFailed", kitName));
e.printStackTrace();
}
});
}
@@ -55,22 +55,25 @@ public class Commanddelhome extends EssentialsCommand {
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
User user = ess.getUser(sender.getPlayer());
boolean canDelOthers = (user == null || user.isAuthorized("essentials.delhome.others"));
boolean canDelOthers = user == null || user.isAuthorized("essentials.delhome.others");
if (args.length == 1) {
List<String> homes = user == null ? new ArrayList<>() : user.getHomes();
if (canDelOthers) {
return getPlayers(server, sender);
} else {
return user.getHomes();
}
} else if (args.length == 2 && canDelOthers) {
try {
user = getPlayer(server, args, 0, true, true);
return user.getHomes();
} catch (Exception ex) {
// No such user
return Collections.emptyList();
int sepIndex = args[0].indexOf(':');
if (sepIndex < 0) {
getPlayers(server, sender).forEach(player -> homes.add(player + ":"));
} else {
String namePart = args[0].substring(0, sepIndex);
User otherUser;
try {
otherUser = getPlayer(server, new String[]{namePart}, 0, true, true);
} catch (Exception ex) {
return homes;
}
otherUser.getHomes().forEach(home -> homes.add(namePart + ":" + home));
}
}
return homes;
} else {
return Collections.emptyList();
}
@@ -15,7 +15,7 @@ public class Commanddeljail extends EssentialsCommand {
@Override
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
if (args.length == 0) {
throw new NotEnoughArgumentsException();
}
@@ -18,12 +18,12 @@ public class Commanddelkit extends EssentialsCommand {
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
if (args.length == 0) {
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 = args[0];
final String kitName = ess.getKits().matchKit(args[0]);
final Kit kit = new Kit(kitName, ess);
if (sender.getPlayer() != null) {
@@ -17,7 +17,7 @@ public class Commanddelwarp extends EssentialsCommand {
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
if (args.length == 0) {
throw new NotEnoughArgumentsException();
}
@@ -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) {
@@ -18,8 +18,6 @@ import static com.earth2me.essentials.I18n.tl;
public class Commandeco extends EssentialsLoopCommand {
Commandeco.EcoCommands cmd;
BigDecimal amount;
public Commandeco() {
super("eco");
@@ -31,71 +29,49 @@ public class Commandeco extends EssentialsLoopCommand {
throw new NotEnoughArgumentsException();
}
BigDecimal startingBalance = ess.getSettings().getStartingBalance();
EcoCommands cmd;
boolean isPercent;
BigDecimal amount;
try {
cmd = Commandeco.EcoCommands.valueOf(args[0].toUpperCase(Locale.ENGLISH));
amount = (cmd == Commandeco.EcoCommands.RESET) ? startingBalance : new BigDecimal(args[2].replaceAll("[^0-9\\.]", ""));
cmd = EcoCommands.valueOf(args[0].toUpperCase(Locale.ENGLISH));
isPercent = cmd != EcoCommands.RESET && args[2].endsWith("%");
amount = (cmd == EcoCommands.RESET) ? ess.getSettings().getStartingBalance() : new BigDecimal(args[2].replaceAll("[^0-9\\.]", ""));
} catch (Exception ex) {
throw new NotEnoughArgumentsException(ex);
}
loopOfflinePlayers(server, sender, false, true, args[1], args);
if (cmd == Commandeco.EcoCommands.RESET || cmd == Commandeco.EcoCommands.SET) {
if (args[1].contentEquals("**")) {
server.broadcastMessage(tl("resetBalAll", NumberUtil.displayCurrency(amount, ess)));
} else if (args[1].contentEquals("*")) {
server.broadcastMessage(tl("resetBal", NumberUtil.displayCurrency(amount, ess)));
loopOfflinePlayersConsumer(server, sender, false, true, args[1], player -> {
BigDecimal userAmount = amount;
if (isPercent) {
userAmount = player.getMoney().multiply(userAmount).scaleByPowerOfTen(-2);
}
}
}
@Override
protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) throws NotEnoughArgumentsException, ChargeException, MaxMoneyException {
switch (cmd) {
case GIVE:
player.giveMoney(amount, sender, UserBalanceUpdateEvent.Cause.COMMAND_ECO);
break;
case TAKE:
take(amount, player, sender);
break;
case RESET:
case SET:
set(amount, player, sender);
break;
}
}
private void take(BigDecimal amount, final User player, final CommandSource sender) throws ChargeException {
BigDecimal money = player.getMoney();
BigDecimal minBalance = ess.getSettings().getMinMoney();
if (money.subtract(amount).compareTo(minBalance) >= 0) {
player.takeMoney(amount, sender, UserBalanceUpdateEvent.Cause.COMMAND_ECO);
} else if (sender == null) {
try {
player.setMoney(minBalance, UserBalanceUpdateEvent.Cause.COMMAND_ECO);
} catch (MaxMoneyException ex) {
// Take shouldn't be able to throw a max money exception
switch (cmd) {
case GIVE: {
player.giveMoney(userAmount, sender, UserBalanceUpdateEvent.Cause.COMMAND_ECO);
break;
}
case TAKE: {
if (player.getMoney().subtract(userAmount).compareTo(ess.getSettings().getMinMoney()) >= 0) {
player.takeMoney(userAmount, sender, UserBalanceUpdateEvent.Cause.COMMAND_ECO);
} else {
ess.showError(sender, new Exception(tl("minimumBalanceError", NumberUtil.displayCurrency(ess.getSettings().getMinMoney(), ess))), commandLabel);
}
break;
}
case RESET:
case SET: {
BigDecimal minBal = ess.getSettings().getMinMoney();
BigDecimal maxBal = ess.getSettings().getMaxMoney();
boolean underMin = (userAmount.compareTo(minBal) < 0);
boolean aboveMax = (userAmount.compareTo(maxBal) > 0);
player.setMoney(underMin ? minBal : aboveMax ? maxBal : userAmount, UserBalanceUpdateEvent.Cause.COMMAND_ECO);
player.sendMessage(tl("setBal", NumberUtil.displayCurrency(player.getMoney(), ess)));
sender.sendMessage(tl("setBalOthers", player.getDisplayName(), NumberUtil.displayCurrency(player.getMoney(), ess)));
break;
}
}
player.sendMessage(tl("takenFromAccount", NumberUtil.displayCurrency(player.getMoney(), ess)));
} else {
throw new ChargeException(tl("insufficientFunds"));
}
}
private void set(BigDecimal amount, final User player, final CommandSource sender) throws MaxMoneyException {
BigDecimal minBalance = ess.getSettings().getMinMoney();
BigDecimal maxBalance = ess.getSettings().getMaxMoney();
boolean underMinimum = (amount.compareTo(minBalance) < 0);
boolean aboveMax = (amount.compareTo(maxBalance) > 0);
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)));
}
});
}
@@ -103,6 +79,11 @@ public class Commandeco extends EssentialsLoopCommand {
GIVE, TAKE, SET, RESET
}
@Override
protected void updatePlayer(Server server, CommandSource sender, User user, String[] args) throws NotEnoughArgumentsException, PlayerExemptException, ChargeException, MaxMoneyException {
}
@Override
protected List<String> getTabCompleteOptions(Server server, final CommandSource sender, String commandLabel, String[] args) {
if (args.length == 1) {
@@ -0,0 +1,82 @@
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 if (args.length == 3 && args[0].equalsIgnoreCase("set") && NumberUtil.isPositiveInt(args[1])) {
int line = Integer.parseInt(args[1]);
Block target = user.getBase().getTargetBlock(null, 5);
if (target.getState() instanceof Sign && line <= 4) {
Sign sign = (Sign) target.getState();
return Lists.newArrayList(FormatUtil.unformatString(user, "essentials.editsign", sign.getLine(line - 1)));
}
return Collections.emptyList();
} else {
return Collections.emptyList();
}
}
}
@@ -11,13 +11,7 @@ import org.bukkit.Server;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import java.util.Collections;
import java.util.ArrayList;
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;
@@ -34,16 +28,16 @@ public class Commandenchant extends EssentialsCommand {
if (stack == null || stack.getType() == Material.AIR) {
throw new Exception(tl("nothingInHand"));
}
if (args.length == 0) {
final Set<String> enchantmentslist = new TreeSet<>();
final Set<String> usableEnchants = new TreeSet<>();
for (Map.Entry<String, Enchantment> entry : Enchantments.entrySet()) {
final String enchantmentName = entry.getValue().getName().toLowerCase(Locale.ENGLISH);
if (enchantmentslist.contains(enchantmentName) || (user.isAuthorized("essentials.enchantments." + enchantmentName) && entry.getValue().canEnchantItem(stack))) {
enchantmentslist.add(entry.getKey());
//enchantmentslist.add(enchantmentName);
final String name = entry.getValue().getName().toLowerCase(Locale.ENGLISH);
if (usableEnchants.contains(name) || (user.isAuthorized("essentials.enchantments." + name) && entry.getValue().canEnchantItem(stack))) {
usableEnchants.add(entry.getKey());
}
}
throw new NotEnoughArgumentsException(tl("enchantments", StringUtil.joinList(enchantmentslist.toArray())));
throw new NotEnoughArgumentsException(tl("enchantments", StringUtil.joinList(usableEnchants.toArray())));
}
int level = 1;
@@ -51,23 +45,20 @@ public class Commandenchant extends EssentialsCommand {
try {
level = Integer.parseInt(args[1]);
} catch (NumberFormatException ex) {
level = -1;
throw new NotEnoughArgumentsException();
}
}
final boolean allowUnsafe = ess.getSettings().allowUnsafeEnchantments() && user.isAuthorized("essentials.enchantments.allowunsafe");
final MetaItemStack metaStack = new MetaItemStack(stack);
final Enchantment enchantment = metaStack.getEnchantment(user, args[0]);
metaStack.addEnchantment(user.getSource(), allowUnsafe, enchantment, level);
metaStack.addEnchantment(user.getSource(), ess.getSettings().allowUnsafeEnchantments() && user.isAuthorized("essentials.enchantments.allowunsafe"), enchantment, level);
InventoryWorkaround.setItemInMainHand(user.getBase(), metaStack.getItemStack());
user.getBase().updateInventory();
final String enchantmentName = enchantment.getName().toLowerCase(Locale.ENGLISH);
final String enchantName = enchantment.getName().toLowerCase(Locale.ENGLISH).replace('_', ' ');
if (level == 0) {
user.sendMessage(tl("enchantmentRemoved", enchantmentName.replace('_', ' ')));
user.sendMessage(tl("enchantmentRemoved", enchantName));
} else {
user.sendMessage(tl("enchantmentApplied", enchantmentName.replace('_', ' ')));
user.sendMessage(tl("enchantmentApplied", enchantName));
}
}
@@ -13,17 +13,14 @@ public class Commandenderchest extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
User target = user;
if (args.length > 0 && user.isAuthorized("essentials.enderchest.others")) {
final User invUser = getPlayer(server, user, args, 0);
user.getBase().closeInventory();
user.getBase().openInventory(invUser.getBase().getEnderChest());
user.setEnderSee(true);
} else {
user.getBase().closeInventory();
user.getBase().openInventory(user.getBase().getEnderChest());
user.setEnderSee(false);
target = getPlayer(server, user, args, 0);
}
user.getBase().closeInventory();
user.getBase().openInventory(target.getBase().getEnderChest());
user.setEnderSee(!target.equals(user));
}
@Override
@@ -175,7 +175,7 @@ public class Commandessentials extends EssentialsCommand {
}
// Cow farts.
private void runMoo(final Server server, final CommandSource sender, final String command, final String args[]) {
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 : CONSOLE_MOO) {
logger.info(s);
@@ -197,7 +197,7 @@ public class Commandessentials extends EssentialsCommand {
}
// Cleans up inactive users.
private void runCleanup(final Server server, final CommandSource sender, final String command, final String args[]) throws Exception {
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 haven't logged in in the last <days> days.");
sender.sendMessage("Optional parameters define the minimum amount required to prevent deletion.");
@@ -213,7 +213,7 @@ public class Commandessentials extends EssentialsCommand {
final UserMap userMap = ess.getUserMap();
ess.runTaskAsynchronously(() -> {
Long currTime = System.currentTimeMillis();
long currTime = System.currentTimeMillis();
for (UUID u : userMap.getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
if (user == null) {
@@ -1,223 +1,222 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.SetExpFix;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commandexp extends EssentialsCommand {
public Commandexp() {
super("exp");
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length == 0) {
showExp(user.getSource(), user);
} else if (args.length > 1 && args[0].equalsIgnoreCase("set") && user.isAuthorized("essentials.exp.set")) {
if (args.length == 3 && user.isAuthorized("essentials.exp.set.others")) {
expMatch(server, user.getSource(), args[1], args[2], false);
} else {
setExp(user.getSource(), user, args[1], false);
}
} else if (args.length > 1 && args[0].equalsIgnoreCase("give") && user.isAuthorized("essentials.exp.give")) {
if (args.length == 3 && user.isAuthorized("essentials.exp.give.others")) {
expMatch(server, user.getSource(), args[1], args[2], true);
} else {
setExp(user.getSource(), user, args[1], true);
}
} else if (args.length > 1 && args[0].equalsIgnoreCase("take") && user.isAuthorized("essentials.exp.take")) {
if (args.length == 3 && user.isAuthorized("essentials.exp.take.others")) {
expMatch(server, user.getSource(), args[1], "-" + args[2], true);
} else {
setExp(user.getSource(), user, "-" + args[1], true);
}
} else if (args.length < 3 && args[0].equalsIgnoreCase("reset") && user.isAuthorized("essentials.exp.reset")) {
if (args.length == 2 && user.isAuthorized("essentials.exp.reset.others")) {
expMatch(server, user.getSource(), args[1], "0", false);
} else {
setExp(user.getSource(), user, "0", false);
}
} else if (args[0].equalsIgnoreCase("show")) {
if (args.length >= 2 && user.isAuthorized("essentials.exp.others")) {
String match = args[1].trim();
showMatch(server, user.getSource(), match);
} else {
showExp(user.getSource(), user);
}
} else {
if (args.length >= 1 && NumberUtil.isInt(args[0].toLowerCase(Locale.ENGLISH).replace("l", "")) && user.isAuthorized("essentials.exp.give")) {
if (args.length >= 2 && user.isAuthorized("essentials.exp.give.others")) {
expMatch(server, user.getSource(), args[1], args[0], true);
} else {
setExp(user.getSource(), user, args[0], true);
}
} else if (args.length >= 1 && user.isAuthorized("essentials.exp.others")) {
String match = args[0].trim();
showMatch(server, user.getSource(), match);
} else {
showExp(user.getSource(), user);
}
}
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
throw new NotEnoughArgumentsException();
} else if (args.length > 2 && args[0].equalsIgnoreCase("set")) {
expMatch(server, sender, args[1], args[2], false);
} else if (args.length > 2 && args[0].equalsIgnoreCase("give")) {
expMatch(server, sender, args[1], args[2], true);
} else {
String match = args[0].trim();
if (args.length >= 2 && NumberUtil.isInt(args[0].toLowerCase(Locale.ENGLISH).replace("l", ""))) {
match = args[1].trim();
expMatch(server, sender, match, args[0], true);
} else if (args.length == 1) {
match = args[0].trim();
}
showMatch(server, sender, match);
}
}
private void showMatch(final Server server, final CommandSource sender, final String match) throws PlayerNotFoundException {
boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished();
boolean foundUser = false;
final List<Player> matchedPlayers = server.matchPlayer(match);
for (Player matchPlayer : matchedPlayers) {
final User player = ess.getUser(matchPlayer);
if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) {
continue;
}
foundUser = true;
showExp(sender, player);
}
if (!foundUser) {
throw new PlayerNotFoundException();
}
}
private void expMatch(final Server server, final CommandSource sender, final String match, String amount, final boolean give) throws NotEnoughArgumentsException, PlayerNotFoundException {
boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished();
boolean foundUser = false;
final List<Player> matchedPlayers = server.matchPlayer(match);
for (Player matchPlayer : matchedPlayers) {
final User player = ess.getUser(matchPlayer);
if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) {
continue;
}
foundUser = true;
setExp(sender, player, amount, give);
}
if (!foundUser) {
throw new PlayerNotFoundException();
}
}
private void showExp(final CommandSource sender, final User target) {
sender.sendMessage(tl("exp", target.getDisplayName(), SetExpFix.getTotalExperience(target.getBase()), target.getBase().getLevel(), SetExpFix.getExpUntilNextLevel(target.getBase())));
}
//TODO: Limit who can give negative exp?
private void setExp(final CommandSource sender, final User target, String strAmount, final boolean give) throws NotEnoughArgumentsException {
long amount;
strAmount = strAmount.toLowerCase(Locale.ENGLISH);
if (strAmount.contains("l")) {
strAmount = strAmount.replaceAll("l", "");
int neededLevel = Integer.parseInt(strAmount);
if (give) {
neededLevel += target.getBase().getLevel();
}
amount = (long) SetExpFix.getExpToLevel(neededLevel);
SetExpFix.setTotalExperience(target.getBase(), 0);
} else {
amount = Long.parseLong(strAmount);
if (amount > Integer.MAX_VALUE || amount < Integer.MIN_VALUE) {
throw new NotEnoughArgumentsException();
}
}
if (give) {
amount += SetExpFix.getTotalExperience(target.getBase());
}
if (amount > Integer.MAX_VALUE) {
amount = (long) Integer.MAX_VALUE;
}
if (amount < 0l) {
amount = 0l;
}
SetExpFix.setTotalExperience(target.getBase(), (int) amount);
sender.sendMessage(tl("expSet", target.getDisplayName(), amount));
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
if (args.length == 1) {
List<String> options = Lists.newArrayList("show");
if (user.isAuthorized("essentials.exp.set")) {
options.add("set");
}
if (user.isAuthorized("essentials.exp.give")) {
options.add("give");
}
if (user.isAuthorized("essentials.exp.take")) {
options.add("take");
}
if (user.isAuthorized("essentials.exp.reset")) {
options.add("reset");
}
return options;
} else if (args.length == 2) {
if ((args[0].equalsIgnoreCase("set") && user.isAuthorized("essentials.exp.set")) || (args[0].equalsIgnoreCase("give") && user.isAuthorized("essentials.exp.give"))) {
String levellessArg = args[1].toLowerCase(Locale.ENGLISH).replace("l", "");
if (NumberUtil.isInt(levellessArg)) {
return Lists.newArrayList(levellessArg, args[1] + "l");
} else {
return Collections.emptyList();
}
} else if (args[0].equalsIgnoreCase("show") && user.isAuthorized("essentials.exp.others")) {
return getPlayers(server, user);
} else {
return Collections.emptyList();
}
} else if (args.length == 3 && (args[0].equalsIgnoreCase("set") && user.isAuthorized("essentials.exp.set.others")) || (args[0].equalsIgnoreCase("give") && user.isAuthorized("essentials.exp.give.others"))) {
return getPlayers(server, user);
} else {
return Collections.emptyList();
}
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
// TODO: This seems somewhat buggy, both setting and showing - right now, ignoring that
return Lists.newArrayList("set", "give", "show", "take", "reset");
} else if (args.length == 2) {
if (args[0].equalsIgnoreCase("set") || args[0].equalsIgnoreCase("give")) {
String levellessArg = args[1].toLowerCase(Locale.ENGLISH).replace("l", "");
if (NumberUtil.isInt(levellessArg)) {
return Lists.newArrayList(levellessArg, args[1] + "l");
} else {
return Collections.emptyList();
}
} else { // even without 'show'
return getPlayers(server, sender);
}
} else if (args.length == 3 && (args[0].equalsIgnoreCase("set") || args[0].equalsIgnoreCase("give"))) {
return getPlayers(server, sender);
} else {
return Collections.emptyList();
}
}
}
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.IUser;
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 java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commandexp extends EssentialsLoopCommand {
public Commandexp() {
super("exp");
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
IUser user = sender.getUser(ess);
if (args.length == 0 || (args.length < 2 && user == null)) {
if (user == null) {
throw new NotEnoughArgumentsException();
}
showExp(sender, user);
return;
}
ExpCommands cmd;
try {
cmd = ExpCommands.valueOf(args[0].toUpperCase(Locale.ENGLISH));
} catch (Exception ex) {
throw new NotEnoughArgumentsException(ex);
}
if (!cmd.hasPermission(user)) {
user.sendMessage(tl("noAccessSubCommand", "/" + commandLabel + " " + cmd.name().toLowerCase(Locale.ENGLISH)));
return;
}
switch (cmd) {
case SET: {
if (args.length == 3 && cmd.hasOtherPermission(user)) {
loopOnlinePlayersConsumer(server,sender, false, true, args[1], player -> setExp(sender, player, args[2], false));
} else if (args.length == 2 && user != null) {
setExp(sender, user, args[1], false);
} else {
throw new NotEnoughArgumentsException();
}
return;
}
case GIVE: {
if (args.length == 3 && cmd.hasOtherPermission(user)) {
loopOnlinePlayersConsumer(server, sender, false, true, args[1], player -> setExp(sender, player, args[2], true));
} else if (args.length == 2 && user != null) {
setExp(sender, user, args[1], true);
} else {
throw new NotEnoughArgumentsException();
}
return;
}
case TAKE: {
if (args.length == 3 && cmd.hasOtherPermission(user)) {
loopOnlinePlayersConsumer(server, sender, false, true, args[1], player -> setExp(sender, player, "-" + args[2], true));
} else if (args.length == 2) {
setExp(sender, user, "-" + args[1], true);
} else {
throw new NotEnoughArgumentsException();
}
return;
}
case RESET: {
if (args.length == 2 && cmd.hasOtherPermission(user)) {
loopOnlinePlayersConsumer(server, sender, false, true, args[1], player -> setExp(sender, player, "0", false));
} else if (user != null) {
setExp(sender, user, "0", false);
} else {
throw new NotEnoughArgumentsException();
}
return;
}
case SHOW: {
if (args.length == 2 && (user == null || user.isAuthorized("essentials.exp.others"))) {
showExp(sender, getPlayer(server, sender, args[1]));
} else if (user != null) {
showExp(sender, user);
} else {
throw new NotEnoughArgumentsException();
}
return;
}
}
throw new NotEnoughArgumentsException(); //Should never happen but in the impossible chance it does...
}
private enum ExpCommands {
SET,
GIVE,
TAKE,
RESET,
SHOW(false);
private final boolean permCheck;
ExpCommands() {
permCheck = true;
}
ExpCommands(boolean perm) {
permCheck = perm;
}
boolean hasPermission(IUser user) {
return user == null || !permCheck || user.isAuthorized("essentials.exp." + name().toLowerCase(Locale.ENGLISH));
}
boolean hasOtherPermission(IUser user) {
return user == null || user.isAuthorized("essentials.exp." + name().toLowerCase(Locale.ENGLISH) + ".others");
}
}
private void showExp(final CommandSource sender, final IUser 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 IUser 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 void updatePlayer(Server server, CommandSource sender, User user, String[] args) {
}
@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");
for (ExpCommands cmd : ExpCommands.values()) {
if (cmd.hasPermission(user)) {
options.add(cmd.name().toLowerCase(Locale.ENGLISH));
}
}
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) {
List<String> list = new ArrayList<>();
for (ExpCommands cmd : ExpCommands.values()) {
list.add(cmd.name().toLowerCase(Locale.ENGLISH));
}
return list;
} 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();
}
}
}
@@ -18,7 +18,7 @@ public class Commandext extends EssentialsLoopCommand {
@Override
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
if (args.length == 0) {
throw new NotEnoughArgumentsException();
}
@@ -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);
}
@@ -7,6 +7,7 @@ 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;
@@ -17,6 +18,9 @@ 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 {
@@ -28,12 +32,12 @@ public class Commandfireball extends EssentialsCommand {
.put("skull", WitherSkull.class)
.put("egg", Egg.class)
.put("snowball", Snowball.class)
.put("expbottle", ThrownExpBottle.class)
.put("splashpotion", SplashPotion.class)
.put("lingeringpotion", LingeringPotion.class);
.put("expbottle", ThrownExpBottle.class);
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_9_R01)) {
builder.put("dragon", DragonFireball.class);
builder.put("dragon", DragonFireball.class)
.put("splashpotion", SplashPotion.class)
.put("lingeringpotion", LingeringPotion.class);
}
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_13_0_R01)) {
@@ -49,13 +53,9 @@ public class Commandfireball extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
String type = "fireball";
String type = args.length > 0 && types.containsKey(args[0]) ? args[0] : "fireball";
double speed = 2;
boolean ride = false;
if (args.length > 0 && types.containsKey(args[0])) {
type = args[0];
}
boolean ride = args.length > 2 && args[2].equalsIgnoreCase("ride") && user.isAuthorized("essentials.fireball.ride");
if (args.length > 1) {
try {
@@ -65,10 +65,6 @@ public class Commandfireball extends EssentialsCommand {
}
}
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));
}
@@ -77,6 +73,7 @@ public class Commandfireball extends EssentialsCommand {
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());
@@ -1,178 +1,177 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.DyeColor;
import org.bukkit.FireworkEffect;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Firework;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.FireworkMeta;
import org.bukkit.util.Vector;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
//This command has quite a complicated syntax, in theory it has 4 seperate syntaxes which are all variable:
//
//1: /firework clear - This clears all of the effects on a firework stack
//
//2: /firework power <int> - This changes the base power of a firework
//
//3: /firework fire - This 'fires' a copy of the firework held.
//3: /firework fire <int> - This 'fires' a number of copies of the firework held.
//3: /firework fire <other> - This 'fires' a copy of the firework held, in the direction you are looking, #easteregg
//
//4: /firework [meta] - This will add an effect to the firework stack held
//4: /firework color:<color> - The minimum you need to set an effect is 'color'
//4: Full Syntax: color:<color[,color,..]> [fade:<color[,color,..]>] [shape:<shape>] [effect:<effect[,effect]>]
//4: Possible Shapes: star, ball, large, creeper, burst
//4: Possible Effects trail, twinkle
public class Commandfirework extends EssentialsCommand {
public Commandfirework() {
super("firework");
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final ItemStack stack = user.getItemInHand();
if (MaterialUtil.isFirework(stack.getType())) {
if (args.length > 0) {
if (args[0].equalsIgnoreCase("clear")) {
FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
fmeta.clearEffects();
stack.setItemMeta(fmeta);
user.sendMessage(tl("fireworkEffectsCleared"));
} else if (args.length > 1 && (args[0].equalsIgnoreCase("power") || (args[0].equalsIgnoreCase("p")))) {
FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
try {
int power = Integer.parseInt(args[1]);
fmeta.setPower(power > 3 ? 4 : power);
} catch (NumberFormatException e) {
throw new Exception(tl("invalidFireworkFormat", args[1], args[0]));
}
stack.setItemMeta(fmeta);
} else if ((args[0].equalsIgnoreCase("fire") || (args[0].equalsIgnoreCase("f"))) && user.isAuthorized("essentials.firework.fire")) {
int amount = 1;
boolean direction = false;
if (args.length > 1) {
if (NumberUtil.isInt(args[1])) {
final int serverLimit = ess.getSettings().getSpawnMobLimit();
amount = Integer.parseInt(args[1]);
if (amount > serverLimit) {
amount = serverLimit;
user.sendMessage(tl("mobSpawnLimit"));
}
} else {
direction = true;
}
}
for (int i = 0; i < amount; i++) {
Firework firework = (Firework) user.getWorld().spawnEntity(user.getLocation(), EntityType.FIREWORK);
FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
if (direction) {
final Vector vector = user.getBase().getEyeLocation().getDirection().multiply(0.070);
if (fmeta.getPower() > 1) {
fmeta.setPower(1);
}
firework.setVelocity(vector);
}
firework.setFireworkMeta(fmeta);
}
} else {
final MetaItemStack mStack = new MetaItemStack(stack);
for (String arg : args) {
try {
mStack.addFireworkMeta(user.getSource(), true, arg, ess);
} catch (Exception e) {
user.sendMessage(tl("fireworkSyntax"));
throw e;
}
}
if (mStack.isValidFirework()) {
FireworkMeta fmeta = (FireworkMeta) mStack.getItemStack().getItemMeta();
FireworkEffect effect = mStack.getFireworkBuilder().build();
if (fmeta.getEffects().size() > 0 && !user.isAuthorized("essentials.firework.multiple")) {
throw new Exception(tl("multipleCharges"));
}
fmeta.addEffect(effect);
stack.setItemMeta(fmeta);
} else {
user.sendMessage(tl("fireworkSyntax"));
throw new Exception(tl("fireworkColor"));
}
}
} else {
throw new NotEnoughArgumentsException();
}
} else {
throw new Exception(tl("holdFirework"));
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
// Note: this enforces an order of color fade shape effect, which the actual command doesn't have. But that's fine.
if (args.length == 1) {
List<String> options = Lists.newArrayList();
if (args[0].startsWith("color:")) {
String prefix;
if (args[0].contains(",")) {
prefix = args[0].substring(0, args[0].lastIndexOf(',') + 1);
} else {
prefix = "color:";
}
for (DyeColor color : DyeColor.values()) {
options.add(prefix + color.name().toLowerCase() + ",");
}
return options;
}
options.add("clear");
options.add("power");
options.add("color:");
if (user.isAuthorized("essentials.firework.fire")) {
options.add("fire");
}
return options;
} else if (args.length == 2) {
if (args[0].equals("power")) {
return Lists.newArrayList("1", "2", "3", "4");
} else if (args[0].equals("fire")) {
return Lists.newArrayList("1");
} else if (args[0].startsWith("color:")) {
List<String> options = Lists.newArrayList();
if (!args[1].startsWith("fade:")) {
args[1] = "fade:";
}
String prefix;
if (args[1].contains(",")) {
prefix = args[1].substring(0, args[1].lastIndexOf(',') + 1);
} else {
prefix = "fade:";
}
for (DyeColor color : DyeColor.values()) {
options.add(prefix + color.name().toLowerCase() + ",");
}
return options;
} else {
return Collections.emptyList();
}
} else if (args.length == 3 && args[0].startsWith("color:")) {
return Lists.newArrayList("shape:star", "shape:ball", "shape:large", "shape:creeper", "shape:burst");
} else if (args.length == 4 && args[0].startsWith("color:")) {
return Lists.newArrayList("effect:trail", "effect:twinkle", "effect:trail,twinkle", "effect:twinkle,trail");
} else {
return Collections.emptyList();
}
}
}
package com.earth2me.essentials.commands;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.DyeColor;
import org.bukkit.FireworkEffect;
import org.bukkit.Server;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Firework;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.FireworkMeta;
import org.bukkit.util.Vector;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
//This command has quite a complicated syntax, in theory it has 4 seperate syntaxes which are all variable:
//
//1: /firework clear - This clears all of the effects on a firework stack
//
//2: /firework power <int> - This changes the base power of a firework
//
//3: /firework fire - This 'fires' a copy of the firework held.
//3: /firework fire <int> - This 'fires' a number of copies of the firework held.
//3: /firework fire <other> - This 'fires' a copy of the firework held, in the direction you are looking, #easteregg
//
//4: /firework [meta] - This will add an effect to the firework stack held
//4: /firework color:<color> - The minimum you need to set an effect is 'color'
//4: Full Syntax: color:<color[,color,..]> [fade:<color[,color,..]>] [shape:<shape>] [effect:<effect[,effect]>]
//4: Possible Shapes: star, ball, large, creeper, burst
//4: Possible Effects trail, twinkle
public class Commandfirework extends EssentialsCommand {
public Commandfirework() {
super("firework");
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length == 0) {
throw new NotEnoughArgumentsException();
}
final ItemStack stack = user.getItemInHand();
if (!MaterialUtil.isFirework(stack.getType())) {
throw new Exception(tl("holdFirework"));
}
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"));
}
}
}
@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();
}
}
}
@@ -27,9 +27,8 @@ public class Commandfly extends EssentialsToggleCommand {
if (enabled == null) {
enabled = !user.getBase().getAllowFlight();
}
final User controller = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null;
FlyStatusChangeEvent event = new FlyStatusChangeEvent(user, controller, enabled);
FlyStatusChangeEvent event = new FlyStatusChangeEvent(user, sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null, enabled);
ess.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
@@ -1,11 +1,11 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.IUser;
import com.earth2me.essentials.User;
import com.google.common.collect.ImmutableList;
import org.bukkit.GameMode;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import java.util.Collections;
import java.util.List;
@@ -14,22 +14,19 @@ import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commandgamemode extends EssentialsCommand {
public class Commandgamemode extends EssentialsLoopCommand {
public Commandgamemode() {
super("gamemode");
}
@Override
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
GameMode gameMode;
if (args.length == 0) {
throw new NotEnoughArgumentsException();
} else if (args.length == 1) {
gameMode = matchGameMode(commandLabel);
gamemodeOtherPlayers(server, sender, gameMode, args[0]);
loopOnlinePlayersConsumer(server, sender, false, true, args[0], user -> setUserGamemode(sender, matchGameMode(commandLabel), user));
} else if (args.length == 2) {
gameMode = matchGameMode(args[0].toLowerCase(Locale.ENGLISH));
gamemodeOtherPlayers(server, sender, gameMode, args[1]);
loopOnlinePlayersConsumer(server, sender, false, true, args[1], user -> setUserGamemode(sender, matchGameMode(args[0]), user));
}
}
@@ -40,16 +37,14 @@ public class Commandgamemode extends EssentialsCommand {
if (args.length == 0) {
gameMode = matchGameMode(commandLabel);
} else if (args.length > 1 && args[1].trim().length() > 2 && user.isAuthorized("essentials.gamemode.others")) {
gameMode = matchGameMode(args[0].toLowerCase(Locale.ENGLISH));
gamemodeOtherPlayers(server, user.getSource(), gameMode, args[1]);
loopOnlinePlayersConsumer(server, user.getSource(), false, true, args[1], player -> setUserGamemode(user.getSource(), matchGameMode(args[0].toLowerCase(Locale.ENGLISH)), player));
return;
} else {
try {
gameMode = matchGameMode(args[0].toLowerCase(Locale.ENGLISH));
} catch (NotEnoughArgumentsException e) {
if (user.isAuthorized("essentials.gamemode.others")) {
gameMode = matchGameMode(commandLabel);
gamemodeOtherPlayers(server, user.getSource(), gameMode, args[0]);
loopOnlinePlayersConsumer(server, user.getSource(), false, true, args[0], player -> setUserGamemode(user.getSource(), matchGameMode(commandLabel), player));
return;
}
throw new NotEnoughArgumentsException();
@@ -60,7 +55,7 @@ public class Commandgamemode extends EssentialsCommand {
gameMode = user.getBase().getGameMode() == GameMode.SURVIVAL ? GameMode.CREATIVE : user.getBase().getGameMode() == GameMode.CREATIVE ? GameMode.ADVENTURE : GameMode.SURVIVAL;
}
if (!canChangeToMode(user, gameMode)) {
if (isProhibitedChange(user, gameMode)) {
user.sendMessage(tl("cantGamemode", gameMode.name()));
return;
}
@@ -69,57 +64,43 @@ public class Commandgamemode extends EssentialsCommand {
user.sendMessage(tl("gameMode", tl(user.getBase().getGameMode().toString().toLowerCase(Locale.ENGLISH)), user.getDisplayName()));
}
private void gamemodeOtherPlayers(final Server server, final CommandSource sender, final GameMode gameMode, final String name) throws NotEnoughArgumentsException, PlayerNotFoundException {
if (name.trim().length() < 2 || gameMode == null) {
private void setUserGamemode(final CommandSource sender, final GameMode gameMode, final User user) throws NotEnoughArgumentsException {
if (gameMode == null) {
throw new NotEnoughArgumentsException(tl("gameModeInvalid"));
}
if (sender.isPlayer() && !canChangeToMode(ess.getUser(sender.getPlayer()), gameMode)) {
if (sender.isPlayer() && isProhibitedChange(sender.getUser(ess), gameMode)) {
sender.sendMessage(tl("cantGamemode", gameMode.name()));
return;
}
boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished();
boolean foundUser = false;
final List<Player> matchedPlayers = server.matchPlayer(name);
for (Player matchPlayer : matchedPlayers) {
final User player = ess.getUser(matchPlayer);
if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) {
continue;
}
foundUser = true;
player.getBase().setGameMode(gameMode);
sender.sendMessage(tl("gameMode", tl(player.getBase().getGameMode().toString().toLowerCase(Locale.ENGLISH)), player.getDisplayName()));
}
if (!foundUser) {
throw new PlayerNotFoundException();
}
user.getBase().setGameMode(gameMode);
sender.sendMessage(tl("gameMode", tl(gameMode.toString().toLowerCase(Locale.ENGLISH)), user.getDisplayName()));
}
// essentials.gamemode will let them change to any but essentials.gamemode.survival would only let them change to survival.
private boolean canChangeToMode(User user, GameMode to) {
return user.isAuthorized("essentials.gamemode.all") || user.isAuthorized("essentials.gamemode." + to.name().toLowerCase());
private boolean isProhibitedChange(IUser user, GameMode to) {
return user != null && !user.isAuthorized("essentials.gamemode.all") && !user.isAuthorized("essentials.gamemode." + to.name().toLowerCase());
}
private GameMode matchGameMode(String modeString) throws NotEnoughArgumentsException {
GameMode mode = null;
modeString = modeString.toLowerCase();
if (modeString.equalsIgnoreCase("gmc") || modeString.equalsIgnoreCase("egmc") || modeString.contains("creat") || modeString.equalsIgnoreCase("1") || modeString.equalsIgnoreCase("c")) {
mode = GameMode.CREATIVE;
} else if (modeString.equalsIgnoreCase("gms") || modeString.equalsIgnoreCase("egms") || modeString.contains("survi") || modeString.equalsIgnoreCase("0") || modeString.equalsIgnoreCase("s")) {
mode = GameMode.SURVIVAL;
} else if (modeString.equalsIgnoreCase("gma") || modeString.equalsIgnoreCase("egma") || modeString.contains("advent") || modeString.equalsIgnoreCase("2") || modeString.equalsIgnoreCase("a")) {
mode = GameMode.ADVENTURE;
} else if (modeString.equalsIgnoreCase("gmt") || modeString.equalsIgnoreCase("egmt") || modeString.contains("toggle") || modeString.contains("cycle") || modeString.equalsIgnoreCase("t")) {
mode = null;
} else if (modeString.equalsIgnoreCase("gmsp") || modeString.equalsIgnoreCase("egmsp") || modeString.contains("spec") || modeString.equalsIgnoreCase("3") || modeString.equalsIgnoreCase("sp")) {
mode = GameMode.SPECTATOR;
} else {
} else if (!modeString.equalsIgnoreCase("gmt") && !modeString.equalsIgnoreCase("egmt") && !modeString.contains("toggle") && !modeString.contains("cycle") && !modeString.equalsIgnoreCase("t")) {
throw new NotEnoughArgumentsException();
}
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) {
@@ -159,4 +140,9 @@ public class Commandgamemode extends EssentialsCommand {
return Collections.emptyList();
}
}
@Override
protected void updatePlayer(Server server, CommandSource sender, User user, String[] args) {
}
}
@@ -19,7 +19,7 @@ import java.util.Map;
import static com.earth2me.essentials.I18n.tl;
public class Commandgive extends EssentialsCommand {
public class Commandgive extends EssentialsLoopCommand {
public Commandgive() {
super("give");
}
@@ -37,8 +37,6 @@ public class Commandgive extends EssentialsCommand {
throw new Exception(tl("cantSpawnItem", itemname));
}
final User giveTo = getPlayer(server, sender, args, 0);
try {
if (args.length > 3 && NumberUtil.isInt(args[2]) && NumberUtil.isInt(args[3])) {
stack.setAmount(Integer.parseInt(args[2]));
@@ -47,7 +45,7 @@ public class Commandgive extends EssentialsCommand {
stack.setAmount(Integer.parseInt(args[2]));
} else if (ess.getSettings().getDefaultStackSize() > 0) {
stack.setAmount(ess.getSettings().getDefaultStackSize());
} else if (ess.getSettings().getOversizedStackSize() > 0 && giveTo.isAuthorized("essentials.oversizedstacks")) {
} else if (ess.getSettings().getOversizedStackSize() > 0 && sender.isAuthorized("essentials.oversizedstacks", ess)) {
stack.setAmount(ess.getSettings().getOversizedStackSize());
}
} catch (NumberFormatException e) {
@@ -79,28 +77,29 @@ public class Commandgive extends EssentialsCommand {
}
final String itemName = stack.getType().toString().toLowerCase(Locale.ENGLISH).replace('_', ' ');
sender.sendMessage(tl("giveSpawn", stack.getAmount(), itemName, giveTo.getDisplayName()));
Map<Integer, ItemStack> leftovers;
if (giveTo.isAuthorized("essentials.oversizedstacks")) {
leftovers = InventoryWorkaround.addOversizedItems(giveTo.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), stack);
} else {
leftovers = InventoryWorkaround.addItems(giveTo.getBase().getInventory(), stack);
}
boolean isDropItemsIfFull = ess.getSettings().isDropItemsIfFull();
final ItemStack finalStack = stack;
loopOnlinePlayersConsumer(server, sender, false, true, args[0], player -> {
sender.sendMessage(tl("giveSpawn", finalStack.getAmount(), itemName, player.getDisplayName()));
Map<Integer, ItemStack> leftovers;
for (ItemStack item : leftovers.values()) {
if (isDropItemsIfFull) {
World w = giveTo.getWorld();
w.dropItemNaturally(giveTo.getLocation(), item);
if (player.isAuthorized("essentials.oversizedstacks")) {
leftovers = InventoryWorkaround.addOversizedItems(player.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), finalStack);
} else {
sender.sendMessage(tl("giveSpawnFailure", item.getAmount(), itemName, giveTo.getDisplayName()));
leftovers = InventoryWorkaround.addItems(player.getBase().getInventory(), finalStack);
}
}
giveTo.getBase().updateInventory();
for (ItemStack item : leftovers.values()) {
if (isDropItemsIfFull) {
World w = player.getWorld();
w.dropItemNaturally(player.getLocation(), item);
} else {
sender.sendMessage(tl("giveSpawnFailure", item.getAmount(), itemName, player.getDisplayName()));
}
}
player.getBase().updateInventory();
});
}
@Override
@@ -117,4 +116,9 @@ public class Commandgive extends EssentialsCommand {
return Collections.emptyList();
}
}
@Override
protected void updatePlayer(Server server, CommandSource sender, User user, String[] args) {
}
}
@@ -29,8 +29,7 @@ public class Commandgod extends EssentialsToggleCommand {
enabled = !user.isGodModeEnabled();
}
final User controller = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null;
final GodStatusChangeEvent godEvent = new GodStatusChangeEvent(user, controller, enabled);
final GodStatusChangeEvent godEvent = new GodStatusChangeEvent(user, sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null, enabled);
ess.getServer().getPluginManager().callEvent(godEvent);
if (!godEvent.isCancelled()) {
user.setGodModeEnabled(enabled);
@@ -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,38 +25,73 @@ 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"))) {
if (args.length == 0 || (!args[0].contains("rem") && !args[0].contains("off") && !args[0].equalsIgnoreCase("0"))) {
final ItemStack hand = user.getItemInHand();
if (hand == null || hand.getType() == Material.AIR) {
user.sendMessage(tl("hatFail"));
return;
}
if (user.isAuthorized("essentials.hat.prevent-type." + hand.getType().name().toLowerCase())) {
user.sendMessage(tl("hatFail"));
return;
}
if (hand.getType().getMaxDurability() != 0) {
user.sendMessage(tl("hatArmor"));
return;
}
final PlayerInventory inv = user.getBase().getInventory();
final ItemStack head = inv.getHelmet();
if (head == null || head.getType() == Material.AIR) {
user.sendMessage(tl("hatEmpty"));
} else {
final ItemStack air = new ItemStack(Material.AIR);
inv.setHelmet(air);
InventoryWorkaround.addItems(user.getBase().getInventory(), head);
user.sendMessage(tl("hatRemoved"));
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"));
return;
}
final PlayerInventory inv = user.getBase().getInventory();
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 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();
inv.setHelmet(hand);
inv.setItemInHand(head);
user.sendMessage(tl("hatPlaced"));
} else {
user.sendMessage(tl("hatArmor"));
}
} else {
user.sendMessage(tl("hatFail"));
}
final ItemStack air = new ItemStack(Material.AIR);
inv.setHelmet(air);
InventoryWorkaround.addItems(user.getBase().getInventory(), head);
user.sendMessage(tl("hatRemoved"));
}
}
@@ -30,7 +30,7 @@ public class Commandheal extends EssentialsLoopCommand {
return;
}
healPlayer(user);
updatePlayer(server, user.getSource(), user, args);
}
@Override
@@ -43,43 +43,41 @@ public class Commandheal extends EssentialsLoopCommand {
}
@Override
protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) throws PlayerExemptException {
protected void updatePlayer(final Server server, final CommandSource sender, final User user, final String[] args) throws PlayerExemptException {
try {
healPlayer(player);
sender.sendMessage(tl("healOther", player.getDisplayName()));
final Player player = user.getBase();
if (player.getHealth() == 0) {
throw new PlayerExemptException(tl("healDead"));
}
final double amount = player.getMaxHealth() - player.getHealth();
final EntityRegainHealthEvent erhe = new EntityRegainHealthEvent(player, amount, RegainReason.CUSTOM);
ess.getServer().getPluginManager().callEvent(erhe);
if (erhe.isCancelled()) {
throw new QuietAbortException();
}
double newAmount = player.getHealth() + erhe.getAmount();
if (newAmount > player.getMaxHealth()) {
newAmount = player.getMaxHealth();
}
player.setHealth(newAmount);
player.setFoodLevel(20);
player.setFireTicks(0);
user.sendMessage(tl("heal"));
if (ess.getSettings().isRemovingEffectsOnHeal()) {
for (PotionEffect effect : player.getActivePotionEffects()) {
player.removePotionEffect(effect.getType());
}
}
sender.sendMessage(tl("healOther", user.getDisplayName()));
} catch (QuietAbortException e) {
//Handle Quietly
}
}
private void healPlayer(final User user) throws PlayerExemptException, QuietAbortException {
final Player player = user.getBase();
if (player.getHealth() == 0) {
throw new PlayerExemptException(tl("healDead"));
}
final double amount = player.getMaxHealth() - player.getHealth();
final EntityRegainHealthEvent erhe = new EntityRegainHealthEvent(player, amount, RegainReason.CUSTOM);
ess.getServer().getPluginManager().callEvent(erhe);
if (erhe.isCancelled()) {
throw new QuietAbortException();
}
double newAmount = player.getHealth() + erhe.getAmount();
if (newAmount > player.getMaxHealth()) {
newAmount = player.getMaxHealth();
}
player.setHealth(newAmount);
player.setFoodLevel(20);
player.setFireTicks(0);
user.sendMessage(tl("heal"));
for (PotionEffect effect : player.getActivePotionEffects()) {
player.removePotionEffect(effect.getType());
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
if (args.length == 1 && user.isAuthorized("essentials.heal.others")) {
@@ -6,6 +6,7 @@ import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
@@ -20,7 +21,7 @@ public class Commandhelpop extends EssentialsCommand {
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
user.setDisplayNick();
final String message = sendMessage(server, user.getSource(), user.getDisplayName(), args);
final String message = sendMessage(server, user.getDisplayName(), args);
if (!user.isAuthorized("essentials.helpop.receive")) {
user.sendMessage(message);
}
@@ -28,10 +29,10 @@ public class Commandhelpop extends EssentialsCommand {
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
sendMessage(server, sender, Console.NAME, args);
sendMessage(server, Console.NAME, args);
}
private String sendMessage(final Server server, final CommandSource sender, final String from, final String[] args) throws Exception {
private String sendMessage(final Server server, final String from, final String[] args) throws Exception {
if (args.length < 1) {
throw new NotEnoughArgumentsException();
}
@@ -43,6 +44,6 @@ public class Commandhelpop extends EssentialsCommand {
@Override
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
return null; // Use vanilla handler for message
return Collections.emptyList();
}
}
@@ -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,39 +43,70 @@ 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)) {
if (ess.getSettings().isSpawnIfNoHome()) {
user.getTeleport().respawn(charge, TeleportCause.COMMAND);
} else {
throw new Exception(tl("noHomeSetPlayer"));
}
} 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)));
});
throw new NoChargeException();
}
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();
}
@@ -87,7 +121,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();
}
@@ -98,36 +132,46 @@ public class Commandhome extends EssentialsCommand {
if (user.getWorld() != loc.getWorld() && ess.getSettings().isWorldHomePermissions() && !user.isAuthorized("essentials.worlds." + loc.getWorld().getName())) {
throw new Exception(tl("noPerm", "essentials.worlds." + loc.getWorld().getName()));
}
user.getTeleport().teleport(loc, charge, TeleportCause.COMMAND);
user.sendMessage(tl("teleportHome", home));
UserTeleportHomeEvent event = new UserTeleportHomeEvent(user, home, loc, UserTeleportHomeEvent.HomeType.HOME);
user.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
user.getAsyncTeleport().teleport(loc, charge, TeleportCause.COMMAND, future);
future.thenAccept(success -> {
if (success) {
user.sendMessage(tl("teleportHome", home));
}
});
}
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
boolean canVisitOthers = user.isAuthorized("essentials.home.others");
boolean canVisitBed = user.isAuthorized("essentials.home.bed");
if (args.length == 1) {
List<String> homes = user.getHomes();
if (canVisitBed) {
homes.add("bed");
}
if (canVisitOthers) {
return getPlayers(server, user);
} else {
List<String> homes = user.getHomes();
if (user.isAuthorized("essentials.home.bed")) {
homes.add("bed");
int sepIndex = args[0].indexOf(':');
if (sepIndex < 0) {
getPlayers(server, user).forEach(player -> homes.add(player + ":"));
} else {
String namePart = args[0].substring(0, sepIndex);
User otherUser;
try {
otherUser = getPlayer(server, new String[]{namePart}, 0, true, true);
} catch (Exception ex) {
return homes;
}
otherUser.getHomes().forEach(home -> homes.add(namePart + ":" + home));
if (canVisitBed) {
homes.add(namePart + ":bed");
}
}
return homes;
}
} else if (args.length == 2 && canVisitOthers) {
try {
User otherUser = getPlayer(server, args, 0, true, true);
List<String> homes = otherUser.getHomes();
if (user.isAuthorized("essentials.home.bed")) {
homes.add("bed");
}
return homes;
} catch (Exception ex) {
// No such user
return Collections.emptyList();
}
return homes;
} else {
return Collections.emptyList();
}
@@ -5,6 +5,7 @@ import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import static com.earth2me.essentials.I18n.tl;
@@ -16,32 +17,37 @@ public class Commandignore extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
if (args.length == 0) {
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"));
return;
}
User player;
try {
player = getPlayer(server, args, 0, true, true);
} catch (PlayerNotFoundException ex) {
player = ess.getOfflineUser(args[0]);
}
if (player == null) {
throw new PlayerNotFoundException();
}
if (player.isIgnoreExempt()) {
user.sendMessage(tl("ignoreExempt"));
} else if (user.isIgnoredPlayer(player)) {
user.setIgnoredPlayer(player, false);
user.sendMessage(tl("unignorePlayer", player.getName()));
} else {
User player;
try {
player = getPlayer(server, args, 0, true, true);
} catch (PlayerNotFoundException ex) {
player = ess.getOfflineUser(args[0]);
}
if (player == null) {
throw new PlayerNotFoundException();
}
if (player.isIgnoreExempt()) {
user.sendMessage(tl("ignoreExempt"));
} else if (user.isIgnoredPlayer(player)) {
user.setIgnoredPlayer(player, false);
user.sendMessage(tl("unignorePlayer", player.getName()));
} else {
user.setIgnoredPlayer(player, true);
user.sendMessage(tl("ignorePlayer", player.getName()));
}
user.setIgnoredPlayer(player, true);
user.sendMessage(tl("ignorePlayer", player.getName()));
}
}
@@ -1,7 +1,6 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.TextInput;
import com.earth2me.essentials.textreader.TextPager;
@@ -19,9 +18,7 @@ public class Commandinfo extends EssentialsCommand {
ess.getUser(sender.getPlayer()).setDisplayNick();
}
final IText input = new TextInput(sender, "info", true, ess);
final IText output = new KeywordReplacer(input, sender, ess);
final TextPager pager = new TextPager(output);
final TextPager pager = new TextPager(new KeywordReplacer(new TextInput(sender, "info", true, ess), sender, ess));
pager.showPage(args.length > 0 ? args[0] : null, args.length > 1 ? args[1] : null, commandLabel, sender);
}
}
@@ -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();
}
@@ -22,7 +22,7 @@ public class Commanditem extends EssentialsCommand {
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
if (args.length == 0) {
throw new NotEnoughArgumentsException();
}
@@ -21,7 +21,7 @@ public class Commanditemdb extends EssentialsCommand {
protected void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
ItemStack itemStack = null;
boolean itemHeld = false;
if (args.length < 1) {
if (args.length == 0) {
if (sender.isPlayer() && sender.getPlayer() != null) {
itemHeld = true;
itemStack = ess.getUser(sender.getPlayer()).getItemInHand();
@@ -0,0 +1,75 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commanditemlore extends EssentialsCommand {
public Commanditemlore() {
super("itemlore");
}
@Override
protected void run(Server server, User user, String commandLabel, String[] args) throws Exception {
ItemStack item = user.getBase().getItemInHand();
if (item.getType().name().contains("AIR")) {
throw new Exception(tl("itemloreInvalidItem"));
}
if (args.length == 0) {
throw new NotEnoughArgumentsException();
}
ItemMeta im = item.getItemMeta();
if (args[0].equalsIgnoreCase("add") && args.length > 1) {
String line = FormatUtil.formatString(user, "essentials.itemlore", getFinalArg(args, 1)).trim();
List<String> lore = im.hasLore() ? im.getLore() : new ArrayList<>();
lore.add(line);
im.setLore(lore);
item.setItemMeta(im);
user.sendMessage(tl("itemloreSuccess", line));
} else if (args[0].equalsIgnoreCase("clear")) {
im.setLore(new ArrayList<>());
item.setItemMeta(im);
user.sendMessage(tl("itemloreClear"));
} else if (args[0].equalsIgnoreCase("set") && args.length > 2 && NumberUtil.isInt(args[1])) {
if (!im.hasLore()) {
throw new Exception(tl("itemloreNoLore"));
}
int line = Integer.parseInt(args[1]);
String newLine = FormatUtil.formatString(user, "essentials.itemlore", getFinalArg(args, 2)).trim();
List<String> lore = im.getLore();
try {
lore.set(line - 1, newLine);
} catch (Exception e) {
throw new Exception(tl("itemloreNoLine", line), e);
}
im.setLore(lore);
item.setItemMeta(im);
user.sendMessage(tl("itemloreSuccessLore", line, newLine));
} else {
throw new NotEnoughArgumentsException();
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
if (args.length == 1) {
return Lists.newArrayList("add", "set", "clear");
} else {
return Collections.emptyList();
}
}
}
@@ -1,13 +1,7 @@
package com.earth2me.essentials.commands;
import static com.earth2me.essentials.I18n.tl;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.I18n;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
@@ -15,6 +9,8 @@ import org.bukkit.inventory.meta.ItemMeta;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commanditemname extends EssentialsCommand {
public Commanditemname() {
@@ -24,13 +20,15 @@ public class Commanditemname extends EssentialsCommand {
@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")) {
if (item.getType() == Material.AIR) {
user.sendMessage(tl("itemnameInvalidItem", item.getType().toString().toLowerCase(Locale.ENGLISH).replace('_', ' ')));
return;
}
String name = FormatUtil.formatString(user, "essentials.itemname", getFinalArg(args, 0)).trim();
if (name.isEmpty()) name = null;
if (name.isEmpty()) {
name = null;
}
ItemMeta im = item.getItemMeta();
im.setDisplayName(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;
@@ -16,7 +14,7 @@ public class Commandjails extends EssentialsCommand {
@Override
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (ess.getJails().getCount() < 1) {
if (ess.getJails().getCount() == 0) {
sender.sendMessage(tl("noJailsDefined"));
} else {
sender.sendMessage(tl("jailList", StringUtil.joinList(" ", ess.getJails().getList())));
@@ -24,10 +24,10 @@ public class Commandjump extends EssentialsCommand {
if (args.length > 0 && args[0].contains("lock") && user.isAuthorized("essentials.jump.lock")) {
if (user.isFlyClickJump()) {
user.setRightClickJump(false);
user.sendMessage("Flying wizard mode disabled");
user.sendMessage(tl("jumpEasterDisable"));
} else {
user.setRightClickJump(true);
user.sendMessage("Enabling flying wizard mode");
user.sendMessage(tl("jumpEasterEnable"));
}
return;
}
@@ -46,7 +46,8 @@ public class Commandjump extends EssentialsCommand {
final Trade charge = new Trade(this.getName(), ess);
charge.isAffordableFor(user);
user.getTeleport().teleport(loc, charge, TeleportCause.COMMAND);
user.getAsyncTeleport().teleport(loc, charge, TeleportCause.COMMAND, getNewExceptionFuture(user.getSource(), commandLabel));
throw new NoChargeException();
}
@@ -19,7 +19,7 @@ public class Commandkill extends EssentialsLoopCommand {
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
if (args.length == 0) {
throw new NotEnoughArgumentsException();
}
@@ -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()));
}
@@ -27,12 +27,9 @@ public class Commandkit extends EssentialsCommand {
user.sendMessage(kitList.length() > 0 ? tl("kits", kitList) : tl("noKits"));
throw new NoChargeException();
} else if (args.length > 1 && user.isAuthorized("essentials.kit.others")) {
final User userTo = getPlayer(server, user, args, 1);
final String kitNames = StringUtil.sanitizeString(args[0].toLowerCase(Locale.ENGLISH)).trim();
giveKits(userTo, user, kitNames);
giveKits(getPlayer(server, user, args, 1), user, StringUtil.sanitizeString(args[0].toLowerCase(Locale.ENGLISH)).trim());
} else {
final String kitNames = StringUtil.sanitizeString(args[0].toLowerCase(Locale.ENGLISH)).trim();
giveKits(user, user, kitNames);
giveKits(user, user, StringUtil.sanitizeString(args[0].toLowerCase(Locale.ENGLISH)).trim());
}
}
@@ -44,11 +41,9 @@ public class Commandkit extends EssentialsCommand {
throw new NoChargeException();
} else {
final User userTo = getPlayer(server, args, 1, true, false);
final String[] kits = args[0].toLowerCase(Locale.ENGLISH).split(",");
for (final String kitName : kits) {
final Kit kit = new Kit(kitName, ess);
kit.expandItems(userTo);
for (final String kitName : args[0].toLowerCase(Locale.ENGLISH).split(",")) {
new Kit(kitName, ess).expandItems(userTo);
sender.sendMessage(tl("kitGiveTo", kitName, userTo.getDisplayName()));
userTo.sendMessage(tl("kitReceive", kitName));
@@ -60,11 +55,10 @@ public class Commandkit extends EssentialsCommand {
if (kitNames.isEmpty()) {
throw new Exception(tl("kitNotFound"));
}
String[] kitList = kitNames.split(",");
List<Kit> kits = new ArrayList<Kit>();
List<Kit> kits = new ArrayList<>();
for (final String kitName : kitList) {
for (final String kitName : kitNames.split(",")) {
if (kitName.isEmpty()) {
throw new Exception(tl("kitNotFound"));
}
@@ -81,8 +75,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,6 @@ 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;
@@ -22,45 +21,32 @@ public class Commandkittycannon extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final Entity ocelot = Mob.CAT.getType() == null ? spawnOcelot(user.getWorld(), server, user) : spawnCat(user.getWorld(), server, user);
class KittyCannonExplodeTask implements Runnable {
@Override
public void run() {
final Location loc = ocelot.getLocation();
ocelot.remove();
loc.getWorld().createExplosion(loc, 0F);
}
}
ess.scheduleSyncDelayedTask(new KittyCannonExplodeTask(), 20);
final Entity ocelot = Mob.CAT.getType() == null ? spawnOcelot(server, user) : spawnCat(server, user);
ess.scheduleSyncDelayedTask(() -> {
final Location loc = ocelot.getLocation();
ocelot.remove();
loc.getWorld().createExplosion(loc, 0F);
}, 20);
}
private static Ocelot spawnOcelot(World world, Server server, User user) throws Mob.MobException {
private static Ocelot spawnOcelot(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 {
private static Entity spawnCat(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;
}
}
@@ -3,56 +3,54 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.google.common.collect.Lists;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.entity.LightningStrike;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static com.earth2me.essentials.I18n.tl;
public class Commandlightning extends EssentialsLoopCommand {
int power = 5;
public Commandlightning() {
super("lightning");
}
@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());
if (args.length == 0) {
if (sender.isPlayer() || !sender.isAuthorized("essentials.lightning.others", ess)) {
sender.getPlayer().getWorld().strikeLightning(sender.getPlayer().getTargetBlock(null, 600).getLocation());
return;
}
throw new NotEnoughArgumentsException();
}
int power = 5;
if (args.length > 1) {
try {
power = Integer.parseInt(args[1]);
} catch (NumberFormatException ex) {
} catch (NumberFormatException ignored) {
}
}
final int finalPower = power;
loopOnlinePlayersConsumer(server, sender, false, true, args[0], player -> {
sender.sendMessage(tl("lightningUse", player.getDisplayName()));
final LightningStrike strike = player.getBase().getWorld().strikeLightningEffect(player.getBase().getLocation());
if (!player.isGodModeEnabled()) {
player.getBase().damage(finalPower, strike);
}
if (ess.getSettings().warnOnSmite()) {
player.sendMessage(tl("lightningSmited"));
}
});
loopOnlinePlayers(server, sender, true, true, args[0], null);
}
@Override
protected void updatePlayer(final Server server, final CommandSource sender, final User matchUser, final String[] args) {
sender.sendMessage(tl("lightningUse", matchUser.getDisplayName()));
final LightningStrike strike = matchUser.getBase().getWorld().strikeLightningEffect(matchUser.getBase().getLocation());
if (!matchUser.isGodModeEnabled()) {
matchUser.getBase().damage(power, strike);
}
if (ess.getSettings().warnOnSmite()) {
matchUser.sendMessage(tl("lightningSmited"));
}
}
@Override
@@ -64,12 +62,13 @@ 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) {
return getPlayers(server, sender);
} else if (args.length == 2) {
return Lists.newArrayList(Integer.toString(this.power));
return Lists.newArrayList("5");
} else {
return Collections.emptyList();
}
@@ -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))));
@@ -78,7 +78,7 @@ public class Commandlist extends EssentialsCommand {
outputUserList = PlayerList.getMergedList(ess, playerList, configGroup);
// If we have no users, than we don't need to continue parsing this group
if (outputUserList == null || outputUserList.isEmpty()) {
if (outputUserList.isEmpty()) {
continue;
}
@@ -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
@@ -120,7 +120,7 @@ public class Commandlist extends EssentialsCommand {
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
return getGroups();
return new ArrayList<>(PlayerList.getPlayerLists(ess, sender.getUser(ess), true).keySet());
} else {
return Collections.emptyList();
}
@@ -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;
@@ -25,7 +26,6 @@ public class Commandmail extends EssentialsCommand {
super("mail");
}
//TODO: Tidy this up / TL these errors.
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length >= 1 && "read".equalsIgnoreCase(args[0])) {
@@ -48,11 +48,17 @@ public class Commandmail extends EssentialsCommand {
}
if (user.isMuted()) {
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
}
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
}
User u = getPlayer(server, args[1], true, true);
if (u == null) {
User u;
try {
u = getPlayer(server, args[1], true, true);
} catch (PlayerNotFoundException e) {
throw new Exception(tl("playerNeverOnServer", args[1]));
}
@@ -106,8 +112,10 @@ public class Commandmail extends EssentialsCommand {
} else if (args.length >= 1 && "clear".equalsIgnoreCase(args[0])) {
throw new Exception(tl("onlyPlayers", commandLabel + " clear"));
} else if (args.length >= 3 && "send".equalsIgnoreCase(args[0])) {
User u = getPlayer(server, args[1], true, true);
if (u == null) {
User u;
try {
u = getPlayer(server, args[1], true, true);
} catch (PlayerNotFoundException e) {
throw new Exception(tl("playerNeverOnServer", args[1]));
}
u.addMail(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 2))));
@@ -119,8 +127,10 @@ public class Commandmail extends EssentialsCommand {
return;
} else if (args.length >= 2) {
//allow sending from console without "send" argument, since it's the only thing the console can do
User u = getPlayer(server, args[0], true, true);
if (u == null) {
User u;
try {
u = getPlayer(server, args[0], true, true);
} catch (PlayerNotFoundException e) {
throw new Exception(tl("playerNeverOnServer", args[0]));
}
u.addMail(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 1))));
@@ -2,6 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -24,7 +25,11 @@ public class Commandme extends EssentialsCommand {
@Override
public void run(Server server, User user, String commandLabel, String[] args) throws Exception {
if (user.isMuted()) {
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
}
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
}
if (args.length < 1) {
Loaded 100 of 363 files, more files were not shown because too many files have changed in this diff. Show more