Compare commits

...

295 Commits
2.19.1 ... 2.x

Author SHA1 Message Date
Charles DeLancey cde7184da3
Fix duplicated messages with /helpop (#5776) 2024-04-29 21:26:49 -04:00
DarkLaw 549283a1e5
Translate Gamemode placeholder in cantGamemode message (#5771) 2024-04-28 01:44:21 -07:00
Charles DeLancey 6a2527ccdb
Fix sender not receiving helpop message (#5769) 2024-04-28 01:39:26 -07:00
Emilia Kond c60ed56190
Fix stack trace when buying from sign when inventory full (#5761) 2024-04-13 21:50:45 +00:00
pop4959 c85e179718
Make ChargeException translatable (#5736)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2024-04-08 01:22:31 +00:00
DarkLaw 71ca7ffbf6
Fix heal signs not healing up to the player's max health (#5752) 2024-03-31 22:53:53 +00:00
pop4959 76a513a05c
Don't run keyword replacer by default in translated broadcasts (#5739)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2024-03-25 19:11:18 +00:00
pop4959 8cfe680abc
Fix empty translations being sent to Console (#5737) 2024-03-25 19:09:13 +00:00
pop4959 2cb0af0ca4
Strict parsing for legacy converted placeholders (#5740)
This fixes issues where arguments converted implicitly from MiniMessage
are prone to bleeding into the rest of the output.

The fix mostly works since `MINI_MESSAGE_NO_TAGS` is only used for
legacy conversion, while `miniMessageInstance` is used in all other
cases normally. If that were not the case, we would not want strict
parsing everywhere since we don't enforce this in translations anyway.

Fixes #5729
Fixes #5730
Fixes #5732
Fixes #5735

Fixes #5720
Closes #5728
2024-03-11 04:14:58 -04:00
Charles DeLancey 570eca2e21
Add text box to bug report template (#5715) 2024-03-10 21:31:40 -07:00
Charles DeLancey 3817a11d9d
Convert color codes in tempban and tempbanip (#5726) 2024-03-05 14:58:57 -05:00
Catarina Freire c19b20ea3b
Fix banner patterns not working in kits (#5723)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2024-03-04 13:49:30 -05:00
Charles DeLancey a4ac720057
Fix format parsing in ban messages (#5722) 2024-03-04 13:45:06 -05:00
Charles DeLancey 993d7ede56
Fix shout/local chat not sending with certain formats (#5719) 2024-02-29 23:32:51 +00:00
Bobcat00 622c8147a9
Add setting to use usernames over display names for social spy (#5613)
Co-authored-by: Bobcat00 <Bobcat00@users.noreply.github.com>
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2024-02-26 15:25:30 -05:00
pop4959 6b521e78a6
Fix jail-online-time with offline players (#5701) 2024-02-26 14:32:44 -05:00
pop4959 4219450705
Hotfix legacy serializer to include capitalized formatting code chars (#5711) 2024-02-26 05:09:02 -08:00
pop4959 bd8c792fa4
Support custom biomes in random teleport excluded biome list (#5703) 2024-02-26 03:47:00 -08:00
MD 52a638f18f
Add actions step to log JUnit test reports (#5684) 2024-02-26 01:51:31 +00:00
pop4959 1b1b511b61
Fix conversion issues between Legacy and MiniMessage (#5702)
Fixes #5652
2024-02-26 01:39:18 +00:00
pop4959 d4b72c8af6
Fix Discord /list command showing tags in output (#5698) 2024-02-25 00:06:52 -08:00
pop4959 185b4e266b
Fix /broadcastworld sending in all but the intended world (#5699)
Fixes #5694

This issue was caused by the passed predicate being excludes rather than
includes.

Also addresses a separate issue where no help output was given when no
arguments were specified and the command was sent by a player.
2024-02-24 22:40:22 +00:00
pop4959 7a9a0e6f51
Fix /me from console (#5700)
Fixes #5689
2024-02-24 20:42:30 +00:00
pop4959 9be27ad7ac
Fix custom message colors config not working (#5705)
No linked issue; discussed on Discord with @Evidentsinger14

Also @JRoy, I refuse to believe you ever tested this feature, you're
trolling

---------

Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2024-02-24 20:39:40 +00:00
pop4959 09fa6463a7
Update GitHub Actions (#5704)
Bump actions steps to remove deprecation warnings on GitHub

https://github.com/EssentialsX/Essentials/assets/17698576/0d032078-0c36-4362-b680-5a9b30d30345
2024-02-24 20:28:07 +00:00
Charles DeLancey 1929d4110a
Fix format parsing in /heal (Fixes #5690) 2024-02-20 16:57:57 -05:00
Josh Roy 4386713807
Fix messages not sending after /ess reload (Fixes #5663) 2024-02-19 19:37:03 -05:00
Josh Roy 139db29782 Fix format parsing in various discord commands 2024-02-19 17:01:44 -05:00
Josh Roy d307279b3b Fix format parsing in unlinked kick message (Fixes #5667) 2024-02-19 17:01:44 -05:00
Josh Roy 80e6f96c71 Fix format parsing in /msg from Discord (Fixes #5671) 2024-02-19 17:01:44 -05:00
Josh Roy 77d505bb4a Fix format parsing using in-game commands in console (Fixes #5670) 2024-02-19 17:01:44 -05:00
Josh Roy 14125d9c4c Fix format parsing in /spawner (Fixes #5680) 2024-02-19 17:01:44 -05:00
Josh Roy dfc5c49f56 Log individual JUnit test results 2024-02-19 02:07:58 -05:00
Josh Roy 221a6622f3 Fix format parsing in /time (Fixes #5661) 2024-02-19 02:07:58 -05:00
Josh Roy 82606a7ced Fix format parsing in local spy chat format (Fixes #5665) 2024-02-19 02:07:58 -05:00
Josh Roy 1dccfbfcee Fix format parsing in /suicide (Fixes #5662) 2024-02-19 02:07:58 -05:00
Josh Roy ac0ba8890f Fix format parsing in /unlimited 2024-02-19 02:07:58 -05:00
Josh Roy 0cd47639c2 Fix /kill and /suicide on latest Spigot/Paper 2024-02-19 02:07:58 -05:00
MD 63234d6b1d
Update Gradle and plugins; don't enforce running tests on Java 8 (#5685)
Fixes CI failures when trying to run `testJava8`, now that Spigot API is
compiled for Java 17.
2024-02-18 16:14:56 +00:00
Josh Roy 8a57856c96 Remove CommonPlaceholders#displayName methods
I18n argument mutation already converts legacy color codes
to parsed MiniMessage. This was redundant and was creating
issues with other parts of the codebase.
2024-02-09 23:31:06 -05:00
Josh Roy 3d9d3a3254 Fix format parsing in /home (Fixes #5653) 2024-02-09 23:31:06 -05:00
Josh Roy 544f69aec8 Fix format parsing in /kit (Fixes #5651) 2024-02-09 23:31:06 -05:00
Josh Roy 596ba6e2f5 Fix format parsing in /ptime (Fixes #5655) 2024-02-09 23:31:06 -05:00
Josh Roy 1e040fa7b5 Fix format parsing in /me (Fixes #5654) 2024-02-09 23:31:06 -05:00
Josh Roy 51075adec6 Fix format parsing in /near (Fixes #5641) 2024-02-09 23:31:06 -05:00
Josh Roy 4134b5fb99 Fix format parsing for command usage strings 2024-02-09 23:31:06 -05:00
Josh Roy d4ecfd2263
Fix component appending in social spy (#5650)
fixes #5649

this time it wasn't me!
2024-02-05 18:15:13 +00:00
MD 0d1462a021
Fix message display issues from Adventure refactor (#5648)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2024-02-04 20:31:58 -05:00
Josh Roy 16e297269d
Fix several regressions from adventure PR (#5637)
* Fixes /list
* Fixes /baltop
* Fixes Social Spy
* Fixes Essentials Signs
2024-02-04 03:35:37 +00:00
Pantera (Mad_Daniel) 3b61b3ed31
Update adventure-platform-bukkit (Fix 1.20.4) (#5636) 2024-02-04 02:59:49 +00:00
Josh Roy 23093b68d7
Fix placeholders not parsing inside log messages (#5635) 2024-02-03 21:13:18 -05:00
MD 746627c4b5
Use sendTl to ensure message format is parsed (#5632)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2024-02-04 01:47:20 +00:00
TiagoFar78 04c01655f6
Fix give command for tipped arrow item (#5627) 2024-02-03 17:12:35 -08:00
Josh Roy 388d571da9
We're going on an Adventure! (#4717)
https://user-images.githubusercontent.com/10731363/147530817-f9adc58e-18a5-49ed-84c6-106e51d6948f.mp4
Add support for chat components throughout EssentialsX using the Adventure library.  
Translations have been converted to the MiniMessage format, and custom message files will be migrated on startup.  
This also introduces new options to allow players to see messages in their own language and for server owners to change the main message colours without editing message files.

Closes #2029
Closes #2391

---------

Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
Co-authored-by: pop4959 <pop4959@gmail.com>
2024-02-03 20:38:14 +00:00
Flask Bot 8234dedb22
New Crowdin updates (#5629) 2024-02-03 16:12:09 +00:00
Flask Bot 81a8731330
New Crowdin updates (#5511) 2024-02-03 15:10:46 +00:00
Charles DeLancey fbfd7e9871
Fix msgToggleCommandUsage1Description (#5614) 2024-01-13 17:16:21 -08:00
Charles DeLancey 0af4436c2f
Update supported versions (#5600)
Remove 1.19.1
Update 1.19.2 -> 1.19.4

closes: #5599

---------

Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2023-12-16 17:35:57 +00:00
Josh Roy 84e9051f46
Update to Minecraft 1.20.4 (#5592) 2023-12-16 15:14:37 +00:00
Josh Roy bb7b334ace
Use WeakReference to store alternative commands (#5572)
Co-authored-by: oop778 <oskardhavel@gmail.com>
2023-11-27 21:29:20 +00:00
Josh Roy c68b277782
Fix trade signs not updating with full inventories (#5574)
Starting with 1.19, sign block states are no longer persistent causing them to become dead after any call to Sign#update. 
To avoid this, ensure we either always get the latest block state or update the block state after any call to Sign#update.
2023-11-10 21:23:10 -05:00
Josh Roy 50c4d04b02
Prevent possible NPE during legacy file conversion (#5551)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2023-11-10 19:27:06 -05:00
Marcel Kwiatkowski 3eceec87d3
Fix incorrect online count in custom quit message (#5541)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2023-10-28 22:29:11 +00:00
Josh Roy fdf1875e7f
Fix incorrect permission node in /potion (#5552)
Fixes #5549.
2023-10-24 21:24:06 +00:00
Josh Roy 79449ef663
Update to Minecraft 1.20.2 (#5522) 2023-09-22 18:38:57 -04:00
Flask Bot b900444ff0
New Crowdin updates (#5458) 2023-09-07 16:50:34 -04:00
YanisBft a3a71afcef
Add HelpopMessageSentEvent (#5490)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2023-08-28 18:41:40 -04:00
ThiagoROX 72ba87c509
Prevent /editsign on waxed signs (#5492) 2023-08-28 17:04:15 -04:00
Josh Roy ee1111f6aa
Prevent players from ignoring themselves (#5488)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2023-08-24 22:04:37 +00:00
Josh Roy 42071f4ad4 Lower non bukkit type creation warns amount 2023-08-24 18:02:00 -04:00
Josh Roy cf43e643ed Fix usermap debug message not being debug 2023-08-24 18:02:00 -04:00
Dennis Gyftakis bb2df0b0a4
Add whitelist indicator for /seen and /whois (#5486)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2023-08-23 15:20:09 -04:00
diademiemi e3e52db10e
Add discord roles blacklist and aliases for chat format (#5157)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2023-08-08 21:39:12 -04:00
Alex ad5f17481c
Add abbreviation support to /pay command (#5457)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2023-08-08 21:05:30 +00:00
Luke Chambers 0a4cf27342
Add ability to use texture url in /skull (#5120)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2023-08-08 16:10:26 -04:00
SavageAvocado dfa22969c9
Add default book title and authors (#4920)
Prevents written books from being invalid if no author/title is provided.

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

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

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

Closes #4747.

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

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

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

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

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

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

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

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

Adds `commands.yml`, the known command map and `AlternativeCommandHandler` handover information to `/ess dump`.

Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2022-08-07 11:43:59 +01:00
MD 6dfa18ca53
Implement chat message signing for 1.19.1+ (#5030)
**Known issue: this inadvertently reformats `/minecraft:tell`. There's not much we can do about this in 2.19.x.**

This commit refactors EssentialsX Chat in order to support chat previews and signed chat messages in 1.19.1+.
2022-08-06 22:27:58 +01:00
Josh Roy a394760677
Update VersionUtil and /ess version (#5036) 2022-08-06 15:48:26 -04:00
MD 5f48cdef13
Bump to 1.19.2 (#5035) 2022-08-06 12:14:07 -04:00
pop4959 c56a9e6741
Add spawnable boat variants (#5027)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2022-08-02 14:18:57 -04:00
pop4959 5b20f30350
Fix ice other message (#5028)
Fix `iceOther` being sent to the target player instead of the sender. Fixes #5002.
2022-08-02 08:40:10 +01:00
pop4959 037577162b
Add swift sneak enchantment (#5026)
Closes #5024.
2022-07-31 19:03:31 +00:00
Josh Roy 908189a233 Bump Spigot to 1.19.1 2022-07-28 11:30:24 -04:00
Josh Roy c938767b2d Prepare for 1.19.1 2022-07-28 11:30:24 -04:00
Josh Roy b135fcf086
Fix leave messages being sent when vanished (#5009) 2022-07-23 18:35:14 -04:00
Warrior 09dc49aacb
Fix nickname feedback message when change-displayname is off (#4980)
Make the feedback message use the nickname instead of the player's display name if change-displayname is disabled. Fixes #4979.
2022-07-11 08:02:10 +00:00
Josh Roy f4b6197a49
Fix boolean logic for sleep ignore during afk status change (#4985) 2022-07-10 22:28:08 -07:00
Josh Roy 4a53cfe7ac
Prevent role snowflakes from resolving roles with ids as names (#4983)
Fixes #4981.
2022-07-10 00:24:04 +01:00
Deltric 2bba577567
Fix /unlimited with changing stack sizes (#4877)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2022-07-05 17:01:13 +00:00
pop4959 6e674c73e0
Update unsupported message (#4976)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2022-07-05 09:52:14 -04:00
Josh Roy a60f3c067f
Fix Essentials' logger breaking on 1.8.8-1.12.2 (#4975) 2022-07-02 14:50:45 -04:00
Josh Roy 6816eb4e18
Use component logger on Paper for console colors (#4941)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2022-06-27 14:54:10 -04:00
Tristan Hermanns 9c5536b2e6
Fix minecraft namespace not working in give command (#4960) 2022-06-25 17:40:43 -04:00
Josh Roy ff80338350
Log filenames during configuration serialization errors (#4959) 2022-06-21 22:01:25 +00:00
Josh Roy 8d856dd6db
Fix paths and farmland not being solid (#4915)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2022-06-18 19:31:54 +00:00
Josh Roy 96c6c951e8
Don't teleport to a safe location for AFK freeze when flying (#4944)
Fixes #4902.
2022-06-15 15:43:57 +00:00
Josh Roy 0931b21f6d
Fix places where Discord formatting wasn't sanitized (#4945)
Fixes #4891
2022-06-15 15:35:12 +00:00
Josh Roy 9147d1036d
Fix ANSI color codes not getting stripped on Paper (#4942)
Paper uses 0x7f as an intermediate character between adventure and its ANSI pattern converter, we need to strip this.
2022-06-15 16:31:42 +01:00
MD a7f602e2ad Remove commons-lang3 dependency
`commons-lang3` is scheduled for removal by Spigot.

This commit reimplements the methods we use from StringUtils in StringUtil, and replaces NumberUtils.isDigits(String) with NumberUtil.isLong(String).
2022-06-15 16:18:35 +01:00
Flask Bot 0c81980ead Update items.json for 1.19
Note: this action was performed by a human (@mdcfe) under the
Flask-Bot account.
2022-06-15 16:18:35 +01:00
MD 2d5794f68d Add mangrove signs to MaterialUtil 2022-06-15 16:18:35 +01:00
MD 6b80e0b113 Bump run-paper MC version to 1.19 2022-06-15 16:18:35 +01:00
Josh Roy 18f9af898e Add 1.19 mobs/data 2022-06-15 16:18:35 +01:00
Josh Roy d04c933abe Fix server state reflection provider mappings 2022-06-15 16:18:35 +01:00
Josh Roy b916488de2 Bump VersionUtil and Spigot 2022-06-15 16:18:35 +01:00
MD c6066bd2d8
Update README and contributing guide (#4851)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>

This PR brings the README up-to-date, reduces the number of references to upstream Essentials, and fleshes out the contributing guide with much more detail.
2022-06-10 13:06:24 +00:00
Josh Roy 3af931740b
Don't progress playtime for vanished users (#4918) 2022-06-04 01:43:12 +00:00
Josh Roy 1c5a7e9ffb
Bump down to 2.19.5 (#4914)
Mojang will be releasing 1.19 within two weeks and 2.20.0 is not ready for that timeframe. We want to release 2.19.5 with 1.19 support before that.
2022-05-30 21:21:19 +01:00
pop4959 ea5cdc097d
Fix erroneous TeleportWarmupEvent event call (#4913) 2022-05-22 17:20:39 -04:00
Deltric d891268143
Fix /nick off breaking with changecolor permissions (#4876) 2022-03-31 19:57:36 -04:00
lucko 4bd1b3c09f
Reduce user lookups for LuckPerms contexts (#4869) 2022-03-27 09:07:36 -04:00
MD c4f10d9c1d
Fix double charge for /tpa when target has /tpauto on (#4862)
If a player uses `/tpa` to request a teleport to someone with `/tpauto` enabled, `/tpa` manually creates a charge for the teleportation.  
This PR changes the subsequent code to throw a `NoChargeException` instead of returning, meaning only the `AsyncTeleport` charge is applied, not the standard command one.

Fixes #4854.
2022-03-20 11:19:20 +00:00
MD e12f1b5022
Bump run-paper to 1.18.2 (#4857) 2022-03-15 07:56:52 -04:00
MD 31732cec95
Prepare for 2.20.0 dev builds (#4849)
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
2022-03-12 19:33:28 -05:00
MD f104b6ec15 Release 2.19.4 2022-03-12 23:00:24 +00:00
MD 695546420f
Run update check using Bukkit scheduler (#4839)
Fixes #4825.
2022-03-12 12:02:20 +00:00
Josh Roy 997fb1800e
Fix preemptive setting of owner metadata on to trade signs (#4835)
Fixes #4836.
2022-03-08 15:08:34 +00:00
MD 3984bddd9d
Fix 2.19.4 dev build version (#4834) 2022-03-06 00:06:48 +00:00
MD d92ce8bdfe
Bump to 2.19.4 dev (#4831) 2022-03-05 18:33:04 +00:00
MD 3348bd9129 Release 2.19.3 2022-03-04 11:41:56 +00:00
Josh Roy 1a5526867c
Fix IllegalAccessException with advancement listener on 1.12.2 (#4826)
Fixes #4809.
2022-03-03 20:38:39 +00:00
MD c5253bc5e2
Update to Minecraft 1.18.2 (#4821)
This PR updates the build setup to Gradle 7.4 and updates EssentialsX to Minecraft 1.18.2.
2022-02-28 20:51:26 +00:00
Flask Bot 29a2a865c5
New Crowdin updates (#4744) 2022-02-28 20:31:02 +00:00
MD c3b994808f
Use GitHub proxy fallback for update checker (#4818) 2022-02-26 17:09:54 -05:00
triagonal bc2da98703
Make OfflinePlayer#setName protected for CMI Importer (#4805) 2022-02-14 07:40:48 -05:00
Josh Roy cbb012853c Fix toggleshout causing issues with question/local chat 2022-02-13 22:44:37 -05:00
Josh Roy 4bf4bd432a Add some color to the local prefix by default 2022-02-13 22:44:37 -05:00
Josh Roy 83d0e0d9a0 Add permissions to receive certain channel channels 2022-02-13 22:44:37 -05:00
Josh Roy 2f5c24d114 Add permission for local channel chat 2022-02-13 22:44:37 -05:00
Josh Roy 88c8ccd29b Add config for default shout state and for persisting shout state 2022-02-13 22:44:37 -05:00
Josh Roy 94edbcfeb1 Add chat question config option 2022-02-13 22:44:37 -05:00
Josh Roy d5822e9a41
Add config for max /tree and /bigtree range (#4728)
Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>
2022-02-13 16:46:18 -05:00
Josh Roy debf09437e
Add UUID support to trade and protection signs (#4713) 2022-02-13 15:54:19 -05:00
Josh Roy a9e5f079a9
Fix trade sign length validation issues (#4748) 2022-02-13 15:50:43 -05:00
Josh Roy f00c2dcf92
Fix keepinv policies ignoring offhand (#4725) 2022-02-13 20:37:25 +00:00
Josh Roy 63cbf7e2da
Prevent legacy material support from being initiated (#4697) 2022-02-13 15:33:51 -05:00
Josh Roy 19837f9309
Add some more dump files (#4785)
Adds worth, tpr, and spawns configs.

See also https://github.com/EssentialsX/Website/pull/68
2022-02-08 09:26:05 +00:00
Josh Roy 4b8b770c30
Allow /nick without change-displayname (#4758)
Closes #4709.
2022-02-06 18:23:17 +00:00
Josh Roy ddc258ed11
Fix teleport request queue being reversed order (#4755)
Fix #4753
2022-02-06 18:18:40 +00:00
Josh Roy d23796dade
Support doubles in /tppos (#4729)
Closes #1785
2022-02-06 18:01:51 +00:00
Josh Roy 41f5cc3175
Use Paper command forwarding API (#4794)
Uses API added in PaperMC/Paper@9940bca, when available.
2022-02-06 17:56:13 +00:00
Josh Roy c6fe160b47
Fix Paper command executor on modern Paper versions (#4791) 2022-02-01 22:13:16 +00:00
sxphirus 5c46bea2ca
Add translation key for /near entries (#4740) 2022-01-20 10:05:31 -05:00
Flask Bot a9585bb525
New Crowdin updates (#4668) 2022-01-09 16:27:25 +00:00
Josh Roy bb88a6a749
Fix rate limit exception in update checker (#4731) 2022-01-02 17:24:32 +00:00
Pierre Dedrie 739600eb05
Fix safelogin for 1.18 and above by using worldProvider minHeight (#4715) 2021-12-26 23:56:03 +00:00
Josh Roy 5f98d3fac5
Add mitigation for JDK-8274349 (#4711) 2021-12-24 21:40:41 -05:00
Josh Roy 84326cf13e
Fix LocationUtil#getSafeDestination NSME on older versions (#4708)
Fixes a NoSuchMethodError from old guava versions in old MC versions.

Fixes #4703
2021-12-23 11:55:31 +00:00
Josh Roy 685084219e
Use futureproof Paper component serializer when available (#4706)
#plainSerializer will be removed when adventure 5.0.0 releases. This PR prevents this from breaking in the future.

Closes #4705
2021-12-23 10:57:41 +00:00
Josh Roy c4e62ae22b
Remove usused configuration classes (#4707)
These were not used since configurate, no plugin should be using this, and it causes compile errors on the latest spigot version.
2021-12-23 01:18:02 +00:00
MD 05ce11f657 Bump to 2.19.3 dev 2021-12-15 21:29:45 +00:00
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
462 changed files with 44642 additions and 33460 deletions

View File

@ -7,14 +7,11 @@ contact_links:
url: https://github.com/EssentialsX/Essentials/discussions/categories/q-a
about: Visit the Q&A forum to search for previous help requests.
- name: Check past feature suggestions
url: https://github.com/EssentialsX/Essentials/discussions/categories/ideas-and-feature-suggestions
url: https://github.com/EssentialsX/Essentials/issues?q=is%3Aissue+label%3A%22type%3A+enhancement%22
about: Visit the Feature Suggestions forum to view and discuss existing feature suggestions.
- name: Create help request
url: https://github.com/EssentialsX/Essentials/discussions/new?category=q-a
about: Create a support ticket to get help from developers.
- name: Suggest a feature
url: https://github.com/EssentialsX/Essentials/discussions/new?category=ideas-and-feature-suggestions
about: Suggest new features for EssentialsX!
- name: Get help from the community on Discord
url: https://discord.gg/casfFyh
about: Join the MOSS Discord for community-powered EssentialsX support!

View File

@ -70,10 +70,13 @@ body:
validations:
required: true
- type: markdown
- type: textarea
attributes:
value: |
In the text box below, you can attach any relevant screenshots, files and links to Timings/spark profiler reports.
label: Additional Information
description: |
In this box, 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.
validations:
required: false

View File

@ -0,0 +1,40 @@
name: Request a feature
description: Suggest a feature you want to see in EssentialsX!
labels: 'type: enhancement'
body:
- type: markdown
attributes:
value: |
If you have a feature suggestion for EssentialsX, read the following tips:
1. Fill out the template.
This will help us understand what you're requesting and why you want us
to add it.
2. Keep it simple.
Make sure it's easy to understand what you're requesting. A good way is
to keep it to one request per GitHub issue, as we can then easily track
feature requests.
3. Check whether it has already been asked or added.
You can search the issue tracker to see if your feature has already been
requested at https://github.com/EssentialsX/Essentials/issues. You can
also check the changelogs to see if the feature was recently added:
https://github.com/EssentialsX/Essentials/releases
4. Ask yourself: "Does this belong in EssentialsX?"
There are lots of features that we reject because most servers won't
need or use them. If your feature is very specific or already exists in
another plugin, it might not be a good fit for EssentialsX.
- type: textarea
attributes:
label: Feature description
description: Explain what you should expect to happen.
placeholder: |
What feature are you suggesting?
validations:
required: true
- type: textarea
attributes:
label: How the feature is useful
description: Explain what actually happens.
placeholder: |
How is the feature useful to players, server owners and/or developers?
validations:
required: true

View File

@ -4,6 +4,10 @@ on:
push:
branches:
- 2.x
- dev/*
release:
types:
- published
jobs:
build:
@ -12,34 +16,32 @@ jobs:
steps:
- name: Checkout Git repo
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Restore Gradle cache
uses: actions/cache@v2
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-
distribution: 'temurin'
java-version: 17
- name: Set up JDK 16
uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: 16
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
- name: Setup Gradle
uses: gradle/gradle-build-action@v3
- name: Build with Gradle
run: |
chmod +x gradlew
./gradlew build --stacktrace
- name: Publish JUnit report
uses: mikepenz/action-junit-report@v4
if: success() || failure() # Run even if the previous step fails
with:
report_paths: '**/build/test-results/test*/TEST-*.xml'
- name: Archive plugin jars on GitHub
uses: actions/upload-artifact@master
uses: actions/upload-artifact@v4
with:
name: EssentialsX plugin jars
path: jars/
@ -53,22 +55,43 @@ jobs:
./gradlew publish
- name: Prepare Javadocs
if: ${{ success() && github.event_name == 'push' && github.repository == 'EssentialsX/Essentials' && github.ref == 'refs/heads/2.x' }}
run: |
mv Essentials/build/docs/javadoc/ javadocs/
cp -r EssentialsAntiBuild/build/docs/javadoc/ javadocs/EssentialsAntiBuild/
cp -r EssentialsChat/build/docs/javadoc/ javadocs/EssentialsChat/
cp -r EssentialsDiscord/build/docs/javadoc/ javadocs/EssentialsDiscord/
cp -r EssentialsDiscordLink/build/docs/javadoc/ javadocs/EssentialsDiscordLink/
cp -r EssentialsGeoIP/build/docs/javadoc/ javadocs/EssentialsGeoIP/
cp -r EssentialsProtect/build/docs/javadoc/ javadocs/EssentialsProtect/
cp -r EssentialsSpawn/build/docs/javadoc/ javadocs/EssentialsSpawn/
cp -r EssentialsXMPP/build/docs/javadoc/ javadocs/EssentialsXMPP/
- name: Deploy Javadocs
if: ${{ success() && github.event_name == 'push' && github.repository == 'EssentialsX/Essentials' && github.ref == 'refs/heads/2.x' }}
uses: netlify/actions/cli@master
- name: Archive Javadocs
uses: actions/upload-artifact@v4
with:
args: deploy --dir=javadocs/ --prod --message="GitHubActionsDeploy"
name: javadocs
path: javadocs/
publish-jd:
name: Publish Javadocs
needs: build
if: ${{ github.event_name == 'push' && github.repository == 'EssentialsX/Essentials' && github.ref == 'refs/heads/2.x' }}
runs-on: ubuntu-latest
steps:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 16
- name: Download Javadocs
uses: actions/download-artifact@v4
with:
name: javadocs
path: javadocs/
- name: Deploy Javadocs
run: npx netlify-cli deploy --dir=javadocs/ --prod --message="GitHubActionsDeploy"
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_JD_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_JD_2X_SITE_ID }}

View File

@ -9,6 +9,7 @@ on:
branches:
- 2.x
- mc/*
- dev/*
jobs:
build:
@ -17,34 +18,32 @@ jobs:
steps:
- name: Checkout Git repo
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Restore Gradle cache
uses: actions/cache@v2
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-
distribution: 'temurin'
java-version: 17
- name: Set up JDK 16
uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: 16
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
- name: Setup Gradle
uses: gradle/gradle-build-action@v3
- name: Build with Gradle
run: |
chmod +x gradlew
./gradlew build --stacktrace
- name: Publish JUnit report
uses: mikepenz/action-junit-report@v4
if: success() || failure() # Run even if the previous step fails
with:
report_paths: '**/build/test-results/test*/TEST-*.xml'
- name: Archive plugin jars on GitHub
uses: actions/upload-artifact@master
uses: actions/upload-artifact@v4
with:
name: EssentialsX plugin jars
path: jars/

2
.gitignore vendored
View File

@ -15,6 +15,8 @@
/Essentials/kits.yml
/Essentials/userdata/testplayer1.yml
/Essentials/usermap.csv
/Essentials/usermap.bin
/Essentials/uuids.bin
# Build files
.gradle/

View File

@ -1,19 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CheckStyle-IDEA">
<option name="configuration">
<map>
<entry key="active-configuration" value="PROJECT_RELATIVE:$PROJECT_DIR$/.checkstyle/checkstyle.xml:EssentialsX" />
<entry key="checkstyle-version" value="8.36.2" />
<entry key="copy-libs" value="true" />
<entry key="location-0" value="BUNDLED:(bundled):Sun Checks" />
<entry key="location-1" value="BUNDLED:(bundled):Google Checks" />
<entry key="location-2" value="PROJECT_RELATIVE:$PROJECT_DIR$/.checkstyle/checkstyle.xml:EssentialsX" />
<entry key="property-2.configDirectory" value=".checkstyle/" />
<entry key="scan-before-checkin" value="true" />
<entry key="scanscope" value="JavaOnly" />
<entry key="suppress-errors" value="false" />
</map>
<component name="CheckStyle-IDEA" serialisationVersion="2">
<checkstyleVersion>8.36.2</checkstyleVersion>
<scanScope>JavaOnly</scanScope>
<copyLibs>true</copyLibs>
<scanBeforeCheckin>true</scanBeforeCheckin>
<option name="thirdPartyClasspath" />
<option name="activeLocationIds">
<option value="321e5753-4201-4d2c-bf31-6232011122fd" />
</option>
<option name="locations">
<list>
<ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">(bundled)</ConfigurationLocation>
<ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">(bundled)</ConfigurationLocation>
<ConfigurationLocation id="321e5753-4201-4d2c-bf31-6232011122fd" type="PROJECT_RELATIVE" scope="All" description="EssentialsX">
$PROJECT_DIR$/.checkstyle/checkstyle.xml
<option name="properties">
<map>
<entry key="configDirectory" value=".checkstyle/" />
</map>
</option>
</ConfigurationLocation>
</list>
</option>
</component>
</project>

View File

@ -1,31 +1,102 @@
Contributing to EssentialsX
===========================
# Contributing to EssentialsX
Want to help improve EssentialsX? There are several ways you can support and contribute to the project.
*By contributing to EssentialsX, you agree to license your changes under the [GNU General Public License version 3](https://github.com/EssentialsX/Essentials/blob/2.x/LICENSE).*
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:
## Submitting code changes to EssentialsX
* 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.
If you're interested in submitting new code to EssentialsX, we accept changes via GitHub pull requests.
Submitting a PR
---------------
### Adding features
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)
In general, we will only consider PRs for features if they have already been discussed with the team through
GitHub issues and discussions. Check the list of
["open to PR" issues](https://github.com/EssentialsX/Essentials/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22status%3A+open+to+PR%22)
and [feature request discussions](https://github.com/EssentialsX/Essentials/discussions/categories/ideas-and-feature-suggestions)
before you start working on your changes. If you don't see your desired feature listed,
[open a feature request](https://github.com/EssentialsX/Essentials/issues/new/choose) and wait for a response, otherwise
you may end up wasting your time on a feature that we aren't in a position to accept.
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.
#### Keep it focused
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).
Please try to keep feature PRs focused around one feature. Your PR should ideally contain
one feature, or a few closely-linked features. If you submit several unrelated features
in one PR, the PR will not be accepted.
### Fixing bugs
If you're opening a PR to fix a bug, please ensure a bug report has been filed - search the
[issue tracker](https://github.com/EssentialsX/Essentials/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22bug%3A+confirmed%22%2C%22bug%3A+unconfirmed%22%2C%22bug%3A+upstream%22)
for an existing report, and if you can't find a bug report,
[create one](https://github.com/EssentialsX/Essentials/issues/new/choose) before you submit your PR.
#### Unconfirmed bugs
You may find a bug report with the label `bug: unconfirmed`. This means the EssentialsX team hasn't had the time
to review the bug report yet or hasn't been able to confirm
whether the reported issue is actually a bug in EssentialsX. You can help us by following the steps in the report and
posting whether you are able to replicate this issue, ideally on the latest versions of EssentialsX and Paper. This will
help us confirm issues and prioritise PRs accordingly.
#### Upstream bugs
You may also find bug reports with the `bug: upstream` label. This label means the issue is caused by a bug in *another
project*, not EssentialsX. This includes bugs in CraftBukkit/Spigot and bugs in other plugins. It may be appropriate to
mitigate an issue in EssentialsX, but please check with us in the [EssentialsX Development Discord server](https://discord.gg/CUN7qVb) before you submit a PR.
### Making your changes
You'll need the following to make your changes to EssentialsX:
* A GitHub account
* [`git`](https://git-scm.com/downloads): the Git command-line tool, used to track and save your changes
* [`gh`](https://cli.github.com/): the GitHub command-line tool, used to submit your changes to EssentialsX
* Your IDE of choice - we recommend [IntelliJ IDEA Community Edition](https://www.jetbrains.com/idea/download)
If you're already familiar with Git, you can skip this next section.
You'll need to clone the EssentialsX repository
(`gh repo clone EssentialsX/Essentials`), then create a new branch for your work
(`cd Essentials` then `git switch -c my-cool-pr`).
You can then make changes using your IDE of choice. Follow the instructions in `README.md` to build and test your
changes.
Once you've finished, you should commit your changes (`git commit -am "My cool commit name!"`).
### Submitting your PR
*Even if you're already familiar with GitHub, you will need to follow these steps in order to submit a PR to
EssentialsX. This ensures we have the information we need to test and review your changes.*
Next, you'll need to fork EssentialsX on GitHub and push your changes to a branch on that fork. We strongly recommend
using the `gh` command-line tool for this:
* In your terminal, run `gh pr create`.
* Select either the bug fix or feature template, depending on what your PR is for.
* If you get asked `Where should we push the '...' branch?`, select `Create a fork of EssentialsX/Essentials`.
* For the title, choose a title that describes what your PR does. For example, `Add more ducks to /spawnmob`.
* For the body, press E. You will then need to fill in the PR template in your text editor.
- Follow the instructions in the template and fill out the sections as required.
- This step is important! Without it, we won't know why you've made your changes or how to test them.
* Save the file in your text editor and close it, then return to the terminal.
* Select `Submit` to open your PR.
If you follow these steps correctly, GitHub will create a fork (if necessary) and then open a PR with your changes. You
can now sit back while we review your changes. If we need to ask questions or request further changes to your code,
we will review your PR and post a comment on GitHub. You can respond to our reviews and comments on the GitHub website,
and you can push new changes using `git commit` and `git push`.
## Submitting community translations to EssentialsX
EssentialsX relies on community translations for its messages in other languages. You can help translate EssentialsX on
[Crowdin](https://translate.essentialsx.net/). You'll need a Crowdin account to translate and improve messages.
If your language isn't listed or doesn't have an active proofreader, please let us know on Discord (see below).
## Discussing EssentialsX contributions
Want to discuss something before opening a PR or translating messages? 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.

View File

@ -6,18 +6,21 @@ dependencies {
compileOnly('com.github.milkbowl:VaultAPI:1.7') {
exclude group: "org.bukkit", module: "bukkit"
}
compileOnly 'net.luckperms:api:5.0'
compileOnly 'net.luckperms:api:5.3'
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'
implementation 'org.checkerframework:checker-qual:3.21.0'
implementation 'nu.studer:java-ordered-properties:1.0.4'
implementation 'net.kyori:adventure-api:4.15.0'
implementation 'net.kyori:adventure-text-minimessage:4.15.0'
implementation 'net.kyori:adventure-platform-bukkit:4.3.2'
// Providers
api project(':providers:BaseProviders')
api project(':providers:PaperProvider')
api project(path: ':providers:PaperProvider', configuration: 'shadow')
api(project(':providers:NMSReflectionProvider')) {
exclude group: "org.bukkit", module: "bukkit"
}
@ -29,6 +32,10 @@ dependencies {
}
}
test {
testLogging.showStandardStreams = true
}
shadowJar {
dependencies {
include (dependency('io.papermc:paperlib'))
@ -39,8 +46,25 @@ shadowJar {
include (dependency('org.yaml:snakeyaml'))
include (dependency('io.leangen.geantyref:geantyref'))
include (dependency('org.checkerframework:checker-qual'))
include (dependency('nu.studer:java-ordered-properties'))
include (dependency('net.kyori:adventure-api'))
include (dependency('net.kyori:adventure-key'))
include (dependency('net.kyori:examination-api'))
include (dependency('net.kyori:examination-string'))
include (dependency('net.kyori:option'))
include (dependency('net.kyori:adventure-platform-bukkit'))
include (dependency('net.kyori:adventure-platform-api'))
include (dependency('net.kyori:adventure-platform-facet'))
include (dependency('net.kyori:adventure-nbt'))
include (dependency('net.kyori:adventure-text-serializer-bungeecord'))
include (dependency('net.kyori:adventure-text-serializer-gson'))
include (dependency('net.kyori:adventure-text-serializer-gson-legacy-impl'))
include (dependency('net.kyori:adventure-text-serializer-json'))
include (dependency('net.kyori:adventure-text-serializer-json-legacy-impl'))
include (dependency('net.kyori:adventure-text-serializer-legacy'))
include (dependency('net.kyori:adventure-text-minimessage'))
include (project(':providers:BaseProviders'))
include (project(':providers:PaperProvider'))
include (project(path: ':providers:PaperProvider', configuration: 'shadow'))
include (project(':providers:NMSReflectionProvider'))
include (project(':providers:1_8Provider'))
include (project(':providers:1_12Provider'))
@ -51,8 +75,13 @@ shadowJar {
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'
relocate 'net.kyori', 'com.earth2me.essentials.libs.kyori'
relocate 'net.essentialsx.temp.adventure', 'net.kyori.adventure'
minimize {
include(dependency('org.checkerframework:checker-qual'))
include(dependency('net.kyori:adventure-api'))
include(dependency('net.kyori:adventure-platform-bukkit'))
include(dependency('net.kyori:adventure-text-minimessage'))
}
}

View File

@ -4,6 +4,7 @@ import org.bukkit.command.Command;
import org.bukkit.command.PluginIdentifiableCommand;
import org.bukkit.plugin.Plugin;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@ -11,11 +12,9 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
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<Command>> altcommands = new HashMap<>();
private final transient Map<String, List<WeakReference<Command>>> altCommands = new HashMap<>();
private final transient Map<String, String> disabledList = new HashMap<>();
private final transient IEssentials ess;
@ -37,17 +36,30 @@ public class AlternativeCommandsHandler {
final String commandName = commandSplit.length > 1 ? commandSplit[1] : entry.getKey();
final Command command = entry.getValue();
final List<Command> pluginCommands = altcommands.computeIfAbsent(commandName.toLowerCase(Locale.ENGLISH), k -> new ArrayList<>());
final List<WeakReference<Command>> pluginCommands = altCommands.computeIfAbsent(commandName.toLowerCase(Locale.ENGLISH), k -> new ArrayList<>());
boolean found = false;
for (final Command pc2 : pluginCommands) {
final Iterator<WeakReference<Command>> pluginCmdIterator = pluginCommands.iterator();
while (pluginCmdIterator.hasNext()) {
final Command cmd = pluginCmdIterator.next().get();
if (cmd == null) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "Essentials: Alternative command for " + commandName + " removed due to garbage collection");
}
pluginCmdIterator.remove();
continue;
}
// Safe cast, everything that's added comes from getPluginCommands which already performs the cast check.
if (((PluginIdentifiableCommand) pc2).getPlugin().equals(plugin)) {
if (((PluginIdentifiableCommand) cmd).getPlugin().equals(plugin)) {
found = true;
break;
}
}
if (!found) {
pluginCommands.add(command);
pluginCommands.add(new WeakReference<>(command));
}
}
}
@ -63,10 +75,19 @@ public class AlternativeCommandsHandler {
}
public void removePlugin(final Plugin plugin) {
final Iterator<Map.Entry<String, List<Command>>> iterator = altcommands.entrySet().iterator();
final Iterator<Map.Entry<String, List<WeakReference<Command>>>> iterator = altCommands.entrySet().iterator();
while (iterator.hasNext()) {
final Map.Entry<String, List<Command>> entry = iterator.next();
entry.getValue().removeIf(pc -> !(pc instanceof PluginIdentifiableCommand) || ((PluginIdentifiableCommand) pc).getPlugin().equals(plugin));
final Map.Entry<String, List<WeakReference<Command>>> entry = iterator.next();
final Iterator<WeakReference<Command>> commands = entry.getValue().iterator();
while (commands.hasNext()) {
final Command pc = commands.next().get();
if (pc instanceof PluginIdentifiableCommand && !((PluginIdentifiableCommand) pc).getPlugin().equals(plugin)) {
continue;
}
commands.remove();
}
if (entry.getValue().isEmpty()) {
iterator.remove();
}
@ -74,28 +95,38 @@ public class AlternativeCommandsHandler {
}
public Command getAlternative(final String label) {
final List<Command> commands = altcommands.get(label);
final List<WeakReference<Command>> commands = altCommands.get(label);
if (commands == null || commands.isEmpty()) {
return null;
}
if (commands.size() == 1) {
return commands.get(0);
return commands.get(0).get();
}
// return the first command that is not an alias
for (final Command command : commands) {
if (command.getName().equalsIgnoreCase(label)) {
return command;
final Iterator<WeakReference<Command>> iterator = commands.iterator();
while (iterator.hasNext()) {
final Command cmd = iterator.next().get();
if (cmd == null) {
iterator.remove();
continue;
}
if (cmd.getName().equalsIgnoreCase(label)) {
return cmd;
}
}
// return the first alias
return commands.get(0);
return commands.get(0).get();
}
public void executed(final String label, final Command pc) {
if (pc instanceof PluginIdentifiableCommand) {
final String altString = ((PluginIdentifiableCommand) pc).getPlugin().getName() + ":" + pc.getName();
if (ess.getSettings().isDebug()) {
LOGGER.log(Level.INFO, "Essentials: Alternative command " + label + " found, using " + altString);
ess.getLogger().log(Level.INFO, "Essentials: Alternative command " + label + " found, using " + altString);
}
disabledList.put(label, altString);
}

View File

@ -8,6 +8,7 @@ import io.papermc.lib.PaperLib;
import net.ess3.api.IEssentials;
import net.ess3.api.IUser;
import net.ess3.api.InvalidWorldException;
import net.ess3.api.TranslatableException;
import net.ess3.api.events.UserWarpEvent;
import net.ess3.api.events.teleport.PreTeleportEvent;
import net.ess3.api.events.teleport.TeleportWarmupEvent;
@ -23,8 +24,6 @@ import java.util.GregorianCalendar;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import static com.earth2me.essentials.I18n.tl;
public class AsyncTeleport implements IAsyncTeleport {
private final IUser teleportOwner;
private final IEssentials ess;
@ -73,7 +72,7 @@ public class AsyncTeleport implements IAsyncTeleport {
time.setTimeInMillis(lastTime);
time.add(Calendar.SECOND, (int) cooldown);
time.add(Calendar.MILLISECOND, (int) ((cooldown * 1000.0) % 1000.0));
future.completeExceptionally(new Exception(tl("timeBeforeTeleport", DateUtil.formatDateDiff(time.getTimeInMillis()))));
future.completeExceptionally(new TranslatableException("timeBeforeTeleport", DateUtil.formatDateDiff(time.getTimeInMillis())));
return true;
}
}
@ -107,7 +106,7 @@ public class AsyncTeleport implements IAsyncTeleport {
final Calendar c = new GregorianCalendar();
c.add(Calendar.SECOND, (int) delay);
c.add(Calendar.MILLISECOND, (int) ((delay * 1000.0) % 1000.0));
user.sendMessage(tl("dontMoveMessage", DateUtil.formatDateDiff(c.getTimeInMillis())));
user.sendTl("dontMoveMessage", DateUtil.formatDateDiff(c.getTimeInMillis()));
}
@Override
@ -129,7 +128,7 @@ public class AsyncTeleport implements IAsyncTeleport {
nowAsync(teleportOwner, target, cause, future);
future.thenAccept(success -> {
if (success) {
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
teleportOwner.sendTl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ());
}
});
}
@ -166,7 +165,7 @@ public class AsyncTeleport implements IAsyncTeleport {
if (!ess.getSettings().isForcePassengerTeleport() && !teleportee.getBase().isEmpty()) {
if (!ess.getSettings().isTeleportPassengerDismount()) {
future.completeExceptionally(new Exception(tl("passengerTeleportFail")));
future.completeExceptionally(new TranslatableException("passengerTeleportFail"));
return;
}
@ -204,7 +203,7 @@ public class AsyncTeleport implements IAsyncTeleport {
}
}
} else {
future.completeExceptionally(new Exception(tl("unsafeTeleportDestination", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())));
future.completeExceptionally(new TranslatableException("unsafeTeleportDestination", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
return;
}
} else {
@ -233,7 +232,7 @@ public class AsyncTeleport implements IAsyncTeleport {
@Override
public void teleport(final Player entity, final Trade chargeFor, final TeleportCause cause, final CompletableFuture<Boolean> future) {
teleportOwner.sendMessage(tl("teleportToPlayer", entity.getDisplayName()));
teleportOwner.sendTl("teleportToPlayer", entity.getDisplayName());
teleport(teleportOwner, new PlayerTarget(entity), chargeFor, cause, future);
}
@ -248,8 +247,8 @@ public class AsyncTeleport implements IAsyncTeleport {
teleport(otherUser, target, chargeFor, cause, future);
future.thenAccept(success -> {
if (success) {
otherUser.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
otherUser.sendTl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ());
teleportOwner.sendTl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ());
}
});
}
@ -308,7 +307,7 @@ public class AsyncTeleport implements IAsyncTeleport {
private void teleportOther(final IUser teleporter, final IUser teleportee, final ITarget target, final Trade chargeFor, final TeleportCause cause, final CompletableFuture<Boolean> future) {
double delay = ess.getSettings().getTeleportDelay();
final TeleportWarmupEvent event = new TeleportWarmupEvent(teleportee, cause, target, delay);
final TeleportWarmupEvent event = new TeleportWarmupEvent(teleporter, teleportee, cause, target, delay);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
@ -432,9 +431,9 @@ public class AsyncTeleport implements IAsyncTeleport {
final String finalWarp = warp;
future.thenAccept(success -> {
if (success) {
otherUser.sendMessage(tl("warpingTo", finalWarp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
otherUser.sendTl("warpingTo", finalWarp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
if (!otherUser.equals(teleportOwner)) {
teleportOwner.sendMessage(tl("warpingTo", finalWarp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
teleportOwner.sendTl("warpingTo", finalWarp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
}
}
});
@ -450,7 +449,7 @@ public class AsyncTeleport implements IAsyncTeleport {
public void back(final IUser teleporter, final Trade chargeFor, final CompletableFuture<Boolean> future) {
tpType = TeleportType.BACK;
final Location loc = teleportOwner.getLastLocation();
teleportOwner.sendMessage(tl("backUsageMsg", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
teleportOwner.sendTl("backUsageMsg", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
teleportOther(teleporter, teleportOwner, new LocationTarget(loc), chargeFor, TeleportCause.COMMAND, future);
}

View File

@ -8,8 +8,6 @@ import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import static com.earth2me.essentials.I18n.tl;
public class AsyncTimedTeleport implements Runnable {
private static final double MOVE_CONSTANT = 0.3;
private final IUser teleportOwner;
@ -106,14 +104,14 @@ public class AsyncTimedTeleport implements Runnable {
try {
teleport.cooldown(false);
} catch (final Throwable ex) {
teleportOwner.sendMessage(tl("cooldownWithMessage", ex.getMessage()));
teleportOwner.sendTl("cooldownWithMessage", ex.getMessage());
if (teleportOwner != teleportUser) {
teleportUser.sendMessage(tl("cooldownWithMessage", ex.getMessage()));
teleportUser.sendTl("cooldownWithMessage", ex.getMessage());
}
}
try {
cancelTimer(false);
teleportUser.sendMessage(tl("teleportationCommencing"));
teleportUser.sendTl("teleportationCommencing");
if (timer_chargeFor != null) {
timer_chargeFor.isAffordableFor(teleportOwner);
@ -152,9 +150,9 @@ public class AsyncTimedTeleport implements Runnable {
try {
ess.getServer().getScheduler().cancelTask(timer_task);
if (notifyUser) {
teleportOwner.sendMessage(tl("pendingTeleportCancelled"));
teleportOwner.sendTl("pendingTeleportCancelled");
if (timer_teleportee != null && !timer_teleportee.equals(teleportOwner.getBase().getUniqueId())) {
ess.getUser(timer_teleportee).sendMessage(tl("pendingTeleportCancelled"));
ess.getUser(timer_teleportee).sendTl("pendingTeleportCancelled");
}
}
} finally {

View File

@ -1,5 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.AdventureUtil;
import net.ess3.api.IEssentials;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
@ -10,12 +11,10 @@ import java.io.InputStreamReader;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public class Backup implements Runnable {
private static final Logger LOGGER = Logger.getLogger("Essentials");
private transient final Server server;
private transient final IEssentials ess;
private final AtomicBoolean pendingShutdown = new AtomicBoolean(false);
@ -81,7 +80,7 @@ public class Backup implements Runnable {
taskLock.complete(new Object());
return;
}
LOGGER.log(Level.INFO, tl("backupStarted"));
ess.getLogger().log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("backupStarted")));
final CommandSender cs = server.getConsoleSender();
server.dispatchCommand(cs, "save-all");
server.dispatchCommand(cs, "save-off");
@ -99,17 +98,17 @@ public class Backup implements Runnable {
do {
line = reader.readLine();
if (line != null) {
LOGGER.log(Level.INFO, line);
ess.getLogger().log(Level.INFO, line);
}
} while (line != null);
}
} catch (final IOException ex) {
LOGGER.log(Level.SEVERE, null, ex);
ess.getLogger().log(Level.SEVERE, "An error occurred while reading backup child process", ex);
}
});
child.waitFor();
} catch (final InterruptedException | IOException ex) {
LOGGER.log(Level.SEVERE, null, ex);
ess.getLogger().log(Level.SEVERE, "An error occurred while building the backup child process", ex);
} finally {
class BackupEnableSaveTask implements Runnable {
@Override
@ -120,7 +119,7 @@ public class Backup implements Runnable {
}
active = false;
taskLock.complete(new Object());
LOGGER.log(Level.INFO, tl("backupFinished"));
ess.getLogger().log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("backupFinished")));
}
}

View File

@ -28,8 +28,8 @@ public class BalanceTopImpl implements BalanceTop {
private void calculateBalanceTopMap() {
final List<Entry> entries = new LinkedList<>();
BigDecimal newTotal = BigDecimal.ZERO;
for (UUID u : ess.getUserMap().getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
for (UUID u : ess.getUsers().getAllUserUUIDs()) {
final User user = ess.getUsers().loadUncachedUser(u);
if (user != null) {
if (!ess.getSettings().isNpcsInBalanceRanking() && user.isNPC()) {
// Don't list NPCs in output
@ -40,7 +40,7 @@ public class BalanceTopImpl implements BalanceTop {
user.updateMoneyCache(userMoney);
newTotal = newTotal.add(userMoney);
final String name;
if (user.getBase() instanceof OfflinePlayer) {
if (user.getBase() instanceof OfflinePlayerStub) {
name = user.getLastAccountName();
} else if (user.isHidden()) {
name = user.getName();

View File

@ -1,11 +1,9 @@
package com.earth2me.essentials;
public class ChargeException extends Exception {
public ChargeException(final String message) {
super(message);
}
import net.ess3.api.TranslatableException;
public ChargeException(final String message, final Throwable throwable) {
super(message, throwable);
public class ChargeException extends TranslatableException {
public ChargeException(String tlKey, Object... args) {
super(tlKey, args);
}
}

View File

@ -1,12 +1,19 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.AdventureUtil;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import static com.earth2me.essentials.I18n.tlLiteral;
public class CommandSource {
protected Essentials ess;
protected CommandSender sender;
public CommandSource(final CommandSender base) {
public CommandSource(final Essentials ess, final CommandSender base) {
this.ess = ess;
this.sender = base;
}
@ -21,7 +28,42 @@ public class CommandSource {
return null;
}
public final net.ess3.api.IUser getUser(final IEssentials ess) {
public void sendTl(final String tlKey, final Object... args) {
if (isPlayer()) {
//noinspection ConstantConditions
getUser().sendTl(tlKey, args);
return;
}
final String translation = tlLiteral(tlKey, args);
if (!translation.isEmpty()) {
sendComponent(AdventureUtil.miniMessage().deserialize(translation));
}
}
public String tl(final String tlKey, final Object... args) {
if (isPlayer()) {
//noinspection ConstantConditions
return getUser().playerTl(tlKey, args);
}
return tlLiteral(tlKey, args);
}
public Component tlComponent(final String tlKey, final Object... args) {
if (isPlayer()) {
//noinspection ConstantConditions
return getUser().tlComponent(tlKey, args);
}
final String translation = tlLiteral(tlKey, args);
return AdventureUtil.miniMessage().deserialize(translation);
}
public void sendComponent(final Component component) {
final BukkitAudiences audiences = ess.getBukkitAudience();
audiences.sender(sender).sendMessage(component);
}
public final net.ess3.api.IUser getUser() {
if (sender instanceof Player) {
return ess.getUser((Player) sender);
}
@ -42,15 +84,18 @@ public class CommandSource {
}
}
public boolean isAuthorized(final String permission, final IEssentials ess) {
return !(sender instanceof Player) || getUser(ess).isAuthorized(permission);
public boolean isAuthorized(final String permission) {
//noinspection ConstantConditions
return !(sender instanceof Player) || getUser().isAuthorized(permission);
}
public String getSelfSelector() {
//noinspection ConstantConditions
return sender instanceof Player ? getPlayer().getName() : "*";
}
public String getDisplayName() {
//noinspection ConstantConditions
return sender instanceof Player ? getPlayer().getDisplayName() : getSender().getName();
}
}

View File

@ -2,17 +2,20 @@ package com.earth2me.essentials;
import com.earth2me.essentials.messaging.IMessageRecipient;
import com.earth2me.essentials.messaging.SimpleMessageRecipient;
import com.earth2me.essentials.utils.AdventureUtil;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.UUID;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public final class Console implements IMessageRecipient {
public static final String NAME = "Console";
public static final String DISPLAY_NAME = tl("consoleName");
public static final String DISPLAY_NAME = tlLiteral("consoleName");
private static Console instance; // Set in essentials
private final IEssentials ess;
@ -63,6 +66,24 @@ public final class Console implements IMessageRecipient {
getCommandSender().sendMessage(message);
}
@Override
public void sendTl(String tlKey, Object... args) {
final String translation = tlLiteral(tlKey, args);
if (translation.isEmpty()) {
return;
}
final Audience consoleAudience = ((Essentials) ess).getBukkitAudience().sender(getCommandSender());
final Component component = AdventureUtil.miniMessage()
.deserialize(translation);
consoleAudience.sendMessage(component);
}
@Override
public String tlSender(String tlKey, Object... args) {
return tlLiteral(tlKey, args);
}
@Override
public boolean isReachable() {
return true;

View File

@ -263,6 +263,14 @@ public final class Enchantments {
} catch (final IllegalArgumentException ignored) {
}
try { // 1.19
final Enchantment swiftSneak = Enchantment.getByName("SWIFT_SNEAK");
if (swiftSneak != null) {
ENCHANTMENTS.put("swiftsneak", swiftSneak);
}
} catch (final IllegalArgumentException ignored) {
}
try {
final Class<?> namespacedKeyClass = Class.forName("org.bukkit.NamespacedKey");
final Class<?> enchantmentClass = Class.forName("org.bukkit.enchantments.Enchantment");

View File

@ -39,6 +39,8 @@ import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.updatecheck.UpdateChecker;
import com.earth2me.essentials.userstorage.ModernUserMap;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.VersionUtil;
import io.papermc.lib.PaperLib;
@ -47,6 +49,7 @@ import net.ess3.api.IEssentials;
import net.ess3.api.IItemDb;
import net.ess3.api.IJails;
import net.ess3.api.ISettings;
import net.ess3.api.TranslatableException;
import net.ess3.nms.refl.providers.ReflDataWorldInfoProvider;
import net.ess3.nms.refl.providers.ReflFormattedCommandAliasProvider;
import net.ess3.nms.refl.providers.ReflKnownCommandsProvider;
@ -56,33 +59,44 @@ import net.ess3.nms.refl.providers.ReflServerStateProvider;
import net.ess3.nms.refl.providers.ReflSpawnEggProvider;
import net.ess3.nms.refl.providers.ReflSpawnerBlockProvider;
import net.ess3.nms.refl.providers.ReflSyncCommandsProvider;
import net.ess3.provider.BiomeKeyProvider;
import net.ess3.provider.ContainerProvider;
import net.ess3.provider.DamageEventProvider;
import net.ess3.provider.FormattedCommandAliasProvider;
import net.ess3.provider.ItemUnbreakableProvider;
import net.ess3.provider.KnownCommandsProvider;
import net.ess3.provider.MaterialTagProvider;
import net.ess3.provider.PersistentDataProvider;
import net.ess3.provider.PlayerLocaleProvider;
import net.ess3.provider.PotionMetaProvider;
import net.ess3.provider.ProviderListener;
import net.ess3.provider.SerializationProvider;
import net.ess3.provider.ServerStateProvider;
import net.ess3.provider.SignDataProvider;
import net.ess3.provider.SpawnEggProvider;
import net.ess3.provider.SpawnerBlockProvider;
import net.ess3.provider.SpawnerItemProvider;
import net.ess3.provider.SyncCommandsProvider;
import net.ess3.provider.WorldInfoProvider;
import net.ess3.provider.providers.BaseLoggerProvider;
import net.ess3.provider.providers.BasePotionDataProvider;
import net.ess3.provider.providers.BlockMetaSpawnerItemProvider;
import net.ess3.provider.providers.BukkitMaterialTagProvider;
import net.ess3.provider.providers.BukkitSpawnerBlockProvider;
import net.ess3.provider.providers.FixedHeightWorldInfoProvider;
import net.ess3.provider.providers.FlatSpawnEggProvider;
import net.ess3.provider.providers.LegacyDamageEventProvider;
import net.ess3.provider.providers.LegacyItemUnbreakableProvider;
import net.ess3.provider.providers.LegacyPlayerLocaleProvider;
import net.ess3.provider.providers.LegacyPotionMetaProvider;
import net.ess3.provider.providers.LegacySpawnEggProvider;
import net.ess3.provider.providers.ModernDamageEventProvider;
import net.ess3.provider.providers.ModernDataWorldInfoProvider;
import net.ess3.provider.providers.ModernItemUnbreakableProvider;
import net.ess3.provider.providers.ModernPersistentDataProvider;
import net.ess3.provider.providers.ModernDataWorldInfoProvider;
import net.ess3.provider.providers.ModernPlayerLocaleProvider;
import net.ess3.provider.providers.ModernSignDataProvider;
import net.ess3.provider.providers.PaperBiomeKeyProvider;
import net.ess3.provider.providers.PaperContainerProvider;
import net.ess3.provider.providers.PaperKnownCommandsProvider;
import net.ess3.provider.providers.PaperMaterialTagProvider;
@ -91,6 +105,8 @@ import net.ess3.provider.providers.PaperSerializationProvider;
import net.ess3.provider.providers.PaperServerStateProvider;
import net.essentialsx.api.v2.services.BalanceTop;
import net.essentialsx.api.v2.services.mail.MailService;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.World;
@ -136,12 +152,15 @@ import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
import static com.earth2me.essentials.I18n.tlLocale;
public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
private static final Logger LOGGER = Logger.getLogger("Essentials");
private final transient TNTExplodeListener tntListener = new TNTExplodeListener(this);
private static final Logger BUKKIT_LOGGER = Logger.getLogger("Essentials");
private static Logger LOGGER = null;
private final transient TNTExplodeListener tntListener = new TNTExplodeListener();
private final transient Set<String> vanishedPlayers = new LinkedHashSet<>();
private final transient Map<String, IEssentialsCommand> commandMap = new HashMap<>();
private transient ISettings settings;
private transient Jails jails;
private transient Warps warps;
@ -152,7 +171,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
private transient CustomItemResolver customItemResolver;
private transient PermissionsHandler permissionsHandler;
private transient AlternativeCommandsHandler alternativeCommandsHandler;
private transient UserMap userMap;
@Deprecated
private transient UserMap legacyUserMap;
private transient ModernUserMap userMap;
private transient BalanceTopImpl balanceTop;
private transient ExecuteTimer execTimer;
private transient MailService mail;
@ -175,10 +196,14 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
private transient ReflOnlineModeProvider onlineModeProvider;
private transient ItemUnbreakableProvider unbreakableProvider;
private transient WorldInfoProvider worldInfoProvider;
private transient PlayerLocaleProvider playerLocaleProvider;
private transient SignDataProvider signDataProvider;
private transient DamageEventProvider damageEventProvider;
private transient BiomeKeyProvider biomeKeyProvider;
private transient Kits kits;
private transient RandomTeleport randomTeleport;
private transient UpdateChecker updateChecker;
private transient Map<String, IEssentialsCommand> commandMap = new HashMap<>();
private transient BukkitAudiences bukkitAudience;
static {
EconomyLayers.init();
@ -201,6 +226,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
public void setupForTesting(final Server server) throws IOException, InvalidDescriptionException {
LOGGER = new BaseLoggerProvider(this, BUKKIT_LOGGER);
final File dataFolder = File.createTempFile("essentialstest", "");
if (!dataFolder.delete()) {
throw new IOException();
@ -213,11 +239,11 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
i18n.updateLocale("en");
Console.setInstance(this);
LOGGER.log(Level.INFO, tl("usingTempFolderForTesting"));
LOGGER.log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("usingTempFolderForTesting")));
LOGGER.log(Level.INFO, dataFolder.toString());
settings = new Settings(this);
mail = new MailServiceImpl(this);
userMap = new UserMap(this);
userMap = new ModernUserMap(this);
balanceTop = new BalanceTopImpl(this);
permissionsHandler = new PermissionsHandler(this, false);
Economy.setEss(this);
@ -225,6 +251,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
jails = new Jails(this);
registerListeners(server.getPluginManager());
kits = new Kits(this);
bukkitAudience = BukkitAudiences.create(this);
}
@Override
@ -241,11 +268,19 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
@Override
public void onEnable() {
try {
if (LOGGER != this.getLogger()) {
LOGGER.setParent(this.getLogger());
if (BUKKIT_LOGGER != super.getLogger()) {
BUKKIT_LOGGER.setParent(super.getLogger());
}
LOGGER = EssentialsLogger.getLoggerProvider(this);
EssentialsLogger.updatePluginLogger(this);
execTimer = new ExecuteTimer();
execTimer.start();
final EssentialsUpgrade upgrade = new EssentialsUpgrade(this);
upgrade.upgradeLang();
execTimer.mark("AdventureUpgrade");
i18n = new I18n(this);
i18n.onEnable();
execTimer.mark("I18n1");
@ -254,34 +289,36 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
switch (VersionUtil.getServerSupportStatus()) {
case NMS_CLEANROOM:
getLogger().severe(tl("serverUnsupportedCleanroom"));
getLogger().severe(AdventureUtil.miniToLegacy(tlLiteral("serverUnsupportedCleanroom")));
break;
case DANGEROUS_FORK:
getLogger().severe(tl("serverUnsupportedDangerous"));
getLogger().severe(AdventureUtil.miniToLegacy(tlLiteral("serverUnsupportedDangerous")));
break;
case STUPID_PLUGIN:
getLogger().severe(AdventureUtil.miniToLegacy(tlLiteral("serverUnsupportedDumbPlugins")));
break;
case UNSTABLE:
getLogger().severe(tl("serverUnsupportedMods"));
getLogger().severe(AdventureUtil.miniToLegacy(tlLiteral("serverUnsupportedMods")));
break;
case OUTDATED:
getLogger().severe(tl("serverUnsupported"));
getLogger().severe(AdventureUtil.miniToLegacy(tlLiteral("serverUnsupported")));
break;
case LIMITED:
getLogger().info(tl("serverUnsupportedLimitedApi"));
getLogger().info(AdventureUtil.miniToLegacy(tlLiteral("serverUnsupportedLimitedApi")));
break;
}
if (VersionUtil.getSupportStatusClass() != null) {
getLogger().info(tl("serverUnsupportedClass", VersionUtil.getSupportStatusClass()));
getLogger().info(AdventureUtil.miniToLegacy(tlLiteral("serverUnsupportedClass", VersionUtil.getSupportStatusClass())));
}
final PluginManager pm = getServer().getPluginManager();
for (final 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()));
getLogger().warning(AdventureUtil.miniToLegacy(tlLiteral("versionMismatch", plugin.getDescription().getName())));
}
}
final EssentialsUpgrade upgrade = new EssentialsUpgrade(this);
upgrade.beforeSettings();
execTimer.mark("Upgrade");
@ -290,11 +327,14 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
confList.add(settings);
execTimer.mark("Settings");
upgrade.preModules();
execTimer.mark("Upgrade2");
mail = new MailServiceImpl(this);
execTimer.mark("Init(Mail)");
userMap = new UserMap(this);
confList.add(userMap);
userMap = new ModernUserMap(this);
legacyUserMap = new UserMap(userMap);
execTimer.mark("Init(Usermap)");
balanceTop = new BalanceTopImpl(this);
@ -306,7 +346,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
execTimer.mark("Kits");
upgrade.afterSettings();
execTimer.mark("Upgrade2");
execTimer.mark("Upgrade3");
warps = new Warps(this.getDataFolder());
confList.add(warps);
@ -432,6 +472,26 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
worldInfoProvider = new FixedHeightWorldInfoProvider();
}
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_14_4_R01)) {
signDataProvider = new ModernSignDataProvider(this);
}
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_12_2_R01)) {
playerLocaleProvider = new ModernPlayerLocaleProvider();
} else {
playerLocaleProvider = new LegacyPlayerLocaleProvider();
}
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_20_4_R01)) {
damageEventProvider = new ModernDamageEventProvider();
} else {
damageEventProvider = new LegacyDamageEventProvider();
}
if (PaperLib.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_19_4_R01)) {
biomeKeyProvider = new PaperBiomeKeyProvider();
}
execTimer.mark("Init(Providers)");
reload();
@ -454,9 +514,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
updateChecker = new UpdateChecker(this);
runTaskAsynchronously(() -> {
getLogger().log(Level.INFO, tl("versionFetching"));
for (String str : updateChecker.getVersionMessages(false, true)) {
getLogger().log(getSettings().isUpdateCheckEnabled() ? Level.WARNING : Level.INFO, str);
getLogger().log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("versionFetching")));
for (final Component component : updateChecker.getVersionMessages(false, true, new CommandSource(this, Bukkit.getConsoleSender()))) {
getLogger().log(getSettings().isUpdateCheckEnabled() ? Level.WARNING : Level.INFO, AdventureUtil.adventureToLegacy(component));
}
});
@ -466,7 +526,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
final String timeroutput = execTimer.end();
if (getSettings().isDebug()) {
LOGGER.log(Level.INFO, "Essentials load {0}", timeroutput);
LOGGER.log(Level.INFO, "Essentials load " + timeroutput);
}
} catch (final NumberFormatException ex) {
handleCrash(ex);
@ -477,6 +537,15 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
getBackup().setPendingShutdown(false);
}
// Returns our provider logger if available
public static Logger getWrappedLogger() {
if (LOGGER != null) {
return LOGGER;
}
return BUKKIT_LOGGER;
}
@Override
public void saveConfig() {
// We don't use any of the bukkit config writing, as this breaks our config file formatting.
@ -530,13 +599,13 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
public void onDisable() {
final boolean stopping = getServerStateProvider().isStopping();
if (!stopping) {
LOGGER.log(Level.SEVERE, tl("serverReloading"));
LOGGER.log(Level.SEVERE, AdventureUtil.miniToLegacy(tlLiteral("serverReloading")));
}
getBackup().setPendingShutdown(true);
for (final User user : getOnlineUsers()) {
if (user.isVanished()) {
user.setVanished(false);
user.sendMessage(tl("unvanishedReload"));
user.sendTl("unvanishedReload");
}
if (stopping) {
user.setLogoutLocation();
@ -550,7 +619,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
cleanupOpenInventories();
if (getBackup().getTaskLock() != null && !getBackup().getTaskLock().isDone()) {
LOGGER.log(Level.SEVERE, tl("backupInProgress"));
LOGGER.log(Level.SEVERE, AdventureUtil.miniToLegacy(tlLiteral("backupInProgress")));
getBackup().getTaskLock().join();
}
if (i18n != null) {
@ -564,7 +633,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
Economy.setEss(null);
Trade.closeLog();
getUserMap().getUUIDMap().shutdown();
getUsers().shutdown();
HandlerList.unregisterAll(this);
}
@ -573,6 +642,11 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
public void reload() {
Trade.closeLog();
if (bukkitAudience != null) {
bukkitAudience.close();
bukkitAudience = null;
}
for (final IConf iConf : confList) {
iConf.reloadConfig();
execTimer.mark("Reload(" + iConf.getClass().getSimpleName() + ")");
@ -582,13 +656,16 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
for (final String commandName : this.getDescription().getCommands().keySet()) {
final Command command = this.getCommand(commandName);
if (command != null) {
command.setDescription(tl(commandName + "CommandDescription"));
command.setUsage(tl(commandName + "CommandUsage"));
command.setDescription(tlLiteral(commandName + "CommandDescription"));
command.setUsage(tlLiteral(commandName + "CommandUsage"));
}
}
final PluginManager pm = getServer().getPluginManager();
registerListeners(pm);
AdventureUtil.setEss(this);
bukkitAudience = BukkitAudiences.create(this);
}
private IEssentialsCommand loadCommand(final String path, final String name, final IEssentialsModule module, final ClassLoader classLoader) throws Exception {
@ -625,7 +702,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return completer.onTabComplete(cSender, command, commandLabel, args);
}
} catch (final Exception ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
}
}
}
@ -637,7 +714,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
user = getUser((Player) cSender);
}
final CommandSource sender = new CommandSource(cSender);
final CommandSource sender = new CommandSource(this, cSender);
// Check for disabled commands
if (getSettings().isCommandDisabled(commandLabel)) {
@ -654,8 +731,8 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
try {
cmd = loadCommand(commandPath, command.getName(), module, classLoader);
} catch (final Exception ex) {
sender.sendMessage(tl("commandNotLoaded", commandLabel));
LOGGER.log(Level.SEVERE, tl("commandNotLoaded", commandLabel), ex);
sender.sendTl("commandNotLoaded", commandLabel);
LOGGER.log(Level.SEVERE, AdventureUtil.miniToLegacy(tlLiteral("commandNotLoaded", commandLabel)), ex);
return Collections.emptyList();
}
@ -678,11 +755,11 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
} catch (final Exception ex) {
showError(sender, ex, commandLabel);
// Tab completion shouldn't fail
LOGGER.log(Level.SEVERE, tl("commandFailed", commandLabel), ex);
LOGGER.log(Level.SEVERE, AdventureUtil.miniToLegacy(tlLiteral("commandFailed", commandLabel)), ex);
return Collections.emptyList();
}
} catch (final Throwable ex) {
LOGGER.log(Level.SEVERE, tl("commandFailed", commandLabel), ex);
LOGGER.log(Level.SEVERE, AdventureUtil.miniToLegacy(tlLiteral("commandFailed", commandLabel)), ex);
return Collections.emptyList();
}
}
@ -706,8 +783,12 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
try {
pc.execute(cSender, commandLabel, args);
} catch (final Exception ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
cSender.sendMessage(tl("internalError"));
LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
if (cSender instanceof Player) {
cSender.sendMessage(tlLocale(I18n.getLocale(getPlayerLocaleProvider().getLocale((Player) cSender)), "internalError"));
} else {
cSender.sendMessage(tlLiteral("internalError"));
}
}
return true;
}
@ -726,13 +807,13 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
if (bSenderBlock != null) {
if (getSettings().logCommandBlockCommands()) {
Bukkit.getLogger().log(Level.INFO, "CommandBlock at {0},{1},{2} issued server command: /{3} {4}", new Object[] {bSenderBlock.getX(), bSenderBlock.getY(), bSenderBlock.getZ(), commandLabel, EssentialsCommand.getFinalArg(args, 0)});
LOGGER.log(Level.INFO, "CommandBlock at " + bSenderBlock.getX() + "," + bSenderBlock.getY() + "," + bSenderBlock.getZ() + " issued server command: /" + 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)});
LOGGER.log(Level.INFO, cSender.getName()+ " issued server command: /" + commandLabel + " " + EssentialsCommand.getFinalArg(args, 0));
}
final CommandSource sender = new CommandSource(cSender);
final CommandSource sender = new CommandSource(this, cSender);
// New mail notification
if (user != null && !getSettings().isCommandDisabled("mail") && !command.getName().equals("mail") && user.isAuthorized("essentials.mail")) {
@ -753,7 +834,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return newCmd.execute(cSender, commandLabel, args);
}
}
sender.sendMessage(tl("commandDisabled", commandLabel));
sender.sendTl("commandDisabled", commandLabel);
return true;
}
@ -761,23 +842,23 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
try {
cmd = loadCommand(commandPath, command.getName(), module, classLoader);
} catch (final Exception ex) {
sender.sendMessage(tl("commandNotLoaded", commandLabel));
LOGGER.log(Level.SEVERE, tl("commandNotLoaded", commandLabel), ex);
sender.sendTl("commandNotLoaded", commandLabel);
LOGGER.log(Level.SEVERE, AdventureUtil.miniToLegacy(tlLiteral("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"));
LOGGER.log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("deniedAccessCommand", user.getName())));
user.sendTl("noAccessCommand");
return true;
}
if (user != null && user.isJailed() && !user.isAuthorized(cmd, "essentials.jail.allow.")) {
if (user.getJailTimeout() > 0) {
user.sendMessage(tl("playerJailedFor", user.getName(), user.getFormattedJailTime()));
user.sendTl("playerJailedFor", user.getName(), user.getFormattedJailTime());
} else {
user.sendMessage(tl("jailMessage"));
user.sendTl("jailMessage");
}
return true;
}
@ -794,18 +875,18 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return true;
} catch (final NotEnoughArgumentsException ex) {
if (getSettings().isVerboseCommandUsages() && !cmd.getUsageStrings().isEmpty()) {
sender.sendMessage(tl("commandHelpLine1", commandLabel));
sender.sendMessage(tl("commandHelpLine2", command.getDescription()));
sender.sendMessage(tl("commandHelpLine3"));
sender.sendTl("commandHelpLine1", commandLabel);
sender.sendTl("commandHelpLine2", command.getDescription());
sender.sendTl("commandHelpLine3");
for (Map.Entry<String, String> usage : cmd.getUsageStrings().entrySet()) {
sender.sendMessage(tl("commandHelpLineUsage", usage.getKey().replace("<command>", commandLabel), usage.getValue()));
sender.sendTl("commandHelpLineUsage", AdventureUtil.parsed(usage.getKey().replace("<command>", commandLabel)), AdventureUtil.parsed(usage.getValue()));
}
} else {
sender.sendMessage(command.getDescription());
sender.sendMessage(command.getUsage().replace("<command>", commandLabel));
}
if (!ex.getMessage().isEmpty()) {
sender.sendMessage(ex.getMessage());
sender.sendComponent(AdventureUtil.miniMessage().deserialize(ex.getMessage()));
}
if (ex.getCause() != null && settings.isDebug()) {
ex.getCause().printStackTrace();
@ -819,7 +900,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return true;
}
} catch (final Throwable ex) {
LOGGER.log(Level.SEVERE, tl("commandFailed", commandLabel), ex);
LOGGER.log(Level.SEVERE, AdventureUtil.miniToLegacy(tlLiteral("commandFailed", commandLabel)), ex);
return true;
}
}
@ -845,9 +926,14 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
@Override
public void showError(final CommandSource sender, final Throwable exception, final String commandLabel) {
sender.sendMessage(tl("errorWithMessage", exception.getMessage()));
if (exception instanceof TranslatableException) {
final String tlMessage = sender.tl(((TranslatableException) exception).getTlKey(), ((TranslatableException) exception).getArgs());
sender.sendTl("errorWithMessage", AdventureUtil.parsed(tlMessage));
} else {
sender.sendTl("errorWithMessage", exception.getMessage());
}
if (getSettings().isDebug()) {
LOGGER.log(Level.INFO, tl("errorCallingCommand", commandLabel), exception);
LOGGER.log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("errorCallingCommand", commandLabel)), exception);
}
}
@ -924,17 +1010,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
//This will return null if there is not a match.
@Override
public User getOfflineUser(final String name) {
final User user = userMap.getUser(name);
if (user != null && user.getBase() instanceof OfflinePlayer) {
//This code should attempt to use the last known name of a user, if Bukkit returns name as null.
final String lastName = user.getLastAccountName();
if (lastName != null) {
((OfflinePlayer) user.getBase()).setName(lastName);
} else {
((OfflinePlayer) user.getBase()).setName(name);
}
}
return user;
return userMap.getUser(name);
}
@Override
@ -1022,7 +1098,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return true;
}
return interactor.getBase().canSee(interactee.getBase());
return !interactee.isHiddenFrom(interactor.getBase());
}
//This will create a new user if there is not a match.
@ -1037,14 +1113,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return null;
}
User user = userMap.getUser(base.getUniqueId());
final User user = userMap.getUser(base);
if (user == null) {
if (getSettings().isDebug()) {
LOGGER.log(Level.INFO, "Constructing new userfile from base player {0}", base.getName());
}
user = new User(base, this);
} else {
if (base.getClass() != UUIDPlayer.class || user.getBase() == null) {
user.update(base);
}
return user;
@ -1052,8 +1123,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
private void handleCrash(final Throwable exception) {
final PluginManager pm = getServer().getPluginManager();
LOGGER.log(Level.SEVERE, exception.toString());
exception.printStackTrace();
getWrappedLogger().log(Level.SEVERE, exception.toString(), exception);
pm.registerEvents(new Listener() {
@EventHandler(priority = EventPriority.LOW)
public void onPlayerJoin(final PlayerJoinEvent event) {
@ -1084,12 +1154,12 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
@Override
public int broadcastMessage(final String message) {
return broadcastMessage(null, null, message, true, u -> false);
return broadcastMessage(null, null, message, true, null);
}
@Override
public int broadcastMessage(final IUser sender, final String message) {
return broadcastMessage(sender, null, message, false, u -> false);
return broadcastMessage(sender, null, message, false, null);
}
@Override
@ -1099,7 +1169,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
@Override
public int broadcastMessage(final String permission, final String message) {
return broadcastMessage(null, permission, message, false, u -> false);
return broadcastMessage(null, permission, message, false, null);
}
private int broadcastMessage(final IUser sender, final String permission, final String message, final boolean keywords, final Predicate<IUser> shouldExclude) {
@ -1113,11 +1183,11 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
for (final Player player : players) {
final User user = getUser(player);
if ((permission == null && (sender == null || !user.isIgnoredPlayer(sender))) || (permission != null && user.isAuthorized(permission))) {
if (shouldExclude.test(user)) {
if (shouldExclude != null && shouldExclude.test(user)) {
continue;
}
if (keywords) {
broadcast = new KeywordReplacer(broadcast, new CommandSource(player), this, false);
broadcast = new KeywordReplacer(broadcast, new CommandSource(this, player), this, false);
}
for (final String messageText : broadcast.getLines()) {
user.sendMessage(messageText);
@ -1128,6 +1198,52 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return players.size();
}
@Override
public void broadcastTl(final String tlKey, final Object... args) {
broadcastTl(null, null, false, tlKey, args);
}
@Override
public void broadcastTl(final IUser sender, final String tlKey, final Object... args) {
broadcastTl(sender, null, false, tlKey, args);
}
@Override
public void broadcastTl(final IUser sender, final String permission, final String tlKey, final Object... args) {
broadcastTl(sender, u -> !u.isAuthorized(permission), false, tlKey, args);
}
@Override
public void broadcastTl(IUser sender, Predicate<IUser> shouldExclude, String tlKey, Object... args) {
broadcastTl(sender, shouldExclude, false, tlKey, args);
}
@Override
public void broadcastTl(final IUser sender, final Predicate<IUser> shouldExclude, final boolean parseKeywords, final String tlKey, final Object... args) {
if (sender != null && sender.isHidden()) {
return;
}
for (final User user : getOnlineUsers()) {
if (sender != null && user.isIgnoredPlayer(sender)) {
continue;
}
if (shouldExclude != null && shouldExclude.test(user)) {
continue;
}
final Object[] processedArgs;
if (parseKeywords) {
processedArgs = I18n.mutateArgs(args, s -> new KeywordReplacer(new SimpleTextInput(s.toString()), new CommandSource(this, user.getBase()), this, false).getLines().get(0));
} else {
processedArgs = args;
}
user.sendTl(tlKey, processedArgs);
}
}
@Override
public BukkitTask runTaskAsynchronously(final Runnable run) {
return this.getScheduler().runTaskAsynchronously(this, run);
@ -1158,11 +1274,6 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return this.getScheduler().scheduleSyncRepeatingTask(this, run, delay, period);
}
@Override
public TNTExplodeListener getTNTListener() {
return tntListener;
}
@Override
public PermissionsHandler getPermissionsHandler() {
return permissionsHandler;
@ -1179,7 +1290,13 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
@Override
@Deprecated
public UserMap getUserMap() {
return legacyUserMap;
}
@Override
public ModernUserMap getUsers() {
return userMap;
}
@ -1306,11 +1423,35 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return worldInfoProvider;
}
@Override
public PlayerLocaleProvider getPlayerLocaleProvider() {
return playerLocaleProvider;
}
@Override
public DamageEventProvider getDamageEventProvider() {
return damageEventProvider;
}
@Override
public BiomeKeyProvider getBiomeKeyProvider() {
return biomeKeyProvider;
}
@Override
public SignDataProvider getSignDataProvider() {
return signDataProvider;
}
@Override
public PluginCommand getPluginCommand(final String cmd) {
return this.getCommand(cmd);
}
public BukkitAudiences getBukkitAudience() {
return bukkitAudience;
}
private AbstractItemDb getItemDbFromConfig() {
final String setting = settings.getItemDbType();

View File

@ -1,5 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.MaterialUtil;
import net.ess3.api.IEssentials;
import org.bukkit.GameMode;
@ -42,8 +43,12 @@ public class EssentialsBlockListener implements Listener {
final User user = ess.getUser(event.getPlayer());
if (user.hasUnlimited(is) && user.getBase().getGameMode() == GameMode.SURVIVAL) {
ess.scheduleSyncDelayedTask(() -> {
user.getBase().getInventory().addItem(is);
user.getBase().updateInventory();
if (is != null && is.getType() != null && !MaterialUtil.isAir(is.getType())) {
final ItemStack cloneIs = is.clone();
cloneIs.setAmount(1);
Inventories.addItem(user.getBase(), cloneIs);
user.getBase().updateInventory();
}
});
}
}

View File

@ -1,674 +0,0 @@
package com.earth2me.essentials;
import com.google.common.io.Files;
import net.ess3.api.InvalidWorldException;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.math.MathContext;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.earth2me.essentials.I18n.tl;
public class EssentialsConf extends YamlConfiguration {
protected static final Logger LOGGER = Logger.getLogger("Essentials");
protected static final Charset UTF8 = StandardCharsets.UTF_8;
private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
protected final File configFile;
private final AtomicInteger pendingDiskWrites = new AtomicInteger(0);
private final AtomicBoolean transaction = new AtomicBoolean(false);
private final byte[] bytebuffer = new byte[1024];
protected String templateName = null;
private Class<?> resourceClass = EssentialsConf.class;
public EssentialsConf(final File configFile) {
super();
this.configFile = configFile.getAbsoluteFile();
}
public static BigDecimal toBigDecimal(final String input, final BigDecimal def) {
if (input == null || input.isEmpty()) {
return def;
} else {
try {
return new BigDecimal(input, MathContext.DECIMAL128);
} catch (final NumberFormatException | ArithmeticException e) {
return def;
}
}
}
public synchronized void load() {
if (pendingDiskWrites.get() != 0) {
LOGGER.log(Level.INFO, "File {0} not read, because it''s not yet written to disk.", configFile);
return;
}
if (!configFile.getParentFile().exists()) {
if (!configFile.getParentFile().mkdirs()) {
LOGGER.log(Level.SEVERE, tl("failedToCreateConfig", configFile.toString()));
}
}
// This will delete files where the first character is 0. In most cases they are broken.
if (configFile.exists() && configFile.length() != 0) {
try {
final InputStream input = new FileInputStream(configFile);
try {
if (input.read() == 0) {
input.close();
configFile.delete();
}
} catch (final IOException ex) {
LOGGER.log(Level.SEVERE, null, ex);
} finally {
try {
input.close();
} catch (final IOException ex) {
LOGGER.log(Level.SEVERE, null, ex);
}
}
} catch (final FileNotFoundException ex) {
LOGGER.log(Level.SEVERE, null, ex);
}
}
if (!configFile.exists()) {
if (legacyFileExists()) {
convertLegacyFile();
} else if (altFileExists()) {
convertAltFile();
} else if (templateName != null) {
LOGGER.log(Level.INFO, tl("creatingConfigFromTemplate", configFile.toString()));
createFromTemplate();
} else {
return;
}
}
try {
try (final FileInputStream inputStream = new FileInputStream(configFile)) {
final long startSize = configFile.length();
if (startSize > Integer.MAX_VALUE) {
throw new InvalidConfigurationException("File too big");
}
ByteBuffer buffer = ByteBuffer.allocate((int) startSize);
int length;
while ((length = inputStream.read(bytebuffer)) != -1) {
if (length > buffer.remaining()) {
final ByteBuffer resize = ByteBuffer.allocate(buffer.capacity() + length - buffer.remaining());
final int resizePosition = buffer.position();
// Fix builds compiled against Java 9+ breaking on Java 8
((Buffer) buffer).rewind();
resize.put(buffer);
resize.position(resizePosition);
buffer = resize;
}
buffer.put(bytebuffer, 0, length);
}
((Buffer) buffer).rewind();
final CharBuffer data = CharBuffer.allocate(buffer.capacity());
CharsetDecoder decoder = UTF8.newDecoder();
CoderResult result = decoder.decode(buffer, data, true);
if (result.isError()) {
((Buffer) buffer).rewind();
((Buffer) data).clear();
LOGGER.log(Level.INFO, "File " + configFile.getAbsolutePath() + " is not utf-8 encoded, trying " + Charset.defaultCharset().displayName());
decoder = Charset.defaultCharset().newDecoder();
result = decoder.decode(buffer, data, true);
if (result.isError()) {
throw new InvalidConfigurationException("Invalid Characters in file " + configFile.getAbsolutePath());
} else {
decoder.flush(data);
}
} else {
decoder.flush(data);
}
final int end = data.position();
((Buffer) data).rewind();
super.loadFromString(data.subSequence(0, end).toString());
}
} catch (final IOException ex) {
LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
} catch (final InvalidConfigurationException ex) {
final File broken = new File(configFile.getAbsolutePath() + ".broken." + System.currentTimeMillis());
configFile.renameTo(broken);
LOGGER.log(Level.SEVERE, "The file " + configFile.toString() + " is broken, it has been renamed to " + broken.toString(), ex.getCause());
}
}
public boolean legacyFileExists() {
return false;
}
public void convertLegacyFile() {
LOGGER.log(Level.SEVERE, "Unable to import legacy config file.");
}
public boolean altFileExists() {
return false;
}
public void convertAltFile() {
LOGGER.log(Level.SEVERE, "Unable to import alt config file.");
}
private void createFromTemplate() {
InputStream istr = null;
OutputStream ostr = null;
try {
istr = resourceClass.getResourceAsStream(templateName);
if (istr == null) {
LOGGER.log(Level.SEVERE, tl("couldNotFindTemplate", templateName));
return;
}
ostr = new FileOutputStream(configFile);
final byte[] buffer = new byte[1024];
int length = 0;
length = istr.read(buffer);
while (length > 0) {
ostr.write(buffer, 0, length);
length = istr.read(buffer);
}
} catch (final IOException ex) {
LOGGER.log(Level.SEVERE, tl("failedToWriteConfig", configFile.toString()), ex);
} finally {
try {
if (istr != null) {
istr.close();
}
} catch (final IOException ex) {
Logger.getLogger(EssentialsConf.class.getName()).log(Level.SEVERE, null, ex);
}
try {
if (ostr != null) {
ostr.close();
}
} catch (final IOException ex) {
LOGGER.log(Level.SEVERE, tl("failedToCloseConfig", configFile.toString()), ex);
}
}
}
public void setTemplateName(final String templateName) {
this.templateName = templateName;
}
public File getFile() {
return configFile;
}
public void setTemplateName(final String templateName, final Class<?> resClass) {
this.templateName = templateName;
this.resourceClass = resClass;
}
public void startTransaction() {
transaction.set(true);
}
public void stopTransaction() {
transaction.set(false);
save();
}
public void save() {
try {
save(configFile);
} catch (final IOException ex) {
LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
}
}
public void saveWithError() throws IOException {
save(configFile);
}
@Override
public synchronized void save(final File file) throws IOException {
if (!transaction.get()) {
delayedSave(file);
}
}
//This may be aborted if there are stagnant requests sitting in queue.
//This needs fixed to discard outstanding save requests.
public synchronized void forceSave() {
try {
final Future<?> future = delayedSave(configFile);
if (future != null) {
future.get();
}
} catch (final InterruptedException | ExecutionException ex) {
LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
}
}
public synchronized void cleanup() {
forceSave();
}
private Future<?> delayedSave(final File file) {
if (file == null) {
throw new IllegalArgumentException("File cannot be null");
}
final String data = saveToString();
if (data.length() == 0) {
return null;
}
pendingDiskWrites.incrementAndGet();
return EXECUTOR_SERVICE.submit(new WriteRunner(configFile, data, pendingDiskWrites));
}
public boolean hasProperty(final String path) {
return isSet(path);
}
public Location getLocation(final String path, final Server server) throws InvalidWorldException {
final String worldString = (path == null ? "" : path + ".") + "world";
final String worldName = getString(worldString);
if (worldName == null || worldName.isEmpty()) {
return null;
}
final World world = server.getWorld(worldName);
if (world == null) {
throw new InvalidWorldException(worldName);
}
return new Location(world, getDouble((path == null ? "" : path + ".") + "x", 0), getDouble((path == null ? "" : path + ".") + "y", 0), getDouble((path == null ? "" : path + ".") + "z", 0), (float) getDouble((path == null ? "" : path + ".") + "yaw", 0), (float) getDouble((path == null ? "" : path + ".") + "pitch", 0));
}
public void setProperty(final String path, final Location loc) {
set((path == null ? "" : path + ".") + "world", loc.getWorld().getName());
set((path == null ? "" : path + ".") + "x", loc.getX());
set((path == null ? "" : path + ".") + "y", loc.getY());
set((path == null ? "" : path + ".") + "z", loc.getZ());
set((path == null ? "" : path + ".") + "yaw", loc.getYaw());
set((path == null ? "" : path + ".") + "pitch", loc.getPitch());
}
@Override
public ItemStack getItemStack(final String path) {
final ItemStack stack = new ItemStack(Material.valueOf(getString(path + ".type", "AIR")), getInt(path + ".amount", 1), (short) getInt(path + ".damage", 0));
final ConfigurationSection enchants = getConfigurationSection(path + ".enchant");
if (enchants != null) {
for (final String enchant : enchants.getKeys(false)) {
final Enchantment enchantment = Enchantment.getByName(enchant.toUpperCase(Locale.ENGLISH));
if (enchantment == null) {
continue;
}
final int level = getInt(path + ".enchant." + enchant, enchantment.getStartLevel());
stack.addUnsafeEnchantment(enchantment, level);
}
}
return stack;
/*
* ,
* (byte)getInt(path + ".data", 0)
*/
}
public void setProperty(final String path, final ItemStack stack) {
final Map<String, Object> map = new HashMap<>();
map.put("type", stack.getType().toString());
map.put("amount", stack.getAmount());
map.put("damage", stack.getDurability());
final Map<Enchantment, Integer> enchantments = stack.getEnchantments();
if (!enchantments.isEmpty()) {
final Map<String, Integer> enchant = new HashMap<>();
for (final Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
enchant.put(entry.getKey().getName().toLowerCase(Locale.ENGLISH), entry.getValue());
}
map.put("enchant", enchant);
}
// getData().getData() is broken
//map.put("data", stack.getDurability());
set(path, map);
}
public void setProperty(final String path, final List object) {
set(path, new ArrayList(object));
}
public void setProperty(final String path, final Map object) {
set(path, new LinkedHashMap(object));
}
public Object getProperty(final String path) {
return get(path);
}
public void setProperty(final String path, final BigDecimal bigDecimal) {
set(path, bigDecimal.toString());
}
public void setProperty(final String path, final Object object) {
set(path, object);
}
public void removeProperty(final String path) {
set(path, null);
}
@Override
public synchronized Object get(final String path) {
return super.get(path);
}
@Override
public synchronized Object get(final String path, final Object def) {
return super.get(path, def);
}
public synchronized BigDecimal getBigDecimal(final String path, final BigDecimal def) {
final String input = super.getString(path);
return toBigDecimal(input, def);
}
@Override
public synchronized boolean getBoolean(final String path) {
return super.getBoolean(path);
}
@Override
public synchronized boolean getBoolean(final String path, final boolean def) {
return super.getBoolean(path, def);
}
@Override
public synchronized List<Boolean> getBooleanList(final String path) {
return super.getBooleanList(path);
}
@Override
public synchronized List<Byte> getByteList(final String path) {
return super.getByteList(path);
}
@Override
public synchronized List<Character> getCharacterList(final String path) {
return super.getCharacterList(path);
}
@Override
public synchronized ConfigurationSection getConfigurationSection(final String path) {
return super.getConfigurationSection(path);
}
@Override
public synchronized double getDouble(final String path) {
return super.getDouble(path);
}
@Override
public synchronized double getDouble(final String path, final double def) {
return super.getDouble(path, def);
}
@Override
public synchronized List<Double> getDoubleList(final String path) {
return super.getDoubleList(path);
}
@Override
public synchronized List<Float> getFloatList(final String path) {
return super.getFloatList(path);
}
@Override
public synchronized int getInt(final String path) {
return super.getInt(path);
}
@Override
public synchronized int getInt(final String path, final int def) {
return super.getInt(path, def);
}
@Override
public synchronized List<Integer> getIntegerList(final String path) {
return super.getIntegerList(path);
}
@Override
public synchronized ItemStack getItemStack(final String path, final ItemStack def) {
return super.getItemStack(path, def);
}
@Override
public synchronized Set<String> getKeys(final boolean deep) {
return super.getKeys(deep);
}
@Override
public synchronized List<?> getList(final String path) {
return super.getList(path);
}
@Override
public synchronized List<?> getList(final String path, final List<?> def) {
return super.getList(path, def);
}
@Override
public synchronized long getLong(final String path) {
return super.getLong(path);
}
@Override
public synchronized long getLong(final String path, final long def) {
return super.getLong(path, def);
}
@Override
public synchronized List<Long> getLongList(final String path) {
return super.getLongList(path);
}
public synchronized Map<String, Object> getMap() {
return map;
}
@Override
public synchronized List<Map<?, ?>> getMapList(final String path) {
return super.getMapList(path);
}
@Override
public synchronized OfflinePlayer getOfflinePlayer(final String path) {
return super.getOfflinePlayer(path);
}
@Override
public synchronized OfflinePlayer getOfflinePlayer(final String path, final OfflinePlayer def) {
return super.getOfflinePlayer(path, def);
}
@Override
public synchronized List<Short> getShortList(final String path) {
return super.getShortList(path);
}
@Override
public synchronized String getString(final String path) {
return super.getString(path);
}
@Override
public synchronized String getString(final String path, final String def) {
return super.getString(path, def);
}
@Override
public synchronized List<String> getStringList(final String path) {
return super.getStringList(path);
}
@Override
public synchronized Map<String, Object> getValues(final boolean deep) {
return super.getValues(deep);
}
@Override
public synchronized Vector getVector(final String path) {
return super.getVector(path);
}
@Override
public synchronized Vector getVector(final String path, final Vector def) {
return super.getVector(path, def);
}
@Override
public synchronized boolean isBoolean(final String path) {
return super.isBoolean(path);
}
@Override
public synchronized boolean isConfigurationSection(final String path) {
return super.isConfigurationSection(path);
}
@Override
public synchronized boolean isDouble(final String path) {
return super.isDouble(path);
}
@Override
public synchronized boolean isInt(final String path) {
return super.isInt(path);
}
@Override
public synchronized boolean isItemStack(final String path) {
return super.isItemStack(path);
}
@Override
public synchronized boolean isList(final String path) {
return super.isList(path);
}
@Override
public synchronized boolean isLong(final String path) {
return super.isLong(path);
}
@Override
public synchronized boolean isOfflinePlayer(final String path) {
return super.isOfflinePlayer(path);
}
@Override
public synchronized boolean isSet(final String path) {
return super.isSet(path);
}
@Override
public synchronized boolean isString(final String path) {
return super.isString(path);
}
@Override
public synchronized boolean isVector(final String path) {
return super.isVector(path);
}
@Override
public synchronized void set(final String path, final Object value) {
super.set(path, value);
}
private static final class WriteRunner implements Runnable {
private final File configFile;
private final String data;
private final AtomicInteger pendingDiskWrites;
private WriteRunner(final File configFile, final String data, final AtomicInteger pendingDiskWrites) {
this.configFile = configFile;
this.data = data;
this.pendingDiskWrites = pendingDiskWrites;
}
@Override
public void run() {
//long startTime = System.nanoTime();
synchronized (configFile) {
if (pendingDiskWrites.get() > 1) {
// Writes can be skipped, because they are stored in a queue (in the executor).
// Only the last is actually written.
pendingDiskWrites.decrementAndGet();
//LOGGER.log(Level.INFO, configFile + " skipped writing in " + (System.nanoTime() - startTime) + " nsec.");
return;
}
try {
Files.createParentDirs(configFile);
if (!configFile.exists()) {
try {
LOGGER.log(Level.INFO, tl("creatingEmptyConfig", configFile.toString()));
if (!configFile.createNewFile()) {
LOGGER.log(Level.SEVERE, tl("failedToCreateConfig", configFile.toString()));
return;
}
} catch (final IOException ex) {
LOGGER.log(Level.SEVERE, tl("failedToCreateConfig", configFile.toString()), ex);
return;
}
}
try (final FileOutputStream fos = new FileOutputStream(configFile)) {
try (final OutputStreamWriter writer = new OutputStreamWriter(fos, UTF8)) {
writer.write(data);
}
}
} catch (final IOException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} finally {
//LOGGER.log(Level.INFO, configFile + " written to disk in " + (System.nanoTime() - startTime) + " nsec.");
pendingDiskWrites.decrementAndGet();
}
}
}
}
}

View File

@ -1,5 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.api.IEssentials;
import org.bukkit.Location;
@ -29,13 +30,9 @@ import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import static com.earth2me.essentials.I18n.tl;
public class EssentialsEntityListener implements Listener {
private static final Logger LOGGER = Logger.getLogger("Essentials");
private static final transient Pattern powertoolPlayer = Pattern.compile("\\{player\\}");
private final IEssentials ess;
@ -53,12 +50,12 @@ public class EssentialsEntityListener implements Listener {
if (eDefend instanceof Player) {
onPlayerVsPlayerDamage(event, (Player) eDefend, attacker);
} else if (eDefend instanceof Ageable) {
final ItemStack hand = attacker.getBase().getItemInHand();
final ItemStack hand = Inventories.getItemInMainHand(attacker.getBase());
if (ess.getSettings().isMilkBucketEasterEggEnabled()
&& hand != null && hand.getType() == Material.MILK_BUCKET) {
((Ageable) eDefend).setBaby();
hand.setType(Material.BUCKET);
attacker.getBase().setItemInHand(hand);
Inventories.setItemInMainHand(attacker.getBase(), hand);
attacker.getBase().updateInventory();
event.setCancelled(true);
}
@ -99,7 +96,7 @@ public class EssentialsEntityListener implements Listener {
}
private void onPlayerVsPlayerPowertool(final EntityDamageByEntityEvent event, final Player defender, final User attacker) {
final List<String> commandList = attacker.getPowertool(attacker.getBase().getItemInHand());
final List<String> commandList = attacker.getPowertool(Inventories.getItemInHand(attacker.getBase()));
if (commandList != null && !commandList.isEmpty()) {
for (final String tempCommand : commandList) {
final String command = powertoolPlayer.matcher(tempCommand).replaceAll(defender.getName());
@ -109,7 +106,7 @@ public class EssentialsEntityListener implements Listener {
@Override
public void run() {
attacker.getBase().chat("/" + command);
LOGGER.log(Level.INFO, String.format("[PT] %s issued server command: /%s", attacker.getName(), command));
ess.getLogger().log(Level.INFO, String.format("[PT] %s issued server command: /%s", attacker.getName(), command));
}
}
@ -168,11 +165,11 @@ public class EssentialsEntityListener implements Listener {
final User user = ess.getUser(event.getEntity());
if (ess.getSettings().infoAfterDeath()) {
final Location loc = user.getLocation();
user.sendMessage(tl("infoAfterDeath", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
user.sendTl("infoAfterDeath", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
}
if (user.isAuthorized("essentials.back.ondeath") && !ess.getSettings().isCommandDisabled("back")) {
user.setLastLocation();
user.sendMessage(tl("backAfterDeath"));
user.sendTl("backAfterDeath");
}
if (!ess.getSettings().areDeathMessagesEnabled()) {
event.setDeathMessage("");
@ -197,53 +194,23 @@ public class EssentialsEntityListener implements Listener {
final ISettings.KeepInvPolicy vanish = ess.getSettings().getVanishingItemsPolicy();
final ISettings.KeepInvPolicy bind = ess.getSettings().getBindingItemsPolicy();
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_11_2_R01) && (vanish != ISettings.KeepInvPolicy.KEEP || bind != ISettings.KeepInvPolicy.KEEP)) {
for (final ItemStack stack : event.getEntity().getInventory()) {
if (stack != null) {
if (stack.getEnchantments().containsKey(Enchantment.VANISHING_CURSE)) {
if (vanish == ISettings.KeepInvPolicy.DELETE) {
event.getEntity().getInventory().remove(stack);
} else if (vanish == ISettings.KeepInvPolicy.DROP) {
event.getDrops().add(stack);
event.getEntity().getInventory().remove(stack);
}
}
if (stack.getEnchantments().containsKey(Enchantment.BINDING_CURSE)) {
if (bind == ISettings.KeepInvPolicy.DELETE) {
event.getEntity().getInventory().remove(stack);
} else if (bind == ISettings.KeepInvPolicy.DROP) {
event.getEntity().getInventory().remove(stack);
event.getDrops().add(stack);
}
Inventories.removeItems(user.getBase(), stack -> {
if (vanish != ISettings.KeepInvPolicy.KEEP && stack.getEnchantments().containsKey(Enchantment.VANISHING_CURSE)) {
if (vanish == ISettings.KeepInvPolicy.DROP) {
event.getDrops().add(stack.clone());
}
return true;
}
}
final ItemStack[] armor = event.getEntity().getInventory().getArmorContents();
for (int i = 0; i < armor.length; i++) {
final ItemStack stack = armor[i];
if (stack != null) {
if (stack.getEnchantments().containsKey(Enchantment.VANISHING_CURSE)) {
if (vanish == ISettings.KeepInvPolicy.DELETE) {
armor[i] = null;
} else if (vanish == ISettings.KeepInvPolicy.DROP) {
if (!event.getDrops().contains(stack)) {
event.getDrops().add(stack);
}
armor[i] = null;
}
}
if (stack.getEnchantments().containsKey(Enchantment.BINDING_CURSE)) {
if (bind == ISettings.KeepInvPolicy.DELETE) {
armor[i] = null;
} else if (bind == ISettings.KeepInvPolicy.DROP) {
if (!event.getDrops().contains(stack)) {
event.getDrops().add(stack);
}
armor[i] = null;
}
if (bind != ISettings.KeepInvPolicy.KEEP && stack.getEnchantments().containsKey(Enchantment.BINDING_CURSE)) {
if (bind == ISettings.KeepInvPolicy.DROP) {
event.getDrops().add(stack.clone());
}
return true;
}
}
event.getEntity().getInventory().setArmorContents(armor);
return false;
}, true);
}
}
}

View File

@ -0,0 +1,74 @@
package com.earth2me.essentials;
import net.ess3.nms.refl.ReflUtil;
import net.ess3.provider.LoggerProvider;
import net.ess3.provider.providers.BaseLoggerProvider;
import net.ess3.provider.providers.PaperLoggerProvider;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
public final class EssentialsLogger {
private final static Map<String, LoggerProvider> loggerProviders = new HashMap<>();
private final static MethodHandle loggerFieldHandle;
static {
try {
final Field loggerField = ReflUtil.getFieldCached(JavaPlugin.class, "logger");
//noinspection ConstantConditions
loggerFieldHandle = MethodHandles.lookup().unreflectSetter(loggerField);
} catch (Throwable t) {
throw new RuntimeException("Failed to get logger field handle", t);
}
}
private EssentialsLogger() {
}
public static LoggerProvider getLoggerProvider(final Plugin plugin) {
if (loggerProviders.containsKey(plugin.getName())) {
return loggerProviders.get(plugin.getName());
}
final Logger parentLogger = Logger.getLogger(plugin.getName());
final LoggerProvider provider;
if (ReflUtil.getClassCached("io.papermc.paper.adventure.providers.ComponentLoggerProviderImpl") != null) {
provider = new PaperLoggerProvider(plugin);
provider.setParent(parentLogger);
} else {
provider = new BaseLoggerProvider(plugin, parentLogger);
provider.setParent(parentLogger);
}
loggerProviders.put(plugin.getName(), provider);
return provider;
}
public static void updatePluginLogger(final Plugin plugin) {
final LoggerProvider provider = getLoggerProvider(plugin);
try {
loggerFieldHandle.invoke(plugin, provider);
} catch (Throwable e) {
provider.log(Level.SEVERE, "Failed to update " + plugin.getName() + " logger", e);
}
}
public static LoggerProvider getLoggerProvider(final String pluginName) {
if (loggerProviders.containsKey(pluginName)) {
return loggerProviders.get(pluginName);
}
final Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName);
if (plugin == null) {
throw new IllegalArgumentException("Plugin not found: " + pluginName);
}
return getLoggerProvider(plugin);
}
}

View File

@ -1,10 +1,13 @@
package com.earth2me.essentials;
import com.earth2me.essentials.commands.Commandfireball;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.TextInput;
import com.earth2me.essentials.textreader.TextPager;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.CommonPlaceholders;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.LocationUtil;
@ -17,6 +20,7 @@ import net.ess3.provider.CommandSendListenerProvider;
import net.ess3.provider.providers.BukkitCommandSendListenerProvider;
import net.ess3.provider.providers.PaperCommandSendListenerProvider;
import net.essentialsx.api.v2.events.AsyncUserDataLoadEvent;
import net.kyori.adventure.text.Component;
import org.bukkit.BanEntry;
import org.bukkit.BanList;
import org.bukkit.GameMode;
@ -72,13 +76,11 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public class EssentialsPlayerListener implements Listener, FakeAccessor {
private static final Logger LOGGER = Logger.getLogger("Essentials");
private final transient IEssentials ess;
private final ConcurrentHashMap<UUID, Integer> pendingMotdTasks = new ConcurrentHashMap<>();
@ -122,6 +124,15 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
}
}
private static boolean isGameEventEvent() {
try {
Class.forName("org.bukkit.event.block.BlockReceiveGameEvent");
return true;
} catch (final ClassNotFoundException ignored) {
return false;
}
}
public void registerEvents() {
ess.getServer().getPluginManager().registerEvents(this, ess);
@ -129,6 +140,10 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
ess.getServer().getPluginManager().registerEvents(new ArrowPickupListener(), ess);
}
if (isGameEventEvent()) {
ess.getServer().getPluginManager().registerEvents(new SculkListener1_17(), ess);
}
if (isEntityPickupEvent()) {
ess.getServer().getPluginManager().registerEvents(new PickupListener1_12(), ess);
} else {
@ -161,12 +176,20 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
final String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
user.sendMessage(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
if (user.hasMuteReason()) {
user.sendTl("voiceSilencedReason", user.getMuteReason());
} else {
user.sendTl("voiceSilenced");
}
} else {
user.sendMessage(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
if (user.hasMuteReason()) {
user.sendTl("voiceSilencedReasonTime", dateDiff, user.getMuteReason());
} else {
user.sendTl("voiceSilencedTime", dateDiff);
}
}
LOGGER.info(tl("mutedUserSpeaks", user.getName(), event.getMessage()));
ess.getLogger().info(AdventureUtil.miniToLegacy(tlLiteral("mutedUserSpeaks", user.getName(), event.getMessage())));
}
try {
final Iterator<Player> it = event.getRecipients().iterator();
@ -194,17 +217,26 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
return;
}
if (!ess.getSettings().cancelAfkOnMove() && !ess.getSettings().getFreezeAfkPlayers()) {
event.getHandlers().unregister(this);
final User user = ess.getUser(event.getPlayer());
if (ess.getSettings().isDebug()) {
LOGGER.log(Level.INFO, "Unregistering move listener");
if (user.isFreeze()) {
final Location from = event.getFrom();
final Location to = event.getTo().clone();
to.setX(from.getX());
to.setY(from.getY());
to.setZ(from.getZ());
try {
event.setTo(LocationUtil.getSafeDestination(ess, to));
} catch (final Exception ex) {
event.setTo(to);
}
return;
}
final User user = ess.getUser(event.getPlayer());
if (!ess.getSettings().cancelAfkOnMove() && !ess.getSettings().getFreezeAfkPlayers()) {
return;
}
if (user.isAfk() && ess.getSettings().getFreezeAfkPlayers()) {
final Location from = event.getFrom();
final Location origTo = event.getTo();
@ -217,6 +249,10 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
to.setY(from.getY());
to.setZ(from.getZ());
try {
if (event.getPlayer().getAllowFlight()) {
// Don't teleport to a safe location here, they are either a god or flying
throw new Exception();
}
event.setTo(LocationUtil.getSafeDestination(ess, to));
} catch (final Exception ex) {
event.setTo(to);
@ -245,7 +281,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
final String msg = ess.getSettings().getCustomQuitMessage()
.replace("{PLAYER}", player.getDisplayName())
.replace("{USERNAME}", player.getName())
.replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size()))
.replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size() - 1)) // Subtract 1 as the leaving player is still online during this time
.replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()))
.replace("{PREFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getPrefix(player)))
.replace("{SUFFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getSuffix(player)));
@ -258,6 +294,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
user.setGodModeEnabled(false);
}
if (user.isVanished()) {
user.setLeavingHidden(true);
user.setVanished(false);
}
user.setLogoutLocation();
@ -305,6 +342,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
ess.getBackup().onPlayerJoin();
final User dUser = ess.getUser(player);
dUser.update(player);
dUser.startTransaction();
if (dUser.isNPC()) {
@ -332,6 +370,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
user.setLastLogin(currentTime);
user.setDisplayNick();
updateCompass(user);
user.setLeavingHidden(false);
// Check for new username. If they don't want the message, let's just say it's false.
final boolean newUsername = ess.getSettings().isCustomNewUsernameMessage() && lastAccountName != null && !lastAccountName.equals(user.getBase().getName());
@ -363,7 +402,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
} else if (ess.getSettings().isCustomJoinMessage()) {
final String msg = (newUsername ? ess.getSettings().getCustomNewUsernameMessage() : ess.getSettings().getCustomJoinMessage())
.replace("{PLAYER}", player.getDisplayName()).replace("{USERNAME}", player.getName())
.replace("{UNIQUE}", NumberFormat.getInstance().format(ess.getUserMap().getUniqueUsers()))
.replace("{UNIQUE}", NumberFormat.getInstance().format(ess.getUsers().getUserCount()))
.replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size()))
.replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()))
.replace("{PREFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getPrefix(player)))
@ -395,7 +434,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
if (!ess.getSettings().isCommandDisabled("mail") && user.isAuthorized("essentials.mail")) {
if (user.getUnreadMailAmount() == 0) {
if (ess.getSettings().isNotifyNoNewMail()) {
user.sendMessage(tl("noNewMail")); // Only notify if they want us to.
user.sendTl("noNewMail"); // Only notify if they want us to.
}
} else {
user.notifyOfMail();
@ -404,8 +443,8 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
if (user.isAuthorized("essentials.updatecheck")) {
ess.runTaskAsynchronously(() -> {
for (String str : ess.getUpdateChecker().getVersionMessages(false, false)) {
user.sendMessage(str);
for (final Component component : ess.getUpdateChecker().getVersionMessages(false, false, user.getSource())) {
user.sendComponent(component);
}
});
}
@ -416,7 +455,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
user.getBase().setAllowFlight(true);
user.getBase().setFlying(true);
if (ess.getSettings().isSendFlyEnableOnJoin()) {
user.getBase().sendMessage(tl("flyMode", tl("enabled"), user.getDisplayName()));
user.sendTl("flyMode", CommonPlaceholders.enableDisable(user.getSource(), true), user.getDisplayName());
}
}
}
@ -460,9 +499,9 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
tempInput = new TextInput(user.getSource(), "motd", true, ess);
} catch (final IOException ex) {
if (ess.getSettings().isDebug()) {
LOGGER.log(Level.WARNING, ex.getMessage(), ex);
ess.getLogger().log(Level.WARNING, ex.getMessage(), ex);
} else {
LOGGER.log(Level.WARNING, ex.getMessage());
ess.getLogger().log(Level.WARNING, ex.getMessage());
}
}
}
@ -506,14 +545,14 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
final Date banExpiry = banEntry.getExpiration();
if (banExpiry != null) {
final String expiry = DateUtil.formatDateDiff(banExpiry.getTime());
event.setKickMessage(tl("tempbanJoin", expiry, banEntry.getReason()));
event.setKickMessage(AdventureUtil.miniToLegacy(tlLiteral("tempbanJoin", expiry, banEntry.getReason())));
} else {
event.setKickMessage(tl("banJoin", banEntry.getReason()));
event.setKickMessage(AdventureUtil.miniToLegacy(tlLiteral("banJoin", banEntry.getReason())));
}
} else {
banEntry = ess.getServer().getBanList(BanList.Type.IP).getBanEntry(event.getAddress().getHostAddress());
if (banEntry != null) {
event.setKickMessage(tl("banIpJoin", banEntry.getReason()));
event.setKickMessage(AdventureUtil.miniToLegacy(tlLiteral("banIpJoin", banEntry.getReason())));
}
}
}
@ -523,12 +562,13 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
public void onPlayerLogin(final PlayerLoginEvent event) {
if (event.getResult() == Result.KICK_FULL) {
final User kfuser = ess.getUser(event.getPlayer());
kfuser.update(event.getPlayer());
if (kfuser.isAuthorized("essentials.joinfullserver")) {
event.allow();
return;
}
if (ess.getSettings().isCustomServerFullMessage()) {
event.disallow(Result.KICK_FULL, tl("serverFull"));
event.disallow(Result.KICK_FULL, tlLiteral("serverFull"));
}
}
}
@ -553,7 +593,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
final User user = ess.getUser(event.getPlayer());
final ItemStack stack = new ItemStack(Material.EGG, 1);
if (user.hasUnlimited(stack)) {
user.getBase().getInventory().addItem(stack);
Inventories.addItem(user.getBase(), stack);
user.getBase().updateInventory();
}
}
@ -600,13 +640,13 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
|| (!pluginCommand.getName().equals("msg") && !pluginCommand.getName().equals("r"))) { // /msg and /r are handled in SimpleMessageRecipient
final User user = ess.getUser(player);
if (!user.isAuthorized("essentials.chat.spy.exempt")) {
final String playerName = ess.getSettings().isSocialSpyDisplayNames() ? player.getDisplayName() : player.getName();
for (final User spyer : ess.getOnlineUsers()) {
if (spyer.isSocialSpyEnabled() && !player.equals(spyer.getBase())) {
if (user.isMuted() && ess.getSettings().getSocialSpyListenMutedPlayers()) {
spyer.sendMessage(tl("socialSpyMutedPrefix") + player.getDisplayName() + ": " + event.getMessage());
} else {
spyer.sendMessage(tl("socialSpyPrefix") + player.getDisplayName() + ": " + event.getMessage());
}
final Component base = (user.isMuted() && ess.getSettings().getSocialSpyListenMutedPlayers())
? spyer.tlComponent("socialSpyMutedPrefix")
: spyer.tlComponent("socialSpyPrefix");
spyer.sendComponent(base.append(AdventureUtil.legacyToAdventure(playerName)).append(Component.text(": " + event.getMessage())));
}
}
}
@ -618,11 +658,19 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
event.setCancelled(true);
final String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
player.sendMessage(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
if (user.hasMuteReason()) {
user.sendTl("voiceSilencedReason", user.getMuteReason());
} else {
user.sendTl("voiceSilenced");
}
} else {
player.sendMessage(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
if (user.hasMuteReason()) {
user.sendTl("voiceSilencedReasonTime", dateDiff, user.getMuteReason());
} else {
user.sendTl("voiceSilencedTime", dateDiff);
}
}
LOGGER.info(tl("mutedUserSpeaks", player.getName(), event.getMessage()));
ess.getLogger().info(AdventureUtil.miniToLegacy(tlLiteral("mutedUserSpeaks", player.getName(), event.getMessage())));
return;
}
@ -646,7 +694,8 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
}
if (ess.getSettings().isCommandCooldownsEnabled()
&& !user.isAuthorized("essentials.commandcooldowns.bypass")) {
&& !user.isAuthorized("essentials.commandcooldowns.bypass")
&& (pluginCommand == null || !user.isAuthorized("essentials.commandcooldowns.bypass." + pluginCommand.getName()))) {
final int argStartIndex = effectiveCommand.indexOf(" ");
final String args = argStartIndex == -1 ? "" // No arguments present
: " " + effectiveCommand.substring(argStartIndex); // arguments start at argStartIndex; substring from there.
@ -666,7 +715,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
// User's current cooldown hasn't expired, inform and terminate cooldown code.
if (entry.getValue() > System.currentTimeMillis()) {
final String commandCooldownTime = DateUtil.formatDateDiff(entry.getValue());
user.sendMessage(tl("commandCooldown", commandCooldownTime));
user.sendTl("commandCooldown", commandCooldownTime);
cooldownFound = true;
event.setCancelled(true);
break;
@ -729,11 +778,11 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
if (ess.getSettings().getNoGodWorlds().contains(newWorld) && user.isGodModeEnabledRaw()) {
// Player god mode is never disabled in order to retain it when changing worlds once more.
// With that said, players will still take damage as per the result of User#isGodModeEnabled()
user.sendMessage(tl("noGodWorldWarning"));
user.sendTl("noGodWorldWarning");
}
if (!user.getWorld().getName().equals(newWorld)) {
user.sendMessage(tl("currentWorld", newWorld));
user.sendTl("currentWorld", newWorld);
}
if (user.isVanished()) {
user.setVanished(user.isAuthorized("essentials.vanish"));
@ -755,7 +804,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
player.getBase().setBedSpawnLocation(event.getClickedBlock().getLocation());
// In 1.15 and above, vanilla sends its own bed spawn message.
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_15_R01)) {
player.sendMessage(tl("bedSet", player.getLocation().getWorld().getName(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()));
player.sendTl("bedSet", player.getLocation().getWorld().getName(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ());
}
}
}
@ -810,7 +859,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
ess.scheduleSyncDelayedTask(new DelayedClickJumpTask());
} catch (final Exception ex) {
if (ess.getSettings().isDebug()) {
LOGGER.log(Level.WARNING, ex.getMessage(), ex);
ess.getLogger().log(Level.WARNING, ex.getMessage(), ex);
}
}
}
@ -834,7 +883,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
@Override
public void run() {
user.getBase().chat("/" + command);
LOGGER.log(Level.INFO, String.format("[PT] %s issued server command: /%s", user.getName(), command));
ess.getLogger().log(Level.INFO, String.format("[PT] %s issued server command: /%s", user.getName(), command));
}
}
@ -984,6 +1033,15 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
}
}
private final class SculkListener1_17 implements Listener {
@EventHandler
public void onGameEvent(final org.bukkit.event.block.BlockReceiveGameEvent event) {
if (event.getEntity() instanceof Player && ess.getUser((Player) event.getEntity()).isVanished()) {
event.setCancelled(true);
}
}
}
private final class CommandSendFilter implements CommandSendListenerProvider.Filter {
@Override
public Predicate<String> apply(Player player) {

View File

@ -4,13 +4,15 @@ import com.earth2me.essentials.config.ConfigurateUtil;
import com.earth2me.essentials.config.EssentialsConfiguration;
import com.earth2me.essentials.config.EssentialsUserConfiguration;
import com.earth2me.essentials.craftbukkit.BanLookup;
import com.earth2me.essentials.userstorage.ModernUUIDCache;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.base.Charsets;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.google.gson.reflect.TypeToken;
import net.ess3.api.IEssentials;
import net.essentialsx.api.v2.services.mail.MailMessage;
import nu.studer.java.util.OrderedProperties;
import org.bukkit.BanList;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -31,10 +33,10 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@ -47,15 +49,12 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public class EssentialsUpgrade {
private final static Logger LOGGER = Logger.getLogger("Essentials");
private static final FileFilter YML_FILTER = pathname -> pathname.isFile() && pathname.getName().endsWith(".yml");
public static final FileFilter YML_FILTER = pathname -> pathname.isFile() && pathname.getName().endsWith(".yml");
private static final String PATTERN_CONFIG_UUID_REGEX = "(?mi)^uuid:\\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\s*$";
private static final Pattern PATTERN_CONFIG_UUID = Pattern.compile(PATTERN_CONFIG_UUID_REGEX);
private static final String PATTERN_CONFIG_NAME_REGEX = "(?mi)^lastAccountName:\\s*[\"\']?(\\w+)[\"\']?\\s*$";
@ -95,7 +94,6 @@ public class EssentialsUpgrade {
final int showProgress = countFiles % 250;
if (showProgress == 0) {
ess.getUserMap().getUUIDMap().forceWriteUUIDMap();
ess.getLogger().info("Converted " + countFiles + "/" + userdir.list().length);
}
@ -105,7 +103,8 @@ public class EssentialsUpgrade {
final EssentialsUserConfiguration config;
UUID uuid = null;
try {
uuid = UUID.fromString(name);
//noinspection ResultOfMethodCallIgnored
UUID.fromString(name);
} catch (final IllegalArgumentException ex) {
final File file = new File(userdir, string);
final EssentialsConfiguration conf = new EssentialsConfiguration(file);
@ -117,6 +116,7 @@ public class EssentialsUpgrade {
final String uuidString = conf.getString(uuidConf, null);
//noinspection ConstantConditions
for (int i = 0; i < 4; i++) {
try {
uuid = UUID.fromString(uuidString);
@ -124,7 +124,7 @@ public class EssentialsUpgrade {
break;
} catch (final Exception ex2) {
if (conf.getBoolean("npc", false)) {
uuid = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
uuid = UUID.nameUUIDFromBytes(("NPC:" + (ess.getSettings().isSafeUsermap() ? StringUtil.safeString(name) : name)).getBytes(Charsets.UTF_8));
break;
}
@ -132,23 +132,24 @@ public class EssentialsUpgrade {
uuid = player.getUniqueId();
}
//noinspection ConstantConditions
if (uuid != null) {
countBukkit++;
break;
}
}
//noinspection ConstantConditions
if (uuid != null) {
conf.blockingSave();
config = new EssentialsUserConfiguration(name, uuid, new File(userdir, uuid + ".yml"));
config.convertLegacyFile();
ess.getUserMap().trackUUID(uuid, name, false);
ess.getUsers().loadUncachedUser(uuid);
continue;
}
countFails++;
}
}
ess.getUserMap().getUUIDMap().forceWriteUUIDMap();
ess.getLogger().info("Converted " + countFiles + "/" + countFiles + ". Conversion complete.");
ess.getLogger().info("Converted via cache: " + countEssCache + " :: Converted via lookup: " + countBukkit + " :: Failed to convert: " + countFails);
@ -186,13 +187,13 @@ public class EssentialsUpgrade {
config.blockingSave();
}
} catch (RuntimeException ex) {
LOGGER.log(Level.INFO, "File: " + file);
ess.getLogger().log(Level.INFO, "File: " + file);
throw ex;
}
}
doneFile.setProperty("updateUsersMailList", true);
doneFile.save();
LOGGER.info("Done converting mail list.");
ess.getLogger().info("Done converting mail list.");
}
public void convertStupidCamelCaseUserdataKeys() {
@ -200,7 +201,7 @@ public class EssentialsUpgrade {
return;
}
LOGGER.info("Attempting to migrate legacy userdata keys to Configurate");
ess.getLogger().info("Attempting to migrate legacy userdata keys to Configurate");
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
if (!userdataFolder.exists() || !userdataFolder.isDirectory()) {
@ -241,13 +242,13 @@ public class EssentialsUpgrade {
}
config.blockingSave();
} catch (final RuntimeException ex) {
LOGGER.log(Level.INFO, "File: " + file);
ess.getLogger().log(Level.INFO, "File: " + file);
throw ex;
}
}
doneFile.setProperty("updateUsersStupidLegacyPathNames", true);
doneFile.save();
LOGGER.info("Done converting legacy userdata keys to Configurate.");
ess.getLogger().info("Done converting legacy userdata keys to Configurate.");
}
/**
@ -290,31 +291,31 @@ public class EssentialsUpgrade {
}
final File backupFolder = new File(ess.getDataFolder(), "userdata-npc-backup");
if (backupFolder.exists()) {
LOGGER.info("NPC backup folder already exists; skipping NPC purge.");
LOGGER.info("To finish purging broken NPC accounts, rename the \"plugins/Essentials/userdata-npc-backup\" folder and restart your server.");
ess.getLogger().info("NPC backup folder already exists; skipping NPC purge.");
ess.getLogger().info("To finish purging broken NPC accounts, rename the \"plugins/Essentials/userdata-npc-backup\" folder and restart your server.");
return;
} else if (!backupFolder.mkdir()) {
LOGGER.info("Skipping NPC purge due to error creating backup folder.");
ess.getLogger().info("Skipping NPC purge due to error creating backup folder.");
return;
}
LOGGER.info("#===========================================================================#");
LOGGER.info(" EssentialsX will now purge any NPC accounts which were incorrectly created.");
LOGGER.info(" Only NPC accounts with the default starting balance will be deleted. If");
LOGGER.info(" they turn out to be valid NPC accounts, they will be re-created as needed.");
LOGGER.info(" Any files deleted here will be backed up to the ");
LOGGER.info(" \"plugins/Essentials/userdata-npc-backup\" folder. If you notice any files");
LOGGER.info(" have been purged incorrectly, you should restore it from the backup and");
LOGGER.info(" report it to us on GitHub:");
LOGGER.info(" https://github.com/EssentialsX/Essentials/issues/new/choose");
LOGGER.info("");
LOGGER.info(" NOTE: This is a one-time process and will take several minutes if you have");
LOGGER.info(" a lot of userdata files! If you interrupt this process, EssentialsX will");
LOGGER.info(" skip the process until you rename or remove the backup folder.");
LOGGER.info("#===========================================================================#");
ess.getLogger().info("#===========================================================================#");
ess.getLogger().info(" EssentialsX will now purge any NPC accounts which were incorrectly created.");
ess.getLogger().info(" Only NPC accounts with the default starting balance will be deleted. If");
ess.getLogger().info(" they turn out to be valid NPC accounts, they will be re-created as needed.");
ess.getLogger().info(" Any files deleted here will be backed up to the ");
ess.getLogger().info(" \"plugins/Essentials/userdata-npc-backup\" folder. If you notice any files");
ess.getLogger().info(" have been purged incorrectly, you should restore it from the backup and");
ess.getLogger().info(" report it to us on GitHub:");
ess.getLogger().info(" https://github.com/EssentialsX/Essentials/issues/new/choose");
ess.getLogger().info("");
ess.getLogger().info(" NOTE: This is a one-time process and will take several minutes if you have");
ess.getLogger().info(" a lot of userdata files! If you interrupt this process, EssentialsX will");
ess.getLogger().info(" skip the process until you rename or remove the backup folder.");
ess.getLogger().info("#===========================================================================#");
final int totalUserFiles = userFiles.length;
LOGGER.info("Found ~" + totalUserFiles + " files under \"plugins/Essentials/userdata\"...");
ess.getLogger().info("Found ~" + totalUserFiles + " files under \"plugins/Essentials/userdata\"...");
final AtomicInteger movedAccounts = new AtomicInteger(0);
final AtomicInteger totalAccounts = new AtomicInteger(0);
@ -324,7 +325,7 @@ public class EssentialsUpgrade {
final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
final ScheduledFuture<?> feedbackTask = executor.scheduleWithFixedDelay(
() -> LOGGER.info("Scanned " + totalAccounts.get() + "/" + totalUserFiles + " accounts; moved " + movedAccounts.get() + " accounts"),
() -> ess.getLogger().info("Scanned " + totalAccounts.get() + "/" + totalUserFiles + " accounts; moved " + movedAccounts.get() + " accounts"),
5, feedbackInterval, TimeUnit.SECONDS);
for (final File file : userFiles) {
@ -358,10 +359,10 @@ public class EssentialsUpgrade {
Files.move(file, new File(backupFolder, file.getName()));
movedAccounts.incrementAndGet();
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Error while moving NPC file", e);
ess.getLogger().log(Level.SEVERE, "Error while moving NPC file", e);
}
} catch (final RuntimeException ex) {
LOGGER.log(Level.INFO, "File: " + file);
ess.getLogger().log(Level.INFO, "File: " + file);
feedbackTask.cancel(false);
executor.shutdown();
throw ex;
@ -372,18 +373,18 @@ public class EssentialsUpgrade {
doneFile.setProperty("updatePurgeBrokenNpcAccounts", true);
doneFile.save();
LOGGER.info("#===========================================================================#");
LOGGER.info(" EssentialsX has finished purging NPC accounts.");
LOGGER.info("");
LOGGER.info(" Deleted accounts: " + movedAccounts);
LOGGER.info(" Total accounts processed: " + totalAccounts);
LOGGER.info("");
LOGGER.info(" Purged accounts have been backed up to");
LOGGER.info(" \"plugins/Essentials/userdata-npc-backup\", and can be restored from there");
LOGGER.info(" if needed. Please report any files which have been incorrectly deleted");
LOGGER.info(" to us on GitHub:");
LOGGER.info(" https://github.com/EssentialsX/Essentials/issues/new/choose");
LOGGER.info("#===========================================================================#");
ess.getLogger().info("#===========================================================================#");
ess.getLogger().info(" EssentialsX has finished purging NPC accounts.");
ess.getLogger().info("");
ess.getLogger().info(" Deleted accounts: " + movedAccounts);
ess.getLogger().info(" Total accounts processed: " + totalAccounts);
ess.getLogger().info("");
ess.getLogger().info(" Purged accounts have been backed up to");
ess.getLogger().info(" \"plugins/Essentials/userdata-npc-backup\", and can be restored from there");
ess.getLogger().info(" if needed. Please report any files which have been incorrectly deleted");
ess.getLogger().info(" to us on GitHub:");
ess.getLogger().info(" https://github.com/EssentialsX/Essentials/issues/new/choose");
ess.getLogger().info("#===========================================================================#");
}
public void convertIgnoreList() {
@ -392,7 +393,7 @@ public class EssentialsUpgrade {
return;
}
LOGGER.info("Attempting to migrate ignore list to UUIDs");
ess.getLogger().info("Attempting to migrate ignore list to UUIDs");
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
if (!userdataFolder.exists() || !userdataFolder.isDirectory()) {
@ -414,7 +415,7 @@ public class EssentialsUpgrade {
continue;
}
if (pattern.matcher(name.trim()).matches()) {
LOGGER.info("Detected already migrated ignore list!");
ess.getLogger().info("Detected already migrated ignore list!");
return;
}
final User user = ess.getOfflineUser(name);
@ -427,13 +428,13 @@ public class EssentialsUpgrade {
config.blockingSave();
}
} catch (final RuntimeException ex) {
LOGGER.log(Level.INFO, "File: " + file);
ess.getLogger().log(Level.INFO, "File: " + file);
throw ex;
}
}
doneFile.setProperty("updateUsersIgnoreListUUID", true);
doneFile.save();
LOGGER.info("Done converting ignore list.");
ess.getLogger().info("Done converting ignore list.");
}
public void convertKits() {
@ -443,25 +444,25 @@ public class EssentialsUpgrade {
return;
}
LOGGER.info("Attempting to convert old kits in config.yml to new kits.yml");
ess.getLogger().info("Attempting to convert old kits in config.yml to new kits.yml");
final CommentedConfigurationNode section = ess.getSettings().getKitSection();
if (section == null) {
LOGGER.info("No kits found to migrate.");
ess.getLogger().info("No kits found to migrate.");
return;
}
final Map<String, Object> legacyKits = ConfigurateUtil.getRawMap(section);
for (final Map.Entry<String, Object> entry : legacyKits.entrySet()) {
LOGGER.info("Converting " + entry.getKey());
ess.getLogger().info("Converting " + entry.getKey());
config.setRaw("kits." + entry.getKey(), entry.getValue());
}
config.save();
doneFile.setProperty("kitsyml", true);
doneFile.save();
LOGGER.info("Done converting kits.");
ess.getLogger().info("Done converting kits.");
}
private void moveMotdRulesToFile(final String name) {
@ -494,7 +495,7 @@ public class EssentialsUpgrade {
doneFile.setProperty("move" + name + "ToFile", true);
doneFile.save();
} catch (final IOException e) {
LOGGER.log(Level.SEVERE, tl("upgradingFilesError"), e);
ess.getLogger().log(Level.SEVERE, AdventureUtil.miniToLegacy(tlLiteral("upgradingFilesError")), e);
}
}
@ -529,10 +530,10 @@ public class EssentialsUpgrade {
bWriter.close();
if (needUpdate) {
if (!file.renameTo(new File(file.getParentFile(), file.getName().concat("." + System.currentTimeMillis() + ".upgradebackup")))) {
throw new Exception(tl("configFileMoveError"));
throw new Exception(tlLiteral("configFileMoveError"));
}
if (!tempFile.renameTo(file)) {
throw new Exception(tl("configFileRenameError"));
throw new Exception(tlLiteral("configFileRenameError"));
}
} else {
tempFile.delete();
@ -572,7 +573,7 @@ public class EssentialsUpgrade {
config.blockingSave();
}
} catch (final RuntimeException ex) {
LOGGER.log(Level.INFO, "File: " + file);
ess.getLogger().log(Level.INFO, "File: " + file);
throw ex;
}
}
@ -628,7 +629,7 @@ public class EssentialsUpgrade {
}
} catch (final RuntimeException ex) {
LOGGER.log(Level.INFO, "File: " + file);
ess.getLogger().log(Level.INFO, "File: " + file);
throw ex;
}
}
@ -657,15 +658,15 @@ public class EssentialsUpgrade {
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));
ess.getLogger().log(Level.WARNING, AdventureUtil.miniToLegacy(tlLiteral("userdataMoveError", filename, sanitizedFilename)));
continue;
}
if (newFile.exists()) {
LOGGER.log(Level.WARNING, tl("duplicatedUserdata", filename, sanitizedFilename));
ess.getLogger().log(Level.WARNING, AdventureUtil.miniToLegacy(tlLiteral("duplicatedUserdata", filename, sanitizedFilename)));
continue;
}
if (!tmpFile.renameTo(newFile)) {
LOGGER.log(Level.WARNING, tl("userdataMoveBackError", sanitizedFilename, sanitizedFilename));
ess.getLogger().log(Level.WARNING, AdventureUtil.miniToLegacy(tlLiteral("userdataMoveBackError", sanitizedFilename, sanitizedFilename)));
}
}
doneFile.setProperty("sanitizeAllUserFilenames", true);
@ -722,7 +723,7 @@ public class EssentialsUpgrade {
doneFile.setProperty("deleteOldItemsCsv", true);
doneFile.save();
} catch (final IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
ess.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
}
}
}
@ -743,12 +744,12 @@ public class EssentialsUpgrade {
config.setProperty(entry.getKey(), loc);
}
if (!configFile.renameTo(new File(ess.getDataFolder(), "spawn.yml.old"))) {
throw new Exception(tl("fileRenameError", "spawn.yml"));
throw new Exception(tlLiteral("fileRenameError", "spawn.yml"));
}
config.blockingSave();
}
} catch (final Exception ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
ess.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
}
}
doneFile.setProperty("updateSpawnsToNewSpawnsConfig", true);
@ -771,12 +772,12 @@ public class EssentialsUpgrade {
config.setProperty(entry.getKey(), loc);
}
if (!configFile.renameTo(new File(ess.getDataFolder(), "jail.yml.old"))) {
throw new Exception(tl("fileRenameError", "jail.yml"));
throw new Exception(tlLiteral("fileRenameError", "jail.yml"));
}
config.blockingSave();
}
} catch (final Exception ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
ess.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
}
}
doneFile.setProperty("updateJailsToNewJailsConfig", true);
@ -915,74 +916,130 @@ public class EssentialsUpgrade {
Bukkit.getBanList(BanList.Type.NAME).addBan(playerName, banReason, banTimeout == 0 ? null : new Date(banTimeout), Console.NAME);
}
private void repairUserMap() {
if (doneFile.getBoolean("userMapRepaired", false)) {
public void generateUidCache() {
if (doneFile.getBoolean("newUidCacheBuilt", false)) {
return;
}
ess.getLogger().info("Starting usermap repair");
final File usermapFile = new File(ess.getDataFolder(), "usermap.bin");
final File uidsFile = new File(ess.getDataFolder(), "uuids.bin");
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
if (!userdataFolder.isDirectory()) {
if (!userdataFolder.isDirectory() || usermapFile.exists() || uidsFile.exists()) {
ess.getLogger().warning("Missing userdata folder, aborting");
doneFile.setProperty("newUidCacheBuilt", true);
doneFile.save();
return;
}
final File[] files = userdataFolder.listFiles(YML_FILTER);
final DecimalFormat format = new DecimalFormat("#0.00");
final Map<String, UUID> names = Maps.newHashMap();
for (int index = 0; index < files.length; index++) {
final File file = files[index];
try {
UUID uuid = null;
final String filename = file.getName();
final String configData = new String(java.nio.file.Files.readAllBytes(file.toPath()), Charsets.UTF_8);
if (filename.length() > 36) {
try {
// ".yml" ending has 4 chars...
uuid = UUID.fromString(filename.substring(0, filename.length() - 4));
} catch (final IllegalArgumentException ignored) {
}
}
final Matcher uuidMatcher = PATTERN_CONFIG_UUID.matcher(configData);
if (uuidMatcher.find()) {
try {
uuid = UUID.fromString(uuidMatcher.group(1));
} catch (final IllegalArgumentException ignored) {
}
}
if (uuid == null) {
// Don't import
continue;
}
final Matcher nameMatcher = PATTERN_CONFIG_NAME.matcher(configData);
if (nameMatcher.find()) {
final String username = nameMatcher.group(1);
if (username != null && username.length() > 0) {
names.put(StringUtil.safeString(username), uuid);
}
}
if (index % 1000 == 0) {
ess.getLogger().info("Reading: " + format.format((100d * (double) index) / files.length)
+ "%");
}
} catch (final IOException e) {
ess.getLogger().log(Level.SEVERE, "Error while reading file: ", e);
try {
if (!usermapFile.createNewFile() || !uidsFile.createNewFile()) {
ess.getLogger().warning("Couldn't create usermap.bin or uuids.bin, aborting");
return;
}
final Map<UUID, Long> uuids = new HashMap<>();
final Map<String, UUID> nameToUuidMap = new HashMap<>();
final File[] files = userdataFolder.listFiles(YML_FILTER);
if (files != null) {
for (final File file : files) {
try {
final String fileName = file.getName();
final UUID uuid = UUID.fromString(fileName.substring(0, fileName.length() - 4));
final EssentialsConfiguration config = new EssentialsConfiguration(file);
config.load();
String name = config.getString("last-account-name", null);
name = ess.getSettings().isSafeUsermap() ? StringUtil.safeString(name) : name;
final long time = config.getLong("timestamps.logout", 0L);
if (name != null) {
if (nameToUuidMap.containsKey(name)) {
final UUID oldUuid = nameToUuidMap.get(name);
if (oldUuid.version() < uuid.version() || (oldUuid.version() == uuid.version() && uuids.get(oldUuid) < time)) {
ess.getLogger().warning("New UUID found for " + name + ": " + uuid + " (old: " + oldUuid + "). Replacing.");
uuids.remove(oldUuid);
} else {
ess.getLogger().warning("Found UUID for " + name + ": " + uuid + " (old: " + oldUuid + "). Skipping.");
continue;
}
}
uuids.put(uuid, time);
nameToUuidMap.put(name, uuid);
}
} catch (IllegalArgumentException | IndexOutOfBoundsException ignored) {
}
}
}
if (!nameToUuidMap.isEmpty()) {
ModernUUIDCache.writeNameUuidMap(usermapFile, nameToUuidMap);
}
if (!uuids.isEmpty()) {
ModernUUIDCache.writeUuidCache(uidsFile, uuids.keySet());
}
doneFile.setProperty("newUidCacheBuilt", true);
doneFile.save();
} catch (final IOException e) {
ess.getLogger().log(Level.SEVERE, "Error while generating initial uuids/names cache", e);
}
}
public void upgradeLang() {
if (doneFile.getBoolean("updateLegacyToAdventure", false)) {
return;
}
ess.getUserMap().getNames().putAll(names);
ess.getUserMap().reloadConfig();
ess.getLogger().log(Level.WARNING, "Beginning Adventure locale file conversion.");
doneFile.setProperty("userMapRepaired", true);
doneFile.save();
ess.getLogger().info("Completed usermap repair.");
try {
final File dataFolder = ess.getDataFolder();
if (!dataFolder.exists() || !dataFolder.isDirectory()) {
return;
}
final File backDir = new File(dataFolder, "msg-backups-" + System.currentTimeMillis());
if (backDir.exists() || !backDir.mkdir()) {
ess.getLogger().log(Level.SEVERE, "Unable to make msg-backups dir?!");
return;
}
final File messagesDir = new File(dataFolder, "messages");
//noinspection ResultOfMethodCallIgnored
messagesDir.mkdir();
final File[] files = dataFolder.listFiles();
boolean isThereAtLeastOneBackup = false;
if (files != null) {
for (final File file : files) {
if (file.getName().endsWith(".properties")) {
final File newFile = new File(messagesDir, file.getName());
final File backup = new File(backDir, file.getName());
Files.move(file, backup);
isThereAtLeastOneBackup = true;
final OrderedProperties properties = new OrderedProperties();
properties.load(Files.newReader(backup, Charsets.UTF_8));
for (final String key : properties.stringPropertyNames()) {
final String value = properties.getProperty(key);
properties.setProperty(key, AdventureUtil.legacyToMini(AdventureUtil.miniMessage().escapeTags(value), true));
}
properties.store(Files.newWriter(newFile, Charsets.UTF_8), null);
}
}
}
if (!isThereAtLeastOneBackup) {
backDir.delete();
}
doneFile.setProperty("updateLegacyToAdventure", true);
doneFile.save();
} catch (final Throwable e) {
ess.getLogger().log(Level.SEVERE, "Error while upgrading custom locales", e);
}
}
public void beforeSettings() {
@ -993,6 +1050,10 @@ public class EssentialsUpgrade {
moveMotdRulesToFile("rules");
}
public void preModules() {
generateUidCache();
}
public void afterSettings() {
sanitizeAllUserFilenames();
updateUsersPowerToolsFormat();
@ -1003,7 +1064,6 @@ public class EssentialsUpgrade {
uuidFileChange();
banFormatChange();
warnMetrics();
repairUserMap();
convertIgnoreList();
convertStupidCamelCaseUserdataKeys();
convertMailList();

View File

@ -1,66 +0,0 @@
package com.earth2me.essentials;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import org.bukkit.Bukkit;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import java.util.UUID;
import java.util.logging.Level;
public class EssentialsUserConf extends EssentialsConf {
public String username;
public final UUID uuid;
public EssentialsUserConf(final String username, final UUID uuid, final File configFile) {
super(configFile);
this.username = username;
this.uuid = uuid;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public boolean legacyFileExists() {
final File file = new File(configFile.getParentFile(), username + ".yml");
return file.exists();
}
@Override
public void convertLegacyFile() {
final File file = new File(configFile.getParentFile(), username + ".yml");
try {
Files.move(file, new File(configFile.getParentFile(), uuid + ".yml"));
} catch (final IOException ex) {
Bukkit.getLogger().log(Level.WARNING, "Failed to migrate user: " + username, ex);
}
setProperty("lastAccountName", username);
}
private File getAltFile() {
final UUID fn = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username.toLowerCase(Locale.ENGLISH)).getBytes(Charsets.UTF_8));
return new File(configFile.getParentFile(), fn.toString() + ".yml");
}
@Override
public boolean altFileExists() {
if (username.equals(username.toLowerCase())) {
return false;
}
return getAltFile().exists();
}
@Override
public void convertAltFile() {
try {
Files.move(getAltFile(), new File(configFile.getParentFile(), uuid + ".yml"));
} catch (final IOException ex) {
Bukkit.getLogger().log(Level.WARNING, "Failed to migrate user: " + username, ex);
}
}
}

View File

@ -1,6 +1,8 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.AdventureUtil;
import net.ess3.api.IEssentials;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileInputStream;
@ -13,26 +15,34 @@ import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
public class I18n implements net.ess3.api.II18n {
private static final String MESSAGES = "messages";
private static final Pattern NODOUBLEMARK = Pattern.compile("''");
private static final ExecutorService BUNDLE_LOADER_EXECUTOR = Executors.newFixedThreadPool(2);
private static final ResourceBundle NULL_BUNDLE = new ResourceBundle() {
@SuppressWarnings("NullableProblems")
public Enumeration<String> getKeys() {
return null;
}
protected Object handleGetObject(final String key) {
protected Object handleGetObject(final @NotNull String key) {
return null;
}
};
@ -41,30 +51,53 @@ public class I18n implements net.ess3.api.II18n {
private final transient ResourceBundle defaultBundle;
private final transient IEssentials ess;
private transient Locale currentLocale = defaultLocale;
private transient ResourceBundle customBundle;
private final transient Map<Locale, ResourceBundle> loadedBundles = new ConcurrentHashMap<>();
private final transient List<Locale> loadingBundles = new ArrayList<>();
private transient ResourceBundle localeBundle;
private transient Map<String, MessageFormat> messageFormatCache = new HashMap<>();
private final transient Map<Locale, Map<String, MessageFormat>> messageFormatCache = new HashMap<>();
public I18n(final IEssentials ess) {
this.ess = ess;
defaultBundle = ResourceBundle.getBundle(MESSAGES, Locale.ENGLISH, new UTF8PropertiesControl());
localeBundle = defaultBundle;
customBundle = NULL_BUNDLE;
}
public static String tl(final String string, final Object... objects) {
/**
* Translates a message using the server's configured locale.
* @param tlKey The translation key.
* @param objects Translation parameters, if applicable. Note: by default, these will not be parsed for MiniMessage.
* @return The translated message.
* @see AdventureUtil#parsed(String)
*/
public static String tlLiteral(final String tlKey, final Object... objects) {
if (instance == null) {
return "";
}
return tlLocale(instance.currentLocale, tlKey, objects);
}
/**
* Translates a message using the provided locale.
* @param locale The locale to translate the key to.
* @param tlKey The translation key.
* @param objects Translation parameters, if applicable. Note: by default, these will not be parsed for MiniMessage.
* @return The translated message.
* @see AdventureUtil#parsed(String)
*/
public static String tlLocale(final Locale locale, final String tlKey, final Object... objects) {
if (instance == null) {
return "";
}
if (objects.length == 0) {
return NODOUBLEMARK.matcher(instance.translate(string)).replaceAll("'");
return NODOUBLEMARK.matcher(instance.translate(locale, tlKey)).replaceAll("'");
} else {
return instance.format(string, objects);
return instance.format(tlKey, objects);
}
}
public static String capitalCase(final String input) {
return input == null || input.length() == 0 ? input : input.toUpperCase(Locale.ENGLISH).charAt(0) + input.toLowerCase(Locale.ENGLISH).substring(1);
return input == null || input.isEmpty() ? input : input.toUpperCase(Locale.ENGLISH).charAt(0) + input.toLowerCase(Locale.ENGLISH).substring(1);
}
public void onEnable() {
@ -80,81 +113,148 @@ public class I18n implements net.ess3.api.II18n {
return currentLocale;
}
private String translate(final String string) {
/**
* Returns the {@link ResourceBundle} for the given {@link Locale}, if loaded. If a bundle is requested which is
* not loaded, it will be loaded asynchronously and the default bundle will be returned in the meantime.
*/
private ResourceBundle getBundle(final Locale locale) {
if (loadedBundles.containsKey(locale)) {
return loadedBundles.get(locale);
} else {
synchronized (loadingBundles) {
if (!loadingBundles.contains(locale)) {
loadingBundles.add(locale);
BUNDLE_LOADER_EXECUTOR.submit(() -> {
ResourceBundle bundle;
try {
bundle = ResourceBundle.getBundle(MESSAGES, locale, new FileResClassLoader(I18n.class.getClassLoader(), ess), new UTF8PropertiesControl());
} catch (MissingResourceException ex) {
try {
bundle = ResourceBundle.getBundle(MESSAGES, locale, new UTF8PropertiesControl());
} catch (MissingResourceException ex2) {
bundle = NULL_BUNDLE;
}
}
loadedBundles.put(locale, bundle);
synchronized (loadingBundles) {
loadingBundles.remove(locale);
}
});
}
}
return defaultBundle;
}
}
private String translate(final Locale locale, final String string) {
try {
try {
return customBundle.getString(string);
return getBundle(locale).getString(string);
} catch (final MissingResourceException ex) {
return localeBundle.getString(string);
}
} catch (final MissingResourceException ex) {
if (ess == null || ess.getSettings().isDebug()) {
Logger.getLogger("Essentials").log(Level.WARNING, String.format("Missing translation key \"%s\" in translation file %s", ex.getKey(), localeBundle.getLocale().toString()), ex);
if (ess != null && ess.getSettings().isDebug()) {
ess.getLogger().log(Level.WARNING, String.format("Missing translation key \"%s\" in translation file %s", ex.getKey(), localeBundle.getLocale().toString()), ex);
}
return defaultBundle.getString(string);
}
}
public String format(final String string, final Object... objects) {
String format = translate(string);
MessageFormat messageFormat = messageFormatCache.get(format);
private String format(final String string, final Object... objects) {
return format(currentLocale, string, objects);
}
private String format(final Locale locale, final String string, final Object... objects) {
String format = translate(locale, string);
MessageFormat messageFormat = messageFormatCache.computeIfAbsent(locale, l -> new HashMap<>()).get(format);
if (messageFormat == null) {
try {
messageFormat = new MessageFormat(format);
} catch (final IllegalArgumentException e) {
ess.getLogger().log(Level.SEVERE, "Invalid Translation key for '" + string + "': " + e.getMessage());
format = format.replaceAll("\\{(\\D*?)\\}", "\\[$1\\]");
format = format.replaceAll("\\{(\\D*?)}", "\\[$1\\]");
messageFormat = new MessageFormat(format);
}
messageFormatCache.put(format, messageFormat);
messageFormatCache.get(locale).put(format, messageFormat);
}
return messageFormat.format(objects).replace(' ', ' '); // replace nbsp with a space
final Object[] processedArgs = mutateArgs(objects, arg -> {
if (arg instanceof AdventureUtil.ParsedPlaceholder) {
return arg.toString();
}
return AdventureUtil.legacyToMini(AdventureUtil.miniMessage().escapeTags(arg.toString()));
});
return messageFormat.format(processedArgs).replace(' ', ' '); // replace nbsp with a space
}
public static Object[] mutateArgs(final Object[] objects, final Function<Object, String> mutator) {
final Object[] args = new Object[objects.length];
for (int i = 0; i < objects.length; i++) {
final Object object = objects[i];
// MessageFormat will format these itself, troll face.
if (object instanceof Number || object instanceof Date || object == null) {
args[i] = object;
continue;
}
args[i] = mutator.apply(object);
}
return args;
}
public void updateLocale(final String loc) {
if (loc != null && !loc.isEmpty()) {
final String[] parts = loc.split("[_\\.]");
if (parts.length == 1) {
currentLocale = new Locale(parts[0]);
}
if (parts.length == 2) {
currentLocale = new Locale(parts[0], parts[1]);
}
if (parts.length == 3) {
currentLocale = new Locale(parts[0], parts[1], parts[2]);
}
currentLocale = getLocale(loc);
}
ResourceBundle.clearCache();
messageFormatCache = new HashMap<>();
Logger.getLogger("Essentials").log(Level.INFO, String.format("Using locale %s", currentLocale.toString()));
loadedBundles.clear();
messageFormatCache.clear();
ess.getLogger().log(Level.INFO, String.format("Using locale %s", currentLocale.toString()));
try {
localeBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new UTF8PropertiesControl());
} catch (final MissingResourceException ex) {
localeBundle = NULL_BUNDLE;
}
}
try {
customBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new FileResClassLoader(I18n.class.getClassLoader(), ess), new UTF8PropertiesControl());
} catch (final MissingResourceException ex) {
customBundle = NULL_BUNDLE;
public static Locale getLocale(final String loc) {
if (loc == null || loc.isEmpty()) {
return instance.currentLocale;
}
final String[] parts = loc.split("[_.]");
if (parts.length == 1) {
return new Locale(parts[0]);
}
if (parts.length == 2) {
return new Locale(parts[0], parts[1]);
}
if (parts.length == 3) {
return new Locale(parts[0], parts[1], parts[2]);
}
return instance.currentLocale;
}
/**
* Attempts to load properties files from the plugin directory before falling back to the jar.
*/
private static class FileResClassLoader extends ClassLoader {
private final transient File dataFolder;
private final transient File messagesFolder;
FileResClassLoader(final ClassLoader classLoader, final IEssentials ess) {
super(classLoader);
this.dataFolder = ess.getDataFolder();
this.messagesFolder = new File(ess.getDataFolder(), "messages");
//noinspection ResultOfMethodCallIgnored
this.messagesFolder.mkdirs();
}
@Override
public URL getResource(final String string) {
final File file = new File(dataFolder, string);
final File file = new File(messagesFolder, string);
if (file.exists()) {
try {
return file.toURI().toURL();
@ -166,7 +266,7 @@ public class I18n implements net.ess3.api.II18n {
@Override
public InputStream getResourceAsStream(final String string) {
final File file = new File(dataFolder, string);
final File file = new File(messagesFolder, string);
if (file.exists()) {
try {
return new FileInputStream(file);
@ -208,5 +308,13 @@ public class I18n implements net.ess3.api.II18n {
}
return bundle;
}
@Override
public Locale getFallbackLocale(String baseName, Locale locale) {
if (baseName == null || locale == null) {
throw new NullPointerException();
}
return null;
}
}
}

View File

@ -7,15 +7,20 @@ import com.earth2me.essentials.commands.IEssentialsCommand;
import com.earth2me.essentials.commands.PlayerNotFoundException;
import com.earth2me.essentials.perm.PermissionsHandler;
import com.earth2me.essentials.updatecheck.UpdateChecker;
import com.earth2me.essentials.userstorage.IUserMap;
import net.ess3.nms.refl.providers.ReflOnlineModeProvider;
import net.ess3.provider.BiomeKeyProvider;
import net.ess3.provider.ContainerProvider;
import net.ess3.provider.DamageEventProvider;
import net.ess3.provider.FormattedCommandAliasProvider;
import net.ess3.provider.ItemUnbreakableProvider;
import net.ess3.provider.KnownCommandsProvider;
import net.ess3.provider.MaterialTagProvider;
import net.ess3.provider.PersistentDataProvider;
import net.ess3.provider.ServerStateProvider;
import net.ess3.provider.PlayerLocaleProvider;
import net.ess3.provider.SerializationProvider;
import net.ess3.provider.ServerStateProvider;
import net.ess3.provider.SignDataProvider;
import net.ess3.provider.SpawnerBlockProvider;
import net.ess3.provider.SpawnerItemProvider;
import net.ess3.provider.SyncCommandsProvider;
@ -78,6 +83,16 @@ public interface IEssentials extends Plugin {
int broadcastMessage(String permission, String message);
void broadcastTl(String tlKey, Object... args);
void broadcastTl(IUser sender, String tlKey, Object... args);
void broadcastTl(IUser sender, String permission, String tlKey, Object... args);
void broadcastTl(IUser sender, Predicate<IUser> shouldExclude, String tlKey, Object... args);
void broadcastTl(IUser sender, Predicate<IUser> shouldExclude, boolean parseKeywords, String tlKey, Object... args);
ISettings getSettings();
BukkitScheduler getScheduler();
@ -108,8 +123,6 @@ public interface IEssentials extends Plugin {
int scheduleSyncRepeatingTask(Runnable run, long delay, long period);
TNTExplodeListener getTNTListener();
PermissionsHandler getPermissionsHandler();
AlternativeCommandsHandler getAlternativeCommandsHandler();
@ -118,6 +131,9 @@ public interface IEssentials extends Plugin {
IItemDb getItemDb();
IUserMap getUsers();
@Deprecated
UserMap getUserMap();
BalanceTop getBalanceTop();
@ -165,5 +181,13 @@ public interface IEssentials extends Plugin {
WorldInfoProvider getWorldInfoProvider();
SignDataProvider getSignDataProvider();
PlayerLocaleProvider getPlayerLocaleProvider();
DamageEventProvider getDamageEventProvider();
BiomeKeyProvider getBiomeKeyProvider();
PluginCommand getPluginCommand(String cmd);
}

View File

@ -3,6 +3,7 @@ package com.earth2me.essentials;
import com.earth2me.essentials.commands.IEssentialsCommand;
import com.earth2me.essentials.signs.EssentialsSign;
import com.earth2me.essentials.textreader.IText;
import net.kyori.adventure.text.minimessage.tag.Tag;
import org.bukkit.Material;
import org.bukkit.event.EventPriority;
import org.spongepowered.configurate.CommentedConfigurationNode;
@ -46,6 +47,12 @@ public interface ISettings extends IConf {
char getChatQuestion();
boolean isShoutDefault();
boolean isPersistShout();
boolean isChatQuestionEnabled();
BigDecimal getCommandCost(IEssentialsCommand cmd);
BigDecimal getCommandCost(String label);
@ -66,6 +73,8 @@ public interface ISettings extends IConf {
boolean isSocialSpyMessages();
boolean isSocialSpyDisplayNames();
Set<String> getMuteCommands();
@Deprecated
@ -75,6 +84,8 @@ public interface ISettings extends IConf {
String getLocale();
boolean isPerPlayerLocale();
String getNewbieSpawn();
String getNicknamePrefix();
@ -228,6 +239,8 @@ public interface ISettings extends IConf {
boolean isWorldHomePermissions();
int getMaxTreeCommandRange();
boolean registerBackInListener();
boolean getDisableItemPickupWhileAfk();
@ -274,6 +287,8 @@ public interface ISettings extends IConf {
int getMaxUserCacheCount();
long getMaxUserCacheValueExpiry();
boolean allowSilentJoinQuit();
boolean isCustomJoinMessage();
@ -396,6 +411,12 @@ public interface ISettings extends IConf {
boolean showZeroBaltop();
int getMaxItemLore();
Tag getPrimaryColor();
Tag getSecondaryColor();
enum KeepInvPolicy {
KEEP,
DELETE,

View File

@ -8,6 +8,8 @@ import net.ess3.api.MaxMoneyException;
import net.ess3.api.events.AfkStatusChangeEvent;
import net.essentialsx.api.v2.services.mail.MailMessage;
import net.essentialsx.api.v2.services.mail.MailSender;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
@ -15,7 +17,6 @@ import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@ -94,6 +95,15 @@ public interface IUser {
*/
boolean isHidden();
/**
* Whether the user was hidden before leaving the server.
*
* @return true if the user was hidden.
*/
boolean isLeavingHidden();
void setLeavingHidden(boolean leavingHidden);
void setHidden(boolean vanish);
boolean isGodModeEnabled();
@ -133,6 +143,14 @@ public interface IUser {
void sendMessage(String message);
void sendComponent(ComponentLike component);
Component tlComponent(String tlKey, Object... args);
String playerTl(String tlKey, Object... args);
void sendTl(String tlKey, Object... args);
/*
* UserData
*/
@ -146,6 +164,8 @@ public interface IUser {
void delHome(String name) throws Exception;
void renameHome(String name, String newName) throws Exception;
boolean hasHome();
Location getLastLocation();
@ -261,12 +281,12 @@ public interface IUser {
* period are removed from queue and therefore not returned here. The maximum size of this
* queue is determined by {@link ISettings#getTpaMaxRequests()}.
*
* @param inform true if the underlying {@link IUser} should be informed if a request expires during iteration.
* @param performExpirations true if this method should not spend time validating time for all items in the queue and just return the first item in the queue.
* @param excludeHere true if /tphere requests should be ignored in fetching the next tpa request.
* @param inform true if the underlying {@link IUser} should be informed if a request expires during iteration.
* @param ignoreExpirations true if this method should not process expirations for the entire queue and stop execution on the first unexpired request.
* @param excludeHere true if /tphere requests should be ignored in fetching the next tpa request.
* @return A {@link TpaRequest} corresponding to the next available request or null if no valid request is present.
*/
@Nullable TpaRequest getNextTpaRequest(boolean inform, boolean performExpirations, boolean excludeHere);
@Nullable TpaRequest getNextTpaRequest(boolean inform, boolean ignoreExpirations, boolean excludeHere);
/**
* Whether or not this {@link IUser} has any valid TPA requests in queue.
@ -321,4 +341,12 @@ public interface IUser {
this.time = time;
}
}
List<String> getPastUsernames();
void addPastUsername(String username);
boolean isFreeze();
void setFreeze(boolean freeze);
}

View File

@ -3,8 +3,10 @@ package com.earth2me.essentials;
import com.earth2me.essentials.config.ConfigurateUtil;
import com.earth2me.essentials.config.EssentialsConfiguration;
import com.earth2me.essentials.config.entities.LazyLocation;
import com.earth2me.essentials.utils.AdventureUtil;
import net.ess3.api.IEssentials;
import net.ess3.api.IUser;
import net.ess3.api.TranslatableException;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
@ -34,12 +36,10 @@ import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public class Jails implements net.ess3.api.IJails {
private static final transient Logger LOGGER = Logger.getLogger("Essentials");
private static transient boolean enabled = false;
private final IEssentials ess;
private final EssentialsConfiguration config;
@ -76,7 +76,7 @@ public class Jails implements net.ess3.api.IJails {
final JailListener blockListener = new JailListener();
pluginManager.registerEvents(blockListener, ess);
if (ess.getSettings().isDebug()) {
LOGGER.log(Level.INFO, "Registering Jail listener");
ess.getLogger().log(Level.INFO, "Registering Jail listener");
}
}
@ -104,17 +104,17 @@ public class Jails implements net.ess3.api.IJails {
@Override
public Location getJail(String jailName) throws Exception {
if (jailName == null) {
throw new Exception(tl("jailNotExist"));
throw new TranslatableException("jailNotExist");
}
jailName = jailName.toLowerCase(Locale.ENGLISH);
synchronized (jails) {
if (!jails.containsKey(jailName)) {
throw new Exception(tl("jailNotExist"));
throw new TranslatableException("jailNotExist");
}
final Location location = jails.get(jailName).location();
if (location == null) {
throw new Exception(tl("jailWorldNotExist"));
throw new TranslatableException("jailWorldNotExist");
}
return location;
}
@ -205,6 +205,10 @@ public class Jails implements net.ess3.api.IJails {
private class JailListener implements Listener {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailBlockBreak(final BlockBreakEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-break")) {
event.setCancelled(true);
@ -213,6 +217,10 @@ public class Jails implements net.ess3.api.IJails {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailBlockPlace(final BlockPlaceEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-place")) {
event.setCancelled(true);
@ -221,6 +229,10 @@ public class Jails implements net.ess3.api.IJails {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailBlockDamage(final BlockDamageEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-block-damage")) {
event.setCancelled(true);
@ -234,6 +246,9 @@ public class Jails implements net.ess3.api.IJails {
}
final Entity damager = event.getDamager();
if (damager.getType() == EntityType.PLAYER) {
if (shouldIgnore((Player) damager)) {
return;
}
final User user = ess.getUser((Player) damager);
if (user != null && user.isJailed()) {
event.setCancelled(true);
@ -243,6 +258,10 @@ public class Jails implements net.ess3.api.IJails {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailPlayerInteract(final PlayerInteractEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-interact")) {
event.setCancelled(true);
@ -251,6 +270,10 @@ public class Jails implements net.ess3.api.IJails {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onJailPlayerGameModeChange(final PlayerGameModeChangeEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (user.isJailed()) {
event.setCancelled(true);
@ -259,6 +282,10 @@ public class Jails implements net.ess3.api.IJails {
@EventHandler(priority = EventPriority.HIGHEST)
public void onJailPlayerRespawn(final PlayerRespawnEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (!user.isJailed() || user.getJail() == null || user.getJail().isEmpty()) {
return;
@ -268,15 +295,19 @@ public class Jails implements net.ess3.api.IJails {
event.setRespawnLocation(getJail(user.getJail()));
} catch (final Exception ex) {
if (ess.getSettings().isDebug()) {
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()), ex);
ess.getLogger().log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage())), ex);
} else {
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()));
ess.getLogger().log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage())));
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onJailPlayerTeleport(final PlayerTeleportEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
if (!user.isJailed() || user.getJail() == null || user.getJail().isEmpty()) {
return;
@ -286,16 +317,20 @@ public class Jails implements net.ess3.api.IJails {
event.setTo(getJail(user.getJail()));
} catch (final Exception ex) {
if (ess.getSettings().isDebug()) {
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()), ex);
ess.getLogger().log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage())), ex);
} else {
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()));
ess.getLogger().log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage())));
}
}
user.sendMessage(tl("jailMessage"));
user.sendTl("jailMessage");
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onJailPlayerJoin(final PlayerJoinEvent event) {
if (shouldIgnore(event.getPlayer())) {
return;
}
final User user = ess.getUser(event.getPlayer());
final long currentTime = System.currentTimeMillis();
user.checkJailTimeout(currentTime);
@ -306,13 +341,13 @@ public class Jails implements net.ess3.api.IJails {
final CompletableFuture<Boolean> future = new CompletableFuture<>();
future.exceptionally(ex -> {
if (ess.getSettings().isDebug()) {
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()), ex);
ess.getLogger().log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage())), ex);
} else {
LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()));
ess.getLogger().log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage())));
}
return false;
});
future.thenAccept(success -> user.sendMessage(tl("jailMessage")));
future.thenAccept(success -> user.sendTl("jailMessage"));
try {
sendToJail(user, user.getJail(), future);
@ -320,5 +355,10 @@ public class Jails implements net.ess3.api.IJails {
future.completeExceptionally(ex);
}
}
private boolean shouldIgnore(final Player base) {
// Ignore Citizens NPCs
return base.getUniqueId().version() == 2 || base.hasMetadata("NPC");
}
}
}

View File

@ -2,30 +2,32 @@ package com.earth2me.essentials;
import com.earth2me.essentials.Trade.OverflowType;
import com.earth2me.essentials.commands.NoChargeException;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
import net.ess3.api.IEssentials;
import net.ess3.api.TranslatableException;
import net.ess3.api.events.KitClaimEvent;
import net.essentialsx.api.v2.events.KitPreExpandItemsEvent;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public class Kit {
final IEssentials ess;
@ -40,7 +42,7 @@ public class Kit {
this.charge = new Trade("kit-" + kitName, new Trade("kit-kit", ess), ess);
if (kit == null) {
throw new Exception(tl("kitNotFound"));
throw new TranslatableException("kitNotFound");
}
}
@ -50,7 +52,7 @@ public class Kit {
public void checkPerms(final User user) throws Exception {
if (!user.isAuthorized("essentials.kits." + kitName)) {
throw new Exception(tl("noKitPermission", "essentials.kits." + kitName));
throw new TranslatableException("noKitPermission", "essentials.kits." + kitName);
}
}
@ -59,10 +61,10 @@ public class Kit {
if (nextUse == 0L) {
} else if (nextUse < 0L) {
user.sendMessage(tl("kitOnce"));
user.sendTl("kitOnce");
throw new NoChargeException();
} else {
user.sendMessage(tl("kitTimed", DateUtil.formatDateDiff(nextUse)));
user.sendTl("kitTimed", DateUtil.formatDateDiff(nextUse));
throw new NoChargeException();
}
}
@ -96,7 +98,7 @@ public class Kit {
// Make sure delay is valid
delay = kit.containsKey("delay") ? ((Number) kit.get("delay")).doubleValue() : 0.0d;
} catch (final Exception e) {
throw new Exception(tl("kitError2"));
throw new TranslatableException("kitError2");
}
// When was the last kit used?
@ -130,7 +132,7 @@ public class Kit {
public List<String> getItems() throws Exception {
if (kit == null) {
throw new Exception(tl("kitNotFound"));
throw new TranslatableException("kitNotFound");
}
try {
final List<String> itemList = new ArrayList<>();
@ -148,7 +150,7 @@ public class Kit {
throw new Exception("Invalid item list");
} catch (final Exception e) {
ess.getLogger().log(Level.WARNING, "Error parsing kit " + kitName + ": " + e.getMessage());
throw new Exception(tl("kitError2"), e);
throw new TranslatableException(e,"kitError2");
}
}
@ -192,7 +194,7 @@ public class Kit {
if (kitItem.startsWith("@")) {
if (ess.getSerializationProvider() == null) {
ess.getLogger().log(Level.WARNING, tl("kitError3", kitName, user.getName()));
ess.getLogger().log(Level.WARNING, AdventureUtil.miniToLegacy(tlLiteral("kitError3", kitName, user.getName())));
continue;
}
stack = ess.getSerializationProvider().deserializeItem(Base64Coder.decodeLines(kitItem.substring(1)));
@ -214,57 +216,38 @@ public class Kit {
stack = metaStack.getItemStack();
}
if (autoEquip) {
final Material material = stack.getType();
final PlayerInventory inventory = user.getBase().getInventory();
if (MaterialUtil.isHelmet(material) && isEmptyStack(inventory.getHelmet())) {
inventory.setHelmet(stack);
continue;
} else if (MaterialUtil.isChestplate(material) && isEmptyStack(inventory.getChestplate())) {
inventory.setChestplate(stack);
continue;
} else if (MaterialUtil.isLeggings(material) && isEmptyStack(inventory.getLeggings())) {
inventory.setLeggings(stack);
continue;
} else if (MaterialUtil.isBoots(material) && isEmptyStack(inventory.getBoots())) {
inventory.setBoots(stack);
continue;
}
}
itemList.add(stack);
}
final Map<Integer, ItemStack> overfilled;
final boolean allowOversizedStacks = user.isAuthorized("essentials.oversizedstacks");
final int maxStackSize = user.isAuthorized("essentials.oversizedstacks") ? ess.getSettings().getOversizedStackSize() : 0;
final boolean isDropItemsIfFull = ess.getSettings().isDropItemsIfFull();
if (isDropItemsIfFull) {
if (allowOversizedStacks) {
overfilled = InventoryWorkaround.addOversizedItems(user.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), itemList.toArray(new ItemStack[0]));
} else {
overfilled = InventoryWorkaround.addItems(user.getBase().getInventory(), itemList.toArray(new ItemStack[0]));
final KitPreExpandItemsEvent itemsEvent = new KitPreExpandItemsEvent(user, kitName, itemList);
Bukkit.getPluginManager().callEvent(itemsEvent);
final ItemStack[] itemArray = itemList.toArray(new ItemStack[0]);
if (!isDropItemsIfFull && !Inventories.hasSpace(user.getBase(), maxStackSize, autoEquip, itemArray)) {
user.sendTl("kitInvFullNoDrop");
return false;
}
final Map<Integer, ItemStack> leftover = Inventories.addItem(user.getBase(), maxStackSize, autoEquip, itemArray);
if (!isDropItemsIfFull && !leftover.isEmpty()) {
// Inventories#hasSpace should prevent this state from EVER being reached; If it does, something has gone terribly wrong, and we should just give up and hope people report it :(
throw new IllegalStateException("Something has gone terribly wrong while adding items to the user's inventory. Please report this to the EssentialsX developers. Items left over: " + leftover + ". Original items: " + Arrays.toString(itemArray));
}
for (final ItemStack itemStack : leftover.values()) {
int spillAmount = itemStack.getAmount();
if (maxStackSize != 0) {
itemStack.setAmount(Math.min(spillAmount, itemStack.getMaxStackSize()));
}
for (final ItemStack itemStack : overfilled.values()) {
int spillAmount = itemStack.getAmount();
if (!allowOversizedStacks) {
itemStack.setAmount(Math.min(spillAmount, itemStack.getMaxStackSize()));
}
while (spillAmount > 0) {
user.getWorld().dropItemNaturally(user.getLocation(), itemStack);
spillAmount -= itemStack.getAmount();
}
spew = true;
}
} else {
if (allowOversizedStacks) {
overfilled = InventoryWorkaround.addAllOversizedItems(user.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), itemList.toArray(new ItemStack[0]));
} else {
overfilled = InventoryWorkaround.addAllItems(user.getBase().getInventory(), itemList.toArray(new ItemStack[0]));
}
if (overfilled != null) {
user.sendMessage(tl("kitInvFullNoDrop"));
return false;
while (spillAmount > 0) {
user.getWorld().dropItemNaturally(user.getLocation(), itemStack);
spillAmount -= itemStack.getAmount();
}
spew = true;
}
user.getBase().updateInventory();
@ -282,17 +265,13 @@ public class Kit {
}
if (spew) {
user.sendMessage(tl("kitInvFull"));
user.sendTl("kitInvFull");
}
} catch (final Exception e) {
user.getBase().updateInventory();
ess.getLogger().log(Level.WARNING, e.getMessage());
throw new Exception(tl("kitError2"), e);
throw new TranslatableException(e, "kitError2");
}
return true;
}
private boolean isEmptyStack(ItemStack stack) {
return stack == null || MaterialUtil.isAir(stack.getType());
}
}

View File

@ -3,6 +3,7 @@ package com.earth2me.essentials;
import com.earth2me.essentials.config.ConfigurateUtil;
import com.earth2me.essentials.config.EssentialsConfiguration;
import com.earth2me.essentials.utils.NumberUtil;
import net.ess3.api.TranslatableException;
import org.spongepowered.configurate.CommentedConfigurationNode;
import java.io.File;
@ -14,7 +15,6 @@ import java.util.Map;
import java.util.Set;
import static com.earth2me.essentials.I18n.capitalCase;
import static com.earth2me.essentials.I18n.tl;
public class Kits implements IConf {
private final IEssentials ess;
@ -145,7 +145,7 @@ public class Kits implements IConf {
String name = capitalCase(kitItem);
final BigDecimal costPrice = new Trade("kit-" + kitItem.toLowerCase(Locale.ENGLISH), ess).getCommandCost(user);
if (costPrice.signum() > 0) {
cost = tl("kitCost", NumberUtil.displayCurrency(costPrice, ess));
cost = user.playerTl("kitCost", NumberUtil.displayCurrency(costPrice, ess));
}
final Kit kit = new Kit(kitItem, ess);
@ -153,7 +153,7 @@ public class Kits implements IConf {
if (nextUse == -1 && ess.getSettings().isSkippingUsedOneTimeKitsFromKitList()) {
continue;
} else if (nextUse != 0) {
name = tl("kitDelay", name);
name = user.playerTl("kitDelay", name);
}
list.append(" ").append(name).append(cost);
@ -161,7 +161,7 @@ public class Kits implements IConf {
}
return list.toString().trim();
} catch (final Exception ex) {
throw new Exception(tl("kitError"), ex);
throw new TranslatableException(ex, "kitError");
}
}

View File

@ -1,16 +1,18 @@
package com.earth2me.essentials;
import net.ess3.api.IUser;
import net.essentialsx.api.v2.services.mail.MailService;
import net.essentialsx.api.v2.events.UserMailEvent;
import net.essentialsx.api.v2.services.mail.MailMessage;
import net.essentialsx.api.v2.services.mail.MailSender;
import net.essentialsx.api.v2.services.mail.MailService;
import org.bukkit.Bukkit;
import org.bukkit.plugin.ServicePriority;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public class MailServiceImpl implements MailService {
private final transient ThreadLocal<SimpleDateFormat> df = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy/MM/dd HH:mm"));
@ -35,6 +37,12 @@ public class MailServiceImpl implements MailService {
}
private void sendMail(IUser recipient, MailMessage message) {
final UserMailEvent event = new UserMailEvent(recipient, message);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
final ArrayList<MailMessage> messages = recipient.getMailMessages();
messages.add(0, message);
recipient.setMailList(messages);
@ -44,10 +52,28 @@ public class MailServiceImpl implements MailService {
public String getMailLine(MailMessage mail) {
final String message = mail.getMessage();
if (mail.isLegacy()) {
return tl("mailMessage", message);
return tlLiteral("mailMessage", message);
}
final String expire = mail.getTimeExpire() != 0 ? "Timed" : "";
return tl((mail.isRead() ? "mailFormatNewRead" : "mailFormatNew") + expire, df.get().format(new Date(mail.getTimeSent())), mail.getSenderUsername(), message);
return tlLiteral((mail.isRead() ? "mailFormatNewRead" : "mailFormatNew") + expire, df.get().format(new Date(mail.getTimeSent())), mail.getSenderUsername(), message);
}
@Override
public String getMailTlKey(MailMessage message) {
if (message.isLegacy()) {
return "mailMessage";
}
final String expire = message.getTimeExpire() != 0 ? "Timed" : "";
return (message.isRead() ? "mailFormatNewRead" : "mailFormatNew") + expire;
}
@Override
public Object[] getMailTlArgs(MailMessage message) {
if (message.isLegacy()) {
return new Object[] {message.getMessage()};
}
return new Object[] {df.get().format(new Date(message.getTimeSent())), message.getSenderUsername(), message.getMessage()};
}
}

View File

@ -1,7 +1,7 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.AdventureUtil;
import net.ess3.api.IEssentials;
import org.bukkit.Bukkit;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
@ -23,7 +23,7 @@ import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public class ManagedFile {
private static final int BUFFERSIZE = 1024 * 8;
@ -38,7 +38,7 @@ public class ManagedFile {
throw new IOException("Could not delete file " + file.toString());
}
} catch (final IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
Essentials.getWrappedLogger().log(Level.SEVERE, ex.getMessage(), ex);
}
}
@ -46,7 +46,7 @@ public class ManagedFile {
try {
copyResourceAscii("/" + filename, file);
} catch (final IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, tl("itemsCsvNotLoaded", filename), ex);
Essentials.getWrappedLogger().log(Level.SEVERE, AdventureUtil.miniToLegacy(tlLiteral("itemsCsvNotLoaded", filename)), ex);
}
}
}
@ -113,7 +113,7 @@ public class ManagedFile {
if (correct.equals(test)) {
return true;
} else {
Bukkit.getLogger().warning("File " + file.toString() + " has been modified by user and file version differs, please update the file manually.");
Essentials.getWrappedLogger().warning("File " + file.toString() + " has been modified by user and file version differs, please update the file manually.");
}
}
}
@ -147,7 +147,7 @@ public class ManagedFile {
return lines;
}
} catch (final IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
Essentials.getWrappedLogger().log(Level.SEVERE, ex.getMessage(), ex);
return Collections.emptyList();
}
}

View File

@ -10,6 +10,7 @@ import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.base.Joiner;
import net.ess3.api.IEssentials;
import net.ess3.api.TranslatableException;
import org.bukkit.Color;
import org.bukkit.DyeColor;
import org.bukkit.FireworkEffect;
@ -42,8 +43,6 @@ import java.util.Map;
import java.util.logging.Level;
import java.util.regex.Pattern;
import static com.earth2me.essentials.I18n.tl;
public class MetaItemStack {
private static final Map<String, DyeColor> colorMap = new HashMap<>();
private static final Map<String, FireworkEffect.Type> fireworkShape = new HashMap<>();
@ -153,7 +152,7 @@ public class MetaItemStack {
ess.getLogger().log(Level.INFO, "Itemstack is invalid", npe);
}
} catch (final NoSuchMethodError nsme) {
throw new Exception(tl("noMetaJson"), nsme);
throw new TranslatableException(nsme, "noMetaJson");
} catch (final Throwable throwable) {
throw new Exception(throwable.getMessage(), throwable);
}
@ -163,19 +162,19 @@ public class MetaItemStack {
}
if (validFirework) {
if (!hasMetaPermission(sender, "firework", true, true, ess)) {
throw new Exception(tl("noMetaFirework"));
throw new TranslatableException("noMetaFirework");
}
final FireworkEffect effect = builder.build();
final FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
fmeta.addEffect(effect);
if (fmeta.getEffects().size() > 1 && !hasMetaPermission(sender, "firework-multiple", true, true, ess)) {
throw new Exception(tl("multipleCharges"));
throw new TranslatableException("multipleCharges");
}
stack.setItemMeta(fmeta);
}
if (validFireworkCharge) {
if (!hasMetaPermission(sender, "firework", true, true, ess)) {
throw new Exception(tl("noMetaFirework"));
throw new TranslatableException("noMetaFirework");
}
final FireworkEffect effect = builder.build();
final FireworkEffectMeta meta = (FireworkEffectMeta) stack.getItemMeta();
@ -194,33 +193,50 @@ public class MetaItemStack {
final Material WRITTEN_BOOK = EnumUtil.getMaterial("WRITTEN_BOOK");
if (split.length > 1 && split[0].equalsIgnoreCase("name") && hasMetaPermission(sender, "name", false, true, ess)) {
final String displayName = FormatUtil.replaceFormat(split[1].replace('_', ' '));
final String displayName = FormatUtil.replaceFormat(split[1].replaceAll("(?<!\\\\)_", " ").replace("\\_", "_"));
final ItemMeta meta = stack.getItemMeta();
meta.setDisplayName(displayName);
stack.setItemMeta(meta);
} else if (split.length > 1 && (split[0].equalsIgnoreCase("lore") || split[0].equalsIgnoreCase("desc")) && hasMetaPermission(sender, "lore", false, true, ess)) {
final List<String> lore = new ArrayList<>();
for (final String line : split[1].split("(?<!\\\\)\\|")) {
lore.add(FormatUtil.replaceFormat(line.replace('_', ' ').replace("\\|", "|")));
lore.add(FormatUtil.replaceFormat(line.replaceAll("(?<!\\\\)_", " ").replace("\\_", "_").replace("\\|", "|")));
}
final ItemMeta meta = stack.getItemMeta();
meta.setLore(lore);
stack.setItemMeta(meta);
} else if ((split[0].equalsIgnoreCase("custom-model-data") || split[0].equalsIgnoreCase("cmd")) && hasMetaPermission(sender, "custom-model-data", false, true, ess)) {
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_14_R01)) {
final int value = split.length <= 1 ? 0 : Integer.parseInt(split[1]);
final ItemMeta meta = stack.getItemMeta();
meta.setCustomModelData(value);
stack.setItemMeta(meta);
}
} else if (split[0].equalsIgnoreCase("unbreakable") && hasMetaPermission(sender, "unbreakable", false, true, ess)) {
final boolean value = split.length <= 1 || Boolean.parseBoolean(split[1]);
setUnbreakable(ess, stack, value);
} else if (split.length > 1 && (split[0].equalsIgnoreCase("player") || split[0].equalsIgnoreCase("owner")) && hasMetaPermission(sender, "head", false, true, ess)) {
if (MaterialUtil.isPlayerHead(stack.getType(), stack.getDurability())) {
if (MaterialUtil.isPlayerHead(stack)) {
final String owner = split[1];
setSkullOwner(ess, stack, owner);
} else {
throw new Exception(tl("onlyPlayerSkulls"));
throw new TranslatableException("onlyPlayerSkulls");
}
} else if (split.length > 1 && split[0].equalsIgnoreCase("book") && MaterialUtil.isEditableBook(stack.getType()) && (hasMetaPermission(sender, "book",true, true, ess) || hasMetaPermission(sender, "chapter-" + split[1].toLowerCase(Locale.ENGLISH), true, true, ess))) {
} else if (split.length > 1 && split[0].equalsIgnoreCase("book") && MaterialUtil.isEditableBook(stack.getType()) && (hasMetaPermission(sender, "book", true, true, ess) || hasMetaPermission(sender, "chapter-" + split[1].toLowerCase(Locale.ENGLISH), true, true, ess))) {
final BookMeta meta = (BookMeta) stack.getItemMeta();
final IText input = new BookInput("book", true, ess);
final BookPager pager = new BookPager(input);
// This fix only applies to written books - which require an author and a title. https://bugs.mojang.com/browse/MC-59153
if (stack.getType() == WRITTEN_BOOK) {
if (!meta.hasAuthor()) {
// The sender can be null when this method is called from {@link com.earth2me.essentials.signs.EssentialsSign#getItemMeta(ItemStack, String, IEssentials)}
meta.setAuthor(sender == null ? Console.getInstance().getDisplayName() : sender.getPlayer().getName());
}
if (!meta.hasTitle()) {
final String title = FormatUtil.replaceFormat(split[1].replace('_', ' '));
meta.setTitle(title.length() > 32 ? title.substring(0, 32) : title);
}
}
final List<String> pages = pager.getPages(split[1]);
meta.setPages(pages);
stack.setItemMeta(meta);
@ -230,7 +246,7 @@ public class MetaItemStack {
meta.setAuthor(author);
stack.setItemMeta(meta);
} else if (split.length > 1 && split[0].equalsIgnoreCase("title") && stack.getType() == WRITTEN_BOOK && hasMetaPermission(sender, "title", false, true, ess)) {
final String title = FormatUtil.replaceFormat(split[1].replace('_', ' '));
final String title = FormatUtil.replaceFormat(split[1].replaceAll("(?<!\\\\)_", " ").replace("\\_", "_"));
final BookMeta meta = (BookMeta) stack.getItemMeta();
meta.setTitle(title);
stack.setItemMeta(meta);
@ -240,7 +256,7 @@ public class MetaItemStack {
final List<String> pages = meta.hasPages() ? new ArrayList<>(meta.getPages()) : new ArrayList<>();
final List<String> lines = new ArrayList<>();
for (final String line : split[1].split("(?<!\\\\)\\|")) {
lines.add(FormatUtil.replaceFormat(line.replace('_', ' ').replace("\\|", "|")));
lines.add(FormatUtil.replaceFormat(line.replaceAll("(?<!\\\\)_", " ").replace("\\_", "_").replace("\\|", "|")));
}
final String content = String.join("\n", lines);
if (page >= pages.size()) {
@ -301,7 +317,7 @@ public class MetaItemStack {
meta.setColor(Color.fromRGB(red, green, blue));
stack.setItemMeta(meta);
} else {
throw new Exception(tl("leatherSyntax"));
throw new TranslatableException("leatherSyntax");
}
} else {
parseEnchantmentStrings(sender, allowUnsafe, split, ess);
@ -311,7 +327,7 @@ public class MetaItemStack {
public void addItemFlags(final String string) throws Exception {
final String[] separate = splitPattern.split(string, 2);
if (separate.length != 2) {
throw new Exception(tl("invalidItemFlagMeta", string));
throw new TranslatableException("invalidItemFlagMeta", string);
}
final String[] split = separate[1].split(",");
@ -326,7 +342,7 @@ public class MetaItemStack {
}
if (meta.getItemFlags().isEmpty()) {
throw new Exception(tl("invalidItemFlagMeta", string));
throw new TranslatableException("invalidItemFlagMeta", string);
}
stack.setItemMeta(meta);
@ -349,7 +365,7 @@ public class MetaItemStack {
validFireworkCharge = true;
primaryColors.add(Color.fromRGB(Integer.decode(color)));
} else {
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
throw new TranslatableException("invalidFireworkFormat", split[1], split[0]);
}
}
builder.withColor(primaryColors);
@ -359,7 +375,7 @@ public class MetaItemStack {
if (fireworkShape.containsKey(split[1].toUpperCase())) {
finalEffect = fireworkShape.get(split[1].toUpperCase());
} else {
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
throw new TranslatableException("invalidFireworkFormat", split[1], split[0]);
}
if (finalEffect != null) {
builder.with(finalEffect);
@ -373,7 +389,7 @@ public class MetaItemStack {
} else if (hexPattern.matcher(color).matches()) {
fadeColors.add(Color.fromRGB(Integer.decode(color)));
} else {
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
throw new TranslatableException("invalidFireworkFormat", split[1], split[0]);
}
}
if (!fadeColors.isEmpty()) {
@ -387,7 +403,7 @@ public class MetaItemStack {
} else if (effect.equalsIgnoreCase("trail")) {
builder.trail(true);
} else {
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
throw new TranslatableException("invalidFireworkFormat", split[1], split[0]);
}
}
}
@ -403,13 +419,13 @@ public class MetaItemStack {
if (split[0].equalsIgnoreCase("color") || split[0].equalsIgnoreCase("colour") || (allowShortName && split[0].equalsIgnoreCase("c"))) {
if (validFirework) {
if (!hasMetaPermission(sender, "firework", true, true, ess)) {
throw new Exception(tl("noMetaFirework"));
throw new TranslatableException("noMetaFirework");
}
final FireworkEffect effect = builder.build();
final FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
fmeta.addEffect(effect);
if (fmeta.getEffects().size() > 1 && !hasMetaPermission(sender, "firework-multiple", true, true, ess)) {
throw new Exception(tl("multipleCharges"));
throw new TranslatableException("multipleCharges");
}
stack.setItemMeta(fmeta);
builder = FireworkEffect.builder();
@ -425,7 +441,7 @@ public class MetaItemStack {
validFirework = true;
primaryColors.add(Color.fromRGB(Integer.decode(color)));
} else {
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
throw new TranslatableException("invalidFireworkFormat", split[1], split[0]);
}
}
builder.withColor(primaryColors);
@ -435,7 +451,7 @@ public class MetaItemStack {
if (fireworkShape.containsKey(split[1].toUpperCase())) {
finalEffect = fireworkShape.get(split[1].toUpperCase());
} else {
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
throw new TranslatableException("invalidFireworkFormat", split[1], split[0]);
}
if (finalEffect != null) {
builder.with(finalEffect);
@ -449,7 +465,7 @@ public class MetaItemStack {
} else if (hexPattern.matcher(color).matches()) {
fadeColors.add(Color.fromRGB(Integer.decode(color)));
} else {
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
throw new TranslatableException("invalidFireworkFormat", split[1], split[0]);
}
}
if (!fadeColors.isEmpty()) {
@ -463,7 +479,7 @@ public class MetaItemStack {
} else if (effect.equalsIgnoreCase("trail")) {
builder.trail(true);
} else {
throw new Exception(tl("invalidFireworkFormat", split[1], split[0]));
throw new TranslatableException("invalidFireworkFormat", split[1], split[0]);
}
}
}
@ -484,10 +500,10 @@ public class MetaItemStack {
if (hasMetaPermission(sender, "potions." + pEffectType.getName().toLowerCase(Locale.ENGLISH), true, false, ess)) {
validPotionEffect = true;
} else {
throw new Exception(tl("noPotionEffectPerm", pEffectType.getName().toLowerCase(Locale.ENGLISH)));
throw new TranslatableException("noPotionEffectPerm", pEffectType.getName().toLowerCase(Locale.ENGLISH));
}
} else {
throw new Exception(tl("invalidPotionMeta", split[1]));
throw new TranslatableException("invalidPotionMeta", split[1]);
}
} else if (split[0].equalsIgnoreCase("power") || (allowShortName && split[0].equalsIgnoreCase("p"))) {
if (NumberUtil.isInt(split[1])) {
@ -497,21 +513,21 @@ public class MetaItemStack {
power -= 1;
}
} else {
throw new Exception(tl("invalidPotionMeta", split[1]));
throw new TranslatableException("invalidPotionMeta", split[1]);
}
} else if (split[0].equalsIgnoreCase("amplifier") || (allowShortName && split[0].equalsIgnoreCase("a"))) {
if (NumberUtil.isInt(split[1])) {
validPotionPower = true;
power = Integer.parseInt(split[1]);
} else {
throw new Exception(tl("invalidPotionMeta", split[1]));
throw new TranslatableException("invalidPotionMeta", split[1]);
}
} else if (split[0].equalsIgnoreCase("duration") || (allowShortName && split[0].equalsIgnoreCase("d"))) {
if (NumberUtil.isInt(split[1])) {
validPotionDuration = true;
duration = Integer.parseInt(split[1]) * 20; //Duration is in ticks by default, converted to seconds
} else {
throw new Exception(tl("invalidPotionMeta", split[1]));
throw new TranslatableException("invalidPotionMeta", split[1]);
}
} else if (split[0].equalsIgnoreCase("splash") || (allowShortName && split[0].equalsIgnoreCase("s"))) {
isSplashPotion = Boolean.parseBoolean(split[1]);
@ -521,14 +537,14 @@ public class MetaItemStack {
final PotionMeta pmeta = (PotionMeta) stack.getItemMeta();
pEffect = pEffectType.createEffect(duration, power);
if (pmeta.getCustomEffects().size() > 1 && !hasMetaPermission(sender, "potions.multiple", true, false, ess)) {
throw new Exception(tl("multiplePotionEffects"));
throw new TranslatableException("multiplePotionEffects");
}
pmeta.addCustomEffect(pEffect, true);
stack.setItemMeta(pmeta);
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_9_R01)) {
if (isSplashPotion && stack.getType() != Material.SPLASH_POTION) {
if (isSplashPotion && stack.getType() == Material.POTION) {
stack.setType(Material.SPLASH_POTION);
} else if (!isSplashPotion && stack.getType() != Material.POTION) {
} else if (!isSplashPotion && stack.getType() == Material.SPLASH_POTION) {
stack.setType(Material.POTION);
}
} else {
@ -566,7 +582,7 @@ public class MetaItemStack {
public void addEnchantment(final CommandSource sender, final boolean allowUnsafe, final Enchantment enchantment, final int level) throws Exception {
if (enchantment == null) {
throw new Exception(tl("enchantmentNotFound"));
throw new TranslatableException("enchantmentNotFound");
}
try {
if (stack.getType().equals(Material.ENCHANTED_BOOK)) {
@ -602,7 +618,7 @@ public class MetaItemStack {
final String enchantmentName = enchantment.getName().toLowerCase(Locale.ENGLISH);
if (!hasMetaPermission(user, "enchantments." + enchantmentName, true, false)) {
throw new Exception(tl("enchantmentPerm", enchantmentName));
throw new TranslatableException("enchantmentPerm", enchantmentName);
}
return enchantment;
}
@ -612,12 +628,12 @@ public class MetaItemStack {
final String[] split = splitPattern.split(string, 2);
if (split.length < 2) {
throw new Exception(tl("invalidBanner", split[1]));
throw new TranslatableException("invalidBanner", split[1]);
}
PatternType patternType = null;
try {
patternType = PatternType.valueOf(split[0]);
patternType = PatternType.getByIdentifier(split[0]);
} catch (final Exception ignored) {
}
@ -626,7 +642,7 @@ public class MetaItemStack {
final Color color = Color.fromRGB(Integer.parseInt(split[1]));
meta.setBaseColor(DyeColor.getByColor(color));
} else if (patternType != null) {
final PatternType type = PatternType.valueOf(split[0]);
final PatternType type = PatternType.getByIdentifier(split[0]);
final DyeColor color = DyeColor.getByColor(Color.fromRGB(Integer.parseInt(split[1])));
final org.bukkit.block.banner.Pattern pattern = new org.bukkit.block.banner.Pattern(color, type);
meta.addPattern(pattern);
@ -637,12 +653,12 @@ public class MetaItemStack {
final String[] split = splitPattern.split(string, 2);
if (split.length < 2) {
throw new Exception(tl("invalidBanner", split[1]));
throw new TranslatableException("invalidBanner", split[1]);
}
PatternType patternType = null;
try {
patternType = PatternType.valueOf(split[0]);
patternType = PatternType.getByIdentifier(split[0]);
} catch (final Exception ignored) {
}
@ -653,7 +669,7 @@ public class MetaItemStack {
final Color color = Color.fromRGB(Integer.parseInt(split[1]));
banner.setBaseColor(DyeColor.getByColor(color));
} else if (patternType != null) {
final PatternType type = PatternType.valueOf(split[0]);
final PatternType type = PatternType.getByIdentifier(split[0]);
final DyeColor color = DyeColor.getByColor(Color.fromRGB(Integer.parseInt(split[1])));
final org.bukkit.block.banner.Pattern pattern = new org.bukkit.block.banner.Pattern(color, type);
banner.addPattern(pattern);
@ -678,7 +694,7 @@ public class MetaItemStack {
if (graceful) {
return false;
} else {
throw new Exception(tl("noMetaPerm", metaPerm));
throw new TranslatableException("noMetaPerm", metaPerm);
}
}

View File

@ -1,5 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.EnumUtil;
import org.bukkit.Location;
import org.bukkit.Server;
@ -13,9 +14,8 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
// Suffixes can be appended on the end of a mob name to make it plural
// Entities without a suffix, will default to 's'
@ -105,9 +105,15 @@ public enum Mob {
AXOLOTL("Axolotl", Enemies.FRIENDLY, "AXOLOTL"),
GOAT("Goat", Enemies.NEUTRAL, "GOAT"),
GLOW_SQUID("GlowSquid", Enemies.FRIENDLY, "GLOW_SQUID"),
ALLAY("Allay", Enemies.FRIENDLY, "ALLAY"),
FROG("Frog", Enemies.FRIENDLY, "FROG"),
TADPOLE("Tadpole", Enemies.FRIENDLY, "TADPOLE"),
WARDEN("Warden", Enemies.ENEMY, "WARDEN"),
CHEST_BOAT("ChestBoat", Enemies.NEUTRAL, "CHEST_BOAT"),
CAMEL("Camel", Enemies.FRIENDLY, "CAMEL"),
SNIFFER("Sniffer", Enemies.FRIENDLY, "SNIFFER"),
;
public static final Logger logger = Logger.getLogger("Essentials");
private static final Map<String, Mob> hashMap = new HashMap<>();
private static final Map<EntityType, Mob> bukkitMap = new HashMap<>();
@ -166,7 +172,7 @@ public enum Mob {
public Entity spawn(final World world, final Server server, final Location loc) throws MobException {
final Entity entity = world.spawn(loc, this.bukkitType.getEntityClass());
if (entity == null) {
logger.log(Level.WARNING, tl("unableToSpawnMob"));
Essentials.getWrappedLogger().log(Level.WARNING, AdventureUtil.miniToLegacy(tlLiteral("unableToSpawnMob")));
throw new MobException();
}
return entity;

View File

@ -3,17 +3,24 @@ package com.earth2me.essentials;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.nms.refl.ReflUtil;
import org.bukkit.Material;
import org.bukkit.TreeSpecies;
import org.bukkit.entity.Axolotl;
import org.bukkit.entity.Boat;
import org.bukkit.entity.Camel;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Fox;
import org.bukkit.entity.Frog;
import org.bukkit.entity.Llama;
import org.bukkit.entity.MushroomCow;
import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Panda;
import org.bukkit.entity.Parrot;
import org.bukkit.entity.Player;
import org.bukkit.entity.TropicalFish;
import org.bukkit.entity.Villager;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.Method;
@ -37,6 +44,8 @@ public final class MobCompat {
public static final EntityType PHANTOM = getEntityType("PHANTOM");
public static final EntityType AXOLOTL = getEntityType("AXOLOTL");
public static final EntityType GOAT = getEntityType("GOAT");
public static final EntityType FROG = getEntityType("FROG");
public static final EntityType CAMEL = getEntityType("CAMEL");
// Constants for mobs that have changed since earlier versions
public static final EntityType CAT = getEntityType("CAT", "OCELOT");
@ -164,6 +173,46 @@ public final class MobCompat {
}
}
public static void setFrogVariant(final Entity entity, final String variant) {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_19_R01)) {
return;
}
if (entity instanceof Frog) {
((Frog) entity).setVariant(Frog.Variant.valueOf(variant));
}
}
public static void setBoatVariant(final Entity entity, final BoatVariant variant) {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_9_R01)) {
return;
}
final Boat boat;
if (entity instanceof Boat) {
boat = (Boat) entity;
} else {
return;
}
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_19_R01)) {
//noinspection deprecation
boat.setWoodType(TreeSpecies.valueOf(variant.getTreeSpecies()));
} else {
boat.setBoatType(Boat.Type.valueOf(variant.getBoatType()));
}
}
public static void setCamelSaddle(final Entity entity, final Player target) {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_20_1_R01)) {
return;
}
if (entity instanceof Camel) {
final Camel camel = (Camel) entity;
camel.setTamed(true);
camel.setOwner(target);
camel.getInventory().setSaddle(new ItemStack(Material.SADDLE, 1));
}
}
public enum CatType {
// These are (loosely) Mojang names for the cats
SIAMESE("SIAMESE", "SIAMESE_CAT"),
@ -228,4 +277,34 @@ public final class MobCompat {
}
}
public enum BoatVariant {
// Mappings for TreeSpecies names
ACACIA("ACACIA", "ACACIA"),
BIRCH("BIRCH", "BIRCH"),
DARKOAK("DARK_OAK", "DARK_OAK"),
GENERIC("GENERIC", "OAK"),
JUNGLE("JUNGLE", "JUNGLE"),
REDWOOD("REDWOOD", "SPRUCE"),
// Mappings for Boat.Type names (falling back to GENERIC where undefined)
OAK("GENERIC", "OAK"),
SPRUCE("REDWOOD", "SPRUCE"),
MANGROVE("GENERIC", "MANGROVE"),
;
private final String treeSpecies;
private final String boatType;
BoatVariant(final String treeSpecies, final String boatType) {
this.treeSpecies = treeSpecies;
this.boatType = boatType;
}
public String getTreeSpecies() {
return treeSpecies;
}
public String getBoatType() {
return boatType;
}
}
}

View File

@ -1,12 +1,14 @@
package com.earth2me.essentials;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.api.TranslatableException;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.entity.Ageable;
import org.bukkit.entity.Boat;
import org.bukkit.entity.ChestedHorse;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Entity;
@ -35,11 +37,8 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import static com.earth2me.essentials.I18n.tl;
public enum MobData {
BABY_AGEABLE("baby", Ageable.class, Data.BABY, true),
@ -197,9 +196,21 @@ public enum MobData {
CYAN_AXOLOTL("cyan", MobCompat.AXOLOTL, "axolotl:CYAN", true),
BLUE_AXOLOTL("blue", MobCompat.AXOLOTL, "axolotl:BLUE", true),
SCREAMING_GOAT("screaming", MobCompat.GOAT, Data.GOAT_SCREAMING, true),
TEMPERATE_FROG("temperate", MobCompat.FROG, "frog:TEMPERATE", true),
WARM_FROG("warm", MobCompat.FROG, "frog:WARM", true),
COLD_FROG("cold", MobCompat.FROG, "frog:COLD", true),
ACACIA_BOAT("acacia", Boat.class, MobCompat.BoatVariant.ACACIA, true),
BIRCH_BOAT("birch", Boat.class, MobCompat.BoatVariant.BIRCH, true),
DARK_OAK_BOAT("darkoak", Boat.class, MobCompat.BoatVariant.DARKOAK, true),
GENERIC_BOAT("generic", Boat.class, MobCompat.BoatVariant.GENERIC, true),
JUNGLE_BOAT("jungle", Boat.class, MobCompat.BoatVariant.JUNGLE, true),
REDWOOD_BOAT("redwood", Boat.class, MobCompat.BoatVariant.REDWOOD, true),
MANGROVE_BOAT("mangrove", Boat.class, MobCompat.BoatVariant.MANGROVE, true),
OAK_BOAT("oak", Boat.class, MobCompat.BoatVariant.OAK, true),
SPRUCE_BOAT("spruce", Boat.class, MobCompat.BoatVariant.SPRUCE, true),
SADDLE_CAMEL("saddle", MobCompat.CAMEL, Data.CAMELSADDLE, true),
;
public static final Logger logger = Logger.getLogger("Essentials");
final private String nickname;
final private List<String> suggestions;
final private Object type;
@ -316,14 +327,14 @@ public enum MobData {
}
this.matched = rawData;
} catch (final Exception e) {
throw new Exception(tl("sheepMalformedColor"), e);
throw new TranslatableException(e, "sheepMalformedColor");
}
} else if (this.value.equals(Data.EXP)) {
try {
((ExperienceOrb) spawned).setExperience(Integer.parseInt(rawData));
this.matched = rawData;
} catch (final NumberFormatException e) {
throw new Exception(tl("invalidNumber"), e);
throw new TranslatableException(e, "invalidNumber");
}
} else if (this.value.equals(Data.SIZE)) {
try {
@ -335,7 +346,7 @@ public enum MobData {
}
this.matched = rawData;
} catch (final NumberFormatException e) {
throw new Exception(tl("slimeMalformedSize"), e);
throw new TranslatableException(e, "slimeMalformedSize");
}
} else if (this.value instanceof Horse.Color) {
((Horse) spawned).setColor((Horse.Color) this.value);
@ -351,8 +362,8 @@ public enum MobData {
((Horse) spawned).getInventory().setArmor(new ItemStack((Material) this.value, 1));
} else if (this.type.equals(EntityType.ZOMBIE.getEntityClass()) || this.type.equals(EntityType.SKELETON)) {
final EntityEquipment invent = ((LivingEntity) spawned).getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack((Material) this.value, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
Inventories.setItemInMainHand(invent, new ItemStack((Material) this.value, 1));
Inventories.setItemInMainHandDropChance(invent, 0.1f);
}
} else if (this.value.equals(Data.RAID_LEADER)) {
((Raider) spawned).setPatrolLeader(true);
@ -376,6 +387,10 @@ public enum MobData {
}
} else if (this.value.equals(Data.GOAT_SCREAMING)) {
((Goat) spawned).setScreaming(true);
} else if (this.value.equals(Data.CAMELSADDLE)) {
MobCompat.setCamelSaddle(spawned, target);
} else if (this.value instanceof MobCompat.BoatVariant) {
MobCompat.setBoatVariant(spawned, (MobCompat.BoatVariant) this.value);
} else if (this.value instanceof String) {
final String[] split = ((String) this.value).split(":");
switch (split[0]) {
@ -403,13 +418,15 @@ public enum MobData {
case "fox":
MobCompat.setFoxType(spawned, split[1]);
break;
case "axolotl": {
case "axolotl":
MobCompat.setAxolotlVariant(spawned, split[1]);
break;
}
case "frog":
MobCompat.setFrogVariant(spawned, split[1]);
break;
}
} else {
logger.warning("Unknown mob data type: " + this.toString());
Essentials.getWrappedLogger().warning("Unknown mob data type: " + this.toString());
}
}
@ -431,5 +448,6 @@ public enum MobData {
FISH_BODY_COLOR,
FISH_PATTERN_COLOR,
GOAT_SCREAMING,
CAMELSADDLE,
}
}

View File

@ -1,6 +1,7 @@
package com.earth2me.essentials;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Player;
@ -31,4 +32,11 @@ public class PlayerExtension {
public Location getLocation() {
return base.getLocation();
}
public OfflinePlayer getOffline() {
if (base instanceof OfflinePlayerStub) {
return ((OfflinePlayerStub) base).base;
}
return base;
}
}

View File

@ -1,8 +1,9 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.NumberUtil;
import org.bukkit.ChatColor;
import net.ess3.api.TranslatableException;
import org.bukkit.Server;
import java.util.ArrayList;
@ -14,7 +15,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public final class PlayerList {
@ -32,19 +33,19 @@ public final class PlayerList {
}
needComma = true;
if (user.isAfk()) {
groupString.append(tl("listAfkTag"));
groupString.append(tlLiteral("listAfkTag"));
}
if (user.isHidden()) {
groupString.append(tl("listHiddenTag"));
groupString.append(tlLiteral("listHiddenTag"));
}
user.setDisplayNick();
groupString.append(user.getDisplayName());
groupString.append(AdventureUtil.legacyToMini(user.getDisplayName()));
final String strippedNick = FormatUtil.stripFormat(user.getNickname());
if (ess.getSettings().realNamesOnList() && strippedNick != null && !strippedNick.equals(user.getName())) {
groupString.append(" ").append(tl("listRealName",user.getName()));
groupString.append(" ").append(tlLiteral("listRealName",user.getName()));
}
groupString.append(ChatColor.WHITE.toString());
groupString.append("<white>");
}
return groupString.toString();
}
@ -55,27 +56,31 @@ public final class PlayerList {
int playerHidden = 0;
int hiddenCount = 0;
for (final User onlinePlayer : ess.getOnlineUsers()) {
if (onlinePlayer.isHidden() || (user != null && !user.getBase().canSee(onlinePlayer.getBase()))) {
if (onlinePlayer.isHidden() || (user != null && onlinePlayer.isHiddenFrom(user.getBase()))) {
playerHidden++;
if (showHidden || user != null && user.getBase().canSee(onlinePlayer.getBase())) {
if (showHidden || user != null && !onlinePlayer.isHiddenFrom(user.getBase())) {
hiddenCount++;
}
}
}
final String online;
final String tlKey;
final Object[] objects;
if (hiddenCount > 0) {
online = tl("listAmountHidden", ess.getOnlinePlayers().size() - playerHidden, hiddenCount, server.getMaxPlayers());
tlKey = "listAmountHidden";
objects = new Object[]{ess.getOnlinePlayers().size() - playerHidden, hiddenCount, server.getMaxPlayers()};
} else {
online = tl("listAmount", ess.getOnlinePlayers().size() - playerHidden, server.getMaxPlayers());
tlKey = "listAmount";
objects = new Object[]{ess.getOnlinePlayers().size() - playerHidden, server.getMaxPlayers()};
}
return online;
return user == null ? tlLiteral(tlKey, objects) : user.playerTl(tlKey, objects);
}
// Build the basic player list, divided by groups.
public static Map<String, List<User>> getPlayerLists(final IEssentials ess, final IUser sender, final boolean showHidden) {
final Map<String, List<User>> playerList = new HashMap<>();
for (final User onlineUser : ess.getOnlineUsers()) {
if ((sender == null && !showHidden && onlineUser.isHidden()) || (sender != null && !showHidden && !sender.getBase().canSee(onlineUser.getBase()))) {
if ((sender == null && !showHidden && onlineUser.isHidden()) || (sender != null && !showHidden && onlineUser.isHiddenFrom(sender.getBase()))) {
continue;
}
final String group = FormatUtil.stripFormat(FormatUtil.stripEssentialsFormat(onlineUser.getGroup().toLowerCase()));
@ -117,7 +122,7 @@ public final class PlayerList {
users.addAll(groupUsers);
}
if (users.isEmpty()) {
throw new Exception(tl("groupDoesNotExist"));
throw new TranslatableException("groupDoesNotExist");
}
final String displayGroupName = Character.toTitleCase(groupName.charAt(0)) +
groupName.substring(1);
@ -126,11 +131,11 @@ public final class PlayerList {
// Build the output string
public static String outputFormat(final String group, final String message) {
return tl("listGroupTag", FormatUtil.replaceFormat(group)) +
return tlLiteral("listGroupTag", FormatUtil.replaceFormat(group)) +
message;
}
public static List<String> prepareGroupedList(final IEssentials ess, final String commandLabel, final Map<String, List<User>> playerList) {
public static List<String> prepareGroupedList(final IEssentials ess, final CommandSource source, final String commandLabel, final Map<String, List<User>> playerList) {
final List<String> output = new ArrayList<>();
final Set<String> configGroups = ess.getSettings().getListGroupConfig().keySet();
@ -163,7 +168,9 @@ public final class PlayerList {
outputUserList = new ArrayList<>(matchedList);
final int limit = Integer.parseInt(groupValue);
if (matchedList.size() > limit) {
output.add(outputFormat(oConfigGroup, tl("groupNumber", matchedList.size(), commandLabel, FormatUtil.stripFormat(configGroup))));
final String tlKey = "groupNumber";
final Object[] objects = {matchedList.size(), commandLabel, FormatUtil.stripFormat(configGroup)};
output.add(outputFormat(oConfigGroup, source == null ? tlLiteral(tlKey, objects) : source.tl(tlKey, objects)));
} else {
output.add(outputFormat(oConfigGroup, listUsers(ess, outputUserList, ", ")));
}
@ -203,7 +210,7 @@ public final class PlayerList {
String groupName = asterisk.isEmpty() ? users.get(0).getGroup() : onlineGroup;
if (ess.getPermissionsHandler().getName().equals("ConfigPermissions")) {
groupName = tl("connectedPlayers");
groupName = source == null ? tlLiteral("connectedPlayers") : source.tl("connectedPlayers");
}
if (users == null || users.isEmpty()) {
continue;

View File

@ -4,15 +4,17 @@ import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import java.util.UUID;
public class PlayerTarget implements ITarget {
private final String name;
private final UUID uuid;
public PlayerTarget(final Player entity) {
this.name = entity.getName();
this.uuid = entity.getUniqueId();
}
@Override
public Location getLocation() {
return Bukkit.getServer().getPlayerExact(name).getLocation();
return Bukkit.getPlayer(uuid).getLocation();
}
}

View File

@ -6,13 +6,12 @@ import com.earth2me.essentials.utils.LocationUtil;
import com.earth2me.essentials.utils.VersionUtil;
import io.papermc.lib.PaperLib;
import net.ess3.api.InvalidWorldException;
import net.ess3.provider.BiomeKeyProvider;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Biome;
import java.io.File;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import java.util.Set;
@ -76,14 +75,10 @@ public class RandomTeleport implements IConf {
config.save();
}
public Set<Biome> getExcludedBiomes() {
final List<String> biomeNames = config.getList("excluded-biomes", String.class);
final Set<Biome> excludedBiomes = new HashSet<>();
for (final String biomeName : biomeNames) {
try {
excludedBiomes.add(Biome.valueOf(biomeName.toUpperCase()));
} catch (final IllegalArgumentException ignored) {
}
public Set<String> getExcludedBiomes() {
final Set<String> excludedBiomes = new HashSet<>();
for (final String key : config.getList("excluded-biomes", String.class)) {
excludedBiomes.add(key.toLowerCase());
}
return excludedBiomes;
}
@ -204,6 +199,34 @@ public class RandomTeleport implements IConf {
}
private boolean isValidRandomLocation(final Location location) {
return location.getBlockY() > ess.getWorldInfoProvider().getMinHeight(location.getWorld()) && !this.getExcludedBiomes().contains(location.getBlock().getBiome());
return location.getBlockY() > ess.getWorldInfoProvider().getMinHeight(location.getWorld()) && !isExcludedBiome(location);
}
// Exclude biome if enum or namespaced key matches
private boolean isExcludedBiome(final Location location) {
final Set<String> excluded = getExcludedBiomes();
final String enumKey = location.getBlock().getBiome().name().toLowerCase();
// Try with good old bukkit enum
if (excluded.contains(enumKey)) {
return true;
}
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_4_R01)) {
// No way to get the biome key on versions below this
return false;
}
final String biomeKey;
final BiomeKeyProvider biomeKeyProvider = ess.getBiomeKeyProvider();
if (biomeKeyProvider != null) {
// Works with custom biome keys
biomeKey = biomeKeyProvider.getBiomeKey(location.getBlock()).toString();
} else {
// Custom biome keys resolve as "minecraft:custom" which is unfortunate
biomeKey = location.getBlock().getBiome().getKey().toString();
}
return excluded.contains(biomeKey);
}
public File getFile() {
return config.getFile();
}
}

View File

@ -8,12 +8,17 @@ import com.earth2me.essentials.signs.EssentialsSign;
import com.earth2me.essentials.signs.Signs;
import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.LocationUtil;
import com.earth2me.essentials.utils.NumberUtil;
import net.ess3.api.IEssentials;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.minimessage.tag.Tag;
import org.bukkit.ChatColor;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.event.EventPriority;
@ -40,16 +45,16 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public class Settings implements net.ess3.api.ISettings {
private static final Logger logger = Logger.getLogger("Essentials");
private static final BigDecimal DEFAULT_MAX_MONEY = new BigDecimal("10000000000000");
private static final BigDecimal DEFAULT_MIN_MONEY = new BigDecimal("-10000000000000");
private static final Tag DEFAULT_PRIMARY_COLOR = Tag.styling(NamedTextColor.GOLD);
private static final Tag DEFAULT_SECONDARY_COLOR = Tag.styling(NamedTextColor.RED);
private final transient EssentialsConfiguration config;
private final transient IEssentials ess;
private final transient AtomicInteger reloadCount = new AtomicInteger(0);
@ -138,6 +143,8 @@ public class Settings implements net.ess3.api.ISettings {
private double maxProjectileSpeed;
private boolean removeEffectsOnHeal;
private Map<String, String> worldAliases;
private Tag primaryColor = DEFAULT_PRIMARY_COLOR;
private Tag secondaryColor = DEFAULT_SECONDARY_COLOR;
public Settings(final IEssentials ess) {
this.ess = ess;
@ -226,6 +233,21 @@ public class Settings implements net.ess3.api.ISettings {
return chatQuestion;
}
@Override
public boolean isShoutDefault() {
return config.getBoolean("chat.shout-default", false);
}
@Override
public boolean isPersistShout() {
return config.getBoolean("chat.persist-shout", false);
}
@Override
public boolean isChatQuestionEnabled() {
return config.getBoolean("chat.question-enabled", true);
}
public boolean _isTeleportSafetyEnabled() {
return config.getBoolean("teleport-safety", true);
}
@ -434,6 +456,11 @@ public class Settings implements net.ess3.api.ISettings {
return config.getBoolean("socialspy-messages", true);
}
@Override
public boolean isSocialSpyDisplayNames() {
return config.getBoolean("socialspy-uses-displaynames", true);
}
private Set<String> _getMuteCommands() {
final Set<String> muteCommands = new HashSet<>();
if (config.isList("mute-commands")) {
@ -671,7 +698,7 @@ public class Settings implements net.ess3.api.ISettings {
boolean mapModified = false;
if (!disabledBukkitCommands.isEmpty()) {
if (isDebug()) {
logger.log(Level.INFO, "Re-adding " + disabledBukkitCommands.size() + " disabled commands!");
ess.getLogger().log(Level.INFO, "Re-adding " + disabledBukkitCommands.size() + " disabled commands!");
}
ess.getKnownCommandsProvider().getKnownCommands().putAll(disabledBukkitCommands);
disabledBukkitCommands.clear();
@ -683,12 +710,12 @@ public class Settings implements net.ess3.api.ISettings {
final Command toDisable = ess.getPluginCommand(effectiveAlias);
if (toDisable != null) {
if (isDebug()) {
logger.log(Level.INFO, "Attempting removal of " + effectiveAlias);
ess.getLogger().log(Level.INFO, "Attempting removal of " + effectiveAlias);
}
final Command removed = ess.getKnownCommandsProvider().getKnownCommands().remove(effectiveAlias);
if (removed != null) {
if (isDebug()) {
logger.log(Level.INFO, "Adding command " + effectiveAlias + " to disabled map!");
ess.getLogger().log(Level.INFO, "Adding command " + effectiveAlias + " to disabled map!");
}
disabledBukkitCommands.put(effectiveAlias, removed);
}
@ -705,7 +732,7 @@ public class Settings implements net.ess3.api.ISettings {
if (mapModified) {
if (isDebug()) {
logger.log(Level.INFO, "Syncing commands");
ess.getLogger().log(Level.INFO, "Syncing commands");
}
if (reloadCount.get() < 2) {
ess.scheduleSyncDelayedTask(() -> ess.getSyncCommandsProvider().syncCommands());
@ -766,6 +793,8 @@ public class Settings implements net.ess3.api.ISettings {
bindingItemPolicy = _getBindingItemsPolicy();
currencySymbol = _getCurrencySymbol();
worldAliases = _getWorldAliases();
primaryColor = _getPrimaryColor();
secondaryColor = _getSecondaryColor();
reloadCount.incrementAndGet();
}
@ -784,7 +813,7 @@ public class Settings implements net.ess3.api.ISettings {
//noinspection deprecation
final IItemDb itemDb = ess.getItemDb();
if (itemDb == null || !itemDb.isReady()) {
logger.log(Level.FINE, "Skipping item spawn blacklist read; item DB not yet loaded.");
ess.getLogger().log(Level.FINE, "Skipping item spawn blacklist read; item DB not yet loaded.");
return epItemSpwn;
}
for (String itemName : config.getString("item-spawn-blacklist", "").split(",")) {
@ -796,7 +825,7 @@ public class Settings implements net.ess3.api.ISettings {
final ItemStack iStack = itemDb.get(itemName);
epItemSpwn.add(iStack.getType());
} catch (final Exception ex) {
logger.log(Level.SEVERE, tl("unknownItemInList", itemName, "item-spawn-blacklist"), ex);
ess.getLogger().log(Level.SEVERE, AdventureUtil.miniToLegacy(tlLiteral("unknownItemInList", itemName, "item-spawn-blacklist")), ex);
}
}
return epItemSpwn;
@ -824,7 +853,7 @@ public class Settings implements net.ess3.api.ISettings {
try {
newSigns.add(Signs.valueOf(signName).getSign());
} catch (final Exception ex) {
logger.log(Level.SEVERE, tl("unknownItemInList", signName, "enabledSigns"));
ess.getLogger().log(Level.SEVERE, AdventureUtil.miniToLegacy(tlLiteral("unknownItemInList", signName, "enabledSigns")));
continue;
}
signsEnabled = true;
@ -870,6 +899,11 @@ public class Settings implements net.ess3.api.ISettings {
return config.getString("locale", "");
}
@Override
public boolean isPerPlayerLocale() {
return config.getBoolean("per-player-locale", false);
}
private String currencySymbol = "$";
// A valid currency symbol value must be one non-integer character.
@ -938,7 +972,7 @@ public class Settings implements net.ess3.api.ISettings {
}
if (mat == null) {
logger.log(Level.SEVERE, tl("unknownItemInList", itemName, configName));
ess.getLogger().log(Level.SEVERE, AdventureUtil.miniToLegacy(tlLiteral("unknownItemInList", itemName, configName)));
} else {
list.add(mat);
}
@ -1212,6 +1246,11 @@ public class Settings implements net.ess3.api.ISettings {
return registerBackInListener;
}
@Override
public int getMaxTreeCommandRange() {
return config.getInt("tree-command-range-limit", 300);
}
private boolean _registerBackInListener() {
return config.getBoolean("register-back-in-listener", false);
}
@ -1451,10 +1490,16 @@ public class Settings implements net.ess3.api.ISettings {
// #easteregg
@Override
public int getMaxUserCacheCount() {
final long count = Runtime.getRuntime().maxMemory() / 1024 / 96;
final long count = Runtime.getRuntime().maxMemory() / 1024 / 1024;
return config.getInt("max-user-cache-count", (int) count);
}
// #easteregg
@Override
public long getMaxUserCacheValueExpiry() {
return config.getLong("max-user-cache-value-expiry", 600);
}
@Override
public boolean isLastMessageReplyRecipient() {
return config.getBoolean("last-message-reply-recipient", false);
@ -1675,7 +1720,7 @@ public class Settings implements net.ess3.api.ISettings {
try {
newSigns.add(Signs.valueOf(signName).getSign());
} catch (final Exception ex) {
logger.log(Level.SEVERE, tl("unknownItemInList", signName, "unprotected-sign-names"));
ess.getLogger().log(Level.SEVERE, AdventureUtil.miniToLegacy(tlLiteral("unknownItemInList", signName, "unprotected-sign-names")));
}
}
return newSigns;
@ -1860,7 +1905,7 @@ public class Settings implements net.ess3.api.ISettings {
try {
blacklist.add(Pattern.compile(entry).asPredicate());
} catch (final PatternSyntaxException e) {
logger.warning("Invalid nickname blacklist regex: " + entry);
ess.getLogger().warning("Invalid nickname blacklist regex: " + entry);
}
});
@ -1919,4 +1964,47 @@ public class Settings implements net.ess3.api.ISettings {
public boolean showZeroBaltop() {
return config.getBoolean("show-zero-baltop", true);
}
@Override
public int getMaxItemLore() {
return config.getInt("max-itemlore-lines", 10);
}
@Override
public Tag getPrimaryColor() {
return primaryColor;
}
private Tag _getPrimaryColor() {
final String color = config.getString("message-colors.primary", "#ffaa00");
final TextColor textColor = _getTagColor(color);
return textColor != null ? Tag.styling(textColor) : DEFAULT_PRIMARY_COLOR;
}
@Override
public Tag getSecondaryColor() {
return secondaryColor;
}
private Tag _getSecondaryColor() {
final String color = config.getString("message-colors.secondary", "#ff5555");
final TextColor textColor = _getTagColor(color);
return textColor != null ? Tag.styling(textColor) : DEFAULT_SECONDARY_COLOR;
}
private TextColor _getTagColor(final String color) {
try {
if (color.startsWith("#") && color.length() == 7 && NumberUtil.isHexadecimal(color.substring(1))) {
return TextColor.color(Color.fromRGB(Integer.decode(color)).asRGB());
}
if (color.length() == 1) {
return AdventureUtil.fromChar(color.charAt(0));
}
return NamedTextColor.NAMES.value(color.toLowerCase(Locale.ENGLISH));
} catch (IllegalArgumentException ignored) {
}
return null;
}
}

View File

@ -1,12 +1,13 @@
package com.earth2me.essentials;
import com.earth2me.essentials.Mob.MobException;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.LocationUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.api.IEssentials;
import net.ess3.api.TranslatableException;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Server;
@ -27,8 +28,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Set;
import static com.earth2me.essentials.I18n.tl;
public final class SpawnMob {
private static final Material GOLDEN_HELMET = EnumUtil.getMaterial("GOLDEN_HELMET", "GOLD_HELMET");
@ -49,7 +48,7 @@ public final class SpawnMob {
}
}
if (availableList.isEmpty()) {
availableList.add(tl("none"));
availableList.add(user.playerTl("none"));
}
return StringUtil.joinList(availableList);
}
@ -91,7 +90,7 @@ public final class SpawnMob {
public static void spawnmob(final IEssentials ess, final Server server, final User user, final List<String> parts, final List<String> data, final int mobCount) throws Exception {
final Block block = LocationUtil.getTarget(user.getBase()).getBlock();
if (block == null) {
throw new Exception(tl("unableToSpawnMob"));
throw new TranslatableException("unableToSpawnMob");
}
spawnmob(ess, server, user.getSource(), user, block.getLocation(), parts, data, mobCount);
}
@ -122,7 +121,7 @@ public final class SpawnMob {
if (mobCount > effectiveLimit) {
mobCount = effectiveLimit;
sender.sendMessage(tl("mobSpawnLimit"));
sender.sendTl("mobSpawnLimit");
}
final Mob mob = Mob.fromName(parts.get(0)); // Get the first mob
@ -130,13 +129,13 @@ public final class SpawnMob {
for (int i = 0; i < mobCount; i++) {
spawnMob(ess, server, sender, target, sloc, parts, data);
}
sender.sendMessage(mobCount * parts.size() + " " + mob.name.toLowerCase(Locale.ENGLISH) + mob.suffix + " " + tl("spawned"));
sender.sendMessage(mobCount * parts.size() + " " + mob.name.toLowerCase(Locale.ENGLISH) + mob.suffix + " " + sender.tl("spawned"));
} catch (final MobException e1) {
throw new Exception(tl("unableToSpawnMob"), e1);
throw new TranslatableException(e1, "unableToSpawnMob");
} catch (final NumberFormatException e2) {
throw new Exception(tl("numberRequired"), e2);
throw new TranslatableException(e2, "numberRequired");
} catch (final NullPointerException np) {
throw new Exception(tl("soloMob"), np);
throw new TranslatableException(np, "soloMob");
}
}
@ -176,15 +175,15 @@ public final class SpawnMob {
private static void checkSpawnable(final IEssentials ess, final CommandSource sender, final Mob mob) throws Exception {
if (mob == null || mob.getType() == null) {
throw new Exception(tl("invalidMob"));
throw new TranslatableException("invalidMob");
}
if (ess.getSettings().getProtectPreventSpawn(mob.getType().toString().toLowerCase(Locale.ENGLISH))) {
throw new Exception(tl("disabledToSpawnMob"));
throw new TranslatableException("disabledToSpawnMob");
}
if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.spawnmob." + mob.name.toLowerCase(Locale.ENGLISH))) {
throw new Exception(tl("noPermToSpawnMob"));
throw new TranslatableException("noPermToSpawnMob");
}
}
@ -192,7 +191,7 @@ public final class SpawnMob {
String data = inputData;
if (data.isEmpty()) {
sender.sendMessage(tl("mobDataList", StringUtil.joinList(MobData.getValidHelp(spawned))));
sender.sendTl("mobDataList", StringUtil.joinList(MobData.getValidHelp(spawned)));
}
if (spawned instanceof Zombie) {
@ -251,8 +250,8 @@ public final class SpawnMob {
private static void defaultMobData(final EntityType type, final Entity spawned) {
if (type == EntityType.SKELETON) {
final EntityEquipment invent = ((LivingEntity) spawned).getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack(Material.BOW, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
Inventories.setItemInMainHand(invent, new ItemStack(Material.BOW, 1));
Inventories.setItemInMainHandDropChance(invent, 0.1f);
}
if (type == MobCompat.ZOMBIFIED_PIGLIN) {
@ -260,8 +259,8 @@ public final class SpawnMob {
setVillager(zombie, false);
final EntityEquipment invent = zombie.getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack(GOLDEN_SWORD, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
Inventories.setItemInMainHand(invent, new ItemStack(GOLDEN_SWORD, 1));
Inventories.setItemInMainHandDropChance(invent, 0.1f);
}
if (type == EntityType.ZOMBIE) {

View File

@ -1,51 +1,22 @@
package com.earth2me.essentials;
import net.ess3.api.IEssentials;
import org.bukkit.entity.LivingEntity;
import com.earth2me.essentials.commands.Commandnuke;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent;
public class TNTExplodeListener implements Listener, Runnable {
private final transient IEssentials ess;
private transient boolean enabled = false;
private transient int timer = -1;
public TNTExplodeListener(final IEssentials ess) {
super();
this.ess = ess;
}
public void enable() {
if (!enabled) {
enabled = true;
timer = ess.scheduleSyncDelayedTask(this, 200);
return;
}
if (timer != -1) {
ess.getScheduler().cancelTask(timer);
timer = ess.scheduleSyncDelayedTask(this, 200);
}
}
public class TNTExplodeListener implements Listener {
@EventHandler(priority = EventPriority.LOW)
public void onEntityExplode(final EntityExplodeEvent event) {
if (!enabled) {
if (!(event.getEntity() instanceof TNTPrimed)) {
return;
}
if (event.getEntity() instanceof LivingEntity) {
return;
}
if (event.blockList().size() < 1) {
if (!event.getEntity().hasMetadata(Commandnuke.NUKE_META_KEY)) {
return;
}
event.setCancelled(true);
event.getLocation().getWorld().createExplosion(event.getLocation(), 0F);
}
@Override
public void run() {
enabled = false;
}
}

View File

@ -6,6 +6,7 @@ import io.papermc.lib.PaperLib;
import net.ess3.api.IEssentials;
import net.ess3.api.ITeleport;
import net.ess3.api.IUser;
import net.ess3.api.TranslatableException;
import net.ess3.api.events.UserWarpEvent;
import net.ess3.api.events.teleport.PreTeleportEvent;
import net.ess3.api.events.teleport.TeleportWarmupEvent;
@ -19,8 +20,6 @@ import java.math.BigDecimal;
import java.util.Calendar;
import java.util.GregorianCalendar;
import static com.earth2me.essentials.I18n.tl;
/**
* @deprecated This API is not asynchronous. Use {@link com.earth2me.essentials.AsyncTeleport AsyncTeleport}
*/
@ -64,7 +63,7 @@ public class Teleport implements ITeleport {
time.setTimeInMillis(lastTime);
time.add(Calendar.SECOND, (int) cooldown);
time.add(Calendar.MILLISECOND, (int) ((cooldown * 1000.0) % 1000.0));
throw new Exception(tl("timeBeforeTeleport", DateUtil.formatDateDiff(time.getTimeInMillis())));
throw new TranslatableException("timeBeforeTeleport", DateUtil.formatDateDiff(time.getTimeInMillis()));
}
}
// if justCheck is set, don't update lastTeleport; we're just checking
@ -98,7 +97,7 @@ public class Teleport implements ITeleport {
final Calendar c = new GregorianCalendar();
c.add(Calendar.SECOND, (int) delay);
c.add(Calendar.MILLISECOND, (int) ((delay * 1000.0) % 1000.0));
user.sendMessage(tl("dontMoveMessage", DateUtil.formatDateDiff(c.getTimeInMillis())));
user.sendTl("dontMoveMessage", DateUtil.formatDateDiff(c.getTimeInMillis()));
}
//The now function is used when you want to skip tp delay when teleporting someone to a location or player.
@ -120,7 +119,7 @@ public class Teleport implements ITeleport {
}
final ITarget target = new PlayerTarget(entity);
now(teleportOwner, target, cause);
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
teleportOwner.sendTl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ());
}
@Deprecated
@ -140,7 +139,7 @@ public class Teleport implements ITeleport {
if (!teleportee.getBase().isEmpty()) {
if (!ess.getSettings().isTeleportPassengerDismount()) {
throw new Exception(tl("passengerTeleportFail"));
throw new TranslatableException("passengerTeleportFail");
}
teleportee.getBase().eject();
}
@ -153,7 +152,7 @@ public class Teleport implements ITeleport {
PaperLib.teleportAsync(teleportee.getBase(), LocationUtil.getSafeDestination(ess, teleportee, loc), cause);
}
} else {
throw new Exception(tl("unsafeTeleportDestination", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
throw new TranslatableException("unsafeTeleportDestination", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
}
} else {
if (ess.getSettings().isForceDisableTeleportSafety()) {
@ -186,7 +185,7 @@ public class Teleport implements ITeleport {
@Deprecated
public void teleport(final Player entity, final Trade chargeFor, final TeleportCause cause) throws Exception {
final ITarget target = new PlayerTarget(entity);
teleportOwner.sendMessage(tl("teleportToPlayer", entity.getDisplayName()));
teleportOwner.sendTl("teleportToPlayer", entity.getDisplayName());
teleport(teleportOwner, target, chargeFor, cause);
}
@ -203,8 +202,8 @@ public class Teleport implements ITeleport {
public void teleportPlayer(final IUser teleportee, final Player entity, final Trade chargeFor, final TeleportCause cause) throws Exception {
final ITarget target = new PlayerTarget(entity);
teleport(teleportee, target, chargeFor, cause);
teleportee.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ()));
teleportee.sendTl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ());
teleportOwner.sendTl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ());
}
@Deprecated
@ -345,9 +344,9 @@ public class Teleport implements ITeleport {
warp = event.getWarp();
final Location loc = ess.getWarps().getWarp(warp);
teleportee.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
teleportee.sendTl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
if (!teleportee.equals(teleportOwner)) {
teleportOwner.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
teleportOwner.sendTl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
}
teleport(teleportee, new LocationTarget(loc), chargeFor, cause);
}
@ -365,7 +364,7 @@ public class Teleport implements ITeleport {
public void back(final IUser teleporter, final Trade chargeFor) throws Exception {
tpType = TeleportType.BACK;
final Location loc = teleportOwner.getLastLocation();
teleportOwner.sendMessage(tl("backUsageMsg", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
teleportOwner.sendTl("backUsageMsg", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
teleportOther(teleporter, teleportOwner, new LocationTarget(loc), chargeFor, TeleportCause.COMMAND);
}

View File

@ -7,8 +7,6 @@ import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import java.util.UUID;
import static com.earth2me.essentials.I18n.tl;
@Deprecated
public class TimedTeleport implements Runnable {
private static final double MOVE_CONSTANT = 0.3;
@ -89,14 +87,14 @@ public class TimedTeleport implements Runnable {
try {
teleport.cooldown(false);
} catch (final Exception ex) {
teleportOwner.sendMessage(tl("cooldownWithMessage", ex.getMessage()));
teleportOwner.sendTl("cooldownWithMessage", ex.getMessage());
if (teleportOwner != teleportUser) {
teleportUser.sendMessage(tl("cooldownWithMessage", ex.getMessage()));
teleportUser.sendTl("cooldownWithMessage", ex.getMessage());
}
}
try {
cancelTimer(false);
teleportUser.sendMessage(tl("teleportationCommencing"));
teleportUser.sendTl("teleportationCommencing");
if (timer_chargeFor != null) {
timer_chargeFor.isAffordableFor(teleportOwner);
@ -128,9 +126,9 @@ public class TimedTeleport implements Runnable {
try {
ess.getServer().getScheduler().cancelTask(timer_task);
if (notifyUser) {
teleportOwner.sendMessage(tl("pendingTeleportCancelled"));
teleportOwner.sendTl("pendingTeleportCancelled");
if (timer_teleportee != null && !timer_teleportee.equals(teleportOwner.getBase().getUniqueId())) {
ess.getUser(timer_teleportee).sendMessage(tl("pendingTeleportCancelled"));
ess.getUser(timer_teleportee).sendTl("pendingTeleportCancelled");
}
}
} finally {

View File

@ -1,13 +1,13 @@
package com.earth2me.essentials;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.craftbukkit.SetExpFix;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.api.IEssentials;
import net.ess3.api.IUser;
import net.ess3.api.MaxMoneyException;
import org.bukkit.Location;
import org.bukkit.entity.Item;
import org.bukkit.inventory.ItemStack;
import java.io.File;
@ -15,15 +15,13 @@ import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.earth2me.essentials.I18n.tl;
public class Trade {
private static FileWriter fw = null;
@ -79,7 +77,7 @@ public class Trade {
try {
fw = new FileWriter(new File(ess.getDataFolder(), "trade.log"), true);
} catch (final IOException ex) {
Logger.getLogger("Essentials").log(Level.SEVERE, null, ex);
Essentials.getWrappedLogger().log(Level.SEVERE, null, ex);
}
}
final StringBuilder sb = new StringBuilder();
@ -95,8 +93,10 @@ public class Trade {
} else {
if (charge.getItemStack() != null) {
sb.append(charge.getItemStack().getAmount()).append(",");
sb.append(charge.getItemStack().getType().toString()).append(",");
sb.append(charge.getItemStack().getDurability());
sb.append(charge.getItemStack().getType()).append(",");
if (VersionUtil.PRE_FLATTENING) {
sb.append(charge.getItemStack().getDurability());
}
}
if (charge.getMoney() != null) {
sb.append(charge.getMoney()).append(",");
@ -119,8 +119,10 @@ public class Trade {
} else {
if (pay.getItemStack() != null) {
sb.append(pay.getItemStack().getAmount()).append(",");
sb.append(pay.getItemStack().getType().toString()).append(",");
sb.append(pay.getItemStack().getDurability());
sb.append(pay.getItemStack().getType()).append(",");
if (VersionUtil.PRE_FLATTENING) {
sb.append(pay.getItemStack().getDurability());
}
}
if (pay.getMoney() != null) {
sb.append(pay.getMoney()).append(",");
@ -154,7 +156,7 @@ public class Trade {
fw.write(sb.toString());
fw.flush();
} catch (final IOException ex) {
Logger.getLogger("Essentials").log(Level.SEVERE, null, ex);
Essentials.getWrappedLogger().log(Level.SEVERE, null, ex);
}
}
@ -163,7 +165,7 @@ public class Trade {
try {
fw.close();
} catch (final IOException ex) {
Logger.getLogger("Essentials").log(Level.SEVERE, null, ex);
Essentials.getWrappedLogger().log(Level.SEVERE, null, ex);
}
fw = null;
}
@ -189,23 +191,23 @@ public class Trade {
}
if (getMoney() != null && getMoney().signum() > 0 && !user.canAfford(getMoney())) {
future.completeExceptionally(new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess))));
future.completeExceptionally(new ChargeException("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess)));
return;
}
if (getItemStack() != null && !user.getBase().getInventory().containsAtLeast(itemStack, itemStack.getAmount())) {
future.completeExceptionally(new ChargeException(tl("missingItems", getItemStack().getAmount(), ess.getItemDb().name(getItemStack()))));
if (getItemStack() != null && !Inventories.containsAtLeast(user.getBase(), itemStack, itemStack.getAmount())) {
future.completeExceptionally(new ChargeException("missingItems", getItemStack().getAmount(), ess.getItemDb().name(getItemStack())));
return;
}
final BigDecimal money;
if (command != null && !command.isEmpty() && (money = getCommandCost(user)).signum() > 0 && !user.canAfford(money)) {
future.completeExceptionally(new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(money, ess))));
future.completeExceptionally(new ChargeException("notEnoughMoney", NumberUtil.displayCurrency(money, ess)));
return;
}
if (exp != null && exp > 0 && SetExpFix.getTotalExperience(user.getBase()) < exp) {
future.completeExceptionally(new ChargeException(tl("notEnoughExperience")));
future.completeExceptionally(new ChargeException("notEnoughExperience"));
}
}
@ -221,52 +223,33 @@ public class Trade {
user.giveMoney(getMoney());
}
if (getItemStack() != null) {
// This stores the would be overflow
final Map<Integer, ItemStack> overFlow = InventoryWorkaround.addAllItems(user.getBase().getInventory(), getItemStack());
if (type == OverflowType.ABORT && !Inventories.hasSpace(user.getBase(), 0, false, getItemStack())) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "abort paying " + user.getName() + " itemstack " + getItemStack().toString() + " due to lack of inventory space ");
}
return Collections.singletonMap(0, getItemStack());
}
if (overFlow != null) {
switch (type) {
case ABORT:
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "abort paying " + user.getName() + " itemstack " + getItemStack().toString() + " due to lack of inventory space ");
final Map<Integer, ItemStack> leftover = Inventories.addItem(user.getBase(), getItemStack());
user.getBase().updateInventory();
if (!leftover.isEmpty()) {
if (type == OverflowType.RETURN) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " with overflow " + leftover.get(0).toString());
}
return leftover;
} else {
for (final ItemStack itemStack : leftover.values()) {
int spillAmount = itemStack.getAmount();
itemStack.setAmount(Math.min(spillAmount, itemStack.getMaxStackSize()));
while (spillAmount > 0) {
user.getBase().getWorld().dropItemNaturally(user.getBase().getLocation(), itemStack);
spillAmount -= itemStack.getAmount();
}
return overFlow;
case RETURN:
// Pay the user the items, and return overflow
final Map<Integer, ItemStack> returnStack = InventoryWorkaround.addItems(user.getBase().getInventory(), getItemStack());
user.getBase().updateInventory();
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " with overflow " + returnStack.get(0).toString());
}
return returnStack;
case DROP:
// Pay the users the items directly, and drop the rest, will always return no overflow.
final Map<Integer, ItemStack> leftOver = InventoryWorkaround.addItems(user.getBase().getInventory(), getItemStack());
final Location loc = user.getBase().getLocation();
for (final ItemStack loStack : leftOver.values()) {
final int maxStackSize = loStack.getType().getMaxStackSize();
final int stacks = loStack.getAmount() / maxStackSize;
final int leftover = loStack.getAmount() % maxStackSize;
final Item[] itemStacks = new Item[stacks + (leftover > 0 ? 1 : 0)];
for (int i = 0; i < stacks; i++) {
final ItemStack stack = loStack.clone();
stack.setAmount(maxStackSize);
itemStacks[i] = loc.getWorld().dropItem(loc, stack);
}
if (leftover > 0) {
final ItemStack stack = loStack.clone();
stack.setAmount(leftover);
itemStacks[stacks] = loc.getWorld().dropItem(loc, stack);
}
}
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " and dropping overflow " + leftOver.get(0).toString());
}
break;
}
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " and dropping overflow " + leftover.get(0).toString());
}
}
} else if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " itemstack " + getItemStack().toString());
@ -302,7 +285,7 @@ public class Trade {
ess.getLogger().log(Level.INFO, "charging user " + user.getName() + " money " + getMoney().toPlainString());
}
if (!user.canAfford(getMoney()) && getMoney().signum() > 0) {
future.completeExceptionally(new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess))));
future.completeExceptionally(new ChargeException("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess)));
return;
}
user.takeMoney(getMoney());
@ -311,17 +294,17 @@ public class Trade {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "charging user " + user.getName() + " itemstack " + getItemStack().toString());
}
if (!user.getBase().getInventory().containsAtLeast(getItemStack(), getItemStack().getAmount())) {
future.completeExceptionally(new ChargeException(tl("missingItems", getItemStack().getAmount(), getItemStack().getType().toString().toLowerCase(Locale.ENGLISH).replace("_", " "))));
if (!Inventories.containsAtLeast(user.getBase(), getItemStack(), getItemStack().getAmount())) {
future.completeExceptionally(new ChargeException("missingItems", getItemStack().getAmount(), getItemStack().getType().toString().toLowerCase(Locale.ENGLISH).replace("_", " ")));
return;
}
user.getBase().getInventory().removeItem(getItemStack());
Inventories.removeItemAmount(user.getBase(), getItemStack(), getItemStack().getAmount());
user.getBase().updateInventory();
}
if (command != null) {
final BigDecimal cost = getCommandCost(user);
if (!user.canAfford(cost) && cost.signum() > 0) {
future.completeExceptionally(new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(cost, ess))));
future.completeExceptionally(new ChargeException("notEnoughMoney", NumberUtil.displayCurrency(cost, ess)));
return;
}
user.takeMoney(cost);
@ -332,7 +315,7 @@ public class Trade {
}
final int experience = SetExpFix.getTotalExperience(user.getBase());
if (experience < getExperience() && getExperience() > 0) {
future.completeExceptionally(new ChargeException(tl("notEnoughExperience")));
future.completeExceptionally(new ChargeException("notEnoughExperience"));
return;
}
SetExpFix.setTotalExperience(user.getBase(), experience - getExperience());

View File

@ -1,156 +1,19 @@
package com.earth2me.essentials;
import com.google.common.io.Files;
import org.bukkit.Bukkit;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.regex.Pattern;
@Deprecated
public class UUIDMap {
private static final ScheduledExecutorService writeScheduler = Executors.newScheduledThreadPool(1);
private static boolean pendingWrite;
private static boolean loading = false;
private final transient net.ess3.api.IEssentials ess;
private final File userList;
private final transient Pattern splitPattern = Pattern.compile(",");
private final Runnable writeTaskRunnable;
public UUIDMap(final net.ess3.api.IEssentials ess) {
this.ess = ess;
userList = new File(ess.getDataFolder(), "usermap.csv");
pendingWrite = false;
writeTaskRunnable = () -> {
if (pendingWrite) {
try {
new WriteRunner(ess.getDataFolder(), userList, ess.getUserMap().getNames()).run();
} catch (final Throwable t) { // bad code to prevent task from being suppressed
t.printStackTrace();
}
}
};
writeScheduler.scheduleWithFixedDelay(writeTaskRunnable, 5, 5, TimeUnit.SECONDS);
}
public void loadAllUsers(final ConcurrentSkipListMap<String, UUID> names, final ConcurrentSkipListMap<UUID, ArrayList<String>> history) {
try {
if (!userList.exists()) {
userList.createNewFile();
}
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "Reading usermap from disk");
}
if (loading) {
return;
}
names.clear();
history.clear();
loading = true;
try (final BufferedReader reader = new BufferedReader(new FileReader(userList))) {
while (true) {
final String line = reader.readLine();
if (line == null) {
break;
} else {
final String[] values = splitPattern.split(line);
if (values.length == 2) {
final String name = values[0];
final UUID uuid = UUID.fromString(values[1]);
names.put(name, uuid);
if (!history.containsKey(uuid)) {
final ArrayList<String> list = new ArrayList<>();
list.add(name);
history.put(uuid, list);
} else {
final ArrayList<String> list = history.get(uuid);
if (!list.contains(name)) {
list.add(name);
}
}
}
}
}
}
loading = false;
} catch (final IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
}
public UUIDMap() {
}
public void writeUUIDMap() {
pendingWrite = true;
//no-op
}
public void forceWriteUUIDMap() {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "Forcing usermap write to disk");
}
pendingWrite = true;
writeTaskRunnable.run();
//no-op
}
public void shutdown() {
writeScheduler.submit(writeTaskRunnable);
writeScheduler.shutdown();
}
private static final class WriteRunner implements Runnable {
private final File location;
private final File endFile;
private final Map<String, UUID> names;
private WriteRunner(final File location, final File endFile, final Map<String, UUID> names) {
this.location = location;
this.endFile = endFile;
this.names = new HashMap<>(names);
}
@Override
public void run() {
pendingWrite = false;
if (loading || names.isEmpty()) {
return;
}
File configFile = null;
try {
configFile = File.createTempFile("usermap", ".tmp.csv", location);
final BufferedWriter bWriter = new BufferedWriter(new FileWriter(configFile));
for (final Map.Entry<String, UUID> entry : names.entrySet()) {
bWriter.write(entry.getKey() + "," + entry.getValue().toString());
bWriter.newLine();
}
bWriter.close();
Files.move(configFile, endFile);
} catch (final IOException ex) {
try {
if (configFile != null && configFile.exists()) {
Files.move(configFile, new File(endFile.getParentFile(), "usermap.bak.csv"));
}
} catch (final Exception ex2) {
Bukkit.getLogger().log(Level.SEVERE, ex2.getMessage(), ex2);
}
Bukkit.getLogger().log(Level.WARNING, ex.getMessage(), ex);
}
}
//no-op
}
}

View File

@ -1,10 +1,12 @@
package com.earth2me.essentials;
import com.earth2me.essentials.commands.IEssentialsCommand;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.economy.EconomyLayer;
import com.earth2me.essentials.economy.EconomyLayers;
import com.earth2me.essentials.messaging.IMessageRecipient;
import com.earth2me.essentials.messaging.SimpleMessageRecipient;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.FormatUtil;
@ -14,12 +16,15 @@ import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.Lists;
import net.ess3.api.IEssentials;
import net.ess3.api.MaxMoneyException;
import net.ess3.api.TranslatableException;
import net.ess3.api.events.AfkStatusChangeEvent;
import net.ess3.api.events.JailStatusChangeEvent;
import net.ess3.api.events.MuteStatusChangeEvent;
import net.ess3.api.events.UserBalanceUpdateEvent;
import net.essentialsx.api.v2.events.TransactionEvent;
import net.essentialsx.api.v2.services.mail.MailSender;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Statistic;
@ -27,17 +32,17 @@ import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
@ -47,21 +52,23 @@ import java.util.WeakHashMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
import static com.earth2me.essentials.I18n.tlLocale;
public class User extends UserData implements Comparable<User>, IMessageRecipient, net.ess3.api.IUser {
private static final Statistic PLAY_ONE_TICK = EnumUtil.getStatistic("PLAY_ONE_MINUTE", "PLAY_ONE_TICK");
private static final Logger logger = Logger.getLogger("Essentials");
// User modules
private final IMessageRecipient messageRecipient;
private transient final AsyncTeleport teleport;
@SuppressWarnings("deprecation")
private transient final Teleport legacyTeleport;
// User command confirmation strings
private final Map<User, BigDecimal> confirmingPayments = new WeakHashMap<>();
private String confirmingClearCommand;
private String lastHomeConfirmation;
// User teleport variables
private final transient LinkedHashMap<String, TpaRequest> teleportRequestQueue = new LinkedHashMap<>();
@ -69,32 +76,38 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
// User properties
private transient boolean vanished;
private boolean hidden = false;
private boolean leavingHidden = false;
private boolean rightClickJump = false;
private boolean invSee = false;
private boolean recipeSee = false;
private boolean enderSee = false;
private boolean ignoreMsg = false;
private Boolean toggleShout;
private boolean freeze = false;
// User afk variables
private String afkMessage;
private long afkSince;
private transient Location afkPosition = null;
// Misc
// Timestamps
private transient long lastOnlineActivity;
private transient long lastThrottledAction;
private transient long lastActivity = System.currentTimeMillis();
private transient long teleportInvulnerabilityTimestamp = 0;
private String confirmingClearCommand;
private long lastNotifiedAboutMailsMs;
private String lastHomeConfirmation;
private long lastHomeConfirmationTimestamp;
private boolean toggleShout = false;
// Misc
private transient final List<String> signCopy = Lists.newArrayList("", "", "", "");
private transient long lastVanishTime = System.currentTimeMillis();
private String lastLocaleString;
private Locale playerLocale;
public User(final Player base, final IEssentials ess) {
super(base, ess);
teleport = new AsyncTeleport(this, ess);
//noinspection deprecation
legacyTeleport = new Teleport(this, ess);
if (isAfk()) {
afkPosition = this.getLocation();
@ -105,10 +118,14 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
this.messageRecipient = new SimpleMessageRecipient(ess, this);
}
void update(final Player base) {
public void update(final Player base) {
setBase(base);
}
public IEssentials getEssentials() {
return ess;
}
@Override
public boolean isAuthorized(final IEssentialsCommand cmd) {
return isAuthorized(cmd, "essentials.");
@ -146,7 +163,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
private boolean isAuthorizedCheck(final String node) {
if (base instanceof OfflinePlayer) {
if (base instanceof OfflinePlayerStub) {
return false;
}
@ -164,7 +181,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
private boolean isPermSetCheck(final String node) {
if (base instanceof OfflinePlayer) {
if (base instanceof OfflinePlayerStub) {
return false;
}
@ -182,7 +199,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
private TriState isAuthorizedExactCheck(final String node) {
if (base instanceof OfflinePlayer) {
if (base instanceof OfflinePlayerStub) {
return TriState.UNSET;
}
@ -209,7 +226,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
cooldownTime.add(Calendar.SECOND, (int) cooldown);
cooldownTime.add(Calendar.MILLISECOND, (int) ((cooldown * 1000.0) % 1000.0));
if (cooldownTime.after(now) && !isAuthorized("essentials.heal.cooldown.bypass")) {
throw new Exception(tl("timeBeforeHeal", DateUtil.formatDateDiff(cooldownTime.getTimeInMillis())));
throw new TranslatableException("timeBeforeHeal", DateUtil.formatDateDiff(cooldownTime.getTimeInMillis()));
}
}
setLastHealTimestamp(now.getTimeInMillis());
@ -230,9 +247,9 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return;
}
setMoney(getMoney().add(value), cause);
sendMessage(tl("addedToAccount", NumberUtil.displayCurrency(value, ess)));
sendTl("addedToAccount", NumberUtil.displayCurrency(value, ess));
if (initiator != null) {
initiator.sendMessage(tl("addedToOthersAccount", NumberUtil.displayCurrency(value, ess), this.getDisplayName(), NumberUtil.displayCurrency(getMoney(), ess)));
initiator.sendTl("addedToOthersAccount", NumberUtil.displayCurrency(value, ess), getDisplayName(), NumberUtil.displayCurrency(getMoney(), ess));
}
}
@ -243,18 +260,18 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
public void payUser(final User reciever, final BigDecimal value, final UserBalanceUpdateEvent.Cause cause) throws Exception {
if (value.compareTo(BigDecimal.ZERO) < 1) {
throw new Exception(tl("payMustBePositive"));
throw new Exception(tlLocale(playerLocale, "payMustBePositive"));
}
if (canAfford(value)) {
setMoney(getMoney().subtract(value), cause);
reciever.setMoney(reciever.getMoney().add(value), cause);
sendMessage(tl("moneySentTo", NumberUtil.displayCurrency(value, ess), reciever.getDisplayName()));
reciever.sendMessage(tl("moneyRecievedFrom", NumberUtil.displayCurrency(value, ess), getDisplayName()));
sendTl("moneySentTo", NumberUtil.displayCurrency(value, ess), reciever.getDisplayName());
reciever.sendTl("moneyRecievedFrom", NumberUtil.displayCurrency(value, ess), getDisplayName());
final TransactionEvent transactionEvent = new TransactionEvent(this.getSource(), reciever, value);
ess.getServer().getPluginManager().callEvent(transactionEvent);
} else {
throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(value, ess)));
throw new ChargeException("notEnoughMoney", NumberUtil.displayCurrency(value, ess));
}
}
@ -277,9 +294,9 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
} catch (final MaxMoneyException ex) {
ess.getLogger().log(Level.WARNING, "Invalid call to takeMoney, total balance can't be more than the max-money limit.", ex);
}
sendMessage(tl("takenFromAccount", NumberUtil.displayCurrency(value, ess)));
sendTl("takenFromAccount", NumberUtil.displayCurrency(value, ess));
if (initiator != null) {
initiator.sendMessage(tl("takenFromOthersAccount", NumberUtil.displayCurrency(value, ess), this.getDisplayName(), NumberUtil.displayCurrency(getMoney(), ess)));
initiator.sendTl("takenFromOthersAccount", NumberUtil.displayCurrency(value, ess), getDisplayName(), NumberUtil.displayCurrency(getMoney(), ess));
}
}
@ -305,7 +322,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
private void _dispose() {
if (!base.isOnline()) {
this.base = new OfflinePlayer(getConfigUUID(), ess.getServer());
this.base = new OfflinePlayerStub(getConfigUUID(), ess.getServer());
}
cleanup();
}
@ -318,9 +335,10 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
if (isAuthorized("essentials.itemspawn.item-all") || isAuthorized("essentials.itemspawn.item-" + name))
return true;
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_13_0_R01)) {
if (VersionUtil.PRE_FLATTENING) {
//noinspection deprecation
final int id = material.getId();
if (isAuthorized("essentials.itemspawn.item-" + id)) return true;
return isAuthorized("essentials.itemspawn.item-" + id);
}
return false;
@ -349,17 +367,15 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
// Handle max queue size
teleportRequestQueue.remove(request.getName());
if (teleportRequestQueue.size() >= ess.getSettings().getTpaMaxRequests()) {
String lastKey = null;
for (Map.Entry<String, TpaRequest> entry : teleportRequestQueue.entrySet()) {
lastKey = entry.getKey();
}
teleportRequestQueue.remove(lastKey);
final List<String> keys = new ArrayList<>(teleportRequestQueue.keySet());
teleportRequestQueue.remove(keys.get(keys.size() - 1));
}
// Add request to queue
teleportRequestQueue.put(request.getName(), request);
}
@SuppressWarnings("deprecation")
@Override
@Deprecated
public boolean hasOutstandingTeleportRequest() {
@ -392,7 +408,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
teleportRequestQueue.remove(playerUsername);
if (inform) {
sendMessage(tl("requestTimedOutFrom", ess.getUser(request.getRequesterUuid()).getDisplayName()));
sendTl("requestTimedOutFrom", ess.getUser(request.getRequesterUuid()).getDisplayName());
}
return null;
}
@ -402,31 +418,33 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
@Override
public TpaRequest getNextTpaRequest(boolean inform, boolean performExpirations, boolean excludeHere) {
public TpaRequest getNextTpaRequest(boolean inform, boolean ignoreExpirations, boolean excludeHere) {
if (teleportRequestQueue.isEmpty()) {
return null;
}
final long timeout = ess.getSettings().getTpaAcceptCancellation();
final Iterator<Map.Entry<String, TpaRequest>> iterator = teleportRequestQueue.entrySet().iterator();
final List<String> keys = new ArrayList<>(teleportRequestQueue.keySet());
Collections.reverse(keys);
TpaRequest nextRequest = null;
while (iterator.hasNext()) {
final TpaRequest request = iterator.next().getValue();
for (final String key : keys) {
final TpaRequest request = teleportRequestQueue.get(key);
if (timeout < 1 || (System.currentTimeMillis() - request.getTime()) <= TimeUnit.SECONDS.toMillis(timeout)) {
if (excludeHere && request.isHere()) {
continue;
}
if (performExpirations) {
if (ignoreExpirations) {
return request;
} else if (nextRequest == null) {
nextRequest = request;
}
} else {
if (inform) {
sendMessage(tl("requestTimedOutFrom", ess.getUser(request.getRequesterUuid()).getDisplayName()));
sendTl("requestTimedOutFrom", ess.getUser(request.getRequesterUuid()).getDisplayName());
}
iterator.remove();
teleportRequestQueue.remove(key);
}
}
return nextRequest;
@ -439,14 +457,15 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
/**
* Needed for backwards compatibility.
*/
public String getNick(final boolean longnick) {
public String getNick(@SuppressWarnings("unused") final boolean longNick) {
return getNick(true, true);
}
/**
* Needed for backwards compatibility.
*/
public String getNick(final boolean longnick, final boolean withPrefix, final boolean withSuffix) {
@SuppressWarnings("unused")
public String getNick(@SuppressWarnings("unused") final boolean longNick, final boolean withPrefix, final boolean withSuffix) {
return getNick(withPrefix, withSuffix);
}
@ -460,7 +479,11 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
} else if (nick.equalsIgnoreCase(getName())) {
nickname = nick;
} else {
nickname = FormatUtil.replaceFormat(ess.getSettings().getNicknamePrefix()) + nick;
if (isAuthorized("essentials.nick.hideprefix")) {
nickname = nick;
} else {
nickname = FormatUtil.replaceFormat(ess.getSettings().getNicknamePrefix()) + nick;
}
suffix = "§r";
}
@ -515,7 +538,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
this.getBase().setPlayerListName(name);
} catch (final IllegalArgumentException e) {
if (ess.getSettings().isDebug()) {
logger.log(Level.INFO, "Playerlist for " + name + " was not updated. Name clashed with another online player.");
ess.getLogger().log(Level.INFO, "Playerlist for " + name + " was not updated. Name clashed with another online player.");
}
}
}
@ -524,6 +547,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
@Override
public String getDisplayName() {
//noinspection ConstantConditions
return super.getBase().getDisplayName() == null || (ess.getSettings().hideDisplayNameInVanish() && isHidden()) ? super.getBase().getName() : super.getBase().getDisplayName();
}
@ -544,6 +568,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
/**
* @deprecated This API is not asynchronous. Use {@link User#getAsyncTeleport()}
*/
@SuppressWarnings("deprecation")
@Override
@Deprecated
public Teleport getTeleport() {
@ -620,6 +645,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
}
@SuppressWarnings("deprecation")
@Override
public void setAfk(final boolean set) {
setAfk(set, AfkStatusChangeEvent.Cause.UNKNOWN);
@ -633,7 +659,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return;
}
this.getBase().setSleepingIgnored(this.isAuthorized("essentials.sleepingignored") || set && ess.getSettings().sleepIgnoresAfkPlayers());
this.getBase().setSleepingIgnored(this.isAuthorized("essentials.sleepingignored") || (set && ess.getSettings().sleepIgnoresAfkPlayers()));
if (set && !isAfk()) {
afkPosition = this.getLocation();
this.afkSince = System.currentTimeMillis();
@ -670,6 +696,9 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
@Override
public boolean isHiddenFrom(Player player) {
if (getBase() instanceof OfflinePlayerStub || player instanceof OfflinePlayerStub) {
return true;
}
return !player.canSee(getBase());
}
@ -678,6 +707,16 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return hidden;
}
@Override
public boolean isLeavingHidden() {
return leavingHidden;
}
@Override
public void setLeavingHidden(boolean leavingHidden) {
this.leavingHidden = leavingHidden;
}
@Override
public void setHidden(final boolean hidden) {
this.hidden = hidden;
@ -687,7 +726,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
public boolean isHidden(final Player player) {
return hidden || !player.canSee(getBase());
return hidden || isHiddenFrom(player);
}
@Override
@ -700,6 +739,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
//Returns true if status expired during this check
@SuppressWarnings("UnusedReturnValue")
public boolean checkJailTimeout(final long currentTime) {
if (getJailTimeout() > 0) {
@ -717,7 +757,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
setJailTimeout(0);
setOnlineJailedTime(0);
setJailed(false);
sendMessage(tl("haveBeenReleased"));
sendTl("haveBeenReleased");
setJail(null);
if (ess.getSettings().getTeleportWhenFreePolicy() == ISettings.TeleportWhenFreePolicy.BACK) {
final CompletableFuture<Boolean> future = new CompletableFuture<>();
@ -737,6 +777,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
//Returns true if status expired during this check
@SuppressWarnings("UnusedReturnValue")
public boolean checkMuteTimeout(final long currentTime) {
if (getMuteTimeout() > 0 && getMuteTimeout() < currentTime && isMuted()) {
final MuteStatusChangeEvent event = new MuteStatusChangeEvent(this, null, false, getMuteTimeout(), getMuteReason());
@ -744,7 +785,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
if (!event.isCancelled()) {
setMuteTimeout(0);
sendMessage(tl("canTalkAgain"));
sendTl("canTalkAgain");
setMuted(false);
setMuteReason(null);
return true;
@ -763,15 +804,10 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
setAfk(false, cause);
if (broadcast && !isHidden() && !isAfk()) {
setDisplayNick();
final String msg = tl("userIsNotAway", getDisplayName());
final String selfmsg = tl("userIsNotAwaySelf", getDisplayName());
if (!msg.isEmpty() && ess.getSettings().broadcastAfkMessage()) {
// exclude user from receiving general AFK announcement in favor of personal message
ess.broadcastMessage(this, msg, u -> u == this);
}
if (!selfmsg.isEmpty()) {
this.sendMessage(selfmsg);
if (ess.getSettings().broadcastAfkMessage()) {
ess.broadcastTl(this, u -> u == this, "userIsNotAway", getDisplayName());
}
sendTl("userIsNotAwaySelf", getDisplayName());
}
}
lastActivity = System.currentTimeMillis();
@ -792,14 +828,12 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
public void updateActivityOnChat(final boolean broadcast) {
if (ess.getSettings().cancelAfkOnChat()) {
//Chat happens async, make sure we have a sync context
ess.scheduleSyncDelayedTask(() -> {
updateActivity(broadcast, AfkStatusChangeEvent.Cause.CHAT);
});
ess.scheduleSyncDelayedTask(() -> updateActivity(broadcast, AfkStatusChangeEvent.Cause.CHAT));
}
}
public void checkActivity() {
// Graceful time before the first afk check call.
// Graceful time before the first afk check call.
if (System.currentTimeMillis() - lastActivity <= 10000) {
return;
}
@ -809,13 +843,14 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
&& lastActivity > 0 && (lastActivity + (autoafkkick * 1000)) < System.currentTimeMillis()
&& !isAuthorized("essentials.kick.exempt")
&& !isAuthorized("essentials.afk.kickexempt")) {
final String kickReason = tl("autoAfkKickReason", autoafkkick / 60.0);
lastActivity = 0;
this.getBase().kickPlayer(kickReason);
final double kickTime = autoafkkick / 60.0;
this.getBase().kickPlayer(AdventureUtil.miniToLegacy(playerTl("autoAfkKickReason", kickTime)));
for (final User user : ess.getOnlineUsers()) {
if (user.isAuthorized("essentials.kick.notify")) {
user.sendMessage(tl("playerKicked", Console.DISPLAY_NAME, getName(), kickReason));
user.sendTl("playerKicked", Console.DISPLAY_NAME, getName(), user.playerTl("autoAfkKickReason", kickTime));
}
}
}
@ -824,15 +859,10 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
setAfk(true, AfkStatusChangeEvent.Cause.ACTIVITY);
if (isAfk() && !isHidden()) {
setDisplayNick();
final String msg = tl("userIsAway", getDisplayName());
final String selfmsg = tl("userIsAwaySelf", getDisplayName());
if (!msg.isEmpty() && ess.getSettings().broadcastAfkMessage()) {
// exclude user from receiving general AFK announcement in favor of personal message
ess.broadcastMessage(this, msg, u -> u == this);
}
if (!selfmsg.isEmpty()) {
this.sendMessage(selfmsg);
if (ess.getSettings().broadcastAfkMessage()) {
ess.broadcastTl(this, u -> u == this, "userIsAway", getDisplayName());
}
sendTl("userIsAwaySelf", getDisplayName());
}
}
}
@ -847,6 +877,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
// This enables the no-god-in-worlds functionality where the actual player god mode state is never modified in disabled worlds,
// but this method gets called every time the player takes damage. In the case that the world has god-mode disabled then this method
// will return false and the player will take damage, even though they are in god mode (isGodModeEnabledRaw()).
//noinspection ConstantConditions
if (!ess.getSettings().getNoGodWorlds().contains(this.getLocation().getWorld().getName())) {
return true;
}
@ -888,6 +919,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return ess.getPermissionsHandler().canBuild(base, getGroup());
}
@SuppressWarnings("deprecation")
@Override
@Deprecated
public long getTeleportRequestTime() {
@ -956,10 +988,12 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
if (set) {
for (final User user : ess.getOnlineUsers()) {
if (!user.isAuthorized("essentials.vanish.see")) {
//noinspection deprecation
user.getBase().hidePlayer(getBase());
}
}
setHidden(true);
lastVanishTime = System.currentTimeMillis();
ess.getVanishedPlayersNew().add(getName());
this.getBase().setMetadata("vanished", new FixedMetadataValue(ess, true));
if (isAuthorized("essentials.vanish.effect")) {
@ -970,6 +1004,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
} else {
for (final Player p : ess.getOnlinePlayers()) {
//noinspection deprecation
p.showPlayer(getBase());
}
setHidden(false);
@ -1029,6 +1064,48 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
}
@Override
public void sendComponent(ComponentLike component) {
ess.getBukkitAudience().player(base).sendMessage(component);
}
@Override
public Component tlComponent(String tlKey, Object... args) {
final String translation = playerTl(tlKey, args);
return AdventureUtil.miniMessage().deserialize(translation);
}
@Override
public void sendTl(String tlKey, Object... args) {
final String translation = playerTl(tlKey, args);
if (translation.trim().isEmpty()) {
return;
}
sendComponent(AdventureUtil.miniMessage().deserialize(translation));
}
@Override
public String playerTl(String tlKey, Object... args) {
if (ess.getSettings().isPerPlayerLocale()) {
return tlLocale(getPlayerLocale(ess.getPlayerLocaleProvider().getLocale(base)), tlKey, args);
}
return tlLiteral(tlKey, args);
}
@Override
public String tlSender(String tlKey, Object... args) {
return playerTl(tlKey, args);
}
public Locale getPlayerLocale(final String locale) {
if (locale.equals(lastLocaleString)) {
return playerLocale;
}
lastLocaleString = locale;
return playerLocale = I18n.getLocale(locale);
}
@Override
public int compareTo(final User other) {
return FormatUtil.stripFormat(getDisplayName()).compareToIgnoreCase(FormatUtil.stripFormat(other.getDisplayName()));
@ -1050,7 +1127,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
@Override
public CommandSource getSource() {
return new CommandSource(getBase());
return new CommandSource(ess, getBase());
}
@Override
@ -1122,12 +1199,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
* Returns the {@link ItemStack} in the main hand or off-hand. If the main hand is empty then the offhand item is returned - also nullable.
*/
public ItemStack getItemInHand() {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_9_R01)) {
return getBase().getInventory().getItemInHand();
} else {
final PlayerInventory inventory = getBase().getInventory();
return inventory.getItemInMainHand() != null ? inventory.getItemInMainHand() : inventory.getItemInOffHand();
}
return Inventories.getItemInHand(getBase());
}
@Override
@ -1140,6 +1212,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
ess.getMail().sendMail(this, sender, message, expireAt);
}
@SuppressWarnings("deprecation")
@Override
@Deprecated
public void addMail(String mail) {
@ -1151,7 +1224,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
if (unread != 0) {
final int notifyPlayerOfMailCooldown = ess.getSettings().getNotifyPlayerOfMailCooldown() * 1000;
if (System.currentTimeMillis() - lastNotifiedAboutMailsMs >= notifyPlayerOfMailCooldown) {
sendMessage(tl("youHaveNewMail", unread));
sendTl("youHaveNewMail", unread);
lastNotifiedAboutMailsMs = System.currentTimeMillis();
}
}
@ -1177,6 +1250,16 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return signCopy;
}
@Override
public boolean isFreeze() {
return freeze;
}
@Override
public void setFreeze(boolean freeze) {
this.freeze = freeze;
}
public boolean isBaltopExempt() {
if (getBase().isOnline()) {
final boolean exempt = isAuthorized("essentials.balancetop.exclude");
@ -1186,6 +1269,10 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return isBaltopExcludeCache();
}
public long getLastVanishTime() {
return lastVanishTime;
}
@Override
public Block getTargetBlock(int maxDistance) {
final Block block;
@ -1198,10 +1285,16 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
@Override
public void setToggleShout(boolean toggleShout) {
this.toggleShout = toggleShout;
if (ess.getSettings().isPersistShout()) {
setShouting(toggleShout);
}
}
@Override
public boolean isToggleShout() {
return toggleShout;
if (ess.getSettings().isPersistShout()) {
return toggleShout = isShouting();
}
return toggleShout == null ? toggleShout = ess.getSettings().isShoutDefault() : toggleShout;
}
}

View File

@ -5,18 +5,19 @@ import com.earth2me.essentials.config.EssentialsUserConfiguration;
import com.earth2me.essentials.config.entities.CommandCooldown;
import com.earth2me.essentials.config.entities.LazyLocation;
import com.earth2me.essentials.config.holders.UserConfigHolder;
import com.earth2me.essentials.userstorage.ModernUserMap;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.base.Charsets;
import net.ess3.api.IEssentials;
import net.ess3.api.MaxMoneyException;
import net.ess3.api.TranslatableException;
import net.essentialsx.api.v2.services.mail.MailMessage;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.spongepowered.configurate.serialize.SerializationException;
import java.io.File;
import java.math.BigDecimal;
@ -31,31 +32,24 @@ import java.util.UUID;
import java.util.logging.Level;
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;
protected final transient Essentials ess;
private final EssentialsUserConfiguration config;
private UserConfigHolder holder;
private BigDecimal money;
protected UserData(final Player base, final IEssentials ess) {
super(base);
this.ess = ess;
this.ess = (Essentials) ess;
final File folder = new File(ess.getDataFolder(), "userdata");
if (!folder.exists()) {
folder.mkdirs();
if (!folder.exists() && !folder.mkdirs()) {
throw new RuntimeException("Unable to create userdata folder!");
}
String filename;
try {
filename = base.getUniqueId().toString();
} catch (final Throwable ex) {
ess.getLogger().warning("Falling back to old username system for " + base.getName());
filename = base.getName();
}
config = new EssentialsUserConfiguration(base.getName(), base.getUniqueId(), new File(folder, filename + ".yml"));
config = new EssentialsUserConfiguration(base.getName(), base.getUniqueId(), new File(folder, base.getUniqueId() + ".yml"));
config.setSaveHook(() -> {
config.setRootHolder(UserConfigHolder.class, holder);
});
reloadConfig();
if (config.getUsername() == null) {
@ -65,12 +59,15 @@ public abstract class UserData extends PlayerExtension implements IConf {
public final void reset() {
config.blockingSave();
config.getFile().delete();
if (!config.getFile().delete()) {
ess.getLogger().warning("Unable to delete data file for " + config.getFile().getName());
}
if (config.getUsername() != null) {
ess.getUserMap().removeUser(config.getUsername());
final ModernUserMap users = (ModernUserMap) ess.getUsers();
users.invalidate(config.getUuid());
if (isNPC()) {
final String uuid = UUID.nameUUIDFromBytes(("NPC:" + StringUtil.safeString(config.getUsername())).getBytes(Charsets.UTF_8)).toString();
ess.getUserMap().removeUserUUID(uuid);
final String name = ess.getSettings().isSafeUsermap() ? StringUtil.safeString(config.getUsername()) : config.getUsername();
users.invalidate(UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8)));
}
}
}
@ -84,18 +81,10 @@ public abstract class UserData extends PlayerExtension implements IConf {
config.load();
try {
holder = config.getRootNode().get(UserConfigHolder.class);
} catch (SerializationException e) {
ess.getLogger().log(Level.SEVERE, "Error while reading user config: " + e.getMessage(), e);
} catch (Throwable e) {
ess.getLogger().log(Level.SEVERE, "Error while reading user config: " + config.getFile().getName(), e);
throw new RuntimeException(e);
}
config.setSaveHook(() -> {
try {
config.getRootNode().set(UserConfigHolder.class, holder);
} catch (SerializationException e) {
ess.getLogger().log(Level.SEVERE, "Error while saving user config: " + e.getMessage(), e);
throw new RuntimeException(e);
}
});
money = _getMoney();
}
@ -204,7 +193,17 @@ public abstract class UserData extends PlayerExtension implements IConf {
holder.homes().remove(search);
config.save();
} else {
throw new Exception(tl("invalidHome", search));
throw new TranslatableException("invalidHome", search);
}
}
public void renameHome(final String name, final String newName) throws Exception {
final LazyLocation location = holder.homes().remove(name);
if (location != null) {
holder.homes().put(StringUtil.safeString(newName), location);
config.save();
} else {
throw new TranslatableException("invalidHome", name);
}
}
@ -589,9 +588,13 @@ public abstract class UserData extends PlayerExtension implements IConf {
}
public void setLastAccountName(final String lastAccountName) {
if (getLastAccountName() != null && !getLastAccountName().equals(lastAccountName)) {
final List<String> usernames = holder.pastUsernames();
usernames.add(0, getLastAccountName());
holder.pastUsernames(usernames);
}
holder.lastAccountName(lastAccountName);
config.save();
ess.getUserMap().trackUUID(getConfigUUID(), lastAccountName, true);
}
public boolean arePowerToolsEnabled() {
@ -722,6 +725,29 @@ public abstract class UserData extends PlayerExtension implements IConf {
config.save();
}
public List<String> getPastUsernames() {
return holder.pastUsernames();
}
public void addPastUsername(String username) {
final List<String> usernames = holder.pastUsernames();
usernames.add(0, username);
holder.pastUsernames(usernames);
config.save();
}
public boolean isShouting() {
if (holder.shouting() == null) {
holder.shouting(ess.getSettings().isShoutDefault());
}
return holder.shouting();
}
public void setShouting(boolean shouting) {
holder.shouting(shouting);
config.save();
}
public UUID getConfigUUID() {
return config.getUuid();
}

View File

@ -1,383 +1,70 @@
package com.earth2me.essentials;
import com.earth2me.essentials.api.UserDoesNotExistException;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.base.Charsets;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import net.ess3.api.IEssentials;
import net.ess3.api.MaxMoneyException;
import com.earth2me.essentials.userstorage.ModernUserMap;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.regex.Pattern;
public class UserMap extends CacheLoader<String, User> implements IConf {
private static boolean legacy = false;
private static Method getLegacy;
private final transient IEssentials ess;
private final transient ConcurrentSkipListSet<UUID> keys = new ConcurrentSkipListSet<>();
private final transient ConcurrentSkipListMap<String, UUID> names = new ConcurrentSkipListMap<>();
private final transient ConcurrentSkipListMap<UUID, ArrayList<String>> history = new ConcurrentSkipListMap<>();
private final UUIDMap uuidMap;
private final transient Cache<String, User> users;
private final Pattern validUserPattern = Pattern.compile("^[a-zA-Z0-9_]{2,16}$");
@Deprecated
public class UserMap {
private final transient ModernUserMap userMap;
private final transient UUIDMap uuidMap;
private static final String WARN_UUID_NOT_REPLACE = "Found UUID {0} for player {1}, but player already has a UUID ({2}). Not replacing UUID in usermap.";
public UserMap(final IEssentials ess) {
super();
this.ess = ess;
uuidMap = new UUIDMap(ess);
//RemovalListener<UUID, User> remListener = new UserMapRemovalListener();
//users = CacheBuilder.newBuilder().maximumSize(ess.getSettings().getMaxUserCacheCount()).softValues().removalListener(remListener).build(this);
final CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder();
final int maxCount = ess.getSettings().getMaxUserCacheCount();
try {
cacheBuilder.maximumSize(maxCount);
} catch (final NoSuchMethodError nsme) {
legacy = true;
legacyMaximumSize(cacheBuilder, maxCount);
}
cacheBuilder.softValues();
if (!legacy) {
users = cacheBuilder.build(this);
} else {
users = legacyBuild(cacheBuilder);
}
}
private void loadAllUsersAsync(final IEssentials ess) {
ess.runTaskAsynchronously(() -> {
synchronized (users) {
final File userdir = new File(ess.getDataFolder(), "userdata");
if (!userdir.exists()) {
return;
}
keys.clear();
users.invalidateAll();
for (final String string : userdir.list()) {
if (!string.endsWith(".yml")) {
continue;
}
final String name = string.substring(0, string.length() - 4);
try {
keys.add(UUID.fromString(name));
} catch (final IllegalArgumentException ex) {
//Ignore these users till they rejoin.
}
}
uuidMap.loadAllUsers(names, history);
}
});
}
public boolean userExists(final UUID uuid) {
return keys.contains(uuid);
public UserMap(final ModernUserMap userMap) {
this.userMap = userMap;
this.uuidMap = new UUIDMap();
}
public User getUser(final String name) {
final String sanitizedName = StringUtil.safeString(name);
try {
if (ess.getSettings().isDebug()) {
ess.getLogger().warning("Looking up username " + name + " (" + sanitizedName + ") ...");
}
if (names.containsKey(sanitizedName)) {
final UUID uuid = names.get(sanitizedName);
return getUser(uuid);
}
if (ess.getSettings().isDebug()) {
ess.getLogger().warning(name + "(" + sanitizedName + ") has no known usermap entry");
}
final File userFile = getUserFileFromString(sanitizedName);
if (userFile.exists()) {
ess.getLogger().info("Importing user " + name + " to usermap.");
final User user = new User(new OfflinePlayer(sanitizedName, ess.getServer()), ess);
trackUUID(user.getBase().getUniqueId(), user.getName(), true);
return user;
}
return null;
} catch (final UncheckedExecutionException ex) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.WARNING, ex, () -> String.format("Exception while getting user for %s (%s)", name, sanitizedName));
}
return null;
}
return userMap.getUser(name);
}
public User getUser(final UUID uuid) {
try {
if (!legacy) {
return ((LoadingCache<String, User>) users).get(uuid.toString());
} else {
return legacyCacheGet(uuid);
}
} catch (final ExecutionException | UncheckedExecutionException ex) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.WARNING, ex, () -> "Exception while getting user for " + uuid);
}
return null;
}
return userMap.getUser(uuid);
}
public void trackUUID(final UUID uuid, final String name, final boolean replace) {
if (uuid != null) {
keys.add(uuid);
if (name != null && name.length() > 0) {
final String keyName = ess.getSettings().isSafeUsermap() ? StringUtil.safeString(name) : name;
if (!names.containsKey(keyName)) {
names.put(keyName, uuid);
uuidMap.writeUUIDMap();
} else if (!isUUIDMatch(uuid, keyName)) {
if (replace) {
ess.getLogger().info("Found new UUID for " + name + ". Replacing " + names.get(keyName).toString() + " with " + uuid.toString());
names.put(keyName, uuid);
uuidMap.writeUUIDMap();
} else {
ess.getLogger().log(Level.INFO, MessageFormat.format(WARN_UUID_NOT_REPLACE, uuid.toString(), name, names.get(keyName).toString()), new RuntimeException());
}
}
}
}
// no-op
}
public boolean isUUIDMatch(final UUID uuid, final String name) {
return names.containsKey(name) && names.get(name).equals(uuid);
}
@Override
public User load(final String stringUUID) throws Exception {
final UUID uuid = UUID.fromString(stringUUID);
Player player = ess.getServer().getPlayer(uuid);
if (player != null) {
final User user = new User(player, ess);
trackUUID(uuid, user.getName(), true);
return user;
}
final File userFile = getUserFileFromID(uuid);
if (userFile.exists()) {
player = new OfflinePlayer(uuid, ess.getServer());
final User user = new User(player, ess);
((OfflinePlayer) player).setName(user.getLastAccountName());
trackUUID(uuid, user.getName(), false);
return user;
}
throw new Exception("User not found!");
return userMap.load(UUID.fromString(stringUUID));
}
public User load(final org.bukkit.OfflinePlayer player) throws UserDoesNotExistException {
if (player == null) {
throw new IllegalArgumentException("Player cannot be null!");
}
final Player userPlayer;
if (player instanceof Player) {
if (ess.getSettings().isDebug()) {
ess.getLogger().info("Loading online OfflinePlayer into user map...");
}
final User user = new User((Player) player, ess);
trackUUID(player.getUniqueId(), player.getName(), true);
return user;
}
final File userFile = getUserFileFromID(player.getUniqueId());
if (ess.getSettings().isDebug()) {
ess.getLogger().info("Loading OfflinePlayer into user map. Has data: " + userFile.exists() + " for " + player);
}
final OfflinePlayer essPlayer = new OfflinePlayer(player.getUniqueId(), ess.getServer());
final User user = new User(essPlayer, ess);
if (userFile.exists()) {
essPlayer.setName(user.getLastAccountName());
userPlayer = (Player) player;
} else {
if (ess.getSettings().isDebug()) {
ess.getLogger().info("OfflinePlayer usermap load saving user data for " + player);
}
// this code makes me sad
user.startTransaction();
try {
user.setMoney(ess.getSettings().getStartingBalance());
} catch (MaxMoneyException e) {
// Shouldn't happen as it would be an illegal configuration state
throw new RuntimeException(e);
}
user.setLastAccountName(user.getName());
user.stopTransaction();
final OfflinePlayerStub essPlayer = new OfflinePlayerStub(player.getUniqueId(), Bukkit.getServer());
essPlayer.setName(player.getName());
userPlayer = essPlayer;
}
trackUUID(player.getUniqueId(), user.getName(), false);
final User user = userMap.getUser(userPlayer);
if (user == null) {
throw new UserDoesNotExistException("User not found");
}
return user;
}
@Override
public void reloadConfig() {
getUUIDMap().forceWriteUUIDMap();
loadAllUsersAsync(ess);
}
public void invalidateAll() {
users.invalidateAll();
}
public void removeUser(final String name) {
if (names == null) {
ess.getLogger().warning("Name collection is null, cannot remove user.");
return;
}
final UUID uuid = names.get(name);
if (uuid != null) {
keys.remove(uuid);
users.invalidate(uuid.toString());
}
names.remove(name);
names.remove(StringUtil.safeString(name));
}
public void removeUserUUID(final String uuid) {
users.invalidate(uuid);
}
public Set<UUID> getAllUniqueUsers() {
return Collections.unmodifiableSet(keys);
return userMap.getAllUserUUIDs();
}
public int getUniqueUsers() {
return keys.size();
return userMap.getUserCount();
}
protected ConcurrentSkipListMap<String, UUID> getNames() {
return names;
}
protected ConcurrentSkipListMap<UUID, ArrayList<String>> getHistory() {
return history;
}
public List<String> getUserHistory(final UUID uuid) {
return history.get(uuid);
return new ConcurrentSkipListMap<>(userMap.getNameCache());
}
public UUIDMap getUUIDMap() {
return uuidMap;
}
// class UserMapRemovalListener implements RemovalListener
// {
// @Override
// public void onRemoval(final RemovalNotification notification)
// {
// Object value = notification.getValue();
// if (value != null)
// {
// ((User)value).cleanup();
// }
// }
// }
private File getUserFileFromID(final UUID uuid) {
final File userFolder = new File(ess.getDataFolder(), "userdata");
return new File(userFolder, uuid.toString() + ".yml");
}
public File getUserFileFromString(final String name) {
final File userFolder = new File(ess.getDataFolder(), "userdata");
return new File(userFolder, StringUtil.sanitizeFileName(name) + ".yml");
}
@SuppressWarnings("deprecation")
public User getUserFromBukkit(String name) {
name = StringUtil.safeString(name);
if (ess.getSettings().isDebug()) {
ess.getLogger().warning("Using potentially blocking Bukkit UUID lookup for: " + name);
}
// Don't attempt to look up entirely invalid usernames
if (name == null || !validUserPattern.matcher(name).matches()) {
return null;
}
final org.bukkit.OfflinePlayer offlinePlayer = ess.getServer().getOfflinePlayer(name);
if (offlinePlayer == null) {
return null;
}
final UUID uuid;
try {
uuid = offlinePlayer.getUniqueId();
} catch (final UnsupportedOperationException | NullPointerException e) {
return null;
}
// This is how Bukkit generates fake UUIDs
if (UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)).equals(uuid)) {
return null;
} else {
names.put(name, uuid);
return getUser(uuid);
}
}
private User legacyCacheGet(final UUID uuid) {
if (getLegacy == null) {
final Class<?> usersClass = users.getClass();
for (final Method m : usersClass.getDeclaredMethods()) {
if (m.getName().equals("get")) {
getLegacy = m;
getLegacy.setAccessible(true);
break;
}
}
}
try {
return (User) getLegacy.invoke(users, uuid.toString());
} catch (final IllegalAccessException | InvocationTargetException e) {
return null;
}
}
private void legacyMaximumSize(final CacheBuilder builder, final int maxCount) {
try {
final Method maxSizeLegacy = builder.getClass().getDeclaredMethod("maximumSize", Integer.TYPE);
maxSizeLegacy.setAccessible(true);
maxSizeLegacy.invoke(builder, maxCount);
} catch (final NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
private Cache<String, User> legacyBuild(final CacheBuilder builder) {
Method build = null;
for (final Method method : builder.getClass().getDeclaredMethods()) {
if (method.getName().equals("build")) {
build = method;
break;
}
}
Cache<String, User> legacyUsers;
try {
assert build != null;
build.setAccessible(true);
legacyUsers = (Cache<String, User>) build.invoke(builder, this);
} catch (final IllegalAccessException | InvocationTargetException e) {
legacyUsers = null;
}
return legacyUsers;
}
}

View File

@ -2,9 +2,11 @@ package com.earth2me.essentials;
import com.earth2me.essentials.commands.WarpNotFoundException;
import com.earth2me.essentials.config.EssentialsConfiguration;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.StringUtil;
import net.ess3.api.InvalidNameException;
import net.ess3.api.InvalidWorldException;
import net.ess3.api.TranslatableException;
import org.bukkit.Location;
import java.io.File;
@ -16,12 +18,10 @@ import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public class Warps implements IConf, net.ess3.api.IWarps {
private static final Logger logger = Logger.getLogger("Essentials");
private final Map<StringIgnoreCase, EssentialsConfiguration> warpPoints = new HashMap<>();
private final File warpsFolder;
@ -79,7 +79,7 @@ public class Warps implements IConf, net.ess3.api.IWarps {
if (conf == null) {
final File confFile = new File(warpsFolder, filename + ".yml");
if (confFile.exists()) {
throw new Exception(tl("similarWarpExist"));
throw new Exception(user == null ? tlLiteral("similarWarpExist") : user.playerTl("similarWarpExist"));
}
conf = new EssentialsConfiguration(confFile);
conf.load();
@ -111,10 +111,10 @@ public class Warps implements IConf, net.ess3.api.IWarps {
public void removeWarp(final String name) throws Exception {
final EssentialsConfiguration conf = warpPoints.get(new StringIgnoreCase(name));
if (conf == null) {
throw new Exception(tl("warpNotExist"));
throw new TranslatableException("warpNotExist");
}
if (!conf.getFile().delete()) {
throw new Exception(tl("warpDeleteError"));
throw new TranslatableException("warpDeleteError");
}
warpPoints.remove(new StringIgnoreCase(name));
}
@ -123,7 +123,7 @@ public class Warps implements IConf, net.ess3.api.IWarps {
public final void reloadConfig() {
warpPoints.clear();
final File[] listOfFiles = warpsFolder.listFiles();
if (listOfFiles.length >= 1) {
if (listOfFiles != null) {
for (final File listOfFile : listOfFiles) {
final String filename = listOfFile.getName();
if (listOfFile.isFile() && filename.endsWith(".yml")) {
@ -135,7 +135,7 @@ public class Warps implements IConf, net.ess3.api.IWarps {
warpPoints.put(new StringIgnoreCase(name), conf);
}
} catch (final Exception ex) {
logger.log(Level.WARNING, tl("loadWarpError", filename), ex);
Essentials.getWrappedLogger().log(Level.WARNING, AdventureUtil.miniToLegacy(tlLiteral("loadWarpError", filename)), ex);
}
}
}

View File

@ -3,7 +3,9 @@ package com.earth2me.essentials;
import com.earth2me.essentials.commands.NotEnoughArgumentsException;
import com.earth2me.essentials.config.ConfigurateUtil;
import com.earth2me.essentials.config.EssentialsConfiguration;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.api.TranslatableException;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.spongepowered.configurate.CommentedConfigurationNode;
@ -12,8 +14,6 @@ import java.io.File;
import java.math.BigDecimal;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Worth implements IConf {
private final EssentialsConfiguration config;
@ -30,13 +30,15 @@ public class Worth implements IConf {
* @return The price from the config.
*/
public BigDecimal getPrice(final IEssentials ess, final ItemStack itemStack) {
BigDecimal result;
BigDecimal result = BigDecimal.ONE.negate();
final String itemname = itemStack.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", "");
// Check for matches with data value from stack
// Note that we always default to BigDecimal.ONE.negate(), equivalent to -1
result = config.getBigDecimal("worth." + itemname + "." + itemStack.getDurability(), BigDecimal.ONE.negate());
if (VersionUtil.PRE_FLATTENING) {
// Check for matches with data value from stack
// Note that we always default to BigDecimal.ONE.negate(), equivalent to -1
result = config.getBigDecimal("worth." + itemname + "." + itemStack.getDurability(), BigDecimal.ONE.negate());
}
// Check for matches with data value 0
if (result.signum() < 0) {
@ -75,7 +77,7 @@ public class Worth implements IConf {
*/
public int getAmount(final IEssentials ess, final User user, final ItemStack is, final String[] args, final boolean isBulkSell) throws Exception {
if (is == null || is.getType() == Material.AIR) {
throw new Exception(tl("itemSellAir"));
throw new TranslatableException("itemSellAir");
}
int amount = 0;
@ -95,11 +97,11 @@ public class Worth implements IConf {
final boolean requireStack = ess.getSettings().isTradeInStacks(is.getType());
if (requireStack && !stack) {
throw new Exception(tl("itemMustBeStacked"));
throw new TranslatableException("itemMustBeStacked");
}
int max = 0;
for (final ItemStack s : user.getBase().getInventory().getContents()) {
for (final ItemStack s : Inventories.getInventory(user.getBase(), false)) {
if (s == null || !s.isSimilar(is)) {
continue;
}
@ -118,9 +120,9 @@ public class Worth implements IConf {
}
if (amount > max || amount < 1) {
if (!isBulkSell) {
user.sendMessage(tl("itemNotEnough2"));
user.sendMessage(tl("itemNotEnough3"));
throw new Exception(tl("itemNotEnough1"));
user.sendTl("itemNotEnough2");
user.sendTl("itemNotEnough3");
throw new TranslatableException("itemNotEnough1");
} else {
return amount;
}
@ -140,7 +142,7 @@ public class Worth implements IConf {
String path = "worth." + itemStack.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", "");
// Spigot 1.13+ throws an exception if a 1.13+ plugin even *attempts* to do set data.
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_13_0_R01) && itemStack.getType().getData() == null) {
if (VersionUtil.PRE_FLATTENING && itemStack.getType().getData() == null) {
// Bukkit-bug: getDurability still contains the correct value, while getData().getData() is 0.
path = path + "." + itemStack.getDurability();
}
@ -149,6 +151,10 @@ public class Worth implements IConf {
config.save();
}
public File getFile() {
return config.getFile();
}
@Override
public void reloadConfig() {
config.load();

View File

@ -3,6 +3,7 @@ package com.earth2me.essentials.api;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.config.EssentialsUserConfiguration;
import com.earth2me.essentials.userstorage.ModernUserMap;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.base.Charsets;
@ -17,14 +18,12 @@ import java.math.MathContext;
import java.text.MessageFormat;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* You should use Vault instead of directly using this class.
*/
public class Economy {
public static final MathContext MATH_CONTEXT = MathContext.DECIMAL128;
private static final Logger LOGGER = Logger.getLogger("Essentials");
private static IEssentials ess;
private static final String WARN_CALL_BEFORE_LOAD = "Essentials API is called before Essentials is loaded.";
@ -43,9 +42,9 @@ public class Economy {
ess = aEss;
}
private static void createNPCFile(String name) {
private static void createNPCFile(final String unsanitizedName) {
final File folder = new File(ess.getDataFolder(), "userdata");
name = StringUtil.safeString(name);
final String name = ess.getSettings().isSafeUsermap() ? StringUtil.safeString(unsanitizedName) : unsanitizedName;
if (!folder.exists()) {
if (!folder.mkdirs()) {
throw new RuntimeException("Error while creating userdata directory!");
@ -54,16 +53,19 @@ public class Economy {
final UUID npcUUID = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
final File npcFile = new File(folder, npcUUID + ".yml");
if (npcFile.exists()) {
LOGGER.log(Level.SEVERE, MessageFormat.format(WARN_NPC_RECREATE_1, name, npcUUID.toString()), new RuntimeException());
LOGGER.log(Level.SEVERE, WARN_NPC_RECREATE_2);
ess.getLogger().log(Level.SEVERE, MessageFormat.format(WARN_NPC_RECREATE_1, name, npcUUID.toString()), new RuntimeException());
ess.getLogger().log(Level.SEVERE, WARN_NPC_RECREATE_2);
}
final EssentialsUserConfiguration npcConfig = new EssentialsUserConfiguration(name, npcUUID, npcFile);
npcConfig.load();
npcConfig.setProperty("npc", true);
npcConfig.setProperty("last-account-name", name);
npcConfig.setProperty("npc-name", unsanitizedName);
npcConfig.setProperty("money", ess.getSettings().getStartingBalance());
npcConfig.blockingSave();
ess.getUserMap().trackUUID(npcUUID, name, false);
// This will load the NPC into the UserMap + UUID cache
((ModernUserMap) ess.getUsers()).addCachedNpcName(npcUUID, name);
ess.getUsers().getUser(npcUUID);
}
private static void deleteNPC(final String name) {
@ -90,7 +92,7 @@ public class Economy {
if (player != null) {
user = ess.getUser(player.getUniqueId());
if (user != null) {
LOGGER.log(Level.INFO, MessageFormat.format(WARN_PLAYER_UUID_NO_NAME, name, player.getUniqueId().toString()), new RuntimeException());
ess.getLogger().log(Level.INFO, MessageFormat.format(WARN_PLAYER_UUID_NO_NAME, name, player.getUniqueId().toString()), new RuntimeException());
}
}
}
@ -190,7 +192,7 @@ public class Economy {
try {
setMoney(name, BigDecimal.valueOf(balance));
} catch (final ArithmeticException e) {
LOGGER.log(Level.WARNING, "Failed to set balance of " + name + " to " + balance + ": " + e.getMessage(), e);
ess.getLogger().log(Level.WARNING, "Failed to set balance of " + name + " to " + balance + ": " + e.getMessage(), e);
}
}
@ -268,7 +270,7 @@ public class Economy {
try {
add(name, BigDecimal.valueOf(amount));
} catch (final ArithmeticException e) {
LOGGER.log(Level.WARNING, "Failed to add " + amount + " to balance of " + name + ": " + e.getMessage(), e);
ess.getLogger().log(Level.WARNING, "Failed to add " + amount + " to balance of " + name + ": " + e.getMessage(), e);
}
}
@ -340,7 +342,7 @@ public class Economy {
try {
substract(name, BigDecimal.valueOf(amount));
} catch (final ArithmeticException e) {
LOGGER.log(Level.WARNING, "Failed to subtract " + amount + " of balance of " + name + ": " + e.getMessage(), e);
ess.getLogger().log(Level.WARNING, "Failed to subtract " + amount + " of balance of " + name + ": " + e.getMessage(), e);
}
}
@ -410,7 +412,7 @@ public class Economy {
try {
divide(name, BigDecimal.valueOf(amount));
} catch (final ArithmeticException e) {
LOGGER.log(Level.WARNING, "Failed to divide balance of " + name + " by " + amount + ": " + e.getMessage(), e);
ess.getLogger().log(Level.WARNING, "Failed to divide balance of " + name + " by " + amount + ": " + e.getMessage(), e);
}
}
@ -482,7 +484,7 @@ public class Economy {
try {
multiply(name, BigDecimal.valueOf(amount));
} catch (final ArithmeticException e) {
LOGGER.log(Level.WARNING, "Failed to multiply balance of " + name + " by " + amount + ": " + e.getMessage(), e);
ess.getLogger().log(Level.WARNING, "Failed to multiply balance of " + name + " by " + amount + ": " + e.getMessage(), e);
}
}
@ -603,7 +605,7 @@ public class Economy {
try {
return hasEnough(name, BigDecimal.valueOf(amount));
} catch (final ArithmeticException e) {
LOGGER.log(Level.WARNING, "Failed to compare balance of " + name + " with " + amount + ": " + e.getMessage(), e);
ess.getLogger().log(Level.WARNING, "Failed to compare balance of " + name + " with " + amount + ": " + e.getMessage(), e);
return false;
}
}
@ -664,7 +666,7 @@ public class Economy {
try {
return hasMore(name, BigDecimal.valueOf(amount));
} catch (final ArithmeticException e) {
LOGGER.log(Level.WARNING, "Failed to compare balance of " + name + " with " + amount + ": " + e.getMessage(), e);
ess.getLogger().log(Level.WARNING, "Failed to compare balance of " + name + " with " + amount + ": " + e.getMessage(), e);
return false;
}
}
@ -726,7 +728,7 @@ public class Economy {
try {
return hasLess(name, BigDecimal.valueOf(amount));
} catch (final ArithmeticException e) {
LOGGER.log(Level.WARNING, "Failed to compare balance of " + name + " with " + amount + ": " + e.getMessage(), e);
ess.getLogger().log(Level.WARNING, "Failed to compare balance of " + name + " with " + amount + ": " + e.getMessage(), e);
return false;
}
}
@ -833,7 +835,7 @@ public class Economy {
try {
return format(BigDecimal.valueOf(amount));
} catch (final NumberFormatException e) {
LOGGER.log(Level.WARNING, "Failed to display " + amount + ": " + e.getMessage(), e);
ess.getLogger().log(Level.WARNING, "Failed to display " + amount + ": " + e.getMessage(), e);
return "NaN";
}
}
@ -900,7 +902,7 @@ public class Economy {
createNPCFile(name);
return true;
}
LOGGER.log(Level.WARNING, MessageFormat.format(WARN_EXISTING_NPC_CREATE, name, user.getConfigUUID()), new RuntimeException());
ess.getLogger().log(Level.WARNING, MessageFormat.format(WARN_EXISTING_NPC_CREATE, name, user.getConfigUUID()), new RuntimeException());
return false;
}

View File

@ -1,16 +1,16 @@
package com.earth2me.essentials.api;
import static com.earth2me.essentials.I18n.tl;
import net.ess3.api.TranslatableException;
/**
* @deprecated This exception is unused. Use {@link net.ess3.api.InvalidWorldException} instead.
*/
@Deprecated
public class InvalidWorldException extends Exception {
public class InvalidWorldException extends TranslatableException {
private final String world;
public InvalidWorldException(final String world) {
super(tl("invalidWorld"));
super("invalidWorld");
this.world = world;
}

View File

@ -1,18 +1,18 @@
package com.earth2me.essentials.api;
import java.util.UUID;
import net.ess3.api.TranslatableException;
import static com.earth2me.essentials.I18n.tl;
import java.util.UUID;
/**
* Thrown when the requested user does not exist.
*/
public class UserDoesNotExistException extends Exception {
public class UserDoesNotExistException extends TranslatableException {
public UserDoesNotExistException(final String name) {
super(tl("userDoesNotExist", name));
super("userDoesNotExist", name);
}
public UserDoesNotExistException(final UUID uuid) {
super(tl("uuidDoesNotExist", uuid.toString()));
super("uuidDoesNotExist", uuid.toString());
}
}

View File

@ -3,14 +3,13 @@ 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.TranslatableException;
import net.ess3.api.events.AfkStatusChangeEvent;
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");
@ -50,17 +49,23 @@ public class Commandafk extends EssentialsCommand {
if (sender.isMuted()) {
final String dateDiff = sender.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(sender.getMuteTimeout()) : null;
if (dateDiff == null) {
throw new Exception(sender.hasMuteReason() ? tl("voiceSilencedReason", sender.getMuteReason()) : tl("voiceSilenced"));
if (sender.hasMuteReason()) {
throw new TranslatableException("voiceSilencedReason", sender.getMuteReason());
} else {
throw new TranslatableException("voiceSilenced");
}
}
if (sender.hasMuteReason()) {
throw new TranslatableException("voiceSilencedReasonTime", dateDiff, sender.getMuteReason());
} else {
throw new TranslatableException("voiceSilencedTime", dateDiff);
}
throw new Exception(sender.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, sender.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
}
if (!sender.isAuthorized("essentials.afk.message")) {
throw new Exception(tl("noPermToAFKMessage"));
throw new TranslatableException("noPermToAFKMessage");
}
}
user.setDisplayNick();
String msg = "";
String selfmsg = "";
final boolean currentStatus = user.isAfk();
final boolean afterStatus = user.toggleAfk(AfkStatusChangeEvent.Cause.COMMAND);
@ -68,37 +73,39 @@ public class Commandafk extends EssentialsCommand {
return;
}
String tlKey = "";
String selfTlKey = "";
if (!afterStatus) {
if (!user.isHidden()) {
msg = tl("userIsNotAway", user.getDisplayName());
selfmsg = tl("userIsNotAwaySelf", user.getDisplayName());
tlKey = "userIsNotAway";
selfTlKey = "userIsNotAwaySelf";
}
user.updateActivity(false, AfkStatusChangeEvent.Cause.COMMAND);
} else {
if (!user.isHidden()) {
if (message != null) {
msg = tl("userIsAwayWithMessage", user.getDisplayName(), message);
selfmsg = tl("userIsAwaySelfWithMessage", user.getDisplayName(), message);
tlKey = "userIsAwayWithMessage";
selfTlKey = "userIsAwaySelfWithMessage";
} else {
msg = tl("userIsAway", user.getDisplayName());
selfmsg = tl("userIsAwaySelf", user.getDisplayName());
tlKey = "userIsAway";
selfTlKey = "userIsAwaySelf";
}
}
user.setAfkMessage(message);
}
if (!msg.isEmpty() && ess.getSettings().broadcastAfkMessage()) {
if (!tlKey.isEmpty() && ess.getSettings().broadcastAfkMessage()) {
// exclude user from receiving general AFK announcement in favor of personal message
ess.broadcastMessage(user, msg, u -> u == user);
ess.broadcastTl(user, u -> u == user, tlKey, user.getDisplayName(), message);
}
if (!selfmsg.isEmpty()) {
user.sendMessage(selfmsg);
if (!selfTlKey.isEmpty()) {
user.sendTl(selfTlKey, user.getDisplayName(), message);
}
user.setDisplayNick(); // Set this again after toggling
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1 && sender.isAuthorized("essentials.afk.others", ess)) {
if (args.length == 1 && sender.isAuthorized("essentials.afk.others")) {
return getPlayers(server, sender);
} else {
return Collections.emptyList();

View File

@ -3,8 +3,6 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import static com.earth2me.essentials.I18n.tl;
public class Commandanvil extends EssentialsCommand {
public Commandanvil() {
@ -14,7 +12,7 @@ public class Commandanvil extends EssentialsCommand {
@Override
protected void run(Server server, User user, String commandLabel, String[] args) throws Exception {
if (ess.getContainerProvider() == null) {
user.sendMessage(tl("unsupportedBrand"));
user.sendTl("unsupportedBrand");
return;
}

View File

@ -3,13 +3,12 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import net.ess3.api.TranslatableException;
import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandback extends EssentialsCommand {
public Commandback() {
super("back");
@ -37,13 +36,13 @@ public class Commandback extends EssentialsCommand {
private void parseOthers(final Server server, final CommandSource sender, final String[] args, final String commandLabel) throws Exception {
final User player = getPlayer(server, args, 0, true, false);
sender.sendMessage(tl("backOther", player.getName()));
sender.sendTl("backOther", player.getName());
teleportBack(sender, player, commandLabel);
}
private void teleportBack(final CommandSource sender, final User user, final String commandLabel) throws Exception {
if (user.getLastLocation() == null) {
throw new Exception(tl("noLocationFound"));
throw new TranslatableException("noLocationFound");
}
final String lastWorldName = user.getLastLocation().getWorld().getName();
@ -53,11 +52,11 @@ public class Commandback extends EssentialsCommand {
requester = ess.getUser(sender.getPlayer());
if (user.getWorld() != user.getLastLocation().getWorld() && this.ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + lastWorldName)) {
throw new Exception(tl("noPerm", "essentials.worlds." + lastWorldName));
throw new TranslatableException("noPerm", "essentials.worlds." + lastWorldName);
}
if (!requester.isAuthorized("essentials.back.into." + lastWorldName)) {
throw new Exception(tl("noPerm", "essentials.back.into." + lastWorldName));
throw new TranslatableException("noPerm", "essentials.back.into." + lastWorldName);
}
}

View File

@ -2,10 +2,9 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.Backup;
import com.earth2me.essentials.CommandSource;
import net.ess3.api.TranslatableException;
import org.bukkit.Server;
import static com.earth2me.essentials.I18n.tl;
public class Commandbackup extends EssentialsCommand {
public Commandbackup() {
super("backup");
@ -15,13 +14,13 @@ public class Commandbackup extends EssentialsCommand {
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
final Backup backup = ess.getBackup();
if (backup == null) {
throw new Exception(tl("backupDisabled"));
throw new TranslatableException("backupDisabled");
}
final String command = ess.getSettings().getBackupCommand();
if (command == null || "".equals(command) || "save-all".equalsIgnoreCase(command)) {
throw new Exception(tl("backupDisabled"));
throw new TranslatableException("backupDisabled");
}
backup.run();
sender.sendMessage(tl("backupStarted"));
sender.sendTl("backupStarted");
}
}

View File

@ -8,8 +8,6 @@ import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandbalance extends EssentialsCommand {
public Commandbalance() {
super("balance");
@ -22,16 +20,16 @@ public class Commandbalance extends EssentialsCommand {
}
final User target = getPlayer(server, args, 0, false, true);
sender.sendMessage(tl("balanceOther", target.isHidden() ? target.getName() : target.getDisplayName(), NumberUtil.displayCurrency(target.getMoney(), ess)));
sender.sendTl("balanceOther", target.isHidden() ? target.getName() : target.getDisplayName(), NumberUtil.displayCurrency(target.getMoney(), ess));
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length == 1 && user.isAuthorized("essentials.balance.others")) {
final User target = getPlayer(server, args, 0, true, true);
user.sendMessage(tl("balanceOther", target.isHidden() ? target.getName() : target.getDisplayName(), NumberUtil.displayCurrency(target.getMoney(), ess)));
user.sendTl("balanceOther", target.isHidden() ? target.getName() : target.getDisplayName(), NumberUtil.displayCurrency(target.getMoney(), ess));
} else if (args.length < 2) {
user.sendMessage(tl("balance", NumberUtil.displayCurrency(user.getMoney(), ess)));
user.sendTl("balance", NumberUtil.displayCurrency(user.getMoney(), ess));
} else {
throw new NotEnoughArgumentsException();
}
@ -39,7 +37,7 @@ public class Commandbalance extends EssentialsCommand {
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1 && sender.isAuthorized("essentials.balance.others", ess)) {
if (args.length == 1 && sender.isAuthorized("essentials.balance.others")) {
return getPlayers(server, sender);
} else {
return Collections.emptyList();

View File

@ -3,10 +3,12 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.textreader.TextPager;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import net.essentialsx.api.v2.services.BalanceTop;
import org.bukkit.Server;
import org.bukkit.command.BlockCommandSender;
import java.math.BigDecimal;
import java.text.DateFormat;
@ -17,7 +19,7 @@ import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public class Commandbalancetop extends EssentialsCommand {
public static final int MINUSERS = 50;
@ -32,8 +34,15 @@ public class Commandbalancetop extends EssentialsCommand {
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(ess.getBalanceTop().getCacheAge());
final DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
sender.sendMessage(tl("balanceTop", format.format(cal.getTime())));
new TextPager(cache).showPage(Integer.toString(page), null, "balancetop", sender);
final Runnable runnable = () -> {
sender.sendTl("balanceTop", format.format(cal.getTime()));
new TextPager(cache).showPage(Integer.toString(page), null, "balancetop", sender);
};
if (sender.getSender() instanceof BlockCommandSender) {
ess.scheduleSyncDelayedTask(runnable);
} else {
runnable.run();
}
}
@Override
@ -56,8 +65,8 @@ public class Commandbalancetop extends EssentialsCommand {
}
// If there are less than 50 users in our usermap, there is no need to display a warning as these calculations should be done quickly
if (ess.getUserMap().getUniqueUsers() > MINUSERS) {
sender.sendMessage(tl("orderBalances", ess.getUserMap().getUniqueUsers()));
if (ess.getUsers().getUserCount() > MINUSERS) {
sender.sendTl("orderBalances", ess.getUsers().getUserCount());
}
ess.runTaskAsynchronously(new Viewer(sender, page, force));
@ -101,11 +110,11 @@ public class Commandbalancetop extends EssentialsCommand {
future.thenRun(() -> {
if (fresh) {
final SimpleTextInput newCache = new SimpleTextInput();
newCache.getLines().add(tl("serverTotal", NumberUtil.displayCurrency(ess.getBalanceTop().getBalanceTopTotal(), ess)));
newCache.getLines().add(AdventureUtil.miniToLegacy(tlLiteral("serverTotal", NumberUtil.displayCurrency(ess.getBalanceTop().getBalanceTopTotal(), ess))));
int pos = 1;
for (final Map.Entry<UUID, BalanceTop.Entry> entry : ess.getBalanceTop().getBalanceTopCache().entrySet()) {
if (ess.getSettings().showZeroBaltop() || entry.getValue().getBalance().compareTo(BigDecimal.ZERO) > 0) {
newCache.getLines().add(tl("balanceTopLine", pos, entry.getValue().getDisplayName(), NumberUtil.displayCurrency(entry.getValue().getBalance(), ess)));
newCache.getLines().add(AdventureUtil.miniToLegacy(tlLiteral("balanceTopLine", pos, entry.getValue().getDisplayName(), NumberUtil.displayCurrency(entry.getValue().getBalance(), ess))));
}
pos++;
}

View File

@ -2,9 +2,11 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Console;
import com.earth2me.essentials.OfflinePlayer;
import com.earth2me.essentials.OfflinePlayerStub;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.FormatUtil;
import net.ess3.api.TranslatableException;
import org.bukkit.BanList;
import org.bukkit.Server;
@ -12,7 +14,7 @@ import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public class Commandban extends EssentialsCommand {
public Commandban() {
@ -30,14 +32,14 @@ public class Commandban extends EssentialsCommand {
user = getPlayer(server, args, 0, true, true);
} catch (final PlayerNotFoundException e) {
nomatch = true;
user = ess.getUser(new OfflinePlayer(args[0], ess.getServer()));
user = ess.getUser(new OfflinePlayerStub(args[0], ess.getServer()));
}
if (!user.getBase().isOnline()) {
if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.ban.offline")) {
throw new Exception(tl("banExemptOffline"));
throw new TranslatableException("banExemptOffline");
}
} else if (user.isAuthorized("essentials.ban.exempt") && sender.isPlayer()) {
throw new Exception(tl("banExempt"));
throw new TranslatableException("banExempt");
}
final String senderName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.NAME;
@ -46,21 +48,21 @@ public class Commandban extends EssentialsCommand {
if (args.length > 1) {
banReason = FormatUtil.replaceFormat(getFinalArg(args, 1).replace("\\n", "\n").replace("|", "\n"));
} else {
banReason = tl("defaultBanReason");
banReason = tlLiteral("defaultBanReason");
}
ess.getServer().getBanList(BanList.Type.NAME).addBan(user.getName(), banReason, null, senderName);
final String banDisplay = tl("banFormat", banReason, senderDisplayName);
final String banDisplay = tlLiteral("banFormat", banReason, senderDisplayName);
user.getBase().kickPlayer(banDisplay);
server.getLogger().log(Level.INFO, tl("playerBanned", senderDisplayName, user.getName(), banDisplay));
user.getBase().kickPlayer(AdventureUtil.miniToLegacy(banDisplay));
ess.getLogger().log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("playerBanned", senderDisplayName, user.getName(), banDisplay)));
if (nomatch) {
sender.sendMessage(tl("userUnknown", user.getName()));
sender.sendTl("userUnknown", user.getName());
}
ess.broadcastMessage("essentials.ban.notify", tl("playerBanned", senderDisplayName, user.getName(), banReason));
ess.broadcastTl(null, u -> !u.isAuthorized("essentials.ban.notify"), "playerBanned", senderDisplayName, user.getName(), banReason);
}
@Override

View File

@ -3,6 +3,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Console;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.BanList;
import org.bukkit.Server;
@ -12,7 +13,7 @@ import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public class Commandbanip extends EssentialsCommand {
public Commandbanip() {
@ -48,13 +49,13 @@ public class Commandbanip extends EssentialsCommand {
if (args.length > 1) {
banReason = FormatUtil.replaceFormat(getFinalArg(args, 1).replace("\\n", "\n").replace("|", "\n"));
} else {
banReason = tl("defaultBanReason");
banReason = tlLiteral("defaultBanReason");
}
final String banDisplay = tl("banFormat", banReason, senderDisplayName);
final String banDisplay = AdventureUtil.miniToLegacy(tlLiteral("banFormat", banReason, senderDisplayName));
ess.getServer().getBanList(BanList.Type.IP).addBan(ipAddress, banReason, null, senderName);
server.getLogger().log(Level.INFO, tl("playerBanIpAddress", senderDisplayName, ipAddress, banReason));
ess.getLogger().log(Level.INFO, AdventureUtil.miniToLegacy(tlLiteral("playerBanIpAddress", senderDisplayName, ipAddress, banReason)));
for (final Player player : ess.getServer().getOnlinePlayers()) {
if (player.getAddress().getAddress().getHostAddress().equalsIgnoreCase(ipAddress)) {
@ -62,7 +63,7 @@ public class Commandbanip extends EssentialsCommand {
}
}
ess.broadcastMessage("essentials.banip.notify", tl("playerBanIpAddress", senderDisplayName, ipAddress, banReason));
ess.broadcastTl(null, u -> !u.isAuthorized("essentials.banip.notify"), "playerBanIpAddress", senderDisplayName, ipAddress, banReason);
}
@Override

View File

@ -7,8 +7,6 @@ import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.entity.Entity;
import static com.earth2me.essentials.I18n.tl;
public class Commandbeezooka extends EssentialsCommand {
public Commandbeezooka() {
@ -18,7 +16,7 @@ public class Commandbeezooka extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_15_R01)) {
user.sendMessage(tl("unsupportedFeature"));
user.sendTl("unsupportedFeature");
return;
}

View File

@ -3,6 +3,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.LocationUtil;
import com.google.common.collect.Lists;
import net.ess3.api.TranslatableException;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.TreeType;
@ -10,8 +11,6 @@ import org.bukkit.TreeType;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandbigtree extends EssentialsCommand {
public Commandbigtree() {
super("bigtree");
@ -32,15 +31,15 @@ public class Commandbigtree extends EssentialsCommand {
throw new NotEnoughArgumentsException();
}
final Location loc = LocationUtil.getTarget(user.getBase()).add(0, 1, 0);
final Location loc = LocationUtil.getTarget(user.getBase(), ess.getSettings().getMaxTreeCommandRange()).add(0, 1, 0);
if (loc.getBlock().getType().isSolid()) {
throw new Exception(tl("bigTreeFailure"));
throw new TranslatableException("bigTreeFailure");
}
final boolean success = user.getWorld().generateTree(loc, tree);
if (success) {
user.sendMessage(tl("bigTreeSuccess"));
user.sendTl("bigTreeSuccess");
} else {
throw new Exception(tl("bigTreeFailure"));
throw new TranslatableException("bigTreeFailure");
}
}

View File

@ -1,10 +1,11 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.FormatUtil;
import com.google.common.collect.Lists;
import net.ess3.api.TranslatableException;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
@ -13,8 +14,6 @@ import org.bukkit.inventory.meta.BookMeta;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandbook extends EssentialsCommand {
private static final Material WRITABLE_BOOK = EnumUtil.getMaterial("WRITABLE_BOOK", "BOOK_AND_QUILL");
@ -25,7 +24,7 @@ public class Commandbook extends EssentialsCommand {
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final ItemStack item = user.getItemInHand();
final ItemStack item = Inventories.getItemInMainHand(user.getBase());
final String player = user.getName();
if (item.getType() == Material.WRITTEN_BOOK) {
final BookMeta bmeta = (BookMeta) item.getItemMeta();
@ -35,27 +34,27 @@ public class Commandbook extends EssentialsCommand {
final String newAuthor = FormatUtil.formatString(user, "essentials.book.author", getFinalArg(args, 1)).trim();
bmeta.setAuthor(newAuthor);
item.setItemMeta(bmeta);
user.sendMessage(tl("bookAuthorSet", newAuthor));
user.sendTl("bookAuthorSet", newAuthor);
} else {
throw new Exception(tl("denyChangeAuthor"));
throw new TranslatableException("denyChangeAuthor");
}
} else if (args.length > 1 && args[0].equalsIgnoreCase("title")) {
if (user.isAuthorized("essentials.book.title") && (isAuthor(bmeta, player) || user.isAuthorized("essentials.book.others"))) {
final String newTitle = FormatUtil.formatString(user, "essentials.book.title", getFinalArg(args, 1)).trim();
bmeta.setTitle(newTitle);
item.setItemMeta(bmeta);
user.sendMessage(tl("bookTitleSet", newTitle));
user.sendTl("bookTitleSet", newTitle);
} else {
throw new Exception(tl("denyChangeTitle"));
throw new TranslatableException("denyChangeTitle");
}
} else {
if (isAuthor(bmeta, player) || user.isAuthorized("essentials.book.others")) {
final ItemStack newItem = new ItemStack(WRITABLE_BOOK, item.getAmount());
newItem.setItemMeta(bmeta);
InventoryWorkaround.setItemInMainHand(user.getBase(), newItem);
user.sendMessage(tl("editBookContents"));
Inventories.setItemInMainHand(user.getBase(), newItem);
user.sendTl("editBookContents");
} else {
throw new Exception(tl("denyBookEdit"));
throw new TranslatableException("denyBookEdit");
}
}
} else if (item.getType() == WRITABLE_BOOK) {
@ -65,10 +64,10 @@ public class Commandbook extends EssentialsCommand {
}
final ItemStack newItem = new ItemStack(Material.WRITTEN_BOOK, item.getAmount());
newItem.setItemMeta(bmeta);
InventoryWorkaround.setItemInMainHand(user.getBase(), newItem);
user.sendMessage(tl("bookLocked"));
Inventories.setItemInMainHand(user.getBase(), newItem);
user.sendTl("bookLocked");
} else {
throw new Exception(tl("holdBook"));
throw new TranslatableException("holdBook");
}
}

View File

@ -0,0 +1,34 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.LocationUtil;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.event.player.PlayerTeleportEvent;
import java.util.concurrent.CompletableFuture;
public class Commandbottom extends EssentialsCommand {
public Commandbottom() {
super("bottom");
}
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final int bottomX = user.getLocation().getBlockX();
final int bottomZ = user.getLocation().getBlockZ();
final float pitch = user.getLocation().getPitch();
final float yaw = user.getLocation().getYaw();
final Location unsafe = new Location(user.getWorld(), bottomX, ess.getWorldInfoProvider().getMinHeight(user.getWorld()), bottomZ, yaw, pitch);
final Location safe = LocationUtil.getSafeDestination(ess, unsafe);
final CompletableFuture<Boolean> future = getNewExceptionFuture(user.getSource(), commandLabel);
future.thenAccept(success -> {
if (success) {
user.sendTl("teleportBottom", safe.getWorld().getName(), safe.getBlockX(), safe.getBlockY(), safe.getBlockZ());
}
});
user.getAsyncTeleport().teleport(safe, new Trade(this.getName(), ess), PlayerTeleportEvent.TeleportCause.COMMAND, future);
}
}

View File

@ -1,13 +1,12 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import net.ess3.api.TranslatableException;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.block.Block;
import org.bukkit.event.block.BlockBreakEvent;
import static com.earth2me.essentials.I18n.tl;
public class Commandbreak extends EssentialsCommand {
public Commandbreak() {
super("break");
@ -22,7 +21,7 @@ public class Commandbreak extends EssentialsCommand {
throw new NoChargeException();
}
if (block.getType() == Material.BEDROCK && !user.isAuthorized("essentials.break.bedrock")) {
throw new Exception(tl("noBreakBedrock"));
throw new TranslatableException("noBreakBedrock");
}
//final List<ItemStack> list = (List<ItemStack>)block.getDrops();
//final BlockBreakEvent event = new BlockBreakEvent(block, user.getBase(), list);

View File

@ -4,8 +4,6 @@ import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.Server;
import static com.earth2me.essentials.I18n.tl;
public class Commandbroadcast extends EssentialsCommand {
public Commandbroadcast() {
super("broadcast");
@ -17,6 +15,6 @@ public class Commandbroadcast extends EssentialsCommand {
throw new NotEnoughArgumentsException();
}
ess.broadcastMessage(tl("broadcast", FormatUtil.replaceFormat(getFinalArg(args, 0)).replace("\\n", "\n"), sender.getDisplayName()));
ess.broadcastTl("broadcast", FormatUtil.replaceFormat(getFinalArg(args, 0)).replace("\\n", "\n"), sender.getDisplayName());
}
}

View File

@ -2,21 +2,15 @@ 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.KeywordReplacer;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.AdventureUtil;
import com.google.common.collect.Lists;
import net.ess3.api.TranslatableException;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandbroadcastworld extends EssentialsCommand {
public Commandbroadcastworld() {
@ -25,13 +19,13 @@ public class Commandbroadcastworld extends EssentialsCommand {
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length == 0) {
if (args.length < 2) {
throw new NotEnoughArgumentsException();
}
World world = user.getWorld();
String message = getFinalArg(args, 0);
if (args.length > 1 && ess.getSettings().isAllowWorldInBroadcastworld()) {
if (ess.getSettings().isAllowWorldInBroadcastworld()) {
final World argWorld = ess.getWorld(args[0]);
if (argWorld != null) {
world = argWorld;
@ -45,12 +39,12 @@ public class Commandbroadcastworld extends EssentialsCommand {
@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("world");
throw new NotEnoughArgumentsException();
}
final World world = ess.getWorld(args[0]);
if (world == null) {
throw new Exception(tl("invalidWorld"));
throw new TranslatableException("invalidWorld");
}
sendBroadcast(world, sender.getSender().getName(), getFinalArg(args, 1));
}
@ -59,22 +53,7 @@ public class Commandbroadcastworld extends EssentialsCommand {
if (message.isEmpty()) {
throw new NotEnoughArgumentsException();
}
sendToWorld(world, tl("broadcast", FormatUtil.replaceFormat(message).replace("\\n", "\n"), name));
}
private void sendToWorld(final World world, final String message) {
IText broadcast = new SimpleTextInput(message);
final Collection<Player> players = ess.getOnlinePlayers();
for (final Player player : players) {
if (player.getWorld().equals(world)) {
final User user = ess.getUser(player);
broadcast = new KeywordReplacer(broadcast, new CommandSource(player), ess, false);
for (final String messageText : broadcast.getLines()) {
user.sendMessage(messageText);
}
}
}
ess.broadcastTl(null, u -> !u.getBase().getWorld().equals(world), true, "broadcast", message, AdventureUtil.parsed(AdventureUtil.legacyToMini(name)));
}
@Override

View File

@ -7,8 +7,6 @@ import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandburn extends EssentialsCommand {
public Commandburn() {
super("burn");
@ -22,7 +20,7 @@ public class Commandburn extends EssentialsCommand {
final User user = getPlayer(server, sender, args, 0);
user.getBase().setFireTicks(Integer.parseInt(args[1]) * 20);
sender.sendMessage(tl("burnMsg", user.getDisplayName(), Integer.parseInt(args[1])));
sender.sendTl("burnMsg", user.getDisplayName(), Integer.parseInt(args[1]));
}
@Override

View File

@ -3,8 +3,6 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import static com.earth2me.essentials.I18n.tl;
public class Commandcartographytable extends EssentialsCommand {
public Commandcartographytable() {
@ -14,7 +12,7 @@ public class Commandcartographytable extends EssentialsCommand {
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (ess.getContainerProvider() == null) {
user.sendMessage(tl("unsupportedBrand"));
user.sendTl("unsupportedBrand");
return;
}

View File

@ -2,7 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.earth2me.essentials.utils.VersionUtil;
@ -19,11 +19,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Set;
import static com.earth2me.essentials.I18n.tl;
public class Commandclearinventory extends EssentialsCommand {
private static final int BASE_AMOUNT = 100000;
private static final int EXTENDED_CAP = 8;
public Commandclearinventory() {
@ -57,7 +53,7 @@ public class Commandclearinventory extends EssentialsCommand {
}
if (allowAll && args.length > 0 && args[0].contentEquals("*")) {
sender.sendMessage(tl("inventoryClearingFromAll"));
sender.sendTl("inventoryClearingFromAll");
offset = 1;
players = ess.getOnlinePlayers();
} else if (allowOthers && args.length > 0 && args[0].trim().length() > 2) {
@ -74,7 +70,7 @@ public class Commandclearinventory extends EssentialsCommand {
if (senderUser != null && senderUser.isPromptingClearConfirm()) {
if (!formattedCommand.equals(previousClearCommand)) {
senderUser.setConfirmingClearCommand(formattedCommand);
senderUser.sendMessage(tl("confirmClear", formattedCommand));
senderUser.sendTl("confirmClear", formattedCommand);
return;
}
}
@ -114,41 +110,33 @@ public class Commandclearinventory extends EssentialsCommand {
}
}
if (type == ClearHandlerType.ALL_EXCEPT_ARMOR) {
if (type != ClearHandlerType.SPECIFIC_ITEM) {
final boolean armor = type == ClearHandlerType.ALL_INCLUDING_ARMOR;
if (showExtended) {
sender.sendMessage(tl("inventoryClearingAllItems", player.getDisplayName()));
sender.sendTl(armor ? "inventoryClearingAllArmor" : "inventoryClearingAllItems", player.getDisplayName());
}
InventoryWorkaround.clearInventoryNoArmor(player.getInventory());
InventoryWorkaround.setItemInOffHand(player, null);
} else if (type == ClearHandlerType.ALL_INCLUDING_ARMOR) {
if (showExtended) {
sender.sendMessage(tl("inventoryClearingAllArmor", player.getDisplayName()));
}
InventoryWorkaround.clearInventoryNoArmor(player.getInventory());
InventoryWorkaround.setItemInOffHand(player, null);
player.getInventory().setArmorContents(null);
Inventories.removeItems(player, item -> true, armor);
} else {
for (final Item item : items) {
final ItemStack stack = new ItemStack(item.getMaterial());
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_13_0_R01)) {
if (VersionUtil.PRE_FLATTENING) {
//noinspection deprecation
stack.setDurability(item.getData());
}
// amount -1 means all items will be cleared
if (amount == -1) {
stack.setAmount(BASE_AMOUNT);
final ItemStack removedStack = player.getInventory().removeItem(stack).get(0);
final int removedAmount = BASE_AMOUNT - removedStack.getAmount() + InventoryWorkaround.clearItemInOffHand(player, stack);
final int removedAmount = Inventories.removeItemSimilar(player, stack, true);
if (removedAmount > 0 || showExtended) {
sender.sendMessage(tl("inventoryClearingStack", removedAmount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName()));
sender.sendTl("inventoryClearingStack", removedAmount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName());
}
} else {
stack.setAmount(amount < 0 ? 1 : amount);
if (player.getInventory().containsAtLeast(stack, amount)) {
sender.sendMessage(tl("inventoryClearingStack", amount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName()));
player.getInventory().removeItem(stack);
if (Inventories.removeItemAmount(player, stack, amount)) {
sender.sendTl("inventoryClearingStack", amount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName());
} else {
if (showExtended) {
sender.sendMessage(tl("inventoryClearFail", player.getDisplayName(), amount, stack.getType().toString().toLowerCase(Locale.ENGLISH)));
sender.sendTl("inventoryClearFail", player.getDisplayName(), amount, stack.getType().toString().toLowerCase(Locale.ENGLISH));
}
}
}
@ -203,7 +191,7 @@ public class Commandclearinventory extends EssentialsCommand {
}
private String formatCommand(final String commandLabel, final String[] args) {
return "/" + commandLabel + " " + StringUtil.joinList(" ", args);
return "/" + commandLabel + " " + StringUtil.joinList(" ", (Object[]) args);
}
private enum ClearHandlerType {

View File

@ -3,8 +3,6 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import static com.earth2me.essentials.I18n.tl;
public class Commandclearinventoryconfirmtoggle extends EssentialsCommand {
public Commandclearinventoryconfirmtoggle() {
@ -21,9 +19,9 @@ public class Commandclearinventoryconfirmtoggle extends EssentialsCommand {
}
user.setPromptingClearConfirm(confirmingClear);
if (confirmingClear) {
user.sendMessage(tl("clearInventoryConfirmToggleOn"));
user.sendTl("clearInventoryConfirmToggleOn");
} else {
user.sendMessage(tl("clearInventoryConfirmToggleOff"));
user.sendTl("clearInventoryConfirmToggleOff");
}
user.setConfirmingClearCommand(null);
}

View File

@ -3,8 +3,6 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import static com.earth2me.essentials.I18n.tl;
public class Commandcompass extends EssentialsCommand {
public Commandcompass() {
super("compass");
@ -15,24 +13,24 @@ public class Commandcompass extends EssentialsCommand {
final int bearing = (int) (user.getLocation().getYaw() + 180 + 360) % 360;
final String dir;
if (bearing < 23) {
dir = tl("north");
dir = user.playerTl("north");
} else if (bearing < 68) {
dir = tl("northEast");
dir = user.playerTl("northEast");
} else if (bearing < 113) {
dir = tl("east");
dir = user.playerTl("east");
} else if (bearing < 158) {
dir = tl("southEast");
dir = user.playerTl("southEast");
} else if (bearing < 203) {
dir = tl("south");
dir = user.playerTl("south");
} else if (bearing < 248) {
dir = tl("southWest");
dir = user.playerTl("southWest");
} else if (bearing < 293) {
dir = tl("west");
dir = user.playerTl("west");
} else if (bearing < 338) {
dir = tl("northWest");
dir = user.playerTl("northWest");
} else {
dir = tl("north");
dir = user.playerTl("north");
}
user.sendMessage(tl("compassBearing", dir, bearing));
user.sendTl("compassBearing", dir, bearing);
}
}

View File

@ -4,6 +4,8 @@ import com.earth2me.essentials.ChargeException;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.Trade.OverflowType;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.api.MaxMoneyException;
import org.bukkit.Material;
import org.bukkit.Server;
@ -21,8 +23,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import static com.earth2me.essentials.I18n.tl;
public class Commandcondense extends EssentialsCommand {
private final Map<ItemStack, SimpleRecipe> condenseList = new HashMap<>();
@ -38,7 +38,7 @@ public class Commandcondense extends EssentialsCommand {
if (args.length > 0) {
is = ess.getItemDb().getMatching(user, args);
} else {
for (final ItemStack stack : user.getBase().getInventory().getContents()) {
for (final ItemStack stack : Inventories.getInventory(user.getBase(), false)) {
if (stack == null || stack.getType() == Material.AIR) {
continue;
}
@ -56,9 +56,9 @@ public class Commandcondense extends EssentialsCommand {
user.getBase().updateInventory();
if (didConvert) {
user.sendMessage(tl("itemsConverted"));
user.sendTl("itemsConverted");
} else {
user.sendMessage(tl("itemsNotConverted"));
user.sendTl("itemsNotConverted");
throw new NoChargeException();
}
}
@ -84,7 +84,7 @@ public class Commandcondense extends EssentialsCommand {
int amount = 0;
for (final ItemStack contents : user.getBase().getInventory().getContents()) {
for (final ItemStack contents : Inventories.getInventory(user.getBase(), false)) {
if (contents != null && contents.isSimilar(stack)) {
amount += contents.getAmount();
}
@ -161,8 +161,7 @@ public class Commandcondense extends EssentialsCommand {
iter.remove();
continue;
}
if (inputSlot.getDurability() == Short.MAX_VALUE) {
if (VersionUtil.PRE_FLATTENING && inputSlot.getDurability() == Short.MAX_VALUE) {
inputSlot.setDurability((short) 0);
}
if (!inputSlot.isSimilar(stack)) {

View File

@ -2,8 +2,10 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.PasteUtil;
import net.ess3.api.TranslatableException;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
@ -20,7 +22,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
public class Commandcreatekit extends EssentialsCommand {
public Commandcreatekit() {
@ -37,13 +39,13 @@ public class Commandcreatekit extends EssentialsCommand {
// Command handler will auto fail if this fails.
final long delay = Long.parseLong(args[1]);
final String kitname = args[0];
final ItemStack[] items = user.getBase().getInventory().getContents();
final ItemStack[] items = Inventories.getInventory(user.getBase(), true);
final List<String> list = new ArrayList<>();
boolean useSerializationProvider = ess.getSettings().isUseBetterKits();
if (useSerializationProvider && ess.getSerializationProvider() == null) {
ess.showError(user.getSource(), new Exception(tl("createKitUnsupported")), commandLabel);
ess.showError(user.getSource(), new TranslatableException("createKitUnsupported"), commandLabel);
useSerializationProvider = false;
}
@ -61,7 +63,7 @@ public class Commandcreatekit extends EssentialsCommand {
// 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));
user.sendTl("createdKit", kitname, list.size(), delay);
} else {
uploadPaste(user.getSource(), kitname, delay, list);
}
@ -85,10 +87,10 @@ public class Commandcreatekit extends EssentialsCommand {
final CompletableFuture<PasteUtil.PasteResult> future = PasteUtil.createPaste(Collections.singletonList(new PasteUtil.PasteFile("kit_" + kitName + ".yml", fileContents)));
future.thenAccept(result -> {
if (result != null) {
final String separator = tl("createKitSeparator");
final String separator = tlLiteral("createKitSeparator");
final String delayFormat = delay <= 0 ? "0" : DateUtil.formatDateDiff(System.currentTimeMillis() + (delay * 1000));
sender.sendMessage(separator);
sender.sendMessage(tl("createKitSuccess", kitName, delayFormat, result.getPasteUrl()));
sender.sendTl("createKitSuccess", kitName, delayFormat, result.getPasteUrl());
sender.sendMessage(separator);
if (ess.getSettings().isDebug()) {
ess.getLogger().info(sender.getSender().getName() + " created a kit: " + result.getPasteUrl());
@ -96,12 +98,12 @@ public class Commandcreatekit extends EssentialsCommand {
}
});
future.exceptionally(throwable -> {
sender.sendMessage(tl("createKitFailed", kitName));
sender.sendTl("createKitFailed", kitName);
ess.getLogger().log(Level.SEVERE, "Error creating kit: ", throwable);
return null;
});
} catch (Exception e) {
sender.sendMessage(tl("createKitFailed", kitName));
sender.sendTl("createKitFailed", kitName);
ess.getLogger().log(Level.SEVERE, "Error creating kit: ", e);
}
});

View File

@ -3,6 +3,9 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.IUser;
import com.earth2me.essentials.User;
import net.ess3.api.TranslatableException;
import net.essentialsx.api.v2.events.HomeModifyEvent;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import java.util.ArrayList;
@ -10,8 +13,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commanddelhome extends EssentialsCommand {
public Commanddelhome() {
super("delhome");
@ -37,25 +38,34 @@ public class Commanddelhome extends EssentialsCommand {
if (expandedArg.length > 1 && (user == null || user.isAuthorized("essentials.delhome.others"))) {
user = getPlayer(server, expandedArg, 0, true, true);
name = expandedArg[1];
name = expandedArg[1].toLowerCase(Locale.ENGLISH);
} else if (user == null) {
throw new NotEnoughArgumentsException();
} else {
name = expandedArg[0];
name = expandedArg[0].toLowerCase(Locale.ENGLISH);
}
if (name.equalsIgnoreCase("bed")) {
throw new Exception(tl("invalidHomeName"));
if (name.equals("bed")) {
throw new TranslatableException("invalidHomeName");
}
user.delHome(name.toLowerCase(Locale.ENGLISH));
sender.sendMessage(tl("deleteHome", name));
final HomeModifyEvent event = new HomeModifyEvent(sender.getUser(), user, name, user.getHome(name), false);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
if (ess.getSettings().isDebug()) {
ess.getLogger().info("HomeModifyEvent canceled for /delhome execution by " + sender.getDisplayName());
}
return;
}
user.delHome(name);
sender.sendTl("deleteHome", name);
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
final IUser user = sender.getUser(ess);
final boolean canDelOthers = sender.isAuthorized("essentials.delhome.others", ess);
final IUser user = sender.getUser();
final boolean canDelOthers = sender.isAuthorized("essentials.delhome.others");
if (args.length == 1) {
final List<String> homes = user == null ? new ArrayList<>() : user.getHomes();
if (canDelOthers) {

View File

@ -1,14 +1,13 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import net.ess3.api.TranslatableException;
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 Commanddeljail extends EssentialsCommand {
public Commanddeljail() {
super("deljail");
@ -21,11 +20,11 @@ public class Commanddeljail extends EssentialsCommand {
}
if (ess.getJails().getJail(args[0]) == null) {
throw new Exception(tl("jailNotExist"));
throw new TranslatableException("jailNotExist");
}
ess.getJails().removeJail(args[0]);
sender.sendMessage(tl("deleteJail", args[0]));
sender.sendTl("deleteJail", args[0]);
}
@Override

View File

@ -8,8 +8,6 @@ import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commanddelkit extends EssentialsCommand {
public Commanddelkit() {
super("delkit");
@ -19,7 +17,7 @@ public class Commanddelkit extends EssentialsCommand {
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length == 0) {
final String kitList = ess.getKits().listKits(ess, null);
sender.sendMessage(kitList.length() > 0 ? tl("kits", kitList) : tl("noKits"));
sender.sendTl(kitList.length() > 0 ? "kits" : "noKits", kitList);
throw new NoChargeException();
} else {
final String kitName = ess.getKits().matchKit(args[0]);
@ -30,7 +28,7 @@ public class Commanddelkit extends EssentialsCommand {
}
ess.getKits().removeKit(kitName);
sender.sendMessage(tl("deleteKit", kitName));
sender.sendTl("deleteKit", kitName);
}
}

View File

@ -1,6 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import net.ess3.api.TranslatableException;
import net.essentialsx.api.v2.events.WarpModifyEvent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -10,8 +11,6 @@ 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");
@ -31,15 +30,15 @@ public class Commanddelwarp extends EssentialsCommand {
// World is unloaded/deleted
location = null;
}
final WarpModifyEvent event = new WarpModifyEvent(sender.getUser(this.ess), args[0], location, null, WarpModifyEvent.WarpModifyCause.DELETE);
final WarpModifyEvent event = new WarpModifyEvent(sender.getUser(), args[0], location, null, WarpModifyEvent.WarpModifyCause.DELETE);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
ess.getWarps().removeWarp(args[0]);
sender.sendMessage(tl("deleteWarp", args[0]));
sender.sendTl("deleteWarp", args[0]);
} else {
throw new Exception(tl("warpNotExist"));
throw new TranslatableException("warpNotExist");
}
}

View File

@ -3,8 +3,6 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import static com.earth2me.essentials.I18n.tl;
public class Commanddepth extends EssentialsCommand {
public Commanddepth() {
super("depth");
@ -14,11 +12,11 @@ public class Commanddepth extends EssentialsCommand {
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final int depth = user.getLocation().getBlockY() - user.getWorld().getSeaLevel();
if (depth > 0) {
user.sendMessage(tl("depthAboveSea", depth));
user.sendTl("depthAboveSea", depth);
} else if (depth < 0) {
user.sendMessage(tl("depthBelowSea", -depth));
user.sendTl("depthBelowSea", -depth);
} else {
user.sendMessage(tl("depth"));
user.sendTl("depth");
}
}
}

View File

@ -3,8 +3,6 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import org.bukkit.Server;
import static com.earth2me.essentials.I18n.tl;
public class Commanddisposal extends EssentialsCommand {
public Commanddisposal() {
@ -13,8 +11,8 @@ public class Commanddisposal extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
user.sendMessage(tl("openingDisposal"));
user.getBase().openInventory(ess.getServer().createInventory(user.getBase(), 36, tl("disposal")));
user.sendTl("openingDisposal");
user.getBase().openInventory(ess.getServer().createInventory(user.getBase(), 36, user.playerTl("disposal")));
}
}

View File

@ -6,6 +6,7 @@ import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import net.ess3.api.MaxMoneyException;
import net.ess3.api.TranslatableException;
import net.ess3.api.events.UserBalanceUpdateEvent;
import org.bukkit.Server;
@ -14,8 +15,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commandeco extends EssentialsLoopCommand {
public Commandeco() {
@ -54,7 +53,7 @@ public class Commandeco extends EssentialsLoopCommand {
if (player.getMoney().subtract(userAmount).compareTo(ess.getSettings().getMinMoney()) >= 0) {
player.takeMoney(userAmount, sender, UserBalanceUpdateEvent.Cause.COMMAND_ECO);
} else {
ess.showError(sender, new Exception(tl("minimumBalanceError", NumberUtil.displayCurrency(ess.getSettings().getMinMoney(), ess))), commandLabel);
ess.showError(sender, new TranslatableException("minimumBalanceError", NumberUtil.displayCurrency(ess.getSettings().getMinMoney(), ess)), commandLabel);
}
break;
}
@ -65,8 +64,8 @@ public class Commandeco extends EssentialsLoopCommand {
final boolean underMin = userAmount.compareTo(minBal) < 0;
final boolean aboveMax = userAmount.compareTo(maxBal) > 0;
player.setMoney(underMin ? minBal : aboveMax ? maxBal : userAmount, UserBalanceUpdateEvent.Cause.COMMAND_ECO);
player.sendMessage(tl("setBal", NumberUtil.displayCurrency(player.getMoney(), ess)));
sender.sendMessage(tl("setBalOthers", player.getDisplayName(), NumberUtil.displayCurrency(player.getMoney(), ess)));
player.sendTl("setBal", NumberUtil.displayCurrency(player.getMoney(), ess));
sender.sendTl("setBalOthers", player.getDisplayName(), NumberUtil.displayCurrency(player.getMoney(), ess));
break;
}
}

View File

@ -3,17 +3,27 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.Lists;
import net.ess3.api.TranslatableException;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Server;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.HangingSign;
import org.bukkit.block.data.type.WallHangingSign;
import org.bukkit.block.data.type.WallSign;
import org.bukkit.block.sign.Side;
import org.bukkit.entity.Player;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.util.Vector;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandeditsign extends EssentialsCommand {
public Commandeditsign() {
super("editsign");
@ -27,67 +37,109 @@ public class Commandeditsign extends EssentialsCommand {
final Block target = user.getTargetBlock(5); //5 is a good number
if (!(target.getState() instanceof Sign)) {
throw new Exception(tl("editsignCommandTarget"));
throw new TranslatableException("editsignCommandTarget");
}
final Sign sign = (Sign) target.getState();
final ModifiableSign sign = wrapSign((Sign) target.getState(), user);
try {
if (args[0].equalsIgnoreCase("set") && args.length > 2) {
final String[] existingLines = sign.getLines();
final int line = Integer.parseInt(args[1]) - 1;
final String text = FormatUtil.formatString(user, "essentials.editsign", getFinalArg(args, 2)).trim();
if (ChatColor.stripColor(text).length() > 15 && !user.isAuthorized("essentials.editsign.unlimited")) {
throw new Exception(tl("editsignCommandLimit"));
throw new TranslatableException("editsignCommandLimit");
}
sign.setLine(line, text);
sign.update();
user.sendMessage(tl("editsignCommandSetSuccess", line + 1, text));
existingLines[line] = text;
if (callSignEvent(sign, user.getBase(), existingLines)) {
return;
}
user.sendTl("editsignCommandSetSuccess", line + 1, text);
} else if (args[0].equalsIgnoreCase("clear")) {
if (args.length == 1) {
final String[] existingLines = sign.getLines();
for (int i = 0; i < 4; i++) { // A whole one line of line savings!
sign.setLine(i, "");
existingLines[i] = "";
}
sign.update();
user.sendMessage(tl("editsignCommandClear"));
if (callSignEvent(sign, user.getBase(), existingLines)) {
return;
}
user.sendTl("editsignCommandClear");
} else {
final String[] existingLines = sign.getLines();
final int line = Integer.parseInt(args[1]) - 1;
sign.setLine(line, "");
sign.update();
user.sendMessage(tl("editsignCommandClearLine", line + 1));
existingLines[line] = "";
if (callSignEvent(sign, user.getBase(), existingLines)) {
return;
}
user.sendTl("editsignCommandClearLine", line + 1);
}
} else if (args[0].equalsIgnoreCase("copy") || args[0].equalsIgnoreCase("paste")) {
final boolean copy = args[0].equalsIgnoreCase("copy");
final String tlPrefix = copy ? "editsignCopy" : "editsignPaste";
} else if (args[0].equalsIgnoreCase("copy")) {
final int line = args.length == 1 ? -1 : Integer.parseInt(args[1]) - 1;
if (line == -1) {
for (int i = 0; i < 4; i++) {
processSignCopyPaste(user, sign, i, copy);
// We use unformat here to prevent players from copying signs with colors that they do not have permission to use.
user.getSignCopy().set(i, FormatUtil.unformatString(user, "essentials.editsign", sign.getLine(i)));
}
user.sendMessage(tl(tlPrefix, commandLabel));
user.sendTl("editsignCopy", commandLabel);
} else {
processSignCopyPaste(user, sign, line, copy);
user.sendMessage(tl(tlPrefix + "Line", line + 1, commandLabel));
// We use unformat here to prevent players from copying signs with colors that they do not have permission to use.
user.getSignCopy().set(line, FormatUtil.unformatString(user, "essentials.editsign", sign.getLine(line)));
user.sendTl("editsignCopyLine", line + 1, commandLabel);
}
if (!copy) {
sign.update();
} else if (args[0].equalsIgnoreCase("paste")) {
final int line = args.length == 1 ? -1 : Integer.parseInt(args[1]) - 1;
final String[] existingLines = sign.getLines();
if (line == -1) {
for (int i = 0; i < 4; i++) {
existingLines[i] = FormatUtil.formatString(user, "essentials.editsign", user.getSignCopy().get(i));
}
user.sendTl("editsignPaste", commandLabel);
} else {
existingLines[line] = FormatUtil.formatString(user, "essentials.editsign", user.getSignCopy().get(line));
user.sendTl("editsignPasteLine", line + 1, commandLabel);
}
callSignEvent(sign, user.getBase(), existingLines);
} else {
throw new NotEnoughArgumentsException();
}
} catch (final IndexOutOfBoundsException e) {
throw new Exception(tl("editsignCommandNoLine"), e);
throw new TranslatableException(e, "editsignCommandNoLine");
}
}
private void processSignCopyPaste(final User user, final Sign sign, final int index, final boolean copy) {
if (copy) {
// We use unformat here to prevent players from copying signs with colors that they do not have permission to use.
user.getSignCopy().set(index, FormatUtil.unformatString(user, "essentials.editsign", sign.getLine(index)));
return;
private boolean callSignEvent(final ModifiableSign sign, final Player player, final String[] lines) {
final SignChangeEvent event;
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_20_1_R01)) {
if (sign.isWaxed() && !player.hasPermission("essentials.editsign.waxed.exempt")) {
return true;
}
event = new SignChangeEvent(sign.getBlock(), player, lines, sign.isFront() ? Side.FRONT : Side.BACK);
} else {
//noinspection deprecation
event = new SignChangeEvent(sign.getBlock(), player, lines);
}
final String line = FormatUtil.formatString(user, "essentials.editsign", user.getSignCopy().get(index));
sign.setLine(index, line == null ? "" : line);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
if (ess.getSettings().isDebug()) {
ess.getLogger().info("SignChangeEvent canceled for /editsign execution by " + player.getName());
}
return true;
}
for (int i = 0; i < 4; i++) {
sign.setLine(i, lines[i]);
}
sign.update();
return false;
}
@Override
@ -100,7 +152,7 @@ public class Commandeditsign extends EssentialsCommand {
final int line = Integer.parseInt(args[1]);
final Block target = user.getTargetBlock(5);
if (target.getState() instanceof Sign && line <= 4) {
final Sign sign = (Sign) target.getState();
final ModifiableSign sign = wrapSign((Sign) target.getState(), user);
return Lists.newArrayList(FormatUtil.unformatString(user, "essentials.editsign", sign.getLine(line - 1)));
}
return Collections.emptyList();
@ -108,4 +160,105 @@ public class Commandeditsign extends EssentialsCommand {
return Collections.emptyList();
}
}
private ModifiableSign wrapSign(final Sign sign, final User user) {
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_20_1_R01)) {
final Vector eyeLocLessSign = user.getBase().getEyeLocation().toVector().subtract(sign.getLocation().add(.5, .5, .5).toVector());
final BlockData signBlockData = sign.getBlockData();
final BlockFace signDirection;
if (signBlockData instanceof org.bukkit.block.data.type.Sign) {
signDirection = ((org.bukkit.block.data.type.Sign) signBlockData).getRotation();
} else if (signBlockData instanceof WallSign) {
signDirection = ((WallSign) signBlockData).getFacing();
} else if (signBlockData instanceof HangingSign) {
signDirection = ((HangingSign) signBlockData).getRotation();
} else if (signBlockData instanceof WallHangingSign) {
signDirection = ((WallHangingSign) signBlockData).getFacing();
} else {
throw new IllegalStateException("Unknown block data for sign: " + signBlockData.getClass());
}
final Side side = eyeLocLessSign.dot(signDirection.getDirection()) > 0 ? Side.FRONT : Side.BACK;
return new ModifiableSign(sign) {
@Override
String[] getLines() {
return sign.getSide(side).getLines();
}
@Override
String getLine(int line) {
return sign.getSide(side).getLine(line);
}
@Override
void setLine(int line, String text) {
sign.getSide(side).setLine(line, text);
}
@Override
boolean isFront() {
return side == Side.FRONT;
}
@Override
boolean isWaxed() {
return sign.isWaxed();
}
};
}
return new ModifiableSign(sign) {
@Override
String[] getLines() {
return sign.getLines();
}
@Override
String getLine(int line) {
return sign.getLine(line);
}
@Override
void setLine(int line, String text) {
sign.setLine(line, text);
}
@Override
boolean isFront() {
return true;
}
@Override
boolean isWaxed() {
return false;
}
};
}
private abstract static class ModifiableSign {
protected final Sign sign;
protected ModifiableSign(final Sign sign) {
this.sign = sign;
}
abstract String getLine(int line);
abstract String[] getLines();
abstract void setLine(int line, String text);
abstract boolean isFront();
abstract boolean isWaxed();
Block getBlock() {
return sign.getBlock();
}
void update() {
sign.update();
}
}
}

View File

@ -3,9 +3,9 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.Enchantments;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.collect.Lists;
import net.ess3.api.TranslatableException;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.enchantments.Enchantment;
@ -19,8 +19,6 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import static com.earth2me.essentials.I18n.tl;
public class Commandenchant extends EssentialsCommand {
public Commandenchant() {
super("enchant");
@ -31,7 +29,7 @@ public class Commandenchant extends EssentialsCommand {
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final ItemStack stack = user.getItemInHand();
if (stack == null || stack.getType() == Material.AIR) {
throw new Exception(tl("nothingInHand"));
throw new TranslatableException("nothingInHand");
}
if (args.length == 0) {
@ -42,7 +40,7 @@ public class Commandenchant extends EssentialsCommand {
usableEnchants.add(entry.getKey());
}
}
throw new NotEnoughArgumentsException(tl("enchantments", StringUtil.joinList(usableEnchants.toArray())));
throw new NotEnoughArgumentsException(user.playerTl("enchantments", StringUtil.joinList(usableEnchants.toArray())));
}
int level = 1;
@ -57,13 +55,13 @@ public class Commandenchant extends EssentialsCommand {
final MetaItemStack metaStack = new MetaItemStack(stack);
final Enchantment enchantment = metaStack.getEnchantment(user, args[0]);
metaStack.addEnchantment(user.getSource(), ess.getSettings().allowUnsafeEnchantments() && user.isAuthorized("essentials.enchantments.allowunsafe"), enchantment, level);
InventoryWorkaround.setItemInMainHand(user.getBase(), metaStack.getItemStack());
stack.setItemMeta(metaStack.getItemStack().getItemMeta());
user.getBase().updateInventory();
final String enchantName = enchantment.getName().toLowerCase(Locale.ENGLISH).replace('_', ' ');
if (level == 0) {
user.sendMessage(tl("enchantmentRemoved", enchantName));
user.sendTl("enchantmentRemoved", enchantName);
} else {
user.sendMessage(tl("enchantmentApplied", enchantName));
user.sendTl("enchantmentApplied", enchantName);
}
}

View File

@ -3,34 +3,42 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.EssentialsUpgrade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.UserMap;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.economy.EconomyLayer;
import com.earth2me.essentials.economy.EconomyLayers;
import com.earth2me.essentials.userstorage.ModernUserMap;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.CommandMapUtil;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.FloatUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.PasteUtil;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.gson.JsonArray;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import net.ess3.api.TranslatableException;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.nio.charset.StandardCharsets;
@ -42,15 +50,19 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.stream.Collectors;
import static com.earth2me.essentials.I18n.tl;
import static com.earth2me.essentials.I18n.tlLiteral;
// This command has 4 undocumented behaviours #EasterEgg
public class Commandessentials extends EssentialsCommand {
@ -76,12 +88,18 @@ public class Commandessentials extends EssentialsCommand {
"PermissionsEx", // permissions (unsupported)
"GroupManager", // permissions (unsupported)
"bPermissions", // permissions (unsupported)
"DiscordSRV" // potential for issues if EssentialsXDiscord is installed
"DiscordSRV", // potential for issues if EssentialsXDiscord is installed
// Chat signing bypass plugins that can potentially break EssentialsChat
"AntiPopup",
"NoChatReports",
"NoEncryption"
);
private static final List<String> officialPlugins = Arrays.asList(
"EssentialsAntiBuild",
"EssentialsChat",
"EssentialsDiscord",
"EssentialsDiscordLink",
"EssentialsGeoIP",
"EssentialsProtect",
"EssentialsSpawn",
@ -90,7 +108,11 @@ public class Commandessentials extends EssentialsCommand {
private static final List<String> warnPlugins = Arrays.asList(
"PermissionsEx",
"GroupManager",
"bPermissions"
"bPermissions",
// Brain-dead chat signing bypass that break EssentialsChat
"NoChatReports",
"NoEncryption"
);
private transient TuneRunnable currentTune = null;
@ -135,11 +157,12 @@ public class Commandessentials extends EssentialsCommand {
case "homes":
runHomes(server, sender, commandLabel, args);
break;
case "uuidconvert":
runUUIDConvert(server, sender, commandLabel, args);
case "usermap":
runUserMap(sender, args);
break;
case "uuidtest":
runUUIDTest(server, sender, commandLabel, args);
case "itemtest":
runItemTest(server, sender, commandLabel, args);
break;
// "#EasterEgg"
@ -156,6 +179,56 @@ public class Commandessentials extends EssentialsCommand {
}
}
public void runItemTest(Server server, CommandSource sender, String commandLabel, String[] args) {
if (!sender.isAuthorized("essentials.itemtest") || args.length < 2 || !sender.isPlayer()) {
return;
}
final Player player = sender.getPlayer();
assert player != null;
switch (args[1]) {
case "slot": {
if (args.length < 3) {
return;
}
player.getInventory().setItem(Integer.parseInt(args[2]), new ItemStack(Material.DIRT));
break;
}
case "overfill": {
sender.sendMessage(Inventories.addItem(player, 42, false, new ItemStack(Material.DIAMOND_SWORD, 1), new ItemStack(Material.DIRT, 32), new ItemStack(Material.DIRT, 32)).toString());
break;
}
case "overfill2": {
if (args.length < 4) {
return;
}
final boolean armor = Boolean.parseBoolean(args[2]);
final boolean add = Boolean.parseBoolean(args[3]);
final ItemStack[] items = new ItemStack[]{new ItemStack(Material.DIAMOND_SWORD, 1), new ItemStack(Material.DIRT, 32), new ItemStack(Material.DIRT, 32), new ItemStack(Material.DIAMOND_HELMET, 4), new ItemStack(Material.CHAINMAIL_LEGGINGS, 1)};
if (Inventories.hasSpace(player, 0, armor, items)) {
if (add) {
sender.sendMessage(Inventories.addItem(player, 0, armor, items).toString());
}
sender.sendMessage("SO MUCH SPACE!");
} else {
sender.sendMessage("No space!");
}
break;
}
case "remove": {
if (args.length < 3) {
return;
}
Inventories.removeItemExact(player, new ItemStack(Material.PUMPKIN, 1), Boolean.parseBoolean(args[2]));
break;
}
default: {
break;
}
}
}
// Displays the command's usage.
private void showUsage(final CommandSource sender) throws Exception {
throw new NotEnoughArgumentsException();
@ -164,11 +237,11 @@ public class Commandessentials extends EssentialsCommand {
// Lists commands that are being handed over to other plugins.
private void runCommands(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (ess.getAlternativeCommandsHandler().disabledCommands().size() == 0) {
sender.sendMessage(tl("blockListEmpty"));
sender.sendTl("blockListEmpty");
return;
}
sender.sendMessage(tl("blockList"));
sender.sendTl("blockList");
for (final Map.Entry<String, String> entry : ess.getAlternativeCommandsHandler().disabledCommands().entrySet()) {
sender.sendMessage(entry.getKey() + " => " + entry.getValue());
}
@ -176,7 +249,7 @@ public class Commandessentials extends EssentialsCommand {
// Generates a paste of useful information
private void runDump(Server server, CommandSource sender, String commandLabel, String[] args) {
sender.sendMessage(tl("dumpCreating"));
sender.sendTl("dumpCreating");
final JsonObject dump = new JsonObject();
@ -258,6 +331,11 @@ public class Commandessentials extends EssentialsCommand {
files.add(new PasteUtil.PasteFile("dump.json", dump.toString()));
final Plugin essDiscord = Bukkit.getPluginManager().getPlugin("EssentialsDiscord");
final Plugin essDiscordLink = Bukkit.getPluginManager().getPlugin("EssentialsDiscordLink");
final Plugin essSpawn = Bukkit.getPluginManager().getPlugin("EssentialsSpawn");
final Map<String, Command> knownCommandsCopy = new HashMap<>(ess.getKnownCommandsProvider().getKnownCommands());
final Map<String, String> disabledCommandsCopy = new HashMap<>(ess.getAlternativeCommandsHandler().disabledCommands());
// Further operations will be heavy IO
ess.runTaskAsynchronously(() -> {
@ -265,12 +343,20 @@ public class Commandessentials extends EssentialsCommand {
boolean discord = false;
boolean kits = false;
boolean log = false;
boolean worth = false;
boolean tpr = false;
boolean spawns = false;
boolean commands = false;
for (final String arg : args) {
if (arg.equals("*") || arg.equalsIgnoreCase("all")) {
config = true;
discord = true;
kits = true;
log = true;
worth = true;
tpr = true;
spawns = true;
commands = true;
break;
} else if (arg.equalsIgnoreCase("config")) {
config = true;
@ -280,6 +366,14 @@ public class Commandessentials extends EssentialsCommand {
kits = true;
} else if (arg.equalsIgnoreCase("log")) {
log = true;
} else if (arg.equalsIgnoreCase("worth")) {
worth = true;
} else if (arg.equalsIgnoreCase("tpr")) {
tpr = true;
} else if (arg.equalsIgnoreCase("spawns")) {
spawns = true;
} else if (arg.equalsIgnoreCase("commands")) {
commands = true;
}
}
@ -287,7 +381,7 @@ public class Commandessentials extends EssentialsCommand {
try {
files.add(new PasteUtil.PasteFile("config.yml", new String(Files.readAllBytes(ess.getSettings().getConfigFile().toPath()), StandardCharsets.UTF_8)));
} catch (IOException e) {
sender.sendMessage(tl("dumpErrorUpload", "config.yml", e.getMessage()));
sender.sendTl("dumpErrorUpload", "config.yml", e.getMessage());
}
}
@ -297,7 +391,16 @@ public class Commandessentials extends EssentialsCommand {
new String(Files.readAllBytes(essDiscord.getDataFolder().toPath().resolve("config.yml")), StandardCharsets.UTF_8)
.replaceAll("[A-Za-z\\d]{24}\\.[\\w-]{6}\\.[\\w-]{27}", "<censored token>")));
} catch (IOException e) {
sender.sendMessage(tl("dumpErrorUpload", "discord-config.yml", e.getMessage()));
sender.sendTl("dumpErrorUpload", "discord-config.yml", e.getMessage());
}
if (essDiscordLink != null) {
try {
files.add(new PasteUtil.PasteFile("discord-link-config.yml",
new String(Files.readAllBytes(essDiscordLink.getDataFolder().toPath().resolve("config.yml")), StandardCharsets.UTF_8)));
} catch (IOException e) {
sender.sendTl("dumpErrorUpload", "discord-link-config.yml", e.getMessage());
}
}
}
@ -305,7 +408,7 @@ public class Commandessentials extends EssentialsCommand {
try {
files.add(new PasteUtil.PasteFile("kits.yml", new String(Files.readAllBytes(ess.getKits().getFile().toPath()), StandardCharsets.UTF_8)));
} catch (IOException e) {
sender.sendMessage(tl("dumpErrorUpload", "kits.yml", e.getMessage()));
sender.sendTl("dumpErrorUpload", "kits.yml", e.getMessage());
}
}
@ -315,7 +418,41 @@ public class Commandessentials extends EssentialsCommand {
.replaceAll("(?m)^\\[\\d\\d:\\d\\d:\\d\\d] \\[.+/(?:DEBUG|TRACE)]: .+\\s(?:[A-Za-z.]+:.+\\s(?:\\t.+\\s)*)?\\s*(?:\"[A-Za-z]+\" : .+[\\s}\\]]+)*", "")
.replaceAll("(?:[0-9]{1,3}\\.){3}[0-9]{1,3}", "<censored ip address>")));
} catch (IOException e) {
sender.sendMessage(tl("dumpErrorUpload", "latest.log", e.getMessage()));
sender.sendTl("dumpErrorUpload", "latest.log", e.getMessage());
}
}
if (worth) {
try {
files.add(new PasteUtil.PasteFile("worth.yml", new String(Files.readAllBytes(ess.getWorth().getFile().toPath()), StandardCharsets.UTF_8)));
} catch (IOException e) {
sender.sendTl("dumpErrorUpload", "worth.yml", e.getMessage());
}
}
if (tpr) {
try {
files.add(new PasteUtil.PasteFile("tpr.yml", new String(Files.readAllBytes(ess.getRandomTeleport().getFile().toPath()), StandardCharsets.UTF_8)));
} catch (IOException e) {
sender.sendTl("dumpErrorUpload", "tpr.yml", e.getMessage());
}
}
if (spawns && essSpawn != null) {
try {
files.add(new PasteUtil.PasteFile("spawn.yml", new String(Files.readAllBytes(ess.getDataFolder().toPath().resolve("spawn.yml")), StandardCharsets.UTF_8)));
} catch (IOException e) {
sender.sendTl("dumpErrorUpload", "spawn.yml", e.getMessage());
}
}
if (commands) {
try {
files.add(new PasteUtil.PasteFile("commands.yml", new String(Files.readAllBytes(Paths.get("commands.yml")), StandardCharsets.UTF_8)));
files.add(new PasteUtil.PasteFile("commandmap.json", CommandMapUtil.toJsonPretty(ess, knownCommandsCopy)));
files.add(new PasteUtil.PasteFile("commandoverride.json", disabledCommandsCopy.toString()));
} catch (IOException e) {
sender.sendTl("dumpErrorUpload", "commands.yml", e.getMessage());
}
}
@ -323,17 +460,17 @@ public class Commandessentials extends EssentialsCommand {
future.thenAccept(result -> {
if (result != null) {
final String dumpUrl = "https://essentialsx.net/dump.html?id=" + result.getPasteId();
sender.sendMessage(tl("dumpUrl", dumpUrl));
sender.sendMessage(tl("dumpDeleteKey", result.getDeletionKey()));
sender.sendTl("dumpUrl", dumpUrl);
sender.sendTl("dumpDeleteKey", result.getDeletionKey());
if (sender.isPlayer()) {
ess.getLogger().info(tl("dumpConsoleUrl", dumpUrl));
ess.getLogger().info(tl("dumpDeleteKey", result.getDeletionKey()));
ess.getLogger().info(AdventureUtil.miniToLegacy(tlLiteral("dumpConsoleUrl", dumpUrl)));
ess.getLogger().info(AdventureUtil.miniToLegacy(tlLiteral("dumpDeleteKey", result.getDeletionKey())));
}
}
files.clear();
});
future.exceptionally(throwable -> {
sender.sendMessage(tl("dumpError", throwable.getMessage()));
sender.sendTl("dumpError", throwable.getMessage());
return null;
});
});
@ -358,7 +495,7 @@ public class Commandessentials extends EssentialsCommand {
// Reloads all reloadable configs.
private void runReload(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
ess.reload();
sender.sendMessage(tl("essentialsReload", ess.getDescription().getVersion()));
sender.sendTl("essentialsReload", ess.getDescription().getVersion());
}
// Pop tarts.
@ -375,7 +512,7 @@ public class Commandessentials extends EssentialsCommand {
private void runMoo(final Server server, final CommandSource sender, final String command, final String[] args) {
if (args.length == 2 && args[1].equals("moo")) {
for (final String s : CONSOLE_MOO) {
logger.info(s);
ess.getLogger().info(s);
}
for (final Player player : ess.getOnlinePlayers()) {
player.sendMessage(PLAYER_MOO);
@ -402,17 +539,16 @@ public class Commandessentials extends EssentialsCommand {
throw new Exception("/<command> cleanup <days> [money] [homes]");
}
sender.sendMessage(tl("cleaning"));
sender.sendTl("cleaning");
final long daysArg = Long.parseLong(args[1]);
final double moneyArg = args.length >= 3 ? FloatUtil.parseDouble(args[2].replaceAll("[^0-9\\.]", "")) : 0;
final double moneyArg = args.length >= 3 ? FloatUtil.parseDouble(args[2].replaceAll("[^0-9.]", "")) : 0;
final int homesArg = args.length >= 4 && NumberUtil.isInt(args[3]) ? Integer.parseInt(args[3]) : 0;
final UserMap userMap = ess.getUserMap();
ess.runTaskAsynchronously(() -> {
final long currTime = System.currentTimeMillis();
for (final UUID u : userMap.getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
for (final UUID u : ess.getUsers().getAllUserUUIDs()) {
final User user = ess.getUsers().loadUncachedUser(u);
if (user == null) {
continue;
}
@ -444,7 +580,7 @@ public class Commandessentials extends EssentialsCommand {
user.reset();
}
sender.sendMessage(tl("cleaned"));
sender.sendTl("cleaned");
});
}
@ -457,13 +593,12 @@ public class Commandessentials extends EssentialsCommand {
throw new Exception(HOMES_USAGE);
}
final UserMap userMap = ess.getUserMap();
switch (args[1]) {
case "fix":
sender.sendMessage(tl("fixingHomes"));
sender.sendTl("fixingHomes");
ess.runTaskAsynchronously(() -> {
for (final UUID u : userMap.getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
for (final UUID u : ess.getUsers().getAllUserUUIDs()) {
final User user = ess.getUsers().loadUncachedUser(u);
if (user == null) {
continue;
}
@ -477,18 +612,22 @@ public class Commandessentials extends EssentialsCommand {
}
}
}
sender.sendMessage(tl("fixedHomes"));
sender.sendTl("fixedHomes");
});
break;
case "delete":
final boolean filterByWorld = args.length >= 3;
if (filterByWorld && server.getWorld(args[2]) == null) {
throw new Exception(tl("invalidWorld"));
throw new TranslatableException("invalidWorld");
}
if (filterByWorld) {
sender.sendTl("deletingHomesWorld", args[2]);
} else {
sender.sendTl("deletingHomes");
}
sender.sendMessage(filterByWorld ? tl("deletingHomesWorld", args[2]) : tl("deletingHomes"));
ess.runTaskAsynchronously(() -> {
for (final UUID u : userMap.getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(u);
for (final UUID u : ess.getUsers().getAllUserUUIDs()) {
final User user = ess.getUsers().loadUncachedUser(u);
if (user == null) {
continue;
}
@ -503,7 +642,12 @@ public class Commandessentials extends EssentialsCommand {
}
}
}
sender.sendMessage(filterByWorld ? tl("deletedHomesWorld", args[2]) : tl("deletedHomes"));
if (filterByWorld) {
sender.sendTl("deletedHomesWorld", args[2]);
} else {
sender.sendTl("deletedHomes");
}
});
break;
default:
@ -511,52 +655,79 @@ public class Commandessentials extends EssentialsCommand {
}
}
// Forces a rerun of userdata UUID conversion.
private void runUUIDConvert(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
sender.sendMessage("Starting Essentials UUID userdata conversion; this may lag the server.");
final Boolean ignoreUFCache = args.length > 2 && args[1].toLowerCase(Locale.ENGLISH).contains("ignore");
EssentialsUpgrade.uuidFileConvert(ess, ignoreUFCache);
sender.sendMessage("UUID conversion complete. Check your server log for more information.");
}
// Looks up various UUIDs for a user.
private void runUUIDTest(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 2) {
throw new Exception("/<command> uuidtest <name>");
// Gets information about cached users
private void runUserMap(final CommandSource sender, final String[] args) {
if (!sender.isAuthorized("essentials.usermap")) {
return;
}
final String name = args[1];
sender.sendMessage("Looking up UUID for " + name);
UUID onlineUUID = null;
final ModernUserMap userMap = (ModernUserMap) ess.getUsers();
sender.sendTl("usermapSize", userMap.getCachedCount(), userMap.getUserCount(), ess.getSettings().getMaxUserCacheCount());
if (args.length > 1) {
if (args[1].equals("full")) {
for (final Map.Entry<String, UUID> entry : userMap.getNameCache().entrySet()) {
sender.sendTl("usermapEntry", entry.getKey(), entry.getValue().toString());
}
} else if (args[1].equals("purge")) {
final boolean seppuku = args.length > 2 && args[2].equals("iknowwhatimdoing");
for (final Player player : ess.getOnlinePlayers()) {
if (player.getName().equalsIgnoreCase(name)) {
onlineUUID = player.getUniqueId();
break;
sender.sendTl("usermapPurge", String.valueOf(seppuku));
final Set<UUID> uuids = new HashSet<>(ess.getUsers().getAllUserUUIDs());
ess.runTaskAsynchronously(() -> {
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
final File backupFolder = new File(ess.getDataFolder(), "userdata-npc-backup-boogaloo-" + System.currentTimeMillis());
if (!userdataFolder.isDirectory()) {
ess.getLogger().warning("Missing userdata folder, aborting usermap purge.");
return;
}
if (seppuku && !backupFolder.mkdir()) {
ess.getLogger().warning("Unable to create backup folder, aborting usermap purge.");
return;
}
int total = 0;
final File[] files = userdataFolder.listFiles(EssentialsUpgrade.YML_FILTER);
if (files != null) {
for (final File file : files) {
try {
final String fileName = file.getName();
final UUID uuid = UUID.fromString(fileName.substring(0, fileName.length() - 4));
if (!uuids.contains(uuid)) {
total++;
ess.getLogger().warning("Found orphaned userdata file: " + file.getName());
if (seppuku) {
try {
com.google.common.io.Files.move(file, new File(backupFolder, file.getName()));
} catch (IOException e) {
ess.getLogger().log(Level.WARNING, "Unable to move orphaned userdata file: " + file.getName(), e);
}
}
}
} catch (IllegalArgumentException ignored) {
}
}
}
ess.getLogger().info("Found " + total + " orphaned userdata files.");
});
} else if (args[1].equalsIgnoreCase("cache")) {
sender.sendTl("usermapKnown", ess.getUsers().getAllUserUUIDs().size(), ess.getUsers().getNameCache().size());
} else {
try {
final UUID uuid = UUID.fromString(args[1]);
for (final Map.Entry<String, UUID> entry : userMap.getNameCache().entrySet()) {
if (entry.getValue().equals(uuid)) {
sender.sendTl("usermapEntry", entry.getKey(), args[1]);
}
}
} catch (IllegalArgumentException ignored) {
final String sanitizedName = userMap.getSanitizedName(args[1]);
sender.sendTl("usermapEntry", sanitizedName, userMap.getNameCache().get(sanitizedName).toString());
}
}
}
final UUID essUUID = ess.getUserMap().getUser(name).getConfigUUID();
final org.bukkit.OfflinePlayer player = ess.getServer().getOfflinePlayer(name);
final UUID bukkituuid = player.getUniqueId();
sender.sendMessage("Bukkit Lookup: " + bukkituuid.toString());
if (onlineUUID != null && onlineUUID != bukkituuid) {
sender.sendMessage("Online player: " + onlineUUID.toString());
}
if (essUUID != null && essUUID != bukkituuid) {
sender.sendMessage("Essentials config: " + essUUID.toString());
}
final UUID npcuuid = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
sender.sendMessage("NPC UUID: " + npcuuid.toString());
final UUID offlineuuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8));
sender.sendMessage("Offline Mode UUID: " + offlineuuid.toString());
}
// Displays versions of EssentialsX and related plugins.
@ -579,9 +750,9 @@ public class Commandessentials extends EssentialsCommand {
serverMessageKey = "versionOutputWarn";
}
sender.sendMessage(tl(serverMessageKey, "Server", server.getBukkitVersion() + " " + server.getVersion()));
sender.sendMessage(tl(serverMessageKey, "Brand", server.getName()));
sender.sendMessage(tl("versionOutputFine", "EssentialsX", essVer));
sender.sendTl(serverMessageKey, "Server", server.getBukkitVersion() + " " + server.getVersion());
sender.sendTl(serverMessageKey, "Brand", server.getName());
sender.sendTl("versionOutputFine", "EssentialsX", essVer);
for (final Plugin plugin : pm.getPlugins()) {
final PluginDescriptionFile desc = plugin.getDescription();
@ -594,22 +765,22 @@ public class Commandessentials extends EssentialsCommand {
if (!version.equalsIgnoreCase(essVer)) {
isMismatched = true;
sender.sendMessage(tl("versionOutputWarn", name, version));
sender.sendTl("versionOutputWarn", name, version);
} else {
sender.sendMessage(tl("versionOutputFine", name, version));
sender.sendTl("versionOutputFine", name, version);
}
} else {
sender.sendMessage(tl("versionOutputUnsupported", name, version));
sender.sendTl("versionOutputUnsupported", name, version);
isUnsupported = true;
}
}
if (versionPlugins.contains(name)) {
if (warnPlugins.contains(name)) {
sender.sendMessage(tl("versionOutputUnsupported", name, version));
sender.sendTl("versionOutputUnsupported", name, version);
isUnsupported = true;
} else {
sender.sendMessage(tl("versionOutputFine", name, version));
sender.sendTl("versionOutputFine", name, version);
}
}
@ -625,45 +796,48 @@ public class Commandessentials extends EssentialsCommand {
} else {
layer = "None";
}
sender.sendMessage(tl("versionOutputEconLayer", layer));
sender.sendTl("versionOutputEconLayer", layer);
if (isMismatched) {
sender.sendMessage(tl("versionMismatchAll"));
sender.sendTl("versionMismatchAll");
}
if (!isVaultInstalled) {
sender.sendMessage(tl("versionOutputVaultMissing"));
sender.sendTl("versionOutputVaultMissing");
}
if (isUnsupported) {
sender.sendMessage(tl("versionOutputUnsupportedPlugins"));
sender.sendTl("versionOutputUnsupportedPlugins");
}
switch (supportStatus) {
case NMS_CLEANROOM:
sender.sendMessage(ChatColor.DARK_RED + tl("serverUnsupportedCleanroom"));
sender.sendComponent(sender.tlComponent("serverUnsupportedCleanroom").color(NamedTextColor.DARK_RED));
break;
case DANGEROUS_FORK:
sender.sendMessage(ChatColor.DARK_RED + tl("serverUnsupportedDangerous"));
sender.sendComponent(sender.tlComponent("serverUnsupportedDangerous").color(NamedTextColor.DARK_RED));
break;
case STUPID_PLUGIN:
sender.sendComponent(sender.tlComponent("serverUnsupportedDumbPlugins").color(NamedTextColor.DARK_RED));
break;
case UNSTABLE:
sender.sendMessage(ChatColor.DARK_RED + tl("serverUnsupportedMods"));
sender.sendComponent(sender.tlComponent("serverUnsupportedMods").color(NamedTextColor.DARK_RED));
break;
case OUTDATED:
sender.sendMessage(ChatColor.RED + tl("serverUnsupported"));
sender.sendComponent(sender.tlComponent("serverUnsupported").color(NamedTextColor.RED));
break;
case LIMITED:
sender.sendMessage(ChatColor.RED + tl("serverUnsupportedLimitedApi"));
sender.sendComponent(sender.tlComponent("serverUnsupportedLimitedApi").color(NamedTextColor.RED));
break;
}
if (VersionUtil.getSupportStatusClass() != null) {
sender.sendMessage(ChatColor.RED + tl("serverUnsupportedClass", VersionUtil.getSupportStatusClass()));
sender.sendComponent(sender.tlComponent("serverUnsupportedClass").color(NamedTextColor.RED));
}
sender.sendMessage(tl("versionFetching"));
sender.sendTl("versionFetching");
ess.runTaskAsynchronously(() -> {
for (String str : ess.getUpdateChecker().getVersionMessages(true, true)) {
sender.sendMessage(str);
for (final Component component : ess.getUpdateChecker().getVersionMessages(true, true, sender)) {
sender.sendComponent(component);
}
});
}
@ -681,7 +855,6 @@ public class Commandessentials extends EssentialsCommand {
options.add("cleanup");
options.add("homes");
//options.add("uuidconvert");
//options.add("uuidtest");
//options.add("nya");
//options.add("moo");
return options;
@ -694,7 +867,6 @@ public class Commandessentials extends EssentialsCommand {
}
break;
case "reset":
case "uuidtest":
if (args.length == 2) {
return getPlayers(server, sender);
}
@ -713,13 +885,8 @@ public class Commandessentials extends EssentialsCommand {
return server.getWorlds().stream().map(World::getName).collect(Collectors.toList());
}
break;
case "uuidconvert":
if (args.length == 2) {
return Lists.newArrayList("ignoreUFCache");
}
break;
case "dump":
final List<String> list = Lists.newArrayList("config", "kits", "log", "discord", "all");
final List<String> list = Lists.newArrayList("config", "kits", "log", "discord", "worth", "tpr", "spawns", "commands", "all");
for (String arg : args) {
if (arg.equals("*") || arg.equalsIgnoreCase("all")) {
list.clear();

View File

@ -13,8 +13,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commandexp extends EssentialsLoopCommand {
public Commandexp() {
super("exp");
@ -22,7 +20,7 @@ public class Commandexp extends EssentialsLoopCommand {
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
final IUser user = sender.getUser(ess);
final IUser user = sender.getUser();
if (args.length == 0 || (args.length < 2 && user == null)) {
if (user == null) {
throw new NotEnoughArgumentsException();
@ -39,7 +37,7 @@ public class Commandexp extends EssentialsLoopCommand {
}
if (!cmd.hasPermission(user)) {
user.sendMessage(tl("noAccessSubCommand", "/" + commandLabel + " " + cmd.name().toLowerCase(Locale.ENGLISH)));
user.sendTl("noAccessSubCommand", "/" + commandLabel + " " + cmd.name().toLowerCase(Locale.ENGLISH));
return;
}
@ -99,7 +97,7 @@ public class Commandexp extends EssentialsLoopCommand {
}
private void showExp(final CommandSource sender, final IUser target) {
sender.sendMessage(tl("exp", target.getDisplayName(), SetExpFix.getTotalExperience(target.getBase()), target.getBase().getLevel(), SetExpFix.getExpUntilNextLevel(target.getBase())));
sender.sendTl("exp", target.getDisplayName(), SetExpFix.getTotalExperience(target.getBase()), target.getBase().getLevel(), SetExpFix.getExpUntilNextLevel(target.getBase()));
}
//TODO: Limit who can give negative exp?
@ -131,7 +129,7 @@ public class Commandexp extends EssentialsLoopCommand {
amount = 0L;
}
SetExpFix.setTotalExperience(target.getBase(), (int) amount);
sender.sendMessage(tl("expSet", target.getDisplayName(), amount));
sender.sendTl("expSet", target.getDisplayName(), amount);
}
@Override

View File

@ -8,8 +8,6 @@ import org.bukkit.entity.Player;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandext extends EssentialsLoopCommand {
public Commandext() {
super("ext");
@ -32,13 +30,13 @@ public class Commandext extends EssentialsLoopCommand {
}
extPlayer(user.getBase());
user.sendMessage(tl("extinguish"));
user.sendTl("extinguish");
}
@Override
protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) {
extPlayer(player.getBase());
sender.sendMessage(tl("extinguishOthers", player.getDisplayName()));
sender.sendTl("extinguishOthers", player.getDisplayName());
}
private void extPlayer(final Player player) {

View File

@ -9,8 +9,6 @@ import org.bukkit.event.entity.FoodLevelChangeEvent;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandfeed extends EssentialsLoopCommand {
public Commandfeed() {
super("feed");
@ -28,7 +26,7 @@ public class Commandfeed extends EssentialsLoopCommand {
}
feedPlayer(user.getBase());
user.sendMessage(tl("feed"));
user.sendTl("feed");
}
@Override
@ -44,7 +42,7 @@ public class Commandfeed extends EssentialsLoopCommand {
protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) throws PlayerExemptException {
try {
feedPlayer(player.getBase());
sender.sendMessage(tl("feedOther", player.getDisplayName()));
sender.sendTl("feedOther", player.getDisplayName());
} catch (final QuietAbortException e) {
//Handle Quietly
}
@ -66,7 +64,7 @@ public class Commandfeed extends EssentialsLoopCommand {
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1 && sender.isAuthorized("essentials.feed.others", ess)) {
if (args.length == 1 && sender.isAuthorized("essentials.feed.others")) {
return getPlayers(server, sender);
} else {
return Collections.emptyList();

View File

@ -5,6 +5,7 @@ import com.earth2me.essentials.utils.FloatUtil;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import net.ess3.api.TranslatableException;
import org.bukkit.Server;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.DragonFireball;
@ -27,8 +28,6 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.earth2me.essentials.I18n.tl;
public class Commandfireball extends EssentialsCommand {
public static final String FIREBALL_META_KEY = "ess_fireball_proj";
@ -78,7 +77,7 @@ public class Commandfireball extends EssentialsCommand {
}
if (!user.isAuthorized("essentials.fireball." + type)) {
throw new Exception(tl("noPerm", "essentials.fireball." + type));
throw new TranslatableException("noPerm", "essentials.fireball." + type);
}
final Vector direction = user.getBase().getEyeLocation().getDirection().multiply(speed);

View File

@ -5,6 +5,7 @@ import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import net.ess3.api.TranslatableException;
import org.bukkit.DyeColor;
import org.bukkit.FireworkEffect;
import org.bukkit.Server;
@ -17,8 +18,6 @@ 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
@ -49,21 +48,21 @@ public class Commandfirework extends EssentialsCommand {
final ItemStack stack = user.getItemInHand();
if (!MaterialUtil.isFirework(stack.getType())) {
throw new Exception(tl("holdFirework"));
throw new TranslatableException("holdFirework");
}
if (args[0].equalsIgnoreCase("clear")) {
final FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
fmeta.clearEffects();
stack.setItemMeta(fmeta);
user.sendMessage(tl("fireworkEffectsCleared"));
user.sendTl("fireworkEffectsCleared");
} else if (args.length > 1 && (args[0].equalsIgnoreCase("power") || args[0].equalsIgnoreCase("p"))) {
final FireworkMeta fmeta = (FireworkMeta) stack.getItemMeta();
try {
final int power = Integer.parseInt(args[1]);
fmeta.setPower(power > 3 ? 4 : power);
} catch (final NumberFormatException e) {
throw new Exception(tl("invalidFireworkFormat", args[1], args[0]));
throw new TranslatableException("invalidFireworkFormat", args[1], args[0]);
}
stack.setItemMeta(fmeta);
} else if ((args[0].equalsIgnoreCase("fire") || args[0].equalsIgnoreCase("f")) && user.isAuthorized("essentials.firework.fire")) {
@ -75,7 +74,7 @@ public class Commandfirework extends EssentialsCommand {
amount = Integer.parseInt(args[1]);
if (amount > serverLimit) {
amount = serverLimit;
user.sendMessage(tl("mobSpawnLimit"));
user.sendTl("mobSpawnLimit");
}
} else {
direction = true;
@ -99,7 +98,7 @@ public class Commandfirework extends EssentialsCommand {
try {
mStack.addFireworkMeta(user.getSource(), true, arg, ess);
} catch (final Exception e) {
user.sendMessage(tl("fireworkSyntax"));
user.sendTl("fireworkSyntax");
throw e;
}
}
@ -108,13 +107,13 @@ public class Commandfirework extends EssentialsCommand {
final FireworkMeta fmeta = (FireworkMeta) mStack.getItemStack().getItemMeta();
final FireworkEffect effect = mStack.getFireworkBuilder().build();
if (fmeta.getEffects().size() > 0 && !user.isAuthorized("essentials.firework.multiple")) {
throw new Exception(tl("multipleCharges"));
throw new TranslatableException("multipleCharges");
}
fmeta.addEffect(effect);
stack.setItemMeta(fmeta);
} else {
user.sendMessage(tl("fireworkSyntax"));
throw new Exception(tl("fireworkColor"));
user.sendTl("fireworkSyntax");
throw new TranslatableException("fireworkColor");
}
}
}

View File

@ -2,11 +2,10 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.CommonPlaceholders;
import net.ess3.api.events.FlyStatusChangeEvent;
import org.bukkit.Server;
import static com.earth2me.essentials.I18n.tl;
public class Commandfly extends EssentialsToggleCommand {
public Commandfly() {
super("fly", "essentials.fly.others");
@ -39,9 +38,9 @@ public class Commandfly extends EssentialsToggleCommand {
user.getBase().setFlying(false);
}
user.sendMessage(tl("flyMode", tl(enabled ? "enabled" : "disabled"), user.getDisplayName()));
user.sendTl("flyMode", CommonPlaceholders.enableDisable(user.getSource(), enabled), user.getDisplayName());
if (!sender.isPlayer() || !sender.getPlayer().equals(user.getBase())) {
sender.sendMessage(tl("flyMode", tl(enabled ? "enabled" : "disabled"), user.getDisplayName()));
sender.sendTl("flyMode", CommonPlaceholders.enableDisable(user.getSource(), enabled), user.getDisplayName());
}
}
}

View File

@ -11,8 +11,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static com.earth2me.essentials.I18n.tl;
public class Commandgamemode extends EssentialsLoopCommand {
private final List<String> STANDARD_OPTIONS = ImmutableList.of("creative", "survival", "adventure", "spectator", "toggle");
@ -57,26 +55,26 @@ public class Commandgamemode extends EssentialsLoopCommand {
}
if (isProhibitedChange(user, gameMode)) {
user.sendMessage(tl("cantGamemode", gameMode.name()));
user.sendTl("cantGamemode", user.playerTl(gameMode.toString().toLowerCase(Locale.ENGLISH)));
return;
}
user.getBase().setGameMode(gameMode);
user.sendMessage(tl("gameMode", tl(user.getBase().getGameMode().toString().toLowerCase(Locale.ENGLISH)), user.getDisplayName()));
user.sendTl("gameMode", user.playerTl(user.getBase().getGameMode().toString().toLowerCase(Locale.ENGLISH)), user.getDisplayName());
}
private void setUserGamemode(final CommandSource sender, final GameMode gameMode, final User user) throws NotEnoughArgumentsException {
if (gameMode == null) {
throw new NotEnoughArgumentsException(tl("gameModeInvalid"));
throw new NotEnoughArgumentsException(sender.tl("gameModeInvalid"));
}
if (sender.isPlayer() && isProhibitedChange(sender.getUser(ess), gameMode)) {
sender.sendMessage(tl("cantGamemode", gameMode.name()));
if (sender.isPlayer() && isProhibitedChange(sender.getUser(), gameMode)) {
sender.sendTl("cantGamemode", gameMode.name());
return;
}
user.getBase().setGameMode(gameMode);
sender.sendMessage(tl("gameMode", tl(gameMode.toString().toLowerCase(Locale.ENGLISH)), user.getDisplayName()));
sender.sendTl("gameMode", sender.tl(gameMode.toString().toLowerCase(Locale.ENGLISH)), user.getDisplayName());
}
// essentials.gamemode will let them change to any but essentials.gamemode.survival would only let them change to survival.

View File

@ -3,7 +3,6 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.NumberUtil;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.Server;
@ -13,8 +12,6 @@ import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.logging.Level;
import static com.earth2me.essentials.I18n.tl;
public class Commandgc extends EssentialsCommand {
public Commandgc() {
super("gc");
@ -32,11 +29,11 @@ public class Commandgc extends EssentialsCommand {
color = ChatColor.RED;
}
sender.sendMessage(tl("uptime", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime())));
sender.sendMessage(tl("tps", "" + color + NumberUtil.formatDouble(tps)));
sender.sendMessage(tl("gcmax", Runtime.getRuntime().maxMemory() / 1024 / 1024));
sender.sendMessage(tl("gctotal", Runtime.getRuntime().totalMemory() / 1024 / 1024));
sender.sendMessage(tl("gcfree", Runtime.getRuntime().freeMemory() / 1024 / 1024));
sender.sendTl("uptime", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()));
sender.sendTl("tps", "" + color + NumberUtil.formatDouble(tps));
sender.sendTl("gcmax", Runtime.getRuntime().maxMemory() / 1024 / 1024);
sender.sendTl("gctotal", Runtime.getRuntime().totalMemory() / 1024 / 1024);
sender.sendTl("gcfree", Runtime.getRuntime().freeMemory() / 1024 / 1024);
final List<World> worlds = server.getWorlds();
for (final World w : worlds) {
@ -57,10 +54,10 @@ public class Commandgc extends EssentialsCommand {
tileEntities += chunk.getTileEntities().length;
}
} catch (final java.lang.ClassCastException ex) {
Bukkit.getLogger().log(Level.SEVERE, "Corrupted chunk data on world " + w, ex);
ess.getLogger().log(Level.SEVERE, "Corrupted chunk data on world " + w, ex);
}
sender.sendMessage(tl("gcWorld", worldType, w.getName(), w.getLoadedChunks().length, w.getEntities().size(), tileEntities));
sender.sendTl("gcWorld", worldType, w.getName(), w.getLoadedChunks().length, w.getEntities().size(), tileEntities);
}
}
}

View File

@ -8,8 +8,6 @@ import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
import static com.earth2me.essentials.I18n.tl;
public class Commandgetpos extends EssentialsCommand {
public Commandgetpos() {
super("getpos");
@ -35,20 +33,20 @@ public class Commandgetpos extends EssentialsCommand {
}
private void outputPosition(final CommandSource sender, final Location coords, final Location distance) {
sender.sendMessage(tl("currentWorld", coords.getWorld().getName()));
sender.sendMessage(tl("posX", coords.getBlockX()));
sender.sendMessage(tl("posY", coords.getBlockY()));
sender.sendMessage(tl("posZ", coords.getBlockZ()));
sender.sendMessage(tl("posYaw", (coords.getYaw() + 360) % 360));
sender.sendMessage(tl("posPitch", coords.getPitch()));
sender.sendTl("currentWorld", coords.getWorld().getName());
sender.sendTl("posX", coords.getBlockX());
sender.sendTl("posY", coords.getBlockY());
sender.sendTl("posZ", coords.getBlockZ());
sender.sendTl("posYaw", (coords.getYaw() + 360) % 360);
sender.sendTl("posPitch", coords.getPitch());
if (distance != null && coords.getWorld().equals(distance.getWorld())) {
sender.sendMessage(tl("distance", coords.distance(distance)));
sender.sendTl("distance", coords.distance(distance));
}
}
@Override
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1 && sender.isAuthorized("essentials.getpos.others", ess)) {
if (args.length == 1 && sender.isAuthorized("essentials.getpos.others")) {
return getPlayers(server, sender);
} else {
return Collections.emptyList();

View File

@ -3,9 +3,11 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.Lists;
import net.ess3.api.TranslatableException;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.World;
@ -16,8 +18,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import static com.earth2me.essentials.I18n.tl;
public class Commandgive extends EssentialsLoopCommand {
public Commandgive() {
super("give");
@ -33,18 +33,18 @@ public class Commandgive extends EssentialsLoopCommand {
final String itemname = stack.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", "");
if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).canSpawnItem(stack.getType())) {
throw new Exception(tl("cantSpawnItem", itemname));
throw new TranslatableException("cantSpawnItem", itemname);
}
try {
if (args.length > 3 && NumberUtil.isInt(args[2]) && NumberUtil.isInt(args[3])) {
if (args.length > 3 && VersionUtil.PRE_FLATTENING && NumberUtil.isInt(args[2]) && NumberUtil.isInt(args[3])) {
stack.setAmount(Integer.parseInt(args[2]));
stack.setDurability(Short.parseShort(args[3]));
} else if (args.length > 2 && Integer.parseInt(args[2]) > 0) {
stack.setAmount(Integer.parseInt(args[2]));
} else if (ess.getSettings().getDefaultStackSize() > 0) {
stack.setAmount(ess.getSettings().getDefaultStackSize());
} else if (ess.getSettings().getOversizedStackSize() > 0 && sender.isAuthorized("essentials.oversizedstacks", ess)) {
} else if (ess.getSettings().getOversizedStackSize() > 0 && sender.isAuthorized("essentials.oversizedstacks")) {
stack.setAmount(ess.getSettings().getOversizedStackSize());
}
} catch (final NumberFormatException e) {
@ -53,7 +53,7 @@ public class Commandgive extends EssentialsLoopCommand {
final MetaItemStack metaStack = new MetaItemStack(stack);
if (!metaStack.canSpawn(ess)) {
throw new Exception(tl("unableToSpawnItem", itemname));
throw new TranslatableException("unableToSpawnItem", itemname);
}
if (args.length > 3) {
@ -72,28 +72,23 @@ public class Commandgive extends EssentialsLoopCommand {
}
if (stack.getType() == Material.AIR) {
throw new Exception(tl("cantSpawnItem", "Air"));
throw new TranslatableException("cantSpawnItem", "Air");
}
final String itemName = stack.getType().toString().toLowerCase(Locale.ENGLISH).replace('_', ' ');
final boolean isDropItemsIfFull = ess.getSettings().isDropItemsIfFull();
final ItemStack finalStack = stack;
loopOnlinePlayersConsumer(server, sender, false, true, args[0], player -> {
sender.sendMessage(tl("giveSpawn", finalStack.getAmount(), itemName, player.getDisplayName()));
final Map<Integer, ItemStack> leftovers;
sender.sendTl("giveSpawn", finalStack.getAmount(), itemName, player.getDisplayName());
if (player.isAuthorized("essentials.oversizedstacks")) {
leftovers = InventoryWorkaround.addOversizedItems(player.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), finalStack);
} else {
leftovers = InventoryWorkaround.addItems(player.getBase().getInventory(), finalStack);
}
final Map<Integer, ItemStack> leftovers = Inventories.addItem(player.getBase(), player.isAuthorized("essentials.oversizedstacks") ? ess.getSettings().getOversizedStackSize() : 0, finalStack);
for (final ItemStack item : leftovers.values()) {
if (isDropItemsIfFull) {
final World w = player.getWorld();
w.dropItemNaturally(player.getLocation(), item);
} else {
sender.sendMessage(tl("giveSpawnFailure", item.getAmount(), itemName, player.getDisplayName()));
sender.sendTl("giveSpawnFailure", item.getAmount(), itemName, player.getDisplayName());
}
}

Some files were not shown because too many files have changed in this diff Show More