Compare commits

...
931 Commits
Author SHA1 Message Date
MD bcb0fb5825 Bump to 2.19.2 release 2021-12-15 20:58:38 +00:00
MD 91f4493fe0 Run Actions builds for dev branches (#4691) 2021-12-15 20:55:37 +00:00
MD d53ff36a2a Prevent IndexOutOfBoundsException in interaction replies (#4690) 2021-12-15 20:55:37 +00:00
MD 98917d97c8 Bump down to 2.19.2-dev 2021-12-15 20:55:37 +00:00
Josh Roy 7e1d18fee4 Prepare for 2.20.0 dev builds 2021-12-14 21:26:44 +00:00
Josh Roy 0b7e7801d0 Release 2.19.1 (#4681) 2021-12-14 19:16:08 +00:00
Josh Roy 840035944a Truncate Discord interaction messages to proper length (#4686) 2021-12-14 18:46:59 +00:00
Josh RoyandMD 20a7d1c7ee Add DiscordRelayEvent to edit relayed Discord->MC messages (#4656)
Implements the event suggested in #4580.

Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2021-12-14 16:26:57 +00:00
pop4959 253185bd0e Remove ignore teleport metadata 2021-12-12 22:23:56 +00:00
Josh Roy dae519494e Fix stack overflow when disabling commands from other addons (#4680) 2021-12-11 19:16:23 -08:00
Josh Roy dc27af78bf Update to MC 1.18.1 2021-12-11 12:13:50 +00:00
Flask Bot 41861a8551 New Crowdin updates (#4467) 2021-12-04 14:53:26 +00:00
Josh Roy 9b629e42d8 Bump JDA + discord-webhooks dependencies (#4655) 2021-12-04 14:47:40 +00:00
7794634d37 Add support for multiple queued TPA requests (#3801)
This PR adds support for players to receive multiple teleport requests, which are queued and can be managed independently of one another.

All commands should retain their current behavior but have some new additions;
* `/tpaccept`: now allows you to specify a player or `*` to accept a specific player's or all players' teleport request(s) respectively.
  - Using a wildcard will only accept all tpahere requests, as players can't teleport to multiple places simultaneously.
* `/tpdeny`: now allows you to specify a player or `*` to deny a specific player's or all players' teleport request(s) respectively.

This PR also adds a new setting for the maximum amount of pending TPA requests a user can have at once.
```yml
# The maximum amount of simultaneous tpa requests that can be pending for any given user.
# Once at this threshold, any new tpa requests will bump the oldest tpa requests out of queue.
# Defaults to 5.
tpa-max-amount: 5
```

Closes #3769
Closes #1550

Co-authored-by: Mariell Hoversholm <proximyst@proximy.st>
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2021-12-04 14:40:06 +00:00
Josh Roy d091d6902c Fix safelogin support with 1.18 world heights (#4667)
Fixes #4665.
2021-12-03 20:31:36 +00:00
MD c45c741210 Bump supported version to 1.18 release 2021-11-30 16:33:05 +00:00
MD e35c65b976 Refactor world info provider; only clamp to logical height when already below
Fixes #4657.
2021-11-30 16:33:05 +00:00
MDandJason 0983167740 Port remaining groovy build logic to kotlin
Co-authored-by: Jason <11360596+jpenilla@users.noreply.github.com>
2021-11-30 16:33:05 +00:00
1509cf8978 Support 0>y>256 for safe/random teleports (#4641)
Co-authored-by: pop4959 <pop4959@gmail.com>
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-11-30 16:33:05 +00:00
MD c0082ee734 Update to Gradle 7.3 and toolchain to JDK 17 2021-11-30 16:33:05 +00:00
Flask Bot db2ec1b436 Update items.json for Minecraft 1.18 2021-11-30 16:33:05 +00:00
Josh Roy 7a1e50d10f Fix reflection mappings for the ServerStateProvider in 1.18 2021-11-30 16:33:05 +00:00
Josh Roy b6ba1768a1 Mark 1.18 as a supported version 2021-11-30 16:33:05 +00:00
Josh Roy c38dd997d2 Update Spigot to 1.18 2021-11-30 16:33:05 +00:00
Josh Roy f8ca1bae5d Fix offline player error in /playtime for versions < 1.15.2 (#4649) 2021-11-25 19:50:49 +00:00
Josh Roy 3c60bcf2de Allow unsafe homes when force-disable-teleport-safety is enabled (#4650) 2021-11-25 19:47:42 +00:00
Josh Roy 3f857e3183 Fix DiscordUtil#getOrCreateWebhook using webhooks without tokens 2021-11-25 14:03:56 -05:00
Josh Roy 668c9634ca Ensure JDA is started before allowing calls to the JDA object 2021-11-25 14:03:56 -05:00
nik2143andJosh Roy 51c49b0de6 Set a metadata value for vanished players (#4646)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-11-24 09:57:55 -05:00
Lax 5723dac6ba Send discord config in dump even when plugin is disabled 2021-11-17 19:15:02 -05:00
Josh Roy 680d3230ea Add /discord command to display invite code (#4620) 2021-11-06 19:18:37 -04:00
Josh Roy 8f679de352 Add offline user support to /playtime (#4619) 2021-11-06 15:41:38 -07:00
Josh Roy 86d435eee1 Move UUID below alts in /seen (#4615) 2021-11-06 13:50:56 -07:00
Bobcat00andBobcat00 e4cf965bae Add translation for /list real name (#4614)
Co-authored-by: Bobcat00 <Bobcat00@users.noreply.github.com>
2021-11-05 22:24:21 +00:00
Andre_601 78c846a0a8 Minor typo corrections for EssentialsXDiscord (#4603) 2021-11-01 21:41:58 -04:00
pop4959andJosh Roy c466c9c370 Add metadata value to bypass last location setting on teleport (#4597)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-10-31 17:25:18 -04:00
Josh Roy 6994005a5f Fix light blocks being considering solid (#4601) 2021-10-30 22:25:03 -07:00
Josh Roy e43f06bfa6 Add /mail sendtempall (#4561)
Implements #4558
2021-10-24 16:45:01 +00:00
Josh Roy 9601687190 Add console regex filter for discord module (#4534) 2021-10-24 12:12:42 -04:00
Josh Roy 2ed94f1048 Add provider to use new Paper advancement API (#4588)
Paper added in PaperMC/Paper@40ee634
2021-10-24 14:27:07 +00:00
Josh Roy 70045c30f3 Migrate reflection in MetaItemStack to a provider (#4592) 2021-10-24 15:17:06 +01:00
Josh Roy ce88c0e1e4 Fix kit issues with potions in 1.8 (#4591)
Fixes #2867
2021-10-24 14:12:20 +00:00
Josh Roy 494e82e581 Fix ability to delete warps in unloaded worlds (#4590)
Fixes #4584.
2021-10-24 15:05:10 +01:00
MelluhandJosh Roy edd15132fd Add playtime command (#4562)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-10-23 15:29:37 -04:00
Tadhg BoyleandJosh Roy add664441e Add notify messages to jail command (#4576)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-10-23 15:18:51 -04:00
Josh Roy 58b0fb089f Improve error message when primary channel is improperly defined (#4586)
* Improve message verboseness when primary channel is improperly defined

* Clarify primary channel behavior
2021-10-20 13:09:56 +01:00
Josh Roy 90e4845627 Remove config reloads on world load/unload (#4573)
Since the Configurate rewrite, we hold locations using `LazyLocation`, which is converted to a `Location` with world lookups on demand; as such we no longer need to reload configs on each world load since invalid locations will now softly fail.
2021-10-13 18:41:48 +01:00
Josh RoyandMD 43f4d306be Add discordbroadcast command (#4541)
* Add discordbroadcast command

* Update EssentialsDiscord/src/main/resources/plugin.yml

Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

* Add emoji parsing/tab complete for discordbroadcast command

Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2021-10-11 15:54:55 -04:00
Josh Roy cb7d9baf7a Fix exception while running vanilla commands for chat command relay (#4552)
Fixes #4545
2021-10-11 19:32:41 +00:00
Josh Roy f3aea5e6ec Improve error message for updater checker rate limit (#4560)
Fixes #4556
2021-10-11 20:06:18 +01:00
Josh Roy a7a1fcd98c Fix Discord token regex censor pattern (#4563)
Discord changed their token format again
2021-10-07 09:22:41 +01:00
ef8bcc8bc4 Add kits subfolder to allow for multiple kit files (#4407)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-10-02 19:14:41 -04:00
MDandJosh Roy b3692d18b0 Update plugin.yml authors to reflect EssentialsX contributions (#4551)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-09-28 15:49:55 -04:00
Josh Roy a7b2b675d5 Add essentials.seen.uuid permission to show uuids in seen (#4531)
Adds `essentials.seen.uuid` permission requirement to show uuids in `/seen`. People were complaining this cluttered it so whatever. Also adds said permission to the `essentials.seen.extra` permission group.

Closes #4499.
2021-09-28 13:13:50 +00:00
Josh RoyandMD 7d7a8e47ac Fix verbose command usages not being disabled properly (#4530)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2021-09-28 13:09:04 +00:00
MDandJosh Roy f0da17b75c Asynchronously filter commands on Paper when possible (#4460)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-09-15 17:23:31 -04:00
Josh Roy d86b471402 Add action message type (#4520)
Adds a message type which will show when a player runs the /action (/me) command.

Message Type:
```yml
# Configure which Discord channels different messages will be sent to.
# You can either use the names of the channels listed above or just the id of a channel.
# If an invalid channel is used, the primary channel will be used instead.
#
# To disable a message from showing, use 'none' as the channel name.
message-types:
  ...
  # Action messages sent when a player runs the /me or /action commands.
  action: primary
```

Message Format:
```yml
# The following entries allow you to customize the formatting of messages sent by the plugin.
# Each message has a description of how it is used along with placeholders that can be used.
messages:
  ...
  # This is the message sent to Discord when a player runs the /me or /action command.
  # The following placeholders can be used here:
  # - {username}: The name of the user who ran the command
  # - {displayname}: The display name of the user who ran the command
  # - {action}: The action (message) the user used in the command.
  # ... PlaceholderAPI placeholders are also supported here too!
  action: ":person_biking: {displayname} *{action}*"
```
2021-09-15 14:52:14 +00:00
Josh Roy 767508fb87 Fix bed spawn setting when waking up villagers (#4524)
Fixes #4461.
2021-09-15 15:40:23 +01:00
LaxandJosh Roy c85d772e1b Add /ess dump all as alias for /ess dump * (#4517)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-09-08 17:48:47 -04:00
MDandJosh Roy fde6524e46 Fix error with commands ending in single colon (#4508)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-09-01 13:37:46 -04:00
b2886969f0 Update to bStats v2 (#4350)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-09-01 13:33:43 -04:00
Josh RoyandMD 19ca5186e4 Replace unneeded inputs with new /ess dump in issue template (#4479)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2021-09-01 13:26:54 +01:00
Josh Roy b86a34c909 Prepare for 2.19.1 dev builds (#4505) 2021-09-01 12:55:37 +01:00
MD d145fbc5cc Require forceSign property even on releases 2021-08-31 21:27:35 +01:00
Josh Roy 3ca960e31b Release 2.19.0 2021-08-31 13:04:34 -04:00
MD 8bbaf7da68 Update Gradle to 7.2; set run-paper to 1.17.1 with toolchain (#4496)
:chatting:
2021-08-31 16:53:09 +01:00
Josh Roy 14c2ab5ddd Add online mode data for /ess dump (#4497)
EssentialsX/Website#60
2021-08-31 15:34:10 +00:00
Josh Roy 6f20a789f9 Delete (& backup) invalid NPC accounts created by poor econ code (#4490)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

my magnum opus

---

* Delete (& backup) invalid NPC accounts created by poor econ code

* Add feedback for large migrations

* Improve feedback messages

- Improve the wording of console messages
- Include details about how to resume purging userdata in case it gets interrupted
- Scale the message delay based on the number of userdata files to be processed
- Always cancel the repeating task and shut down the executor when we're done

* Update Essentials/src/main/java/com/earth2me/essentials/EssentialsUpgrade.java

* Add less ranty context to rant

At least I had caffeine before writing this
2021-08-31 16:28:44 +01:00
Josh Roy 4bee15956a Fix economy usernames being unsanitized in some places (#4484)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

This PR fixes various issues with NPC accounts:
- Fixes some NPC account names not being sanitised
- Fixes wrong keys being used when manually generating a NPC account file
- Adds some debug logging to `UserMap` name lookups
2021-08-28 17:32:45 +01:00
pop4959andJosh Roy e4c179f5ed Allow auto equip in nbt serialized kits (#4491)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-08-28 11:46:38 -04:00
Josh Roy 4811eb1558 Fix /ess dump on 1.8.8 (#4489)
Fixes #4487

pain
2021-08-27 21:50:41 +01:00
Josh Roy 69850d82c8 Fix NoClassDefFoundError on < 1.12 with Discord execute command (#4478) 2021-08-26 16:12:52 -04:00
Josh Roy df88a89c14 Add missing translation for argument pipe color (#4480) 2021-08-26 16:09:16 -04:00
Josh Roy c746a1ce17 Bump Configurate (#4475)
Some performance improvements, <3 zml
2021-08-24 11:35:53 +01:00
Flask Bot ecdaed7d11 New Crowdin updates (#4281) 2021-08-19 20:11:35 +00:00
CyberKitsuneandMD c062651821 Add option for tab complete to use displaynames (#4432)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

This feature adds a new configuration option, `change-tab-complete-name`

When `change-tab-complete-name` is turned on, `getPlayers()` in `EssentialsCommand` will use `getDisplayName()` instead of `getName()`; populating the list with display names instead of player names.

Closes #4431.
2021-08-19 20:00:06 +00:00
Josh RoyandMD 3692740762 Add /ess dump command to generate a debug dump output (#4361)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

Command usage: /essentials dump [config] [discord] [kits] [log]

Either of the optional args can be used to add the given data to the dump.

Related: EssentialsX/Website#51
2021-08-19 20:35:19 +01:00
Josh Roy 1179caab88 Fix bot-command-relay option not ignoring itself (#4453) 2021-08-12 12:37:19 +01:00
Josh Roy 35b1a284f3 Fix improper MOTD delay check (#4454) 2021-08-10 10:51:33 -04:00
Josh RoyandMD 36432c65e9 Fix NPE on webhooks messages with show-webhook-messages enabled (#4452)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

Fixes #4451.
2021-08-09 21:30:30 +00:00
Josh Roy 871e718f63 Add online/unique placeholders to join/leave formats for discord (#4427) 2021-08-09 16:23:49 -04:00
Josh Roy 42293596f3 Add config option to disable verbose usage strings (#4396)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

```yml
# Whether or not Essentials should show detailed command usages.
# If set to false, Essentials will collapse all usages in to one single usage message.
verbose-command-usages: true
```

This PR also fixes a regression in legacy usage strings where the `<command>` wasn't replaced.
2021-08-09 19:56:38 +00:00
Josh Roy ac8a13f039 Add name parameter for Discord avatar URL (#4369)
Allows offline mode/Geyser users to configure their own avatar URL using a service that accepts usernames.
2021-08-09 19:48:43 +00:00
Josh RoyandMD d56ecaacdc Allow world name fallback for LazyLocation (#4428)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2021-08-09 20:39:55 +01:00
Josh Roy 14fbfe360e Allow disabling MOTD task and cancel on player logout (#4411)
This PR allows setting `delay-motd` to a negative value in `config.yml` to disable the MOTD join task without disabling `/motd`, and fixes an issue where delayed MOTD tasks would run even after a player logged out (in case someone previously set an insanely high MOTD delay to "disable" the MOTD on join).

Fixes #4408.
2021-08-09 20:22:09 +01:00
Josh Roy 5334a3fd34 Move update check message out of MOTD task (#4410)
Update message will now show after mail, and will not be affected by insane MOTD delays.
2021-08-09 19:14:15 +00:00
Josh Roy 2fa9c6486e Fix disabled-commands not removing aliases (#4399)
Fixes #4383, an issue where only the main command name is disabled instead of the alias specified in `config.yml`.
2021-08-09 18:59:36 +00:00
Josh Roy c221e96122 Make discord chat format world name use world alias (#4419) 2021-08-09 19:57:03 +01:00
Josh Roy 26c016fea2 Add config option to allow webhooks/bots to send commands (#4442)
```yml
# Console relay settings
# The console relay sends every message shown in the console to a Discord channel.
console:
  ...
  # Set to true if bots/webhooks should be able to send commands through the command relay.
  bot-command-relay: false
```
2021-08-09 18:48:01 +00:00
Josh Roy b6a08ec712 Fix force-disable-teleport-safety enforcing world border (#4371) 2021-08-09 18:44:13 +00:00
Josh Roy 9179c6c1e2 Update EssXDiscord tutorial for new developer mode location (#4409) 2021-08-09 19:38:04 +01:00
Josh Roy 3f9aceb922 Add DiscordService#sendChatMessage
Allows plugins to send messages to the chat channel via API using the format from our config
2021-08-07 17:37:02 -07:00
Josh Roy 3da8efae49 Fix incorrect parameter name for allowGroupMentions 2021-08-07 17:37:02 -07:00
Josh Roy b84207f955 Fix regression in invalid home check (#4425) 2021-08-02 11:23:40 -04:00
1stGlitchandJosh Roy f57de40668 Fix invalid mob data in spawnmob on versions < 1.17 (#4376)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-08-02 10:33:49 -04:00
Daniil ZandJosh Roy e95df57642 Fix barrier considered as unsafe block to teleport (#4348)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-08-02 10:22:07 -04:00
Josh Roy aaddb2af1f Fix remaining Configurate nullability issues (#4370) 2021-08-02 12:32:41 +00:00
Josh Roy 082950cc18 Fix bStats becoming a transitive dependency (#4426) 2021-08-02 13:21:53 +01:00
triagonal 90828965df Fix NPE during reload with invalid discord bot tokens (#4417) 2021-07-31 10:19:20 -04:00
Josh Roy 17e026f9aa Require MessageType's start with a letter
May cause issues with YML serialization as it can get finicky with keys starting with numbers.
2021-07-28 16:24:09 -07:00
Josh Roy f1d7e50dc0 Don't warn about unregistered channel-id based MessageType's
You shouldn't be registering these, there is no point for a user to configure where these go because it would be ignored.
2021-07-28 16:24:09 -07:00
Josh Roy e2cb7b2102 Fix advanced relay breaking when multiple channels were defined 2021-07-28 16:24:09 -07:00
Josh Roy 28578a5d8a Fix some typos in the tutorial 2021-07-28 16:24:09 -07:00
Josh Roy 0d8e90b8da Move FakeServer to 1.8 provider (#4395)
Moving this removes the need to needlessly update the FakeServer class with new methods when upstream changes it.
2021-07-27 21:23:20 +01:00
Josh Roy 1556b911b2 Fix webhook messages being parsed unnecessarily (#4346)
This wasted CPU time parsing responses from Discord that we will never use, plus caused problems when parsing webhooks that our library couldn't parse correctly (MinnDevelopment/discord-webhooks#36).
2021-07-11 20:36:46 +01:00
MD eed73e3157 Cache overridden-commands and player-commands in Settings (#4345) 2021-07-11 12:25:25 -04:00
triagonal c020526b1e Strip formatting in webhook name (#4344) 2021-07-11 09:57:46 -04:00
Josh Roy cca98e817f Add show-displayname option 2021-07-10 11:08:51 -04:00
Josh Roy 46a8a7d04c Remove join/quit message null checks
If you don't want to see them, don't configure them.
2021-07-10 11:08:51 -04:00
Josh Roy d4ddc87d81 Fix less strict length check on messageQueue add rather than iteration 2021-07-10 11:08:51 -04:00
Chew b473460ffc Use native Discord timestamps for console timestamps 2021-07-10 11:08:51 -04:00
Josh Roy db027bced3 Add option to log channels to console 2021-07-10 11:08:51 -04:00
Josh Roy 12cc0b99f9 Fix some minor grammer issues in config 2021-07-10 11:08:51 -04:00
Josh Roy 15cac529c5 Improve death message validation
Now takes gamerules in to account and will not send blank or null death messages.
2021-07-10 11:08:51 -04:00
Josh Roy feed2d6a45 Fix improper bitwise logic in DiscordUtil#getRoleColorFormat 2021-07-10 11:08:51 -04:00
Josh Roy b516db669c Fix prefixes/suffixes not stripping hex format 2021-07-10 11:08:51 -04:00
Josh Roy 3bc58264ea Add advancement message type 2021-07-10 11:08:51 -04:00
Josh Roy 0a0416ae38 Fix disabling a single command causing all commands to be disabled 2021-07-10 11:08:51 -04:00
Josh Roy d244956b4b Ensure no JDA code is called during invalid shutdown 2021-07-10 11:08:51 -04:00
Josh Roy 37e3730e9d Add fake vanish join/leave + exclude vanished messages 2021-07-10 11:08:51 -04:00
triagonal 48532a0ae6 Fix NPE in UserData#getLogoutLocation (#4341) 2021-07-10 09:17:26 -04:00
Josh Roy 0b6b0f9c61 Fix NPE with custom join messages (#4334)
This fixes a bug in #4290 in which custom join messages would throw a NullPointerException if the user hasn't changed their username.
2021-07-09 16:33:44 +00:00
Josh Roy 435ac80ff9 Fix delay not working in /spawn (#4335) 2021-07-09 11:55:52 -04:00
triagonal a098055fc9 Fix NPE when teleporting offline players (#4332) 2021-07-08 09:24:40 -04:00
cba5063b33 Add config option to change discord show-avatar url (#4330)
Co-authored-by: T41US <adityakomp@gmail.com>
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-07-07 19:55:43 +00:00
AnsandrandJosh Roy 3787b80286 Add UserTeleportSpawnEvent (#4328)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-07-07 14:52:49 -04:00
pop4959andJosh Roy 2858bd3784 Add role placeholder to Discord message format (#4329)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-07-07 11:55:25 -04:00
OliviaandJosh Roy ff58d8e443 Add config option for new username join messages (#4290)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-07-07 15:46:54 +00:00
Josh Roy 5e178943a0 Update to Minecraft 1.17.1 (#4324) 2021-07-06 18:34:40 +01:00
triagonal 33ca3b2981 Fix behavior of itemdb command on legacy versions (#4320) 2021-07-05 21:29:24 -07:00
triagonal 8c8c85d753 Fix server shutdown not setting logout location (#4318) 2021-07-05 15:47:42 -04:00
Josh Roy 6535edf4e0 Fix MailMessageSerializer not handling null UUIDs (#4314) 2021-07-03 19:32:34 -04:00
Josh Roy 7e25570344 Remove usage of java.awt.Color (#4312)
This fixes issues on headless JREs which lack java.awt classes.
2021-07-03 20:46:09 +01:00
Josh Roy 409210ccde Fix issues with 3rd-party Vault economy providers (#4303)
Turns out that when you depend on a plugin, get this, the plugin will load before you. So we need to rework how we do things here.

Fixes #4075
Fixes #4304
2021-07-03 16:54:01 +01:00
Josh Roy 555a62c582 Fix baltop something having a null name for offline players 2021-07-03 01:04:59 -04:00
Josh Roy 36a070be4c Fix Configurate conversions not saving 2021-07-03 01:04:59 -04:00
Josh Roy d903e40a53 Fix weird behavior with legacy mails (#4307) 2021-07-02 21:52:49 -07:00
Josh Roy d78729f343 Disallow empty discord filters (#4298) 2021-07-01 15:59:35 -07:00
Josh Roy a55289196b Add server start/stop messages 2021-07-01 15:56:46 -04:00
Josh Roy 3505b47d8f Fix vanilla command execution on discord 2021-07-01 15:56:46 -04:00
Josh Roy 11836e6662 Ensure MessageFormat's are clean before parsing 2021-07-01 15:56:46 -04:00
Josh Roy 4ce38bde36 Allow uppercase variables 2021-07-01 15:56:46 -04:00
Josh Roy 711f701d62 Fix typo in mail tab complete (#4296) 2021-07-01 19:22:48 +00:00
triagonal 94c509b1e2 Prevent exception when retrieving enchantments (#4297) 2021-07-01 15:18:05 -04:00
triagonalandJosh Roy 5c08a0e72c Ignore case when matching custom item aliases (#4295)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-07-01 16:30:08 +00:00
Josh Roy 9c451271e0 Rework Mail System (#3710)
* New `/mail sendtemp <time diff> <message>` command to send mail that will self-destruct after time diff.
* New `/mail clear <number>` command to clear a specific mail item.
* `/mail read` now tracks which mails you read and won't nag you about them.
* A bunch of other flexibility since we store actual data instead of strings
2021-07-01 11:23:32 -04:00
Josh Roy 55db6c2476 Fix afk list NPE (#4294) 2021-07-01 16:15:24 +01:00
0861427bf3 Discord Module (#3844)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
Co-authored-by: pop4959 <pop4959@gmail.com>
Co-authored-by: Riley Park <riley.park@meino.net>
Co-authored-by: Jason <11360596+jpenilla@users.noreply.github.com>
2021-07-01 09:43:35 -04:00
Josh Roy 9d3bf337e1 Improve itemlore and itemname tab completion (#4280)
- Improve tab completion for itemname and itemlore
- Improve air type matching
- Fix incorrect /itemlore usage messages
2021-06-28 20:19:02 +01:00
Flask BotandMD 4e4eb35240 New Crowdin updates (#4182)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2021-06-27 14:46:04 +01:00
Josh Roy e7e3f58c8f Fix missing translation param in ice command 2021-06-27 14:40:14 +01:00
pop4959andJosh Roy c18830ce75 Fix pickup delay with essentials.build.pickup permission (#4273)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-06-27 02:36:28 +00:00
triagonal 3f36a52685 Prevent NPEs in /powertool (#4276)
This PR fixes a long-standing bug where using the `a:` or `r:` modes in `/powertool` with no commands already set on the item would result in an NPE. To prevent this, the powertool command list is now immediately initialized if it doesn't exist upon retrieval.
2021-06-26 20:11:03 +00:00
Josh Roy 64eb39a417 Add serialization support to kits (#3248)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

This PR makes use of Paper's item serialization to serialize items into base64 allowing for all items to be properly stored without needing to manual write in special cases for every complex item. There is a config option to disable using this new serialization and use the legacy ItemDB serializer since the new serializer removes the ability to manually edit/read kits.

Defaults to not enabled

Note: The new serializer places an @ sign in front of items serialized by the new format in order to quickly determine what is serialized by the new serializer and also to retain backward compatibility with the old serializer.

Att #3114
Att #2867
Att #1694
Att #31
Att #1283
2021-06-26 20:03:27 +00:00
MD 736ecae5ff Add missing FakeServer methods 2021-06-26 20:34:04 +01:00
Flask Bot 6bd4a6a037 Update items.json from generator 2021-06-26 20:34:04 +01:00
Josh Roy 4271938c3a Add ice commmand #EasterEgg 2021-06-26 20:34:04 +01:00
Josh RoyandMD e1441c1d33 Update mobs and NMS usage to 1.17
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2021-06-26 20:34:04 +01:00
triagonal 9bd35a2cd2 Fix regression in /back behavior (#4264) 2021-06-23 08:44:47 -04:00
triagonal d4e194fbf7 Fix NPE when RTP center isn't set (#4251) 2021-06-19 12:23:00 -04:00
Josh Roy 003d556f3d Fix incomplete cooldowns being added to data (#4249) 2021-06-18 19:28:10 -04:00
triagonal 1da3b3f08e Implement home cleanup utility (#4244) 2021-06-18 11:24:43 -04:00
Josh Roy f08c176b68 Fix invalid home locations giving blank errors (#4240) 2021-06-17 20:28:07 +01:00
Josh Roy 780aadedf2 Fix invalid empty value for BigDecimal (#4237) 2021-06-14 22:15:25 -04:00
Josh Roy 3fe279e229 Fix NPE in UserData#getHome (#4234) 2021-06-14 07:28:42 -04:00
Josh Roy c43af5d3d9 Fix NPE for list group (#4230) 2021-06-12 14:34:58 -07:00
DebugandJosh Roy 65b80200bd Fix incorrect behavior from last PR (#4228)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-06-12 14:14:19 -04:00
DebugandJosh Roy 6e5a41a880 Add option to hide balances <=0 from baltop (#4226)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-06-12 12:31:39 -04:00
Daniil ZandJosh Roy fa87c74b56 Allow enchants on fireworks/charges/potions/banners (#3882)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-06-11 11:13:43 -04:00
antiPerson 8142da608c Fix damage from exploding beds being cancelled (#3874) 2021-06-11 15:06:12 +00:00
Debug eacc748b09 Fix /book command not supporting multi-word title & author (#4180) 2021-06-11 15:00:21 +00:00
Josh Roy def41802b8 Fix broken cooldowns causing exceptions (#4219) 2021-06-09 21:20:51 -04:00
Josh Roy 38dcdff659 Fix invalid mail key (#4218) 2021-06-09 17:03:29 +01:00
Josh Roy bd9540cea3 Fix EssentialsSpawn not defaulting on default group (#4217)
Fix regression from #4072, tested in #essx-support on MOSS
2021-06-09 14:54:47 +01:00
triagonal 0d71fe65f6 Prevent getting jail worlds before world load (#4216) 2021-06-09 08:34:14 -04:00
Josh Roy 54c70581a2 Add config option to respawn jailed players to spawn (#4132) 2021-06-08 21:04:30 -04:00
pop4959 3abddd6f84 Fix tab complete on /enchant failing on empty key (#4215) 2021-06-08 20:50:17 -04:00
Josh Roy 8e712bc827 Fix empty paths with Configurate (#4214) 2021-06-09 00:42:45 +01:00
Jason 2018149395 Clean up Bukkit API exclusion, use dep constraint for SnakeYAML (#4213) 2021-06-08 23:36:43 +01:00
Josh Roy ecea17195a Fix parsing of command cooldowns with invalid data (#4212) 2021-06-08 16:51:47 -04:00
Josh Roy a28d0823b2 Fix invalid CommandCooldowns causing NPEs (#4210)
* Fix invalid CommandCooldowns causing NPEs

* Add Map support
2021-06-08 12:40:52 -04:00
Josh Roy 6e6561a267 Minimize (#4209) 2021-06-07 23:48:18 -04:00
Josh Roy 8b1db22a53 Fix setting of locations to LazyLocations + Shade CheckerQual (#4208) 2021-06-07 23:30:37 -04:00
Josh Roy 3d09ea386b Fix remaining uses of Location over LazyLocation (#4206) 2021-06-07 22:23:13 +00:00
Josh Roy 300daea4f9 Lazy load locations in Configurate (#4203) 2021-06-07 15:52:12 -04:00
Josh Roy 7653da0e4f Migrate to Configurate (#4072)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
Co-authored-by: Riley Park <riley.park@meino.net>
Co-authored-by: zml <zml@aoeu.xyz>

Migrates all uses of SnakeYAML and Bukkit's Configuration API to Sponge's Configurate.

Configurate enables us to the do the following stuff:
* Serialize YAML off the main thread
* (in the future) Automatically update our config
* (in the future) Manipulate comments in configs
* Be epic

This commit also *finally* strips out the 3.x storage/object mapping system in favour of Configurate's object mapper.
2021-06-07 13:49:33 +01:00
JasonandJosh Roy 19b4da07b9 Clean up gradle build scripts
Adds run-paper plugin support as well as moves majority of logic to kotlin build scrips

Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-06-07 08:17:39 -04:00
Josh Roy ff9f93fba4 Fix sleeping ignored vanish setting overriding permission (#4201) 2021-06-06 16:12:07 -07:00
Josh Roy fed26071ac Add option to ignore vanished players from sleeping (#4200) 2021-06-06 17:05:16 -04:00
Josh Roy a4fbfbef02 Fix offline player account creation (#4199)
This bug occurs when a player has joined before EssentialsX was installed and a player account creation is requested through Vault while they are offline.

Fixes #4195
2021-06-06 19:40:55 +01:00
Josh RoyandMD 347751a826 Fix branch name when building main branch on GH (#4193)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

Fixes #4191.
2021-06-03 17:03:14 +01:00
Josh Roy fbb3a9a0a4 Fix various NPC account lookup issues (#4188) 2021-06-01 15:47:39 -04:00
Josh Roy f8f1facf43 Check legacy "NPC:" UUIDs in VaultEconomyProvider#hasAccount (#4178) 2021-05-31 15:12:06 +00:00
Flask BotandMD 0d6441d0b6 New Crowdin updates (#4145)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2021-05-29 23:18:25 +01:00
Josh Roy a009b2f9b5 Only use convert spawners tagged by the give command (#3963) 2021-05-28 14:29:52 -04:00
Josh RoyandMD 7852aedabd Add book page serialization (#4048)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

Allows serialization of books in `/createkit`. Closes #31.
2021-05-28 18:52:18 +01:00
Josh RoyandMD b2d7d1b4cb Add prevent-type permissions for /itemname (#4133)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

Adds `essentials.itemname.prevent-type.<material_name>` permissions. Closes #4044.
2021-05-28 17:35:33 +00:00
Josh Roy ec50b28f4b Add ItemStack 1.8.8+ cross-version PersistentDataContainer (#4143)
This PR itself does nothing on its own but creates the underlying backbone I need to make a less hacky solution in #3963 lmfao.

This PR creates a provider which uses NBT on 1.8.8-1.13 to mimic the exact structure of a PersistentDataContainer on 1.14+ which will allow us make any possible upgrades (which don't die from the lack of DFU on >1.13) work as expected. Additionally, this does not use reflection on modern Minecraft versions and thus will not need to be maintained/updated on MC version updates.

In the future, we will need to find a way to store data on tile entities (signs namely) so that we are able to store UUIDs on signs for future plans, but for now ItemStacks work to fix our spawner issues.
2021-05-28 11:23:44 +00:00
Josh Roy 4ed36d9bbe Add support for dev/rc/beta/alpha build types (#4177)
🍍
2021-05-27 21:16:26 +01:00
l1ttleO 887772a428 Add {PREFIX} and {SUFFIX} to custom join/quit messages (#4169) 2021-05-21 13:28:22 -04:00
MDandJosh Roy e9169b890d Set Gradle toolchain to JDK 16 (#4168)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-05-21 13:15:47 +00:00
MDandJosh Roy b716c04d96 Fix minor issue with server support minor issue fix (#4166)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-05-21 07:24:39 -04:00
l1ttleO 2d3cbc9783 Fix Java version command in pull request templates (#4167) 2021-05-21 07:15:05 -04:00
Josh Roy 23a497abf6 Update Gradle to 7.0.2; misc build improvements (#4148)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

* Bumped Gradle to 7.0.2
* Now uses Java 16 for compiling to prepare for MC 1.17
  * Release target is still set to 8 however
* Bumped Actions versions
* Bumped indra version(s)
* Switched from grgit to indra-git
* Fix PR GitHub Actions jars having invalid branch names
2021-05-19 12:34:00 +01:00
Pretty Princess Sailoriae d00b90cd61 Fix formatting issue in with comma-separated lists (#4157) 2021-05-17 10:12:14 -04:00
Jason f4fe8808a4 Remove the /itemdb alias suggestion (#4152) 2021-05-14 19:26:23 -04:00
Josh Roy 02193b0523 Fix ClassNotFoundException when vault is missing (#4151) 2021-05-14 17:33:25 +01:00
Josh Roy c9310ea429 Fix a minor issue with support status detection (#4150) 2021-05-14 16:01:50 +00:00
Josh Roy c76e4239bb Ensure NPC userdata creation for Citizen NPCs (#4149)
https://github.com/CitizensDev/Citizens2/blob/0ddfcbd0fa99678934e7b086f1a7b92e6a1bc49e/v1_16_R3/src/main/java/net/citizensnpcs/nms/v1_16_R3/entity/HumanController.java#L36-L40

why????????????????????????????????????????????????????????????
2021-05-13 22:30:37 +01:00
Josh Roy 8a8d45c91e Fix vault provider account creation (#4147)
Removed an extraneous name->uuid check
  This check swallowed any warnings spit out by UserMap#trackUUID causing problems
  for plugins which didn't check the success of this method and thus leading to
  possible stack overflow exceptions or other unexpected behavior

Actually save accounts created with VaultEconomyProvider#createPlayerAccount
  Complete oversight as I was under the impression tracking the UUID would create
  the files for us.
2021-05-13 00:52:26 +00:00
Josh Roy 071f99560e Migrate to new Vault provider and economy integration (#3975)
This commit:
- Implements a new provider for VaultAPI's `Economy`
  - The legacy provider built into Vault uses player names, and has not changed since Vault was invented in 1864.
  - This properly supports UUIDs and works more predictably with EssentialsX.
- Replaces the Register method economy abstraction layer abstraction layer with a new `EconomyLayer` economy abstraction layer abstraction layer.
  - This opens the pathway for future economy abstraction layers to be supported.
  - This change also removes dubiously-licensed code from the project.

For users encountering userdata issues on this build, see this FAQ entry:
https://github.com/EssentialsX/Essentials/issues/3956#issuecomment-779254544

Fixes #4110.
Closes #3344.
Closes #2401.
2021-05-10 19:36:09 +00:00
Josh Royandtriagonal 8b23c2c4cd Add helpful command argument descriptions (#4057)
Co-authored-by: triagonal <10545540+triagonal@users.noreply.github.com>
2021-05-10 18:36:30 +00:00
Josh Taylor 0d640d1215 Fix netlify deploy message (#4141) 2021-05-05 09:36:43 -04:00
MD b4d63857ce Fix Javadoc preparation step (#4140) 2021-05-05 08:32:49 -04:00
Josh RoyandMariell Hoversholm 4976484d91 Unformat item lore and name when serializing items (#4095)
Co-authored-by: Mariell Hoversholm <proximyst@proximyst.com>
2021-05-02 16:18:35 -04:00
Josh Roy 16627d10b6 Add way for time and weather signs to display the time/weather (#4131) 2021-05-02 19:34:38 +00:00
Josh Roy 83ca7d2574 Prevent stack overflow when finding an EssX cmd as alternative (#4128) 2021-05-02 15:08:18 -04:00
Josh Roy 956afc0382 Fix kit-auto-equip not working on versions < 1.14 (#4130) 2021-05-02 19:03:43 +00:00
MDandJosh Roy 312ff110ec [CI-SKIP] Automatically publish 2.x javadocs (#4083)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-05-01 16:37:24 -04:00
NotMyFault 214d07c468 [CI-SKIP] Address template deprecations (#4125) 2021-04-25 16:45:04 +00:00
l1ttleOandJosh Roy 2c68d1b866 Fix /pay working on vanished players (#4114)
Vanished players are now treated as offline players.

Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-04-18 10:08:07 -04:00
Josh Roy 5171215817 Fix various trade sign issues (#4056)
Fixes various bugs with line length validation and fixes issues with overfilled stacks.
2021-04-14 12:24:24 -04:00
Jason 195148a2a2 Fix disabled commands not marking the command map as dirty (#4108) 2021-04-12 19:08:19 -04:00
pop4959andJosh Roy edf664e19a Unregister disabled commands (#4026)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-04-07 21:37:21 -04:00
Suyeol Jeon 0668e4c48a Fix regression in permission based item spawning (#4100) 2021-04-03 11:38:04 -04:00
triagonal d75787726c Add some extra keywords (#4098) 2021-03-29 13:07:55 -04:00
triagonal 1e0d7fb0a3 Add missing respawn-at-home-bed config option (#4071)
This PR adds a missing config option that was accidentally left out in #3802 (thank you @mibby for the heads up).
2021-03-20 16:09:59 +00:00
Josh Roy 454698bf98 Fix delayed futures never being completed correctly (#4066)
This PR fixes issues related to timed teleports. All timed teleports before this PR would create their own future to send back to the AsyncTeleport api causing the futures returned in the base methods never being completed.

This PR pases the future returned in AsyncTeleport methods to the timed teleport and completes it after the timed teleport has been completed.

Fixes #4065.
2021-03-20 15:48:40 +00:00
Josh Roy bfeb0ef2ad Fix update check on 3+ digit build numbers (#4069) 2021-03-19 00:14:45 -04:00
Josh Roy 1cf2b11f1e Improve currency validation in signs (#3987)
Sanitise currency strings in more cases when handling signs. Should fix #3979.
2021-03-13 16:36:18 +00:00
Josh Roy 0ce4029483 Change createkit to use paste.gg (#4049) 2021-03-09 21:28:07 -05:00
Josh Roy 504e82e9fd Update FakeWorld (#4043) 2021-03-08 15:39:52 -08:00
Josh Roy eca6a9f247 Improve update checker startup message logging (#4039)
* Use plugin logger for update checker
* Use info log level when update checker is disabled

Closes #4038.
2021-03-06 23:52:10 +00:00
Josh Roy 94d4385d41 Fix list command exposing groups with vanished players (#4032)
Fixes #4018.
2021-03-06 19:42:59 +00:00
Josh Roy c41bb0ec42 Delay GeoIP join task to ensure display name is set (#3968)
Delays the GeoIP join messages by 2 ticks to ensure the user's display name has been set by Essentials' `DelayedJoin` task.

Fixes #2388.
2021-03-06 19:22:00 +00:00
Josh Roy 00b71cafc9 Add netherite related items to spawnmob (#4031)
Allows spawning skeletons and zombies with netherite armor and swords. Fixes #4029.
2021-03-06 19:06:31 +00:00
MD 3cd69dabe9 Fix metrics initialising before update checker (#4037)
This PR fixes an issue introduced in #3855, where bStats inits before the update checker and so fails to grab the current release branch.
2021-03-07 03:58:35 +11:00
Josh Roy 10fa3b5a31 Add update checker (#3855)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

Adds an update checker to Essentials that will check for the latest version on startup, on player join (permission is `essentials.updatecheck`), or manually with `/ess version`.

On startup, the update checker will fetch build information from a resource generated at compile time and determine if the build is a dev or stable build. If it's a stable build, the update checker will only check for a new release; while a dev build will check for any new commits.

There are 6 different types of messages the update checker will return;
* Identical: The current build is the latest stable release or latest dev build. This message is only shown in the `/ess version` command.
* Behind: If the current build is stable, it's an entire stable build behind, otherwise it's one or more dev builds behind.
* Diverged: The current build was made from a branch other than `2.x` and is also one or more dev builds behind the latest commit on `2.x`.
* Diverged Latest: The current build was made from a branch other than `2.x` but is based on the latest commit from `2.x`.
* Unknown: The current build either has invalid build information or was customly built. This message is show everywhere but on player join.
* Error: There was an error while fetching the latest version information.

Update checks can be disabled using the `update-check` option in `config.yml`.
2021-03-06 16:29:42 +00:00
Josh Roy b43790e9d2 Fix failing gradle build (#4025)
Paper has recently added adventure as a first part library, and thus has shaded it in. Adventure is on maven central, so we must add it in order for Essentials to build.
2021-03-02 04:52:05 +00:00
Frank van der HeijdenandJosh Roy ee5f4b9b42 Fix some futures in AsyncTeleport never completing (#4016)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-02-27 11:19:28 -05:00
MD e5db842dd6 Document XMPP config and require server TLS by default (#4002)
Small changes related to #3962.
2021-02-21 10:46:32 -05:00
Josh Roy 657a11b1f4 Add permission to adjust delay in /spawner command (#3964) 2021-02-21 08:59:57 -05:00
Josh Roy 0ef1e23c69 Show UUIDs in /seen (#3906) 2021-02-21 13:57:19 +00:00
Josh Roy 141512f2f7 Fix afk message being sent when event cancelled (#3915) 2021-02-21 13:54:02 +00:00
Josh Roy 671983724a Fix invalid configuration section for world aliases (#4000) 2021-02-21 00:09:34 -05:00
Josh Roy 81571fc014 Add /toggleshout command (#3965)
Adds a command to toggle shout mode of a user allowing them not to have to prefix all their messages with `!` if they're shouting a lot.

Closes #3958.
2021-02-20 16:37:16 +00:00
Frank van der Heijden f806409d80 Add support for commands.yml aliases in command cooldowns (#3744)
Fixes #2058.
2021-02-20 16:30:07 +00:00
Josh RoyandMD f3c347424b Add new signs for recently added virtual commands (#3961)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

Closes #3919.
2021-02-20 15:59:30 +00:00
Josh Roy 8cbd9b7935 Add /editsign copy + paste (#3989)
Adds `copy` and `paste` subcommands to `/editsign` to allow users to copy and paste the contents of signs without having to use the tab-completion output of `/editsign set`.

The `/editsign copy` command will also perform format-permission checks to ensure the user copying the sign has the proper permission to use said formatting.

Closes #3973.
2021-02-19 15:13:49 +00:00
Josh Roy 158d273dbe Allow blank currency symbols (#3946)
Fixes a behavior previously possible before c6de771

I wrote the proper logic in c6de771 to handle blank currency symbols but forgot to remove the Settings check that was preventing blank currency symbols.

Fixes #3945.
2021-02-19 14:58:42 +00:00
Josh Roy 1258d2f0a1 Fix further incorrect messages for jail countdowns (#3941)
Fixes #3939, fixes #3940.
2021-02-16 13:56:57 +00:00
Josh Roy 36422ab22b Add Baltop API (#3702)
Co-authored-by: Mariell <proximyst@proximyst.com>
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

This moves storage of balances from the baltop command into the UserMap. This was needed by Glare to able to get a hold of all users balances without causing jvm hell on the usermap.

To access this API as an end user;
```java
import net.essentialsx.api.v2.services.BalanceTop;
//...
BalanceTop api = Bukkit.getServer().getServicesManager().load(BalanceTop.class);
```

Closes #3100, closes #3540
2021-02-15 15:43:10 +00:00
MD 191cea7fb3 Update issue template for new config format (#3982)
This PR updates the issue form to the new schema, which will be introduced on February 19th.

The legacy issue form will be used until the switchover date.
2021-02-15 11:51:26 +00:00
Josh Roy f8cc0e41d1 Update FakeWorld (#3985) 2021-02-12 17:36:38 -08:00
MD f29f9e1aba Relocate GeoIP dependencies (#3976)
Relocates jackson, javatar and the MaxMind database libraries to avoid conflicts with other plugins.
2021-02-10 09:27:56 -05:00
MD 34fdcf8f6f Improve logging of dangerous userdata edge cases (#3969)
This commit improves the logging of a few edge cases that can lead to loss of userdata:
- Third-party plugins forcing creation of a NPC account which could not be found on the usermap, even if the account file exists
- UserMap#trackUUID being called with a conflicting UUID but replace set to false
2021-02-08 15:50:57 +00:00
Josh Roy adef08af3e Add world aliases for Chat (#3912)
Allows world names to be overridden with a defined value from the config in EssentialsX Chat.

Closes #1793.
2021-02-05 20:31:13 +00:00
Josh Roy 1301e8fc99 Show custom item aliases in /itemdb (#3907)
Shows items from the custom_items.yml resolver in /itemdb.

Closes #3686.
2021-02-05 20:27:33 +00:00
Josh Roy eee1c0628b Add API packages (#3938)
Adds packages for future EssentialsX 2.x API and services.
2021-02-05 20:13:03 +00:00
MD 9ce839c9d8 Update issue chooser with forms and Discussions links (#3936)
Co-authored-by: triagonal <10545540+triagonal@users.noreply.github.com>
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>

This commit:
- Introduces a bug reporting form
- Moves feature requests and support requests to Discussions
- Adds a default PR template instructing people to use the correct template
- Adds GitHub Sponsors and Open Collective to the Sponsor button
2021-02-05 19:58:26 +00:00
Josh Roy 401fc4d2eb Fix AntiBuild performing place checks for block state changes (#3914)
Bukkit sometimes decides that state changes are also a block placement. Work around this by comparing the previous block state with the new block type.

Fixes #3150.
2021-02-05 19:44:43 +00:00
Josh Roy 4e7f1377bf Infer jail name when the server only has one jail configured (#3911)
Closes #1122.
2021-02-05 19:39:20 +00:00
Josh Royanddarbyjack fccf796eeb Add /kitreset command (#3909)
Co-authored-by: darbyjack <admin@glaremasters.me>

Closes #163. Ports #2645, which had its branch messed up by merges.
2021-02-05 19:35:38 +00:00
Josh Roy 500edb7860 Add config option to disable message social spy (#3910)
Adds a config option to allow to prevent socialspy from reading private messages. Useful if all you want from social spy is to read commands defined in the list.

Closes #1095.
2021-02-05 19:02:26 +00:00
pop4959andJosh Roy cb168b0c8a Add support for material tags in enchant signs (#3694)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>

Closes #3653.
2021-02-05 18:57:32 +00:00
Simon 74131f816c Update VersionUtil Support Status Check (#3954)
Removed AirplaneLite as an unsupported fork as they removed their concerning patch.
2021-02-02 09:15:01 -05:00
luisc99andJosh Roy f1ef21eb0d Fix duplicate nickname check with custom display names (#3922)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-01-28 10:08:38 -05:00
DaniilandJosh Roy 79406613c1 Add /alts alias for /seen (#3931)
Adds `essentials.alts` also to allow server admins to not give mods the ips of users.

Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-01-28 09:29:50 -05:00
Josh Roy 89c1e3b60d Fix invalid formatted jail time strings in whois/seen (#3917)
Fixes #3916, a "slight" discrepancy on jail time reporting in whois and seen commands
2021-01-23 17:41:24 -05:00
224634d8d2 Improve VersionUtil version checks (#3812)
Co-authored-by: Dylan Xaldin <Puremin0rez515@gmail.com>
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2021-01-19 07:40:05 -05:00
Josh Roy e42d37e86d Fix various problems with firework meta (de)serialization (#3905)
Adds support for parsing fireworks charges (would previously cause exceptions due to illegal casts to FireworkMeta) and fixes createkit from producing invalid color values

Thanks to triagonal for reporting the exception caused by createkit.

Fixes #1283.
2021-01-19 07:30:09 -05:00
DaniilandJosh Roy 191c9e9302 Fix bPermissions not showing up as unsupported (#3928)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-01-18 21:22:04 -05:00
Daniil a482ddf0f6 Fix warp deleting message not showing (#3927)
Fixes #3926
2021-01-18 21:18:13 -05:00
Josh Roy 7245e84f00 Update to 1.16.5 (#3923) 2021-01-16 01:56:56 -05:00
DaniilandJosh Roy e287600c34 Add option to disable custom server-full message (#3899)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-01-11 00:10:07 -05:00
vk2gpz 817585a9a6 Properly detect enchantments with improper names (#3900) 2021-01-09 15:26:07 -05:00
triagonal eae8bc05c9 Prevent sending usage info when executing alternative commands (#3904) 2021-01-09 13:47:58 -05:00
Josh Roy 026d279556 Add option to only count online jailed time (#3705)
Adds `jail-online-time` config option to only count a player's online time to the jail cap.

This also fixes memory leak in `EssentialsTimer` which I found in the process of testing.

Closes #429.
2021-01-08 20:43:32 +00:00
Josh Roy 8177893e28 Add auto armor equip for kits (#3629)
Adds a config option to have player auto-equip armor from kits.

Also adds a performance improvement for all uses of EnumUtil#getAllMatching by switching it to an EnumSet.

Closes #347, closes #3452.
2021-01-08 20:39:32 +00:00
Josh Roy 70de83827d Allow paying offline users via /pay (#3625)
Closes #3577.
2021-01-08 20:35:00 +00:00
JoshuaandJosh Roy 5af9536db1 Add WarpModifyEvent (#3875)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-01-08 15:20:03 -05:00
Josh Roy cb7b2dabf5 Block removing hats with curse of binding using direct-hat (#3895)
Fixed loophole that allowed users to bypass curse of binding when using direct hat feature.

Related to #3299, which added similar checks to `/hat`.
2021-01-08 20:11:35 +00:00
LuukandJRoy 01987a0374 Fix AbstractItemDb#getMatching improper block filtering (#3691)
Co-authored-by: JRoy <joshroy126@gmail.com>
2021-01-03 12:45:32 -05:00
Josh Roy 5528b5b92c Allow users to middle click in armor invsee (#3893) 2021-01-02 15:36:12 -05:00
RyanandJosh Roy 1838354b70 Add ending user balance as a final field in trade.log (#3721)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-01-02 00:12:53 -05:00
1f1edd9b23 Add UserKickEvent (#3490)
Co-authored-by: MD <1917406+md678685@users.noreply.github.com>
Co-authored-by: JRoy <joshroy126@gmail.com>
2021-01-02 00:04:13 -05:00
kmecppandJRoy 2b7a4364b1 Don't lowercase item names in IItemDb#get(String, int) (#3636)
Co-authored-by: JRoy <joshroy126@gmail.com>
2021-01-01 23:16:24 -05:00
2f45d3edf3 Add API to register enchantment names/aliases (#3669)
Co-authored-by: MD <1917406+md678685@users.noreply.github.com>
Co-authored-by: JRoy <joshroy126@gmail.com>
2021-01-01 23:11:22 -05:00
Olivia a20d20574e Add TransactionEvent for successful transactions (#3649) 2021-01-01 22:45:52 -05:00
pop4959andJosh Roy d78832498e Fix warp messages sending incorrectly with teleport delays (#3696)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-01-01 22:06:09 -05:00
MDandJosh Roy e2c6170eba Add option to disable players respawning at beds (#3802)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-01-01 22:02:55 -05:00
powercas_gamerandJosh Roy 6864af762c Update plugin.yml (#3832)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2021-01-01 21:58:59 -05:00
OmegaWeaponDev a8daa2160f Separate option to cancel afk on chat from interact (#3863) 2020-12-31 19:20:08 -05:00
triagonal b84aaa1dab Fix behaviour of /list when showing real names (#3858) 2020-12-31 19:14:39 -05:00
Josh Roy c6de77130f Rework Currency Symbol Parsing (#3628)
* Made currency symbol standardized in Kit 
  * Kits should be in a standardized format.
  * Having monetary rewards in kits should not break based off of a config value oriented around currency display (suffix).
  * Additionally, the dollar sign should be the standard money symbol which works on all servers and should not be tied to the server's individual currency symbol.
  * Note that the server's individual currency symbol will still work but probably should not be used due its volatility.
* Reworked config currency symbol parsing in Settings 
  * Simplifies the number of actions needed to sanitize the input.
  * Now just defaults to `$` if the currency-symbol cannot be parsed.
* Removed symbol-suffixed parsing in NumberUtil#sanitizeCurrencyString
2020-12-30 15:37:30 -05:00
Josh Roy 02ba924f33 Fix AlternativeCommandsHandler not detecting some aliases (#3856) 2020-12-30 11:59:38 -08:00
Josh Roy 318df64e54 Fix Improper Use of Event API (#3853)
* Fix Improper Use of Event API

* Checkstyle OOOO
2020-12-21 18:35:58 +00:00
Josh Roy cb45867de8 Remove Jenkins from README (#3850)
EssX website is PogU, Jenkins is PogO
2020-12-21 15:21:36 +00:00
Jason c4ca0e51e2 Add restart note to respawn listener priority option (#3789) 2020-12-20 20:41:26 -08:00
triagonal 7bb12fd33c Fix incorrect radius check in /me command (#3848) 2020-12-20 20:08:11 -08:00
MD 001213ee2c Update bStats Metrics class to 1.8 (#3845)
Replace modified bStats Metrics 1.7 class with official 1.8 artifact. 1.8 adds random submit intervals and changes the way submissions are scheduled, and our custom modifications are no longer needed as we now use the plugin ID.
2020-12-19 16:27:07 +00:00
Josh Roy f320705216 Fix build script not working when git repo isn't cloned (#3831) 2020-12-13 20:54:54 -08:00
Josh Roy d4ed77fdc6 Update FakeServer (#3829) 2020-12-13 18:11:29 -08:00
Josh Roy ef1202923e Fix command handler not finding dynamically registered commands (#3816)
Fixes #3815.
2020-12-12 13:50:34 +00:00
e1e98f5048 Add /warpinfo command (#3820)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2020-12-11 16:38:10 +00:00
MD 5bb3cc88e5 Dispatch commands on main thread when run from XMPP (#3803)
This PR fixes an issue reported on Discord, where commands executed through XMPP are dispatched async from the XMPP listener thread.
2020-12-11 16:36:29 +00:00
Josh Roy 43eff69a2f Fix incompatibility on TacoSpigot and derivatives (#3817)
The countless support tickets from users of TacoSpigot (and forks of it)
have become so numerous it's not worth holding our ground on this. Taco fucked up
by going against upstream revision numbers, but as they're defunct, it's not
going to change now. We will not fix server implementations that do this in the
future, but hopefully they have all learned their lesson to use proper
versioning. The way md_5 intended.
2020-12-11 16:31:40 +00:00
Roman Zabaluev 450da59057 Allow console name to be translated (#3700)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>

Closes #2756. 

Notes:
- I've kept original name for internal purposes (storing bans, etc), just in case user wants to rename it to something unbearable;
- User can message console via both names (since he can try both, duh);
- Some refactoring. Just a little.
2020-12-11 16:29:48 +00:00
Josh Roy dda4d58a23 Move paperlib off snapshot (#3808) 2020-12-02 19:44:35 +00:00
Josh Roy f5d5ed9844 Fix respawn anchor explosion protection (#3778)
Fixes #3723, where respawn anchors explode at charges > 0 when glowstone isn't in the players hand, or at charges = 4 on right click regardless of item.
2020-12-02 19:43:01 +00:00
MD 2342d53dba Revert Spanish translation spam 2020-11-30 16:33:24 +00:00
MD 005d83c6fe Fix checkstyle-idea default settings 2020-11-30 15:01:14 +00:00
Flask Bot 8c4fb3fefb New Crowdin updates (#3793) 2020-11-28 11:10:49 +00:00
MD b0fa0d1ec8 Remove mavenLocal repo from default repositories 2020-11-26 12:39:52 +00:00
MD 2ce5797d5e Update metrics warnings 2020-11-26 12:26:08 +00:00
MD c2617e5a1d Fix javadoc warning suppression 2020-11-26 01:19:16 +00:00
MD 3f73e31d9e Suppress deprecation and javadoc warnings by default 2020-11-26 01:12:58 +00:00
MD 84a48adbdd Change resolution strategy to refresh snapshot dependencies more frequently 2020-11-26 01:04:11 +00:00
MD 63c29a318e Implement missing FakeWorld methods 2020-11-26 00:42:26 +00:00
MD 69748fd72e Make resource processing depend on version string 2020-11-26 00:38:27 +00:00
MD 35278c6e90 Upload GH artifacts before publish 2020-11-25 20:43:23 +00:00
MD 088fc35435 Mark gradlew as executable 2020-11-25 20:37:45 +00:00
MD 4baad6b89c Fix missing "s" which prevented GH Actions deployment 2020-11-25 20:33:33 +00:00
Josh Roy 9a23f806fe Refactor Project to Gradle (#3720)
Gradle is better than Maven, don't @ me. okay but actually it's [faster](https://www.youtube.com/watch?v=atuFSv2bLa8&feature=youtu.be&t=77), compiles and tests in parallel more efficiently, and more epic stuff).
2020-11-25 20:24:24 +00:00
powercas_gamer 82b466db0b update website links in config.yml (#3779)
Updates the website links in the config.yml to `essentialsx.net` instead of `essentialsx.cf`
2020-11-18 10:23:45 +00:00
JRoy a6edf04a60 Release 2.18.2 2020-11-16 11:32:40 +00:00
Josh Roy 3ba675a899 Allow users to modify existing homes when over homes limit (#3776)
Fixes #3761
2020-11-15 17:40:34 +00:00
pop4959 1fed7a9a3a Fix tab completion for delhome (#3775)
There was a minor issue with one line of code in delhome which was causing the user's homes not to be listed since the condition was effectively reversed. This was also causing an NPE for console senders attempting to tab complete.

Fixes #3774
2020-11-14 22:50:48 +00:00
80fb91b6d7 Fix /clear <player> <item> not clearing offhand (#3715)
Co-authored-by: Kenichycmd <kenichycmd@gmail.com>
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2020-11-09 16:43:55 +00:00
Josh Roy 5b0c2a4131 Use ray-tracing based target block for 1.13.2+ (#3763)
Uses new method of ray-tracing to target block instead of using BlockIterator which doesn't respect the player looking at a different y-level. Falls back to old BlockIterator method on server versions older than 1.13.2

Fixes #3756.
2020-11-09 16:38:02 +00:00
Josh Roy bb43e8f7b6 Add option to prevent replying from vanished players (#3703)
Closes #2066
2020-11-09 12:25:16 +00:00
Josh Roy 4d9a10147a Split backup command by space (#3762)
Splits command sent to ProcessBuilder by spaces. Fixes backup commands with arguments

Fixes #3759
2020-11-09 08:52:35 +00:00
Josh Roy ea4f5cf919 Update to 1.16.4 (#3753) 2020-11-02 13:36:48 -08:00
dependabot[bot] 295bc9f76d Bump junit from 4.12 to 4.13.1 (#3726)
Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1.
- [Release notes](https://github.com/junit-team/junit4/releases)
- [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md)
- [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-10-23 00:19:54 +01:00
MD 327806d9a1 Add new PR templates and revamp issue templates (#3711)
Adds new PR templates and revamps the existing issue templates to (hopefully) make the PR/issue submission easier to understand.
2020-10-23 00:19:04 +01:00
Josh Roy 80e7558fc0 Move some tab complete messages to debug mode only (#3739) 2020-10-22 12:15:02 -07:00
md678685 9cda59511e Consolidate permissions default setup into single class 2020-10-19 21:27:05 +01:00
md678685 c12a031918 Add more specific platform support messages 2020-10-19 21:26:38 +01:00
Alexander SöderbergandMD a4f580e319 Make HelpInput use the known command map (#3675)
Co-authored-by: MD <1917406+md678685@users.noreply.github.com>

This PR makes HelpInput use knownCommands in the command map, rather than relying on plugin descriptions. This means that commands that have been registered programmatically (or impromptu) will be recognized and displayed in the help menu.

The ugly reflection is due to Spigot not exposing the command map getter. This has been tested on Spigot 1.8, 1.16.3 and Paper 1.16.3 with plugins that register commands directly to the command map.
2020-10-19 15:27:40 +01:00
md678685 583bf88207 Implement ConsoleCommandSender methods 2020-10-19 15:06:50 +01:00
montlikadani a5f8e83e03 Remove redundant checks in the tree command (#3716) 2020-10-13 00:47:12 -07:00
Alexander Söderberg e2f17f11d3 Tab-complete plugin names in /help (#3713)
Plugin names are accepted as input to `/essentials:help`, but they are not completed. This makes it easier to lookup plugin commands.
2020-10-07 11:54:30 -07:00
md678685 4f8c040d06 Add link to Register license notice 2020-10-05 17:34:55 +01:00
Josh Roy af1d068022 Add more inventory commands (#3704)
Add more commands to access virtual crafting inventories (on platforms with the required APIs).

Closes #3195 and #108.
2020-10-05 14:45:33 +01:00
Andre_601andMD 1bd8d1c85c Update old EssentialsX URLs in issue templates (#3678)
Co-authored-by: MD <1917406+md678685@users.noreply.github.com>

This updates the old essentialsx.github.io domains to the new essentialsx.net one.
2020-10-05 14:20:17 +01:00
pop4959 d7fc859d14 Use username instead of nickname in console /sell messages (#3693)
Closes #3662

This PR changes the default placeholder `{0}` to username. Display name can still be used with `{5}`.

Before change:
messages.properties
`itemSoldConsole=\u00a7e{0} \u00a7asold\u00a7e {1}\u00a7a for \u00a7e{2} \u00a7a({3} items at {4} each).`
console
`[Essentials] ~test sold dirt for $64 (64 items at $1 each).`

After change:
messages.properties
`itemSoldConsole=\u00a7e{0} \u00a7asold\u00a7e {1}\u00a7a for \u00a7e{2} \u00a7a({3} items at {4} each).`
console
`[Essentials] pop4959 sold dirt for $64 (64 items at $1 each).`

messages.properties
`itemSoldConsole=\u00a7e{5} \u00a7asold\u00a7e {1}\u00a7a for \u00a7e{2} \u00a7a({3} items at {4} each).`
console
`[Essentials] ~test sold dirt for $64 (64 items at $1 each).`
2020-10-05 09:50:56 +01:00
Ryan ac953cd114 Remove sign color codes from trade.log (#3699)
Started looking into #3116 but noticed this issue and wanted to fix it first.

Also added a comment as to why the username is truncated as this took me a long time to figure out and seemed arbitrary. Probably could truncate the username later for trade signs only as other signs don't require any username to be present on the sign. However, for now I simply opted to document.
2020-10-05 09:47:12 +01:00
md678685 6e6dd041d5 Add Javadocs to most API classes 2020-10-04 19:59:42 +01:00
md678685 9b3c8a9df2 Reformat and fix Checkstyle violations 2020-10-04 19:59:42 +01:00
md678685 234a481b0d Add Checkstyle rules and suppressions
This commit adds Checkstyle rules for EssentialsX, based on those from the adventure library (https://github.com/KyoriPowered/adventure/tree/master/.checkstyle).

It also makes Checkstyle passes mandatory for a GH build to pass.
2020-10-04 19:59:42 +01:00
pop4959 89b3c9233e Bump Paperlib version (#3695) 2020-10-03 12:29:43 -07:00
Josh Roy 5d61a43fe1 Add balanceTopLine i18n translation string (#3626) 2020-09-25 19:16:12 -07:00
Olivia 29d5ccf751 Fix /lightning ignoring essentials.lightning.others (#3671) 2020-09-13 17:23:50 -07:00
l1ttleO fde0665593 Update Readme to list 1.16.3 as a supported version (#3666) 2020-09-12 10:58:54 -07:00
l1ttleO 29541b0995 Bump supported server version to 1.16.3 (#3664) 2020-09-12 10:37:18 -07:00
Josh Roy 05f31c5ddf Fix time command throwing exceptions when used in console (#3622)
Fixes #3621
2020-09-09 16:00:13 +01:00
JRoy f89840545d Revert clearinventory command to pre-command-refactor
This command is too big to rewrite without a behavior change
2020-09-09 15:52:59 +01:00
JRoy 18534f8576 Fix inverted messages in Commandpaytoggle 2020-09-09 15:52:38 +01:00
JRoy 1382a05dc8 Fix IEssentials#getOnlineUsers ABI breakage 2020-09-09 15:52:37 +01:00
JRoy 1671d4839c Clean up some tab completes that I missed 2020-09-09 15:52:29 +01:00
Josh Roy 4d2fbd04c5 Fix /sell and /worth messages displaying {1} instead of the item(s) value (#3656) 2020-09-08 12:36:05 -07:00
md678685 dc6b9b89cd Handle funky bStats classloading correctly
Fixes bStats for plugins that do funky classloading things, like AntiVPN.
2020-08-29 20:37:20 +01:00
Josh Roy 76f36aa895 [CI-SKIP] Some issue template updates (#3623)
Co-authored-by: MD <1917406+md678685@users.noreply.github.com>

* Forces use of issue templates
* Auto-labels issue templates
* Links to discord in the issue-create matrix as a better form of troubleshooting
2020-08-29 17:21:22 +01:00
Josh Roy fa835e9c64 Fix tablist name getting reset after AFK status change (#3624)
Fixes #3606.
2020-08-29 16:03:49 +01:00
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
md678685 279d6f16e1 Bump version to 2.17.2
\o/
2020-02-22 10:05:14 +00:00
md678685 a747eccaa3 Fix /fireball on 1.8.8 (#3027)
Dragon fireballs were added in 1.9 and so this previously caused an
error. This PR fixes that (and adds tridents as throwables). Fixes #3016.
2020-02-22 10:03:43 +00:00
md678685 0bafbc3184 Reduce permission check calls in PlayerCommandSendEvent (#3026)
This reduces permissions checks by only checking each command once, not checking each command for each alias.

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

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

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

* Update Essentials/src/kits.yml

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

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

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

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

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

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

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

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

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

---

* Update GeoIP

* Simplify branch

* Update old config detection

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

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

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

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

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

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

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

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

---

* Allow for control of transformations

* Undid removal of villager checking

* Undid removal of villager checking

* Documentation for transformation configs

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

* Removed duplicate configuration lines

* Updated info about husks drowning

* Changed config names

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

---

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

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

* Update workflow

* Run BuildTools in workflow

* Update build.yml

* Add distributionManagement to pom.xml

* Add GitHub registry Maven credentials

* Remove Travis CI config

* mkdir -p

* Remove GitHub package registry push

Didn't work anyway

* Remove distributionManagement

* Cache Maven repo

* Fix step order

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

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

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

* Remove achievement related methods for OfflinePlayer

* Add 1.15 to VersionUtil

* Revert "Remove achievement related methods for OfflinePlayer"

This reverts commit d0ab84e0

* Add 1.15 Mobs

* Remove Achievement related methods from OfflinePlayer

This needs more work as this currently breaks > 1.15 support

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

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

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

closes #1153, closes #162

---

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

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

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

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

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

# Description of #2457
Fixes #2121.

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

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

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

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

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

* Replace formatting implementation

* Add permissions for individual color codes

Resolves #415

* Use format code names

* Fix escaping

* Mockito: test scope only

* Explicitly check the .magic permission

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

* Add support for removing individual colors

* Use `obfuscated` as the name for §k

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* Allow resolvers to add item names to list

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

* New translations messages.properties (Russian)

* New translations messages.properties (Korean)

* New translations messages.properties (Lithuanian)

* New translations messages.properties (Polish)

* New translations messages.properties (Portuguese)

* New translations messages.properties (Portuguese, Brazilian)

* New translations messages.properties (Romanian)

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

* New translations messages.properties (Italian)

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

* New translations messages.properties (Slovak)

* New translations messages.properties (Spanish)

* New translations messages.properties (Swedish)

* New translations messages.properties (Thai)

* New translations messages.properties (Turkish)

* New translations messages.properties (Ukrainian)

* New translations messages.properties (Japanese)

* New translations messages.properties (Hungarian)

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

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

* New translations messages.properties (German)

* New translations messages.properties (Norwegian)

* New translations messages.properties (Bulgarian)

* New translations messages.properties (Basque)

* New translations messages.properties (Bosnian)

* New translations messages.properties (Chinese Simplified)

* New translations messages.properties (Chinese Traditional)

* New translations messages.properties (Croatian)

* New translations messages.properties (Hebrew)

* New translations messages.properties (Czech)

* New translations messages.properties (Danish)

* New translations messages.properties (Dutch)

* New translations messages.properties (Estonian)

* New translations messages.properties (Finnish)

* New translations messages.properties (French)

* New translations messages.properties (Greek)

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

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

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

* Re-add PermissionEX handler

* Use PaperLib to load chunks async whenever possible

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

This reverts commit db4df6f3cf.

* Use PaperLib to load chunks and teleport players async

* Resolve some PR issues

* Update PaperLib, return teleport causes

* Remove useless PaperLib usage in LocationUtil

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

* Re-add PermissionEX handler

* Use PaperLib to load chunks async whenever possible

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

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

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

* format text

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

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

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

No files matched your search

+183
View File
@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE module PUBLIC "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<!-- based on https://github.com/KyoriPowered/adventure/blob/master/.checkstyle/checkstyle.xml -->
<module name="Checker">
<property name="charset" value="UTF-8"/>
<property name="fileExtensions" value="java, properties, xml"/>
<property name="severity" value="error"/>
<!-- https://checkstyle.org/config_filefilters.html#BeforeExecutionExclusionFileFilter -->
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="module\-info\.java$"/>
</module>
<!-- https://checkstyle.org/config_whitespace.html#FileTabCharacter -->
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
</module>
<!-- https://checkstyle.org/config_misc.html#NewlineAtEndOfFile -->
<module name="NewlineAtEndOfFile"/>
<!-- https://checkstyle.org/config_filters.html#SuppressionFilter -->
<module name="SuppressionFilter">
<property name="file" value="${configDirectory}/suppressions.xml"/>
</module>
<!-- https://checkstyle.org/config_filters.html#SuppressWithPlainTextCommentFilter -->
<module name="SuppressWithPlainTextCommentFilter"/>
<module name="TreeWalker">
<!-- https://checkstyle.org/config_misc.html#ArrayTypeStyle -->
<module name="ArrayTypeStyle"/>
<!-- https://checkstyle.org/config_imports.html#AvoidStarImport -->
<module name="AvoidStarImport"/>
<!-- https://checkstyle.org/config_misc.html#AvoidEscapedUnicodeCharacters -->
<module name="AvoidEscapedUnicodeCharacters">
<property name="allowByTailComment" value="true"/>
<property name="allowEscapesForControlCharacters" value="true"/>
<property name="allowNonPrintableEscapes" value="true"/>
<property name="severity" value="info"/>
</module>
<!-- https://checkstyle.org/config_misc.html#CommentsIndentation -->
<module name="CommentsIndentation"/>
<!-- https://checkstyle.org/config_whitespace.html#EmptyForInitializerPad -->
<module name="EmptyForInitializerPad"/>
<!-- https://checkstyle.org/config_whitespace.html#EmptyForIteratorPad -->
<module name="EmptyForIteratorPad"/>
<!-- https://checkstyle.org/config_whitespace.html#EmptyLineSeparator -->
<module name="EmptyLineSeparator">
<property name="allowMultipleEmptyLines" value="false"/>
<property name="allowMultipleEmptyLinesInsideClassMembers" value="false"/>
<property name="allowNoEmptyLineBetweenFields" value="true"/>
<property name="tokens"
value="CLASS_DEF, CTOR_DEF, ENUM_DEF, IMPORT, INSTANCE_INIT, INTERFACE_DEF, METHOD_DEF, STATIC_IMPORT, STATIC_INIT, VARIABLE_DEF"/> <!-- remove PACKAGE_DEF, temporarily remove COMPACT_CTOR_DEF, RECORD_DEF -->
</module>
<!-- https://checkstyle.org/config_coding.html#FallThrough -->
<module name="FallThrough">
<property name="checkLastCaseGroup" value="true"/>
</module>
<!-- https://checkstyle.org/config_design.html#FinalClass -->
<module name="FinalClass"/>
<!-- https://checkstyle.org/config_coding.html#FinalLocalVariable -->
<module name="FinalLocalVariable"/>
<!-- https://checkstyle.org/config_whitespace.html#GenericWhitespace -->
<module name="GenericWhitespace"/>
<!-- https://checkstyle.org/config_design.html#HideUtilityClassConstructor -->
<module name="HideUtilityClassConstructor"/>
<!-- https://checkstyle.org/config_imports.html#IllegalImport -->
<module name="IllegalImport">
<property name="illegalPkgs" value="sun, jdk, com.sun"/>
</module>
<!-- https://checkstyle.org/config_coding.html#IllegalTokenText -->
<module name="IllegalTokenText">
<property name="format"
value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
<property name="message"
value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
<property name="tokens" value="CHAR_LITERAL, STRING_LITERAL"/>
</module>
<!-- https://checkstyle.org/config_misc.html#Indentation -->
<module name="Indentation"/>
<!-- https://checkstyle.org/config_blocks.html#LeftCurly -->
<module name="LeftCurly"/>
<!-- https://checkstyle.org/config_naming.html#MethodName -->
<module name="MethodName">
<property name="format" value="^[_]?[a-z][a-zA-Z0-9]*$"/>
</module>
<!-- https://checkstyle.org/config_whitespace.html#MethodParamPad -->
<module name="MethodParamPad"/>
<!-- https://checkstyle.org/config_javadoc.html#MissingJavadocMethod -->
<module name="MissingJavadocMethod">
<property name="allowMissingPropertyJavadoc" value="true"/>
<property name="tokens" value="METHOD_DEF, ANNOTATION_FIELD_DEF"/> <!-- remove CTOR_DEF, COMPACT_CTOR_DEF -->
</module>
<!-- https://checkstyle.org/config_javadoc.html#MissingJavadocType -->
<module name="MissingJavadocType"/>
<!-- https://checkstyle.org/config_coding.html#NoFinalizer -->
<module name="NoFinalizer"/>
<!-- https://checkstyle.org/config_whitespace.html#NoLineWrap -->
<module name="NoLineWrap"/>
<!-- https://checkstyle.org/config_whitespace.html#NoWhitespaceAfter -->
<module name="NoWhitespaceAfter">
<property name="allowLineBreaks" value="false"/>
</module>
<!-- https://checkstyle.org/config_whitespace.html#NoWhitespaceBefore -->
<module name="NoWhitespaceBefore">
<property name="allowLineBreaks" value="true"/>
</module>
<!-- https://checkstyle.org/config_coding.html#OneStatementPerLine -->
<module name="OneStatementPerLine"/>
<!-- https://checkstyle.org/config_misc.html#OuterTypeFilename -->
<module name="OuterTypeFilename"/>
<!-- https://checkstyle.org/config_imports.html#RedundantImport -->
<module name="RedundantImport"/>
<!-- https://checkstyle.org/config_modifier.html#RedundantModifier -->
<module name="RedundantModifier">
<property name="tokens"
value="ANNOTATION_FIELD_DEF, CLASS_DEF, CTOR_DEF, ENUM_DEF, INTERFACE_DEF, VARIABLE_DEF"/> <!-- remove METHOD_DEF and RESOURCE -->
</module>
<!-- https://checkstyle.org/config_coding.html#RequireThis -->
<module name="RequireThis"/>
<!-- https://checkstyle.org/config_blocks.html#RightCurly -->
<module name="RightCurly">
<property name="id" value="RightCurlyAlone"/>
<property name="option" value="alone"/>
<property name="tokens"
value="ANNOTATION_DEF, CLASS_DEF, CTOR_DEF, ENUM_DEF, INSTANCE_INIT, LITERAL_FOR, LITERAL_WHILE, METHOD_DEF, STATIC_INIT"/>
</module>
<module name="RightCurly">
<property name="id" value="RightCurlySame"/>
<property name="option" value="same"/>
<property name="tokens"
value="LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_IF, LITERAL_TRY"/> <!-- add LITERAL_DO -->
</module>
<!-- https://checkstyle.org/config_whitespace.html#SingleSpaceSeparator -->
<module name="SingleSpaceSeparator">
<property name="validateComments" value="true"/>
</module>
<!-- https://checkstyle.org/config_whitespace.html#TypecastParenPad -->
<module name="TypecastParenPad"/>
<!-- https://checkstyle.org/config_coding.html#UnnecessaryParentheses -->
<module name="UnnecessaryParentheses"/>
<!-- https://checkstyle.org/config_imports.html#UnusedImports -->
<module name="UnusedImports"/>
</module>
</module>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suppressions PUBLIC "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" "http://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
<suppress files=".*[\\/]test[\\/]java[\\/].*" checks="RequireExplicitVisibilityModifier"/>
<!-- TODO: don't suppress I-prefixed API interfaces under com.earth2me.essentials -->
<suppress files="(com[\\/]earth2me[\\/]essentials[\\/]|net[\\/]ess3[\\/]|net[\\/]essentialsx[\\/])(?:[^\\/]+$|(?!api)[^\\/]+[\\/])" checks="MissingJavadoc(Method|Type)"/>
</suppressions>
+13
View File
@@ -0,0 +1,13 @@
# Currently used
patreon: EssentialsX
ko_fi: essentialsx
github: EssentialsX
open_collective: EssentialsX
# Currently not used
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
#liberapay: # Replace with a single Liberapay username
#issuehunt: # Replace with a single IssueHunt username
#otechie: # Replace with a single Otechie username
#custom: # Replace with a single custom sponsorship URL
+20
View File
@@ -0,0 +1,20 @@
blank_issues_enabled: false
contact_links:
- name: View common issues
url: https://github.com/EssentialsX/Essentials/issues/3956
about: Check the list of known common issues to see if it solves your problem.
- name: Check past help requests
url: https://github.com/EssentialsX/Essentials/discussions/categories/q-a
about: Visit the Q&A forum to search for previous help requests.
- name: Check past feature suggestions
url: https://github.com/EssentialsX/Essentials/discussions/categories/ideas-and-feature-suggestions
about: Visit the Feature Suggestions forum to view and discuss existing feature suggestions.
- name: Create help request
url: https://github.com/EssentialsX/Essentials/discussions/new?category=q-a
about: Create a support ticket to get help from developers.
- name: Suggest a feature
url: https://github.com/EssentialsX/Essentials/discussions/new?category=ideas-and-feature-suggestions
about: Suggest new features for EssentialsX!
- name: Get help from the community on Discord
url: https://discord.gg/casfFyh
about: Join the MOSS Discord for community-powered EssentialsX support!
-45
View File
@@ -1,45 +0,0 @@
---
name: Help!
about: Encountered a problem with EssentialsX? Not sure how to fix it?
---
<!-- EssentialsX help guide
Don't write inside the arrows as they will be hidden when you post your issue.
Want faster support? Come join our Discord server to get help sooner:
https://discord.gg/F7gexAQ
If you're happy to wait (or you were sent here from Discord), read on:
1. Fill out the template.
This will help us understand what problem you've encountered and help us
find a solution.
2. Check the Common Issues page.
Read through the wiki page to see if you've encountered a regular issue:
https://essentialsx.github.io/#/Common-Issues
3. Delete this line and all above lines before posting your issue! -->
### Information
Full output of `/ess version`:
<!-- Replace this with the command output -->
**Server log:** <!-- Upload `logs/latest.log` to https://gist.github.com/ -->
**EssentialsX config** <!-- Upload `plugins/Essentials/config.yml` to https://gist.github.com/ -->
### Help request
**Problem**
<!-- What problem did you encounter? -->
**What I have tried**
<!-- What have you tried so far? -->
**Screenshots**
<!-- If relevant, include any screenshots here. -->
-58
View File
@@ -1,58 +0,0 @@
---
name: Report a bug
about: Report an EssentialsX bug. Only use this if you're 100% sure there's something wrong with EssentialsX - otherwise, try "Help!".
---
<!-- EssentialsX bug reporting guide
Don't put anything inside this block, as it won't be included in the issue.
If you are reporting a bug, please follow the following steps:
1. Fill out the template in full.
Run the commands in the console. Don't just put "latest" as a version,
or we will ignore it.
2. When linking files, do not attach them to the post!
Copy and paste any logs into https://gist.github.com/, then paste a
link to them in the relevant parts of the template. Avoid using
Hastebin or Pastebin, as this makes providing support more difficult.
**DO NOT drag files into this box!**
3. If you are reporting a performance issue, please include a link to a
Timings and/or profiler report.
4. If you are reporting a bug with commands or something else in-game,
please include screenshots to help us diagnose the problem.
5. Make sure not to write between the arrows, as anything there will be
hidden.
6. Delete this line and all above lines before posting your issue! -->
### Information
**Full output of `/ess version`**:
```
<!-- Run the command in your console, and copy and paste the whole output here -->
```
**Server log**: <!-- Upload `logs/latest.log` to https://gist.github.com/, replace this with link -->
**EssentialsX config**: <!-- Upload `plugins/Essentials/config.yml` to https://gist.github.com/, replace this with link -->
### Details
**Description**
<!-- Replace this with a brief summary of the bug. -->
**Steps to reproduce**
<!-- Replace this with exactly what you did to cause the bug. -->
**Expected behavior**
<!-- Replace this with what you expected to happen. -->
**Screenshots**
<!-- Replace this with screenshots, if necessary. -->
+79
View File
@@ -0,0 +1,79 @@
name: Report bug
description: Report a bug in EssentialsX.
labels: 'bug: unconfirmed'
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to report an EssentialsX bug! Fill out the form below to provide us with info to help fix the bug.
Only use this if you're 100% sure you've found a bug and can reproduce it. If you're looking for general help with EssentialsX, try the Q&A forum or MOSS Discord server.
- type: dropdown
attributes:
label: Type of bug
description: What type of bug is this? Choose all that apply.
multiple: true
options:
- Performance issue or memory leak
- Data loss
- Exploit
- Compatibility issue
- Error in console
- Other unexpected behaviour
validations:
required: true
- type: input
attributes:
label: "`/ess dump all` output"
description: Run `/ess dump all` in the console, then copy and paste the link from the output of the command into this box. (If this command doesn't work, you should [update EssentialsX](https://essentialsx.net/downloads.html) and try again.)
validations:
required: true
- type: input
attributes:
label: Error log (if applicable)
description: If you are reporting a console error, upload any relevant log excerpts to either https://paste.gg or https://gist.github.com, save and the paste the link in this box. If you included those files in the same paste as your startup log, paste the same link here.
placeholder: "Example: https://paste.gg/p/anonymous/109dd6a10a734a3aa430d5a351ea5210"
- type: textarea
attributes:
label: Bug description
description: Describe roughly what the bug is here.
placeholder: |
Example: "When running /nuke after putting everyone into adventure mode, there aren't any explosions..."
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce
description: Provide an example of how to trigger the bug.
placeholder: |
Example:
1. Have at least 3 people online
2. Run `/gma *` to put everyone into adventure mode
3. Run `/nuke`
validations:
required: true
- type: textarea
attributes:
label: Expected behaviour
description: Explain what you should expect to happen.
placeholder: |
Example: "Everything should explode!"
validations:
required: true
- type: textarea
attributes:
label: Actual behaviour
description: Explain what actually happens.
placeholder: |
Example: "Everything doesn't explode :("
validations:
required: true
- type: markdown
attributes:
value: |
In the text box below, you can attach any relevant screenshots, files and links to Timings/spark profiler reports.
You can also include a link to a heapdump if necessary, but please make sure you don't include any private player data in the heapdump.
If you suspect this issue is related to a prior issue/PR/commit, please mention it here.
@@ -1,45 +0,0 @@
---
name: Request a feature
about: Suggest a feature you want to see in EssentialsX!
---
<!-- EssentialsX feature request guide
Fill out the template. Don't write inside the arrows as they will be hidden
when you post your issue.
Not sure if your feature fits in EssentialsX? Feel free to ask on our Discord
server: https://discord.gg/F7gexAQ
If you have a feature suggestion for EssentialsX, read the following tips:
1. Fill out the template.
This will help us understand what you're requesting and why you want us
to add it.
2. Keep it simple.
Make sure it's easy to understand what you're requesting. A good way is
to keep it to one request per GitHub issue, as we can then easily track
feature requests.
3. Check whether it has already been asked or added.
You can search the issue tracker to see if your feature has already been
requested at https://github.com/EssentialsX/Essentials/issues. You can
also check the wiki at https://essentialsx.github.io/ to see if the
feature was recently added.
4. Ask yourself: "Does this belong in EssentialsX?"
There are lots of features that we reject because most servers won't
need or use them. If your feature is very specific or already exists in
another plugin, it might not be a good fit for EssentialsX.
5. Delete this line and all above lines before posting your issue! -->
### Feature request
**Feature description**
<!-- What feature are you suggesting? -->
**How the feature is useful**
<!-- How is the feature useful to players, server owners and/or developers? -->
+94
View File
@@ -0,0 +1,94 @@
<!--
EssentialsX bug fix submission guide
====================================
NOTE: Failure to fill out this template properly may result in your PR being
delayed or ignored without warning.
NOTE: Don't type between any arrows in the template, as this text will be
hidden. This includes this header block and any other explanation text
blocks.
Want to discuss your PR before submitting it? Join the EssentialsX Development
server: https://discord.gg/CUN7qVb
EssentialsX is GPL
------------------
By contributing to EssentialsX, you agree to license your code under the
GNU General Public License version 3, which can be found at the link below:
https://github.com/EssentialsX/Essentials/blob/2.x/LICENSE
Instructions
------------
If you are submitting a bug fix, please follow the following steps:
1. Fill out the template in full.
This includes providing screenshots and a link to the original bug
report. If there isn't an existing bug report, we recommend opening a new
detailed bug report BEFORE opening your PR to fix it, else your PR may be
delayed or rejected without warning.
You can open a new bug report by following this link:
https://github.com/EssentialsX/Essentials/issues/new/choose
2. When linking logs or config files, do not attach them to the post!
Copy and paste any logs into https://gist.github.com/, then paste a
link to them in the relevant parts of the template. Do not use Hastebin
or Pastebin, as this can cause issues with future reviews.
DO NOT drag logs directly into this text box, as we cannot read these!
3. If you are fixing a performance issue, please include a link to a
Timings and/or profiler report, both before and after your PR.
4. If you are fixing a visual bug, such as in commands, please include
screenshots so that we can more easily review the proposed fix.
(You can drag screenshots into the bottom of the editor.)
-->
### Information
<!--
Replace #nnnn with the number of the original issue. If this PR fixes
multiple issues, you should repeat the phrase "fixes #nnnn" for each issue.
-->
This PR fixes #nnnn.
### Details
**Proposed fix:**
<!-- Type a description of your proposed fix below this line. -->
**Environments tested:**
<!-- Type the OS you have used below. -->
OS:
<!-- Type the JDK version (from java -version) you have used below. -->
Java version:
<!--
Put an "x" inside the boxes for the server software you have tested this
bug fix on. If this feature does not apply to a server, strike through the server software using ~~strikethrough~~. If you have tested on other
environments, add a new line with relevant details.
-->
- [ ] Most recent Paper version (1.XX.Y, git-Paper-BUILD)
- [ ] CraftBukkit/Spigot/Paper 1.12.2
- [ ] CraftBukkit 1.8.8
**Demonstration:**
<!--
Below this block, include screenshots/log snippets from before and after as
necessary. If you have created or used a test case plugin, please link to a
download of the plugin, source code and exact version used where possible.
-->
+8
View File
@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: MOSS Discord Server
url: https://discord.gg/casfFyh
about: Need help with using EssentialsX? Join the MOSS Discord server for help.
- name: EssentialsX Development Discord Server
url: https://discord.gg/CUN7qVb
about: Got questions or want to discuss changes before opening your PR? Join the EssentialsX Development Discord server. (Need help? Join MOSS instead.)
@@ -0,0 +1,93 @@
<!--
EssentialsX feature submission guide
====================================
NOTE: Failure to fill out this template properly may result in your PR being
delayed or ignored without warning.
NOTE: Don't type between any arrows in the template, as this text will be
hidden. This includes this header block and any other explanation text
blocks.
Want to discuss your PR before submitting it? Join the EssentialsX Development
server: https://discord.gg/CUN7qVb
EssentialsX is GPL
------------------
By contributing to EssentialsX, you agree to license your code under the
GNU General Public License version 3, which can be found at the link below:
https://github.com/EssentialsX/Essentials/blob/2.x/LICENSE
Instructions
------------
If you are submitting a new feature, please follow the following steps:
1. Fill out the template in full.
This includes providing screenshots and a link to the original feature
request. If there isn't an existing feature request, we strongly
recommend opening a new feature request BEFORE opening your PR to
implement it, as this allows us to review whether we're likely to accept
your feature in advance, and also allows us to discuss possible
implementations for the feature. If there is no associated feature
request, your PR may be delayed or rejected without warning.
You can open a new feature request by following this link:
https://github.com/EssentialsX/Essentials/issues/new/choose
2. If you are fixing a performance issue, please use the "Bug fix" PR template
instead. The "bug fix" template is better suited to performance issues.
3. Include a demonstration.
If you are adding commands, please provide screenshots and/or a video
demonstration of the feature. Similarly, if you are adding a new API,
please include a link to example code that takes advantage of your
proposed API. This will aid us in reviewing PRs and speed up the process
significantly.
-->
### Information
<!--
Replace #nnnn with the number of the original issue. If this PR implements
features from multiple issues, you should repeat the phrase "closes #nnnn"
for each issue.
-->
This PR closes #nnnn.
### Details
**Proposed feature:**
<!-- Type a description of your proposed feature below this line. -->
**Environments tested:**
<!-- Type the OS you have used below. -->
OS:
<!-- Type the JDK version (from java -version) you have used below. -->
Java version:
<!--
Put an "x" inside the boxes for the server software you have tested this
bug fix on. If this feature does not apply to a server, strike through the server software using ~~strikethrough~~. If you have tested on other
environments, add a new line with relevant details.
-->
- [ ] Most recent Paper version (1.XX.Y, git-Paper-BUILD)
- [ ] CraftBukkit/Spigot/Paper 1.12.2
- [ ] CraftBukkit 1.8.8
**Demonstration:**
<!--
Below this block, include screenshots/log snippets from before and after as
necessary. If you have created or used a test case plugin, please link to a
download of the plugin, source code and exact version used where possible.
-->
+10
View File
@@ -0,0 +1,10 @@
You need to select a pull request template!
If you're adding a new feature, copy and paste the following parameter at the end of the URL:
?template=new-feature.md
If you're fixing a bug, copy and paste the following parameter at the end of the URL:
?template=bug-fix.md
For more information about contributing to EssentialsX, see CONTRIBUTING.md:
https://github.com/EssentialsX/Essentials/blob/2.x/CONTRIBUTING.md
+75
View File
@@ -0,0 +1,75 @@
name: Build EssentialsX
on:
push:
branches:
- 2.x
- dev/*
jobs:
build:
name: Build and upload
runs-on: ubuntu-latest
steps:
- name: Checkout Git repo
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Restore Gradle cache
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Set up JDK 16
uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: 16
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
- name: Build with Gradle
run: |
chmod +x gradlew
./gradlew build --stacktrace
- name: Archive plugin jars on GitHub
uses: actions/upload-artifact@master
with:
name: EssentialsX plugin jars
path: jars/
- name: Deploy to Maven repo
if: ${{ success() && github.event_name == 'push' && github.repository == 'EssentialsX/Essentials' && github.ref == 'refs/heads/2.x' }}
env:
ORG_GRADLE_PROJECT_essxUsername: ${{ secrets.ESSENTIALSX_DEPLOY_USERNAME }}
ORG_GRADLE_PROJECT_essxPassword: ${{ secrets.ESSENTIALSX_DEPLOY_PASSWORD }}
run: |
./gradlew publish
- name: Prepare Javadocs
if: ${{ success() && github.event_name == 'push' && github.repository == 'EssentialsX/Essentials' && github.ref == 'refs/heads/2.x' }}
run: |
mv Essentials/build/docs/javadoc/ javadocs/
cp -r EssentialsAntiBuild/build/docs/javadoc/ javadocs/EssentialsAntiBuild/
cp -r EssentialsChat/build/docs/javadoc/ javadocs/EssentialsChat/
cp -r EssentialsDiscord/build/docs/javadoc/ javadocs/EssentialsDiscord/
cp -r EssentialsGeoIP/build/docs/javadoc/ javadocs/EssentialsGeoIP/
cp -r EssentialsProtect/build/docs/javadoc/ javadocs/EssentialsProtect/
cp -r EssentialsSpawn/build/docs/javadoc/ javadocs/EssentialsSpawn/
cp -r EssentialsXMPP/build/docs/javadoc/ javadocs/EssentialsXMPP/
- name: Deploy Javadocs
if: ${{ success() && github.event_name == 'push' && github.repository == 'EssentialsX/Essentials' && github.ref == 'refs/heads/2.x' }}
uses: netlify/actions/cli@master
with:
args: deploy --dir=javadocs/ --prod --message="GitHubActionsDeploy"
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_JD_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_JD_2X_SITE_ID }}
+51
View File
@@ -0,0 +1,51 @@
name: Build Pull Request
on:
push:
branches:
- mc/* # MC version updates
- pr/* # PR rebases
pull_request:
branches:
- 2.x
- mc/*
- dev/*
jobs:
build:
name: Build and upload
runs-on: ubuntu-latest
steps:
- name: Checkout Git repo
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Restore Gradle cache
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Set up JDK 16
uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: 16
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
- name: Build with Gradle
run: |
chmod +x gradlew
./gradlew build --stacktrace
- name: Archive plugin jars on GitHub
uses: actions/upload-artifact@master
with:
name: EssentialsX plugin jars
path: jars/
+28 -53
View File
@@ -1,53 +1,28 @@
.DS_Store
/BuildAll/nbproject/private/
/EssentialsProtect/nbproject/private/
/EssentialsChat/nbproject/private/
/EssentialsGroupBridge/nbproject/private/
/EssentialsGeoIP/nbproject/private/
/EssentialsSpawn/nbproject/private/
/EssentialsXMPP/nbproject/private/
/BuildAll/build/
/EssentialsGroupBridge/dist/
/EssentialsGroupBridge/build/
/EssentialsGeoIP/dist/
/EssentialsGeoIP/build/
/BuildAll/dist/
/EssentialsChat/build/
/EssentialsChat/dist/
/EssentialsSpawn/build/
/EssentialsSpawn/dist/
/EssentialsXMPP/dist/
/EssentialsXMPP/build/
/EssentialsProtect/dist/
/EssentialsProtect/build/
/EssentialsPermissionsCommands/nbproject/private/
/EssentialsPermissionsCommands/build/
/EssentialsPermissionsCommands/dist/
/Essentials/nbproject/private/
/Essentials/dist/
/Essentials/build/
/YamlAnnotations/
/EssentialsUpdate/nbproject/private/
/EssentialsRelease/
/EssentialsUpdate/dist/
/EssentialsUpdate/build/
/WebPush/apikey.php
/WebPush/nbproject/private
/EssentialsAntiBuild/nbproject/private/
/EssentialsAntiBuild/dist/
/EssentialsAntiBuild/build/
/jars
/out
.idea/
*.iml
*.classpath
*.project
*.settings/
target/
dependency-reduced-pom.xml
/Essentials/config.yml
/Essentials/kits.yml
/Essentials/userdata/testplayer1.yml
/Essentials/usermap.csv
/Essentials/userdata
/EssentialsGroupManager/target/
# Other IDE files
*.classpath
*.project
*.settings/
.idea/*
*.iml
.DS_Store
# Checkstyle-IDEA config
!.idea/checkstyle-idea.xml
# Essentials files
/Essentials/userdata
/Essentials/config.yml
/Essentials/kits.yml
/Essentials/userdata/testplayer1.yml
/Essentials/usermap.csv
# Build files
.gradle/
/jars/
out/
build/
target/
*.class
# Run directory
/run/
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CheckStyle-IDEA">
<option name="configuration">
<map>
<entry key="active-configuration" value="PROJECT_RELATIVE:$PROJECT_DIR$/.checkstyle/checkstyle.xml:EssentialsX" />
<entry key="checkstyle-version" value="8.36.2" />
<entry key="copy-libs" value="true" />
<entry key="location-0" value="BUNDLED:(bundled):Sun Checks" />
<entry key="location-1" value="BUNDLED:(bundled):Google Checks" />
<entry key="location-2" value="PROJECT_RELATIVE:$PROJECT_DIR$/.checkstyle/checkstyle.xml:EssentialsX" />
<entry key="property-2.configDirectory" value=".checkstyle/" />
<entry key="scan-before-checkin" value="true" />
<entry key="scanscope" value="JavaOnly" />
<entry key="suppress-errors" value="false" />
</map>
</option>
</component>
</project>
-23
View File
@@ -1,23 +0,0 @@
language: java
branches:
only:
- 2.x
- 1.13
cache:
directories:
- .buildtools
- $HOME/.m2
before_install:
- mkdir -p .buildtools
- cd .buildtools
- wget -O BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar
- rm -r work/
- java -jar BuildTools.jar --rev 1.8
- java -jar BuildTools.jar --rev 1.8.3
- java -jar BuildTools.jar --rev 1.9
- java -jar BuildTools.jar --rev 1.9.4
- java -jar BuildTools.jar --rev 1.13.1
- cd ..
+31
View File
@@ -0,0 +1,31 @@
Contributing to EssentialsX
===========================
Want to help improve EssentialsX? There are several ways you can support and contribute to the project.
If you'd like to make a financial contribution to the project, you can join our [Patreon](https://www.patreon.com/essentialsx/),
or to make a one-off donation you can visit our [Ko-fi page](https://ko-fi.com/essentialsx). If you can't make a
donation, don't worry! There are lots of other ways to contribute:
* Do you run a server? Take a look at our ["help wanted"](https://github.com/EssentialsX/Essentials/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22help+wanted%22)
and ["bug: unconfirmed"](https://github.com/EssentialsX/Essentials/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22bug%3A+unconfirmed%22)
issues, where you can find issues that need extra testing and investigation.
* Do you speak multiple languages? If so, we always welcome contributions to our [Crowdin project](https://crowdin.com/project/essentialsx-official).
* Do you enjoy helping others? If so, why not contribute to the [EssentialsX documentation](https://github.com/EssentialsX/wiki)?
You can also join the [MOSS Discord community](https://discord.gg/casfFyh) and provide direct community support to
other EssentialsX users.
* If you're a developer, you could look through our ["open to PR"](https://github.com/EssentialsX/Essentials/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22status%3A+open+to+PR%22)
issues. We're always happy to receive bug fixes and feature additions as pull requests.
Submitting a PR
---------------
EssentialsX has extensive templates for PRs that detail how to submit your PR. To find out more, see the PR templates for:
* [Bug fixes](https://github.com/EssentialsX/Essentials/blob/2.x/.github/PULL_REQUEST_TEMPLATE/bug-fix.md)
* [New features](https://github.com/EssentialsX/Essentials/blob/2.x/.github/PULL_REQUEST_TEMPLATE/new-feature.md)
Want to discuss a feature before opening a PR? Join the [EssentialsX Development Discord server](https://discord.gg/CUN7qVb). Note that this server is **not for end-users** - if you need support with EssentialsX, you should join [MOSS](https://discord.gg/casfFyh) instead.
By contributing to EssentialsX, you agree to license your code under the [GNU General Public License version 3](https://github.com/EssentialsX/Essentials/blob/2.x/LICENSE).
+58
View File
@@ -0,0 +1,58 @@
plugins {
id("essentials.shadow-module")
}
dependencies {
compileOnly('com.github.milkbowl:VaultAPI:1.7') {
exclude group: "org.bukkit", module: "bukkit"
}
compileOnly 'net.luckperms:api:5.0'
api 'io.papermc:paperlib:1.0.6'
api 'org.bstats:bstats-bukkit:2.2.1'
implementation 'org.spongepowered:configurate-yaml:4.1.2'
implementation 'org.checkerframework:checker-qual:3.14.0'
// Providers
api project(':providers:BaseProviders')
api project(':providers:PaperProvider')
api(project(':providers:NMSReflectionProvider')) {
exclude group: "org.bukkit", module: "bukkit"
}
api(project(':providers:1_8Provider')) {
exclude group: "org.spigotmc", module: "spigot"
}
api(project(':providers:1_12Provider')) {
exclude group: "org.bukkit", module: "bukkit"
}
}
shadowJar {
dependencies {
include (dependency('io.papermc:paperlib'))
include (dependency('org.bstats:bstats-bukkit'))
include (dependency('org.bstats:bstats-base'))
include (dependency('org.spongepowered:configurate-yaml'))
include (dependency('org.spongepowered:configurate-core'))
include (dependency('org.yaml:snakeyaml'))
include (dependency('io.leangen.geantyref:geantyref'))
include (dependency('org.checkerframework:checker-qual'))
include (project(':providers:BaseProviders'))
include (project(':providers:PaperProvider'))
include (project(':providers:NMSReflectionProvider'))
include (project(':providers:1_8Provider'))
include (project(':providers:1_12Provider'))
}
relocate 'io.papermc.lib', 'com.earth2me.essentials.paperlib'
relocate 'org.bstats', 'com.earth2me.essentials.libs.bstats'
relocate 'org.spongepowered.configurate', 'com.earth2me.essentials.libs.configurate'
relocate 'org.yaml.snakeyaml', 'com.earth2me.essentials.libs.snakeyaml'
relocate 'io.leangen.geantyref', 'com.earth2me.essentials.libs.geantyref'
relocate 'org.checkerframework', 'com.earth2me.essentials.libs.checkerframework'
minimize {
include(dependency('org.checkerframework:checker-qual'))
}
}
-122
View File
@@ -1,122 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.ess3</groupId>
<artifactId>EssentialsXParent</artifactId>
<version>2.16.0</version>
</parent>
<artifactId>EssentialsX</artifactId>
<licenses>
<license>
<name>GPLv3</name>
<url>http://www.gnu.org/copyleft/gpl.html</url>
</license>
</licenses>
<build>
<finalName>EssentialsX-${full.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<showDeprecation>false</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>net.milkbowl.vault</groupId>
<artifactId>Vault</artifactId>
<version>1.5.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>NMSProvider</artifactId>
<version>2.16.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>UpdatedMetaProvider</artifactId>
<version>2.16.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>1_8_R1Provider</artifactId>
<version>2.16.0</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>1_8_R2Provider</artifactId>
<version>2.16.0</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>LegacyProvider</artifactId>
<version>2.16.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>ReflectionProvider</artifactId>
<version>2.16.0</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
<artifactId>FlattenedProvider</artifactId>
<version>2.16.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>vault-repo</id>
<url>http://nexus.hc.to/content/repositories/pub_releases</url>
</repository>
</repositories>
</project>
@@ -1,113 +0,0 @@
package com.earth2me.essentials;
import net.ess3.api.IEssentials;
import org.bukkit.command.Command;
import org.bukkit.command.PluginCommand;
import org.bukkit.command.PluginCommandYamlParser;
import org.bukkit.plugin.Plugin;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class AlternativeCommandsHandler {
private static final Logger LOGGER = Logger.getLogger("Essentials");
private final transient Map<String, List<PluginCommand>> altcommands = new HashMap<>();
private final transient Map<String, String> disabledList = new HashMap<>();
private final transient IEssentials ess;
public AlternativeCommandsHandler(final IEssentials ess) {
this.ess = ess;
for (Plugin plugin : ess.getServer().getPluginManager().getPlugins()) {
if (plugin.isEnabled()) {
addPlugin(plugin);
}
}
}
public final void addPlugin(final Plugin plugin) {
if (plugin.getDescription().getMain().contains("com.earth2me.essentials")) {
return;
}
final List<Command> commands = PluginCommandYamlParser.parse(plugin);
final String pluginName = plugin.getDescription().getName().toLowerCase(Locale.ENGLISH);
for (Command command : commands) {
final PluginCommand pc = (PluginCommand) command;
final List<String> labels = new ArrayList<>(pc.getAliases());
labels.add(pc.getName());
PluginCommand reg = ess.getServer().getPluginCommand(pluginName + ":" + pc.getName().toLowerCase(Locale.ENGLISH));
if (reg == null) {
reg = ess.getServer().getPluginCommand(pc.getName().toLowerCase(Locale.ENGLISH));
}
if (reg == null || !reg.getPlugin().equals(plugin)) {
continue;
}
for (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);
}
boolean found = false;
for (PluginCommand pc2 : plugincommands) {
if (pc2.getPlugin().equals(plugin)) {
found = true;
}
}
if (!found) {
plugincommands.add(reg);
}
}
}
}
public void removePlugin(final Plugin plugin) {
final Iterator<Map.Entry<String, List<PluginCommand>>> iterator = altcommands.entrySet().iterator();
while (iterator.hasNext()) {
final Map.Entry<String, List<PluginCommand>> entry = iterator.next();
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();
}
}
if (entry.getValue().isEmpty()) {
iterator.remove();
}
}
}
public PluginCommand getAlternative(final String label) {
final List<PluginCommand> commands = altcommands.get(label);
if (commands == null || commands.isEmpty()) {
return null;
}
if (commands.size() == 1) {
return commands.get(0);
}
// return the first command that is not an alias
for (PluginCommand command : commands) {
if (command.getName().equalsIgnoreCase(label)) {
return command;
}
}
// return the first alias
return commands.get(0);
}
public void executed(final String label, final PluginCommand pc) {
final String altString = pc.getPlugin().getName() + ":" + pc.getLabel();
if (ess.getSettings().isDebug()) {
LOGGER.log(Level.INFO, "Essentials: Alternative command " + label + " found, using " + altString);
}
disabledList.put(label, altString);
}
public Map<String, String> disabledCommands() {
return disabledList;
}
}
@@ -1,132 +0,0 @@
package com.earth2me.essentials;
import net.ess3.api.IEssentials;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.earth2me.essentials.I18n.tl;
public class Backup implements Runnable {
private static final Logger LOGGER = Logger.getLogger("Essentials");
private transient final Server server;
private transient final IEssentials ess;
private transient boolean running = false;
private transient int taskId = -1;
private transient boolean active = false;
public Backup(final IEssentials ess) {
this.ess = ess;
server = ess.getServer();
if (!ess.getOnlinePlayers().isEmpty()) {
ess.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
startTask();
}
});
}
}
public void onPlayerJoin() {
startTask();
}
public synchronized void stopTask() {
running = false;
if (taskId != -1) {
server.getScheduler().cancelTask(taskId);
}
taskId = -1;
}
private synchronized void startTask() {
if (!running) {
final long interval = ess.getSettings().getBackupInterval() * 1200; // minutes -> ticks
if (interval < 1200) {
return;
}
taskId = ess.scheduleSyncRepeatingTask(this, interval, interval);
running = true;
}
}
@Override
public void run() {
if (active) {
return;
}
active = true;
final String command = ess.getSettings().getBackupCommand();
if (command == null || "".equals(command)) {
return;
}
if ("save-all".equalsIgnoreCase(command)) {
final CommandSender cs = server.getConsoleSender();
server.dispatchCommand(cs, "save-all");
active = false;
return;
}
LOGGER.log(Level.INFO, tl("backupStarted"));
final CommandSender cs = server.getConsoleSender();
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();
}
} 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"));
}
}
ess.scheduleSyncDelayedTask(new BackupEnableSaveTask());
}
}
});
}
}
@@ -1,953 +0,0 @@
/*
* Essentials - a bukkit plugin
* Copyright (C) 2011 Essentials Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.earth2me.essentials;
import com.earth2me.essentials.commands.*;
import com.earth2me.essentials.items.AbstractItemDb;
import com.earth2me.essentials.items.FlatItemDb;
import com.earth2me.essentials.items.LegacyItemDb;
import com.earth2me.essentials.metrics.Metrics;
import com.earth2me.essentials.perm.PermissionsHandler;
import com.earth2me.essentials.register.payment.Methods;
import com.earth2me.essentials.signs.SignBlockListener;
import com.earth2me.essentials.signs.SignEntityListener;
import com.earth2me.essentials.signs.SignPlayerListener;
import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import net.ess3.api.*;
import net.ess3.api.IEssentials;
import net.ess3.api.ISettings;
import net.ess3.nms.PotionMetaProvider;
import net.ess3.nms.SpawnEggProvider;
import net.ess3.nms.SpawnerProvider;
import net.ess3.nms.flattened.FlatSpawnEggProvider;
import net.ess3.nms.legacy.LegacyPotionMetaProvider;
import net.ess3.nms.legacy.LegacySpawnEggProvider;
import net.ess3.nms.legacy.LegacySpawnerProvider;
import net.ess3.nms.refl.ReflSpawnEggProvider;
import net.ess3.nms.updatedmeta.BasePotionDataProvider;
import net.ess3.nms.updatedmeta.BlockMetaSpawnerProvider;
import net.ess3.nms.v1_8_R1.v1_8_R1SpawnerProvider;
import net.ess3.nms.v1_8_R2.v1_8_R2SpawnerProvider;
import net.ess3.providers.ProviderFactory;
import 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.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.InvalidDescriptionException;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import org.yaml.snakeyaml.error.YAMLException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.earth2me.essentials.I18n.tl;
public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
private static final Logger LOGGER = Logger.getLogger("Essentials");
private transient ISettings settings;
private final transient TNTExplodeListener tntListener = new TNTExplodeListener(this);
private transient Jails jails;
private transient Warps warps;
private transient Worth worth;
private transient List<IConf> confList;
private transient Backup backup;
private transient AbstractItemDb itemDb;
private transient final Methods paymentMethod = new Methods();
private transient PermissionsHandler permissionsHandler;
private transient AlternativeCommandsHandler alternativeCommandsHandler;
private transient UserMap userMap;
private transient ExecuteTimer execTimer;
private transient I18n i18n;
private transient Metrics metrics;
private transient EssentialsTimer timer;
private final transient Set<String> vanishedPlayers = new LinkedHashSet<>();
private transient Method oldGetOnlinePlayers;
private transient SpawnerProvider spawnerProvider;
private transient SpawnEggProvider spawnEggProvider;
private transient PotionMetaProvider potionMetaProvider;
private transient Kits kits;
public Essentials() {
}
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;
}
public void setupForTesting(final Server server) throws IOException, InvalidDescriptionException {
final File dataFolder = File.createTempFile("essentialstest", "");
if (!dataFolder.delete()) {
throw new IOException();
}
if (!dataFolder.mkdir()) {
throw new IOException();
}
i18n = new I18n(this);
i18n.onEnable();
i18n.updateLocale("en");
Console.setInstance(this);
LOGGER.log(Level.INFO, tl("usingTempFolderForTesting"));
LOGGER.log(Level.INFO, dataFolder.toString());
settings = new Settings(this);
userMap = new UserMap(this);
permissionsHandler = new PermissionsHandler(this, false);
Economy.setEss(this);
confList = new ArrayList<>();
jails = new Jails(this);
registerListeners(server.getPluginManager());
kits = new Kits(this);
}
@Override
public void onEnable() {
try {
if (LOGGER != this.getLogger()) {
LOGGER.setParent(this.getLogger());
}
execTimer = new ExecuteTimer();
execTimer.start();
i18n = new I18n(this);
i18n.onEnable();
execTimer.mark("I18n1");
Console.setInstance(this);
if (!VersionUtil.isServerSupported()) {
getLogger().severe(tl("serverUnsupported"));
}
final PluginManager pm = getServer().getPluginManager();
for (Plugin plugin : pm.getPlugins()) {
if (plugin.getDescription().getName().startsWith("Essentials") && !plugin.getDescription().getVersion().equals(this.getDescription().getVersion()) && !plugin.getDescription().getName().equals("EssentialsAntiCheat")) {
getLogger().warning(tl("versionMismatch", plugin.getDescription().getName()));
}
}
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();
execTimer.mark("Upgrade");
confList = new ArrayList<>();
settings = new Settings(this);
confList.add(settings);
execTimer.mark("Settings");
userMap = new UserMap(this);
confList.add(userMap);
execTimer.mark("Init(Usermap)");
kits = new Kits(this);
confList.add(kits);
upgrade.convertKits();
execTimer.mark("Kits");
upgrade.afterSettings();
execTimer.mark("Upgrade2");
warps = new Warps(getServer(), this.getDataFolder());
confList.add(warps);
execTimer.mark("Init(Spawn/Warp)");
worth = new Worth(this.getDataFolder());
confList.add(worth);
itemDb = getItemDbFromConfig();
confList.add(itemDb);
execTimer.mark("Init(Worth/ItemDB)");
jails = new Jails(this);
confList.add(jails);
execTimer.mark("Init(Jails)");
spawnerProvider = new ProviderFactory<>(getLogger(),
Arrays.asList(
BlockMetaSpawnerProvider.class,
v1_8_R2SpawnerProvider.class,
v1_8_R1SpawnerProvider.class,
LegacySpawnerProvider.class
), "mob spawner").getProvider();
spawnEggProvider = new ProviderFactory<>(getLogger(),
Arrays.asList(
FlatSpawnEggProvider.class,
ReflSpawnEggProvider.class,
LegacySpawnEggProvider.class
), "spawn egg").getProvider();
potionMetaProvider = new ProviderFactory<>(getLogger(),
Arrays.asList(
BasePotionDataProvider.class,
LegacyPotionMetaProvider.class
), "potion meta").getProvider();
execTimer.mark("Init(Providers)");
reload();
} catch (YAMLException exception) {
if (pm.getPlugin("EssentialsUpdate") != null) {
LOGGER.log(Level.SEVERE, tl("essentialsHelp2"));
} else {
LOGGER.log(Level.SEVERE, tl("essentialsHelp1"));
}
handleCrash(exception);
return;
}
backup = new Backup(this);
permissionsHandler = new PermissionsHandler(this, settings.useBukkitPermissions());
alternativeCommandsHandler = new AlternativeCommandsHandler(this);
timer = new EssentialsTimer(this);
scheduleSyncRepeatingTask(timer, 1000, 50);
Economy.setEss(this);
execTimer.mark("RegHandler");
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.");
}
final String timeroutput = execTimer.end();
if (getSettings().isDebug()) {
LOGGER.log(Level.INFO, "Essentials load {0}", timeroutput);
}
} catch (NumberFormatException ex) {
handleCrash(ex);
} catch (Error ex) {
handleCrash(ex);
throw ex;
}
}
@Override
public void saveConfig() {
// We don't use any of the bukkit config writing, as this breaks our config file formatting.
}
private void registerListeners(PluginManager pm) {
HandlerList.unregisterAll(this);
if (getSettings().isDebug()) {
LOGGER.log(Level.INFO, "Registering Listeners");
}
final EssentialsPluginListener pluginListener = new EssentialsPluginListener(this);
pm.registerEvents(pluginListener, this);
confList.add(pluginListener);
final EssentialsPlayerListener playerListener = new EssentialsPlayerListener(this);
playerListener.registerEvents();
final EssentialsBlockListener blockListener = new EssentialsBlockListener(this);
pm.registerEvents(blockListener, this);
final SignBlockListener signBlockListener = new SignBlockListener(this);
pm.registerEvents(signBlockListener, this);
final SignPlayerListener signPlayerListener = new SignPlayerListener(this);
pm.registerEvents(signPlayerListener, this);
final SignEntityListener signEntityListener = new SignEntityListener(this);
pm.registerEvents(signEntityListener, this);
final EssentialsEntityListener entityListener = new EssentialsEntityListener(this);
pm.registerEvents(entityListener, this);
final EssentialsWorldListener worldListener = new EssentialsWorldListener(this);
pm.registerEvents(worldListener, this);
final EssentialsServerListener serverListener = new EssentialsServerListener(this);
pm.registerEvents(serverListener, this);
pm.registerEvents(tntListener, this);
jails.resetListener();
}
@Override
public void onDisable() {
for (User user : getOnlineUsers()) {
if (user.isVanished()) {
user.setVanished(false);
user.sendMessage(tl("unvanishedReload"));
}
user.stopTransaction();
}
cleanupOpenInventories();
if (i18n != null) {
i18n.onDisable();
}
if (backup != null) {
backup.stopTask();
}
Economy.setEss(null);
Trade.closeLog();
getUserMap().getUUIDMap().shutdown();
HandlerList.unregisterAll(this);
}
@Override
public void reload() {
Trade.closeLog();
for (IConf iConf : confList) {
iConf.reloadConfig();
execTimer.mark("Reload(" + iConf.getClass().getSimpleName() + ")");
}
i18n.updateLocale(settings.getLocale());
final PluginManager pm = getServer().getPluginManager();
registerListeners(pm);
}
@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);
}
@Override
public List<String> onTabCompleteEssentials(final CommandSender cSender, final Command command, final String commandLabel, final String[] args,
final ClassLoader classLoader, final String commandPath, final String permissionPrefix,
final IEssentialsModule module) {
if (!getSettings().isCommandOverridden(command.getName()) && (!commandLabel.startsWith("e") || commandLabel.equalsIgnoreCase(command.getName()))) {
final PluginCommand pc = alternativeCommandsHandler.getAlternative(commandLabel);
if (pc != null) {
try {
TabCompleter completer = pc.getTabCompleter();
if (completer != null) {
return completer.onTabComplete(cSender, command, commandLabel, args);
}
} catch (final Exception ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
}
}
}
try {
// Note: The tab completer is always a player, even when tab-completing in a command block
User user = null;
if (cSender instanceof Player) {
user = getUser((Player) cSender);
}
CommandSource sender = new CommandSource(cSender);
// Check for disabled commands
if (getSettings().isCommandDisabled(commandLabel)) {
return Collections.emptyList();
}
IEssentialsCommand cmd;
try {
cmd = (IEssentialsCommand) classLoader.loadClass(commandPath + command.getName()).newInstance();
cmd.setEssentials(this);
cmd.setEssentialsModule(module);
} catch (Exception ex) {
sender.sendMessage(tl("commandNotLoaded", commandLabel));
LOGGER.log(Level.SEVERE, tl("commandNotLoaded", commandLabel), ex);
return Collections.emptyList();
}
// Check authorization
if (user != null && !user.isAuthorized(cmd, permissionPrefix)) {
return Collections.emptyList();
}
if (user != null && user.isJailed() && !user.isAuthorized(cmd, "essentials.jail.allow.")) {
return Collections.emptyList();
}
// Run the command
try {
if (user == null) {
return cmd.tabComplete(getServer(), sender, commandLabel, command, args);
} else {
return cmd.tabComplete(getServer(), user, commandLabel, command, args);
}
} catch (Exception ex) {
showError(sender, ex, commandLabel);
// Tab completion shouldn't fail
LOGGER.log(Level.SEVERE, tl("commandFailed", commandLabel), ex);
return Collections.emptyList();
}
} catch (Throwable ex) {
LOGGER.log(Level.SEVERE, tl("commandFailed", commandLabel), ex);
return Collections.emptyList();
}
}
@Override
public boolean onCommand(final CommandSender sender, final Command command, final String commandLabel, final String[] args) {
return onCommandEssentials(sender, command, commandLabel, args, Essentials.class.getClassLoader(), "com.earth2me.essentials.commands.Command", "essentials.", null);
}
@Override
public boolean onCommandEssentials(final CommandSender cSender, final Command command, final String commandLabel, final String[] args, final ClassLoader classLoader, final String commandPath, final String permissionPrefix, final IEssentialsModule module) {
// Allow plugins to override the command via onCommand
if (!getSettings().isCommandOverridden(command.getName()) && (!commandLabel.startsWith("e") || commandLabel.equalsIgnoreCase(command.getName()))) {
final PluginCommand pc = alternativeCommandsHandler.getAlternative(commandLabel);
if (pc != null) {
alternativeCommandsHandler.executed(commandLabel, pc);
try {
return pc.execute(cSender, commandLabel, args);
} catch (final Exception ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
cSender.sendMessage(tl("internalError"));
return true;
}
}
}
try {
User user = null;
Block bSenderBlock = null;
if (cSender instanceof Player) {
user = getUser((Player) cSender);
} else if (cSender instanceof BlockCommandSender) {
BlockCommandSender bsender = (BlockCommandSender) cSender;
bSenderBlock = bsender.getBlock();
}
if (bSenderBlock != null) {
Bukkit.getLogger().log(Level.INFO, "CommandBlock at {0},{1},{2} issued server command: /{3} {4}", new Object[]{bSenderBlock.getX(), bSenderBlock.getY(), bSenderBlock.getZ(), commandLabel, EssentialsCommand.getFinalArg(args, 0)});
} else if (user == null) {
Bukkit.getLogger().log(Level.INFO, "{0} issued server command: /{1} {2}", new Object[]{cSender.getName(), commandLabel, EssentialsCommand.getFinalArg(args, 0)});
}
CommandSource sender = new CommandSource(cSender);
// New mail notification
if (user != null && !getSettings().isCommandDisabled("mail") && !command.getName().equals("mail") && user.isAuthorized("essentials.mail")) {
user.notifyOfMail();
}
//Print version even if admin command is not available #easteregg
if (commandLabel.equalsIgnoreCase("essversion")) {
sender.sendMessage("This server is running Essentials " + getDescription().getVersion());
return true;
}
// Check for disabled commands
if (getSettings().isCommandDisabled(commandLabel)) {
return true;
}
IEssentialsCommand cmd;
try {
cmd = (IEssentialsCommand) classLoader.loadClass(commandPath + command.getName()).newInstance();
cmd.setEssentials(this);
cmd.setEssentialsModule(module);
} catch (Exception ex) {
sender.sendMessage(tl("commandNotLoaded", commandLabel));
LOGGER.log(Level.SEVERE, tl("commandNotLoaded", commandLabel), ex);
return true;
}
// Check authorization
if (user != null && !user.isAuthorized(cmd, permissionPrefix)) {
LOGGER.log(Level.INFO, tl("deniedAccessCommand", user.getName()));
user.sendMessage(tl("noAccessCommand"));
return true;
}
if (user != null && user.isJailed() && !user.isAuthorized(cmd, "essentials.jail.allow.")) {
if (user.getJailTimeout() > 0) {
user.sendMessage(tl("playerJailedFor", user.getName(), DateUtil.formatDateDiff(user.getJailTimeout())));
} else {
user.sendMessage(tl("jailMessage"));
}
return true;
}
// Run the command
try {
if (user == null) {
cmd.run(getServer(), sender, commandLabel, command, args);
} else {
cmd.run(getServer(), user, commandLabel, command, args);
}
return true;
} catch (NoChargeException ex) {
return true;
} catch (QuietAbortException ex) {
return true;
} catch (NotEnoughArgumentsException ex) {
sender.sendMessage(command.getDescription());
sender.sendMessage(command.getUsage().replaceAll("<command>", commandLabel));
if (!ex.getMessage().isEmpty()) {
sender.sendMessage(ex.getMessage());
}
return true;
} catch (Exception ex) {
showError(sender, ex, commandLabel);
if (settings.isDebug()) {
ex.printStackTrace();
}
return true;
}
} catch (Throwable ex) {
LOGGER.log(Level.SEVERE, tl("commandFailed", commandLabel), ex);
return true;
}
}
public void cleanupOpenInventories() {
for (User user : getOnlineUsers()) {
if (user.isRecipeSee()) {
user.getBase().getOpenInventory().getTopInventory().clear();
user.getBase().getOpenInventory().close();
user.setRecipeSee(false);
}
if (user.isInvSee() || user.isEnderSee()) {
user.getBase().getOpenInventory().close();
user.setInvSee(false);
user.setEnderSee(false);
}
}
}
@Override
public void showError(final CommandSource sender, final Throwable exception, final String commandLabel) {
sender.sendMessage(tl("errorWithMessage", exception.getMessage()));
if (getSettings().isDebug()) {
LOGGER.log(Level.INFO, tl("errorCallingCommand", commandLabel), exception);
}
}
@Override
public BukkitScheduler getScheduler() {
return this.getServer().getScheduler();
}
@Override
public IJails getJails() {
return jails;
}
@Override
public Warps getWarps() {
return warps;
}
@Override
public Worth getWorth() {
return worth;
}
@Override
public Backup getBackup() {
return backup;
}
@Override
public Kits getKits() {
return kits;
}
@Override
public Metrics getMetrics() {
return metrics;
}
@Override
public void setMetrics(Metrics metrics) {
this.metrics = metrics;
}
@Deprecated
@Override
public User getUser(final Object base) {
if (base instanceof Player) {
return getUser((Player) base);
}
if (base instanceof org.bukkit.OfflinePlayer) {
return getUser(((org.bukkit.OfflinePlayer) base).getUniqueId());
}
if (base instanceof UUID) {
return getUser((UUID) base);
}
if (base instanceof String) {
return getOfflineUser((String) base);
}
return null;
}
//This will return null if there is not a match.
@Override
public User getUser(final String base) {
return getOfflineUser(base);
}
//This will return null if there is not a match.
@Override
public User getUser(final UUID base) {
return userMap.getUser(base);
}
//This will return null if there is not a match.
@Override
public User getOfflineUser(final String name) {
final User user = userMap.getUser(name);
if (user != null && user.getBase() instanceof OfflinePlayer) {
//This code should attempt to use the last known name of a user, if Bukkit returns name as null.
final String lastName = user.getLastAccountName();
if (lastName != null) {
((OfflinePlayer) user.getBase()).setName(lastName);
} else {
((OfflinePlayer) user.getBase()).setName(name);
}
}
return user;
}
//This will create a new user if there is not a match.
@Override
public User getUser(final Player base) {
if (base == null) {
return null;
}
if (userMap == null) {
LOGGER.log(Level.WARNING, "Essentials userMap not initialized");
return null;
}
User user = userMap.getUser(base.getUniqueId());
if (user == null) {
if (getSettings().isDebug()) {
LOGGER.log(Level.INFO, "Constructing new userfile from base player {0}", base.getName());
}
user = new User(base, this);
} else {
user.update(base);
}
return user;
}
private void handleCrash(Throwable exception) {
final PluginManager pm = getServer().getPluginManager();
LOGGER.log(Level.SEVERE, exception.toString());
exception.printStackTrace();
pm.registerEvents(new Listener() {
@EventHandler(priority = EventPriority.LOW)
public void onPlayerJoin(final PlayerJoinEvent event) {
event.getPlayer().sendMessage("Essentials failed to load, read the log file.");
}
}, this);
for (Player player : getOnlinePlayers()) {
player.sendMessage("Essentials failed to load, read the log file.");
}
this.setEnabled(false);
}
@Override
public World getWorld(final String name) {
if (name.matches("[0-9]+")) {
final int worldId = Integer.parseInt(name);
if (worldId < getServer().getWorlds().size()) {
return getServer().getWorlds().get(worldId);
}
}
return getServer().getWorld(name);
}
@Override
public void addReloadListener(final IConf listener) {
confList.add(listener);
}
@Override
public Methods getPaymentMethod() {
return paymentMethod;
}
@Override
public int broadcastMessage(final String message) {
return broadcastMessage(null, null, message, true);
}
@Override
public int broadcastMessage(final IUser sender, final String message) {
return broadcastMessage(sender, null, message, false);
}
@Override
public int broadcastMessage(final String permission, final String message) {
return broadcastMessage(null, permission, message, false);
}
private int broadcastMessage(final IUser sender, final String permission, final String message, final boolean keywords) {
if (sender != null && sender.isHidden()) {
return 0;
}
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 (keywords) {
broadcast = new KeywordReplacer(broadcast, new CommandSource(player), this, false);
}
for (String messageText : broadcast.getLines()) {
user.sendMessage(messageText);
}
}
}
return players.size();
}
@Override
public BukkitTask runTaskAsynchronously(final Runnable run) {
return this.getScheduler().runTaskAsynchronously(this, run);
}
@Override
public BukkitTask runTaskLaterAsynchronously(final Runnable run, final long delay) {
return this.getScheduler().runTaskLaterAsynchronously(this, run, delay);
}
@Override
public BukkitTask runTaskTimerAsynchronously(final Runnable run, final long delay, final long period) {
return this.getScheduler().runTaskTimerAsynchronously(this, run, delay, period);
}
@Override
public int scheduleSyncDelayedTask(final Runnable run) {
return this.getScheduler().scheduleSyncDelayedTask(this, run);
}
@Override
public int scheduleSyncDelayedTask(final Runnable run, final long delay) {
return this.getScheduler().scheduleSyncDelayedTask(this, run, delay);
}
@Override
public int scheduleSyncRepeatingTask(final Runnable run, final long delay, final long period) {
return this.getScheduler().scheduleSyncRepeatingTask(this, run, delay, period);
}
@Override
public TNTExplodeListener getTNTListener() {
return tntListener;
}
@Override
public PermissionsHandler getPermissionsHandler() {
return permissionsHandler;
}
@Override
public AlternativeCommandsHandler getAlternativeCommandsHandler() {
return alternativeCommandsHandler;
}
@Override
public IItemDb getItemDb() {
return itemDb;
}
@Override
public UserMap getUserMap() {
return userMap;
}
@Override
public I18n getI18n() {
return i18n;
}
@Override
public EssentialsTimer getTimer() {
return timer;
}
@Override
public List<String> getVanishedPlayers() {
return Collections.unmodifiableList(new ArrayList<>(vanishedPlayers));
}
@Override
public Collection<String> getVanishedPlayersNew() {
return vanishedPlayers;
}
@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);
}
}
}
@Override
public Iterable<User> getOnlineUsers() {
return Iterables.transform(getOnlinePlayers(), new Function<Player, User>() {
@Override
public User apply(Player player) {
return getUser(player);
}
});
}
@Override
public SpawnerProvider getSpawnerProvider() {
return spawnerProvider;
}
@Override
public SpawnEggProvider getSpawnEggProvider() {
return spawnEggProvider;
}
@Override
public PotionMetaProvider getPotionMetaProvider() {
return potionMetaProvider;
}
private static void addDefaultBackPermissionsToWorld(World w) {
String permName = "essentials.back.into." + w.getName();
Permission p = Bukkit.getPluginManager().getPermission(permName);
if (p == null) {
p = new Permission(permName,
"Allows access to /back when the destination location is within world " + w.getName(),
PermissionDefault.TRUE);
Bukkit.getPluginManager().addPermission(p);
}
}
private static class EssentialsWorldListener implements Listener, Runnable {
private transient final IEssentials ess;
public EssentialsWorldListener(final IEssentials ess) {
this.ess = ess;
}
@EventHandler(priority = EventPriority.LOW)
public void onWorldLoad(final WorldLoadEvent event) {
addDefaultBackPermissionsToWorld(event.getWorld());
ess.getJails().onReload();
ess.getWarps().reloadConfig();
for (IConf iConf : ((Essentials) ess).confList) {
if (iConf instanceof IEssentialsModule) {
iConf.reloadConfig();
}
}
}
@EventHandler(priority = EventPriority.LOW)
public void onWorldUnload(final WorldUnloadEvent event) {
ess.getJails().onReload();
ess.getWarps().reloadConfig();
for (IConf iConf : ((Essentials) ess).confList) {
if (iConf instanceof IEssentialsModule) {
iConf.reloadConfig();
}
}
}
@Override
public void run() {
ess.reload();
}
}
private AbstractItemDb getItemDbFromConfig() {
final String setting = settings.getItemDbType();
if (setting.equalsIgnoreCase("json")) {
return new FlatItemDb(this);
} else if (setting.equalsIgnoreCase("csv")) {
return new LegacyItemDb(this);
} else {
VersionUtil.BukkitVersion version = VersionUtil.getServerBukkitVersion();
if (version.isHigherThanOrEqualTo(VersionUtil.v1_13_0_R01)) {
return new FlatItemDb(this);
} else {
return new LegacyItemDb(this);
}
}
}
}
@@ -1,90 +0,0 @@
package com.earth2me.essentials;
import net.ess3.api.IEssentials;
import net.ess3.nms.refl.ReflUtil;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.server.ServerListPingEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
public class EssentialsServerListener implements Listener {
private final transient IEssentials ess;
private boolean unsupportedLogged = false;
private boolean npeWarned = false;
private boolean isPaperSample;
private Method setSampleText;
private Method getSampleText;
public EssentialsServerListener(final IEssentials ess) {
this.ess = ess;
if (ReflUtil.getClassCached("com.destroystokyo.paper.event.server.PaperServerListPingEvent") == null) {
// This workaround is only necessary for older Paper builds
setSampleText = ReflUtil.getMethodCached(ServerListPingEvent.class, "setSampleText", List.class);
getSampleText = ReflUtil.getMethodCached(ServerListPingEvent.class, "getSampleText");
if (setSampleText != null && getSampleText != null) {
ess.getLogger().info("Using Paper 1.12+ ServerListPingEvent methods");
isPaperSample = true;
return;
}
}
ess.getLogger().info("Using Spigot 1.7.10+ ServerListPingEvent iterator");
isPaperSample = false;
}
@EventHandler(priority = EventPriority.LOWEST)
public void onServerListPing(final ServerListPingEvent event) throws Exception {
if (isPaperSample) {
try {
List<String> playerNames = (List<String>) getSampleText.invoke(event, null);
Iterator<String> iterator = playerNames.iterator();
while (iterator.hasNext()) {
String player = iterator.next();
if (ess.getUser(player).isVanished()) {
iterator.remove();
}
}
setSampleText.invoke(event, playerNames);
} catch (IllegalAccessException | InvocationTargetException | ClassCastException e) {
if (!unsupportedLogged) {
ess.getLogger().log(Level.WARNING, "Unable to hide players from server list ping "
+ "using Paper 1.12+ method!", e);
unsupportedLogged = true;
}
} catch (NullPointerException e) {
if (!npeWarned) {
npeWarned = true;
Exception ex = new Exception("A plugin has fired a ServerListPingEvent "
+ "without implementing Paper's methods. Point the author to https://git.io/v7Xzl.");
ex.setStackTrace(e.getStackTrace());
throw ex;
}
}
} else {
try {
Iterator<Player> iterator = event.iterator();
while (iterator.hasNext()) {
Player player = iterator.next();
if (ess.getUser(player).isVanished()) {
iterator.remove();
}
}
} catch (UnsupportedOperationException e) {
if (!unsupportedLogged) {
ess.getLogger().warning("Current server implementation does not support "
+ "hiding players from server list ping. Update or contact the maintainers.");
unsupportedLogged = true;
}
}
}
}
}
@@ -1,722 +0,0 @@
package com.earth2me.essentials;
import com.earth2me.essentials.craftbukkit.BanLookup;
import com.earth2me.essentials.craftbukkit.FakeWorld;
import com.earth2me.essentials.settings.Spawns;
import com.earth2me.essentials.storage.YamlStorageWriter;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.base.Charsets;
import com.google.common.collect.Maps;
import net.ess3.api.IEssentials;
import org.bukkit.BanList;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
import java.io.*;
import java.math.BigInteger;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.earth2me.essentials.I18n.tl;
public class EssentialsUpgrade {
private final static Logger LOGGER = Logger.getLogger("Essentials");
private final transient IEssentials ess;
private final transient EssentialsConf doneFile;
EssentialsUpgrade(final IEssentials essentials) {
ess = essentials;
if (!ess.getDataFolder().exists()) {
ess.getDataFolder().mkdirs();
}
doneFile = new EssentialsConf(new File(ess.getDataFolder(), "upgrades-done.yml"));
doneFile.load();
}
public void convertKits() {
Kits kits = ess.getKits();
EssentialsConf config = kits.getConfig();
if (doneFile.getBoolean("kitsyml", false)) {
return;
}
LOGGER.info("Attempting to convert old kits in config.yml to new kits.yml");
ConfigurationSection section = ess.getSettings().getKitSection();
if (section == null) {
LOGGER.info("No kits found to migrate.");
return;
}
Map<String, Object> legacyKits = ess.getSettings().getKitSection().getValues(true);
for (Map.Entry<String, Object> entry : legacyKits.entrySet()) {
LOGGER.info("Converting " + entry.getKey());
config.set("kits." + entry.getKey(), entry.getValue());
}
config.save();
doneFile.setProperty("kitsyml", true);
doneFile.save();
LOGGER.info("Done converting kits.");
}
private void moveMotdRulesToFile(String name) {
if (doneFile.getBoolean("move" + name + "ToFile", false)) {
return;
}
try {
final File file = new File(ess.getDataFolder(), name + ".txt");
if (file.exists()) {
return;
}
final File configFile = new File(ess.getDataFolder(), "config.yml");
if (!configFile.exists()) {
return;
}
final EssentialsConf conf = new EssentialsConf(configFile);
conf.load();
List<String> lines = conf.getStringList(name);
if (lines != null && !lines.isEmpty()) {
if (!file.createNewFile()) {
throw new IOException("Failed to create file " + file);
}
PrintWriter writer = new PrintWriter(file);
for (String line : lines) {
writer.println(line);
}
writer.close();
}
doneFile.setProperty("move" + name + "ToFile", true);
doneFile.save();
} catch (IOException e) {
LOGGER.log(Level.SEVERE, tl("upgradingFilesError"), e);
}
}
private void removeLinesFromConfig(File file, String regex, String info) throws Exception {
boolean needUpdate = false;
final BufferedReader bReader = new BufferedReader(new FileReader(file));
final File tempFile = File.createTempFile("essentialsupgrade", ".tmp.yml", ess.getDataFolder());
final BufferedWriter bWriter = new BufferedWriter(new FileWriter(tempFile));
do {
final String line = bReader.readLine();
if (line == null) {
break;
}
if (line.matches(regex)) {
if (!needUpdate && info != null) {
bWriter.write(info, 0, info.length());
bWriter.newLine();
}
needUpdate = true;
} else {
if (line.endsWith("\r\n")) {
bWriter.write(line, 0, line.length() - 2);
} else if (line.endsWith("\r") || line.endsWith("\n")) {
bWriter.write(line, 0, line.length() - 1);
} else {
bWriter.write(line, 0, line.length());
}
bWriter.newLine();
}
} while (true);
bReader.close();
bWriter.close();
if (needUpdate) {
if (!file.renameTo(new File(file.getParentFile(), file.getName().concat("." + System.currentTimeMillis() + ".upgradebackup")))) {
throw new Exception(tl("configFileMoveError"));
}
if (!tempFile.renameTo(file)) {
throw new Exception(tl("configFileRenameError"));
}
} else {
tempFile.delete();
}
}
private void updateUsersPowerToolsFormat() {
if (doneFile.getBoolean("updateUsersPowerToolsFormat", false)) {
return;
}
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
if (!userdataFolder.exists() || !userdataFolder.isDirectory()) {
return;
}
final File[] userFiles = userdataFolder.listFiles();
for (File file : userFiles) {
if (!file.isFile() || !file.getName().endsWith(".yml")) {
continue;
}
final EssentialsConf config = new EssentialsConf(file);
try {
config.load();
if (config.hasProperty("powertools")) {
@SuppressWarnings("unchecked") final Map<String, Object> powertools = config.getConfigurationSection("powertools").getValues(false);
if (powertools == null) {
continue;
}
for (Map.Entry<String, Object> entry : powertools.entrySet()) {
if (entry.getValue() instanceof String) {
List<String> temp = new ArrayList<>();
temp.add((String) entry.getValue());
powertools.put(entry.getKey(), temp);
}
}
config.forceSave();
}
} catch (RuntimeException ex) {
LOGGER.log(Level.INFO, "File: " + file.toString());
throw ex;
}
}
doneFile.setProperty("updateUsersPowerToolsFormat", true);
doneFile.save();
}
private void updateUsersHomesFormat() {
if (doneFile.getBoolean("updateUsersHomesFormat", false)) {
return;
}
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
if (!userdataFolder.exists() || !userdataFolder.isDirectory()) {
return;
}
final File[] userFiles = userdataFolder.listFiles();
for (File file : userFiles) {
if (!file.isFile() || !file.getName().endsWith(".yml")) {
continue;
}
final EssentialsConf config = new EssentialsConf(file);
try {
config.load();
if (config.hasProperty("home") && config.hasProperty("home.default")) {
@SuppressWarnings("unchecked") final String defworld = (String) config.getProperty("home.default");
final Location defloc = getFakeLocation(config, "home.worlds." + defworld);
if (defloc != null) {
config.setProperty("homes.home", defloc);
}
Set<String> worlds = config.getConfigurationSection("home.worlds").getKeys(false);
Location loc;
String worldName;
if (worlds == null) {
continue;
}
for (String world : worlds) {
if (defworld.equalsIgnoreCase(world)) {
continue;
}
loc = getFakeLocation(config, "home.worlds." + world);
if (loc == null) {
continue;
}
worldName = loc.getWorld().getName().toLowerCase(Locale.ENGLISH);
if (worldName != null && !worldName.isEmpty()) {
config.setProperty("homes." + worldName, loc);
}
}
config.removeProperty("home");
config.forceSave();
}
} catch (RuntimeException ex) {
LOGGER.log(Level.INFO, "File: " + file.toString());
throw ex;
}
}
doneFile.setProperty("updateUsersHomesFormat", true);
doneFile.save();
}
private void sanitizeAllUserFilenames() {
if (doneFile.getBoolean("sanitizeAllUserFilenames", false)) {
return;
}
final File usersFolder = new File(ess.getDataFolder(), "userdata");
if (!usersFolder.exists()) {
return;
}
final File[] listOfFiles = usersFolder.listFiles();
for (File listOfFile : listOfFiles) {
final String filename = listOfFile.getName();
if (!listOfFile.isFile() || !filename.endsWith(".yml")) {
continue;
}
final String sanitizedFilename = StringUtil.sanitizeFileName(filename.substring(0, filename.length() - 4)) + ".yml";
if (sanitizedFilename.equals(filename)) {
continue;
}
final File tmpFile = new File(listOfFile.getParentFile(), sanitizedFilename + ".tmp");
final File newFile = new File(listOfFile.getParentFile(), sanitizedFilename);
if (!listOfFile.renameTo(tmpFile)) {
LOGGER.log(Level.WARNING, tl("userdataMoveError", filename, sanitizedFilename));
continue;
}
if (newFile.exists()) {
LOGGER.log(Level.WARNING, tl("duplicatedUserdata", filename, sanitizedFilename));
continue;
}
if (!tmpFile.renameTo(newFile)) {
LOGGER.log(Level.WARNING, tl("userdataMoveBackError", sanitizedFilename, sanitizedFilename));
}
}
doneFile.setProperty("sanitizeAllUserFilenames", true);
doneFile.save();
}
private World getFakeWorld(final String name) {
final File bukkitDirectory = ess.getDataFolder().getParentFile().getParentFile();
final File worldDirectory = new File(bukkitDirectory, name);
if (worldDirectory.exists() && worldDirectory.isDirectory()) {
return new FakeWorld(worldDirectory.getName(), World.Environment.NORMAL);
}
return null;
}
public Location getFakeLocation(EssentialsConf config, String path) {
String worldName = config.getString((path != null ? path + "." : "") + "world");
if (worldName == null || worldName.isEmpty()) {
return null;
}
World world = getFakeWorld(worldName);
if (world == null) {
return null;
}
return new Location(world, config.getDouble((path != null ? path + "." : "") + "x", 0), config.getDouble((path != null ? path + "." : "") + "y", 0), config.getDouble((path != null ? path + "." : "") + "z", 0), (float) config.getDouble((path != null ? path + "." : "") + "yaw", 0), (float) config.getDouble((path != null ? path + "." : "") + "pitch", 0));
}
private void deleteOldItemsCsv() {
if (doneFile.getBoolean("deleteOldItemsCsv", false)) {
return;
}
final File file = new File(ess.getDataFolder(), "items.csv");
if (file.exists()) {
try {
final Set<BigInteger> oldconfigs = new HashSet<>();
oldconfigs.add(new BigInteger("66ec40b09ac167079f558d1099e39f10", 16)); // sep 1
oldconfigs.add(new BigInteger("34284de1ead43b0bee2aae85e75c041d", 16)); // crlf
oldconfigs.add(new BigInteger("c33bc9b8ee003861611bbc2f48eb6f4f", 16)); // jul 24
oldconfigs.add(new BigInteger("6ff17925430735129fc2a02f830c1daa", 16)); // crlf
MessageDigest digest = ManagedFile.getDigest();
final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
final byte[] buffer = new byte[1024];
try (DigestInputStream dis = new DigestInputStream(bis, digest)) {
while (dis.read(buffer) != -1) {
}
}
BigInteger hash = new BigInteger(1, digest.digest());
if (oldconfigs.contains(hash) && !file.delete()) {
throw new IOException("Could not delete file " + file.toString());
}
doneFile.setProperty("deleteOldItemsCsv", true);
doneFile.save();
} catch (IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
}
}
}
private void updateSpawnsToNewSpawnsConfig() {
if (doneFile.getBoolean("updateSpawnsToNewSpawnsConfig", false)) {
return;
}
final File configFile = new File(ess.getDataFolder(), "spawn.yml");
if (configFile.exists()) {
final EssentialsConf config = new EssentialsConf(configFile);
try {
config.load();
if (!config.hasProperty("spawns")) {
final Spawns spawns = new Spawns();
Set<String> keys = config.getKeys(false);
for (String group : keys) {
Location loc = getFakeLocation(config, group);
spawns.getSpawns().put(group.toLowerCase(Locale.ENGLISH), loc);
}
if (!configFile.renameTo(new File(ess.getDataFolder(), "spawn.yml.old"))) {
throw new Exception(tl("fileRenameError", "spawn.yml"));
}
try (PrintWriter writer = new PrintWriter(configFile)) {
new YamlStorageWriter(writer).save(spawns);
}
}
} catch (Exception ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
}
}
doneFile.setProperty("updateSpawnsToNewSpawnsConfig", true);
doneFile.save();
}
private void updateJailsToNewJailsConfig() {
if (doneFile.getBoolean("updateJailsToNewJailsConfig", false)) {
return;
}
final File configFile = new File(ess.getDataFolder(), "jail.yml");
if (configFile.exists()) {
final EssentialsConf config = new EssentialsConf(configFile);
try {
config.load();
if (!config.hasProperty("jails")) {
final com.earth2me.essentials.settings.Jails jails = new com.earth2me.essentials.settings.Jails();
Set<String> keys = config.getKeys(false);
for (String jailName : keys) {
Location loc = getFakeLocation(config, jailName);
jails.getJails().put(jailName.toLowerCase(Locale.ENGLISH), loc);
}
if (!configFile.renameTo(new File(ess.getDataFolder(), "jail.yml.old"))) {
throw new Exception(tl("fileRenameError", "jail.yml"));
}
try (PrintWriter writer = new PrintWriter(configFile)) {
new YamlStorageWriter(writer).save(jails);
}
}
} catch (Exception ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
}
}
doneFile.setProperty("updateJailsToNewJailsConfig", true);
doneFile.save();
}
private void warnMetrics() {
if (doneFile.getBoolean("warnMetrics", false)) {
return;
}
doneFile.setProperty("warnMetrics", true);
doneFile.save();
}
private void uuidFileChange() {
if (doneFile.getBoolean("uuidFileChange", false)) {
return;
}
Boolean ignoreUFCache = doneFile.getBoolean("ignore-userfiles-cache", false);
final File userdir = new File(ess.getDataFolder(), "userdata");
if (!userdir.exists()) {
return;
}
int countFiles = 0;
int countReqFiles = 0;
for (String string : userdir.list()) {
if (!string.endsWith(".yml") || string.length() < 5) {
continue;
}
countFiles++;
final String name = string.substring(0, string.length() - 4);
UUID uuid = null;
try {
uuid = UUID.fromString(name);
} catch (IllegalArgumentException ex) {
countReqFiles++;
}
if (countFiles > 100) {
break;
}
}
if (countReqFiles < 1) {
return;
}
ess.getLogger().info("#### Starting Essentials UUID userdata conversion in a few seconds. ####");
ess.getLogger().info("We recommend you take a backup of your server before upgrading from the old username system.");
try {
Thread.sleep(15000);
} catch (InterruptedException ex) {
// NOOP
}
uuidFileConvert(ess, ignoreUFCache);
doneFile.setProperty("uuidFileChange", true);
doneFile.save();
}
public static void uuidFileConvert(IEssentials ess, Boolean ignoreUFCache) {
ess.getLogger().info("Starting Essentials UUID userdata conversion");
final File userdir = new File(ess.getDataFolder(), "userdata");
if (!userdir.exists()) {
return;
}
int countFiles = 0;
int countFails = 0;
int countEssCache = 0;
int countBukkit = 0;
ess.getLogger().info("Found " + userdir.list().length + " files to convert...");
for (String string : userdir.list()) {
if (!string.endsWith(".yml") || string.length() < 5) {
continue;
}
final int showProgress = countFiles % 250;
if (showProgress == 0) {
ess.getUserMap().getUUIDMap().forceWriteUUIDMap();
ess.getLogger().info("Converted " + countFiles + "/" + userdir.list().length);
}
countFiles++;
String name = string.substring(0, string.length() - 4);
EssentialsUserConf config;
UUID uuid = null;
try {
uuid = UUID.fromString(name);
} catch (IllegalArgumentException ex) {
File file = new File(userdir, string);
EssentialsConf conf = new EssentialsConf(file);
conf.load();
conf.setProperty("lastAccountName", name);
conf.save();
String uuidConf = ignoreUFCache ? "force-uuid" : "uuid";
String uuidString = conf.getString(uuidConf, null);
for (int i = 0; i < 4; i++) {
try {
uuid = UUID.fromString(uuidString);
countEssCache++;
break;
} catch (Exception ex2) {
if (conf.getBoolean("npc", false)) {
uuid = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
break;
}
org.bukkit.OfflinePlayer player = ess.getServer().getOfflinePlayer(name);
uuid = player.getUniqueId();
}
if (uuid != null) {
countBukkit++;
break;
}
}
if (uuid != null) {
conf.forceSave();
config = new EssentialsUserConf(name, uuid, new File(userdir, uuid + ".yml"));
config.convertLegacyFile();
ess.getUserMap().trackUUID(uuid, name, false);
continue;
}
countFails++;
}
}
ess.getUserMap().getUUIDMap().forceWriteUUIDMap();
ess.getLogger().info("Converted " + countFiles + "/" + countFiles + ". Conversion complete.");
ess.getLogger().info("Converted via cache: " + countEssCache + " :: Converted via lookup: " + countBukkit + " :: Failed to convert: " + countFails);
ess.getLogger().info("To rerun the conversion type /essentials uuidconvert");
}
public void banFormatChange() {
if (doneFile.getBoolean("banFormatChange", false)) {
return;
}
ess.getLogger().info("Starting Essentials ban format conversion");
final File userdir = new File(ess.getDataFolder(), "userdata");
if (!userdir.exists()) {
return;
}
int countFiles = 0;
ess.getLogger().info("Found " + userdir.list().length + " files to convert...");
for (String string : userdir.list()) {
if (!string.endsWith(".yml") || string.length() < 5) {
continue;
}
final int showProgress = countFiles % 250;
if (showProgress == 0) {
ess.getLogger().info("Converted " + countFiles + "/" + userdir.list().length);
}
countFiles++;
final File pFile = new File(userdir, string);
final EssentialsConf conf = new EssentialsConf(pFile);
conf.load();
String banReason;
Long banTimeout;
try {
banReason = conf.getConfigurationSection("ban").getString("reason");
} catch (NullPointerException n) {
banReason = null;
}
final String playerName = conf.getString("lastAccountName");
if (playerName != null && playerName.length() > 1 && banReason != null && banReason.length() > 1) {
try {
if (conf.getConfigurationSection("ban").contains("timeout")) {
banTimeout = Long.parseLong(conf.getConfigurationSection("ban").getString("timeout"));
} else {
banTimeout = 0L;
}
} catch (NumberFormatException n) {
banTimeout = 0L;
}
if (BanLookup.isBanned(ess, playerName)) {
updateBan(playerName, banReason, banTimeout);
}
}
conf.removeProperty("ban");
conf.save();
}
doneFile.setProperty("banFormatChange", true);
doneFile.save();
ess.getLogger().info("Ban format update complete.");
}
private void updateBan(String playerName, String banReason, Long banTimeout) {
if (banTimeout == 0) {
Bukkit.getBanList(BanList.Type.NAME).addBan(playerName, banReason, null, Console.NAME);
} else {
Bukkit.getBanList(BanList.Type.NAME).addBan(playerName, banReason, new Date(banTimeout), Console.NAME);
}
}
private static final FileFilter YML_FILTER = new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isFile() && pathname.getName().endsWith(".yml");
}
};
private static final String PATTERN_CONFIG_UUID_REGEX = "(?mi)^uuid:\\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\s*$";
private static final Pattern PATTERN_CONFIG_UUID = Pattern.compile(PATTERN_CONFIG_UUID_REGEX);
private static final String PATTERN_CONFIG_NAME_REGEX = "(?mi)^lastAccountName:\\s*[\"\']?(\\w+)[\"\']?\\s*$";
private static final Pattern PATTERN_CONFIG_NAME = Pattern.compile(PATTERN_CONFIG_NAME_REGEX);
private void repairUserMap() {
if (doneFile.getBoolean("userMapRepaired", false)) {
return;
}
ess.getLogger().info("Starting usermap repair");
File userdataFolder = new File(ess.getDataFolder(), "userdata");
if (!userdataFolder.isDirectory()) {
ess.getLogger().warning("Missing userdata folder, aborting");
return;
}
File[] files = userdataFolder.listFiles(YML_FILTER);
final DecimalFormat format = new DecimalFormat("#0.00");
final Map<String, UUID> names = Maps.newHashMap();
for (int index = 0; index < files.length; index++) {
final File file = files[index];
try {
UUID uuid = null;
final String filename = file.getName();
final String configData = new String(java.nio.file.Files.readAllBytes(file.toPath()), Charsets.UTF_8);
if (filename.length() > 36) {
try {
// ".yml" ending has 4 chars...
uuid = UUID.fromString(filename.substring(0, filename.length() - 4));
} catch (IllegalArgumentException ignored) {
}
}
final Matcher uuidMatcher = PATTERN_CONFIG_UUID.matcher(configData);
if (uuidMatcher.find()) {
try {
uuid = UUID.fromString(uuidMatcher.group(1));
} catch (IllegalArgumentException ignored) {
}
}
if (uuid == null) {
// Don't import
continue;
}
final Matcher nameMatcher = PATTERN_CONFIG_NAME.matcher(configData);
if (nameMatcher.find()) {
final String username = nameMatcher.group(1);
if (username != null && username.length() > 0) {
names.put(StringUtil.safeString(username), uuid);
}
}
if (index % 1000 == 0) {
ess.getLogger().info("Reading: " + format.format((100d * (double) index) / files.length)
+ "%");
}
} catch (final IOException e) {
ess.getLogger().log(Level.SEVERE, "Error while reading file: ", e);
return;
}
}
ess.getUserMap().getNames().putAll(names);
ess.getUserMap().reloadConfig();
doneFile.setProperty("userMapRepaired", true);
doneFile.save();
ess.getLogger().info("Completed usermap repair.");
}
public void beforeSettings() {
if (!ess.getDataFolder().exists()) {
ess.getDataFolder().mkdirs();
}
moveMotdRulesToFile("motd");
moveMotdRulesToFile("rules");
}
public void afterSettings() {
sanitizeAllUserFilenames();
updateUsersPowerToolsFormat();
updateUsersHomesFormat();
deleteOldItemsCsv();
updateSpawnsToNewSpawnsConfig();
updateJailsToNewJailsConfig();
uuidFileChange();
banFormatChange();
warnMetrics();
repairUserMap();
}
}
@@ -1,106 +0,0 @@
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 org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
public interface IEssentials extends Plugin {
void addReloadListener(IConf listener);
void reload();
List<String> onTabCompleteEssentials(CommandSender sender, Command command, String commandLabel, String[] args, ClassLoader classLoader, String commandPath, String permissionPrefix, IEssentialsModule module);
boolean onCommandEssentials(CommandSender sender, Command command, String commandLabel, String[] args, ClassLoader classLoader, String commandPath, String permissionPrefix, IEssentialsModule module);
@Deprecated
User getUser(Object base);
User getUser(UUID base);
User getUser(String base);
User getUser(Player base);
I18n getI18n();
User getOfflineUser(String name);
World getWorld(String name);
int broadcastMessage(String message);
int broadcastMessage(IUser sender, String message);
int broadcastMessage(String permission, String message);
ISettings getSettings();
BukkitScheduler getScheduler();
IJails getJails();
IWarps getWarps();
Worth getWorth();
Backup getBackup();
Kits getKits();
Methods getPaymentMethod();
BukkitTask runTaskAsynchronously(Runnable run);
BukkitTask runTaskLaterAsynchronously(Runnable run, long delay);
BukkitTask runTaskTimerAsynchronously(Runnable run, long delay, long period);
int scheduleSyncDelayedTask(Runnable run);
int scheduleSyncDelayedTask(Runnable run, long delay);
int scheduleSyncRepeatingTask(Runnable run, long delay, long period);
TNTExplodeListener getTNTListener();
PermissionsHandler getPermissionsHandler();
AlternativeCommandsHandler getAlternativeCommandsHandler();
void showError(CommandSource sender, Throwable exception, String commandLabel);
IItemDb getItemDb();
UserMap getUserMap();
Metrics getMetrics();
void setMetrics(Metrics metrics);
EssentialsTimer getTimer();
@Deprecated
List<String> getVanishedPlayers();
Collection<Player> getOnlinePlayers();
Iterable<User> getOnlineUsers();
SpawnerProvider getSpawnerProvider();
}
@@ -1,188 +0,0 @@
package com.earth2me.essentials;
import com.earth2me.essentials.commands.IEssentialsCommand;
import net.ess3.api.ITeleport;
import net.ess3.api.MaxMoneyException;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
public interface IUser {
boolean isAuthorized(String node);
boolean isAuthorized(IEssentialsCommand cmd);
boolean isAuthorized(IEssentialsCommand cmd, String permissionPrefix);
void healCooldown() throws Exception;
void giveMoney(BigDecimal value) throws MaxMoneyException;
void giveMoney(final BigDecimal value, final CommandSource initiator) throws MaxMoneyException;
void payUser(final User reciever, final BigDecimal value) throws Exception;
void takeMoney(BigDecimal value);
void takeMoney(final BigDecimal value, final CommandSource initiator);
boolean canAfford(BigDecimal value);
Boolean canSpawnItem(final Material material);
void setLastLocation();
void setLogoutLocation();
void requestTeleport(final User player, final boolean here);
/**
* Returns whether this user has an outstanding teleport request to deal with.
*
* @return whether there is a teleport request
*/
boolean hasOutstandingTeleportRequest();
ITeleport getTeleport();
BigDecimal getMoney();
void setMoney(final BigDecimal value) throws MaxMoneyException;
void setAfk(final boolean set);
/**
* '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
*/
boolean isHidden();
void setHidden(boolean vanish);
boolean isGodModeEnabled();
String getGroup();
boolean inGroup(final String group);
boolean canBuild();
long getTeleportRequestTime();
void enableInvulnerabilityAfterTeleport();
void resetInvulnerabilityAfterTeleport();
boolean hasInvulnerabilityAfterTeleport();
/**
* 'Vanished' Represents when a player is hidden from others by Essentials. This status does NOT include when the
* player is hidden via other plugins. Use isHidden() if you want to check if a user is vanished by any supported
* plugin.
*
* @return If the user is vanished or not
*
* @see isHidden
*/
boolean isVanished();
void setVanished(boolean vanish);
boolean isIgnoreExempt();
void sendMessage(String message);
/*
* UserData
*/
Location getHome(String name) throws Exception;
Location getHome(Location loc) throws Exception;
List<String> getHomes();
void setHome(String name, Location loc);
void delHome(String name) throws Exception;
boolean hasHome();
Location getLastLocation();
Location getLogoutLocation();
long getLastTeleportTimestamp();
void setLastTeleportTimestamp(long time);
String getJail();
void setJail(String jail);
List<String> getMails();
void addMail(String mail);
boolean isAfk();
void setIgnoreMsg(boolean ignoreMsg);
boolean isIgnoreMsg();
void setConfigProperty(String node, Object object);
Set<String> getConfigKeys();
Map<String, Object> getConfigMap();
Map<String, Object> getConfigMap(String node);
Map<Pattern, Long> getCommandCooldowns();
Date getCommandCooldownExpiry(String label);
void addCommandCooldown(Pattern pattern, Date expiresAt, boolean save);
boolean clearCommandCooldown(Pattern pattern);
/*
* PlayerExtension
*/
Player getBase();
CommandSource getSource();
String getName();
String getAfkMessage();
void setAfkMessage(final String message);
long getAfkSince();
boolean isAcceptingPay();
void setAcceptingPay(boolean acceptingPay);
boolean isPromptingPayConfirm();
void setPromptingPayConfirm(boolean prompt);
boolean isPromptingClearConfirm();
void setPromptingClearConfirm(boolean prompt);
Map<User, BigDecimal> getConfirmingPayments();
}
@@ -1,214 +0,0 @@
package com.earth2me.essentials;
import com.earth2me.essentials.Trade.OverflowType;
import com.earth2me.essentials.commands.NoChargeException;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.utils.DateUtil;
import net.ess3.api.IEssentials;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import java.math.BigDecimal;
import java.util.*;
import java.util.logging.Level;
import static com.earth2me.essentials.I18n.tl;
public class Kit {
final IEssentials ess;
final String kitName;
final Map<String, Object> kit;
final Trade charge;
public Kit(final String kitName, final IEssentials ess) throws Exception {
this.kitName = kitName;
this.ess = ess;
this.kit = ess.getKits().getKit(kitName);
this.charge = new Trade("kit-" + kitName, new Trade("kit-kit", ess), ess);
if (kit == null) {
throw new Exception(tl("kitNotFound"));
}
}
public String getName() {
return kitName;
}
public void checkPerms(final User user) throws Exception {
if (!user.isAuthorized("essentials.kits." + kitName)) {
throw new Exception(tl("noKitPermission", "essentials.kits." + kitName));
}
}
public void checkDelay(final User user) throws Exception {
long nextUse = getNextUse(user);
if (nextUse == 0L) {
return;
} else if (nextUse < 0L) {
user.sendMessage(tl("kitOnce"));
throw new NoChargeException();
} else {
user.sendMessage(tl("kitTimed", DateUtil.formatDateDiff(nextUse)));
throw new NoChargeException();
}
}
public void checkAffordable(final User user) throws Exception {
charge.isAffordableFor(user);
}
public void setTime(final User user) throws Exception {
final Calendar time = new GregorianCalendar();
user.setKitTimestamp(kitName, time.getTimeInMillis());
}
public void chargeUser(final User user) throws Exception {
charge.charge(user);
}
public long getNextUse(final User user) throws Exception {
if (user.isAuthorized("essentials.kit.exemptdelay")) {
return 0L;
}
final Calendar time = new GregorianCalendar();
double delay = 0;
try {
// Make sure delay is valid
delay = kit.containsKey("delay") ? ((Number) kit.get("delay")).doubleValue() : 0.0d;
} catch (Exception e) {
throw new Exception(tl("kitError2"));
}
// When was the last kit used?
final long lastTime = user.getKitTimestamp(kitName);
// When can be use the kit again?
final Calendar delayTime = new GregorianCalendar();
delayTime.setTimeInMillis(lastTime);
delayTime.add(Calendar.SECOND, (int) delay);
delayTime.add(Calendar.MILLISECOND, (int) ((delay * 1000.0) % 1000.0));
if (lastTime == 0L || lastTime > time.getTimeInMillis()) {
// If we have no record of kit use, or its corrupted, give them benefit of the doubt.
return 0L;
} else if (delay < 0d) {
// If the kit has a negative kit time, it can only be used once.
return -1;
} else if (delayTime.before(time)) {
// If the kit was used in the past, but outside the delay time, it can be used.
return 0L;
} else {
// If the kit has been used recently, return the next time it can be used.
return delayTime.getTimeInMillis();
}
}
@Deprecated
public List<String> getItems(final User user) throws Exception {
return getItems();
}
public List<String> getItems() throws Exception {
if (kit == null) {
throw new Exception(tl("kitNotFound"));
}
try {
final List<String> itemList = new ArrayList<String>();
final Object kitItems = kit.get("items");
if (kitItems instanceof List) {
for (Object item : (List) kitItems) {
if (item instanceof String) {
itemList.add(item.toString());
continue;
}
throw new Exception("Invalid kit item: " + item.toString());
}
return itemList;
}
throw new Exception("Invalid item list");
} catch (Exception e) {
ess.getLogger().log(Level.WARNING, "Error parsing kit " + kitName + ": " + e.getMessage());
throw new Exception(tl("kitError2"), e);
}
}
public void expandItems(final User user) throws Exception {
expandItems(user, getItems(user));
}
public void 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);
boolean spew = false;
final boolean allowUnsafe = ess.getSettings().allowUnsafeEnchantments();
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);
continue;
}
if (kitItem.startsWith("/")) {
String command = kitItem.substring(1);
String name = user.getName();
command = command.replace("{player}", name);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
continue;
}
final String[] parts = kitItem.split(" +");
final ItemStack parseStack = ess.getItemDb().get(parts[0], parts.length > 1 ? Integer.parseInt(parts[1]) : 1);
if (parseStack.getType() == Material.AIR) {
continue;
}
final MetaItemStack metaStack = new MetaItemStack(parseStack);
if (parts.length > 2) {
// We pass a null sender here because kits should not do perm checks
metaStack.parseStringMeta(null, allowUnsafe, parts, 2, ess);
}
final Map<Integer, ItemStack> overfilled;
final boolean allowOversizedStacks = user.isAuthorized("essentials.oversizedstacks");
if (allowOversizedStacks) {
overfilled = InventoryWorkaround.addOversizedItems(user.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), metaStack.getItemStack());
} else {
overfilled = InventoryWorkaround.addItems(user.getBase().getInventory(), metaStack.getItemStack());
}
for (ItemStack itemStack : overfilled.values()) {
int spillAmount = itemStack.getAmount();
if (!allowOversizedStacks) {
itemStack.setAmount(spillAmount < itemStack.getMaxStackSize() ? spillAmount : itemStack.getMaxStackSize());
}
while (spillAmount > 0) {
user.getWorld().dropItemNaturally(user.getLocation(), itemStack);
spillAmount -= itemStack.getAmount();
}
spew = true;
}
}
user.getBase().updateInventory();
if (spew) {
user.sendMessage(tl("kitInvFull"));
}
} catch (Exception e) {
user.getBase().updateInventory();
ess.getLogger().log(Level.WARNING, e.getMessage());
throw new Exception(tl("kitError2"), e);
}
}
}
@@ -1,114 +0,0 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.NumberUtil;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.MemoryConfiguration;
import java.io.File;
import java.math.BigDecimal;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static com.earth2me.essentials.I18n.capitalCase;
import static com.earth2me.essentials.I18n.tl;
public class Kits implements IConf {
private final EssentialsConf config;
private ConfigurationSection kits;
public Kits(final IEssentials essentials) {
config = new EssentialsConf(new File(essentials.getDataFolder(), "kits.yml"));
config.setTemplateName("/kits.yml");
reloadConfig();
}
@Override
public void reloadConfig() {
config.load();
kits = _getKits();
}
private ConfigurationSection _getKits() {
if (config.isConfigurationSection("kits")) {
final ConfigurationSection section = config.getConfigurationSection("kits");
final ConfigurationSection newSection = new MemoryConfiguration();
for (String kitItem : section.getKeys(false)) {
if (section.isConfigurationSection(kitItem)) {
newSection.set(kitItem.toLowerCase(Locale.ENGLISH), section.getConfigurationSection(kitItem));
}
}
return newSection;
}
return null;
}
public EssentialsConf getConfig() {
return config;
}
public ConfigurationSection getKits() {
return kits;
}
public Map<String, Object> getKit(String name) {
name = name.replace('.', '_').replace('/', '_');
if (getKits() != null) {
final ConfigurationSection kits = getKits();
// For some reason, YAML doesn't sees keys as always lowercase even if they aren't defined like that.
// Workaround is to toLowercase when getting from the config, but showing normally elsewhere.
// ODDLY ENOUGH when you get the configuration section for ALL kits, it will return the proper
// case of each kit. But when you check for each kit's configuration section, it won't return the kit
// you just found if you don't toLowercase it.
if (kits.isConfigurationSection(name.toLowerCase())) {
return kits.getConfigurationSection(name.toLowerCase()).getValues(true);
} else {
}
}
return null;
}
public void addKit(String name, List<String> lines, long delay) {
// Will overwrite but w/e
config.set("kits." + name + ".delay", delay);
config.set("kits." + name + ".items", lines);
kits = _getKits();
config.save();
}
public String listKits(final net.ess3.api.IEssentials ess, final User user) throws Exception {
try {
final ConfigurationSection kits = config.getConfigurationSection("kits");
final StringBuilder list = new StringBuilder();
for (String kitItem : kits.getKeys(false)) {
if (user == null) {
list.append(" ").append(capitalCase(kitItem));
} else if (user.isAuthorized("essentials.kits." + kitItem.toLowerCase(Locale.ENGLISH))) {
String cost = "";
String name = capitalCase(kitItem);
BigDecimal costPrice = new Trade("kit-" + kitItem.toLowerCase(Locale.ENGLISH), ess).getCommandCost(user);
if (costPrice.signum() > 0) {
cost = tl("kitCost", NumberUtil.displayCurrency(costPrice, ess));
}
Kit kit = new Kit(kitItem, ess);
double nextUse = kit.getNextUse(user);
if (nextUse == -1 && ess.getSettings().isSkippingUsedOneTimeKitsFromKitList()) {
continue;
} else if (nextUse != 0) {
name = tl("kitDelay", name);
}
list.append(" ").append(name).append(cost);
}
}
return list.toString().trim();
} catch (Exception ex) {
throw new Exception(tl("kitError"), ex);
}
}
}
@@ -1,272 +0,0 @@
package com.earth2me.essentials;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.StringUtil;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.entity.*;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.Colorable;
import java.util.*;
import java.util.logging.Logger;
import static com.earth2me.essentials.I18n.tl;
public enum MobData {
BABY_AGEABLE("baby", Ageable.class, Data.BABY, true),
ADULT_AGEABLE("adult", Ageable.class, Data.ADULT, true),
BABY_PIG("piglet", EntityType.PIG, Data.BABY, false),
BABY_WOLF("puppy", EntityType.WOLF, Data.BABY, false),
BABY_CHICKEN("chick", EntityType.CHICKEN, Data.BABY, false),
BABY_HORSE("colt", EntityType.HORSE, Data.BABY, false),
BABY_OCELOT("kitten", EntityType.OCELOT, Data.BABY, false),
BABY_SHEEP("lamb", EntityType.SHEEP, Data.BABY, false),
BABY_COW("calf", EntityType.COW.getEntityClass(), Data.BABY, false),
BABY_VILLAGER("child", EntityType.VILLAGER, Data.BABY, false),
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),
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),
SOCKS_HORSE("socks", EntityType.HORSE, Horse.Style.WHITE, false),
LEOPARD_HORSE("leopard", EntityType.HORSE, Horse.Style.WHITE_DOTS, true),
APPALOOSA_HORSE("appaloosa", EntityType.HORSE, Horse.Style.WHITE_DOTS, false),
PAINT_HORSE("paint", EntityType.HORSE, Horse.Style.WHITEFIELD, true),
MILKY_HORSE("milky", EntityType.HORSE, Horse.Style.WHITEFIELD, false),
SPLOTCHY_HORSE("splotchy", EntityType.HORSE, Horse.Style.WHITEFIELD, false),
BLACK_HORSE("black", EntityType.HORSE, Horse.Color.BLACK, true),
CHESTNUT_HORSE("chestnut", EntityType.HORSE, Horse.Color.CHESTNUT, true),
LIVER_HORSE("liver", EntityType.HORSE, Horse.Color.CHESTNUT, false),
CREAMY_HORSE("creamy", EntityType.HORSE, Horse.Color.CREAMY, true),
FLAXEN_HORSE("flaxen", EntityType.HORSE, Horse.Color.CREAMY, false),
GRAY_HORSE("gray", EntityType.HORSE, Horse.Color.GRAY, true),
DAPPLE_HORSE("dapple", EntityType.HORSE, Horse.Color.GRAY, false),
BUCKSKIN_HORSE("buckskin", EntityType.HORSE, Horse.Color.DARK_BROWN, true),
DARKBROWN_HORSE("darkbrown", EntityType.HORSE, Horse.Color.DARK_BROWN, false),
DARK_HORSE("dark", EntityType.HORSE, Horse.Color.DARK_BROWN, false),
DBROWN_HORSE("dbrown", EntityType.HORSE, Horse.Color.DARK_BROWN, false),
BAY_HORSE("bay", EntityType.HORSE, Horse.Color.BROWN, true),
BROWN_HORSE("brown", EntityType.HORSE, Horse.Color.BROWN, false),
SADDLE_HORSE("saddle", EntityType.HORSE, Data.HORSESADDLE, true),
GOLD_ARMOR_HORSE("goldarmor", EntityType.HORSE, EnumUtil.getMaterial("GOLDEN_HORSE_ARMOR", "GOLD_BARDING"), true),
DIAMOND_ARMOR_HORSE("diamondarmor", EntityType.HORSE, EnumUtil.getMaterial("DIAMOND_HORSE_ARMOR", "DIAMOND_BARDING"), true),
ARMOR_HORSE("armor", EntityType.HORSE, EnumUtil.getMaterial("IRON_HORSE_ARMOR", "IRON_BARDING"), true),
SIAMESE_CAT("siamese", EntityType.OCELOT, Ocelot.Type.SIAMESE_CAT, true),
WHITE_CAT("white", EntityType.OCELOT, Ocelot.Type.SIAMESE_CAT, false),
RED_CAT("red", EntityType.OCELOT, Ocelot.Type.RED_CAT, true),
ORANGE_CAT("orange", EntityType.OCELOT, Ocelot.Type.RED_CAT, false),
TABBY_CAT("tabby", EntityType.OCELOT, Ocelot.Type.RED_CAT, false),
BLACK_CAT("black", EntityType.OCELOT, Ocelot.Type.BLACK_CAT, true),
TUXEDO_CAT("tuxedo", EntityType.OCELOT, Ocelot.Type.BLACK_CAT, false),
BABY_ZOMBIE("baby", EntityType.ZOMBIE.getEntityClass(), Data.BABYZOMBIE, true),
ADULT_ZOMBIE("adult", EntityType.ZOMBIE.getEntityClass(), Data.ADULTZOMBIE, true),
DIAMOND_SWORD_ZOMBIE("diamondsword", EntityType.ZOMBIE.getEntityClass(), Material.DIAMOND_SWORD, true),
GOLD_SWORD_ZOMBIE("goldsword", EntityType.ZOMBIE.getEntityClass(), EnumUtil.getMaterial("GOLDEN_SWORD", "GOLD_SWORD"), true),
IRON_SWORD_ZOMBIE("ironsword", EntityType.ZOMBIE.getEntityClass(), Material.IRON_SWORD, true),
STONE_SWORD_ZOMBIE("stonesword", EntityType.ZOMBIE.getEntityClass(), Material.STONE_SWORD, false),
SWORD_ZOMBIE("sword", EntityType.ZOMBIE.getEntityClass(), Material.STONE_SWORD, true),
DIAMOND_SWORD_SKELETON("diamondsword", EntityType.SKELETON, Material.DIAMOND_SWORD, true),
GOLD_SWORD_SKELETON("goldsword", EntityType.SKELETON, EnumUtil.getMaterial("GOLDEN_SWORD", "GOLD_SWORD"), true),
IRON_SWORD_SKELETON("ironsword", EntityType.SKELETON, Material.IRON_SWORD, true),
STONE_SWORD_SKELETON("stonesword", EntityType.SKELETON, Material.STONE_SWORD, false),
SWORD_SKELETON("sword", EntityType.SKELETON, Material.STONE_SWORD, true),
BOW_SKELETON("bow", EntityType.SKELETON, Material.BOW, true),
POWERED_CREEPER("powered", EntityType.CREEPER, Data.ELECTRIFIED, true),
ELECTRIC_CREEPER("electric", EntityType.CREEPER, Data.ELECTRIFIED, false),
CHARGED_CREEPER("charged", EntityType.CREEPER, Data.ELECTRIFIED, false),
SADDLE_PIG("saddle", EntityType.PIG, Data.PIGSADDLE, true),
ANGRY_WOLF("angry", EntityType.WOLF, Data.ANGRY, true),
RABID_WOLF("rabid", EntityType.WOLF, Data.ANGRY, false),
FARMER_VILLAGER("farmer", EntityType.VILLAGER, Villager.Profession.FARMER, true),
LIBRARIAN_VILLAGER("librarian", EntityType.VILLAGER, Villager.Profession.LIBRARIAN, true),
PRIEST_VILLAGER("priest", EntityType.VILLAGER, Villager.Profession.PRIEST, true),
FATHER_VILLAGER("father", EntityType.VILLAGER, Villager.Profession.PRIEST, false),
SMITH_VILLAGER("smith", EntityType.VILLAGER, Villager.Profession.BLACKSMITH, true),
BUTCHER_VILLAGER("butcher", EntityType.VILLAGER, Villager.Profession.BUTCHER, true),
SIZE_SLIME("", "<1-100>", EntityType.SLIME.getEntityClass(), Data.SIZE, true),
NUM_EXPERIENCE_ORB("", "<1-2000000000>", EntityType.EXPERIENCE_ORB, Data.EXP, true),
RED_PARROT("red", EntityType.PARROT, Parrot.Variant.RED, true),
GREEN_PARROT("green", EntityType.PARROT, Parrot.Variant.GREEN, true),
BLUE_PARROT("blue", EntityType.PARROT, Parrot.Variant.BLUE, true),
CYAN_PARROT("cyan", EntityType.PARROT, Parrot.Variant.CYAN, true),
GRAY_PARROT("gray", EntityType.PARROT, Parrot.Variant.GRAY, true),
KOB_TROPICAL_FISH("kob", EntityType.TROPICAL_FISH, TropicalFish.Pattern.KOB, true),
SUNSTREAK_TROPICAL_FISH("sunstreak", EntityType.TROPICAL_FISH, TropicalFish.Pattern.SUNSTREAK, true),
SNOOPER_TROPICAL_FISH("snooper", EntityType.TROPICAL_FISH, TropicalFish.Pattern.SNOOPER, true),
DASHER_TROPICAL_FISH("dasher", EntityType.TROPICAL_FISH, TropicalFish.Pattern.DASHER, true),
BRINELY_TROPICAL_FISH("brinely", EntityType.TROPICAL_FISH, TropicalFish.Pattern.BRINELY, true),
SPOTTY_TROPICAL_FISH("spotty", EntityType.TROPICAL_FISH, TropicalFish.Pattern.SPOTTY, true),
FLOPPER_TROPICAL_FISH("flopper", EntityType.TROPICAL_FISH, TropicalFish.Pattern.FLOPPER, true),
STRIPEY_TROPICAL_FISH("stripey", EntityType.TROPICAL_FISH, TropicalFish.Pattern.STRIPEY, true),
GLITTER_TROPICAL_FISH("glitter", EntityType.TROPICAL_FISH, TropicalFish.Pattern.GLITTER, true),
BLOCKFISH_TROPICAL_FISH("blockfish", EntityType.TROPICAL_FISH, TropicalFish.Pattern.BLOCKFISH, true),
BETTY_TROPICAL_FISH("betty", EntityType.TROPICAL_FISH, TropicalFish.Pattern.BETTY, true),
CLAYFISH_TROPICAL_FISH("clayfish", EntityType.TROPICAL_FISH, TropicalFish.Pattern.CLAYFISH, true);
;
public enum Data {
ADULT,
BABY,
CHEST,
ADULTZOMBIE,
BABYZOMBIE,
HORSESADDLE,
PIGSADDLE,
ELECTRIFIED,
ANGRY,
TAMED,
COLORABLE,
EXP,
SIZE
}
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 Object type;
final private Object value;
final private boolean isPublic;
private String matched;
public static LinkedHashMap<String, MobData> getPossibleData(final Entity spawned, boolean publicOnly) {
LinkedHashMap<String, MobData> mobList = new LinkedHashMap<String, MobData>();
for (MobData data : MobData.values()) {
if (data.type instanceof EntityType && spawned.getType().equals(data.type) && ((publicOnly && data.isPublic) || !publicOnly)) {
mobList.put(data.nickname.toLowerCase(Locale.ENGLISH), data);
} else if (data.type instanceof Class && ((Class) data.type).isAssignableFrom(spawned.getClass()) && ((publicOnly && data.isPublic) || !publicOnly)) {
mobList.put(data.nickname.toLowerCase(Locale.ENGLISH), data);
}
}
return mobList;
}
public static List<String> getValidHelp(final Entity spawned) {
List<String> output = new ArrayList<String>();
LinkedHashMap<String, MobData> posData = getPossibleData(spawned, true);
for (MobData data : posData.values()) {
output.add(data.helpMessage);
}
return output;
}
public static MobData fromData(final Entity spawned, final String name) {
if (name.isEmpty()) {
return null;
}
LinkedHashMap<String, MobData> posData = getPossibleData(spawned, false);
for (String data : posData.keySet()) {
if (name.contains(data)) {
return posData.get(data);
}
}
return null;
}
public String getMatched() {
return this.matched;
}
public void setData(final Entity spawned, final Player target, final String rawData) throws Exception {
if (this.value.equals(Data.ANGRY)) {
((Wolf) spawned).setAngry(true);
} else if (this.value.equals(Data.ADULT)) {
((Ageable) spawned).setAdult();
} else if (this.value.equals(Data.BABY)) {
((Ageable) spawned).setBaby();
} else if (this.value.equals(Data.ADULTZOMBIE)) {
((Zombie) spawned).setBaby(false);
} else if (this.value.equals(Data.BABYZOMBIE)) {
((Zombie) spawned).setBaby(true);
} else if (this.value.equals(Data.ELECTRIFIED)) {
((Creeper) spawned).setPowered(true);
} else if (this.value.equals(Data.HORSESADDLE)) {
final Horse horse = ((Horse) spawned);
horse.setTamed(true);
horse.setOwner(target);
horse.getInventory().setSaddle(new ItemStack(Material.SADDLE, 1));
} else if (this.value.equals(Data.PIGSADDLE)) {
((Pig) spawned).setSaddle(true);
} else if (this.value.equals(Data.TAMED)) {
final Tameable tameable = ((Tameable) spawned);
tameable.setTamed(true);
tameable.setOwner(target);
} else if (this.value.equals(Data.COLORABLE)) {
final String color = rawData.toUpperCase(Locale.ENGLISH);
try {
if (color.equals("RANDOM")) {
final Random rand = new Random();
((Colorable) spawned).setColor(DyeColor.values()[rand.nextInt(DyeColor.values().length)]);
} else if (!color.isEmpty()) {
((Colorable) spawned).setColor(DyeColor.valueOf(color));
}
this.matched = rawData;
} catch (Exception e) {
throw new Exception(tl("sheepMalformedColor"), e);
}
} else if (this.value.equals(Data.EXP)) {
try {
((ExperienceOrb) spawned).setExperience(Integer.parseInt(rawData));
this.matched = rawData;
} catch (NumberFormatException e) {
throw new Exception(tl("invalidNumber"), e);
}
} else if (this.value.equals(Data.SIZE)) {
try {
((Slime) spawned).setSize(Integer.parseInt(rawData));
this.matched = rawData;
} catch (NumberFormatException e) {
throw new Exception(tl("slimeMalformedSize"), e);
}
} else if (this.value instanceof Horse.Color) {
((Horse) spawned).setColor((Horse.Color) this.value);
} else if (this.value instanceof Horse.Style) {
((Horse) spawned).setStyle((Horse.Style) this.value);
} else if (this.value instanceof Ocelot.Type) {
((Ocelot) spawned).setCatType((Ocelot.Type) this.value);
} else if (this.value instanceof Villager.Profession) {
((Villager) spawned).setProfession((Villager.Profession) this.value);
} else if (this.value instanceof Material) {
if (this.type.equals(EntityType.HORSE)) {
((Horse) spawned).setTamed(true);
((Horse) spawned).getInventory().setArmor(new ItemStack((Material) this.value, 1));
} else if (this.type.equals(EntityType.ZOMBIE.getEntityClass()) || this.type.equals(EntityType.SKELETON)) {
final EntityEquipment invent = ((LivingEntity) spawned).getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack((Material) this.value, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
}
} else if (this.value instanceof Parrot.Variant) {
((Parrot) spawned).setVariant((Parrot.Variant) this.value);
} else if (this.value instanceof TropicalFish.Pattern) {
((TropicalFish) spawned).setPattern((TropicalFish.Pattern) this.value);
}
}
}
@@ -1,123 +0,0 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.Server;
import java.util.*;
import static com.earth2me.essentials.I18n.tl;
public class PlayerList {
// Cosmetic list formatting
public static String listUsers(final IEssentials ess, final List<User> users, final String seperator) {
final StringBuilder groupString = new StringBuilder();
Collections.sort(users);
boolean needComma = false;
for (User user : users) {
if (needComma) {
groupString.append(seperator);
}
needComma = true;
if (user.isAfk()) {
groupString.append(tl("listAfkTag"));
}
if (user.isHidden()) {
groupString.append(tl("listHiddenTag"));
}
user.setDisplayNick();
groupString.append(user.getDisplayName());
groupString.append("\u00a7f");
}
return groupString.toString();
}
// Produce a user summary: There are 5 out of maximum 10 players online.
public static String listSummary(final IEssentials ess, final User user, final boolean showHidden) {
Server server = ess.getServer();
int playerHidden = 0;
int hiddenCount = 0;
for (User onlinePlayer : ess.getOnlineUsers()) {
if (onlinePlayer.isHidden() || (user != null && !user.getBase().canSee(onlinePlayer.getBase()))) {
playerHidden++;
if (showHidden || user.getBase().canSee(onlinePlayer.getBase())) {
hiddenCount++;
}
}
}
String online;
if (hiddenCount > 0) {
online = tl("listAmountHidden", ess.getOnlinePlayers().size() - playerHidden, hiddenCount, server.getMaxPlayers());
} else {
online = tl("listAmount", ess.getOnlinePlayers().size() - playerHidden, server.getMaxPlayers());
}
return online;
}
// 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>>();
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.add(onlineUser);
}
return 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>();
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()) {
continue;
}
List<User> u = playerList.get(groupValue.trim());
if (u == null || u.isEmpty()) {
continue;
}
playerList.remove(groupValue);
users.addAll(u);
}
}
}
return users;
}
// Output a playerlist of just a single group, /list <groupname>
public static String listGroupUsers(final IEssentials ess, final Map<String, List<User>> playerList, final String groupName) throws Exception {
final List<User> users = getMergedList(ess, playerList, groupName);
final List<User> groupUsers = playerList.get(groupName);
if (groupUsers != null && !groupUsers.isEmpty()) {
users.addAll(groupUsers);
}
if (users == null || 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, ", "));
}
// 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();
}
}
@@ -1,959 +0,0 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.collect.ImmutableMap;
import net.ess3.api.IEssentials;
import net.ess3.api.InvalidWorldException;
import net.ess3.api.MaxMoneyException;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import static com.earth2me.essentials.I18n.tl;
public abstract class UserData extends PlayerExtension implements IConf {
protected final transient IEssentials ess;
private final EssentialsUserConf config;
private final File folder;
protected UserData(Player base, IEssentials ess) {
super(base);
this.ess = ess;
folder = new File(ess.getDataFolder(), "userdata");
if (!folder.exists()) {
folder.mkdirs();
}
String filename;
try {
filename = base.getUniqueId().toString();
} catch (Throwable ex) {
ess.getLogger().warning("Falling back to old username system for " + base.getName());
filename = base.getName();
}
config = new EssentialsUserConf(base.getName(), base.getUniqueId(), new File(folder, filename + ".yml"));
reloadConfig();
}
public final void reset() {
config.forceSave();
config.getFile().delete();
if (config.username != null) {
ess.getUserMap().removeUser(config.username);
}
}
public final void cleanup() {
config.cleanup();
}
@Override
public final void reloadConfig() {
config.load();
money = _getMoney();
unlimited = _getUnlimited();
powertools = _getPowertools();
homes = _getHomes();
lastLocation = _getLastLocation();
lastTeleportTimestamp = _getLastTeleportTimestamp();
lastHealTimestamp = _getLastHealTimestamp();
jail = _getJail();
mails = _getMails();
teleportEnabled = _getTeleportEnabled();
godmode = _getGodModeEnabled();
muted = _getMuted();
muteTimeout = _getMuteTimeout();
jailed = _getJailed();
jailTimeout = _getJailTimeout();
lastLogin = _getLastLogin();
lastLogout = _getLastLogout();
lastLoginAddress = _getLastLoginAddress();
afk = _getAfk();
geolocation = _getGeoLocation();
isSocialSpyEnabled = _isSocialSpyEnabled();
isNPC = _isNPC();
arePowerToolsEnabled = _arePowerToolsEnabled();
kitTimestamps = _getKitTimestamps();
nickname = _getNickname();
ignoredPlayers = _getIgnoredPlayers();
logoutLocation = _getLogoutLocation();
lastAccountName = _getLastAccountName();
commandCooldowns = _getCommandCooldowns();
acceptingPay = _getAcceptingPay();
confirmPay = _getConfirmPay();
confirmClear = _getConfirmClear();
}
private BigDecimal money;
private BigDecimal _getMoney() {
BigDecimal result = ess.getSettings().getStartingBalance();
BigDecimal maxMoney = ess.getSettings().getMaxMoney();
BigDecimal minMoney = ess.getSettings().getMinMoney();
// NPC banks are not actual player banks, as such they do not have player starting balance.
if (isNPC()) {
result = BigDecimal.ZERO;
}
if (config.hasProperty("money")) {
result = config.getBigDecimal("money", result);
}
if (result.compareTo(maxMoney) > 0) {
result = maxMoney;
}
if (result.compareTo(minMoney) < 0) {
result = minMoney;
}
return result;
}
public BigDecimal getMoney() {
return money;
}
public void setMoney(BigDecimal value, boolean throwError) throws MaxMoneyException {
BigDecimal maxMoney = ess.getSettings().getMaxMoney();
BigDecimal minMoney = ess.getSettings().getMinMoney();
if (value.compareTo(maxMoney) > 0) {
if (throwError) {
throw new MaxMoneyException();
}
money = maxMoney;
} else {
money = value;
}
if (money.compareTo(minMoney) < 0) {
money = minMoney;
}
config.setProperty("money", money);
stopTransaction();
}
private Map<String, Object> homes;
private Map<String, Object> _getHomes() {
if (config.isConfigurationSection("homes")) {
return config.getConfigurationSection("homes").getValues(false);
}
return new HashMap<String, Object>();
}
private String getHomeName(String search) {
if (NumberUtil.isInt(search)) {
try {
search = getHomes().get(Integer.parseInt(search) - 1);
} catch (NumberFormatException e) {
} catch (IndexOutOfBoundsException e) {
}
}
return search;
}
public Location getHome(String name) throws Exception {
String search = getHomeName(name);
return config.getLocation("homes." + search, this.getBase().getServer());
}
public Location getHome(final Location world) {
try {
if (getHomes().isEmpty()) {
return null;
}
Location loc;
for (String home : getHomes()) {
loc = config.getLocation("homes." + home, this.getBase().getServer());
if (world.getWorld() == loc.getWorld()) {
return loc;
}
}
loc = config.getLocation("homes." + getHomes().get(0), this.getBase().getServer());
return loc;
} catch (InvalidWorldException ex) {
return null;
}
}
public List<String> getHomes() {
return new ArrayList<String>(homes.keySet());
}
public void setHome(String name, Location loc) {
//Invalid names will corrupt the yaml
name = StringUtil.safeString(name);
homes.put(name, loc);
config.setProperty("homes." + name, loc);
config.save();
}
public void delHome(String name) throws Exception {
String search = getHomeName(name);
if (!homes.containsKey(search)) {
search = StringUtil.safeString(search);
}
if (homes.containsKey(search)) {
homes.remove(search);
config.removeProperty("homes." + search);
config.save();
} else {
throw new Exception(tl("invalidHome", search));
}
}
public boolean hasHome() {
return config.hasProperty("home");
}
private String nickname;
public String _getNickname() {
return config.getString("nickname");
}
public String getNickname() {
return nickname;
}
public void setNickname(String nick) {
nickname = nick;
config.setProperty("nickname", nick);
config.save();
}
private List<Material> unlimited;
private List<Material> _getUnlimited() {
List<Material> retlist = new ArrayList<>();
List<String> configList = config.getStringList("unlimited");
for(String s : configList) {
Material mat = Material.matchMaterial(s);
if(mat != null) {
retlist.add(mat);
}
}
return retlist;
}
public List<Material> getUnlimited() {
return unlimited;
}
public boolean hasUnlimited(ItemStack stack) {
return unlimited.contains(stack.getType());
}
public void setUnlimited(ItemStack stack, boolean state) {
if (unlimited.contains(stack.getType())) {
unlimited.remove(stack.getType());
}
if (state) {
unlimited.add(stack.getType());
}
config.setProperty("unlimited", unlimited);
config.save();
}
private Map<String, Object> powertools;
private Map<String, Object> _getPowertools() {
if (config.isConfigurationSection("powertools")) {
return config.getConfigurationSection("powertools").getValues(false);
}
return new HashMap<>();
}
public void clearAllPowertools() {
powertools.clear();
config.setProperty("powertools", powertools);
config.save();
}
@SuppressWarnings("unchecked")
public List<String> getPowertool(ItemStack stack) {
return (List<String>) powertools.get(stack.getType().name().toLowerCase(Locale.ENGLISH));
}
@SuppressWarnings("unchecked")
public List<String> getPowertool(Material material) {
return (List<String>) powertools.get(material.name().toLowerCase(Locale.ENGLISH));
}
public void setPowertool(ItemStack stack, List<String> commandList) {
if (commandList == null || commandList.isEmpty()) {
powertools.remove(stack.getType().name().toLowerCase(Locale.ENGLISH));
} else {
powertools.put(stack.getType().name().toLowerCase(Locale.ENGLISH), commandList);
}
config.setProperty("powertools", powertools);
config.save();
}
public boolean hasPowerTools() {
return !powertools.isEmpty();
}
private Location lastLocation;
private Location _getLastLocation() {
try {
return config.getLocation("lastlocation", this.getBase().getServer());
} catch (InvalidWorldException e) {
return null;
}
}
public Location getLastLocation() {
return lastLocation;
}
public void setLastLocation(Location loc) {
if (loc == null || loc.getWorld() == null) {
return;
}
lastLocation = loc;
config.setProperty("lastlocation", loc);
config.save();
}
private Location logoutLocation;
private Location _getLogoutLocation() {
try {
return config.getLocation("logoutlocation", this.getBase().getServer());
} catch (InvalidWorldException e) {
return null;
}
}
public Location getLogoutLocation() {
return logoutLocation;
}
public void setLogoutLocation(Location loc) {
if (loc == null || loc.getWorld() == null) {
return;
}
logoutLocation = loc;
config.setProperty("logoutlocation", loc);
config.save();
}
private long lastTeleportTimestamp;
private long _getLastTeleportTimestamp() {
return config.getLong("timestamps.lastteleport", 0);
}
public long getLastTeleportTimestamp() {
return lastTeleportTimestamp;
}
public void setLastTeleportTimestamp(long time) {
lastTeleportTimestamp = time;
config.setProperty("timestamps.lastteleport", time);
config.save();
}
private long lastHealTimestamp;
private long _getLastHealTimestamp() {
return config.getLong("timestamps.lastheal", 0);
}
public long getLastHealTimestamp() {
return lastHealTimestamp;
}
public void setLastHealTimestamp(long time) {
lastHealTimestamp = time;
config.setProperty("timestamps.lastheal", time);
config.save();
}
private String jail;
private String _getJail() {
return config.getString("jail");
}
public String getJail() {
return jail;
}
public void setJail(String jail) {
if (jail == null || jail.isEmpty()) {
this.jail = null;
config.removeProperty("jail");
} else {
this.jail = jail;
config.setProperty("jail", jail);
}
config.save();
}
private List<String> mails;
private List<String> _getMails() {
return config.getStringList("mail");
}
public List<String> getMails() {
return mails;
}
public void setMails(List<String> mails) {
if (mails == null) {
config.removeProperty("mail");
mails = _getMails();
} else {
config.setProperty("mail", mails);
}
this.mails = mails;
config.save();
}
public void addMail(String mail) {
mails.add(mail);
setMails(mails);
}
private boolean teleportEnabled;
private boolean _getTeleportEnabled() {
return config.getBoolean("teleportenabled", true);
}
public boolean isTeleportEnabled() {
return teleportEnabled;
}
public void setTeleportEnabled(boolean set) {
teleportEnabled = set;
config.setProperty("teleportenabled", set);
config.save();
}
private List<String> ignoredPlayers;
public List<String> _getIgnoredPlayers() {
return Collections.synchronizedList(config.getStringList("ignore"));
}
public void setIgnoredPlayers(List<String> players) {
if (players == null || players.isEmpty()) {
ignoredPlayers = Collections.synchronizedList(new ArrayList<String>());
config.removeProperty("ignore");
} else {
ignoredPlayers = players;
config.setProperty("ignore", players);
}
config.save();
}
@Deprecated
public boolean isIgnoredPlayer(final String userName) {
final IUser user = ess.getUser(userName);
if (user == null || !user.getBase().isOnline()) {
return false;
}
return isIgnoredPlayer(user);
}
public boolean isIgnoredPlayer(IUser user) {
return (ignoredPlayers.contains(user.getName().toLowerCase(Locale.ENGLISH)) && !user.isIgnoreExempt());
}
public void setIgnoredPlayer(IUser user, boolean set) {
final String entry = user.getName().toLowerCase(Locale.ENGLISH);
if (set) {
if (!ignoredPlayers.contains(entry)) ignoredPlayers.add(entry);
} else {
ignoredPlayers.remove(entry);
}
setIgnoredPlayers(ignoredPlayers);
}
private boolean godmode;
private boolean _getGodModeEnabled() {
return config.getBoolean("godmode", false);
}
public boolean isGodModeEnabled() {
return godmode;
}
public void setGodModeEnabled(boolean set) {
godmode = set;
config.setProperty("godmode", set);
config.save();
}
private boolean muted;
public boolean _getMuted() {
return config.getBoolean("muted", false);
}
public boolean getMuted() {
return muted;
}
public boolean isMuted() {
return muted;
}
public void setMuted(boolean set) {
muted = set;
config.setProperty("muted", set);
config.save();
}
private long muteTimeout;
private long _getMuteTimeout() {
return config.getLong("timestamps.mute", 0);
}
public long getMuteTimeout() {
return muteTimeout;
}
public void setMuteTimeout(long time) {
muteTimeout = time;
config.setProperty("timestamps.mute", time);
config.save();
}
private boolean jailed;
private boolean _getJailed() {
return config.getBoolean("jailed", false);
}
public boolean isJailed() {
return jailed;
}
public void setJailed(boolean set) {
jailed = set;
config.setProperty("jailed", set);
config.save();
}
public boolean toggleJailed() {
boolean ret = !isJailed();
setJailed(ret);
return ret;
}
private long jailTimeout;
private long _getJailTimeout() {
return config.getLong("timestamps.jail", 0);
}
public long getJailTimeout() {
return jailTimeout;
}
public void setJailTimeout(long time) {
jailTimeout = time;
config.setProperty("timestamps.jail", time);
config.save();
}
private long lastLogin;
private long _getLastLogin() {
return config.getLong("timestamps.login", 0);
}
public long getLastLogin() {
return lastLogin;
}
private void _setLastLogin(long time) {
lastLogin = time;
config.setProperty("timestamps.login", time);
}
public void setLastLogin(long time) {
_setLastLogin(time);
if (base.getAddress() != null && base.getAddress().getAddress() != null) {
_setLastLoginAddress(base.getAddress().getAddress().getHostAddress());
}
config.save();
}
private long lastLogout;
private long _getLastLogout() {
return config.getLong("timestamps.logout", 0);
}
public long getLastLogout() {
return lastLogout;
}
public void setLastLogout(long time) {
lastLogout = time;
config.setProperty("timestamps.logout", time);
config.save();
}
private String lastLoginAddress;
private String _getLastLoginAddress() {
return config.getString("ipAddress", "");
}
public String getLastLoginAddress() {
return lastLoginAddress;
}
private void _setLastLoginAddress(String address) {
lastLoginAddress = address;
config.setProperty("ipAddress", address);
}
private boolean afk;
private boolean _getAfk() {
return config.getBoolean("afk", false);
}
public boolean isAfk() {
return afk;
}
public void _setAfk(boolean set) {
afk = set;
config.setProperty("afk", set);
config.save();
}
private boolean newplayer;
private String geolocation;
private String _getGeoLocation() {
return config.getString("geolocation");
}
public String getGeoLocation() {
return geolocation;
}
public void setGeoLocation(String geolocation) {
if (geolocation == null || geolocation.isEmpty()) {
this.geolocation = null;
config.removeProperty("geolocation");
} else {
this.geolocation = geolocation;
config.setProperty("geolocation", geolocation);
}
config.save();
}
private boolean isSocialSpyEnabled;
private boolean _isSocialSpyEnabled() {
return config.getBoolean("socialspy", false);
}
public boolean isSocialSpyEnabled() {
return isSocialSpyEnabled;
}
public void setSocialSpyEnabled(boolean status) {
isSocialSpyEnabled = status;
config.setProperty("socialspy", status);
config.save();
}
private boolean isNPC;
private boolean _isNPC() {
return config.getBoolean("npc", false);
}
public boolean isNPC() {
return isNPC;
}
private String lastAccountName = null;
public String getLastAccountName() {
return lastAccountName;
}
public String _getLastAccountName() {
return config.getString("lastAccountName", null);
}
public void setLastAccountName(String lastAccountName) {
this.lastAccountName = lastAccountName;
config.setProperty("lastAccountName", lastAccountName);
config.save();
ess.getUserMap().trackUUID(getConfigUUID(), lastAccountName, true);
}
public void setNPC(boolean set) {
isNPC = set;
config.setProperty("npc", set);
config.save();
}
private boolean arePowerToolsEnabled;
public boolean arePowerToolsEnabled() {
return arePowerToolsEnabled;
}
public void setPowerToolsEnabled(boolean set) {
arePowerToolsEnabled = set;
config.setProperty("powertoolsenabled", set);
config.save();
}
public boolean togglePowerToolsEnabled() {
boolean ret = !arePowerToolsEnabled();
setPowerToolsEnabled(ret);
return ret;
}
private boolean _arePowerToolsEnabled() {
return config.getBoolean("powertoolsenabled", true);
}
private Map<String, Long> kitTimestamps;
private Map<String, Long> _getKitTimestamps() {
if (config.isConfigurationSection("timestamps.kits")) {
final ConfigurationSection section = config.getConfigurationSection("timestamps.kits");
final Map<String, Long> timestamps = new HashMap<String, Long>();
for (String command : section.getKeys(false)) {
if (section.isLong(command)) {
timestamps.put(command.toLowerCase(Locale.ENGLISH), section.getLong(command));
} else if (section.isInt(command)) {
timestamps.put(command.toLowerCase(Locale.ENGLISH), (long) section.getInt(command));
}
}
return timestamps;
}
return new HashMap<String, Long>();
}
public long getKitTimestamp(String name) {
name = name.replace('.', '_').replace('/', '_');
if (kitTimestamps != null && kitTimestamps.containsKey(name)) {
return kitTimestamps.get(name);
}
return 0l;
}
public void setKitTimestamp(final String name, final long time) {
kitTimestamps.put(name.toLowerCase(Locale.ENGLISH), time);
config.setProperty("timestamps.kits", kitTimestamps);
config.save();
}
public void setConfigProperty(String node, Object object) {
final String prefix = "info.";
node = prefix + node;
if (object instanceof Map) {
config.setProperty(node, (Map) object);
} else if (object instanceof List) {
config.setProperty(node, (List<String>) object);
} else if (object instanceof Location) {
config.setProperty(node, (Location) object);
} else if (object instanceof ItemStack) {
config.setProperty(node, (ItemStack) object);
} else {
config.setProperty(node, object);
}
config.save();
}
public Set<String> getConfigKeys() {
if (config.isConfigurationSection("info")) {
return config.getConfigurationSection("info").getKeys(true);
}
return new HashSet<String>();
}
public Map<String, Object> getConfigMap() {
if (config.isConfigurationSection("info")) {
return config.getConfigurationSection("info").getValues(true);
}
return new HashMap<String, Object>();
}
public Map<String, Object> getConfigMap(String node) {
if (config.isConfigurationSection("info." + node)) {
return config.getConfigurationSection("info." + node).getValues(true);
}
return new HashMap<String, Object>();
}
// Pattern, Date. Pattern for less pattern creations
private Map<Pattern, Long> commandCooldowns;
private Map<Pattern, Long> _getCommandCooldowns() {
if (!config.isConfigurationSection("timestamps.command-cooldowns")) {
return null;
}
// See saveCommandCooldowns() for deserialization explanation
List<Map<?, ?>> section = config.getMapList("timestamps.command-cooldowns");
HashMap<Pattern, Long> result = new HashMap<>();
for (Map<?, ?> map : section) {
Pattern pattern = Pattern.compile(map.get("pattern").toString());
long expiry = ((Number) map.get("expiry")).longValue();
result.put(pattern, expiry);
}
return result;
}
public Map<Pattern, Long> getCommandCooldowns() {
if (this.commandCooldowns == null) {
return Collections.emptyMap();
}
return Collections.unmodifiableMap(this.commandCooldowns);
}
public Date getCommandCooldownExpiry(String label) {
if (commandCooldowns != null) {
for (Entry<Pattern, Long> entry : this.commandCooldowns.entrySet()) {
if (entry.getKey().matcher(label).matches()) {
return new Date(entry.getValue());
}
}
}
return null;
}
public void addCommandCooldown(Pattern pattern, Date expiresAt, boolean save) {
if (this.commandCooldowns == null) {
this.commandCooldowns = new HashMap<>();
}
this.commandCooldowns.put(pattern, expiresAt.getTime());
if (save) {
saveCommandCooldowns();
}
}
public boolean clearCommandCooldown(Pattern pattern) {
if (this.commandCooldowns == null) {
return false; // false for no modification
}
if(this.commandCooldowns.remove(pattern) != null) {
saveCommandCooldowns();
return true;
}
return false;
}
private void saveCommandCooldowns() {
// Serialization explanation:
//
// Serialization is done as a map list instead of a config section due to limitations.
// When serializing patterns (which commonly include full stops .) Bukkit/Essentials config framework
// interprets it as a path separator, thus it breaks up the regex into sub nodes causing invalid syntax.
// Thus each command cooldown is instead stored as a Map of {pattern: .., expiry: ..} to work around this.
List<Object> serialized = new ArrayList<>();
for (Entry<Pattern, Long> entry : this.commandCooldowns.entrySet()) {
// Don't save expired cooldowns
if (entry.getValue() < System.currentTimeMillis()) {
continue;
}
Map<?, ?> map = ImmutableMap.builder()
.put("pattern", entry.getKey().pattern())
.put("expiry", entry.getValue())
.build();
serialized.add(map);
}
config.setProperty("timestamps.command-cooldowns", serialized);
save();
}
private boolean acceptingPay = true; // players accept pay by default
public boolean _getAcceptingPay() {
return config.getBoolean("acceptingPay", true);
}
public boolean isAcceptingPay() {
return acceptingPay;
}
public void setAcceptingPay(boolean acceptingPay) {
this.acceptingPay = acceptingPay;
config.setProperty("acceptingPay", acceptingPay);
save();
}
private Boolean confirmPay;
private Boolean _getConfirmPay() {
return (Boolean) config.get("confirm-pay");
}
public boolean isPromptingPayConfirm() {
return confirmPay != null ? confirmPay : ess.getSettings().isConfirmCommandEnabledByDefault("pay");
}
public void setPromptingPayConfirm(boolean prompt) {
this.confirmPay = prompt;
config.setProperty("confirm-pay", prompt);
save();
}
private Boolean confirmClear;
private Boolean _getConfirmClear() {
return (Boolean) config.get("confirm-clear");
}
public boolean isPromptingClearConfirm() {
return confirmClear != null ? confirmClear : ess.getSettings().isConfirmCommandEnabledByDefault("clearinventory");
}
public void setPromptingClearConfirm(boolean prompt) {
this.confirmClear = prompt;
config.setProperty("confirm-clear", prompt);
save();
}
public UUID getConfigUUID() {
return config.uuid;
}
public void save() {
config.save();
}
public void startTransaction() {
config.startTransaction();
}
public void stopTransaction() {
config.stopTransaction();
}
}
@@ -1,409 +0,0 @@
package com.earth2me.essentials.api;
import com.earth2me.essentials.EssentialsUserConf;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.base.Charsets;
import net.ess3.api.IEssentials;
import net.ess3.api.MaxMoneyException;
import java.io.File;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Instead of using this api directly, we recommend to use the register plugin: http://bit.ly/RegisterMethod
*/
public class Economy {
public Economy() {
}
private static final Logger logger = Logger.getLogger("Essentials");
private static IEssentials ess;
private static final String noCallBeforeLoad = "Essentials API is called before Essentials is loaded.";
public static final MathContext MATH_CONTEXT = MathContext.DECIMAL128;
/**
* @param aEss the ess to set
*/
public static void setEss(IEssentials aEss) {
ess = aEss;
}
private static void createNPCFile(String name) {
File folder = new File(ess.getDataFolder(), "userdata");
name = StringUtil.safeString(name);
if (!folder.exists()) {
folder.mkdirs();
}
UUID npcUUID = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
EssentialsUserConf npcConfig = new EssentialsUserConf(name, npcUUID, new File(folder, npcUUID.toString() + ".yml"));
npcConfig.load();
npcConfig.setProperty("npc", true);
npcConfig.setProperty("lastAccountName", name);
npcConfig.setProperty("money", ess.getSettings().getStartingBalance());
npcConfig.forceSave();
ess.getUserMap().trackUUID(npcUUID, name, false);
}
private static void deleteNPC(String name) {
User user = ess.getUser(name);
user.reset();
}
private static User getUserByName(String name) {
if (ess == null) {
throw new RuntimeException(noCallBeforeLoad);
}
if (name == null) {
throw new RuntimeException("Economy username cannot be null");
}
return ess.getUser(name);
}
/**
* Returns the balance of a user
*
* @param name Name of the user
*
* @return balance
*
* @throws UserDoesNotExistException
*/
@Deprecated
public static double getMoney(String name) throws UserDoesNotExistException {
BigDecimal exactAmount = getMoneyExact(name);
double amount = exactAmount.doubleValue();
if (new BigDecimal(amount).compareTo(exactAmount) > 0) {
// closest double is bigger than the exact amount
// -> get the previous double value to not return more money than the user has
amount = Math.nextAfter(amount, Double.NEGATIVE_INFINITY);
}
return amount;
}
public static BigDecimal getMoneyExact(String name) throws UserDoesNotExistException {
User user = getUserByName(name);
if (user == null) {
throw new UserDoesNotExistException(name);
}
return user.getMoney();
}
/**
* Sets the balance of a user
*
* @param name Name of the user
* @param balance The balance you want to set
*
* @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 setMoney(String name, double balance) throws UserDoesNotExistException, NoLoanPermittedException {
try {
setMoney(name, BigDecimal.valueOf(balance));
} catch (ArithmeticException e) {
logger.log(Level.WARNING, "Failed to set balance of " + name + " to " + balance + ": " + e.getMessage(), e);
}
}
public static void setMoney(String name, BigDecimal balance) throws UserDoesNotExistException, NoLoanPermittedException {
User user = getUserByName(name);
if (user == null) {
throw new UserDoesNotExistException(name);
}
if (balance.compareTo(ess.getSettings().getMinMoney()) < 0) {
throw new NoLoanPermittedException();
}
if (balance.signum() < 0 && !user.isAuthorized("essentials.eco.loan")) {
throw new NoLoanPermittedException();
}
try {
user.setMoney(balance);
} 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);
}
/**
* Adds money to the balance of a user
*
* @param name Name of the user
* @param amount The money you want to add
*
* @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 add(String name, double amount) throws UserDoesNotExistException, NoLoanPermittedException {
try {
add(name, BigDecimal.valueOf(amount));
} catch (ArithmeticException e) {
logger.log(Level.WARNING, "Failed to add " + amount + " to balance of " + name + ": " + e.getMessage(), e);
}
}
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);
}
/**
* Substracts money from the balance of a user
*
* @param name Name of the user
* @param amount The money you want to substract
*
* @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 subtract(String name, double amount) throws UserDoesNotExistException, NoLoanPermittedException {
try {
substract(name, BigDecimal.valueOf(amount));
} catch (ArithmeticException e) {
logger.log(Level.WARNING, "Failed to substract " + amount + " of balance of " + name + ": " + e.getMessage(), e);
}
}
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);
}
/**
* Divides the balance of a user by a value
*
* @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 exists
* @throws NoLoanPermittedException If the user is not allowed to have a negative balance
*/
@Deprecated
public static void divide(String name, double amount) throws UserDoesNotExistException, NoLoanPermittedException {
try {
divide(name, BigDecimal.valueOf(amount));
} catch (ArithmeticException e) {
logger.log(Level.WARNING, "Failed to divide balance of " + name + " by " + amount + ": " + e.getMessage(), e);
}
}
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);
}
/**
* Multiplies the balance of a user by a value
*
* @param name Name of the user
* @param amount The balance is multiplied by this value
*
* @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 multiply(String name, double amount) throws UserDoesNotExistException, NoLoanPermittedException {
try {
multiply(name, BigDecimal.valueOf(amount));
} catch (ArithmeticException e) {
logger.log(Level.WARNING, "Failed to multiply balance of " + name + " by " + amount + ": " + e.getMessage(), e);
}
}
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);
}
/**
* Resets the balance of a user to the starting balance
*
* @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
*/
public static void resetBalance(String name) throws UserDoesNotExistException, NoLoanPermittedException {
if (ess == null) {
throw new RuntimeException(noCallBeforeLoad);
}
setMoney(name, ess.getSettings().getStartingBalance());
Trade.log("API", "Reset", "API", name, new Trade(BigDecimal.ZERO, ess), null, null, null, ess);
}
/**
* @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 exists
*/
@Deprecated
public static boolean hasEnough(String name, double amount) throws UserDoesNotExistException {
try {
return hasEnough(name, BigDecimal.valueOf(amount));
} catch (ArithmeticException e) {
logger.log(Level.WARNING, "Failed to compare balance of " + name + " with " + amount + ": " + e.getMessage(), e);
return false;
}
}
public static boolean hasEnough(String name, BigDecimal amount) throws UserDoesNotExistException, ArithmeticException {
return amount.compareTo(getMoneyExact(name)) <= 0;
}
/**
* @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
*/
@Deprecated
public static boolean hasMore(String name, double amount) throws UserDoesNotExistException {
try {
return hasMore(name, BigDecimal.valueOf(amount));
} catch (ArithmeticException e) {
logger.log(Level.WARNING, "Failed to compare balance of " + name + " with " + amount + ": " + e.getMessage(), e);
return false;
}
}
public static boolean hasMore(String name, BigDecimal amount) throws UserDoesNotExistException, ArithmeticException {
return amount.compareTo(getMoneyExact(name)) < 0;
}
/**
* @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 exists
*/
@Deprecated
public static boolean hasLess(String name, double amount) throws UserDoesNotExistException {
try {
return hasLess(name, BigDecimal.valueOf(amount));
} catch (ArithmeticException e) {
logger.log(Level.WARNING, "Failed to compare balance of " + name + " with " + amount + ": " + e.getMessage(), e);
return false;
}
}
public static boolean hasLess(String name, BigDecimal amount) throws UserDoesNotExistException, ArithmeticException {
return amount.compareTo(getMoneyExact(name)) > 0;
}
/**
* Test if the user has a negative balance
*
* @param name Name of the user
*
* @return true, if the user has a negative balance
*
* @throws UserDoesNotExistException If a user by that name does not exists
*/
public static boolean isNegative(String name) throws UserDoesNotExistException {
return getMoneyExact(name).signum() < 0;
}
/**
* Formats the amount of money like all other Essentials functions. Example: $100000 or $12345.67
*
* @param amount The amount of money
*
* @return Formatted money
*/
@Deprecated
public static String format(double amount) {
try {
return format(BigDecimal.valueOf(amount));
} catch (NumberFormatException e) {
logger.log(Level.WARNING, "Failed to display " + amount + ": " + e.getMessage(), e);
return "NaN";
}
}
public static String format(BigDecimal amount) {
if (ess == null) {
throw new RuntimeException(noCallBeforeLoad);
}
return NumberUtil.displayCurrency(amount, ess);
}
/**
* Test if a player exists to avoid the UserDoesNotExistException
*
* @param name Name of the user
*
* @return true, if the user exists
*/
public static boolean playerExists(String name) {
return getUserByName(name) != null;
}
/**
* Test if a player is a npc
*
* @param name Name of the player
*
* @return true, if it's a npc
*
* @throws UserDoesNotExistException
*/
public static boolean isNPC(String name) throws UserDoesNotExistException {
User user = getUserByName(name);
if (user == null) {
throw new UserDoesNotExistException(name);
}
return user.isNPC();
}
/**
* Creates dummy files for a npc, if there is no player yet with that name.
*
* @param name Name of the player
*
* @return true, if a new npc was created
*/
public static boolean createNPC(String name) {
User user = getUserByName(name);
if (user == null) {
createNPCFile(name);
return true;
}
return false;
}
/**
* Deletes a user, if it is marked as npc.
*
* @param name Name of the player
*
* @throws UserDoesNotExistException
*/
public static void removeNPC(String name) throws UserDoesNotExistException {
User user = getUserByName(name);
if (user == null) {
throw new UserDoesNotExistException(name);
}
deleteNPC(name);
}
}
@@ -1,13 +0,0 @@
package com.earth2me.essentials.api;
import java.util.Locale;
public interface II18n {
/**
* Gets the current locale setting
*
* @return the current locale, if not set it will return the default locale
*/
Locale getCurrentLocale();
}
@@ -1,6 +0,0 @@
package com.earth2me.essentials.api;
public interface IReload {
void onReload();
}
@@ -1,10 +0,0 @@
package com.earth2me.essentials.api;
import static com.earth2me.essentials.I18n.tl;
public class UserDoesNotExistException extends Exception {
public UserDoesNotExistException(String name) {
super(tl("userDoesNotExist", name));
}
}
@@ -1,103 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandafk extends EssentialsCommand {
public Commandafk() {
super("afk");
}
@Override
public void run(Server server, User user, String commandLabel, String[] args) throws Exception {
if (args.length > 0 && user.isAuthorized("essentials.afk.others")) {
User afkUser = user; // if no player found, but message specified, set command executor to target user
String message;
try {
afkUser = getPlayer(server, user, args, 0);
message = args.length > 1 ? getFinalArg(args, 1) : null;
} catch (PlayerNotFoundException e) {
// If only one arg is passed, assume the command executor is targeting another player.
if (args.length == 1) {
throw e;
}
message = getFinalArg(args, 0);
}
toggleAfk(user, afkUser, message);
} else {
String message = args.length > 0 ? getFinalArg(args, 0) : null;
toggleAfk(user, user, message);
}
}
@Override
public void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
if (args.length > 0) {
User afkUser = getPlayer(server, args, 0, true, false);
String message = args.length > 1 ? getFinalArg(args, 1) : null;
toggleAfk(null, afkUser, message);
} else {
throw new NotEnoughArgumentsException();
}
}
private void toggleAfk(User sender, User user, String message) throws Exception {
if (message != null && sender != null) {
if (sender.isMuted()) {
throw new Exception(tl("voiceSilenced"));
}
if (!sender.isAuthorized("essentials.afk.message")) {
throw new Exception(tl("noPermToAFKMessage"));
}
}
user.setDisplayNick();
String msg = "";
if (!user.toggleAfk()) {
//user.sendMessage(_("markedAsNotAway"));
if (!user.isHidden()) {
msg = tl("userIsNotAway", user.getDisplayName());
}
user.updateActivity(false);
} else {
//user.sendMessage(_("markedAsAway"));
if (!user.isHidden()) {
if (message != null) {
msg = tl("userIsAwayWithMessage", user.getDisplayName(), message);
} else {
msg = tl("userIsAway", user.getDisplayName());
}
}
user.setAfkMessage(message);
}
if (!msg.isEmpty()) {
ess.broadcastMessage(user, msg);
}
user.setDisplayNick(); // Set this again after toggling
}
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
if (args.length == 1 && user.isAuthorized("essentials.afk.others")) {
return getPlayers(server, user);
} else {
return Collections.emptyList();
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
if (args.length == 1) {
return getPlayers(server, sender);
} else {
return Collections.emptyList();
}
}
}
@@ -1,36 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import static com.earth2me.essentials.I18n.tl;
public class Commandback extends EssentialsCommand {
public Commandback() {
super("back");
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (user.getLastLocation() == null) {
throw new Exception(tl("noLocationFound"));
}
String lastWorldName = user.getLastLocation().getWorld().getName();
if (user.getWorld() != user.getLastLocation().getWorld() && ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + lastWorldName)) {
throw new Exception(tl("noPerm", "essentials.worlds." + lastWorldName));
}
if (!user.isAuthorized("essentials.back.into." + lastWorldName)) {
throw new Exception(tl("noPerm", "essentials.back.into." + lastWorldName));
}
final Trade charge = new Trade(this.getName(), ess);
charge.isAffordableFor(user);
user.getTeleport().back(charge);
throw new NoChargeException();
}
}
@@ -1,178 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.textreader.TextPager;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import static com.earth2me.essentials.I18n.tl;
public class Commandbalancetop extends EssentialsCommand {
public Commandbalancetop() {
super("balancetop");
}
private static final int CACHETIME = 2 * 60 * 1000;
public static final int MINUSERS = 50;
private static final SimpleTextInput cache = new SimpleTextInput();
private static long cacheage = 0;
private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
@Override
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
int page = 0;
boolean force = false;
if (args.length > 0) {
try {
page = Integer.parseInt(args[0]);
} catch (NumberFormatException ex) {
if (args[0].equalsIgnoreCase("force") && (!sender.isPlayer() || ess.getUser(sender.getPlayer()).isAuthorized("essentials.balancetop.force"))) {
force = true;
}
}
}
if (!force && lock.readLock().tryLock()) {
try {
if (cacheage > System.currentTimeMillis() - CACHETIME) {
outputCache(sender, commandLabel, page);
return;
}
if (ess.getUserMap().getUniqueUsers() > MINUSERS) {
sender.sendMessage(tl("orderBalances", ess.getUserMap().getUniqueUsers()));
}
} 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));
}
}
private static void outputCache(final CommandSource sender, String command, int page) {
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(cacheage);
final DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
sender.sendMessage(tl("balanceTop", format.format(cal.getTime())));
new TextPager(cache).showPage(Integer.toString(page), null, "balancetop", sender);
}
private class Calculator implements Runnable {
private final transient Viewer viewer;
private final boolean force;
public Calculator(final Viewer viewer, final boolean force) {
this.viewer = viewer;
this.force = force;
}
@Override
public void run() {
lock.writeLock().lock();
try {
if (force || cacheage <= System.currentTimeMillis() - CACHETIME) {
cache.getLines().clear();
final Map<String, BigDecimal> balances = new HashMap<String, BigDecimal>();
BigDecimal totalMoney = BigDecimal.ZERO;
if (ess.getSettings().isEcoDisabled()) {
if (ess.getSettings().isDebug()) {
ess.getLogger().info("Internal economy functions disabled, aborting baltop.");
}
} else {
for (UUID u : ess.getUserMap().getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
if (user != null) {
if (!ess.getSettings().isNpcsInBalanceRanking() && user.isNPC()) {
// Don't list NPCs in output
continue;
}
final BigDecimal userMoney = user.getMoney();
user.updateMoneyCache(userMoney);
totalMoney = totalMoney.add(userMoney);
final String name = user.isHidden() ? user.getName() : user.getDisplayName();
balances.put(name, userMoney);
}
}
}
final List<Map.Entry<String, BigDecimal>> sortedEntries = new ArrayList<Map.Entry<String, BigDecimal>>(balances.entrySet());
Collections.sort(sortedEntries, new Comparator<Map.Entry<String, BigDecimal>>() {
@Override
public int compare(final Entry<String, BigDecimal> entry1, final Entry<String, BigDecimal> entry2) {
return entry2.getValue().compareTo(entry1.getValue());
}
});
cache.getLines().add(tl("serverTotal", NumberUtil.displayCurrency(totalMoney, ess)));
int pos = 1;
for (Map.Entry<String, BigDecimal> entry : sortedEntries) {
cache.getLines().add(pos + ". " + entry.getKey() + ", " + NumberUtil.displayCurrency(entry.getValue(), ess));
pos++;
}
cacheage = System.currentTimeMillis();
}
} finally {
lock.writeLock().unlock();
}
ess.runTaskAsynchronously(viewer);
}
}
private class Viewer implements Runnable {
private final transient CommandSource sender;
private final transient int page;
private final transient boolean force;
private final transient String commandLabel;
public Viewer(final CommandSource sender, final String commandLabel, final int page, final boolean force) {
this.sender = sender;
this.page = page;
this.force = force;
this.commandLabel = commandLabel;
}
@Override
public void run() {
lock.readLock().lock();
try {
if (!force && cacheage > System.currentTimeMillis() - CACHETIME) {
outputCache(sender, commandLabel, page);
return;
}
} finally {
lock.readLock().unlock();
}
ess.runTaskAsynchronously(new Calculator(new Viewer(sender, commandLabel, page, false), force));
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
if (args.length == 1) {
List<String> options = Lists.newArrayList("1");
if (!sender.isPlayer() || ess.getUser(sender.getPlayer()).isAuthorized("essentials.balancetop.force")) {
options.add("force");
}
return options;
} else {
return Collections.emptyList();
}
}
}
@@ -1,131 +0,0 @@
package com.earth2me.essentials.commands;
import com.google.common.base.Charsets;
import com.google.common.io.CharStreams;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.DateUtil;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.MemoryConfiguration;
import org.bukkit.configuration.file.YamlConstructor;
import org.bukkit.configuration.file.YamlRepresenter;
import org.bukkit.inventory.ItemStack;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.representer.Representer;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static com.earth2me.essentials.I18n.tl;
public class Commandcreatekit extends EssentialsCommand {
private static final String PASTE_URL = "https://hastebin.com/";
private static final String PASTE_UPLOAD_URL = PASTE_URL + "documents";
private static final Gson GSON = new Gson();
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
private final DumperOptions yamlOptions = new DumperOptions();
private final Representer yamlRepresenter = new YamlRepresenter();
private final YamlConstructor yamlConstructor = new YamlConstructor();
public Commandcreatekit() {
super("createkit");
yamlOptions.setDefaultFlowStyle(FlowStyle.BLOCK);
yamlRepresenter.setDefaultFlowStyle(FlowStyle.BLOCK);
}
// /createkit <name> <delay>
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length != 2) {
throw new NotEnoughArgumentsException();
}
// Command handler will auto fail if this fails.
long delay = Long.valueOf(args[1]);
String kitname = args[0];
ItemStack[] items = user.getBase().getInventory().getContents();
List<String> list = new ArrayList<>();
for (ItemStack is : items) {
if (is != null && is.getType() != null && is.getType() != Material.AIR) {
String serialized = ess.getItemDb().serialize(is);
list.add(serialized);
}
}
// Some users might want to directly write to config knowing the consequences. *shrug*
if (!ess.getSettings().isPastebinCreateKit()) {
ess.getKits().addKit(kitname, list, delay);
user.sendMessage(tl("createdKit", kitname, list.size(), delay));
} else {
ConfigurationSection config = new MemoryConfiguration();
config.set("kits." + kitname + ".delay", delay);
config.set("kits." + kitname + ".items", list);
final Yaml yaml = new Yaml(yamlConstructor, yamlRepresenter, yamlOptions);
String fileContents = "# Copy the kit code below into the kits section in your config.yml file\n";
fileContents += yaml.dump(config.getValues(false));
uploadPaste(user.getSource(), kitname, delay, fileContents);
}
}
private void uploadPaste(final CommandSource sender, final String kitName, final long delay, final String contents) {
executorService.submit(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();
}
}
});
}
}
@@ -1,36 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import org.bukkit.Server;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commanddelwarp extends EssentialsCommand {
public Commanddelwarp() {
super("delwarp");
}
@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();
}
ess.getWarps().removeWarp(args[0]);
sender.sendMessage(tl("deleteWarp", args[0]));
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
return new ArrayList<>(ess.getWarps().getList());
} else {
return Collections.emptyList();
}
}
}
@@ -1,125 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.ChargeException;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import net.ess3.api.MaxMoneyException;
import org.bukkit.Server;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commandeco extends EssentialsLoopCommand {
Commandeco.EcoCommands cmd;
BigDecimal amount;
public Commandeco() {
super("eco");
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 2) {
throw new NotEnoughArgumentsException();
}
BigDecimal startingBalance = ess.getSettings().getStartingBalance();
try {
cmd = Commandeco.EcoCommands.valueOf(args[0].toUpperCase(Locale.ENGLISH));
amount = (cmd == Commandeco.EcoCommands.RESET) ? startingBalance : 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)));
}
}
}
@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);
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);
} else if (sender == null) {
try {
player.setMoney(minBalance);
} catch (MaxMoneyException ex) {
// Take shouldn't be able to throw a max money exception
}
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);
player.sendMessage(tl("setBal", NumberUtil.displayCurrency(player.getMoney(), ess)));
if (sender != null) {
sender.sendMessage(tl("setBalOthers", player.getDisplayName(), NumberUtil.displayCurrency(player.getMoney(), ess)));
}
}
private enum EcoCommands {
GIVE, TAKE, SET, RESET
}
@Override
protected List<String> getTabCompleteOptions(Server server, final CommandSource sender, String commandLabel, String[] args) {
if (args.length == 1) {
List<String> options = Lists.newArrayList();
for (EcoCommands command : EcoCommands.values()) {
options.add(command.name().toLowerCase(Locale.ENGLISH));
}
return options;
} else if (args.length == 2) {
return getPlayers(server, sender);
} else if (args.length == 3 && !args[0].equalsIgnoreCase(EcoCommands.RESET.name())) {
if (args[0].equalsIgnoreCase(EcoCommands.SET.name())) {
return Lists.newArrayList("0", ess.getSettings().getStartingBalance().toString());
} else {
return Lists.newArrayList("1", "10", "100", "1000");
}
} else {
return Collections.emptyList();
}
}
}
@@ -1,415 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.EssentialsUpgrade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.UserMap;
import com.earth2me.essentials.utils.*;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import java.util.*;
import static com.earth2me.essentials.I18n.tl;
// This command has 4 undocumented behaviours #EasterEgg
public class Commandessentials extends EssentialsCommand {
private final Sound NOTE_HARP = EnumUtil.valueOf(Sound.class, "BLOCK_NOTE_HARP", "NOTE_PIANO");
public Commandessentials() {
super("essentials");
}
private transient int taskid;
private final transient Map<Player, Block> noteBlocks = new HashMap<Player, Block>();
private final List<String> versionPlugins = Arrays.asList(
"Vault",
"LuckPerms",
"PermissionsEx",
"GroupManager"
);
private final List<String> officialPlugins = Arrays.asList(
"EssentialsAntiBuild",
"EssentialsChat",
"EssentialsGeoIP",
"EssentialsProtect",
"EssentialsSpawn",
"EssentialsXMPP"
);
private final List<String> warnPlugins = Arrays.asList(
"PermissionsEx",
"GroupManager"
);
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length == 0) {
run_disabled(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("debug")) {
run_debug(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("nya")) {
run_nya(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("moo")) {
run_moo(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("reset")) {
run_reset(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("cleanup")) {
run_cleanup(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("uuidconvert")) {
run_uuidconvert(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("uuidtest")) {
run_uuidtest(server, sender, commandLabel, args);
} else if (args[0].equalsIgnoreCase("version")) {
run_version(server, sender, commandLabel, args);
} else {
run_reload(server, sender, commandLabel, args);
}
}
//If you do not supply an argument this command will list 'overridden' commands.
private void run_disabled(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
sender.sendMessage("/<command> <reload/debug>");
final StringBuilder disabledCommands = new StringBuilder();
for (Map.Entry<String, String> entry : ess.getAlternativeCommandsHandler().disabledCommands().entrySet()) {
if (disabledCommands.length() > 0) {
disabledCommands.append(", ");
}
disabledCommands.append(entry.getKey()).append(" => ").append(entry.getValue());
}
if (disabledCommands.length() > 0) {
sender.sendMessage(tl("blockList"));
sender.sendMessage(disabledCommands.toString());
}
}
private void run_reset(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 2) {
throw new Exception("/<command> reset <player>");
}
final User user = getPlayer(server, args, 1, true, true);
user.reset();
sender.sendMessage("Reset Essentials userdata for player: " + user.getDisplayName());
}
private void run_debug(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
ess.getSettings().setDebug(!ess.getSettings().isDebug());
sender.sendMessage("Essentials " + ess.getDescription().getVersion() + " debug mode " + (ess.getSettings().isDebug() ? "enabled" : "disabled"));
}
private void run_reload(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
ess.reload();
sender.sendMessage(tl("essentialsReload", ess.getDescription().getVersion()));
}
private void run_nya(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
final Map<String, Float> noteMap = new HashMap<String, Float>();
noteMap.put("1F#", 0.5f);
noteMap.put("1G", 0.53f);
noteMap.put("1G#", 0.56f);
noteMap.put("1A", 0.6f);
noteMap.put("1A#", 0.63f);
noteMap.put("1B", 0.67f);
noteMap.put("1C", 0.7f);
noteMap.put("1C#", 0.76f);
noteMap.put("1D", 0.8f);
noteMap.put("1D#", 0.84f);
noteMap.put("1E", 0.9f);
noteMap.put("1F", 0.94f);
noteMap.put("2F#", 1.0f);
noteMap.put("2G", 1.06f);
noteMap.put("2G#", 1.12f);
noteMap.put("2A", 1.18f);
noteMap.put("2A#", 1.26f);
noteMap.put("2B", 1.34f);
noteMap.put("2C", 1.42f);
noteMap.put("2C#", 1.5f);
noteMap.put("2D", 1.6f);
noteMap.put("2D#", 1.68f);
noteMap.put("2E", 1.78f);
noteMap.put("2F", 1.88f);
final String tuneStr = "1D#,1E,2F#,,2A#,1E,1D#,1E,2F#,2B,2D#,2E,2D#,2A#,2B,,2F#,,1D#,1E,2F#,2B,2C#,2A#,2B,2C#,2E,2D#,2E,2C#,,2F#,,2G#,,1D,1D#,,1C#,1D,1C#,1B,,1B,,1C#,,1D,,1D,1C#,1B,1C#,1D#,2F#,2G#,1D#,2F#,1C#,1D#,1B,1C#,1B,1D#,,2F#,,2G#,1D#,2F#,1C#,1D#,1B,1D,1D#,1D,1C#,1B,1C#,1D,,1B,1C#,1D#,2F#,1C#,1D,1C#,1B,1C#,,1B,,1C#,,2F#,,2G#,,1D,1D#,,1C#,1D,1C#,1B,,1B,,1C#,,1D,,1D,1C#,1B,1C#,1D#,2F#,2G#,1D#,2F#,1C#,1D#,1B,1C#,1B,1D#,,2F#,,2G#,1D#,2F#,1C#,1D#,1B,1D,1D#,1D,1C#,1B,1C#,1D,,1B,1C#,1D#,2F#,1C#,1D,1C#,1B,1C#,,1B,,1B,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1B,,";
final String[] tune = tuneStr.split(",");
taskid = ess.scheduleSyncRepeatingTask(new Runnable() {
int i = 0;
@Override
public void run() {
final String note = tune[i];
i++;
if (i >= tune.length) {
Commandessentials.this.stopTune();
}
if (note == null || note.isEmpty()) {
return;
}
for (Player onlinePlayer : ess.getOnlinePlayers()) {
onlinePlayer.playSound(onlinePlayer.getLocation(), NOTE_HARP, 1, noteMap.get(note));
}
}
}, 20, 2);
}
private void stopTune() {
ess.getScheduler().cancelTask(taskid);
for (Block block : noteBlocks.values()) {
if (block.getType() == Material.NOTE_BLOCK) {
block.setType(Material.AIR);
}
}
noteBlocks.clear();
}
private final String[] consoleMoo = new String[]{" (__)", " (oo)", " /------\\/", " / | ||", " * /\\---/\\", " ~~ ~~", "....\"Have you mooed today?\"..."};
private final String[] playerMoo = new String[]{" (__)", " (oo)", " /------\\/", " / | | |", " * /\\---/\\", " ~~ ~~", "....\"Have you mooed today?\"..."};
private void run_moo(final Server server, final CommandSource sender, final String command, final String args[]) {
Sound moo = EnumUtil.valueOf(Sound.class, "COW_IDLE", "ENTITY_COW_MILK");
if (args.length == 2 && args[1].equals("moo")) {
for (String s : consoleMoo) {
logger.info(s);
}
for (Player player : ess.getOnlinePlayers()) {
player.sendMessage(playerMoo);
player.playSound(player.getLocation(), moo, 1, 1.0f);
}
} else {
if (sender.isPlayer()) {
sender.getSender().sendMessage(playerMoo);
final Player player = sender.getPlayer();
player.playSound(player.getLocation(), moo, 1, 1.0f);
} else {
sender.getSender().sendMessage(consoleMoo);
}
}
}
private void run_cleanup(final Server server, final CommandSource sender, final String command, final String args[]) throws Exception {
if (args.length < 2 || !NumberUtil.isInt(args[1])) {
sender.sendMessage("This sub-command will delete users who havent logged in in the last <days> days.");
sender.sendMessage("Optional parameters define the minium amount required to prevent deletion.");
sender.sendMessage("Unless you define larger default values, this command wil ignore people who have more than 0 money/homes.");
throw new Exception("/<command> cleanup <days> [money] [homes]");
}
sender.sendMessage(tl("cleaning"));
final long daysArg = Long.parseLong(args[1]);
final double moneyArg = args.length >= 3 ? FloatUtil.parseDouble(args[2].replaceAll("[^0-9\\.]", "")) : 0;
final int homesArg = args.length >= 4 && NumberUtil.isInt(args[3]) ? Integer.parseInt(args[3]) : 0;
final UserMap userMap = ess.getUserMap();
ess.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
Long currTime = System.currentTimeMillis();
for (UUID u : userMap.getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
if (user == null) {
continue;
}
long lastLog = user.getLastLogout();
if (lastLog == 0) {
lastLog = user.getLastLogin();
}
if (lastLog == 0) {
user.setLastLogin(currTime);
}
if (user.isNPC()) {
continue;
}
long timeDiff = currTime - lastLog;
long milliDays = daysArg * 24L * 60L * 60L * 1000L;
int homeCount = user.getHomes().size();
double moneyCount = user.getMoney().doubleValue();
if ((lastLog == 0) || (timeDiff < milliDays) || (homeCount > homesArg) || (moneyCount > moneyArg)) {
continue;
}
if (ess.getSettings().isDebug()) {
ess.getLogger().info("Deleting user: " + user.getName() + " Money: " + moneyCount + " Homes: " + homeCount + " Last seen: " + DateUtil.formatDateDiff(lastLog));
}
user.reset();
}
sender.sendMessage(tl("cleaned"));
}
});
}
private void run_uuidconvert(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
sender.sendMessage("Starting Essentials UUID userdata conversion, this may lag the server.");
Boolean ignoreUFCache = (args.length > 2 && args[1].toLowerCase(Locale.ENGLISH).contains("ignore"));
EssentialsUpgrade.uuidFileConvert(ess, ignoreUFCache);
sender.sendMessage("UUID conversion complete, check your server log for more information.");
}
private void run_uuidtest(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 2) {
throw new Exception("/<command> uuidtest <name>");
}
String name = args[1];
sender.sendMessage("Looking up UUID for " + name);
UUID onlineUUID = null;
for (Player player : ess.getOnlinePlayers()) {
if (player.getName().equalsIgnoreCase(name)) {
onlineUUID = player.getUniqueId();
break;
}
}
UUID essUUID = ess.getUserMap().getUser(name).getConfigUUID();
org.bukkit.OfflinePlayer player = ess.getServer().getOfflinePlayer(name);
UUID bukkituuid = player.getUniqueId();
sender.sendMessage("Bukkit Lookup: " + bukkituuid.toString());
if (onlineUUID != null && onlineUUID != bukkituuid) {
sender.sendMessage("Online player: " + onlineUUID.toString());
}
if (essUUID != null && essUUID != bukkituuid) {
sender.sendMessage("Essentials config: " + essUUID.toString());
}
UUID npcuuid = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
sender.sendMessage("NPC UUID: " + npcuuid.toString());
UUID offlineuuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8));
sender.sendMessage("Offline Mode UUID: " + offlineuuid.toString());
}
private void run_version(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.version")) return;
boolean isMismatched = false;
boolean isVaultInstalled = false;
boolean isUnsupported = false;
final boolean isServerSupported = VersionUtil.isServerSupported();
final PluginManager pm = server.getPluginManager();
final String essVer = pm.getPlugin("Essentials").getDescription().getVersion();
sender.sendMessage(tl(isServerSupported ? "versionOutputFine" : "versionOutputWarn", "Server", server.getBukkitVersion() + " " + server.getVersion()));
sender.sendMessage(tl("versionOutputFine", "EssentialsX", essVer));
for (Plugin plugin : pm.getPlugins()) {
final PluginDescriptionFile desc = plugin.getDescription();
String name = desc.getName();
String version = desc.getVersion();
if (name.startsWith("Essentials") && !name.equalsIgnoreCase("Essentials")) {
if (officialPlugins.contains(name)) {
name = name.replace("Essentials", "EssentialsX");
if (!version.equalsIgnoreCase(essVer)) {
isMismatched = true;
sender.sendMessage(tl("versionOutputWarn", name, version));
} else {
sender.sendMessage(tl("versionOutputFine", name, version));
}
} else {
sender.sendMessage(tl("versionOutputUnsupported", name, version));
isUnsupported = true;
}
}
if (versionPlugins.contains(name)) {
if (warnPlugins.contains(name)) {
sender.sendMessage(tl("versionOutputUnsupported", name, version));
isUnsupported = true;
} else {
sender.sendMessage(tl("versionOutputFine", name, version));
}
}
if (name.equals("Vault")) isVaultInstalled = true;
}
if (isMismatched) {
sender.sendMessage(tl("versionMismatchAll"));
}
if (!isVaultInstalled) {
sender.sendMessage(tl("versionOutputVaultMissing"));
}
if (isUnsupported) {
sender.sendMessage(tl("versionOutputUnsupportedPlugins"));
}
if (!VersionUtil.isServerSupported()) {
sender.sendMessage(tl("serverUnsupported"));
}
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
List<String> options = Lists.newArrayList();
options.add("reload");
options.add("debug");
//options.add("nya");
//options.add("moo");
options.add("reset");
options.add("cleanup");
//options.add("uuidconvert");
//options.add("uuidtest");
options.add("version");
return options;
} else if (args[0].equalsIgnoreCase("debug")) {
// No args
} else if (args[0].equalsIgnoreCase("nya")) {
// No args
} else if (args[0].equalsIgnoreCase("moo")) {
if (args.length == 2) {
return Lists.newArrayList("moo");
}
} else if (args[0].equalsIgnoreCase("reset")) {
if (args.length == 2) {
return getPlayers(server, sender);
}
} else if (args[0].equalsIgnoreCase("cleanup")) {
if (args.length == 2) {
return COMMON_DURATIONS;
} else if (args.length == 3 || args.length == 4) {
return Lists.newArrayList("-1", "0");
}
} else if (args[0].equalsIgnoreCase("uuidconvert")) {
if (args.length == 2) {
return Lists.newArrayList("ignoreUFCache");
}
} else if (args[0].equalsIgnoreCase("uuidtest")) {
if (args.length == 2) {
return getPlayers(server, sender);
}
} else if (args[0].equalsIgnoreCase("version")) {
// No args
} else {
// No args
}
return Collections.emptyList();
}
}
@@ -1,205 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.SetExpFix;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commandexp extends EssentialsCommand {
public Commandexp() {
super("exp");
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length == 0) {
showExp(user.getSource(), user);
} else if (args.length > 1 && args[0].equalsIgnoreCase("set") && user.isAuthorized("essentials.exp.set")) {
if (args.length == 3 && user.isAuthorized("essentials.exp.set.others")) {
expMatch(server, user.getSource(), args[1], args[2], false);
} else {
setExp(user.getSource(), user, args[1], false);
}
} else if (args.length > 1 && args[0].equalsIgnoreCase("give") && user.isAuthorized("essentials.exp.give")) {
if (args.length == 3 && user.isAuthorized("essentials.exp.give.others")) {
expMatch(server, user.getSource(), args[1], args[2], true);
} else {
setExp(user.getSource(), user, args[1], true);
}
} else if (args[0].equalsIgnoreCase("show")) {
if (args.length >= 2 && user.isAuthorized("essentials.exp.others")) {
String match = args[1].trim();
showMatch(server, user.getSource(), match);
} else {
showExp(user.getSource(), user);
}
} else {
if (args.length >= 1 && NumberUtil.isInt(args[0].toLowerCase(Locale.ENGLISH).replace("l", "")) && user.isAuthorized("essentials.exp.give")) {
if (args.length >= 2 && user.isAuthorized("essentials.exp.give.others")) {
expMatch(server, user.getSource(), args[1], args[0], true);
} else {
setExp(user.getSource(), user, args[0], true);
}
} else if (args.length >= 1 && user.isAuthorized("essentials.exp.others")) {
String match = args[0].trim();
showMatch(server, user.getSource(), match);
} else {
showExp(user.getSource(), user);
}
}
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
throw new NotEnoughArgumentsException();
} else if (args.length > 2 && args[0].equalsIgnoreCase("set")) {
expMatch(server, sender, args[1], args[2], false);
} else if (args.length > 2 && args[0].equalsIgnoreCase("give")) {
expMatch(server, sender, args[1], args[2], true);
} else {
String match = args[0].trim();
if (args.length >= 2 && NumberUtil.isInt(args[0].toLowerCase(Locale.ENGLISH).replace("l", ""))) {
match = args[1].trim();
expMatch(server, sender, match, args[0], true);
} else if (args.length == 1) {
match = args[0].trim();
}
showMatch(server, sender, match);
}
}
private void showMatch(final Server server, final CommandSource sender, final String match) throws PlayerNotFoundException {
boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished();
boolean foundUser = false;
final List<Player> matchedPlayers = server.matchPlayer(match);
for (Player matchPlayer : matchedPlayers) {
final User player = ess.getUser(matchPlayer);
if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) {
continue;
}
foundUser = true;
showExp(sender, player);
}
if (!foundUser) {
throw new PlayerNotFoundException();
}
}
private void expMatch(final Server server, final CommandSource sender, final String match, String amount, final boolean give) throws NotEnoughArgumentsException, PlayerNotFoundException {
boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished();
boolean foundUser = false;
final List<Player> matchedPlayers = server.matchPlayer(match);
for (Player matchPlayer : matchedPlayers) {
final User player = ess.getUser(matchPlayer);
if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) {
continue;
}
foundUser = true;
setExp(sender, player, amount, give);
}
if (!foundUser) {
throw new PlayerNotFoundException();
}
}
private void showExp(final CommandSource sender, final User target) {
sender.sendMessage(tl("exp", target.getDisplayName(), SetExpFix.getTotalExperience(target.getBase()), target.getBase().getLevel(), SetExpFix.getExpUntilNextLevel(target.getBase())));
}
//TODO: Limit who can give negative exp?
private void setExp(final CommandSource sender, final User target, String strAmount, final boolean give) throws NotEnoughArgumentsException {
long amount;
strAmount = strAmount.toLowerCase(Locale.ENGLISH);
if (strAmount.contains("l")) {
strAmount = strAmount.replaceAll("l", "");
int neededLevel = Integer.parseInt(strAmount);
if (give) {
neededLevel += target.getBase().getLevel();
}
amount = (long) SetExpFix.getExpToLevel(neededLevel);
SetExpFix.setTotalExperience(target.getBase(), 0);
} else {
amount = Long.parseLong(strAmount);
if (amount > Integer.MAX_VALUE || amount < Integer.MIN_VALUE) {
throw new NotEnoughArgumentsException();
}
}
if (give) {
amount += SetExpFix.getTotalExperience(target.getBase());
}
if (amount > Integer.MAX_VALUE) {
amount = (long) Integer.MAX_VALUE;
}
if (amount < 0l) {
amount = 0l;
}
SetExpFix.setTotalExperience(target.getBase(), (int) amount);
sender.sendMessage(tl("expSet", target.getDisplayName(), amount));
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
if (args.length == 1) {
List<String> options = Lists.newArrayList("show");
if (user.isAuthorized("essentials.exp.set")) {
options.add("set");
}
if (user.isAuthorized("essentials.exp.give")) {
options.add("give");
}
return options;
} else if (args.length == 2) {
if ((args[0].equalsIgnoreCase("set") && user.isAuthorized("essentials.exp.set")) || (args[0].equalsIgnoreCase("give") && user.isAuthorized("essentials.exp.give"))) {
String levellessArg = args[1].toLowerCase(Locale.ENGLISH).replace("l", "");
if (NumberUtil.isInt(levellessArg)) {
return Lists.newArrayList(levellessArg, args[1] + "l");
} else {
return Collections.emptyList();
}
} else if (args[0].equalsIgnoreCase("show") && user.isAuthorized("essentials.exp.others")) {
return getPlayers(server, user);
} else {
return Collections.emptyList();
}
} else if (args.length == 3 && (args[0].equalsIgnoreCase("set") && user.isAuthorized("essentials.exp.set.others")) || (args[0].equalsIgnoreCase("give") && user.isAuthorized("essentials.exp.give.others"))) {
return getPlayers(server, user);
} else {
return Collections.emptyList();
}
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
// TODO: This seems somewhat buggy, both setting and showing - right now, ignoring that
return Lists.newArrayList("set", "give", "show");
} else if (args.length == 2) {
if (args[0].equalsIgnoreCase("set") || args[0].equalsIgnoreCase("give")) {
String levellessArg = args[1].toLowerCase(Locale.ENGLISH).replace("l", "");
if (NumberUtil.isInt(levellessArg)) {
return Lists.newArrayList(levellessArg, args[1] + "l");
} else {
return Collections.emptyList();
}
} else { // even without 'show'
return getPlayers(server, sender);
}
} else if (args.length == 3 && (args[0].equalsIgnoreCase("set") || args[0].equalsIgnoreCase("give"))) {
return getPlayers(server, sender);
} else {
return Collections.emptyList();
}
}
}
@@ -1,53 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import org.bukkit.entity.*;
import org.bukkit.util.Vector;
import java.util.Collections;
import java.util.List;
public class Commandfireball extends EssentialsCommand {
public Commandfireball() {
super("fireball");
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
Class<? extends Entity> type = Fireball.class;
Projectile projectile;
int speed = 2;
if (args.length > 0) {
if (args[0].equalsIgnoreCase("small")) {
type = SmallFireball.class;
} else if (args[0].equalsIgnoreCase("arrow")) {
type = Arrow.class;
} else if (args[0].equalsIgnoreCase("skull")) {
type = WitherSkull.class;
} else if (args[0].equalsIgnoreCase("egg")) {
type = Egg.class;
} else if (args[0].equalsIgnoreCase("snowball")) {
type = Snowball.class;
} else if (args[0].equalsIgnoreCase("expbottle")) {
type = ThrownExpBottle.class;
} else if (args[0].equalsIgnoreCase("large")) {
type = LargeFireball.class;
}
}
final Vector direction = user.getBase().getEyeLocation().getDirection().multiply(speed);
projectile = (Projectile) user.getWorld().spawn(user.getBase().getEyeLocation().add(direction.getX(), direction.getY(), direction.getZ()), type);
projectile.setShooter(user.getBase());
projectile.setVelocity(direction);
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
if (args.length == 1) {
return Lists.newArrayList("small", "arrow", "skull", "egg", "snowball", "expbottle", "large");
} else {
return Collections.emptyList();
}
}
}
@@ -1,178 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.DyeColor;
import org.bukkit.FireworkEffect;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Firework;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.FireworkMeta;
import org.bukkit.util.Vector;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
//This command has quite a complicated syntax, in theory it has 4 seperate syntaxes which are all variable:
//
//1: /firework clear - This clears all of the effects on a firework stack
//
//2: /firework power <int> - This changes the base power of a firework
//
//3: /firework fire - This 'fires' a copy of the firework held.
//3: /firework fire <int> - This 'fires' a number of copies of the firework held.
//3: /firework fire <other> - This 'fires' a copy of the firework held, in the direction you are looking, #easteregg
//
//4: /firework [meta] - This will add an effect to the firework stack held
//4: /firework color:<color> - The minimum you need to set an effect is 'color'
//4: Full Syntax: color:<color[,color,..]> [fade:<color[,color,..]>] [shape:<shape>] [effect:<effect[,effect]>]
//4: Possible Shapes: star, ball, large, creeper, burst
//4: Possible Effects trail, twinkle
public class Commandfirework extends EssentialsCommand {
public Commandfirework() {
super("firework");
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final ItemStack stack = user.getBase().getInventory().getItemInMainHand();
if (MaterialUtil.isFirework(stack.getType())) {
if (args.length > 0) {
if (args[0].equalsIgnoreCase("clear")) {
FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
fmeta.clearEffects();
stack.setItemMeta(fmeta);
user.sendMessage(tl("fireworkEffectsCleared"));
} else if (args.length > 1 && (args[0].equalsIgnoreCase("power") || (args[0].equalsIgnoreCase("p")))) {
FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
try {
int power = Integer.parseInt(args[1]);
fmeta.setPower(power > 3 ? 4 : power);
} catch (NumberFormatException e) {
throw new Exception(tl("invalidFireworkFormat", args[1], args[0]));
}
stack.setItemMeta(fmeta);
} else if ((args[0].equalsIgnoreCase("fire") || (args[0].equalsIgnoreCase("f"))) && user.isAuthorized("essentials.firework.fire")) {
int amount = 1;
boolean direction = false;
if (args.length > 1) {
if (NumberUtil.isInt(args[1])) {
final int serverLimit = ess.getSettings().getSpawnMobLimit();
amount = Integer.parseInt(args[1]);
if (amount > serverLimit) {
amount = serverLimit;
user.sendMessage(tl("mobSpawnLimit"));
}
} else {
direction = true;
}
}
for (int i = 0; i < amount; i++) {
Firework firework = (Firework) user.getWorld().spawnEntity(user.getLocation(), EntityType.FIREWORK);
FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
if (direction) {
final Vector vector = user.getBase().getEyeLocation().getDirection().multiply(0.070);
if (fmeta.getPower() > 1) {
fmeta.setPower(1);
}
firework.setVelocity(vector);
}
firework.setFireworkMeta(fmeta);
}
} else {
final MetaItemStack mStack = new MetaItemStack(stack);
for (String arg : args) {
try {
mStack.addFireworkMeta(user.getSource(), true, arg, ess);
} catch (Exception e) {
user.sendMessage(tl("fireworkSyntax"));
throw e;
}
}
if (mStack.isValidFirework()) {
FireworkMeta fmeta = (FireworkMeta) mStack.getItemStack().getItemMeta();
FireworkEffect effect = mStack.getFireworkBuilder().build();
if (fmeta.getEffects().size() > 0 && !user.isAuthorized("essentials.firework.multiple")) {
throw new Exception(tl("multipleCharges"));
}
fmeta.addEffect(effect);
stack.setItemMeta(fmeta);
} else {
user.sendMessage(tl("fireworkSyntax"));
throw new Exception(tl("fireworkColor"));
}
}
} else {
throw new NotEnoughArgumentsException();
}
} else {
throw new Exception(tl("holdFirework"));
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
// Note: this enforces an order of color fade shape effect, which the actual command doesn't have. But that's fine.
if (args.length == 1) {
List<String> options = Lists.newArrayList();
if (args[0].startsWith("color:")) {
String prefix;
if (args[0].contains(",")) {
prefix = args[0].substring(0, args[0].lastIndexOf(',') + 1);
} else {
prefix = "color:";
}
for (DyeColor color : DyeColor.values()) {
options.add(prefix + color.name().toLowerCase() + ",");
}
return options;
}
options.add("clear");
options.add("power");
options.add("color:");
if (user.isAuthorized("essentials.firework.fire")) {
options.add("fire");
}
return options;
} else if (args.length == 2) {
if (args[0].equals("power")) {
return Lists.newArrayList("1", "2", "3", "4");
} else if (args[0].equals("fire")) {
return Lists.newArrayList("1");
} else if (args[0].startsWith("color:")) {
List<String> options = Lists.newArrayList();
if (!args[1].startsWith("fade:")) {
args[1] = "fade:";
}
String prefix;
if (args[1].contains(",")) {
prefix = args[1].substring(0, args[1].lastIndexOf(',') + 1);
} else {
prefix = "fade:";
}
for (DyeColor color : DyeColor.values()) {
options.add(prefix + color.name().toLowerCase() + ",");
}
return options;
} else {
return Collections.emptyList();
}
} else if (args.length == 3 && args[0].startsWith("color:")) {
return Lists.newArrayList("shape:star", "shape:ball", "shape:large", "shape:creeper", "shape:burst");
} else if (args.length == 4 && args[0].startsWith("color:")) {
return Lists.newArrayList("effect:trail", "effect:twinkle", "effect:trail,twinkle", "effect:twinkle,trail");
} else {
return Collections.emptyList();
}
}
}
@@ -1,61 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.google.common.collect.Lists;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandhat extends EssentialsCommand {
public Commandhat() {
super("hat");
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length > 0 && (args[0].contains("rem") || args[0].contains("off") || args[0].equalsIgnoreCase("0"))) {
final 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"));
}
} else {
if (user.getBase().getInventory().getItemInMainHand().getType() != Material.AIR) {
final ItemStack hand = user.getBase().getInventory().getItemInMainHand();
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"));
}
}
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
if (args.length == 1) {
return Lists.newArrayList("remove", "wear"); // "wear" isn't real
} else {
return Collections.emptyList();
}
}
}
@@ -1,100 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.potion.PotionEffect;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandheal extends EssentialsLoopCommand {
public Commandheal() {
super("heal");
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (!user.isAuthorized("essentials.heal.cooldown.bypass")) {
user.healCooldown();
}
if (args.length > 0 && user.isAuthorized("essentials.heal.others")) {
loopOnlinePlayers(server, user.getSource(), true, true, args[0], null);
return;
}
healPlayer(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();
}
loopOnlinePlayers(server, sender, true, true, args[0], null);
}
@Override
protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) throws PlayerExemptException {
try {
healPlayer(player);
sender.sendMessage(tl("healOther", player.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")) {
return getPlayers(server, user);
} else {
return Collections.emptyList();
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
if (args.length == 1) {
return getPlayers(server, sender);
} else {
return Collections.emptyList();
}
}
}
@@ -1,62 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.textreader.*;
import com.earth2me.essentials.utils.NumberUtil;
import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commandhelp extends EssentialsCommand {
public Commandhelp() {
super("help");
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
IText output;
String pageStr = args.length > 0 ? args[0] : null;
String chapterPageStr = args.length > 1 ? args[1] : null;
String command = commandLabel;
final IText input = new TextInput(user.getSource(), "help", false, ess);
if (input.getLines().isEmpty()) {
if (NumberUtil.isInt(pageStr) || pageStr == null) {
output = new HelpInput(user, "", ess);
} else {
if (pageStr.length() > 26) {
pageStr = pageStr.substring(0, 25);
}
output = new HelpInput(user, pageStr.toLowerCase(Locale.ENGLISH), ess);
command = command.concat(" ").concat(pageStr);
pageStr = chapterPageStr;
}
chapterPageStr = null;
} else {
user.setDisplayNick();
output = new KeywordReplacer(input, user.getSource(), ess);
}
final TextPager pager = new TextPager(output);
pager.showPage(pageStr, chapterPageStr, command, user.getSource());
}
@Override
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
sender.sendMessage(tl("helpConsole"));
}
@Override
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
if (args.length == 1) {
return getCommands(server);
} else {
return Collections.emptyList();
}
}
}
@@ -1,130 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.StringUtil;
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 static com.earth2me.essentials.I18n.tl;
public class Commandhome extends EssentialsCommand {
public Commandhome() {
super("home");
}
// This method contains an undocumented translation parameters #EasterEgg
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final Trade charge = new Trade(this.getName(), ess);
User player = user;
String homeName = "";
String[] nameParts;
if (args.length > 0) {
nameParts = args[0].split(":");
if (nameParts[0].length() == args[0].length() || !user.isAuthorized("essentials.home.others")) {
homeName = nameParts[0];
} else {
player = getPlayer(server, nameParts, 0, true, true);
if (nameParts.length > 1) {
homeName = nameParts[1];
}
}
}
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"));
}
}
goHome(user, player, homeName.toLowerCase(Locale.ENGLISH), charge);
} catch (NotEnoughArgumentsException e) {
Location bed = player.getBase().getBedSpawnLocation();
final List<String> homes = player.getHomes();
if (homes.isEmpty() && player.equals(user)) {
user.getTeleport().respawn(charge, TeleportCause.COMMAND);
} else if (homes.isEmpty()) {
throw new Exception(tl("noHomeSetPlayer"));
} else if (homes.size() == 1 && player.equals(user)) {
goHome(user, player, homes.get(0), charge);
} else {
final int count = homes.size();
if (user.isAuthorized("essentials.home.bed")) {
if (bed != null) {
homes.add(tl("bed"));
} else {
homes.add(tl("bedNull"));
}
}
user.sendMessage(tl("homes", StringUtil.joinList(homes), count, getHomeLimit(player)));
}
}
throw new NoChargeException();
}
private String getHomeLimit(final User player) {
if (!player.getBase().isOnline()) {
return "?";
}
if (player.isAuthorized("essentials.sethome.multiple.unlimited")) {
return "*";
}
return Integer.toString(ess.getSettings().getHomeLimit(player));
}
private void goHome(final User user, final User player, final String home, final Trade charge) throws Exception {
if (home.length() < 1) {
throw new NotEnoughArgumentsException();
}
final Location loc = player.getHome(home);
if (loc == null) {
throw new NotEnoughArgumentsException();
}
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);
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
boolean canVisitOthers = user.isAuthorized("essentials.home.others");
if (args.length == 1) {
if (canVisitOthers) {
return getPlayers(server, user);
} else {
List<String> homes = user.getHomes();
if (user.isAuthorized("essentials.home.bed")) {
homes.add("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();
}
} else {
return Collections.emptyList();
}
}
}
@@ -1,56 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandignore extends EssentialsCommand {
public Commandignore() {
super("ignore");
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
StringBuilder sb = new StringBuilder();
for (String s : user._getIgnoredPlayers()) {
sb.append(s).append(" ");
}
String ignoredList = sb.toString().trim();
user.sendMessage(ignoredList.length() > 0 ? tl("ignoredList", ignoredList) : tl("noIgnored"));
} 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()));
}
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
if (args.length == 1) {
return getPlayers(server, user);
} else {
return Collections.emptyList();
}
}
}
@@ -1,64 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commanditemdb extends EssentialsCommand {
public Commanditemdb() {
super("itemdb");
}
@Override
protected void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
ItemStack itemStack = null;
boolean itemHeld = false;
if (args.length < 1) {
if (sender.isPlayer() && sender.getPlayer() != null) {
itemHeld = true;
itemStack = sender.getPlayer().getInventory().getItemInMainHand();
}
if (itemStack == null) {
throw new NotEnoughArgumentsException();
}
} else {
itemStack = ess.getItemDb().get(args[0]);
}
sender.sendMessage(tl("itemType", itemStack.getType().toString()));
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_13_0_R01)) {
final String itemId = itemStack.getType().getId() + ":" + itemStack.getDurability();
sender.sendMessage(tl("itemId", itemId));
}
if (itemHeld && itemStack.getType() != Material.AIR) {
int maxuses = itemStack.getType().getMaxDurability();
int durability = ((maxuses + 1) - itemStack.getDurability());
if (maxuses != 0) {
sender.sendMessage(tl("durability", Integer.toString(durability)));
}
}
final String itemNameList = ess.getItemDb().names(itemStack);
if (itemNameList != null) {
sender.sendMessage(tl("itemNames", ess.getItemDb().names(itemStack)));
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
if (args.length == 1) {
return getItems();
} else {
return Collections.emptyList();
}
}
}
@@ -1,43 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.Mob;
import com.earth2me.essentials.User;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.entity.Ocelot;
import java.util.Random;
// This command is not documented on the wiki #EasterEgg
public class Commandkittycannon extends EssentialsCommand {
private static final Random random = new Random();
public Commandkittycannon() {
super("kittycannon");
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final Mob cat = Mob.OCELOT;
final Ocelot ocelot = (Ocelot) cat.spawn(user.getWorld(), server, user.getBase().getEyeLocation());
if (ocelot == null) {
return;
}
final int i = random.nextInt(Ocelot.Type.values().length);
ocelot.setCatType(Ocelot.Type.values()[i]);
ocelot.setTamed(true);
ocelot.setBaby();
ocelot.setVelocity(user.getBase().getEyeLocation().getDirection().multiply(2));
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);
}
}
@@ -1,128 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.PlayerList;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.NumberUtil;
import org.bukkit.Server;
import java.util.*;
import static com.earth2me.essentials.I18n.tl;
public class Commandlist extends EssentialsCommand {
public Commandlist() {
super("list");
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
boolean showHidden = true;
User user = null;
if (sender.isPlayer()) {
user = ess.getUser(sender.getPlayer());
showHidden = user.isAuthorized("essentials.list.hidden") || user.canInteractVanished();
}
sender.sendMessage(PlayerList.listSummary(ess, user, showHidden));
final Map<String, List<User>> playerList = PlayerList.getPlayerLists(ess, user, showHidden);
if (args.length > 0) {
sender.sendMessage(PlayerList.listGroupUsers(ess, playerList, args[0].toLowerCase()));
} else {
sendGroupedList(sender, commandLabel, playerList);
}
}
// Output the standard /list output, when no group is specified
private void sendGroupedList(CommandSource sender, String commandLabel, Map<String, List<User>> playerList) {
final Set<String> configGroups = ess.getSettings().getListGroupConfig().keySet();
final List<String> asterisk = new ArrayList<>();
// Loop through the custom defined groups and display them
for (String oConfigGroup : configGroups) {
String groupValue = ess.getSettings().getListGroupConfig().get(oConfigGroup).toString().trim();
String configGroup = oConfigGroup.toLowerCase();
// If the group value is an asterisk, then skip it, and handle it later
if (groupValue.equals("*")) {
asterisk.add(oConfigGroup);
continue;
}
// If the group value is hidden, we don't need to display it
if (groupValue.equalsIgnoreCase("hidden")) {
playerList.remove(configGroup);
continue;
}
List<User> outputUserList = new ArrayList<>();
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);
int limit = Integer.parseInt(groupValue);
if (matchedList.size() > limit) {
sender.sendMessage(PlayerList.outputFormat(oConfigGroup, tl("groupNumber", matchedList.size(), commandLabel, FormatUtil.stripFormat(configGroup))));
} else {
sender.sendMessage(PlayerList.outputFormat(oConfigGroup, PlayerList.listUsers(ess, outputUserList, ", ")));
}
continue;
}
}
outputUserList = PlayerList.getMergedList(ess, playerList, configGroup);
// If we have no users, than we don't need to continue parsing this group
if (outputUserList == null || outputUserList.isEmpty()) {
continue;
}
sender.sendMessage(PlayerList.outputFormat(oConfigGroup, PlayerList.listUsers(ess, outputUserList, ", ")));
}
Set<String> var = playerList.keySet();
String[] onlineGroups = var.toArray(new String[var.size()]);
Arrays.sort(onlineGroups, String.CASE_INSENSITIVE_ORDER);
// If we have an asterisk group, then merge all remaining groups
if (!asterisk.isEmpty()) {
List<User> asteriskUsers = new ArrayList<>();
for (String onlineGroup : onlineGroups) {
asteriskUsers.addAll(playerList.get(onlineGroup));
}
for (String key : asterisk) {
playerList.put(key, asteriskUsers);
}
onlineGroups = asterisk.toArray(new String[asterisk.size()]);
}
// If we have any groups remaining after the custom groups loop through and display them
for (String onlineGroup : onlineGroups) {
List<User> users = playerList.get(onlineGroup);
String groupName = asterisk.isEmpty() ? users.get(0).getGroup() : onlineGroup;
if (ess.getPermissionsHandler().getName().equals("ConfigPermissions")) {
groupName = tl("connectedPlayers");
}
if (users == null || users.isEmpty()) {
continue;
}
sender.sendMessage(PlayerList.outputFormat(groupName, PlayerList.listUsers(ess, users, ", ")));
}
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) {
return getGroups();
} else {
return Collections.emptyList();
}
}
}
@@ -1,191 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
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.FormatUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import static com.earth2me.essentials.I18n.tl;
public class Commandmail extends EssentialsCommand {
private static int mailsPerMinute = 0;
private static long timestamp = 0;
public Commandmail() {
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])) {
final List<String> mail = user.getMails();
if (mail.isEmpty()) {
user.sendMessage(tl("noMail"));
throw new NoChargeException();
}
IText input = new SimpleTextInput(mail);
final TextPager pager = new TextPager(input);
pager.showPage(args.length > 1 ? args[1] : null, null, commandLabel + " " + args[0], user.getSource());
user.sendMessage(tl("mailClear"));
return;
}
if (args.length >= 3 && "send".equalsIgnoreCase(args[0])) {
if (!user.isAuthorized("essentials.mail.send")) {
throw new Exception(tl("noPerm", "essentials.mail.send"));
}
if (user.isMuted()) {
throw new Exception(tl("voiceSilenced"));
}
User u = getPlayer(server, args[1], true, true);
if (u == null) {
throw new Exception(tl("playerNeverOnServer", args[1]));
}
String mail = tl("mailFormat", user.getName(), FormatUtil.formatMessage(user, "essentials.mail", StringUtil.sanitizeString(FormatUtil.stripFormat(getFinalArg(args, 2)))));
if (mail.length() > 1000) {
throw new Exception(tl("mailTooLong"));
}
if (!u.isIgnoredPlayer(user)) {
if (Math.abs(System.currentTimeMillis() - timestamp) > 60000) {
timestamp = System.currentTimeMillis();
mailsPerMinute = 0;
}
mailsPerMinute++;
if (mailsPerMinute > ess.getSettings().getMailsPerMinute()) {
throw new Exception(tl("mailDelay", ess.getSettings().getMailsPerMinute()));
}
u.addMail(tl("mailMessage", mail));
}
user.sendMessage(tl("mailSentTo", u.getDisplayName(), u.getName()));
user.sendMessage(mail);
return;
}
if (args.length > 1 && "sendall".equalsIgnoreCase(args[0])) {
if (!user.isAuthorized("essentials.mail.sendall")) {
throw new Exception(tl("noPerm", "essentials.mail.sendall"));
}
ess.runTaskAsynchronously(new SendAll(tl("mailFormat", user.getName(),
FormatUtil.formatMessage(user, "essentials.mail", StringUtil.sanitizeString(FormatUtil.stripFormat(getFinalArg(args, 1)))))));
user.sendMessage(tl("mailSent"));
return;
}
if (args.length >= 1 && "clear".equalsIgnoreCase(args[0])) {
user.setMails(null);
user.sendMessage(tl("mailCleared"));
return;
}
throw new NotEnoughArgumentsException();
}
@Override
protected void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
if (args.length >= 1 && "read".equalsIgnoreCase(args[0])) {
throw new Exception(tl("onlyPlayers", commandLabel + " read"));
} 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) {
throw new Exception(tl("playerNeverOnServer", args[1]));
}
u.addMail(tl("mailFormat", "Server", getFinalArg(args, 2)));
sender.sendMessage(tl("mailSent"));
return;
} else if (args.length >= 2 && "sendall".equalsIgnoreCase(args[0])) {
ess.runTaskAsynchronously(new SendAll(tl("mailFormat", "Server", getFinalArg(args, 1))));
sender.sendMessage(tl("mailSent"));
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) {
throw new Exception(tl("playerNeverOnServer", args[0]));
}
u.addMail(tl("mailFormat", "Server", getFinalArg(args, 1)));
sender.sendMessage(tl("mailSent"));
return;
}
throw new NotEnoughArgumentsException();
}
private class SendAll implements Runnable {
String message;
public SendAll(String message) {
this.message = message;
}
@Override
public void run() {
for (UUID userid : ess.getUserMap().getAllUniqueUsers()) {
User user = ess.getUserMap().getUser(userid);
if (user != null) {
user.addMail(message);
}
}
}
}
@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("read", "clear");
if (user.isAuthorized("essentials.mail.send")) {
options.add("send");
}
if (user.isAuthorized("essentials.mail.sendall")) {
options.add("sendall");
}
return options;
} else if (args.length == 2 && args[0].equalsIgnoreCase("send") && user.isAuthorized("essentials.mail.send")) {
return getPlayers(server, user);
} else if (args.length == 2 && args[0].equalsIgnoreCase("read")) {
final List<String> mail = user.getMails();
int pages = mail.size() / 9 + (mail.size() % 9 > 0 ? 1 : 0);
if (pages == 0) {
return Lists.newArrayList("0");
} else {
List<String> options = Lists.newArrayList("1");
if (pages > 1) {
options.add(String.valueOf(pages));
}
return options;
}
} else if ((args.length > 2 && args[0].equalsIgnoreCase("send") && user.isAuthorized("essentials.mail.send")) || (args.length > 1 && args[0].equalsIgnoreCase("sendall") && user.isAuthorized("essentials.mail.sendall"))) {
return null; // Use vanilla handler
} 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) {
return Lists.newArrayList("send", "sendall");
} else if (args.length == 2 && args[0].equalsIgnoreCase("send")) {
return getPlayers(server, sender);
} else if ((args.length > 2 && args[0].equalsIgnoreCase("send")) || (args.length > 1 && args[0].equalsIgnoreCase("sendall"))) {
return null; // Use vanilla handler
} else {
return Collections.emptyList();
}
}
}
@@ -1,38 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commandmore extends EssentialsCommand {
public Commandmore() {
super("more");
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final ItemStack stack = user.getBase().getInventory().getItemInMainHand();
if (stack == null) {
throw new Exception(tl("cantSpawnItem", "Air"));
}
if (stack.getAmount() >= ((user.isAuthorized("essentials.oversizedstacks")) ? ess.getSettings().getOversizedStackSize() : stack.getMaxStackSize())) {
throw new Exception(tl("fullStack"));
}
final String itemname = stack.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", "");
if (!user.canSpawnItem(stack.getType())) {
throw new Exception(tl("cantSpawnItem", itemname));
}
if (user.isAuthorized("essentials.oversizedstacks")) {
stack.setAmount(ess.getSettings().getOversizedStackSize());
} else {
stack.setAmount(stack.getMaxStackSize());
}
user.getBase().updateInventory();
}
}
@@ -1,65 +0,0 @@
package com.earth2me.essentials.commands;
import static com.earth2me.essentials.I18n.tl;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Console;
import com.earth2me.essentials.User;
import com.earth2me.essentials.messaging.IMessageRecipient;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.Server;
import java.util.List;
public class Commandmsg extends EssentialsLoopCommand {
public Commandmsg() {
super("msg");
}
@Override
public void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception {
if (args.length < 2 || args[0].trim().length() < 2 || args[1].trim().isEmpty()) {
throw new NotEnoughArgumentsException();
}
String message = getFinalArg(args, 1);
boolean canWildcard;
if (sender.isPlayer()) {
User user = ess.getUser(sender.getPlayer());
if (user.isMuted()) {
throw new Exception(tl("voiceSilenced"));
}
message = FormatUtil.formatMessage(user, "essentials.msg", message);
canWildcard = user.isAuthorized("essentials.msg.multiple");
} else {
message = FormatUtil.replaceFormat(message);
canWildcard = true;
}
// Sending messages to console
if (args[0].equalsIgnoreCase(Console.NAME)) {
IMessageRecipient messageSender = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : Console.getInstance();
messageSender.sendMessage(Console.getInstance(), message);
return;
}
loopOnlinePlayers(server, sender, canWildcard, canWildcard, args[0], new String[]{message});
}
@Override
protected void updatePlayer(final Server server, final CommandSource sender, final User messageReceiver, final String[] args) {
IMessageRecipient messageSender = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : Console.getInstance();
messageSender.sendMessage(messageReceiver, args[0]); // args[0] is the message.
}
@Override
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
if (args.length == 1) {
return getPlayers(server, sender);
} else {
return null; // It's a chat message, use the default chat handler
}
}
}
@@ -1,98 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.OfflinePlayer;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.DateUtil;
import net.ess3.api.events.MuteStatusChangeEvent;
import org.bukkit.Server;
import java.util.List;
import java.util.logging.Level;
import static com.earth2me.essentials.I18n.tl;
public class Commandmute extends EssentialsCommand {
public Commandmute() {
super("mute");
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
boolean nomatch = false;
if (args.length < 1) {
throw new NotEnoughArgumentsException();
}
User user;
try {
user = getPlayer(server, args, 0, true, true);
} catch (PlayerNotFoundException e) {
nomatch = true;
user = ess.getUser(new OfflinePlayer(args[0], ess.getServer()));
}
if (!user.getBase().isOnline()) {
if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.mute.offline")) {
throw new Exception(tl("muteExemptOffline"));
}
} else {
if (user.isAuthorized("essentials.mute.exempt") && sender.isPlayer()) {
throw new Exception(tl("muteExempt"));
}
}
final boolean willMute = (args.length > 1) ? true : !user.getMuted();
final User controller = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null;
final MuteStatusChangeEvent event = new MuteStatusChangeEvent(user, controller, willMute);
ess.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
long muteTimestamp = 0;
if (args.length > 1) {
final String time = getFinalArg(args, 1);
muteTimestamp = DateUtil.parseDateDiff(time, true);
user.setMuted(true);
} else {
user.setMuted(!user.getMuted());
}
user.setMuteTimeout(muteTimestamp);
final boolean muted = user.getMuted();
String muteTime = DateUtil.formatDateDiff(muteTimestamp);
if (nomatch) {
sender.sendMessage(tl("userUnknown", user.getName()));
}
if (muted) {
if (muteTimestamp > 0) {
sender.sendMessage(tl("mutedPlayerFor", user.getDisplayName(), muteTime));
user.sendMessage(tl("playerMutedFor", muteTime));
} else {
sender.sendMessage(tl("mutedPlayer", user.getDisplayName()));
user.sendMessage(tl("playerMuted"));
}
final String message;
if (muteTimestamp > 0) {
message = tl("muteNotifyFor", sender.getSender().getName(), user.getName(), muteTime);
} else {
message = tl("muteNotify", sender.getSender().getName(), user.getName());
}
server.getLogger().log(Level.INFO, message);
ess.broadcastMessage("essentials.mute.notify", message);
} else {
sender.sendMessage(tl("unmutedPlayer", user.getDisplayName()));
user.sendMessage(tl("playerUnmuted"));
}
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
if (args.length == 1) {
return getPlayers(server, sender);
} else {
return COMMON_DATE_DIFFS; // Date diff can span multiple words
}
}
}
@@ -1,101 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.ChargeException;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.collect.Lists;
import net.ess3.api.MaxMoneyException;
import org.bukkit.Server;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandpay extends EssentialsLoopCommand {
BigDecimal amount;
boolean informToConfirm;
public Commandpay() {
super("pay");
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
informToConfirm = false;
if (args.length < 2) {
throw new NotEnoughArgumentsException();
}
if (args[1].contains("-")) {
throw new Exception(tl("payMustBePositive"));
}
String stringAmount = args[1].replaceAll("[^0-9\\.]", "");
if (stringAmount.length() < 1) {
throw new NotEnoughArgumentsException();
}
amount = new BigDecimal(stringAmount);
if (amount.compareTo(ess.getSettings().getMinimumPayAmount()) < 0) { // Check if amount is less than minimum-pay-amount
throw new Exception(tl("minimumPayAmount", NumberUtil.displayCurrencyExactly(ess.getSettings().getMinimumPayAmount(), ess)));
}
loopOnlinePlayers(server, user.getSource(), false, user.isAuthorized("essentials.pay.multiple"), args[0], args);
if (informToConfirm) {
String cmd = "/" + commandLabel + " " + StringUtil.joinList(" ", (Object[]) args);
user.sendMessage(tl("confirmPayment", NumberUtil.displayCurrency(amount, ess), cmd));
}
}
@Override
protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) throws ChargeException {
User user = ess.getUser(sender.getPlayer());
try {
if (!player.isAcceptingPay()) {
sender.sendMessage(tl("notAcceptingPay", player.getDisplayName()));
return;
}
if (user.isPromptingPayConfirm() && !amount.equals(user.getConfirmingPayments().get(player))) { // checks if exists and if command needs to be repeated.
// Used to reset confirmations and inform to confirm when a new pay command has been inserted.
if (!informToConfirm) {
// User hasnt been asked to confirm payment to this player, reset all confirmed payments and ask to confirm again.
// Clear previous confirmations to ensure that a new confirmation message is brought up.
user.getConfirmingPayments().clear();
this.informToConfirm = true;
}
user.getConfirmingPayments().put(player, amount);
return;
}
user.payUser(player, amount);
user.getConfirmingPayments().remove(player);
Trade.log("Command", "Pay", "Player", user.getName(), new Trade(amount, ess), player.getName(), new Trade(amount, ess), user.getLocation(), ess);
} catch (MaxMoneyException ex) {
sender.sendMessage(tl("maxMoney"));
try {
user.setMoney(user.getMoney().add(amount));
} catch (MaxMoneyException ignored) {
// this should never happen
}
} catch (Exception e) {
sender.sendMessage(e.getMessage());
}
}
@Override
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
if (args.length == 1) {
return getPlayers(server, sender);
} else if (args.length == 2) {
return Lists.newArrayList(ess.getSettings().getMinimumPayAmount().toString());
} else {
return Collections.emptyList();
}
}
}
@@ -1,32 +0,0 @@
package com.earth2me.essentials.commands;
import static com.earth2me.essentials.I18n.tl;
import com.earth2me.essentials.I18n;
import com.earth2me.essentials.User;
import org.bukkit.Server;
public class Commandpaytoggle extends EssentialsCommand {
public Commandpaytoggle() {
super("paytoggle");
}
@Override
public void run(Server server, User user, String commandLabel, String[] args) throws Exception {
boolean acceptingPay = !user.isAcceptingPay();
if (commandLabel.contains("payon")) {
acceptingPay = true;
} else if (commandLabel.contains("payoff")) {
acceptingPay = false;
}
user.setAcceptingPay(acceptingPay);
if (acceptingPay) {
user.sendMessage(tl("payToggleOn"));
} else {
user.sendMessage(tl("payToggleOff"));
}
}
}
@@ -1,209 +0,0 @@
package com.earth2me.essentials.commands;
import com.google.common.collect.Lists;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.DescParseTickFormat;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.*;
import static com.earth2me.essentials.I18n.tl;
public class Commandptime extends EssentialsCommand {
private static final Set<String> getAliases = new HashSet<>();
static {
getAliases.add("get");
getAliases.add("list");
getAliases.add("show");
getAliases.add("display");
}
public Commandptime() {
super("ptime");
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
// Which Players(s) / Users(s) are we interested in?
String userSelector = null;
if (args.length == 2) {
userSelector = args[1];
}
Set<User> users = getUsers(server, sender, userSelector);
// If no arguments we are reading the time
if (args.length == 0) {
getUsersTime(sender, users);
return;
}
if (sender.isPlayer()) {
User user = ess.getUser(sender.getPlayer());
if (user != null && (!users.contains(user) || users.size() > 1) && !user.isAuthorized("essentials.ptime.others")) {
user.sendMessage(tl("pTimeOthersPermission"));
return;
}
}
Long ticks;
// Parse the target time int ticks from args[0]
String timeParam = args[0];
boolean relative = true;
if (timeParam.startsWith("@")) {
relative = false;
timeParam = timeParam.substring(1);
}
if (getAliases.contains(timeParam)) {
getUsersTime(sender, users);
return;
} else if (DescParseTickFormat.meansReset(timeParam)) {
ticks = null;
} else {
try {
ticks = DescParseTickFormat.parse(timeParam);
} catch (NumberFormatException e) {
throw new NotEnoughArgumentsException(e);
}
}
setUsersTime(sender, users, ticks, relative);
}
/**
* Used to get the time and inform
*/
private void getUsersTime(final CommandSource sender, final Collection<User> users) {
if (users.size() > 1) {
sender.sendMessage(tl("pTimePlayers"));
}
for (User user : users) {
if (user.getBase().getPlayerTimeOffset() == 0) {
sender.sendMessage(tl("pTimeNormal", user.getName()));
} else {
String time = DescParseTickFormat.format(user.getBase().getPlayerTime());
if (!user.getBase().isPlayerTimeRelative()) {
sender.sendMessage(tl("pTimeCurrentFixed", user.getName(), time));
} else {
sender.sendMessage(tl("pTimeCurrent", user.getName(), time));
}
}
}
}
/**
* Used to set the time and inform of the change
*/
private void setUsersTime(final CommandSource sender, final Collection<User> users, final Long ticks, Boolean relative) {
// Update the time
if (ticks == null) {
// Reset
for (User user : users) {
user.getBase().resetPlayerTime();
}
} else {
// Set
for (User user : users) {
final World world = user.getWorld();
long time = user.getBase().getPlayerTime();
time -= time % 24000;
time += 24000 + ticks;
if (relative) {
time -= world.getTime();
}
user.getBase().setPlayerTime(time, relative);
}
}
final StringBuilder msg = new StringBuilder();
for (User user : users) {
if (msg.length() > 0) {
msg.append(", ");
}
msg.append(user.getName());
}
// Inform the sender of the change
if (ticks == null) {
sender.sendMessage(tl("pTimeReset", msg.toString()));
} else {
String time = DescParseTickFormat.format(ticks);
if (!relative) {
sender.sendMessage(tl("pTimeSetFixed", time, msg.toString()));
} else {
sender.sendMessage(tl("pTimeSet", time, msg.toString()));
}
}
}
/**
* Used to parse an argument of the type "users(s) selector"
*/
private Set<User> getUsers(final Server server, final CommandSource sender, final String selector) throws Exception {
final Set<User> users = new TreeSet<>(new UserNameComparator());
// If there is no selector we want the sender itself. Or all users if sender isn't a user.
if (selector == null) {
if (sender.isPlayer()) {
final User user = ess.getUser(sender.getPlayer());
users.add(user);
} else {
for (User user : ess.getOnlineUsers()) {
users.add(user);
}
}
return users;
}
// Try to find the user with name = selector
User user = null;
final List<Player> matchedPlayers = server.matchPlayer(selector);
if (!matchedPlayers.isEmpty()) {
user = ess.getUser(matchedPlayers.get(0));
}
if (user != null) {
users.add(user);
}
// If that fails, Is the argument something like "*" or "all"?
else if (selector.equalsIgnoreCase("*") || selector.equalsIgnoreCase("all")) {
for (User u : ess.getOnlineUsers()) {
users.add(u);
}
}
// We failed to understand the world target...
else {
throw new PlayerNotFoundException();
}
return users;
}
@Override
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
final User user = ess.getUser(sender.getPlayer());
if (args.length == 1) {
return Lists.newArrayList("get", "reset", "sunrise", "day", "morning", "noon", "afternoon", "sunset", "night", "midnight");
} else if (args.length == 2 && (getAliases.contains(args[0]) || user == null || user.isAuthorized("essentials.ptime.others"))) {
return getPlayers(server, sender);
} else {
return Collections.emptyList();
}
}
}
class UserNameComparator implements Comparator<User> {
@Override
public int compare(User a, User b) {
return a.getName().compareTo(b.getName());
}
}
@@ -1,166 +0,0 @@
package com.earth2me.essentials.commands;
import com.google.common.collect.Lists;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import org.bukkit.WeatherType;
import org.bukkit.entity.Player;
import java.util.*;
import static com.earth2me.essentials.I18n.tl;
public class Commandpweather extends EssentialsCommand {
public static final Set<String> getAliases = new HashSet<>();
public static final Map<String, WeatherType> weatherAliases = new HashMap<>();
static {
getAliases.add("get");
getAliases.add("list");
getAliases.add("show");
getAliases.add("display");
weatherAliases.put("sun", WeatherType.CLEAR);
weatherAliases.put("clear", WeatherType.CLEAR);
weatherAliases.put("storm", WeatherType.DOWNFALL);
weatherAliases.put("thunder", WeatherType.DOWNFALL);
}
public Commandpweather() {
super("pweather");
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
// Which Players(s) / Users(s) are we interested in?
String userSelector = null;
if (args.length == 2) {
userSelector = args[1];
}
Set<User> users = getUsers(server, sender, userSelector);
if (args.length == 0) {
getUsersWeather(sender, users);
return;
}
if (getAliases.contains(args[0])) {
getUsersWeather(sender, users);
return;
}
if (sender.isPlayer()) {
User user = ess.getUser(sender.getPlayer());
if (user != null && (!users.contains(user) || users.size() > 1) && !user.isAuthorized("essentials.pweather.others")) {
user.sendMessage(tl("pWeatherOthersPermission"));
return;
}
}
setUsersWeather(sender, users, args[0].toLowerCase());
}
/**
* Used to get the time and inform
*/
private void getUsersWeather(final CommandSource sender, final Collection<User> users) {
if (users.size() > 1) {
sender.sendMessage(tl("pWeatherPlayers"));
}
for (User user : users) {
if (user.getBase().getPlayerWeather() == null) {
sender.sendMessage(tl("pWeatherNormal", user.getName()));
} else {
sender.sendMessage(tl("pWeatherCurrent", user.getName(), user.getBase().getPlayerWeather().toString().toLowerCase(Locale.ENGLISH)));
}
}
}
/**
* Used to set the time and inform of the change
*/
private void setUsersWeather(final CommandSource sender, final Collection<User> users, final String weatherType) throws Exception {
final StringBuilder msg = new StringBuilder();
for (User user : users) {
if (msg.length() > 0) {
msg.append(", ");
}
msg.append(user.getName());
}
if (weatherType.equalsIgnoreCase("reset")) {
for (User user : users) {
user.getBase().resetPlayerWeather();
}
sender.sendMessage(tl("pWeatherReset", msg));
} else {
if (!weatherAliases.containsKey(weatherType)) {
throw new NotEnoughArgumentsException(tl("pWeatherInvalidAlias"));
}
for (User user : users) {
user.getBase().setPlayerWeather(weatherAliases.get(weatherType));
}
sender.sendMessage(tl("pWeatherSet", weatherType, msg.toString()));
}
}
/**
* Used to parse an argument of the type "users(s) selector"
*/
private Set<User> getUsers(final Server server, final CommandSource sender, final String selector) throws Exception {
final Set<User> users = new TreeSet<>(new UserNameComparator());
// If there is no selector we want the sender itself. Or all users if sender isn't a user.
if (selector == null) {
if (sender.isPlayer()) {
final User user = ess.getUser(sender.getPlayer());
users.add(user);
} else {
for (User user : ess.getOnlineUsers()) {
users.add(user);
}
}
return users;
}
// Try to find the user with name = selector
User user = null;
final List<Player> matchedPlayers = server.matchPlayer(selector);
if (!matchedPlayers.isEmpty()) {
user = ess.getUser(matchedPlayers.get(0));
}
if (user != null) {
users.add(user);
}
// If that fails, Is the argument something like "*" or "all"?
else if (selector.equalsIgnoreCase("*") || selector.equalsIgnoreCase("all")) {
for (User u : ess.getOnlineUsers()) {
users.add(u);
}
}
// We failed to understand the world target...
else {
throw new PlayerNotFoundException();
}
return users;
}
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
if (args.length == 1) {
return Lists.newArrayList("get", "reset", "storm", "sun");
} else if (args.length == 2 && (getAliases.contains(args[0]) || user == null || user.isAuthorized("essentials.pweather.others"))) {
return getPlayers(server, user);
} else {
return Collections.emptyList();
}
}
}
@@ -1,225 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.UserMap;
import com.earth2me.essentials.craftbukkit.BanLookup;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.StringUtil;
import org.bukkit.BanEntry;
import org.bukkit.BanList;
import org.bukkit.Location;
import org.bukkit.Server;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.Collections;
import static com.earth2me.essentials.I18n.tl;
public class Commandseen extends EssentialsCommand {
public Commandseen() {
super("seen");
}
@Override
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
seen(server, sender, commandLabel, args, true, true, true, true);
}
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
seen(server, user.getSource(), commandLabel, args, user.isAuthorized("essentials.seen.banreason"), user.isAuthorized("essentials.seen.ip"), user.isAuthorized("essentials.seen.location"), user.isAuthorized("essentials.seen.ipsearch"));
}
protected void seen(final Server server, final CommandSource sender, final String commandLabel, final String[] args,
final boolean showBan, final boolean showIp, final boolean showLocation, final boolean ipLookup) throws Exception {
if (args.length < 1) {
throw new NotEnoughArgumentsException();
}
User player;
// Check by uuid, if it fails check by name.
try {
UUID uuid = UUID.fromString(args[0]);
player = ess.getUser(uuid);
}catch (IllegalArgumentException ignored) { // Thrown if invalid UUID from string, check by name.
player = ess.getOfflineUser(args[0]);
}
if (player == null) {
if (ipLookup && FormatUtil.validIP(args[0])) {
seenIP(server, sender, args[0]);
return;
} else if (ess.getServer().getBanList(BanList.Type.IP).isBanned(args[0])) {
sender.sendMessage(tl("isIpBanned", args[0]));
return;
} else if (BanLookup.isBanned(ess, args[0])) {
sender.sendMessage(tl("whoisBanned", showBan ? BanLookup.getBanEntry(ess, args[0]).getReason() : tl("true")));
return;
}
ess.getScheduler().runTaskAsynchronously(ess, new Runnable() {
@Override
public void 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);
}
});
} else {
showSeenMessage(server, sender, player, showBan, showIp, showLocation);
}
}
private void showSeenMessage(Server server, CommandSource sender, User player, boolean showBan, boolean showIp, boolean showLocation) throws Exception {
if (player.getBase().isOnline() && canInteractWith(sender, player)) {
seenOnline(server, sender, player, showBan, showIp, showLocation);
} else {
seenOffline(server, sender, player, showBan, showIp, showLocation);
}
}
private void seenOnline(final Server server, final CommandSource sender, final User user, final boolean showBan, final boolean showIp, final boolean showLocation) throws Exception {
user.setDisplayNick();
sender.sendMessage(tl("seenOnline", user.getDisplayName(), DateUtil.formatDateDiff(user.getLastLogin())));
if (ess.getSettings().isDebug()) {
ess.getLogger().info("UUID: " + user.getBase().getUniqueId().toString());
}
List<String> history = ess.getUserMap().getUserHistory(user.getBase().getUniqueId());
if (history != null && history.size() > 1) {
sender.sendMessage(tl("seenAccounts", StringUtil.joinListSkip(", ", user.getName(), history)));
}
if (user.isAfk()) {
sender.sendMessage(tl("whoisAFK", tl("true")));
}
if (user.isJailed()) {
sender.sendMessage(tl("whoisJail", (user.getJailTimeout() > 0 ? DateUtil.formatDateDiff(user.getJailTimeout()) : tl("true"))));
}
if (user.isMuted()) {
sender.sendMessage(tl("whoisMuted", (user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : tl("true"))));
}
final String location = user.getGeoLocation();
if (location != null && (!(sender.isPlayer()) || ess.getUser(sender.getPlayer()).isAuthorized("essentials.geoip.show"))) {
sender.sendMessage(tl("whoisGeoLocation", location));
}
if (showIp) {
sender.sendMessage(tl("whoisIPAddress", user.getBase().getAddress().getAddress().toString()));
}
}
private void seenOffline(final Server server, final CommandSource sender, User user, final boolean showBan, final boolean showIp, final boolean showLocation) throws Exception {
user.setDisplayNick();
if (user.getLastLogout() > 0) {
sender.sendMessage(tl("seenOffline", user.getName(), DateUtil.formatDateDiff(user.getLastLogout())));
} else {
sender.sendMessage(tl("userUnknown", user.getName()));
}
if (ess.getSettings().isDebug()) {
ess.getLogger().info("UUID: " + user.getBase().getUniqueId().toString());
}
List<String> history = ess.getUserMap().getUserHistory(user.getBase().getUniqueId());
if (history != null && history.size() > 1) {
sender.sendMessage(tl("seenAccounts", StringUtil.joinListSkip(", ", user.getName(), history)));
}
if (BanLookup.isBanned(ess, user)) {
final BanEntry banEntry = BanLookup.getBanEntry(ess, user.getName());
final String reason = showBan ? banEntry.getReason() : tl("true");
sender.sendMessage(tl("whoisBanned", reason));
if (banEntry.getExpiration() != null) {
Date expiry = banEntry.getExpiration();
String expireString = tl("now");
if (expiry.after(new Date())) {
expireString = DateUtil.formatDateDiff(expiry.getTime());
}
sender.sendMessage(tl("whoisTempBanned", expireString));
}
}
final String location = user.getGeoLocation();
if (location != null && (!(sender.isPlayer()) || ess.getUser(sender.getPlayer()).isAuthorized("essentials.geoip.show"))) {
sender.sendMessage(tl("whoisGeoLocation", location));
}
if (showIp) {
if (!user.getLastLoginAddress().isEmpty()) {
sender.sendMessage(tl("whoisIPAddress", user.getLastLoginAddress()));
}
}
if (showLocation) {
final Location loc = user.getLogoutLocation();
if (loc != null) {
sender.sendMessage(tl("whoisLocation", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
}
}
}
private void seenIP(final Server server, final CommandSource sender, final String ipAddress) throws Exception {
final UserMap userMap = ess.getUserMap();
if (ess.getServer().getBanList(BanList.Type.IP).isBanned(ipAddress)) {
sender.sendMessage(tl("isIpBanned", ipAddress));
}
sender.sendMessage(tl("runningPlayerMatch", ipAddress));
ess.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
final List<String> matches = new ArrayList<>();
for (final UUID u : userMap.getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
if (user == null) {
continue;
}
final String uIPAddress = user.getLastLoginAddress();
if (!uIPAddress.isEmpty() && uIPAddress.equalsIgnoreCase(ipAddress)) {
matches.add(user.getName());
}
}
if (matches.size() > 0) {
sender.sendMessage(tl("matchingIPAddress"));
sender.sendMessage(StringUtil.joinList(matches));
} else {
sender.sendMessage(tl("noMatchingPlayers"));
}
}
});
}
@Override
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
if (args.length == 1) {
return getPlayers(server, sender);
} else {
return Collections.emptyList();
}
}
}
@@ -1,45 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.api.IWarps;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import net.ess3.api.InvalidWorldException;
import org.bukkit.Location;
import org.bukkit.Server;
import static com.earth2me.essentials.I18n.tl;
public class Commandsetwarp extends EssentialsCommand {
public Commandsetwarp() {
super("setwarp");
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length < 1) {
throw new NotEnoughArgumentsException();
}
if (NumberUtil.isInt(args[0]) || args[0].isEmpty()) {
throw new NoSuchFieldException(tl("invalidWarpName"));
}
final Location loc = user.getLocation();
final IWarps warps = ess.getWarps();
Location warpLoc = null;
try {
warpLoc = warps.getWarp(args[0]);
} catch (WarpNotFoundException | InvalidWorldException ex) {
}
if (warpLoc == null || user.isAuthorized("essentials.warp.overwrite." + StringUtil.safeString(args[0]))) {
warps.setWarp(user, args[0], loc);
} else {
throw new Exception(tl("warpOverwrite"));
}
user.sendMessage(tl("warpSet", args[0]));
}
}
@@ -1,203 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.DescParseTickFormat;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import org.bukkit.World;
import java.util.*;
import static com.earth2me.essentials.I18n.tl;
public class Commandtime extends EssentialsCommand {
public Commandtime() {
super("time");
}
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
boolean add = false;
final List<String> argList = new ArrayList<>(Arrays.asList(args));
if (argList.remove("set") && !argList.isEmpty() && NumberUtil.isInt(argList.get(0))) {
argList.set(0, argList.get(0) + "t");
}
if (argList.remove("add") && !argList.isEmpty() && NumberUtil.isInt(argList.get(0))) {
add = true;
argList.set(0, argList.get(0) + "t");
}
final String[] validArgs = argList.toArray(new String[argList.size()]);
// Which World(s) are we interested in?
String worldSelector = null;
if (validArgs.length == 2) {
worldSelector = validArgs[1];
}
final Set<World> worlds = getWorlds(server, sender, worldSelector);
final String setTime;
// If no arguments we are reading the time
if (validArgs.length == 0) {
if (commandLabel.equalsIgnoreCase("day") || commandLabel.equalsIgnoreCase("eday")) {
setTime = "day";
} else if (commandLabel.equalsIgnoreCase("night") || commandLabel.equalsIgnoreCase("enight")) {
setTime = "night";
} else {
getWorldsTime(sender, worlds);
throw new NoChargeException();
}
} else {
setTime = validArgs[0];
}
final User user = ess.getUser(sender.getPlayer());
if (user != null && !user.isAuthorized("essentials.time.set")) {
throw new Exception(tl("timeSetPermission"));
}
// Parse the target time int ticks from args[0]
long ticks;
try {
ticks = DescParseTickFormat.parse(setTime);
} catch (NumberFormatException e) {
throw new NotEnoughArgumentsException(e);
}
setWorldsTime(sender, worlds, ticks, add);
}
/**
* Used to get the time and inform
*/
private void getWorldsTime(final CommandSource sender, final Collection<World> worlds) {
if (worlds.size() == 1) {
final Iterator<World> iter = worlds.iterator();
sender.sendMessage(DescParseTickFormat.format(iter.next().getTime()));
return;
}
for (World world : worlds) {
sender.sendMessage(tl("timeWorldCurrent", world.getName(), DescParseTickFormat.format(world.getTime())));
}
}
/**
* Used to set the time and inform of the change
*/
private void setWorldsTime(final CommandSource sender, final Collection<World> worlds, final long ticks, final boolean add) throws Exception {
User user = ess.getUser(sender.getPlayer());
for (World world : worlds) {
if (!canUpdateWorld(user, world)) {
throw new Exception(tl("timeSetWorldPermission", user.getWorld().getName()));
}
}
// Update the time
for (World world : worlds) {
long time = world.getTime();
if (!add) {
time -= time % 24000;
}
world.setTime(time + (add ? 0 : 24000) + ticks);
}
final StringBuilder output = new StringBuilder();
for (World world : worlds) {
if (output.length() > 0) {
output.append(", ");
}
output.append(world.getName());
}
sender.sendMessage(tl("timeWorldSet", DescParseTickFormat.format(ticks), output.toString()));
}
/**
* Used to parse an argument of the type "world(s) selector"
*/
private Set<World> getWorlds(final Server server, final CommandSource sender, final String selector) throws Exception {
final Set<World> worlds = new TreeSet<>(new WorldNameComparator());
// If there is no selector we want the world the user is currently in. Or all worlds if it isn't a user.
if (selector == null) {
if (sender.isPlayer()) {
final User user = ess.getUser(sender.getPlayer());
worlds.add(user.getWorld());
} else {
worlds.addAll(server.getWorlds());
}
return worlds;
}
// Try to find the world with name = selector
final World world = server.getWorld(selector);
if (world != null) {
worlds.add(world);
}
// If that fails, Is the argument something like "*" or "all"?
else if (selector.equalsIgnoreCase("*") || selector.equalsIgnoreCase("all")) {
worlds.addAll(server.getWorlds());
}
// We failed to understand the world target...
else {
throw new Exception(tl("invalidWorld"));
}
return worlds;
}
private boolean canUpdateAll(User user) {
return !ess.getSettings().isWorldTimePermissions() // First check if per world permissions are enabled, if not, return true.
|| user == null || user.isAuthorized("essentials.time.world.all");
}
private boolean canUpdateWorld(User user, World world) {
return canUpdateAll(user) || user.isAuthorized("essentials.time.world." + normalizeWorldName(world));
}
private String normalizeWorldName(World world) {
return world.getName().toLowerCase().replaceAll("\\s+", "_");
}
@Override
protected List<String> getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) {
final User user = ess.getUser(sender.getPlayer());
if (args.length == 1) {
if (user == null || user.isAuthorized("essentials.time.set")) {
return Lists.newArrayList("set", "add");
} else {
return Collections.emptyList();
}
} else if (args.length == 2 && args[0].equalsIgnoreCase("set")) {
return Lists.newArrayList("sunrise", "day", "morning", "noon", "afternoon", "sunset", "night", "midnight");
// TODO: handle tab completion for add
} else if (args.length == 3 && (args[0].equalsIgnoreCase("set") || args[0].equalsIgnoreCase("add"))) {
List<String> worlds = Lists.newArrayList();
for (World world : server.getWorlds()) {
if (user == null || user.isAuthorized("essentials.time.world." + normalizeWorldName(world))) {
worlds.add(world.getName());
}
}
if (user == null || user.isAuthorized("essentials.time.world.all")) {
worlds.add("*");
}
return worlds;
} else {
return Collections.emptyList();
}
}
}
class WorldNameComparator implements Comparator<World> {
@Override
public int compare(final World a, final World b) {
return a.getName().compareTo(b.getName());
}
}
@@ -1,115 +0,0 @@
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.JailStatusChangeEvent;
import org.bukkit.Server;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandtogglejail extends EssentialsCommand {
public Commandtogglejail() {
super("togglejail");
}
@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();
}
final User player = getPlayer(server, args, 0, true, true);
if (args.length >= 2 && !player.isJailed()) {
if (!player.getBase().isOnline()) {
if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.togglejail.offline")) {
sender.sendMessage(tl("mayNotJailOffline"));
return;
}
} else {
if (player.isAuthorized("essentials.jail.exempt")) {
sender.sendMessage(tl("mayNotJail"));
return;
}
}
final User controller = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null;
final JailStatusChangeEvent event = new JailStatusChangeEvent(player, controller, true);
ess.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
if (player.getBase().isOnline()) {
ess.getJails().sendToJail(player, args[1]);
} else {
// Check if jail exists
ess.getJails().getJail(args[1]);
}
player.setJailed(true);
player.sendMessage(tl("userJailed"));
player.setJail(null);
player.setJail(args[1]);
long timeDiff = 0;
if (args.length > 2) {
final String time = getFinalArg(args, 2);
timeDiff = DateUtil.parseDateDiff(time, true);
player.setJailTimeout(timeDiff);
}
sender.sendMessage((timeDiff > 0 ? tl("playerJailedFor", player.getName(), DateUtil.formatDateDiff(timeDiff)) : tl("playerJailed", player.getName())));
}
return;
}
if (args.length >= 2 && player.isJailed() && !args[1].equalsIgnoreCase(player.getJail())) {
sender.sendMessage(tl("jailAlreadyIncarcerated", player.getJail()));
return;
}
if (args.length >= 2 && player.isJailed() && args[1].equalsIgnoreCase(player.getJail())) {
final String time = getFinalArg(args, 2);
final long timeDiff = DateUtil.parseDateDiff(time, true);
player.setJailTimeout(timeDiff);
sender.sendMessage(tl("jailSentenceExtended", DateUtil.formatDateDiff(timeDiff)));
return;
}
if (args.length == 1 || (args.length == 2 && args[1].equalsIgnoreCase(player.getJail()))) {
if (!player.isJailed()) {
throw new NotEnoughArgumentsException();
}
final User controller = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null;
final JailStatusChangeEvent event = new JailStatusChangeEvent(player, controller, false);
ess.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
player.setJailed(false);
player.setJailTimeout(0);
player.sendMessage(tl("jailReleasedPlayerNotify"));
player.setJail(null);
if (player.getBase().isOnline()) {
player.getTeleport().back();
}
sender.sendMessage(tl("jailReleased", player.getName()));
}
}
}
@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) {
try {
return new ArrayList<>(ess.getJails().getList());
} catch (Exception e) {
return Collections.emptyList();
}
} else {
return COMMON_DATE_DIFFS;
}
}
}
@@ -1,60 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandtpa extends EssentialsCommand {
public Commandtpa() {
super("tpa");
}
@Override
public void run(Server server, User user, String commandLabel, String[] args) throws Exception {
if (args.length < 1) {
throw new NotEnoughArgumentsException();
}
User player = getPlayer(server, user, args, 0);
if (user.getName().equalsIgnoreCase(player.getName())) {
throw new NotEnoughArgumentsException();
}
if (!player.isTeleportEnabled()) {
throw new Exception(tl("teleportDisabled", player.getDisplayName()));
}
if (user.getWorld() != player.getWorld() && ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + player.getWorld().getName())) {
throw new Exception(tl("noPerm", "essentials.worlds." + player.getWorld().getName()));
}
// Don't let sender request teleport twice to the same player.
if (user.getConfigUUID().equals(player.getTeleportRequest()) && player.hasOutstandingTeleportRequest() // Check timeout
&& player.isTpRequestHere() == false) { // Make sure the last teleport request was actually tpa and not tpahere
throw new Exception(tl("requestSentAlready", player.getDisplayName()));
}
if (!player.isIgnoredPlayer(user)) {
player.requestTeleport(user, false);
player.sendMessage(tl("teleportRequest", user.getDisplayName()));
player.sendMessage(tl("typeTpaccept"));
player.sendMessage(tl("typeTpdeny"));
if (ess.getSettings().getTpaAcceptCancellation() != 0) {
player.sendMessage(tl("teleportRequestTimeoutInfo", ess.getSettings().getTpaAcceptCancellation()));
}
}
user.sendMessage(tl("requestSent", player.getDisplayName()));
user.sendMessage(tl("typeTpacancel"));
}
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
if (args.length == 1) {
return getPlayers(server, user);
} else {
return Collections.emptyList();
}
}
}
@@ -1,72 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.Teleport;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import static com.earth2me.essentials.I18n.tl;
public class Commandtpaccept extends EssentialsCommand {
public Commandtpaccept() {
super("tpaccept");
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final User requester;
try {
requester = ess.getUser(user.getTeleportRequest());
} catch (Exception ex) {
throw new Exception(tl("noPendingRequest"));
}
if (!requester.getBase().isOnline()) {
throw new Exception(tl("noPendingRequest"));
}
if (user.isTpRequestHere() && ((!requester.isAuthorized("essentials.tpahere") && !requester.isAuthorized("essentials.tpaall")) || (user.getWorld() != requester.getWorld() && ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + user.getWorld().getName())))) {
throw new Exception(tl("noPendingRequest"));
}
if (!user.isTpRequestHere() && (!requester.isAuthorized("essentials.tpa") || (user.getWorld() != requester.getWorld() && ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + requester.getWorld().getName())))) {
throw new Exception(tl("noPendingRequest"));
}
if (args.length > 0 && !requester.getName().contains(args[0])) {
throw new Exception(tl("noPendingRequest"));
}
if (!user.hasOutstandingTeleportRequest()) {
user.requestTeleport(null, false);
throw new Exception(tl("requestTimedOut"));
}
final Trade charge = new Trade(this.getName(), ess);
user.sendMessage(tl("requestAccepted"));
requester.sendMessage(tl("requestAcceptedFrom", user.getDisplayName()));
try {
if (user.isTpRequestHere()) {
final Location loc = user.getTpRequestLocation();
Teleport teleport = requester.getTeleport();
teleport.setTpType(Teleport.TeleportType.TPA);
teleport.teleportPlayer(user, user.getTpRequestLocation(), charge, TeleportCause.COMMAND);
requester.sendMessage(tl("teleporting", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
} else {
Teleport teleport = requester.getTeleport();
teleport.setTpType(Teleport.TeleportType.TPA);
teleport.teleport(user.getBase(), charge, TeleportCause.COMMAND);
}
} catch (Exception ex) {
user.sendMessage(tl("pendingTeleportCancelled"));
ess.showError(requester.getSource(), ex, commandLabel);
}
user.requestTeleport(null, false);
throw new NoChargeException();
}
}
@@ -1,28 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import static com.earth2me.essentials.I18n.tl;
public class Commandtpdeny extends EssentialsCommand {
public Commandtpdeny() {
super("tpdeny");
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (user.getTeleportRequest() == null) {
throw new Exception(tl("noPendingRequest"));
}
final User player = ess.getUser(user.getTeleportRequest());
if (player == null) {
throw new Exception(tl("noPendingRequest"));
}
user.sendMessage(tl("requestDenied"));
player.sendMessage(tl("requestDeniedFrom", user.getDisplayName()));
user.requestTeleport(null, false);
}
}
@@ -1,30 +0,0 @@
package com.earth2me.essentials.craftbukkit;
import com.earth2me.essentials.User;
import net.ess3.api.IEssentials;
import org.bukkit.BanEntry;
import org.bukkit.BanList;
import java.util.Set;
public class BanLookup {
public static Boolean isBanned(IEssentials ess, User user) {
return isBanned(ess, user.getName());
}
public static Boolean isBanned(IEssentials ess, String name) {
return getBanEntry(ess, name) != null;
}
public static BanEntry getBanEntry(IEssentials ess, String name) {
Set<BanEntry> benteries = ess.getServer().getBanList(BanList.Type.NAME).getBanEntries();
for (BanEntry banEnt : benteries) {
if (banEnt.getTarget().equals(name)) {
return banEnt;
}
}
return null;
}
}
@@ -1,227 +0,0 @@
package com.earth2me.essentials.items;
import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.IConf;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.Color;
import org.bukkit.DyeColor;
import org.bukkit.FireworkEffect;
import org.bukkit.Material;
import org.bukkit.block.Banner;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.*;
import org.bukkit.potion.Potion;
import org.bukkit.potion.PotionEffect;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import static com.earth2me.essentials.I18n.tl;
public abstract class AbstractItemDb implements IConf, net.ess3.api.IItemDb {
@Override
public List<ItemStack> getMatching(User user, String[] args) throws Exception {
List<ItemStack> is = new ArrayList<>();
if (args.length < 1) {
is.add(user.getItemInHand().clone());
} else if (args[0].equalsIgnoreCase("hand")) {
is.add(user.getItemInHand().clone());
} else if (args[0].equalsIgnoreCase("inventory") || args[0].equalsIgnoreCase("invent") || args[0].equalsIgnoreCase("all")) {
for (ItemStack stack : user.getBase().getInventory().getContents()) {
if (stack == null || stack.getType() == Material.AIR) {
continue;
}
is.add(stack.clone());
}
} else if (args[0].equalsIgnoreCase("blocks")) {
for (ItemStack stack : user.getBase().getInventory().getContents()) {
if (stack == null || stack.getType() == Material.AIR) {
continue;
}
is.add(stack.clone());
}
} else {
is.add(get(args[0]));
}
if (is.isEmpty() || is.get(0).getType() == Material.AIR) {
throw new Exception(tl("itemSellAir"));
}
return is;
}
@Override
public String serialize(ItemStack is) {
String mat = is.getType().name();
if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_12_2_R01) && is.getData().getData() != 0) {
mat = mat + ":" + is.getData().getData();
}
int quantity = is.getAmount();
StringBuilder sb = new StringBuilder(); // Add space AFTER you add something. We can trim at end.
sb.append(mat).append(" ").append(quantity).append(" ");
// ItemMeta applies to anything.
if (is.hasItemMeta()) {
ItemMeta meta = is.getItemMeta();
if (meta.hasDisplayName()) {
sb.append("name:").append(meta.getDisplayName().replaceAll(" ", "_")).append(" ");
}
if (meta.hasLore()) {
sb.append("lore:");
boolean first = true;
for (String s : meta.getLore()) {
// Add | before the line if it's not the first one. Easy but weird way
// to do this since we need each line separated by |
if (!first) {
sb.append("|");
}
first = false;
sb.append(s.replaceAll(" ", "_"));
}
sb.append(" ");
}
if (meta.hasEnchants()) {
for (Enchantment e : meta.getEnchants().keySet()) {
sb.append(e.getName().toLowerCase()).append(":").append(meta.getEnchantLevel(e)).append(" ");
}
}
Set<ItemFlag> flags = meta.getItemFlags();
if (flags != null && !flags.isEmpty()) {
sb.append("itemflags:");
boolean first = true;
for (ItemFlag flag : flags) {
if (!first) {
sb.append(",");
}
sb.append(flag.name());
first = false;
}
}
}
final Material material = is.getType();
switch (material) {
case WRITTEN_BOOK:
// Everything from http://wiki.ess3.net/wiki/Item_Meta#Books in that order.
// Interesting as I didn't see a way to do pages or chapters.
BookMeta bookMeta = (BookMeta) is.getItemMeta();
if (bookMeta.hasTitle()) {
sb.append("title:").append(bookMeta.getTitle()).append(" ");
}
if (bookMeta.hasAuthor()) {
sb.append("author:").append(bookMeta.getAuthor()).append(" ");
}
// Only other thing it could have is lore but that's done up there ^^^
break;
case ENCHANTED_BOOK:
EnchantmentStorageMeta enchantmentStorageMeta = (EnchantmentStorageMeta) is.getItemMeta();
for (Enchantment e : enchantmentStorageMeta.getStoredEnchants().keySet()) {
sb.append(e.getName().toLowerCase()).append(":").append(enchantmentStorageMeta.getStoredEnchantLevel(e)).append(" ");
}
break;
}
if (MaterialUtil.isFirework(material)) {
// Everything from http://wiki.ess3.net/wiki/Item_Meta#Fireworks in that order.
FireworkMeta fireworkMeta = (FireworkMeta) is.getItemMeta();
if (fireworkMeta.hasEffects()) {
for (FireworkEffect effect : fireworkMeta.getEffects()) {
if (effect.getColors() != null && !effect.getColors().isEmpty()) {
sb.append("color:");
boolean first = true;
for (Color c : effect.getColors()) {
if (!first) {
sb.append(","); // same thing as above.
}
sb.append(c.toString());
first = false;
}
sb.append(" ");
}
sb.append("shape:").append(effect.getType().name()).append(" ");
if (effect.getFadeColors() != null && !effect.getFadeColors().isEmpty()) {
sb.append("fade:");
boolean first = true;
for (Color c : effect.getFadeColors()) {
if (!first) {
sb.append(","); // same thing as above.
}
sb.append(c.toString());
first = false;
}
sb.append(" ");
}
}
sb.append("power:").append(fireworkMeta.getPower()).append(" ");
}
} else if (MaterialUtil.isPotion(material)) {
Potion potion = Potion.fromItemStack(is);
for (PotionEffect e : potion.getEffects()) {
// long but needs to be effect:speed power:2 duration:120 in that order.
sb.append("splash:").append(potion.isSplash()).append(" ").append("effect:").append(e.getType().getName().toLowerCase()).append(" ").append("power:").append(e.getAmplifier()).append(" ").append("duration:").append(e.getDuration() / 20).append(" ");
}
} else if (MaterialUtil.isPlayerHead(material, is.getData().getData())) {
// item stack with meta
SkullMeta skullMeta = (SkullMeta) is.getItemMeta();
if (skullMeta != null && skullMeta.hasOwner()) {
sb.append("player:").append(skullMeta.getOwner()).append(" ");
}
} else if (MaterialUtil.isBanner(material)) {
if (material.toString().contains("SHIELD")) {
// Hacky fix for accessing Shield meta - https://github.com/drtshock/Essentials/pull/745#issuecomment-234843795
BlockStateMeta shieldMeta = (BlockStateMeta) is.getItemMeta();
Banner shieldBannerMeta = (Banner) shieldMeta.getBlockState();
DyeColor baseDyeColor = shieldBannerMeta.getBaseColor();
if (baseDyeColor != null) {
int basecolor = baseDyeColor.getColor().asRGB();
sb.append("basecolor:").append(basecolor).append(" ");
}
for (org.bukkit.block.banner.Pattern p : shieldBannerMeta.getPatterns()) {
String type = p.getPattern().getIdentifier();
int color = p.getColor().getColor().asRGB();
sb.append(type).append(",").append(color).append(" ");
}
} else {
BannerMeta bannerMeta = (BannerMeta) is.getItemMeta();
if (bannerMeta != null) {
DyeColor baseDyeColor = bannerMeta.getBaseColor();
if (baseDyeColor == null) {
baseDyeColor = MaterialUtil.getColorOf(material);
}
if (baseDyeColor != null) {
int basecolor = baseDyeColor
.getColor()
.asRGB();
sb.append("basecolor:").append(basecolor).append(" ");
}
for (org.bukkit.block.banner.Pattern p : bannerMeta.getPatterns()) {
String type = p.getPattern().getIdentifier();
int color = p.getColor().getColor().asRGB();
sb.append(type).append(",").append(color).append(" ");
}
}
}
} else if (MaterialUtil.isLeatherArmor(material)) {
LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) is.getItemMeta();
int rgb = leatherArmorMeta.getColor().asRGB();
sb.append("color:").append(rgb).append(" ");
}
return sb.toString().trim().replaceAll("§", "&");
}
}
@@ -1,695 +0,0 @@
package com.earth2me.essentials.metrics;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicePriority;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.zip.GZIPOutputStream;
/**
* bStats collects some data for plugin authors.
* <p>
* Check out https://bStats.org/ to learn more about bStats!
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public class Metrics {
static {
// You can use the property to disable the check in your test environment
if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) {
// Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D
final String defaultPackage = new String(
new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'});
final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
// We want to make sure nobody just copy & pastes the example and use the wrong package names
if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) {
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
}
}
}
// The version of this bStats class
public static final int B_STATS_VERSION = 1;
// The url to which the data is sent
private static final String URL = "https://bStats.org/submitData/bukkit";
// Is bStats enabled on this server?
private boolean enabled;
// Should failed requests be logged?
private static boolean logFailedRequests;
// Should the sent data be logged?
private static boolean logSentData;
// Should the response text be logged?
private static boolean logResponseStatusText;
// The uuid of the server
private static String serverUUID;
// The plugin
private final Plugin plugin;
// A list with all custom charts
private final List<CustomChart> charts = new ArrayList<>();
/**
* Class constructor.
*
* @param plugin The plugin which stats should be submitted.
*/
public Metrics(Plugin plugin) {
if (plugin == null) {
throw new IllegalArgumentException("Plugin cannot be null!");
}
this.plugin = plugin;
// Get the config file
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
File configFile = new File(bStatsFolder, "config.yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
// Check if the config file exists
if (!config.isSet("serverUuid")) {
// Add default values
config.addDefault("enabled", true);
// Every server gets it's unique random id.
config.addDefault("serverUuid", UUID.randomUUID().toString());
// Should failed request be logged?
config.addDefault("logFailedRequests", false);
// Should the sent data be logged?
config.addDefault("logSentData", false);
// Should the response text be logged?
config.addDefault("logResponseStatusText", false);
// Inform the server owners about bStats
config.options().header(
"bStats collects some data for plugin authors like how many servers are using their plugins.\n" +
"To honor their work, you should not disable it.\n" +
"This has nearly no effect on the server performance!\n" +
"Check out https://bStats.org/ to learn more :)"
).copyDefaults(true);
try {
config.save(configFile);
} catch (IOException ignored) { }
}
// Load the data
enabled = config.getBoolean("enabled", true);
serverUUID = config.getString("serverUuid");
logFailedRequests = config.getBoolean("logFailedRequests", false);
logSentData = config.getBoolean("logSentData", false);
logResponseStatusText = config.getBoolean("logResponseStatusText", false);
if (enabled) {
boolean found = false;
// Search for all other bStats Metrics classes to see if we are the first one
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
try {
service.getField("B_STATS_VERSION"); // Our identifier :)
found = true; // We aren't the first
break;
} catch (NoSuchFieldException ignored) { }
}
// Register our service
Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal);
if (!found) {
// We are the first!
startSubmitting();
}
}
}
/**
* Checks if bStats is enabled.
*
* @return Whether bStats is enabled or not.
*/
public boolean isEnabled() {
return enabled;
}
/**
* Adds a custom chart.
*
* @param chart The chart to add.
*/
public void addCustomChart(CustomChart chart) {
if (chart == null) {
throw new IllegalArgumentException("Chart cannot be null!");
}
charts.add(chart);
}
/**
* Starts the Scheduler which submits our data every 30 minutes.
*/
private void startSubmitting() {
final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (!plugin.isEnabled()) { // Plugin was disabled
timer.cancel();
return;
}
// Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler
// Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;)
Bukkit.getScheduler().runTask(plugin, () -> submitData());
}
}, 1000 * 60 * 5, 1000 * 60 * 30);
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
// WARNING: Just don't do it!
}
/**
* Gets the plugin specific data.
* This method is called using Reflection.
*
* @return The plugin specific data.
*/
public JSONObject getPluginData() {
JSONObject data = new JSONObject();
String pluginName = "EssentialsX";
String pluginVersion = plugin.getDescription().getVersion();
data.put("pluginName", pluginName); // Append the name of the plugin
data.put("pluginVersion", pluginVersion); // Append the version of the plugin
JSONArray customCharts = new JSONArray();
for (CustomChart customChart : charts) {
// Add the data of the custom charts
JSONObject chart = customChart.getRequestJsonObject();
if (chart == null) { // If the chart is null, we skip it
continue;
}
customCharts.add(chart);
}
data.put("customCharts", customCharts);
return data;
}
/**
* Gets the server specific data.
*
* @return The server specific data.
*/
private JSONObject getServerData() {
// Minecraft specific data
int playerAmount;
try {
// Around MC 1.8 the return type was changed to a collection from an array,
// This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class)
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
} catch (Exception e) {
playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed
}
int onlineMode = Bukkit.getOnlineMode() ? 1 : 0;
String bukkitVersion = Bukkit.getVersion();
// OS/Java specific data
String javaVersion = System.getProperty("java.version");
String osName = System.getProperty("os.name");
String osArch = System.getProperty("os.arch");
String osVersion = System.getProperty("os.version");
int coreCount = Runtime.getRuntime().availableProcessors();
JSONObject data = new JSONObject();
data.put("serverUUID", serverUUID);
data.put("playerAmount", playerAmount);
data.put("onlineMode", onlineMode);
data.put("bukkitVersion", bukkitVersion);
data.put("javaVersion", javaVersion);
data.put("osName", osName);
data.put("osArch", osArch);
data.put("osVersion", osVersion);
data.put("coreCount", coreCount);
return data;
}
/**
* Collects the data and sends it afterwards.
*/
private void submitData() {
final JSONObject data = getServerData();
JSONArray pluginData = new JSONArray();
// Search for all other bStats Metrics classes to get their plugin data
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
try {
service.getField("B_STATS_VERSION"); // Our identifier :)
for (RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service)) {
try {
pluginData.add(provider.getService().getMethod("getPluginData").invoke(provider.getProvider()));
} catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { }
}
} catch (NoSuchFieldException ignored) { }
}
data.put("plugins", pluginData);
// Create a new thread for the connection to the bStats server
new Thread(new Runnable() {
@Override
public void run() {
try {
// Send the data
sendData(plugin, data);
} catch (Exception e) {
// Something went wrong! :(
if (logFailedRequests) {
plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e);
}
}
}
}).start();
}
/**
* Sends the data to the bStats server.
*
* @param plugin Any plugin. It's just used to get a logger instance.
* @param data The data to send.
* @throws Exception If the request failed.
*/
private static void sendData(Plugin plugin, JSONObject data) throws Exception {
if (data == null) {
throw new IllegalArgumentException("Data cannot be null!");
}
if (Bukkit.isPrimaryThread()) {
throw new IllegalAccessException("This method must not be called from the main thread!");
}
if (logSentData) {
plugin.getLogger().info("Sending data to bStats: " + data.toString());
}
HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
// Compress the data to save bandwidth
byte[] compressedData = compress(data.toString());
// Add headers
connection.setRequestMethod("POST");
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
// Send data
connection.setDoOutput(true);
DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.write(compressedData);
outputStream.flush();
outputStream.close();
InputStream inputStream = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder builder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
}
bufferedReader.close();
if (logResponseStatusText) {
plugin.getLogger().info("Sent data to bStats and received response: " + builder.toString());
}
}
/**
* Gzips the given String.
*
* @param str The string to gzip.
* @return The gzipped String.
* @throws IOException If the compression failed.
*/
private static byte[] compress(final String str) throws IOException {
if (str == null) {
return null;
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
gzip.write(str.getBytes(StandardCharsets.UTF_8));
gzip.close();
return outputStream.toByteArray();
}
/**
* Represents a custom chart.
*/
public static abstract class CustomChart {
// The id of the chart
final String chartId;
/**
* Class constructor.
*
* @param chartId The id of the chart.
*/
CustomChart(String chartId) {
if (chartId == null || chartId.isEmpty()) {
throw new IllegalArgumentException("ChartId cannot be null or empty!");
}
this.chartId = chartId;
}
private JSONObject getRequestJsonObject() {
JSONObject chart = new JSONObject();
chart.put("chartId", chartId);
try {
JSONObject data = getChartData();
if (data == null) {
// If the data is null we don't send the chart.
return null;
}
chart.put("data", data);
} catch (Throwable t) {
if (logFailedRequests) {
Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t);
}
return null;
}
return chart;
}
protected abstract JSONObject getChartData() throws Exception;
}
/**
* Represents a custom simple pie.
*/
public static class SimplePie extends CustomChart {
private final Callable<String> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SimplePie(String chartId, Callable<String> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JSONObject getChartData() throws Exception {
JSONObject data = new JSONObject();
String value = callable.call();
if (value == null || value.isEmpty()) {
// Null = skip the chart
return null;
}
data.put("value", value);
return data;
}
}
/**
* Represents a custom advanced pie.
*/
public static class AdvancedPie extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JSONObject getChartData() throws Exception {
JSONObject data = new JSONObject();
JSONObject values = new JSONObject();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() == 0) {
continue; // Skip this invalid
}
allSkipped = false;
values.put(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
data.put("values", values);
return data;
}
}
/**
* Represents a custom drilldown pie.
*/
public static class DrilldownPie extends CustomChart {
private final Callable<Map<String, Map<String, Integer>>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
super(chartId);
this.callable = callable;
}
@Override
public JSONObject getChartData() throws Exception {
JSONObject data = new JSONObject();
JSONObject values = new JSONObject();
Map<String, Map<String, Integer>> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean reallyAllSkipped = true;
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
JSONObject value = new JSONObject();
boolean allSkipped = true;
for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
value.put(valueEntry.getKey(), valueEntry.getValue());
allSkipped = false;
}
if (!allSkipped) {
reallyAllSkipped = false;
values.put(entryValues.getKey(), value);
}
}
if (reallyAllSkipped) {
// Null = skip the chart
return null;
}
data.put("values", values);
return data;
}
}
/**
* Represents a custom single line chart.
*/
public static class SingleLineChart extends CustomChart {
private final Callable<Integer> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SingleLineChart(String chartId, Callable<Integer> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JSONObject getChartData() throws Exception {
JSONObject data = new JSONObject();
int value = callable.call();
if (value == 0) {
// Null = skip the chart
return null;
}
data.put("value", value);
return data;
}
}
/**
* Represents a custom multi line chart.
*/
public static class MultiLineChart extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public MultiLineChart(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JSONObject getChartData() throws Exception {
JSONObject data = new JSONObject();
JSONObject values = new JSONObject();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() == 0) {
continue; // Skip this invalid
}
allSkipped = false;
values.put(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
data.put("values", values);
return data;
}
}
/**
* Represents a custom simple bar chart.
*/
public static class SimpleBarChart extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SimpleBarChart(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JSONObject getChartData() throws Exception {
JSONObject data = new JSONObject();
JSONObject values = new JSONObject();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
for (Map.Entry<String, Integer> entry : map.entrySet()) {
JSONArray categoryValues = new JSONArray();
categoryValues.add(entry.getValue());
values.put(entry.getKey(), categoryValues);
}
data.put("values", values);
return data;
}
}
/**
* Represents a custom advanced bar chart.
*/
public static class AdvancedBarChart extends CustomChart {
private final Callable<Map<String, int[]>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public AdvancedBarChart(String chartId, Callable<Map<String, int[]>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JSONObject getChartData() throws Exception {
JSONObject data = new JSONObject();
JSONObject values = new JSONObject();
Map<String, int[]> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, int[]> entry : map.entrySet()) {
if (entry.getValue().length == 0) {
continue; // Skip this invalid
}
allSkipped = false;
JSONArray categoryValues = new JSONArray();
for (int categoryValue : entry.getValue()) {
categoryValues.add(categoryValue);
}
values.put(entry.getKey(), categoryValues);
}
if (allSkipped) {
// Null = skip the chart
return null;
}
data.put("values", values);
return data;
}
}
}
@@ -1,17 +0,0 @@
package com.earth2me.essentials.perm.impl;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class BPermissions2Handler extends AbstractVaultHandler {
@Override
public boolean canBuild(final Player base, final String group) {
return hasPermission(base, "bPermissions.build");
}
@Override
public boolean tryProvider() {
return super.canLoad() && Bukkit.getPluginManager().getPlugin("bPermissions") != null;
}
}
@@ -1,16 +0,0 @@
package com.earth2me.essentials.perm.impl;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class PermissionsExHandler extends AbstractVaultHandler {
@Override
public boolean canBuild(final Player base, final String group) {
return base != null && chat.getPlayerInfoBoolean(base.getWorld().getName(), base, "build", false);
}
@Override
public boolean tryProvider() {
return super.canLoad() && Bukkit.getPluginManager().getPlugin("PermissionsEx") != null;
}
}
@@ -1,16 +0,0 @@
package com.earth2me.essentials.perm.impl;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class PrivilegesHandler extends AbstractVaultHandler {
@Override
public boolean canBuild(Player base, String group) {
return hasPermission(base, "privileges.build");
}
@Override
public boolean tryProvider() {
return super.canLoad() && Bukkit.getPluginManager().getPlugin("Privileges") != null;
}
}
@@ -1,16 +0,0 @@
package com.earth2me.essentials.perm.impl;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class SimplyPermsHandler extends AbstractVaultHandler {
@Override
public boolean canBuild(Player base, String group) {
return hasPermission(base, "permissions.allow.build");
}
@Override
public boolean tryProvider() {
return super.canLoad() && Bukkit.getPluginManager().getPlugin("SimplyPerms") != null;
}
}
@@ -1,80 +0,0 @@
package com.earth2me.essentials.perm.impl;
import com.earth2me.essentials.perm.IPermissionsHandler;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.Arrays;
import java.util.List;
public class SuperpermsHandler implements IPermissionsHandler {
@Override
public String getGroup(final Player base) {
return null;
}
@Override
public List<String> getGroups(final Player base) {
return null;
}
@Override
public boolean canBuild(final Player base, final String group) {
return false;
}
@Override
public boolean inGroup(final Player base, final String group) {
return hasPermission(base, "group." + group);
}
@Override
public boolean hasPermission(final Player base, String node) {
String permCheck = node;
int index;
while (true) {
if (base.isPermissionSet(permCheck)) {
return base.hasPermission(permCheck);
}
index = node.lastIndexOf('.');
if (index < 1) {
return base.hasPermission("*");
}
node = node.substring(0, index);
permCheck = node + ".*";
}
}
@Override
public String getPrefix(final Player base) {
return null;
}
@Override
public String getSuffix(final Player base) {
return null;
}
@Override
public boolean tryProvider() {
return getEnabledPermsPlugin() != null;
}
public String getEnabledPermsPlugin() {
String enabledPermsPlugin = null;
List<String> specialCasePlugins = Arrays.asList("PermissionsEx", "GroupManager",
"SimplyPerms", "Privileges", "bPermissions", "zPermissions", "PermissionsBukkit",
"DroxPerms", "xPerms", "LuckPerms");
for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
if (specialCasePlugins.contains(plugin.getName())) {
enabledPermsPlugin = plugin.getName();
break;
}
}
return enabledPermsPlugin;
}
}
@@ -1,222 +0,0 @@
package com.earth2me.essentials.register.payment;
import org.bukkit.plugin.Plugin;
/**
* Interface to be implemented by a payment method.
*
* @author Nijikokun <nijikokun@shortmail.com> (@nijikokun)
* @copyright Copyright (C) 2011
* @license AOL license <http://aol.nexua.org>
*/
public interface Method {
/**
* Encodes the Plugin into an Object disguised as the Plugin. If you want the original Plugin Class you must cast it
* to the correct Plugin, to do so you have to verify the name and or version then cast.
* <p/>
* <pre>
* if(method.getName().equalsIgnoreCase("iConomy"))
* iConomy plugin = ((iConomy)method.getPlugin());</pre>
*
* @return <code>Object</code>
*
* @see #getName()
* @see #getVersion()
*/
Object getPlugin();
/**
* Returns the actual name of this method.
*
* @return <code>String</code> Plugin name.
*/
String getName();
/**
* Returns the reported name of this method.
*
* @return <code>String</code> Plugin name.
*/
String getLongName();
/**
* Returns the actual version of this method.
*
* @return <code>String</code> Plugin version.
*/
String getVersion();
/**
* Returns the amount of decimal places that get stored NOTE: it will return -1 if there is no rounding
*
* @return <code>int</code> for each decimal place
*/
int fractionalDigits();
/**
* Formats amounts into this payment methods style of currency display.
*
* @param amount Double
*
* @return <code>String</code> - Formatted Currency Display.
*/
String format(double amount);
/**
* Allows the verification of bank API existence in this payment method.
*
* @return <code>boolean</code>
*/
boolean hasBanks();
/**
* Determines the existence of a bank via name.
*
* @param bank Bank name
*
* @return <code>boolean</code>
*
* @see #hasBanks
*/
boolean hasBank(String bank);
/**
* Determines the existence of an account via name.
*
* @param name Account name
*
* @return <code>boolean</code>
*/
boolean hasAccount(String name);
/**
* Check to see if an account <code>name</code> is tied to a <code>bank</code>.
*
* @param bank Bank name
* @param name Account name
*
* @return <code>boolean</code>
*/
boolean hasBankAccount(String bank, String name);
/**
* Forces an account creation
*
* @param name Account name
*
* @return <code>boolean</code>
*/
boolean createAccount(String name);
/**
* Forces an account creation
*
* @param name Account name
* @param balance Initial account balance
*
* @return <code>boolean</code>
*/
boolean createAccount(String name, Double balance);
/**
* Returns a <code>MethodAccount</code> class for an account <code>name</code>.
*
* @param name Account name
*
* @return <code>MethodAccount</code> <em>or</em> <code>Null</code>
*/
MethodAccount getAccount(String name);
/**
* Returns a <code>MethodBankAccount</code> class for an account <code>name</code>.
*
* @param bank Bank name
* @param name Account name
*
* @return <code>MethodBankAccount</code> <em>or</em> <code>Null</code>
*/
MethodBankAccount getBankAccount(String bank, String name);
/**
* Checks to verify the compatibility between this Method and a plugin. Internal usage only, for the most part.
*
* @param plugin Plugin
*
* @return <code>boolean</code>
*/
boolean isCompatible(Plugin plugin);
/**
* Set Plugin data.
*
* @param plugin Plugin
*/
void setPlugin(Plugin plugin);
/**
* Contains Calculator and Balance functions for Accounts.
*/
interface MethodAccount {
double balance();
boolean set(double amount);
boolean add(double amount);
boolean subtract(double amount);
boolean multiply(double amount);
boolean divide(double amount);
boolean hasEnough(double amount);
boolean hasOver(double amount);
boolean hasUnder(double amount);
boolean isNegative();
boolean remove();
@Override
String toString();
}
/**
* Contains Calculator and Balance functions for Bank Accounts.
*/
interface MethodBankAccount {
double balance();
String getBankName();
int getBankId();
boolean set(double amount);
boolean add(double amount);
boolean subtract(double amount);
boolean multiply(double amount);
boolean divide(double amount);
boolean hasEnough(double amount);
boolean hasOver(double amount);
boolean hasUnder(double amount);
boolean isNegative();
boolean remove();
@Override
String toString();
}
}
@@ -1,245 +0,0 @@
package com.earth2me.essentials.register.payment;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import java.util.HashSet;
import java.util.Set;
/**
* The <code>Methods</code> initializes Methods that utilize the Method interface based on a "first come, first served"
* basis.
* <p/>
* Allowing you to check whether a payment method exists or not.
* <p/>
* Methods also allows you to set a preferred method of payment before it captures payment plugins in the initialization
* process.
* <p/>
* in
* <code>bukkit.yml</code>: <blockquote><pre>
* economy:
* preferred: "iConomy"
* </pre></blockquote>
*
* @author: Nijikokun <nijikokun@shortmail.com> (@nijikokun) @copyright: Copyright (C) 2011 @license: AOL license
* <http://aol.nexua.org>
*/
public class Methods {
private static String version = null;
private static boolean self = false;
private static Method Method = null;
private static String preferred = "";
private static final Set<Method> Methods = new HashSet<Method>();
private static final Set<String> Dependencies = new HashSet<String>();
private static final Set<Method> Attachables = new HashSet<Method>();
static {
_init();
}
/**
* Implement all methods along with their respective name & class.
*/
private static void _init() {
addMethod("Vault", new com.earth2me.essentials.register.payment.methods.VaultEco());
}
/**
* Used by the plugin to setup version
*
* @param v version
*/
public static void setVersion(String v) {
version = v;
}
/**
* Use to reset methods during disable
*/
public static void reset() {
version = null;
self = false;
Method = null;
preferred = "";
Attachables.clear();
}
/**
* Use to get version of Register plugin
*
* @return version
*/
public static String getVersion() {
return version;
}
/**
* Returns an array of payment method names that have been loaded through the <code>_init</code> method.
*
* @return <code>Set<String></code> - Array of payment methods that are loaded.
*
* @see #setMethod(org.bukkit.plugin.Plugin)
*/
public static Set<String> getDependencies() {
return Dependencies;
}
/**
* Interprets Plugin class data to verify whether it is compatible with an existing payment method to use for
* payments and other various economic activity.
*
* @param plugin Plugin data from bukkit, Internal Class file.
*
* @return Method <em>or</em> Null
*/
public static Method createMethod(Plugin plugin) {
for (Method method : Methods) {
if (method.isCompatible(plugin)) {
method.setPlugin(plugin);
return method;
}
}
return null;
}
private static void addMethod(String name, Method method) {
Dependencies.add(name);
Methods.add(method);
}
/**
* Verifies if Register has set a payment method for usage yet.
*
* @return <code>boolean</code>
*
* @see #setMethod(org.bukkit.plugin.Plugin)
* @see #checkDisabled(org.bukkit.plugin.Plugin)
*/
public static boolean hasMethod() {
return (Method != null);
}
/**
* Checks Plugin Class against a multitude of checks to verify it's usability as a payment method.
*
* @param <code>PluginManager</code> the plugin manager for the server
*
* @return <code>boolean</code> True on success, False on failure.
*/
public static boolean setMethod(PluginManager manager) {
if (hasMethod()) {
return true;
}
if (self) {
self = false;
return false;
}
int count = 0;
boolean match = false;
Plugin plugin = null;
for (String name : getDependencies()) {
if (hasMethod()) {
break;
}
plugin = manager.getPlugin(name);
if (plugin == null || !plugin.isEnabled()) {
continue;
}
Method current = createMethod(plugin);
if (current == null) {
continue;
}
if (preferred.isEmpty()) {
Method = current;
} else {
Attachables.add(current);
}
}
if (!preferred.isEmpty()) {
do {
if (hasMethod()) {
match = true;
} else {
for (Method attached : Attachables) {
if (attached == null) {
continue;
}
if (hasMethod()) {
match = true;
break;
}
if (preferred.isEmpty()) {
Method = attached;
}
if (count == 0) {
if (preferred.equalsIgnoreCase(attached.getName())) {
Method = attached;
} else {
Method = attached;
}
}
}
count++;
}
} while (!match);
}
return hasMethod();
}
/**
* Sets the preferred economy
*
* @return <code>boolean</code>
*/
public static boolean setPreferred(String check) {
if (getDependencies().contains(check)) {
preferred = check;
return true;
}
return false;
}
/**
* Grab the existing and initialized (hopefully) Method Class.
*
* @return <code>Method</code> <em>or</em> <code>Null</code>
*/
public static Method getMethod() {
return Method;
}
/**
* Verify is a plugin is disabled, only does this if we there is an existing payment method initialized in
* Register.
*
* @param method Plugin data from bukkit, Internal Class file.
*
* @return <code>boolean</code>
*/
public static boolean checkDisabled(Plugin method) {
if (!hasMethod()) {
return true;
}
if (Method.isCompatible(method)) {
Method = null;
}
return (Method == null);
}
}
@@ -1,285 +0,0 @@
package com.earth2me.essentials.register.payment.methods;
import com.earth2me.essentials.register.payment.Method;
import net.milkbowl.vault.Vault;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
public class VaultEco implements Method {
private Vault vault;
private Economy economy;
@Override
public Vault getPlugin() {
return this.vault;
}
@Override
public boolean createAccount(String name, Double amount) {
if (hasAccount(name)) {
return false;
}
return false;
}
@Override
public String getName() {
return this.vault.getDescription().getName();
}
public String getEconomy() {
return economy == null ? "NoEco" : economy.getName();
}
@Override
public String getLongName() {
return getName().concat(" - Economy: ").concat(getEconomy());
}
@Override
public String getVersion() {
return this.vault.getDescription().getVersion();
}
@Override
public int fractionalDigits() {
return 0;
}
@Override
public String format(double amount) {
return this.economy.format(amount);
}
@Override
public boolean hasBanks() {
return this.economy.hasBankSupport();
}
@Override
public boolean hasBank(String bank) {
return this.economy.getBanks().contains(bank);
}
@Override
public boolean hasAccount(String name) {
return this.economy.hasAccount(name);
}
@Override
public boolean hasBankAccount(String bank, String name) {
return this.economy.isBankOwner(bank, name).transactionSuccess() || this.economy.isBankMember(bank, name).transactionSuccess();
}
@Override
public boolean createAccount(String name) {
return this.economy.createBank(name, "").transactionSuccess();
}
public boolean createAccount(String name, double balance) {
if (!this.economy.createBank(name, "").transactionSuccess()) {
return false;
}
return this.economy.bankDeposit(name, balance).transactionSuccess();
}
@Override
public MethodAccount getAccount(String name) {
if (!hasAccount(name)) {
return null;
}
return new VaultAccount(name, this.economy);
}
@Override
public MethodBankAccount getBankAccount(String bank, String name) {
if (!hasBankAccount(bank, name)) {
return null;
}
return new VaultBankAccount(bank, economy);
}
@Override
public boolean isCompatible(Plugin plugin) {
try {
RegisteredServiceProvider<Economy> ecoPlugin = plugin.getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
return plugin instanceof Vault && ecoPlugin != null && !ecoPlugin.getProvider().getName().equals("Essentials Economy");
} catch (LinkageError e) {
return false;
} catch (Exception e) {
return false;
}
}
@Override
public void setPlugin(Plugin plugin) {
this.vault = (Vault) plugin;
RegisteredServiceProvider<Economy> economyProvider = this.vault.getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
if (economyProvider != null) {
this.economy = economyProvider.getProvider();
}
}
public class VaultAccount implements MethodAccount {
private final String name;
private final Economy economy;
public VaultAccount(String name, Economy economy) {
this.name = name;
this.economy = economy;
}
@Override
public double balance() {
return this.economy.getBalance(this.name);
}
@Override
public boolean set(double amount) {
if (!this.economy.withdrawPlayer(this.name, this.balance()).transactionSuccess()) {
return false;
}
if (amount == 0) {
return true;
}
return this.economy.depositPlayer(this.name, amount).transactionSuccess();
}
@Override
public boolean add(double amount) {
return this.economy.depositPlayer(this.name, amount).transactionSuccess();
}
@Override
public boolean subtract(double amount) {
return this.economy.withdrawPlayer(this.name, amount).transactionSuccess();
}
@Override
public boolean multiply(double amount) {
double balance = this.balance();
return this.set(balance * amount);
}
@Override
public boolean divide(double amount) {
double balance = this.balance();
return this.set(balance / amount);
}
@Override
public boolean hasEnough(double amount) {
return (this.balance() >= amount);
}
@Override
public boolean hasOver(double amount) {
return (this.balance() > amount);
}
@Override
public boolean hasUnder(double amount) {
return (this.balance() < amount);
}
@Override
public boolean isNegative() {
return (this.balance() < 0);
}
@Override
public boolean remove() {
return this.set(0.0);
}
}
public class VaultBankAccount implements MethodBankAccount {
private final String bank;
private final Economy economy;
public VaultBankAccount(String bank, Economy economy) {
this.bank = bank;
this.economy = economy;
}
@Override
public String getBankName() {
return this.bank;
}
@Override
public int getBankId() {
return -1;
}
@Override
public double balance() {
return this.economy.bankBalance(this.bank).balance;
}
@Override
public boolean set(double amount) {
if (!this.economy.bankWithdraw(this.bank, this.balance()).transactionSuccess()) {
return false;
}
if (amount == 0) {
return true;
}
return this.economy.bankDeposit(this.bank, amount).transactionSuccess();
}
@Override
public boolean add(double amount) {
return this.economy.bankDeposit(this.bank, amount).transactionSuccess();
}
@Override
public boolean subtract(double amount) {
return this.economy.bankWithdraw(this.bank, amount).transactionSuccess();
}
@Override
public boolean multiply(double amount) {
double balance = this.balance();
return this.set(balance * amount);
}
@Override
public boolean divide(double amount) {
double balance = this.balance();
return this.set(balance / amount);
}
@Override
public boolean hasEnough(double amount) {
return (this.balance() >= amount);
}
@Override
public boolean hasOver(double amount) {
return (this.balance() > amount);
}
@Override
public boolean hasUnder(double amount) {
return (this.balance() < amount);
}
@Override
public boolean isNegative() {
return (this.balance() < 0);
}
@Override
public boolean remove() {
return this.set(0.0);
}
}
}
@@ -1,16 +0,0 @@
package com.earth2me.essentials.settings;
import com.earth2me.essentials.storage.MapValueType;
import com.earth2me.essentials.storage.StorageObject;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.bukkit.Location;
import java.util.HashMap;
import java.util.Map;
@Data @EqualsAndHashCode(callSuper = false) public class Jails implements StorageObject {
@MapValueType(Location.class)
private Map<String, Location> jails = new HashMap<String, Location>();
}
@@ -1,15 +0,0 @@
package com.earth2me.essentials.settings;
import com.earth2me.essentials.storage.MapValueType;
import com.earth2me.essentials.storage.StorageObject;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.bukkit.Location;
import java.util.HashMap;
import java.util.Map;
@Data @EqualsAndHashCode(callSuper = false) public class Spawns implements StorageObject {
@MapValueType(Location.class)
private Map<String, Location> spawns = new HashMap<>();
}
@@ -1,29 +0,0 @@
package com.earth2me.essentials.signs;
import com.earth2me.essentials.User;
import net.ess3.api.IEssentials;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class SignMail extends EssentialsSign {
public SignMail() {
super("Mail");
}
@Override
protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException {
final List<String> mail = player.getMails();
if (mail.isEmpty()) {
player.sendMessage(tl("noNewMail"));
return false;
}
for (String s : mail) {
player.sendMessage(s);
}
player.sendMessage(tl("markMailAsRead"));
return true;
}
}
@@ -1,57 +0,0 @@
package com.earth2me.essentials.storage;
import net.ess3.api.IEssentials;
import org.bukkit.Bukkit;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
public abstract class AbstractDelayedYamlFileReader<T extends StorageObject> implements Runnable {
private final transient File file;
private final transient Class<T> clazz;
protected final transient IEssentials plugin;
public AbstractDelayedYamlFileReader(final IEssentials ess, final File file, final Class<T> clazz) {
this.file = file;
this.clazz = clazz;
this.plugin = ess;
ess.runTaskAsynchronously(this);
}
public abstract void onStart();
@Override
public void run() {
onStart();
try {
final FileReader reader = new FileReader(file);
try {
final T object = new YamlStorageReader(reader, plugin).load(clazz);
onSuccess(object);
} finally {
try {
reader.close();
} catch (IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, "File can't be closed: " + file.toString(), ex);
}
}
} catch (FileNotFoundException ex) {
onException();
if (plugin.getSettings() == null || plugin.getSettings().isDebug()) {
Bukkit.getLogger().log(Level.INFO, "File not found: " + file.toString());
}
} catch (ObjectLoadException ex) {
onException();
Bukkit.getLogger().log(Level.SEVERE, "File broken: " + file.toString(), ex.getCause());
}
}
public abstract void onSuccess(T object);
public abstract void onException();
}
@@ -1,45 +0,0 @@
package com.earth2me.essentials.storage;
import net.ess3.api.IEssentials;
import org.bukkit.Bukkit;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.logging.Level;
public abstract class AbstractDelayedYamlFileWriter implements Runnable {
private final transient File file;
public AbstractDelayedYamlFileWriter(IEssentials ess, File file) {
this.file = file;
ess.runTaskAsynchronously(this);
}
public abstract StorageObject getObject();
@Override
public void run() {
PrintWriter pw = null;
try {
final StorageObject object = getObject();
final File folder = file.getParentFile();
if (!folder.exists()) {
folder.mkdirs();
}
pw = new PrintWriter(file);
new YamlStorageWriter(pw).save(object);
} catch (FileNotFoundException ex) {
Bukkit.getLogger().log(Level.SEVERE, file.toString(), ex);
} finally {
onFinish();
if (pw != null) {
pw.close();
}
}
}
public abstract void onFinish();
}
@@ -1,135 +0,0 @@
package com.earth2me.essentials.storage;
import com.earth2me.essentials.IConf;
import net.ess3.api.IEssentials;
import net.ess3.api.IReload;
import org.bukkit.Bukkit;
import java.io.File;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
public abstract class AsyncStorageObjectHolder<T extends StorageObject> implements IConf, IStorageObjectHolder<T>, IReload {
private transient T data;
private final transient ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final transient Class<T> clazz;
protected final transient IEssentials ess;
public AsyncStorageObjectHolder(final IEssentials ess, final Class<T> clazz) {
this.ess = ess;
this.clazz = clazz;
try {
this.data = clazz.newInstance();
} catch (IllegalAccessException ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
} catch (InstantiationException ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
}
}
@Override
public T getData() {
return data;
}
@Override
public void acquireReadLock() {
rwl.readLock().lock();
}
@Override
public void acquireWriteLock() {
while (rwl.getReadHoldCount() > 0) {
rwl.readLock().unlock();
}
rwl.writeLock().lock();
rwl.readLock().lock();
}
@Override
public void close() {
unlock();
}
@Override
public void unlock() {
if (rwl.isWriteLockedByCurrentThread()) {
rwl.writeLock().unlock();
new StorageObjectDataWriter();
}
while (rwl.getReadHoldCount() > 0) {
rwl.readLock().unlock();
}
}
@Override
public void reloadConfig() {
new StorageObjectDataReader();
}
@Override
public void onReload() {
new StorageObjectDataReader();
}
public abstract void finishRead();
public abstract void finishWrite();
public abstract File getStorageFile();
private class StorageObjectDataWriter extends AbstractDelayedYamlFileWriter {
StorageObjectDataWriter() {
super(ess, getStorageFile());
}
@Override
public StorageObject getObject() {
acquireReadLock();
return getData();
}
@Override
public void onFinish() {
unlock();
finishWrite();
}
}
private class StorageObjectDataReader extends AbstractDelayedYamlFileReader<T> {
StorageObjectDataReader() {
super(ess, getStorageFile(), clazz);
}
@Override
public void onStart() {
rwl.writeLock().lock();
}
@Override
public void onSuccess(final T object) {
if (object != null) {
data = object;
}
rwl.writeLock().unlock();
finishRead();
}
@Override
public void onException() {
if (data == null) {
try {
data = clazz.newInstance();
} catch (IllegalAccessException ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
} catch (InstantiationException ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
}
}
rwl.writeLock().unlock();
}
}
}
@@ -1,217 +0,0 @@
package com.earth2me.essentials.storage;
import com.earth2me.essentials.Enchantments;
import com.earth2me.essentials.utils.NumberUtil;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.MaterialData;
import org.bukkit.plugin.Plugin;
import org.yaml.snakeyaml.constructor.BaseConstructor;
import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor;
import org.yaml.snakeyaml.introspector.PropertyUtils;
import org.yaml.snakeyaml.nodes.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Locale;
public class BukkitConstructor extends CustomClassLoaderConstructor {
private final transient Plugin plugin;
public BukkitConstructor(final Class clazz, final Plugin plugin) {
super(clazz, plugin.getClass().getClassLoader());
this.plugin = plugin;
yamlClassConstructors.put(NodeId.scalar, new ConstructBukkitScalar());
yamlClassConstructors.put(NodeId.mapping, new ConstructBukkitMapping());
PropertyUtils propertyUtils = getPropertyUtils();
propertyUtils.setSkipMissingProperties(true);
setPropertyUtils(propertyUtils);
}
private Method constructScalarMethod = null;
protected String constructScalarRefl(ScalarNode scalarNode) {
try {
if (constructScalarMethod == null) {
constructScalarMethod = BaseConstructor.class.getDeclaredMethod("constructScalar", ScalarNode.class);
}
return (String) constructScalarMethod.invoke(this, scalarNode);
} catch (NoSuchMethodException
| SecurityException
| IllegalAccessException
| IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
private class ConstructBukkitScalar extends ConstructScalar {
@Override
public Object construct(final Node node) {
if (node.getType().equals(Material.class)) {
final String val = constructScalarRefl((ScalarNode) node);
return Material.matchMaterial(val);
}
if (node.getType().equals(MaterialData.class)) {
final String val = constructScalarRefl((ScalarNode) node);
if (val.isEmpty()) {
return null;
}
final String[] split = val.split("[:+',;.]", 2);
if (split.length == 0) {
return null;
}
Material mat = Material.matchMaterial(split[0]);
if (mat == null) {
return null;
}
byte data = 0;
if (split.length == 2 && NumberUtil.isInt(split[1])) {
data = Byte.parseByte(split[1]);
}
return new MaterialData(mat, data);
}
if (node.getType().equals(ItemStack.class)) {
final String val = constructScalarRefl((ScalarNode) node);
if (val.isEmpty()) {
return null;
}
final String[] split1 = val.split("\\W");
if (split1.length == 0) {
return null;
}
final String[] split2 = split1[0].split("[:+',;.]", 2);
if (split2.length == 0) {
return null;
}
Material mat = Material.matchMaterial(split2[0]);
if (mat == null) {
return null;
}
short data = 0;
if (split2.length == 2 && NumberUtil.isInt(split2[1])) {
data = Short.parseShort(split2[1]);
}
int size = mat.getMaxStackSize();
if (split1.length > 1 && NumberUtil.isInt(split1[1])) {
size = Integer.parseInt(split1[1]);
}
final ItemStack stack = new ItemStack(mat, size, data);
if (split1.length > 2) {
for (int i = 2; i < split1.length; i++) {
final String[] split3 = split1[0].split("[:+',;.]", 2);
if (split3.length < 1) {
continue;
}
Enchantment enchantment = Enchantments.getByName(split3[0]);
if (enchantment == null) {
continue;
}
int level = enchantment.getStartLevel();
if (split3.length == 2 && NumberUtil.isInt(split3[1])) {
level = Integer.parseInt(split3[1]);
}
if (level < enchantment.getStartLevel()) {
level = enchantment.getStartLevel();
}
if (level > enchantment.getMaxLevel()) {
level = enchantment.getMaxLevel();
}
stack.addUnsafeEnchantment(enchantment, level);
}
}
return stack;
}
if (node.getType().equals(EnchantmentLevel.class)) {
final String val = constructScalarRefl((ScalarNode) node);
if (val.isEmpty()) {
return null;
}
final String[] split = val.split("[:+',;.]", 2);
if (split.length == 0) {
return null;
}
Enchantment enchant = Enchantments.getByName(split[0]);
if (enchant == null) {
return null;
}
int level = enchant.getStartLevel();
if (split.length == 2 && NumberUtil.isInt(split[1])) {
level = Integer.parseInt(split[1]);
}
if (level < enchant.getStartLevel()) {
level = enchant.getStartLevel();
}
if (level > enchant.getMaxLevel()) {
level = enchant.getMaxLevel();
}
return new EnchantmentLevel(enchant, level);
}
return super.construct(node);
}
}
private class ConstructBukkitMapping extends ConstructMapping {
@Override
public Object construct(final Node node) {
if (node.getType().equals(Location.class)) {
//TODO: NPE checks
final MappingNode mnode = (MappingNode) node;
String worldName = "";
double x = 0, y = 0, z = 0;
float yaw = 0, pitch = 0;
if (mnode.getValue().size() < 4) {
return null;
}
for (NodeTuple nodeTuple : mnode.getValue()) {
final String key = constructScalarRefl((ScalarNode) nodeTuple.getKeyNode());
final ScalarNode snode = (ScalarNode) nodeTuple.getValueNode();
if (key.equalsIgnoreCase("world")) {
worldName = constructScalarRefl(snode);
}
if (key.equalsIgnoreCase("x")) {
x = Double.parseDouble(constructScalarRefl(snode));
}
if (key.equalsIgnoreCase("y")) {
y = Double.parseDouble(constructScalarRefl(snode));
}
if (key.equalsIgnoreCase("z")) {
z = Double.parseDouble(constructScalarRefl(snode));
}
if (key.equalsIgnoreCase("yaw")) {
yaw = Float.parseFloat(constructScalarRefl(snode));
}
if (key.equalsIgnoreCase("pitch")) {
pitch = Float.parseFloat(constructScalarRefl(snode));
}
}
if (worldName == null || worldName.isEmpty()) {
return null;
}
final World world = Bukkit.getWorld(worldName);
if (world == null) {
return null;
}
return new Location(world, x, y, z, yaw, pitch);
}
return super.construct(node);
}
}
}
@@ -1,8 +0,0 @@
package com.earth2me.essentials.storage;
import java.lang.annotation.*;
@Target(ElementType.FIELD) @Documented @Retention(RetentionPolicy.RUNTIME) public @interface Comment {
String[] value() default "";
}
@@ -1,67 +0,0 @@
package com.earth2me.essentials.storage;
import org.bukkit.enchantments.Enchantment;
import java.util.Map.Entry;
public class EnchantmentLevel implements Entry<Enchantment, Integer> {
private Enchantment enchantment;
private int level;
public EnchantmentLevel(final Enchantment enchantment, final int level) {
this.enchantment = enchantment;
this.level = level;
}
public Enchantment getEnchantment() {
return enchantment;
}
public void setEnchantment(final Enchantment enchantment) {
this.enchantment = enchantment;
}
public int getLevel() {
return level;
}
public void setLevel(final int level) {
this.level = level;
}
@Override
public Enchantment getKey() {
return enchantment;
}
@Override
public Integer getValue() {
return level;
}
@Override
public Integer setValue(final Integer v) {
int t = level;
level = v;
return t;
}
@Override
public int hashCode() {
return enchantment.hashCode() ^ level;
}
@Override
public boolean equals(final Object obj) {
if (obj instanceof Entry) {
final Entry entry = (Entry) obj;
if (entry.getKey() instanceof Enchantment && entry.getValue() instanceof Integer) {
final Enchantment enchant = (Enchantment) entry.getKey();
final Integer lvl = (Integer) entry.getValue();
return this.enchantment.equals(enchant) && this.level == lvl.intValue();
}
}
return false;
}
}
@@ -1,14 +0,0 @@
package com.earth2me.essentials.storage;
public interface IStorageObjectHolder<T extends StorageObject> {
T getData();
void acquireReadLock();
void acquireWriteLock();
void close();
void unlock();
}
@@ -1,6 +0,0 @@
package com.earth2me.essentials.storage;
public interface IStorageReader {
<T extends StorageObject> T load(final Class<? extends T> clazz) throws ObjectLoadException;
}
@@ -1,6 +0,0 @@
package com.earth2me.essentials.storage;
public interface IStorageWriter {
void save(final StorageObject object);
}
@@ -1,11 +0,0 @@
package com.earth2me.essentials.storage;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ListType {
Class value() default String.class;
}
@@ -1,11 +0,0 @@
package com.earth2me.essentials.storage;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface MapKeyType {
Class value() default String.class;
}
@@ -1,11 +0,0 @@
package com.earth2me.essentials.storage;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface MapValueType {
Class value() default String.class;
}
@@ -1,8 +0,0 @@
package com.earth2me.essentials.storage;
public class ObjectLoadException extends Exception {
public ObjectLoadException(Throwable thrwbl) {
super(thrwbl);
}
}
@@ -1,5 +0,0 @@
package com.earth2me.essentials.storage;
public interface StorageObject {
}
@@ -1,96 +0,0 @@
package com.earth2me.essentials.storage;
import org.bukkit.plugin.Plugin;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import java.io.Reader;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
public class YamlStorageReader implements IStorageReader {
private transient static final Map<Class, Yaml> PREPARED_YAMLS = Collections.synchronizedMap(new HashMap<Class, Yaml>());
private transient static final Map<Class, ReentrantLock> LOCKS = new HashMap<Class, ReentrantLock>();
private transient final Reader reader;
private transient final Plugin plugin;
public YamlStorageReader(final Reader reader, final Plugin plugin) {
this.reader = reader;
this.plugin = plugin;
}
@Override
public <T extends StorageObject> T load(final Class<? extends T> clazz) throws ObjectLoadException {
Yaml yaml = PREPARED_YAMLS.get(clazz);
if (yaml == null) {
yaml = new Yaml(prepareConstructor(clazz));
PREPARED_YAMLS.put(clazz, yaml);
}
ReentrantLock lock;
synchronized (LOCKS) {
lock = LOCKS.get(clazz);
if (lock == null) {
lock = new ReentrantLock();
}
}
lock.lock();
try {
T object = (T) yaml.load(reader);
if (object == null) {
object = clazz.newInstance();
}
return object;
} catch (IllegalAccessException ex) {
throw new ObjectLoadException(ex);
} catch (InstantiationException ex) {
throw new ObjectLoadException(ex);
} finally {
lock.unlock();
}
}
private Constructor prepareConstructor(final Class<?> clazz) {
final Constructor constructor = new BukkitConstructor(clazz, plugin);
final Set<Class> classes = new HashSet<Class>();
prepareConstructor(constructor, classes, clazz);
return constructor;
}
private void prepareConstructor(final Constructor constructor, final Set<Class> classes, final Class clazz) {
classes.add(clazz);
final TypeDescription description = new TypeDescription(clazz);
for (Field field : clazz.getDeclaredFields()) {
prepareList(field, description, classes, constructor);
prepareMap(field, description, classes, constructor);
if (StorageObject.class.isAssignableFrom(field.getType()) && !classes.contains(field.getType())) {
prepareConstructor(constructor, classes, field.getType());
}
}
constructor.addTypeDescription(description);
}
private void prepareList(final Field field, final TypeDescription description, final Set<Class> classes, final Constructor constructor) {
final ListType listType = field.getAnnotation(ListType.class);
if (listType != null) {
description.putListPropertyType(field.getName(), listType.value());
if (StorageObject.class.isAssignableFrom(listType.value()) && !classes.contains(listType.value())) {
prepareConstructor(constructor, classes, listType.value());
}
}
}
private void prepareMap(final Field field, final TypeDescription description, final Set<Class> classes, final Constructor constructor) {
final MapValueType mapType = field.getAnnotation(MapValueType.class);
if (mapType != null) {
final MapKeyType mapKeyType = field.getAnnotation(MapKeyType.class);
description.putMapPropertyType(field.getName(), mapKeyType == null ? String.class : mapKeyType.value(), mapType.value());
if (StorageObject.class.isAssignableFrom(mapType.value()) && !classes.contains(mapType.value())) {
prepareConstructor(constructor, classes, mapType.value());
}
}
}
}
@@ -1,257 +0,0 @@
package com.earth2me.essentials.storage;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.MaterialData;
import org.yaml.snakeyaml.Yaml;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
public class YamlStorageWriter implements IStorageWriter {
private transient static final Pattern NON_WORD_PATTERN = Pattern.compile("\\W");
private transient static final Yaml YAML = new Yaml();
private transient final PrintWriter writer;
public YamlStorageWriter(final PrintWriter writer) {
this.writer = writer;
}
@Override
public void save(final StorageObject object) {
try {
writeToFile(object, 0, object.getClass());
} catch (IllegalArgumentException ex) {
Logger.getLogger(YamlStorageWriter.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(YamlStorageWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void writeToFile(final Object object, final int depth, final Class clazz) throws IllegalAccessException {
for (Field field : clazz.getDeclaredFields()) {
final int modifier = field.getModifiers();
if (Modifier.isPrivate(modifier) && !Modifier.isTransient(modifier) && !Modifier.isStatic(modifier)) {
field.setAccessible(true);
final Object data = field.get(object);
if (writeKey(field, depth, data)) {
continue;
}
if (data instanceof StorageObject) {
writer.println();
writeToFile(data, depth + 1, data.getClass());
} else if (data instanceof Map) {
writeMap((Map<Object, Object>) data, depth + 1);
} else if (data instanceof Collection) {
writeCollection((Collection<Object>) data, depth + 1);
} else if (data instanceof Location) {
writeLocation((Location) data, depth + 1);
} else {
writeScalar(data);
writer.println();
}
}
}
}
private boolean writeKey(final Field field, final int depth, final Object data) {
final boolean commentPresent = writeComment(field, depth);
if (data == null && !commentPresent) {
return true;
}
writeIndention(depth);
if (data == null && commentPresent) {
writer.print('#');
}
final String name = field.getName();
writer.print(name);
writer.print(": ");
if (data == null && commentPresent) {
writer.println();
writer.println();
return true;
}
return false;
}
private boolean writeComment(final Field field, final int depth) {
final boolean commentPresent = field.isAnnotationPresent(Comment.class);
if (commentPresent) {
final Comment comments = field.getAnnotation(Comment.class);
for (String comment : comments.value()) {
final String trimmed = comment.trim();
if (trimmed.isEmpty()) {
continue;
}
writeIndention(depth);
writer.print("# ");
writer.print(trimmed);
writer.println();
}
}
return commentPresent;
}
private void writeCollection(final Collection<Object> data, final int depth) throws IllegalAccessException {
writer.println();
if (data.isEmpty()) {
writer.println();
}
for (Object entry : data) {
if (entry != null) {
writeIndention(depth);
writer.print("- ");
if (entry instanceof StorageObject) {
writer.println();
writeToFile(entry, depth + 1, entry.getClass());
} else if (entry instanceof Location) {
writeLocation((Location) entry, depth + 1);
} else {
writeScalar(entry);
}
}
}
writer.println();
}
private void writeMap(final Map<Object, Object> data, final int depth) throws IllegalArgumentException, IllegalAccessException {
writer.println();
if (data.isEmpty()) {
writer.println();
}
for (Entry<Object, Object> entry : data.entrySet()) {
final Object value = entry.getValue();
if (value != null) {
writeIndention(depth);
writeKey(entry.getKey());
writer.print(": ");
if (value instanceof StorageObject) {
writer.println();
writeToFile(value, depth + 1, value.getClass());
} else if (value instanceof Collection) {
writeCollection((Collection<Object>) value, depth + 1);
} else if (value instanceof Location) {
writeLocation((Location) value, depth + 1);
} else {
writeScalar(value);
writer.println();
}
}
}
}
private void writeIndention(final int depth) {
for (int i = 0; i < depth; i++) {
writer.print(" ");
}
}
private void writeScalar(final Object data) {
if (data instanceof String || data instanceof Boolean || data instanceof Number) {
synchronized (YAML) {
YAML.dumpAll(Collections.singletonList(data).iterator(), writer);
}
} else if (data instanceof Material) {
writeMaterial(data);
writer.println();
} else if (data instanceof MaterialData) {
writeMaterialData(data);
writer.println();
} else if (data instanceof ItemStack) {
writeItemStack(data);
writer.println();
} else if (data instanceof EnchantmentLevel) {
writeEnchantmentLevel(data);
writer.println();
} else {
throw new UnsupportedOperationException();
}
}
private void writeKey(final Object data) {
if (data instanceof String || data instanceof Boolean || data instanceof Number) {
String output = data.toString();
if (NON_WORD_PATTERN.matcher(output).find()) {
writer.print('"');
writer.print(output.replace("\"", "\\\""));
writer.print('"');
} else {
writer.print(output);
}
} else if (data instanceof Material) {
writeMaterial(data);
} else if (data instanceof MaterialData) {
writeMaterialData(data);
} else if (data instanceof EnchantmentLevel) {
writeEnchantmentLevel(data);
} else {
throw new UnsupportedOperationException();
}
}
private void writeMaterial(final Object data) {
writer.print(data.toString().toLowerCase(Locale.ENGLISH));
}
private void writeMaterialData(final Object data) {
final MaterialData matData = (MaterialData) data;
writeMaterial(matData.getItemType());
if (matData.getData() > 0) {
writer.print(':');
writer.print(matData.getData());
}
}
private void writeItemStack(final Object data) {
final ItemStack itemStack = (ItemStack) data;
writeMaterialData(itemStack.getData());
writer.print(' ');
writer.print(itemStack.getAmount());
for (Entry<Enchantment, Integer> entry : itemStack.getEnchantments().entrySet()) {
writer.print(' ');
writeEnchantmentLevel(entry);
}
}
private void writeEnchantmentLevel(Object data) {
final Entry<Enchantment, Integer> enchLevel = (Entry<Enchantment, Integer>) data;
writer.print(enchLevel.getKey().getName().toLowerCase(Locale.ENGLISH));
writer.print(':');
writer.print(enchLevel.getValue());
}
private void writeLocation(final Location entry, final int depth) {
writer.println();
writeIndention(depth);
writer.print("world: ");
writeScalar(entry.getWorld().getName());
writeIndention(depth);
writer.print("x: ");
writeScalar(entry.getX());
writeIndention(depth);
writer.print("y: ");
writeScalar(entry.getY());
writeIndention(depth);
writer.print("z: ");
writeScalar(entry.getZ());
writeIndention(depth);
writer.print("yaw: ");
writeScalar(entry.getYaw());
writeIndention(depth);
writer.print("pitch: ");
writeScalar(entry.getPitch());
}
}
@@ -1,122 +0,0 @@
package com.earth2me.essentials.utils;
import net.ess3.api.IUser;
import org.bukkit.ChatColor;
import java.util.regex.Pattern;
public class FormatUtil {
//Vanilla patterns used to strip existing formats
static final transient Pattern VANILLA_COLOR_PATTERN = Pattern.compile("\u00a7+[0-9A-Fa-f]");
static final transient Pattern VANILLA_MAGIC_PATTERN = Pattern.compile("\u00a7+[Kk]");
static final transient Pattern VANILLA_FORMAT_PATTERN = Pattern.compile("\u00a7+[L-ORl-or]");
//Essentials '&' convention colour codes
static final transient Pattern REPLACE_ALL_PATTERN = Pattern.compile("(?<!&)&([0-9a-fk-orA-FK-OR])");
static final transient Pattern REPLACE_COLOR_PATTERN = Pattern.compile("(?<!&)&([0-9a-fA-F])");
static final transient Pattern REPLACE_MAGIC_PATTERN = Pattern.compile("(?<!&)&([Kk])");
static final transient Pattern REPLACE_FORMAT_PATTERN = Pattern.compile("(?<!&)&([l-orL-OR])");
static final transient Pattern REPLACE_PATTERN = Pattern.compile("&&(?=[0-9a-fk-orA-FK-OR])");
//Used to prepare xmpp output
static final transient Pattern LOGCOLOR_PATTERN = Pattern.compile("\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]");
static final transient Pattern URL_PATTERN = Pattern.compile("((?:(?:https?)://)?[\\w-_\\.]{2,})\\.([a-zA-Z]{2,3}(?:/\\S+)?)");
public static final Pattern IPPATTERN = Pattern.compile("^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
//This method is used to simply strip the native minecraft colour codes
public static String stripFormat(final String input) {
if (input == null) {
return null;
}
return ChatColor.stripColor(input);
}
//This method is used to simply strip the & convention colour codes
public static String stripEssentialsFormat(final String input) {
if (input == null) {
return null;
}
return stripColor(input, REPLACE_ALL_PATTERN);
}
//This is the general permission sensitive message format function, checks for urls.
public static String formatMessage(final IUser user, final String permBase, final String input) {
if (input == null) {
return null;
}
String message = formatString(user, permBase, input);
if (!user.isAuthorized(permBase + ".url")) {
message = FormatUtil.blockURL(message);
}
return message;
}
//This method is used to simply replace the ess colour codes with minecraft ones, ie &c
public static String replaceFormat(final String input) {
if (input == null) {
return null;
}
return replaceColor(input, REPLACE_ALL_PATTERN);
}
static String replaceColor(final String input, final Pattern pattern) {
return REPLACE_PATTERN.matcher(pattern.matcher(input).replaceAll("\u00a7$1")).replaceAll("&");
}
//This is the general permission sensitive message format function, does not touch urls.
public static String formatString(final IUser user, final String permBase, final String input) {
if (input == null) {
return null;
}
String message;
if (user.isAuthorized(permBase + ".color")) {
message = replaceColor(input, REPLACE_COLOR_PATTERN);
} else {
message = stripColor(input, VANILLA_COLOR_PATTERN);
}
if (user.isAuthorized(permBase + ".magic")) {
message = replaceColor(message, REPLACE_MAGIC_PATTERN);
} else {
message = stripColor(message, VANILLA_MAGIC_PATTERN);
}
if (user.isAuthorized(permBase + ".format")) {
message = replaceColor(message, REPLACE_FORMAT_PATTERN);
} else {
message = stripColor(message, VANILLA_FORMAT_PATTERN);
}
return message;
}
public static String stripLogColorFormat(final String input) {
if (input == null) {
return null;
}
return stripColor(input, LOGCOLOR_PATTERN);
}
static String stripColor(final String input, final Pattern pattern) {
return pattern.matcher(input).replaceAll("");
}
public static String lastCode(final String input) {
int pos = input.lastIndexOf('\u00a7');
if (pos == -1 || (pos + 1) == input.length()) {
return "";
}
return input.substring(pos, pos + 2);
}
static String blockURL(final String input) {
if (input == null) {
return null;
}
String text = URL_PATTERN.matcher(input).replaceAll("$1 $2");
while (URL_PATTERN.matcher(text).find()) {
text = URL_PATTERN.matcher(text).replaceAll("$1 $2");
}
return text;
}
public static boolean validIP(String ipAddress) {
return IPPATTERN.matcher(ipAddress).matches();
}
}
Loaded 100 of 808 files, more files were not shown because too many files have changed in this diff. Show more