Compare commits

...
461 Commits
Author SHA1 Message Date
Andrew Wong d7907498c9 fix typo 2026-08-09 20:29:11 +10:00
Andrew Wong afbdc6c009 Update README with maintenance notice and alternative link
Update README to indicate project is no longer maintained and provide alternative link.
2026-08-09 20:28:47 +10:00
mesemi cc3a0b32a4 Add SetMaxExtends 2025-09-20 16:54:49 +10:00
Andrew Wong aca6103b1c Refactor the CacheManager to defensive copy and use a binary format 2025-08-10 01:26:39 +10:00
Solo 02c02dad8d Added a cache layer for the names to avoid having to fetch the offline player everytime 2025-08-10 01:26:39 +10:00
Andrew Wong 822f300e65 Fix group info command
Fixes #36
2025-02-25 00:12:18 +08:00
Andrew Wong 1671dc8c26 Update cloud, move exception handlers around to prevent recursion 2025-02-08 21:30:40 +08:00
Andrew Wong 72c4a76c6c Save regions async 2025-01-12 14:00:31 +08:00
Andrew Wong c9e7e3cdbb Bump gradle verstion to 8.11.1 2025-01-12 10:17:48 +08:00
Andrew Wong 4ceff1b80e Update mockbukkit 2024-10-07 16:31:55 +11:00
Andrew Wong 8e88dc7b6b Update gradle wrapper 2024-10-07 16:23:41 +11:00
Andrew Wong 2762ebae1d Supplement OfflinePlayer#hasPlayedBefore checks with #isOnline checks 2024-08-08 20:34:49 +10:00
Andrew Wong 5742dd623e Fix as me command to have the player arg be properly optional 2024-08-04 21:51:44 +10:00
Andrew Wong e5d190d81e Revert "Remove argument from me command"
This reverts commit b631cfc89d.
2024-08-04 21:50:39 +10:00
Andrew Wong b631cfc89d Remove argument from me command 2024-08-04 21:10:04 +10:00
Andrew Wong 399b166339 Sync back to main after looking up offline player async 2024-08-03 18:10:17 +10:00
Andrew Wong b556cb1bce Refactor commands to avoid main thread offline player lookup 2024-08-01 11:12:19 +10:00
Andrew Wong 105274b633 Snapshot 2.9.2 2024-08-01 11:11:54 +10:00
Andrew Wong 9b036dad93 Release 2.9.1 2024-07-24 14:47:35 +10:00
Andrew Wong 628aa83089 Update cloud to beta.9 2024-07-24 14:45:59 +10:00
Andrew Wong 11da15454d Enforce min version to 1.21 2024-07-24 14:45:59 +10:00
Andrew Wong ff2e4e235d Compile against 1.21, bump version to 2.9.1-SNAPSHOT 2024-07-24 14:45:59 +10:00
Andrew Wong 88c7b7a4bd Release 2.9.0 2024-07-24 14:04:44 +10:00
Andrew Wong cd3a7e97a7 Remove extra listener for SignChangeEvent in SignListener 2024-07-24 14:04:13 +10:00
Andrew Wong d33739491a Revert "Release 2.9.0"
This reverts commit ff59fa7f70.
2024-07-24 13:35:27 +10:00
Andrew Wong 5488deb0d7 Fix message sending errors in the ArgumentParseHandler, fix issue with quickbuy and quickrent where newly joined playes are treated as invalid 2024-07-24 13:35:09 +10:00
Andrew Wong ff59fa7f70 Release 2.9.0 2024-07-24 13:21:03 +10:00
Andrew Wong 219ba0335e Remove paperweight userdev, update cloud to 2.0.0-beta.8 2024-07-24 13:15:08 +10:00
Andrew Wong 724439da7d Remove BukkitInterface 2024-06-30 17:43:23 +10:00
Andrew Wong 7bebca5dca Inline BlockBehaviourHelper, remove areashop-nms and areashop-platform-modern 2024-06-30 17:37:45 +10:00
Andrew Wong 5989ecbcbc Handle new SignChangeEvent in the sign listener 2024-06-28 21:39:15 +10:00
Andrew Wong a6a38be0a5 Set version to 2.9.0-SNAPSHOT 2024-06-22 01:26:21 +10:00
Andrew Wong 5034aa358a Fix version util parsing for versions without trailing zeros 2024-06-22 01:22:55 +10:00
Andrew Wong 4f7982f5b2 Update min required version to 1.20.6 2024-06-22 01:16:47 +10:00
Andrew Wong 92c8eea23a Code cleanup, migrate to java 21 2024-06-22 01:10:28 +10:00
Andrew Wong 4ff5852a9d Update the worldguard, worldedit and fastasyncworldedit dependency and adapters 2024-06-22 00:52:07 +10:00
Andrew Wong b30a292398 Bump version to 2.9.0 2024-06-22 00:39:28 +10:00
Andrew Wong 5640a55d73 Update cloud-paper to 2.0.0-SNAPSHOT. Refactor commands to accomodate the new CommandSourceStack 2024-06-22 00:39:05 +10:00
Andrew Wong cd79e071a4 Bump java version in workflows and jitpack 2024-06-22 00:39:03 +10:00
Andrew Wong 49a4b1420d Initial work on compiling against 1.20.6 2024-06-22 00:39:01 +10:00
Andrew Wong 7ef50fbcba Update gradle wrapper to 8.7 2024-06-22 00:38:59 +10:00
Andrew Wong f9b1920678 Add page flag into the info command 2024-06-21 22:18:06 +10:00
Andrew Wong a9d388a12c Refact info region to use a flag 2024-06-20 15:37:34 +10:00
Andrew Wong d66b79ba67 Refactor the info command into 3 distinct subcommands 2024-06-20 15:03:05 +10:00
Andrew Wong a33e25d83c Refactor the filter arguments in the info command 2024-06-16 16:26:10 +10:00
Andrew Wong 1b1e0c7225 Only create the sign feature instances if they exist 2024-05-14 14:21:28 +10:00
Andrew Wong a977433a22 Remove unused imports 2024-05-06 19:12:06 +10:00
Andrew Wong 81ef7b08ba Update cloud and other dependencies 2024-05-06 19:09:58 +10:00
Andrew Wong 1528668f01 Show help page on default command exec 2024-05-06 18:56:22 +10:00
Andrew Wong 51487b476b Update gradle wrapper to 8.7 2024-04-23 00:15:16 +10:00
Andrew Wong a1a64d8eb4 Fix add friend treating existing players as nonexisting 2024-04-23 00:14:32 +10:00
Andrew Wong e0a451511c Rename RegionFlagUtil to RegionParseUtil, replace the region flag in AddSignCommand with an optional arg 2024-04-20 00:51:41 +10:00
Andrew Wong 1bc2523b95 Refactor RegionCreationUtil to not validate the WE sel nor check for overlapping regions 2024-04-20 00:47:42 +10:00
Andrew Wong dba63b7cdd Fix setprice command arg named incorrectly 2024-04-06 21:58:22 +11:00
Andrew Wong fbef0006d1 Fix as info reselling producing incorrect output 2024-04-03 10:44:10 +11:00
Andrew Wong c1572eb754 Fix bad MM message file. Fix SetDuration command parsing. Fix FindCommand searching 2024-03-29 22:19:02 +11:00
Andrew Wong 82ab8dbbbc Fix info command reselling header 2024-03-25 15:10:39 +11:00
Andrew Wong 0a1d27488b Fix missing name in component 2024-03-24 22:49:47 +11:00
Andrew Wong a92b38e664 Fix tab completions for as togglehome 2024-03-24 21:15:53 +11:00
Andrew Wong 4e1f8f685e Fix bad merge conflict transfer command 2024-03-24 21:07:33 +11:00
Andrew Wong e02f14b041 Dont use cloud to check permissions in SetOwnerCommand 2024-03-24 13:27:24 +11:00
Andrew Wong 7687a9be77 Make the KEY_DURATION required in SetDurationCommand 2024-03-24 13:26:08 +11:00
Andrew Wong 745895cdae Fix invalid command syntaxes in default.yml 2024-03-24 13:20:47 +11:00
Andrew Wong 0305ec3f1f Add info base command, rename version to 2.8.0 2024-03-23 14:53:35 +11:00
Andrew Wong ec36996385 Bump version to 2.8 2024-03-23 14:32:02 +11:00
Andrew Wong 2800bf469b Fail silently when sending a message to a null sender 2024-03-23 14:26:33 +11:00
Andrew Wong d25fc9fd45 Merge branch 'feature/cloud' into feature/quick-commands 2024-03-23 11:48:51 +11:00
Andrew Wong 1172b1b775 Use longer labels as aliases instead of the main label 2024-03-23 11:43:06 +11:00
Andrew Wong 0ba567cf90 Fix setduration duration parsing 2024-03-23 11:43:04 +11:00
Andrew Wong 74f0a8ed3b Fix missing required arg in teleport command: 2024-03-23 11:43:02 +11:00
Andrew Wong 4c6b7233eb State bad duration instead of throwing an exception 2024-03-23 11:43:00 +11:00
Andrew Wong e00cc2c191 Check if the player is online first in ValidatedOflinePlayerParser 2024-03-23 11:42:58 +11:00
Andrew Wong 73346d241c Fix lang key typos 2024-03-23 11:42:54 +11:00
Andrew Wong e8a9c6b3c7 Add handler for invalid command sender 2024-03-23 11:42:29 +11:00
Andrew Wong 6c6f9fc8ed Bump version to 2.8-BETA-1 2024-03-23 11:42:27 +11:00
Andrew Wong 284d915ca5 Dont shade in guava 2024-03-23 11:42:25 +11:00
Andrew Wong 1494d3a3fd Fix bad rename compile errors 2024-03-23 11:42:23 +11:00
Andrew Wong abaf960613 Update command readme 2024-03-23 11:42:20 +11:00
Andrew Wong 0ca301970b Remove legacy commands and replace with cloud commands 2024-03-23 11:42:14 +11:00
Andrew Wong c7c1d9e4f6 Reimplement help messages 2024-03-23 11:39:04 +11:00
Andrew Wong 5a61cee351 Refactor commands to not use the cloud permission system 2024-03-23 11:39:02 +11:00
Andrew Wong a4195eb556 Replace usages of OfflinePlayerParser with ValidatedOfflinePlayerParser 2024-03-23 11:39:00 +11:00
Andrew Wong ddc5145539 Refactor unrent command to cloud 2024-03-23 11:38:58 +11:00
Andrew Wong 5daa99c938 Refactor transfer command to cloud 2024-03-23 11:38:56 +11:00
Andrew Wong 3c2bd89c8d Refactor togglehome command to use cloud 2024-03-23 11:38:53 +11:00
Andrew Wong 3c3e8965a3 Refactor teleport command to cloud 2024-03-23 11:38:51 +11:00
Andrew Wong 6898efb7d7 Refactor stopresell command to cloud 2024-03-23 11:38:49 +11:00
Andrew Wong 030826d343 Refactor stack command to cloud 2024-03-23 11:38:47 +11:00
Andrew Wong b8625237a7 Refactor settransfer command to cloud 2024-03-23 11:38:45 +11:00
Andrew Wong b0df7ba98d Refactor setrestore command to cloud 2024-03-23 11:38:43 +11:00
Andrew Wong a8938dc492 Refactor setrestore command to cloud 2024-03-23 11:38:41 +11:00
Andrew Wong 9f0a6ee196 Refactor setprice command to cloud 2024-03-23 11:38:39 +11:00
Andrew Wong cb7016264f Refactor setowner command to cloud 2024-03-23 11:38:37 +11:00
Andrew Wong feff1c6e24 Refactor setlandlord to cloud 2024-03-23 11:38:35 +11:00
Andrew Wong 02d1881f6d Refactor setduration to cloud 2024-03-23 11:38:32 +11:00
Andrew Wong aa61bc58ca Refactor sell command to cloud 2024-03-23 11:38:30 +11:00
Andrew Wong 4d467e0d05 Refactor schemevent command to cloud 2024-03-23 11:38:28 +11:00
Andrew Wong 32a84dd4c8 Refactor resell command to cloud 2024-03-23 11:38:26 +11:00
Andrew Wong f141f78529 Refactor reload command to cloud 2024-03-23 11:38:24 +11:00
Andrew Wong 96d490836e Refactor message command to cloud 2024-03-23 11:38:22 +11:00
Andrew Wong 7f7f50a650 Refactor me command to cloud 2024-03-23 11:38:20 +11:00
Andrew Wong 91efe92ccc Refactor linksign command to cloud 2024-03-23 11:38:18 +11:00
Andrew Wong d308420f30 Remove unused method 2024-03-23 11:38:16 +11:00
Andrew Wong 22e3785a07 Remove unused imports 2024-03-23 11:38:14 +11:00
Andrew Wong ed55641c8b Replace all usages of checkerframework NonNull with javax Nonnull 2024-03-23 11:38:11 +11:00
Andrew Wong b9653b7382 Reformat AreashopCloudCommands 2024-03-23 11:38:09 +11:00
Andrew Wong 7021b50cbc Refactor info command to cloud 2024-03-23 11:38:07 +11:00
Andrew Wong 894cc9b99c Unwrap command execution exception 2024-03-23 11:38:05 +11:00
Andrew Wong 2b5d0c6bd0 Fix bad message replacements in add command 2024-03-23 11:38:03 +11:00
Andrew Wong 867b50c1f5 Refactor import command to cloud, add confirmations 2024-03-23 11:38:01 +11:00
Andrew Wong d6fdcb05ef Fix add command displaying add-succcess incorrectly 2024-03-23 11:37:59 +11:00
Andrew Wong c347e8de59 Refactor group commands to cloud 2024-03-23 11:37:57 +11:00
Andrew Wong 81457b0d0b Refactor find command to cloud 2024-03-23 11:37:55 +11:00
Andrew Wong d7006267ca Refactor delsign command to cloud 2024-03-23 11:37:52 +11:00
Andrew Wong 31b345ffe0 Fix bad input parsing in the region parsers 2024-03-23 11:37:50 +11:00
Andrew Wong 1336cb78b2 Refactor delfriend to cloud 2024-03-23 11:37:48 +11:00
Andrew Wong 7c6b80e392 Refactor del command to cloud 2024-03-23 11:37:46 +11:00
Andrew Wong 46baea2c0d Refactor buy and rent commands to cloud 2024-03-23 11:37:44 +11:00
Andrew Wong d2e61545ea Add note for why we are unwrapping ArgumentParseException 2024-03-23 11:37:42 +11:00
Andrew Wong a12fb49832 Refactor exception handling and fix add command 2024-03-23 11:37:40 +11:00
Andrew Wong 08be336499 Remove unused import 2024-03-23 11:37:38 +11:00
Andrew Wong 3051e8b402 Refactor command registration 2024-03-23 11:37:36 +11:00
Andrew Wong 52c3742a2a Add AddSignCloudCommand 2024-03-23 11:37:33 +11:00
Andrew Wong 5b16f40335 Refactor to use cloud keys and flags 2024-03-23 11:37:31 +11:00
Andrew Wong 6c6a67928f Initial work on cloud 2024-03-23 11:37:29 +11:00
Andrew Wong 06dd185205 Add sethome feature 2024-03-23 11:37:27 +11:00
md5sha256 02389b7d1b Refactor AddfriendCommand to use cloud 2024-03-23 11:37:25 +11:00
md5sha256 bee7f18bd0 Refactor the AddCommand to use cloud 2024-03-23 11:37:23 +11:00
Andrew Wong 63dc36c3bd Initial work on cloud 2024-03-23 11:37:21 +11:00
Andrew Wong 4723043e9a Fix bad lang entry for togglehome help 2024-03-23 11:36:56 +11:00
Andrew Wong 703bbc6668 Fix togglehome not tab completing the HomeAccessType, fix error message missing param 2024-03-23 11:36:08 +11:00
Andrew Wong b524b1c88f Refactor SimpleMessageBridge to use BukkitAudiences 2024-03-23 00:57:20 +11:00
Andrew Wong f1546f8482 Dont print stacktrace in the DurationInputParser 2024-03-21 12:07:10 +11:00
Andrew Wong 29ec5a2e3b Use longer labels as aliases instead of the main label 2024-03-18 11:33:37 +11:00
Andrew Wong 3a15e3d025 Add deletion message for deleting WG regions in quickdelete 2024-03-18 11:28:25 +11:00
Andrew Wong 90e010494a Fix bad timeunit parsing, add suggestions to DurationInputParser 2024-03-18 11:25:01 +11:00
Andrew Wong 7541af37f3 Remove the region name not regionmanager name 2024-03-18 10:43:02 +11:00
Andrew Wong 36c74a32f0 Fix quickrent missing duration arg 2024-03-18 10:36:07 +11:00
Andrew Wong 129b144cb1 Fix missing inject annotation on QuickDeleteCommand ctor, fix invalid semicolon in lang files 2024-03-17 22:59:53 +11:00
Andrew Wong a79b0067f2 Add help entries for the new quick commands 2024-03-17 22:48:58 +11:00
Andrew Wong 5c2e4f8f0c Add quickdelete command 2024-03-17 22:46:04 +11:00
Andrew Wong d639f61e8f Refactor QuickBuyCommand, add RegionCreationUtil and QuickSellCommand 2024-03-17 22:34:55 +11:00
Andrew Wong 65b9ffed18 Add quickbuy command 2024-03-17 22:02:03 +11:00
Andrew Wong ee94a3d549 Fix setduration duration parsing 2024-03-17 14:55:35 +11:00
Andrew Wong 44d8999b3c Fix missing required arg in teleport command: 2024-03-17 11:19:18 +11:00
Andrew Wong a09d6f9370 State bad duration instead of throwing an exception 2024-03-17 11:06:16 +11:00
Andrew Wong 105cc1033c Check if the player is online first in ValidatedOflinePlayerParser 2024-03-17 11:01:17 +11:00
Andrew Wong c3daff0842 Fix lang key typos 2024-03-17 10:58:54 +11:00
Andrew Wong 3456bc6a37 Add handler for invalid command sender 2024-03-11 11:33:02 +11:00
Andrew Wong 58269daa45 Bump version to 2.8-BETA-1 2024-03-04 22:52:55 +11:00
Andrew Wong bac50ed5d5 Dont shade in guava 2024-03-04 22:52:01 +11:00
Andrew Wong 8d50a0d1a7 Fix bad rename compile errors 2024-03-04 22:42:49 +11:00
Andrew Wong bf5436284a Update command readme 2024-03-04 22:40:09 +11:00
Andrew Wong 592a1b24f4 Remove legacy commands and replace with cloud commands 2024-03-04 22:40:07 +11:00
Andrew Wong aacf75c170 Reimplement help messages 2024-03-04 22:40:05 +11:00
Andrew Wong 4bf598ac5d Refactor commands to not use the cloud permission system 2024-03-04 22:40:03 +11:00
Andrew Wong 4b4521b002 Replace usages of OfflinePlayerParser with ValidatedOfflinePlayerParser 2024-03-04 22:40:01 +11:00
Andrew Wong cd262fdf5e Refactor unrent command to cloud 2024-03-04 22:39:58 +11:00
Andrew Wong 5b283d503b Refactor transfer command to cloud 2024-03-04 22:39:56 +11:00
Andrew Wong b9d5a29629 Refactor togglehome command to use cloud 2024-03-04 22:39:54 +11:00
Andrew Wong 0b0f4b0289 Refactor teleport command to cloud 2024-03-04 22:39:52 +11:00
Andrew Wong 75915f2ebf Refactor stopresell command to cloud 2024-03-04 22:39:50 +11:00
Andrew Wong 1395220edb Refactor stack command to cloud 2024-03-04 22:39:48 +11:00
Andrew Wong a318293bbe Refactor settransfer command to cloud 2024-03-04 22:39:46 +11:00
Andrew Wong 0cbf14183d Refactor setrestore command to cloud 2024-03-04 22:39:44 +11:00
Andrew Wong 4c636856aa Refactor setrestore command to cloud 2024-03-04 22:39:42 +11:00
Andrew Wong 7bb3ed1859 Refactor setprice command to cloud 2024-03-04 22:39:40 +11:00
Andrew Wong 909f6c4b45 Refactor setowner command to cloud 2024-03-04 22:39:38 +11:00
Andrew Wong adfc4334cc Refactor setlandlord to cloud 2024-03-04 22:39:36 +11:00
Andrew Wong f8ae27c3f3 Refactor setduration to cloud 2024-03-04 22:39:34 +11:00
Andrew Wong d2b2ca2b83 Refactor sell command to cloud 2024-03-04 22:39:32 +11:00
Andrew Wong 6f8afea58e Refactor schemevent command to cloud 2024-03-04 22:39:29 +11:00
Andrew Wong 113a1a4f63 Refactor resell command to cloud 2024-03-04 22:39:27 +11:00
Andrew Wong 6e7a659c80 Refactor reload command to cloud 2024-03-04 22:39:25 +11:00
Andrew Wong 1336858316 Refactor message command to cloud 2024-03-04 22:39:23 +11:00
Andrew Wong 7b7b5abf2c Refactor me command to cloud 2024-03-04 22:39:21 +11:00
Andrew Wong 9fd8a740db Refactor linksign command to cloud 2024-03-04 22:39:19 +11:00
Andrew Wong 88a23650a0 Remove unused method 2024-03-04 22:39:17 +11:00
Andrew Wong 4e1f9e6875 Remove unused imports 2024-03-04 22:39:15 +11:00
Andrew Wong 4fdf9d787f Replace all usages of checkerframework NonNull with javax Nonnull 2024-03-04 22:39:13 +11:00
Andrew Wong 413f16a2d4 Reformat AreashopCloudCommands 2024-03-04 22:39:11 +11:00
Andrew Wong 3c21ac1eba Refactor info command to cloud 2024-03-04 22:39:09 +11:00
Andrew Wong 7670d1b479 Unwrap command execution exception 2024-03-04 22:39:07 +11:00
Andrew Wong 73e04ccc68 Fix bad message replacements in add command 2024-03-04 22:39:05 +11:00
Andrew Wong 52256c83b8 Refactor import command to cloud, add confirmations 2024-03-04 22:39:03 +11:00
Andrew Wong 794854e9c2 Fix add command displaying add-succcess incorrectly 2024-03-04 22:39:01 +11:00
Andrew Wong 2c7fc16f8b Refactor group commands to cloud 2024-03-04 22:38:59 +11:00
Andrew Wong b7fc4175a1 Refactor find command to cloud 2024-03-04 22:38:57 +11:00
Andrew Wong 6e686f5a3f Refactor delsign command to cloud 2024-03-04 22:38:55 +11:00
Andrew Wong 324dae03eb Fix bad input parsing in the region parsers 2024-03-04 22:38:53 +11:00
Andrew Wong 8a3122ba93 Refactor delfriend to cloud 2024-03-04 22:38:51 +11:00
Andrew Wong aada9a4624 Refactor del command to cloud 2024-03-04 22:38:49 +11:00
Andrew Wong b74736f23b Refactor buy and rent commands to cloud 2024-03-04 22:38:47 +11:00
Andrew Wong c54c8b32ac Add note for why we are unwrapping ArgumentParseException 2024-03-04 22:38:45 +11:00
Andrew Wong 63c1b7474a Refactor exception handling and fix add command 2024-03-04 22:38:43 +11:00
Andrew Wong 192f34099a Remove unused import 2024-03-04 22:38:41 +11:00
Andrew Wong b933dfea72 Refactor command registration 2024-03-04 22:38:39 +11:00
Andrew Wong 3d08c9f7be Add AddSignCloudCommand 2024-03-04 22:38:36 +11:00
Andrew Wong 52d5b4632b Refactor to use cloud keys and flags 2024-03-04 22:38:34 +11:00
Andrew Wong 7e03db8b10 Initial work on cloud 2024-03-04 22:38:32 +11:00
Andrew Wong 913d1c9b59 Add sethome feature 2024-03-04 22:38:29 +11:00
md5sha256 f24a922fec Refactor AddfriendCommand to use cloud 2024-03-04 22:35:37 +11:00
md5sha256 5871b3ba24 Refactor the AddCommand to use cloud 2024-03-04 22:35:35 +11:00
Andrew Wong 9d3818906c Initial work on cloud 2024-03-04 22:35:30 +11:00
Andrew Wong ac69d18dc0 Refactor the SimpleMessageBridge to provide MiniMessage strings to the MailService 2024-02-28 15:48:43 +11:00
Andrew Wong 2c3a78517d Use mail to notify 2024-02-26 16:46:38 +11:00
Andrew Wong 04d42c5444 Add mail integration foundation 2024-02-26 16:44:09 +11:00
Andrew Wong 172762356d Register the togglehome command 2024-02-26 16:43:01 +11:00
Andrew Wong aeb201c221 Update minimessage lang, fix double minimessage conversions 2024-02-26 01:32:46 +11:00
Andrew Wong 788ba7e2b6 Add sethome feature 2024-02-26 01:20:58 +11:00
Andrew Wong 89114ee126 Drop support for 1.17.1 2024-02-26 01:18:58 +11:00
Andrew Wong d316f2e914 Bump version to 2.7.18-SNAPSHOT 2024-02-25 18:26:33 +11:00
Andrew Wong 74219ff75b Release 2.7.17 2024-01-29 16:12:16 +08:00
Andrew Wong e13a5f2bb0 Update the region immediately after a transfer has occurred. Additionally, remove the previous owner from the friend feature 2024-01-29 16:11:21 +08:00
Andrew Wong c3bc9457ef Minor code smell fixes 2024-01-29 15:52:57 +08:00
Andrew Wong 6dc97b019e Add method in FeatureManager to register feature init 2024-01-15 12:02:00 +08:00
md5sha256 41944102b6 Update dependencies 2024-01-07 10:59:42 +01:00
md5sha256 90fecd1085 Update dependencies and minor buildscript changes 2024-01-07 00:30:13 +01:00
md5sha256 e1b4df8f25 Minor code cleanup, add language converter 2024-01-07 00:28:00 +01:00
= f0e4bd12ca Use InputStream#readAllBytes 2024-01-07 00:28:00 +01:00
= 27d832f05a Simplify try-catch to instanceof 2024-01-07 00:28:00 +01:00
= 1ca846f1ec Put curly braces on the same line 2024-01-07 00:28:00 +01:00
= 2472a14cae Swap Bukkit#getLogger()#severe() for AreaShop#error() 2024-01-07 00:28:00 +01:00
= c2bfe2158e Early check in SimpleMessageBridge.send for ClassCastException 2024-01-07 00:28:00 +01:00
= 745d1dd7d7 Remove unnecessary cast to TextComponent 2024-01-07 00:28:00 +01:00
= f6977061f4 Refactor five different "send" methods into one 2024-01-07 00:28:00 +01:00
= c922b83de4 Remove * imports in ASLanguageManager 2024-01-07 00:28:00 +01:00
= 444a769f37 Use NIO StandardCharsets in ASLanguageManager 2024-01-07 00:28:00 +01:00
= 6b81be9cbb Change some comments in config 2024-01-07 00:28:00 +01:00
= cd07b899c8 Change config to be more usable 2024-01-07 00:28:00 +01:00
= 6bd916facd Add more comments to config to explain MiniMessage 2024-01-07 00:28:00 +01:00
= d16ea37269 Better config.yml comments 2024-01-07 00:27:37 +01:00
= 56ab7ef52b Support the old messaging system 2024-01-07 00:27:35 +01:00
= 6ef2d89cfc Change configuration and lang to be MiniMessage. Add wgPrefix. Create ASLanguageManager. Change how messages are sent and handled to support MiniMessage. 2024-01-07 00:27:21 +01:00
= 94a807d7c2 Change message processing to include MiniMessage formatting 2024-01-07 00:27:21 +01:00
= 0d01cb956e Add the Adventure (MiniMessage) dependency in Gradle 2024-01-07 00:27:21 +01:00
md5sha256 55c4f7f369 Expose libraries as api instead of implementation 2024-01-06 18:47:35 +01:00
md5sha256 3348e5b697 Use the non-deprecrated way to declare the paperdevbundle. Fix missing publishing task on modules 2023-12-07 02:28:24 +08:00
md5sha256 381c8b2ebe Only exclude publishing the bukkit 1.17 module 2023-12-07 02:21:11 +08:00
md5sha256 6bf344e6be Fix inverted condition in checking the if the project is the platform adapter 2023-12-07 02:13:52 +08:00
md5sha256 e2bcc57128 Shade jetbrains annotations 2023-12-07 02:08:37 +08:00
md5sha256 6df08bc713 Compare project by name 2023-12-07 01:59:28 +08:00
md5sha256 0e0b085000 Include the platformInterface project in publishing 2023-12-07 01:56:22 +08:00
md5sha256 4f9fc950f0 Refactor the buildscript to only require platform deps in a non-jitpack environment 2023-12-07 01:50:01 +08:00
md5sha256 fe16d732a2 Revert "Only publish the core plugin jar, don't publish other utility modules"
This reverts commit 8cc44cf79f.
2023-12-07 01:48:31 +08:00
md5sha256 8cc44cf79f Only publish the core plugin jar, don't publish other utility modules 2023-12-07 01:42:39 +08:00
md5sha256 4fd478dbc3 use env variable instead of system prop 2023-12-06 22:47:38 +08:00
md5sha256 fe77bf0318 Set the archive base name to the default if in the jitpack env 2023-12-06 21:35:30 +08:00
md5sha256 e4b53982b2 Don't change the name of the jar if in the jitpack env 2023-12-06 21:27:25 +08:00
md5sha256 3c953ad9a3 Bump version to 2.7.17-SNAPSHOT 2023-12-06 21:27:09 +08:00
md5sha256 88f55bb6a9 Release 2.7.16 2023-12-06 20:13:28 +08:00
md5sha256 4ba8326314 Update dependencies and minor buildscript changes 2023-12-06 20:01:08 +08:00
md5sha256 de81d92da0 Update the SDK before installing 2023-12-06 19:50:50 +08:00
md5sha256 f636a98314 Use temurin jdk in jitpack.yml 2023-12-06 19:45:08 +08:00
md5sha256 e4df5a8cc9 Update gradle wrapper to 8.5 2023-12-06 19:33:54 +08:00
Andrew Wong 56818bebdb Add transfer feature
Adds /as transfer
2023-11-24 21:50:07 +11:00
Andrew Wong 7e1d7168f1 Refactor transfer to transfer both buyers and renters. Update lang files and fix data keys in GeneralRegion 2023-11-24 21:47:40 +11:00
Andrew Wong ff1ea3ae51 Add default config for transfers 2023-11-24 21:47:38 +11:00
Andrew Wong c9dc8dd840 Add SetTransferCommand 2023-11-24 21:47:36 +11:00
Andrew Wong c0794daeeb Actually respect transfers being disabled 2023-11-24 21:47:34 +11:00
Andrew Wong d40b9c660b Fix transfer missing region arg replacement and incorrect ownership checks in TransferCommand 2023-11-24 21:47:32 +11:00
Andrew Wong f7b010b3f3 Fix lang issue with region not being replaced, fix landlord/owner not being changed 2023-11-24 21:47:30 +11:00
Andrew Wong a06d9271c4 Make sure tab complete list is mutable in transfer command 2023-11-24 21:47:27 +11:00
Andrew Wong dd343aa587 Add messages for when regions are transferred 2023-11-24 21:47:25 +11:00
Andrew Wong e09d4ebd83 Fix lang and incorrect argument access 2023-11-24 21:47:23 +11:00
Andrew Wong 5f435941e4 Add transfer region command 2023-11-24 21:47:19 +11:00
Andrew Wong 86316cdd5b Prepare for snapshot 2.7.16 2023-11-24 21:43:33 +11:00
Andrew Wong 61828d3cfd Release 2.7.15 2023-11-24 21:38:48 +11:00
Andrew Wong 54241d5ce3 Replace the warning of null owner on shutdown with null checks of the owner uuid 2023-11-15 13:06:22 +11:00
Andrew Wong d048665530 Cache the landlord instead of parsing it twice in GeneralRegion#isLandLord 2023-11-15 13:01:34 +11:00
Andrew Wong 23de68431c Replace Random instantiations with ThreadLocalRandom in FindCommand 2023-11-15 12:40:17 +11:00
Andrew Wong 95b4543f19 Fix null pointer when comparing null pre release types in VersionData 2023-11-14 03:46:28 +11:00
Andrew Wong d058bb7271 Refactor platform adapters to legacy (1.17.1) and modern (1.18+). Add semver parsing utilities. Fix bug with github updater treating snapshot versions as newer 2023-11-13 22:30:34 +11:00
Andrew Wong 63d26be369 2.7.15-SNAPSHOT 2023-11-13 21:06:58 +11:00
Andrew Wong 1020388aae Release 2.7.14 2023-11-12 18:04:01 +11:00
Andrew Wong e56107ffd6 Fix signs not being deleted from the global sign cache in memory 2023-11-12 17:59:34 +11:00
Andrew Wong 06fceb4643 Drop support for 1.20 and 1.20.1 2023-11-12 15:50:51 +11:00
Andrew Wong e2077c3b32 Fix region signs losing their interactivity after restart. Resolves #20 2023-11-12 15:40:03 +11:00
Andrew Wong fcb64c2ddb Merge pull request #22 from o0sh4d0w0o/ResoldRegionEvent-resellprice-fix
Fixed getResellPrice unsetted when ResoldRegionEvent is notified
2023-10-04 21:35:03 +11:00
o0sh4d0w0o cc51109720 Fixed getResellPrice unsetted when ResoldRegionEvent is notified 2023-10-01 16:03:07 +02:00
Andrew Wong 0b48f4dd2e Fix not including 1.20.2 adapter 2023-09-25 11:37:12 +10:00
Andrew Wong 4d7f00b0ce Add support for 1.20.2 2023-09-25 11:33:02 +10:00
Andrew Wong b27ea83982 Include 1.18-1.20 adapters for jitpack 2023-09-03 08:47:21 +10:00
Andrew Wong 66da717a77 Fix relocations 2023-09-03 08:47:19 +10:00
Andrew Wong 7f779d2df8 Bump version to 2.7.14-SNAPSHOT 2023-09-03 08:47:16 +10:00
Andrew Wong ed3bd01f2a Fix bad release url
Fixes #19
2023-09-03 07:22:58 +10:00
Andrew Wong ef03501d1c 2.7.13 release 2023-08-30 22:09:28 +10:00
Andrew Wong feb35cfd37 User api for BlockBehaviourImpl 1.18 onwards 2023-08-30 22:08:50 +10:00
Andrew Wong b6a8dcc24c Fix module desc for paper 1.20 2023-08-30 20:23:05 +10:00
Andrew Wong 5619612a6e Update gradle wrapper 2023-08-28 23:10:54 +10:00
Andrew Wong 26ac52cc0a Include plugin adapters in jitpack build 2023-08-28 22:46:14 +10:00
Andrew Wong 5f6bd55afe Don't include nms impls if on jitpack 2023-08-28 22:34:28 +10:00
Andrew Wong aba2e12c5d Don't include nms impls if on jitpack 2023-08-28 22:26:28 +10:00
Andrew Wong 2906de11de Fix merge conflicts 2023-08-28 22:17:42 +10:00
Andrew Wong 436672f85b Don't shadowJar and don't include nms providers if building on jitpack 2023-08-28 22:12:09 +10:00
Andrew Wong 5ba8ed7ad8 Add spotbugs 2023-08-28 20:57:17 +10:00
Andrew Wong 00d97f1beb Update dependencies 2023-08-28 20:36:52 +10:00
Andrew Wong f530fa40af Fix signs not being saved on server stop 2023-08-28 20:14:12 +10:00
Andrew Wong a804df2257 Add jitpack logo 2023-08-09 14:08:12 +10:00
Andrew Wong c96e0b464e More jitpack tests 2023-08-09 13:58:44 +10:00
Andrew Wong 13e52aa4f1 More jitpack tests 2023-08-09 13:55:52 +10:00
Andrew Wong 9aeb531d16 More jitpack tests 2023-08-09 13:52:23 +10:00
Andrew Wong 44f83473d1 Add jitpack.yml 2023-08-09 13:46:05 +10:00
Andrew Wong d7260998f5 Update Guice to 7.0.0 and use JakartaEE annotations 2023-06-12 00:59:16 +10:00
Andrew Wong 638382eacf Snapshot 2.7.13 2023-06-12 00:58:34 +10:00
Andrew Wong e18fe99161 Release 2.7.12 2023-06-12 00:40:46 +10:00
Andrew Wong bdc9e32c13 Add support for 1.20 2023-06-12 00:40:08 +10:00
Andrew Wong 9a46d5ae3b Bump version to 2.7.12-SNAPSHOT 2023-03-29 16:14:26 +11:00
Andrew Wong 6795fc43d9 Release 2.7.11 2023-03-29 16:13:54 +11:00
Andrew Wong dd9bd2c434 Drop support for 1.19.3 and add support for 1.19.4 2023-03-29 16:13:23 +11:00
Andrew Wong 9438166180 Prepare for development 2.7.11 2023-02-27 21:58:41 +11:00
Andrew Wong 9e06b9f268 Release 2.7.10 2023-02-27 21:58:14 +11:00
Andrew Wong 4562bf23f6 Update libs 2023-02-27 21:57:49 +11:00
Andrew Wong 24edb01754 Refactor GeneralRegion#getOwner, #isOwner and #setOwner 2023-02-27 21:46:59 +11:00
Andrew Wong 2739bf6ad4 Fix javadocs for IFileManager 2023-02-27 21:41:28 +11:00
Andrew Wong 2ce84186ab Use Server#getOfflinePlayer in PlayerOfflinePlayerHelper 2023-02-27 21:39:48 +11:00
Andrew Wong 279fa001ea Only support 1.19.3 2023-02-27 11:56:41 +11:00
Andrew Wong b56d5320a6 Add support for 1.19.3 2022-12-15 16:25:06 +08:00
Andrew Wong 30665908b9 Bump to 2.7.10-SNAPSHOT 2022-12-09 16:53:03 +08:00
Andrew Wong 0fd384833a Bump version to 2.7.9 release 2022-12-09 16:45:57 +08:00
Andrew Wong 09634de4bf Fix BukkitSchedulerExecutor not having an injectable ctor 2022-12-07 12:13:34 +08:00
Andrew Wong 7fafee82a7 Minor cleanup 2022-12-07 11:59:37 +08:00
Andrew Wong 2899b2978c Rewrite SetownerCommand 2022-12-07 11:56:50 +08:00
Andrew Wong 7afcba79c9 Rewrite SetlandlordCommand 2022-12-07 11:53:44 +08:00
Andrew Wong 72084b38f8 Use OfflinePlayerHelper in MeCommand 2022-12-07 11:49:01 +08:00
Andrew Wong 6a291feedd Rewrite DelFriendCommand 2022-12-07 11:45:16 +08:00
Andrew Wong b85566882c Rewrite AddfriendCommand 2022-12-07 11:39:09 +08:00
Andrew Wong c14407e14b Add PaperPlatform 2022-12-07 01:23:12 +08:00
Andrew Wong ae9bd60d1b Fix typo 2022-09-14 21:25:04 +08:00
Andrew Wong c689c2fae0 Fix dependency versions for WG and WE, and add a section for FAWE 2022-09-14 21:24:48 +08:00
Andrew Wong 728cfb6dfa Add a compiling.md 2022-09-14 21:16:03 +08:00
Andrew Wong 3abb6c06e4 Update readme 2022-09-14 20:56:00 +08:00
Andrew Wong 51c11738af Prepare for snapshot development 2022-09-12 22:39:45 +08:00
Andrew Wong 172b5a99f1 Bump version to release 2022-09-12 22:21:28 +08:00
Andrew Wong 4c5d025e54 Add config option to toggle whether entities are forcefully cleared 2022-09-12 22:20:55 +08:00
Andrew Wong e93a2d04de Forcefully remove entities from FAWE/WE regions before schematic pasting 2022-09-12 22:12:18 +08:00
Andrew Wong af5980d555 Change the messages for update checking and report file manager loading failures 2022-09-12 17:58:09 +08:00
Andrew Wong 3f7249f4a1 Merge pull request #13 from cleonyc/dev/bleeding
Allow unrented event to use placeholders
2022-09-12 17:39:56 +08:00
Andrew Wong 73c6fc858e Update the logging methods to invoke conditionally 2022-09-12 17:37:47 +08:00
Andrew Wong 360c3e7e21 Use Suppliers when logging in the plugin adapters 2022-09-12 17:35:55 +08:00
Andrew Wong 73d0115b78 Actually fix the FAWE and WE handlers when pasting 2022-09-12 17:25:27 +08:00
Andrew Wong baf7eaabf1 Bump versions of WE and FAWE in the libs.toml 2022-09-11 00:50:36 +08:00
Andrew Wong ca8c0487a8 Fix origin setting so that the blocks paste properly 2022-09-11 00:44:47 +08:00
Andrew Wong 24156a03c4 Rewrite region saving and restoring in the adapters 2022-09-10 23:14:28 +08:00
Andrew Wong ec677766d2 Attempt to prevent duplicate signs from loading 2022-09-10 19:27:03 +08:00
Andrew Wong ef6c8fbf9d Only remove leashes, paintings and item frames 2022-09-10 17:54:48 +08:00
Andrew Wong 4f52fe9e6e Forcefully remvoe Entities in the region before pasting 2022-09-10 17:43:07 +08:00
Andrew Wong 3ebe5a6fa9 Use the WG converter to convert WG regions to WE ones 2022-09-10 17:02:29 +08:00
Andrew Wong 3cebe5d2c7 Fix NPE with sign deletion after worlededit operations 2022-09-10 14:59:35 +08:00
Andrew Wong c76415c4f3 Fix NPE when tabbing region restore 2022-09-10 12:47:45 +08:00
Andrew Wong b7bc02aef3 Compile against 1.19.2 and update the gradle wrapper 2022-09-07 15:31:33 +08:00
Cleo d75094e191 Remove unrenting section in eventCommandProfile 2022-07-07 13:51:02 -04:00
Cleo 4045914b48 Fix placeholders in unrented command event [#11] 2022-07-07 13:50:04 -04:00
Andrew Wong 1fac002ee0 Remove the Bukkit113 module and update the versioning url 2022-06-20 19:57:22 +08:00
Andrew Wong 64301e74e0 Bump version 2022-06-20 19:27:28 +08:00
Andrew Wong 5a5a7fc5ef Bump version 2022-06-20 19:25:42 +08:00
Andrew Wong b928caf0c2 Bump worldedit 2022-06-20 19:19:49 +08:00
Andrew Wong 111f629787 Update dependencies and add adapter for 1.19 2022-06-11 00:59:19 +08:00
Andrew Wong 718474ca95 Update gradle wrapper 2022-06-10 23:37:12 +08:00
Andrew Wong 93b9df3e54 Update gradle wrapper to 7.4.1 2022-03-24 18:48:03 +08:00
Andrew Wong bad983a0b8 Update worldedit and fawe adapters 2022-03-24 18:47:02 +08:00
Andrew Wong e2c8b06b68 Bump dependency versions 2022-03-24 16:30:02 +08:00
Andrew Wong 7249e39c02 bump version 2022-03-24 16:27:49 +08:00
Andrew Wong 9d9a58a170 bump to 2.7.6 2022-03-24 16:24:56 +08:00
Andrew Wong e64e884c2a Updates to the fawe module 2022-03-05 00:00:34 +08:00
Andrew Wong 6ad4ff9deb Shade in the provider for 1.18.1 2022-03-05 00:00:23 +08:00
Andrew Wong eec9806492 Add back support for 1.18.1 2022-03-04 23:08:43 +08:00
Andrew Wong 43b2ae8278 Fix bad website in plugin.yml 2022-03-04 22:54:40 +08:00
Andrew Wong 6d5a92e389 1.18.2 2022-03-04 22:48:39 +08:00
Andrew Wong 7d7a62ffa0 Bump gradle wrapper to 7.4 2022-03-03 17:41:52 +08:00
md5sha256 44456d87b6 Fix the sign error file extension 2022-01-25 05:49:47 +08:00
md5sha256 d92c710b27 bump version to snapshot 2022-01-25 05:49:35 +08:00
md5sha256 3dceaf98cd Bump version to 2.7.5 2022-01-25 05:35:08 +08:00
md5sha256 33c29a3756 Fix the fawe integration and do operations async when possible 2022-01-25 05:34:34 +08:00
md5sha256 771734360f add workflow 2022-01-16 23:24:28 +08:00
md5sha256 539e908d32 Initial work on fixing the deadlock in the fawe module 2022-01-16 21:45:11 +08:00
md5sha256 088471aa3c more project restructuring 2022-01-16 21:28:28 +08:00
md5sha256 5a95c95670 Fix gitignore and restructure project 2022-01-16 20:58:44 +08:00
md5sha256 5a5d627d51 Fix publishing 2022-01-16 15:26:54 +08:00
md5sha256 9b5434a4b2 Add type safe project acessors and version catalog 2022-01-16 14:40:19 +08:00
md5sha256 e13717950b Kotlin dsl 2022-01-16 12:05:39 +08:00
md5sha256 03ed2803bd Bump version to 2.7.3 2022-01-15 07:38:40 +08:00
md5sha256 b3f1225934 Deprecate the FAWE WG handler and fix fawe version parsing 2022-01-15 07:36:43 +08:00
md5sha256 68651899b7 Update the fawe module 2022-01-10 22:59:03 +08:00
md5sha256 4a7a4ca4ee Fix reobf 2022-01-10 22:34:35 +08:00
md5sha256 0d272c8fe9 Publish nms provider poms 2021-12-05 23:07:05 +08:00
md5sha256 6b2c905939 Parallel builds 2021-12-05 22:57:17 +08:00
md5sha256 7ab782799b Fix maven publish tasks 2021-12-05 22:57:03 +08:00
md5sha256 bea82eae88 Fix maven publish tasks 2021-12-05 22:56:37 +08:00
md5sha256 4ac0e045bd Add maven publish task 2021-12-05 18:22:41 +08:00
md5sha256 e5061b218e Java 17 and 1.18 2021-12-01 17:59:17 +08:00
md5sha256 40fdfba47d Fix silly typo in the buildscript 2021-11-18 22:16:36 +08:00
md5sha256 e9260cede6 Bump gradle wrapper version to 7.3 2021-11-18 22:14:56 +08:00
md5sha256 bb297c9ff1 Bump version 2021-11-16 15:28:14 +08:00
Andrew Wong 666742ad56 Merge pull request #2 from md5sha256/feature/purge 2021-11-16 15:25:54 +08:00
md5sha256 36eb8c3a5e Fix imports 2021-11-16 15:25:01 +08:00
Olzie-12 06a9f7b28e file management 2021-11-14 14:41:41 +00:00
md5sha256 e101780420 Fix compat for file manager 2021-11-11 13:31:09 +08:00
md5sha256 6abe99e807 Log sign warnings to the sign error logger 2021-11-09 19:06:02 +08:00
md5sha256 a1d18521ee Introduce interface for FileManager 2021-10-11 00:00:57 +08:00
md5sha256 363b416c59 Retain compat for FileManager 2021-10-10 03:48:12 +08:00
md5sha256 7bf516108b Rename AreaShop again and fix teleport feature 2021-10-09 22:22:53 +08:00
md5sha256 7567cb5fe4 Cleanup global features 2021-10-09 21:33:19 +08:00
md5sha256 d2ca54e8ea Fix signs not updating 2021-10-09 21:03:25 +08:00
md5sha256 e47cda4254 Fix plugin.yml 2021-10-09 17:44:01 +08:00
md5sha256 98d4c6a778 Fix relocations and cleanup DI for Economy and Permission 2021-10-09 17:40:10 +08:00
md5sha256 2a44dd29cc Fix relocations 2021-10-09 17:29:36 +08:00
md5sha256 c1665c33ff Finish cleaning up DI 2021-10-09 17:24:28 +08:00
md5sha256 2cdab9b6db Initial work on guice 2021-10-09 13:27:46 +08:00
md5sha256 72faf76619 Fix ClassCastException in RegionSign 2021-10-09 13:27:28 +08:00
md5sha256 ad66ce00b1 Actually register the sign listener 2021-10-09 02:00:38 +08:00
md5sha256 edc7126b87 Performance improvements to FileManager and various commands 2021-10-09 01:02:00 +08:00
md5sha256 a7f0ac248c Initial work on sign refactoring 2021-10-08 17:44:43 +08:00
md5sha256 675dee2cd3 Add sign error logger 2021-10-07 03:12:45 +08:00
md5sha256 c7226750ab Don't check for WG v5 2021-10-07 01:36:36 +08:00
md5sha256 2ecbb61053 Performance improvements for the teleport feature 2021-10-07 01:34:18 +08:00
md5sha256 fc132558a3 Add a BlockBehaviourHelper 2021-10-07 01:24:20 +08:00
md5sha256 b172413b62 Minor performance improvements 2021-10-07 00:11:09 +08:00
md5sha256 dcbb1f5896 Fix buildscripts and Java 16 support 2021-10-06 23:59:23 +08:00
md5sha256 6e3855c0c3 Remove legacy modules, remove use of ScriptEngine 2021-10-06 23:46:58 +08:00
md5sha256 27991d17a2 Gradle 2021-10-06 23:39:57 +08:00
md5sha256 159221d53d Initial work on updating to 1.17 2021-10-05 23:45:25 +08:00
dependabot[bot] 557d11dfb4 Bump checkstyle from 8.21 to 8.29
Bumps [checkstyle](https://github.com/checkstyle/checkstyle) from 8.21 to 8.29.
- [Release notes](https://github.com/checkstyle/checkstyle/releases)
- [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-8.21...checkstyle-8.29)

Signed-off-by: dependabot[bot] <support@github.com>
2020-02-26 11:02:43 +01:00
Thijs Wiefferink b9547e2c67 Remove github action experiment 2019-08-16 18:22:19 +02:00
Thijs Wiefferink 221785ae55 Add test workflow maven build 2019-08-16 17:42:22 +02:00
Thijs Wiefferink 0d04676bce Fix including bukkit into the AreaShop jar 2019-06-23 22:27:35 +02:00
Thijs Wiefferink c8cd68c17b Fixup javadoc build 2019-06-23 22:07:34 +02:00
Thijs Wiefferink 539887449c pom.xml: build with craftbukkit 1.13 2019-06-23 21:59:04 +02:00
Thijs Wiefferink 4cda8a9292 Fix sign handling for 1.14
- Setup modules to load different classes for different Bukkit/Spigot versions
- Create BukkitHandler to get/set the sign facing and get the block it is attached to
- Fix `/as addsign` to use new sign methods
- Fix sign updates to use new sign methods
- Implement full forwards and backwards compatibility of the saved sign material type
    - On Bukkit 1.12 and lower all special wood types are translated to the standard sign
    - On Bukkit 1.13 the internal sign name is translated (and special wood types to the standard one)
    - On Bukkit 1.14 the signs of 1.13- are translated to the OAK variants
- Cleanup the .gitignore files inside of the module folders
2019-06-23 21:53:48 +02:00
Thijs Wiefferink fe131dc157 BuyRegion/RentRegion: fix %player% placeholders for selling/unrenting confirmation messages 2019-06-16 21:40:58 +02:00
Thijs Wiefferink 41ced9ee6c Update checkstyle from 7.6 to 8.21 2019-06-01 17:08:30 +02:00
Thijs Wiefferink 03de0ff252 default.yml: fix spelling mistake 2019-06-01 16:24:15 +02:00
Thijs Wiefferink b057271394 Fix permission check of /as rent, fix 'already bought' check of /as buy 2019-02-20 19:33:37 +01:00
Thijs Wiefferink d7cdff0b22 /as setteleport: fix check that hides it from /as help 2019-02-08 22:29:57 +01:00
Thijs Wiefferink 1035b6b41b Move event commands to a feature class, add two events
- Move eventCommandProfile code to a separate class
- Add AddingRegionEvent
- Add DeletingRegionEvent
- Cleanup a couple of duplicate code paths (merge RentRegion/BuyRegion branches)
2019-01-28 23:37:43 +01:00
Thijs Wiefferink e0bad7397c Refactoring based on SonarLint and Intellij IDEA inspections 2019-01-26 21:23:49 +01:00
Thijs Wiefferink b7124e8cdd Remove mcstats.org metrics class, I don't believe they will be online again 2019-01-26 20:11:26 +01:00
Thijs Wiefferink f0952c32c9 Update issue templates
Add 'NEW' label to issues created using the template
2019-01-13 22:26:54 +01:00
Thijs Wiefferink d3dfa86a65 Set version to 2.6.0 2019-01-13 17:34:50 +01:00
Thijs Wiefferink 8f73b8af3c documentation/release.md: add instructions for releasing a new version 2019-01-13 17:34:37 +01:00
Thijs Wiefferink 51b24c74b4 langHeader.yml: add the template used to generate the language file headers to the repository 2019-01-13 17:33:54 +01:00
Thijs Wiefferink 9beb1eb61b Move the changelog from the wiki to the repository 2019-01-13 17:33:09 +01:00
Thijs Wiefferink de5fdafca0 Pull translations from Transifex 2019-01-08 21:18:19 +01:00
Thijs Wiefferink 0aea914d20 Add FastAsyncWorldEdit support on Spigot 1.13
- FastAsyncWorldEdit now supported on Spigot 1.13
- Improved support for the beta-01 versions of WorldGuard and WorldEdit
- Resolves #436
2019-01-08 00:19:48 +01:00
Thijs Wiefferink b4efe7d5bf Add default labels to issue templates 2019-01-05 16:27:05 +01:00
Thijs Wiefferink ec7983e126 Fix handling of sign updates at places where they will pop off immediately
1. When placing back a missing sign it could be placed in the middle of the air
2. BlockPhysicsEvent would fire immediately (synchronously) breaking the sign
3. Sign update would break because the sign has not actually been placed
2019-01-01 19:32:34 +01:00
Thijs Wiefferink e45c353030 Fix detecting region by location when using WorldEdit 7 beta-2 or later
- The WorldEdit 7 beta-2 handler was inheriting a function from the handler of older version that uses the old Vector class
- Fixes #466
- Fixes #467
2019-01-01 19:30:16 +01:00
Thijs Wiefferink 44b1cb0fc8 /as add: fix setting player as landlord when he is an owner of the region
- Fixes #427
- Adds a debug message to check the behavior easily in the future
2018-12-28 17:11:48 +01:00
Thijs Wiefferink c7299fa56c Update Discord image to a widget image 2018-12-27 23:14:56 +01:00
pmme 12bf467714 Simplify WorldEdit 7 flushQueue vs. flushSession 2018-12-27 22:47:14 +01:00
Thijs Wiefferink 5b327db316 signs: instead of cancelling indirect break, remove the sign to prevent lagg 2018-12-27 19:44:30 +01:00
Thijs Wiefferink b4f33589a1 Cleanup old directory 2018-12-27 17:45:19 +01:00
Thijs Wiefferink 530c74ccd2 Add support for the WorldEdit vector refactor update
- Add WorldEdit and WorldGuard module that supports the new vector system
- WorldGuard/WordEdit dependencies are in the repository itself to make builds more reliable
- Change code that uses WorldEdit vectors to use Spigot vectors
- Rename all modules to areashop-[worldguard|worldedit]-<version>
- Change maven versions of internal modules to 'latest' to be less confusing
2018-12-27 17:42:24 +01:00
Thijs Wiefferink fa4857cbce Simplify code in the handler for WorldEdit 7 2018-12-27 15:00:53 +01:00
Thijs Wiefferink 93fd4e96cb Fix restoring schematics for the latest WorldEdit dev builds
- Fixes #447
- Thanks pmme and x1p for reporting the issue!
2018-10-28 17:58:09 +01:00
Thijs Wiefferink a6863ae782 Also put the Vault dependency into /dependencies
- Now it should be easy again to built AreaShop yourself, only need to run BuildTools for 1.13.0 and it should work
2018-10-28 01:15:12 +02:00
Thijs Wiefferink e5e2c4ca08 Fixup dependencies, use Bukkit/CraftBukkit 1.7.9 instead of 1.8
- 1.7.9 is the lowest supported version, so it is good to use that as base
2018-10-28 00:53:30 +02:00
Thijs Wiefferink b0341e2a3e Fix compatibility with 1.13 Material class
- Fixes sign handling to properly detect and store signs, fixes #440
- Fixes safe teleporting (also improves block detection, making it even safer)
2018-10-28 00:12:24 +02:00
Thijs Wiefferink c8e1ebb068 Change WorldGuard/WorldEdit/Bukkit dependencies to file links
- Fixes the issue that olders WorldEdit and Bukkit versions are not available on Maven anymore
- This speeds up the build a lot
2018-10-28 00:00:41 +02:00
Thijs Wiefferink 39c8eb5f73 Fix tab complete types for /as setduration 2018-10-22 23:44:31 +02:00
Thijs Wiefferink 2483cf1614 Try to add compatibility with the FAWE schematic format 2018-10-21 21:59:45 +02:00
249 changed files with 16763 additions and 9422 deletions

No files matched your search

+3
View File
@@ -1,6 +1,9 @@
---
name: Bug report
about: Report a problem in the plugin
title: ''
labels: 'NEW, Type: Bug'
assignees: ''
---
@@ -1,6 +1,9 @@
---
name: Feature request
about: Suggest an idea
title: ''
labels: 'NEW, Type: Feature'
assignees: ''
---
@@ -1,6 +1,9 @@
---
name: Support question
about: Ask help with the setup or usage of the plugin
title: ''
labels: 'NEW, Type: Support'
assignees: ''
---
+23
View File
@@ -0,0 +1,23 @@
name: Java CI with Gradle
on: [ push, pull_request ]
jobs:
build:
# Only run on PRs if the source branch is on someone else's repo
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
strategy:
matrix:
os: ["ubuntu-latest", "windows-latest"]
runs-on: "${{ matrix.os }}"
steps:
- uses: actions/checkout@v4
- uses: gradle/actions/wrapper-validation@v3
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'zulu'
cache: 'gradle'
- name: Build with Gradle
run: ./gradlew clean build
+191 -20
View File
@@ -1,25 +1,196 @@
# Maven stuff
/target
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# Created by https://www.toptal.com/developers/gitignore/api/macos,windows,intellij+all,gradle,maven
# Edit at https://www.toptal.com/developers/gitignore?templates=macos,windows,intellij+all,gradle,maven
# Locally stored "Eclipse launch configurations"
*.launch
### Intellij+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Intellij+all Patch ###
# Ignores the whole .idea folder and all .iml files
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
.idea/*
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
# IntelliJ IDEA
*.iml
.idea
dependency-reduced-pom.xml
modules.xml
.idea/misc.xml
*.ipr
desktop.ini
# Sonarlint plugin
.idea/sonarlint
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
# Eclipse m2e generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
### Gradle ###
.gradle
build/
build-cache/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Cache of project
.gradletasknamecache
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
# gradle/wrapper/gradle-wrapper.properties
### Gradle Patch ###
**/build/
# End of https://www.toptal.com/developers/gitignore/api/macos,windows,intellij+all,gradle,maven
**/run
-1
View File
@@ -1 +0,0 @@
/target
+144
View File
@@ -0,0 +1,144 @@
plugins {
id("io.github.goooler.shadow") version "8.1.7"
id("xyz.jpenilla.run-paper") version "2.3.0"
}
idea {
module {
isDownloadSources = true
}
}
description = "AreaShop"
dependencies {
// Platform
compileOnlyApi(libs.spigot)
compileOnlyApi(libs.worldeditCore)
compileOnlyApi(libs.worldeditBukkit)
compileOnlyApi(libs.worldguardCore)
compileOnlyApi(libs.worldguardBukkit)
compileOnlyApi("com.github.MilkBowl:VaultAPI:1.7")
// 3rd party libraries
api("io.papermc:paperlib:1.0.8")
api("com.github.NLthijs48:InteractiveMessenger:e7749258ca")
api("com.github.NLthijs48:BukkitDo:819d51ec2b")
api("io.github.baked-libs:dough-data:1.2.0")
api("com.google.inject:guice:7.0.0") {
exclude("com.google.guava")
}
api("com.google.inject.extensions:guice-assistedinject:7.0.0") {
exclude("com.google.guava")
}
implementation("org.incendo:cloud-paper:2.0.0-beta.10") {
exclude("com.google.guava")
}
implementation("org.incendo:cloud-processors-confirmation:1.0.0-beta.3") {
exclude("com.google.guava")
}
implementation("net.kyori:adventure-text-minimessage:4.16.0")
implementation("net.kyori:adventure-platform-bukkit:4.3.2")
implementation("org.spongepowered:configurate-yaml:4.1.2")
// Project submodules
api(projects.areashopInterface)
api(projects.adapters.platform.platformInterface)
api(projects.adapters.platform.paper)
if (!providers.environmentVariable("JITPACK").isPresent) {
// We don't need these adapters if we are only publishing an api jar
runtimeOnly(projects.adapters.plugins.worldedit)
runtimeOnly(projects.adapters.plugins.worldguard)
runtimeOnly(projects.adapters.plugins.fastasyncworldedit)
runtimeOnly(projects.adapters.plugins.essentials)
}
testImplementation("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT")
testImplementation("com.github.seeseemelk:MockBukkit-v1.21:3.131.0")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.1")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.1")
}
repositories {
mavenCentral()
}
tasks {
processResources {
filesMatching("plugin.yml") {
expand("version" to project.version)
}
}
assemble {
if (!providers.environmentVariable("JITPACK").isPresent) {
dependsOn(shadowJar)
}
}
jar {
archiveBaseName.set("AreaShop")
if (!providers.environmentVariable("JITPACK").isPresent) {
archiveClassifier.set("original")
} else {
archiveClassifier.set("")
}
}
if (providers.environmentVariable("JITPACK").isPresent) {
artifacts {
archives(jar)
}
}
java {
withSourcesJar()
}
val javaComponent = project.components["java"] as AdhocComponentWithVariants
javaComponent.withVariantsFromConfiguration(configurations["shadowRuntimeElements"]) {
skip()
}
shadowJar {
archiveClassifier.set("")
base {
archiveBaseName.set("AreaShop")
}
val base = "me.wiefferink.areashop.libraries"
relocate("org.incendo.cloud", "${base}.cloud")
relocate("me.wiefferink.interactivemessenger", "${base}.interactivemessenger")
relocate("me.wiefferink.bukkitdo", "${base}.bukkitdo")
relocate("io.papermc.lib", "${base}.paperlib")
relocate("io.github.bakedlibs.dough", "${base}.dough")
relocate("com.google.inject", "${base}.inject")
relocate("com.google.errorprone", "${base}.errorprone")
relocate("org.aopalliance", "${base}.aopalliance")
relocate("javax.annotation", "${base}.javax.annotation")
relocate("jakarta.inject", "${base}.jakarta.inject")
relocate("org.jetbrains.annotations", "${base}.jetbrains.annotations")
relocate("io.leangen.geantyref", "${base}.geantyref")
relocate("net.kyori", "${base}.kyori")
relocate("org.checkerframework", "${base}.checkerframework")
relocate("org.intellij", "${base}.intellij")
relocate("org.spongepowered", "${base}.spongepowered")
relocate("org.yaml.snakeyaml", "${base}.snakeyaml")
}
runServer {
// Configure the Minecraft version for our task.
// This is the only required configuration besides applying the plugin.
// Your plugin's jar (or shadowJar if present) will be used automatically.
minecraftVersion("1.21.1")
downloadPlugins {
github("EssentialsX", "essentials", "2.20.1", "EssentialsX-2.20.1.jar")
github("MilkBowl", "Vault", "1.7.3", "Vault.jar")
// WorldEdit 7.3.9
url("https://mediafilez.forgecdn.net/files/5935/693/worldedit-bukkit-7.3.9.jar")
// WorldGuard 7.0.12
url("https://mediafilez.forgecdn.net/files/5719/698/worldguard-bukkit-7.0.12-dist.jar")
}
}
}
-280
View File
@@ -1,280 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>areashop</artifactId>
<packaging>jar</packaging>
<name>AreaShop</name>
<version>2.5.0</version> <!-- Main plugin version -->
<parent>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-parent</artifactId>
<version>parent</version>
</parent>
<dependencies>
<!-- Bukkit, AreaShop aims to support 1.7.9+, but this is the lowest Bukkit version available from the Spigot repo, Bukkit repository is gone -->
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>${bukkit.version}</version>
<type>jar</type>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- InteractiveMessenger library -->
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>interactivemessenger</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
<!-- BukkitDo library -->
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>bukkitdo</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-5</artifactId>
<version>WorldGuard-5</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-6</artifactId>
<version>WorldGuard-6</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-6_1_3</artifactId>
<version>WorldGuard-6_1_3</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-7</artifactId>
<version>WorldGuard-7</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-interface</artifactId>
<version>AreaShopInterface</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldedit-5</artifactId>
<version>WorldEdit-5</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldedit-6</artifactId>
<version>WorldEdit-6</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldedit-7</artifactId>
<version>WorldEdit-7</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>worldedit</artifactId>
<scope>system</scope>
<version>any</version>
<systemPath>${project.basedir}/../dependencies/worldedit-bukkit-7.0.0-beta-01.jar</systemPath>
</dependency>
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>worldguard</artifactId>
<scope>system</scope>
<version>any</version>
<systemPath>${project.basedir}/../dependencies/worldguard-legacy-7.0.0-beta01.jar</systemPath>
</dependency>
<dependency>
<groupId>net.milkbowl.vault</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
<profiles>
<!-- Copy the jar file to a test server, activate by using -DcopyResult="/path/to/test/server" -->
<profile>
<id>test-locally</id>
<activation>
<property>
<name>copyResult</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<configuration>
<target>
<copy file="./target/${project.build.finalName}.jar"
tofile="${copyResult}\${project.build.finalName}.jar"/>
</target>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<!-- Package the source files in a jar, activate by using -Dsources -->
<profile>
<id>package-sources</id>
<activation>
<property>
<name>sources</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<!-- Produce javadoc files, activate by using -Djavadoc -->
<profile>
<id>generate-javadoc</id>
<activation>
<property>
<name>javadoc</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<executions>
<execution>
<phase>package</phase>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
<configuration>
<excludePackageNames>me.wiefferink.areashop.lib</excludePackageNames>
<destDir>${javadoc}</destDir>
<links>
<link>https://hub.spigotmc.org/javadocs/bukkit/</link>
<link>http://docs.sk89q.com/worldedit/apidocs/</link>
<link>http://docs.sk89q.com/worldguard/apidocs/</link>
</links>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<directory>target</directory>
<finalName>AreaShop</finalName>
<resources>
<resource>
<targetPath>.</targetPath>
<filtering>true</filtering>
<directory>src/main/resources</directory>
<includes>
<include>plugin.yml</include>
<include>config.yml</include>
<include>hiddenConfig.yml</include>
<include>default.yml</include>
<include>README.md</include>
<include>lang/*.yml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<!-- Relocate messaging framework -->
<relocation>
<pattern>me.wiefferink.interactivemessenger</pattern>
<shadedPattern>me.wiefferink.areashop.shaded.interactivemessenger</shadedPattern>
</relocation>
<!-- Relocate BukkitDo -->
<relocation>
<pattern>me.wiefferink.bukkitdo</pattern>
<shadedPattern>me.wiefferink.areashop.shaded.bukkitdo</shadedPattern>
</relocation>
<!-- Relocate bstats -->
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>me.wiefferink.areashop.shaded.bstats</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,190 @@
package me.wiefferink.areashop;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import me.wiefferink.interactivemessenger.Log;
import me.wiefferink.interactivemessenger.processing.Message;
import me.wiefferink.interactivemessenger.source.LanguageManager;
import me.wiefferink.interactivemessenger.translation.Transifex;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import java.net.URISyntaxException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Enumeration;
import java.util.Collections;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
public class ASLanguageManager extends LanguageManager {
private JavaPlugin plugin;
private String jarLanguagePath;
private File languageFolder;
private String wgPrefix;
private List<String> chatPrefix;
private Map<String, List<String>> currentLanguage, defaultLanguage;
public ASLanguageManager(JavaPlugin plugin,
String jarLanguagePath,
String currentLanguageName,
String defaultLanguageName,
List<String> chatPrefix,
String wgPrefix) {
super(plugin, jarLanguagePath, currentLanguageName, defaultLanguageName, chatPrefix);
this.plugin = plugin;
this.jarLanguagePath = jarLanguagePath;
this.chatPrefix = chatPrefix;
this.languageFolder = new File(plugin.getDataFolder() + File.separator + jarLanguagePath);
Message.init(this, plugin.getLogger());
saveDefaults();
currentLanguage = loadLanguage(currentLanguageName);
if (defaultLanguageName.equals(currentLanguageName)) {
defaultLanguage = currentLanguage;
} else {
defaultLanguage = loadLanguage(defaultLanguageName);
}
this.wgPrefix = wgPrefix;
}
@Override
public List<String> getMessage(String key) {
List<String> message;
if (key.equalsIgnoreCase(Message.CHATLANGUAGEVARIABLE)) {
message = chatPrefix;
} else if (key.equalsIgnoreCase("wgPrefix")) {
message = new ArrayList<>();
message.add(wgPrefix);
} else if (currentLanguage.containsKey(key)) {
message = currentLanguage.get(key);
} else {
message = defaultLanguage.get(key);
}
if (message == null) {
Log.warn("Did not find message '" + key + "' in the current or default language");
return new ArrayList<>();
}
return new ArrayList<>(message);
}
private void saveDefaults() {
// Create the language folder if it not exists
if (!languageFolder.exists()) {
if (!languageFolder.mkdirs()) {
Log.warn("Could not create language directory: " + languageFolder.getAbsolutePath());
return;
}
}
File jarPath;
try {
// Read jar as ZIP file
jarPath = new File(plugin.getClass()
.getProtectionDomain()
.getCodeSource()
.getLocation()
.toURI());
} catch (URISyntaxException e) {
Log.error("Failed to find location of jar file:", ExceptionUtils.getStackTrace(e));
return;
}
try (ZipFile jar = new ZipFile(jarPath)) {
Enumeration<? extends ZipEntry> entries = jar.entries();
// Each entry is a file or directory
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
// Filter to YAML files in the language directory
if (!entry.isDirectory() && entry.getName()
.startsWith(jarLanguagePath + "/") && entry.getName()
.endsWith(".yml")) {
// Save the file to disk
File targetFile = new File(languageFolder.getAbsolutePath() + File.separator + entry.getName()
.substring(entry.getName().lastIndexOf("/")));
try (
InputStream input = jar.getInputStream(entry);
OutputStream output = new FileOutputStream(targetFile)
) {
byte[] bytes = input.readAllBytes();
output.write(bytes);
} catch (IOException e) {
Log.warn("Something went wrong saving a default language file: " + targetFile.getAbsolutePath());
}
}
}
} catch (
IOException e) {
Log.error("Failed to read zip file:", ExceptionUtils.getStackTrace(e));
}
}
private Map<String, List<String>> loadLanguage(String key) {
return loadLanguage(key, true);
}
/**
* Loads the specified language
*
* @param key The language to load
* @param convert try conversion or not (infinite recursion prevention)
* @return Map with the messages loaded from the file
*/
private Map<String, List<String>> loadLanguage(String key, boolean convert) {
Map<String, List<String>> result = new HashMap<>();
// Load the language file
boolean convertFromTransifex = false;
File file = new File(languageFolder.getAbsolutePath() + File.separator + key + ".yml");
try (
InputStream inputStream = new FileInputStream(file);
Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)
) {
// Detect empty language files, happens when the YAML parsers prints an exception (it does return an empty YamlConfiguration though)
YamlConfiguration ymlFile = YamlConfiguration.loadConfiguration(reader);
if (ymlFile.getKeys(false).isEmpty()) {
Log.warn("Language file " + key + ".yml has zero messages.");
return result;
}
// Retrieve the messages from the YAML file and create the result
if (convert && Transifex.needsConversion(ymlFile)) {
convertFromTransifex = true;
} else {
for (String messageKey : ymlFile.getKeys(false)) {
List<String> toPut;
if (ymlFile.isList(messageKey)) {
toPut = ymlFile.getStringList(messageKey);
} else {
toPut = Collections.singletonList(ymlFile.getString(messageKey));
}
result.put(messageKey, new ArrayList<>(toPut));
}
}
} catch (IOException e) {
Log.warn("Could not load language file: " + file.getAbsolutePath());
}
// Do conversion (after block above closed the reader)
if (convertFromTransifex) {
if (!Transifex.convertFrom(file)) {
Log.warn("Failed to convert " + file.getName() + " from the Transifex layout to the AreaShop layout, check the errors above");
}
return loadLanguage(key, false);
}
return result;
}
}
@@ -1,22 +1,41 @@
package me.wiefferink.areashop;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.protection.managers.RegionManager;
import io.papermc.lib.PaperLib;
import me.wiefferink.areashop.adapters.platform.MinecraftPlatform;
import me.wiefferink.areashop.adapters.platform.paper.PaperPlatform;
import me.wiefferink.areashop.commands.util.AreashopCommands;
import me.wiefferink.areashop.extensions.AreashopExtension;
import me.wiefferink.areashop.features.signs.SignManager;
import me.wiefferink.areashop.interfaces.AreaShopInterface;
import me.wiefferink.areashop.interfaces.WorldEditInterface;
import me.wiefferink.areashop.interfaces.WorldGuardInterface;
import me.wiefferink.areashop.listeners.PlayerLoginLogoutListener;
import me.wiefferink.areashop.managers.CommandManager;
import me.wiefferink.areashop.managers.CacheManager;
import me.wiefferink.areashop.managers.FeatureManager;
import me.wiefferink.areashop.managers.FileManager;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.managers.Manager;
import me.wiefferink.areashop.managers.SignErrorLogger;
import me.wiefferink.areashop.managers.SignLinkerManager;
import me.wiefferink.areashop.tools.Analytics;
import me.wiefferink.areashop.modules.AreaShopModule;
import me.wiefferink.areashop.modules.BukkitModule;
import me.wiefferink.areashop.modules.DependencyModule;
import me.wiefferink.areashop.modules.PlatformModule;
import me.wiefferink.areashop.services.ServiceManager;
import me.wiefferink.areashop.tools.GithubUpdateCheck;
import me.wiefferink.areashop.tools.LanguageConverter;
import me.wiefferink.areashop.tools.SimpleMessageBridge;
import me.wiefferink.areashop.tools.SpigotPlatform;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.areashop.tools.version.Version;
import me.wiefferink.areashop.tools.version.VersionUtil;
import me.wiefferink.bukkitdo.Do;
import me.wiefferink.interactivemessenger.processing.Message;
import me.wiefferink.interactivemessenger.source.LanguageManager;
import net.milkbowl.vault.economy.Economy;
import org.apache.commons.lang.StringUtils;
@@ -33,37 +52,50 @@ import org.bukkit.permissions.Permission;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.logging.Level;
/**
* Main class for the AreaShop plugin.
* Contains methods to get parts of the plugins functionality and definitions for constants.
*/
public final class AreaShop extends JavaPlugin implements AreaShopInterface {
public final class AreaShop extends JavaPlugin implements AreaShopApi {
// Statically available instance
private static AreaShop instance = null;
// General variables
private Injector injector;
private WorldGuardPlugin worldGuard = null;
private WorldGuardInterface worldGuardInterface = null;
private WorldEditPlugin worldEdit = null;
private WorldEditInterface worldEditInterface = null;
private FileManager fileManager = null;
private MessageBridge messageBridge;
private IFileManager fileManager = null;
private LanguageManager languageManager = null;
private CommandManager commandManager = null;
private CacheManager cacheManager = null;
private SignLinkerManager signLinkerManager = null;
private FeatureManager featureManager = null;
private SignManager signManager;
private SignErrorLogger signErrorLogger;
private Set<Manager> managers = null;
private boolean debug = false;
private List<String> chatprefix = null;
private boolean ready = false;
private GithubUpdateCheck githubUpdateCheck = null;
private final ServiceManager serviceManager = new ServiceManager();
// Folders and file names
public static final String languageFolder = "lang";
public static final String schematicFolder = "schem";
@@ -72,6 +104,7 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
public static final String defaultFile = "default.yml";
public static final String configFile = "config.yml";
public static final String configFileHidden = "hiddenConfig.yml";
public static final String signLogFile = "sign-errors.log";
public static final String versionFile = "versions";
// Euro tag for in the config
@@ -141,193 +174,167 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
/**
* Called on start or reload of the server.
*/
@Override
public void onEnable() {
AreaShop.instance = this;
Do.init(this);
managers = new HashSet<>();
boolean error = false;
messageBridge = new SimpleMessageBridge(this.serviceManager);
signErrorLogger = new SignErrorLogger(new File(getDataFolder(), signLogFile));
// Check if WorldGuard is present
String wgVersion = null;
String rawVersion = null;
int major = 0;
int minor = 0;
int fixes = 0;
Integer build = null;
Plugin plugin = getServer().getPluginManager().getPlugin("WorldGuard");
if(!(plugin instanceof WorldGuardPlugin) || !plugin.isEnabled()) {
error("WorldGuard plugin is not present or has not loaded correctly");
error = true;
} else {
worldGuard = (WorldGuardPlugin)plugin;
// Get correct WorldGuardInterface (handles things that changed version to version)
try {
rawVersion = worldGuard.getDescription().getVersion();
if(rawVersion.contains("-SNAPSHOT;")) {
String buildNumber = rawVersion.substring(rawVersion.indexOf("-SNAPSHOT;") + 10, rawVersion.length());
if(buildNumber.contains("-")) {
buildNumber = buildNumber.substring(0, buildNumber.indexOf("-"));
try {
build = Integer.parseInt(buildNumber);
} catch(NumberFormatException e) {
warn("Could not correctly parse the build of WorldGuard, raw version: " + rawVersion + ", buildNumber: " + buildNumber);
}
}
}
// Clear stuff from the version string that is not a number
String[] versionParts = rawVersion.split("\\.");
for(int i = 0; i < versionParts.length; i++) {
Pattern pattern = Pattern.compile("^\\d+");
Matcher matcher = pattern.matcher(versionParts[i]);
if(matcher.find()) {
versionParts[i] = matcher.group();
}
}
// Find major, minor and fix numbers
try {
if(versionParts.length > 0) {
major = Integer.parseInt(versionParts[0]);
}
if(versionParts.length > 1) {
minor = Integer.parseInt(versionParts[1]);
}
if(versionParts.length > 2) {
fixes = Integer.parseInt(versionParts[2]);
}
} catch(NumberFormatException e) {
warn("Something went wrong while parsing WorldGuard version number: " + rawVersion);
}
// Determine correct implementation to use
if(worldGuard.getDescription().getVersion().startsWith("5.")) {
wgVersion = "5";
} else if(major == 6 && minor == 1 && fixes < 3) {
wgVersion = "6";
} else if(major == 6) {
if(build != null && build == 1672) {
error = true;
error("Build 1672 of WorldGuard is broken, update to a later build or a stable version!");
} else if(build != null && build < 1672) {
wgVersion = "6";
} else {
wgVersion = "6_1_3";
}
} else {
wgVersion = "7";
}
} catch(Exception e) { // If version detection fails, at least try to load the latest version
wgVersion = "7";
}
// Load chosen implementation
try {
final Class<?> clazz = Class.forName("me.wiefferink.areashop.handlers.WorldGuardHandler" + wgVersion);
// Check if we have a NMSHandler class at that location.
if(WorldGuardInterface.class.isAssignableFrom(clazz)) { // Make sure it actually implements WorldGuardInterface
worldGuardInterface = (WorldGuardInterface)clazz.getConstructor(AreaShopInterface.class).newInstance(this); // Set our handler
}
} catch(final Exception e) {
error("Could not load the handler for WorldGuard (tried to load " + wgVersion + "), report this problem to the author:" + ExceptionUtils.getStackTrace(e));
error = true;
wgVersion = null;
}
// Setup NMS Impl
Version currentServerVersion = VersionUtil.parseMinecraftVersion(Bukkit.getBukkitVersion());
if (currentServerVersion.versionData().isOlderThan(VersionUtil.MC_1_21)) {
error("Unsupported minecraft version: " + currentServerVersion + "! Minimum is 1.21");
shutdownOnError();
return;
}
// Check if WorldEdit is present
String weVersion = null;
plugin = getServer().getPluginManager().getPlugin("WorldEdit");
if(!(plugin instanceof WorldEditPlugin) || !plugin.isEnabled()) {
error("WorldEdit plugin is not present or has not loaded correctly");
error = true;
final MinecraftPlatform platform;
if (PaperLib.isPaper()) {
platform = new PaperPlatform(this);
info("Detected Paper; using the PaperPlatform impl");
} else {
worldEdit = (WorldEditPlugin)plugin;
// Get correct WorldEditInterface (handles things that changed version to version)
if(worldEdit.getDescription().getVersion().startsWith("5.")) {
weVersion = "5";
} else if(worldEdit.getDescription().getVersion().startsWith("6.")) {
weVersion = "6";
} else {
weVersion = "7";
}
try {
final Class<?> clazz = Class.forName("me.wiefferink.areashop.handlers.WorldEditHandler" + weVersion);
// Check if we have a NMSHandler class at that location.
if(WorldEditInterface.class.isAssignableFrom(clazz)) { // Make sure it actually implements WorldEditInterface
worldEditInterface = (WorldEditInterface)clazz.getConstructor(AreaShopInterface.class).newInstance(this); // Set our handler
}
} catch(final Exception e) {
error("Could not load the handler for WorldEdit (tried to load " + weVersion + "), report this problem to the author: " + ExceptionUtils.getStackTrace(e));
error = true;
weVersion = null;
}
platform = new SpigotPlatform(this);
info("Detected Spigot; using the SpigotPlatform impl");
}
final PlatformModule platformModule = new PlatformModule(platform);
// Check if Vault is present
if(getServer().getPluginManager().getPlugin("Vault") == null) {
error("Vault plugin is not present or has not loaded correctly");
error = true;
shutdownOnError();
return;
}
// Find WorldEdit integration version to load
String weHandlerVersion;
Plugin plugin = getServer().getPluginManager().getPlugin("WorldEdit");
if(!(plugin instanceof WorldEditPlugin) || !plugin.isEnabled()) {
error("WorldEdit plugin is not present or has not loaded correctly");
return;
} else {
this.worldEdit = (WorldEditPlugin) plugin;
Plugin fawePlugin = getServer().getPluginManager().getPlugin("FastAsyncWorldEdit");
if (fawePlugin != null && fawePlugin.isEnabled()) {
weHandlerVersion = "FastAsyncWorldEditHandler";
info("Detected FastAsyncWorldEdit, using the fawe handler");
} else {
weHandlerVersion = "WorldEditHandler";
}
}
plugin = getServer().getPluginManager().getPlugin("WorldGuard");
if(!(plugin instanceof WorldGuardPlugin) || !plugin.isEnabled()) {
error("WorldGuard plugin is not present or has not loaded correctly");
shutdownOnError();
return;
} else {
this.worldGuard = (WorldGuardPlugin) plugin;
}
DependencyModule dependencyModule = new DependencyModule(this.worldEdit, this.worldGuard, getEconomy(), getPermissionProvider());
// Load WorldEdit
try {
Class<?> clazz = Class.forName("me.wiefferink.areashop.adapters.plugins." + weHandlerVersion);
if(WorldEditInterface.class.isAssignableFrom(clazz)) { // Make sure it actually implements WorldEditInterface
worldEditInterface = (WorldEditInterface)clazz.getConstructor(AreaShopInterface.class).newInstance(this); // Set our handler
}
} catch(Exception e) {
error("Could not load the handler for WorldEdit (tried to load " + weHandlerVersion + "), report this problem to the author: " + ExceptionUtils.getStackTrace(e));
shutdownOnError();
return;
}
// Load WorldGuard
try {
Class<?> clazz = Class.forName("me.wiefferink.areashop.adapters.plugins.WorldGuardHandler");
// Check if we have a NMSHandler class at that location.
if(WorldGuardInterface.class.isAssignableFrom(clazz)) { // Make sure it actually implements WorldGuardInterface
worldGuardInterface = (WorldGuardInterface)clazz.getConstructor(AreaShopInterface.class).newInstance(this); // Set our handler
}
} catch(Exception e) {
error("Could not load the handler for WorldGuard, report this problem to the author:" + ExceptionUtils.getStackTrace(e));
shutdownOnError();
return;
}
AreaShopModule asModule = new AreaShopModule(this,
this.messageBridge,
this.worldEditInterface,
this.worldGuardInterface,
this.signErrorLogger,
this.serviceManager,
platformModule,
dependencyModule
);
injector = Guice.createInjector(Stage.PRODUCTION, new BukkitModule(getServer()), asModule);
// Load all data from files and check versions
fileManager = new FileManager();
managers.add(fileManager);
error = error | !fileManager.loadFiles(false);
// Print loaded version of WG and WE in debug
if(wgVersion != null) {
AreaShop.debug("Loaded WorldGuardHandler" + wgVersion + " (raw version: " + rawVersion + ", major:" + major + ", minor:" + minor + ", fixes:" + fixes + ", build:" + build + ")");
}
if(weVersion != null) {
AreaShop.debug("Loaded WorldEditHandler" + weVersion);
fileManager = injector.getInstance(IFileManager.class);
managers.add((FileManager) fileManager);
boolean loadFilesResult = fileManager.loadFiles(false);
if (!loadFilesResult) {
shutdownOnError();
return;
}
performLanguageMigrations();
setupLanguageManager();
if(error) {
error("The plugin has not started, fix the errors listed above");
} else {
featureManager = new FeatureManager();
managers.add(featureManager);
featureManager = injector.getInstance(FeatureManager.class);
featureManager.initializeFeatures(injector);
managers.add(featureManager);
signManager = injector.getInstance(SignManager.class);
managers.add(signManager);
cacheManager = injector.getInstance(CacheManager.class);
String rawExpiryDuration = fileManager.getConfig().getString("cacheExpiryDuration", "7d");
long millis = Utils.durationStringToLong(rawExpiryDuration);
cacheManager.initialize(new File(getDataFolder(), "uuid-cache.bin"), Duration.ofMillis(millis));
cacheManager.loadCache();
managers.add(cacheManager);
// Register the event listeners
getServer().getPluginManager().registerEvents(new PlayerLoginLogoutListener(this), this);
loadExtensions();
setupTasks();
// Register the event listeners
getServer().getPluginManager().registerEvents(new PlayerLoginLogoutListener(this, messageBridge, this.cacheManager), this);
// Startup the CommandManager (registers itself for the command)
commandManager = new CommandManager();
managers.add(commandManager);
setupTasks();
// Create a signLinkerManager
signLinkerManager = new SignLinkerManager();
managers.add(signLinkerManager);
// Register commands
AreashopCommands commands = injector.getInstance(AreashopCommands.class);
commands.registerCommands();
// Enable Metrics if config allows it
if(getConfig().getBoolean("sendStats")) {
Analytics.start();
// Create a signLinkerManager
signLinkerManager = injector.getInstance(SignLinkerManager.class);
managers.add(signLinkerManager);
// Register dynamic permission (things declared in config)
registerDynamicPermissions();
// Don't initialize the updatechecker if disabled in the config
if(getConfig().getBoolean("checkForUpdates")) {
githubUpdateCheck = new GithubUpdateCheck(
this,
"md5sha256",
"AreaShop"
).withVersionComparator((latestVersion, currentVersion) -> {
Version latest = Version.parse(cleanVersion(latestVersion));
Version current = Version.parse(cleanVersion(currentVersion));
return latest.versionData().isNewerThan(current.versionData());
}
).checkUpdate(result -> {
AreaShop.debug("Update check result:", result);
if(!result.hasUpdate()) {
return;
}
// Register dynamic permission (things declared in config)
registerDynamicPermissions();
// Don't initialize the updatechecker if disabled in the config
if(getConfig().getBoolean("checkForUpdates")) {
githubUpdateCheck = new GithubUpdateCheck(
AreaShop.getInstance(),
"NLThijs48",
"AreaShop"
).withVersionComparator((latestVersion, currentVersion) ->
!cleanVersion(latestVersion).equals(cleanVersion(currentVersion))
).checkUpdate((result) -> {
AreaShop.debug("Update check result:", result);
if(!result.hasUpdate()) {
return;
}
AreaShop.info("Update from AreaShop V" + cleanVersion(result.getCurrentVersion()) + " to AreaShop V" + cleanVersion(result.getLatestVersion()) + " available, get the latest version at https://www.spigotmc.org/resources/areashop.2991/");
for(Player player : Utils.getOnlinePlayers()) {
notifyUpdate(player);
}
});
}
AreaShop.info("Update from AreaShop V" + cleanVersion(result.getCurrentVersion()) + " to AreaShop V" + cleanVersion(result.getLatestVersion()) + " available, get the latest version at https://github.com/md5sha256/AreaShop/releases");
for(Player player : Utils.getOnlinePlayers()) {
notifyUpdate(player);
}
});
}
}
@@ -337,10 +344,34 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
*/
public void notifyUpdate(CommandSender sender) {
if(githubUpdateCheck != null && githubUpdateCheck.hasUpdate() && sender.hasPermission("areashop.notifyupdate")) {
AreaShop.getInstance().message(sender, "update-playerNotify", cleanVersion(githubUpdateCheck.getCurrentVersion()), cleanVersion(githubUpdateCheck.getLatestVersion()));
messageBridge.message(sender, "update-playerNotify", cleanVersion(githubUpdateCheck.getCurrentVersion()), cleanVersion(githubUpdateCheck.getLatestVersion()));
}
}
private void shutdownOnError() {
error("The plugin has not started, fix the errors listed above");
getServer().getPluginManager().disablePlugin(this);
}
private void loadExtensions() {
if (this.getServer().getPluginManager().isPluginEnabled("Essentials")) {
loadEssentialsExt().ifPresent(ext -> ext.init(this, this.injector));
}
}
private Optional<AreashopExtension> loadEssentialsExt() {
try {
Class<?> clazz = Class.forName("me.wiefferink.areashop.adapters.plugins.essentials.EssentialsExtension");
Class<? extends AreashopExtension> extClass = clazz.asSubclass(AreashopExtension.class);
AreashopExtension extension = extClass.getConstructor().newInstance();
return Optional.of(extension);
} catch (ReflectiveOperationException ex) {
error("Failed to initialize the essentials extension!");
ex.printStackTrace();
}
return Optional.empty();
}
/**
* Cleanup a version number.
* @param version Version to clean
@@ -362,9 +393,14 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
return version;
}
public CacheManager getCacheManager() {
return cacheManager;
}
/**
* Called on shutdown or reload of the server.
*/
@Override
public void onDisable() {
Bukkit.getServer().getScheduler().cancelTasks(this);
@@ -373,27 +409,18 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
for(Manager manager : managers) {
manager.shutdown();
}
managers = null;
fileManager = null;
languageManager = null;
commandManager = null;
signLinkerManager = null;
featureManager = null;
// Cleanup plugins
worldGuard = null;
worldGuardInterface = null;
worldEdit = null;
worldEditInterface = null;
// Cleanup other stuff
chatprefix = null;
debug = false;
ready = false;
signErrorLogger.saveIfDirty();
HandlerList.unregisterAll(this);
}
/**
* Indicates if the plugin will be using MiniMessage or not
* @return true if MiniMessage should be used, false otherwise
*/
public static boolean useMiniMessage() {
return getInstance().getConfig().getBoolean("useMiniMessage");
}
/**
* Indicates if the plugin is ready to be used.
* @return true if the plugin is ready, false otherwise
@@ -418,16 +445,53 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
this.debug = debug;
}
private void performLanguageMigrations() {
boolean migrateExisting = this.getConfig().getBoolean("migrateLanguages", false);
if (!migrateExisting) {
return;
}
getLogger().info("Performing language migration");
List<String> chatPrefix = getConfig().getStringList("chatPrefix");
List<String> convertedChatPrefix = LanguageConverter.convertRawList(chatPrefix);
if (convertedChatPrefix.size() == 1) {
getConfig().set("mmChatPrefix", convertedChatPrefix.getFirst());
} else {
getConfig().set("mmChatPrefix", convertedChatPrefix);
}
saveConfig();
File existingLanguages = getDataFolder().toPath().resolve(languageFolder).toFile();
File[] langFiles = existingLanguages.listFiles(file -> file.getName().endsWith(".yml"));
if (langFiles == null) {
return;
}
for (File file : langFiles) {
String name = file.getName();
String langName = name.substring(0, name.length() - 4);
if (langName.endsWith("-MM")) {
debug("Skipping migration for " + langName + " as it already exists.");
continue;
}
File toMigrate = new File(existingLanguages, langName + "-MM.yml");
try {
LanguageConverter.performConversion(file, toMigrate);
} catch (IOException ex) {
getLogger().log(Level.SEVERE, "Failed to perform migration for lang: " + file.getName(), ex);
}
}
getLogger().info("Language migration complete!");
}
/**
* Setup a new LanguageManager.
*/
private void setupLanguageManager() {
languageManager = new LanguageManager(
languageManager = new ASLanguageManager(
this,
languageFolder,
getConfig().getString("language"),
useMiniMessage() ? getConfig().getString("mmLanguage") : getConfig().getString("language"),
"EN",
chatprefix
useMiniMessage() ? getConfig().getStringList("mmChatPrefix") : chatprefix,
getConfig().getString("wgPrefix")
);
}
@@ -439,10 +503,15 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
this.chatprefix = chatprefix;
}
public SignErrorLogger getSignErrorLogger() {
return signErrorLogger;
}
/**
* Function to get the WorldGuard plugin.
* @return WorldGuardPlugin
*/
@Override
public WorldGuardPlugin getWorldGuard() {
return worldGuard;
}
@@ -455,6 +524,12 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
return this.worldGuardInterface;
}
@Nonnull
public SignManager getSignManager() {
return signManager;
}
/**
* Get the RegionManager.
* @param world World to get the RegionManager for
@@ -468,10 +543,16 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
* Function to get the WorldEdit plugin.
* @return WorldEditPlugin
*/
@Override
public WorldEditPlugin getWorldEdit() {
return worldEdit;
}
@Override
public Plugin pluginInstance() {
return this;
}
/**
* Function to get WorldGuardInterface for version dependent things.
* @return WorldGuardInterface
@@ -488,19 +569,13 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
return languageManager;
}
/**
* Function to get the CommandManager.
* @return the CommandManager
*/
public CommandManager getCommandManager() {
return commandManager;
}
/**
* Get the SignLinkerManager.
* Handles sign linking mode.
* @return The SignLinkerManager
*/
@Nonnull
@Override
public SignLinkerManager getSignlinkerManager() {
return signLinkerManager;
}
@@ -510,17 +585,25 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
* Manages region specific features.
* @return The FeatureManager
*/
@Nonnull
@Override
public FeatureManager getFeatureManager() {
return featureManager;
}
@NotNull
@Override
public ServiceManager getServiceManager() {
return this.serviceManager;
}
/**
* Function to get the Vault plugin.
* @return Economy
*/
public Economy getEconomy() {
private Economy getEconomy() {
RegisteredServiceProvider<Economy> economy = getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
if(economy == null || economy.getProvider() == null) {
if(economy == null) {
error("There is no economy provider to support Vault, make sure you installed an economy plugin");
return null;
}
@@ -531,9 +614,9 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
* Get the Vault permissions provider.
* @return Vault permissions provider
*/
public net.milkbowl.vault.permission.Permission getPermissionProvider() {
private net.milkbowl.vault.permission.Permission getPermissionProvider() {
RegisteredServiceProvider<net.milkbowl.vault.permission.Permission> permissionProvider = getServer().getServicesManager().getRegistration(net.milkbowl.vault.permission.Permission.class);
if (permissionProvider == null || permissionProvider.getProvider() == null) {
if (permissionProvider == null) {
return null;
}
return permissionProvider.getProvider();
@@ -566,7 +649,7 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
* Method to get the FileManager (loads/save regions and can be used to get regions).
* @return The fileManager
*/
public FileManager getFileManager() {
public IFileManager getFileManager() {
return fileManager;
}
@@ -596,6 +679,13 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
* Register all required tasks.
*/
private void setupTasks() {
long signLogTicks = Utils.millisToTicks(TimeUnit.MINUTES.toMillis(5));
Bukkit.getScheduler().runTaskTimerAsynchronously(this,
() -> signErrorLogger.saveIfDirty(),
signLogTicks,
signLogTicks);
// Rent expiration timer
long expirationCheck = Utils.millisToTicks(Utils.getDurationFromSecondsOrString("expiration.delay"));
final AreaShop finalPlugin = this;
@@ -671,26 +761,6 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
}
}
/**
* Send a message to a target without a prefix.
* @param target The target to send the message to
* @param key The key of the language string
* @param replacements The replacements to insert in the message
*/
public void messageNoPrefix(Object target, String key, Object... replacements) {
Message.fromKey(key).replacements(replacements).send(target);
}
/**
* Send a message to a target, prefixed by the default chat prefix.
* @param target The target to send the message to
* @param key The key of the language string
* @param replacements The replacements to insert in the message
*/
public void message(Object target, String key, Object... replacements) {
Message.fromKey(key).prefix().replacements(replacements).send(target);
}
/**
* Return the config.
@@ -714,16 +784,24 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
* Non-static debug to use as implementation of the interface.
* @param message Object parts of the message that should be logged, toString() will be used
*/
@Override
public void debugI(Object... message) {
AreaShop.debug(StringUtils.join(message, " "));
}
@Override
public void debugI(Supplier<String> message) {
if (debug) {
info("Debug: " + message.get());
}
}
/**
* Print an information message to the console.
* @param message The message to print
*/
public static void info(Object... message) {
AreaShop.getInstance().getLogger().info(StringUtils.join(message, " "));
AreaShop.getInstance().getLogger().info(() -> StringUtils.join(message, " "));
}
/**
@@ -731,7 +809,7 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
* @param message The message to print
*/
public static void warn(Object... message) {
AreaShop.getInstance().getLogger().warning(StringUtils.join(message, " "));
AreaShop.getInstance().getLogger().warning(() -> StringUtils.join(message, " "));
}
/**
@@ -739,7 +817,7 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
* @param message The message to print
*/
public static void error(Object... message) {
AreaShop.getInstance().getLogger().severe(StringUtils.join(message, " "));
AreaShop.getInstance().getLogger().severe(() -> StringUtils.join(message, " "));
}
/**
@@ -761,7 +839,7 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
fileManager.saveRequiredFilesAtOnce();
fileManager.loadFiles(true);
setupLanguageManager();
message(confirmationReceiver, "reload-reloading");
messageBridge.message(confirmationReceiver, "reload-reloading");
fileManager.checkRents();
fileManager.updateAllRegions(confirmationReceiver);
}
@@ -0,0 +1,35 @@
package me.wiefferink.areashop;
import me.wiefferink.areashop.features.signs.SignManager;
import me.wiefferink.areashop.interfaces.AreaShopInterface;
import me.wiefferink.areashop.managers.FeatureManager;
import me.wiefferink.areashop.managers.SignLinkerManager;
import me.wiefferink.areashop.services.ServiceManager;
import javax.annotation.Nonnull;
public interface AreaShopApi extends AreaShopInterface {
/**
* Get the SignLinkerManager.
* Handles sign linking mode.
*
* @return The SignLinkerManager
*/
@Nonnull SignLinkerManager getSignlinkerManager();
/**
* Get the FeatureManager.
* Manages region specific features.
*
* @return The FeatureManager
*/
@Nonnull FeatureManager getFeatureManager();
@Nonnull SignManager getSignManager();
@Nonnull
ServiceManager getServiceManager();
}
@@ -0,0 +1,29 @@
package me.wiefferink.areashop;
import org.bukkit.OfflinePlayer;
import javax.annotation.Nonnull;
public interface MessageBridge {
/**
* Send a message to a target without a prefix.
*
* @param target The target to send the message to
* @param key The key of the language string
* @param replacements The replacements to insert in the message
*/
void messageNoPrefix(Object target, String key, Object... replacements);
/**
* Send a message to a target, prefixed by the default chat prefix.
*
* @param target The target to send the message to
* @param key The key of the language string
* @param replacements The replacements to insert in the message
*/
void message(Object target, String key, Object... replacements);
void messagePersistent(@Nonnull OfflinePlayer target,
@Nonnull String key,
@Nonnull Object... replacements);
}
@@ -1,292 +1,445 @@
package me.wiefferink.areashop.commands;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.interfaces.WorldEditSelection;
import me.wiefferink.areashop.managers.FileManager;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.WorldFlagUtil;
import me.wiefferink.areashop.commands.util.WorldGuardRegionParser;
import me.wiefferink.areashop.commands.util.WorldSelection;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.events.ask.AddingRegionEvent;
import me.wiefferink.areashop.events.ask.BuyingRegionEvent;
import me.wiefferink.areashop.events.ask.RentingRegionEvent;
import me.wiefferink.areashop.events.notify.BoughtRegionEvent;
import me.wiefferink.areashop.events.notify.RentedRegionEvent;
import me.wiefferink.areashop.interfaces.WorldEditInterface;
import me.wiefferink.areashop.interfaces.WorldGuardInterface;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionFactory;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.bukkitdo.Do;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.standard.EnumParser;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
import java.util.stream.Collectors;
public class AddCommand extends CommandAreaShop {
@Singleton
public class AddCommand extends AreashopCommandBean {
@Override
public String getCommandStart() {
return "areashop add";
}
private static final CloudKey<GeneralRegion.RegionType> KEY_REGION_TYPE = CloudKey.of("regionType",
GeneralRegion.RegionType.class);
private static final CloudKey<ProtectedRegion> KEY_REGION = CloudKey.of("region", ProtectedRegion.class);
private final MessageBridge messageBridge;
private final AreaShop plugin;
private final WorldEditInterface worldEditInterface;
private final WorldGuardInterface worldGuardInterface;
private final RegionFactory regionFactory;
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.createrent")
|| target.hasPermission("areashop.createrent.member")
|| target.hasPermission("areashop.createrent.owner")
@Inject
public AddCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull AreaShop plugin,
@Nonnull WorldEditInterface worldEditInterface,
@Nonnull WorldGuardInterface worldGuardInterface,
@Nonnull RegionFactory regionFactory) {
this.messageBridge = messageBridge;
this.plugin = plugin;
this.worldEditInterface = worldEditInterface;
this.worldGuardInterface = worldGuardInterface;
this.regionFactory = regionFactory;
}
|| target.hasPermission("areashop.createbuy")
|| target.hasPermission("areashop.createbuy.member")
|| target.hasPermission("areashop.createbuy.owner")) {
return "help-add";
}
return null;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if(target.hasPermission("areashop.createrent")
|| target.hasPermission("areashop.createrent.member")
|| target.hasPermission("areashop.createrent.owner")
@Override
public void execute(final CommandSender sender, final String[] args) {
if(!sender.hasPermission("areashop.createrent")
&& !sender.hasPermission("areashop.createrent.member")
&& !sender.hasPermission("areashop.createrent.owner")
|| target.hasPermission("areashop.createbuy")
|| target.hasPermission("areashop.createbuy.member")
|| target.hasPermission("areashop.createbuy.owner")) {
return "help-add";
}
return null;
}
&& !sender.hasPermission("areashop.createbuy")
&& !sender.hasPermission("areashop.createbuy.member")
&& !sender.hasPermission("areashop.createbuy.owner")) {
plugin.message(sender, "add-noPermission");
return;
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
// /as add <rent|buy> [region] [world]
var wgRegionParser = WorldGuardRegionParser.worldGuardRegionParser(WorldFlagUtil.DEFAULT_WORLD_FLAG, this.worldGuardInterface);
return builder
.literal("add")
.senderType(PlayerCommandSource.class)
.required(KEY_REGION_TYPE, EnumParser.enumParser(GeneralRegion.RegionType.class))
.optional(KEY_REGION, wgRegionParser)
.flag(WorldFlagUtil.DEFAULT_WORLD_FLAG)
.handler(this::handleCommand);
}
if(args.length < 2 || args[1] == null || (!"rent".equals(args[1].toLowerCase()) && !"buy".equals(args[1].toLowerCase()))) {
plugin.message(sender, "add-help");
return;
}
Map<String, ProtectedRegion> regions = new HashMap<>();
World world;
Player player = null;
if(sender instanceof Player) {
player = (Player)sender;
}
if(args.length == 2) {
if(player == null) {
plugin.message(sender, "cmd-weOnlyByPlayer");
return;
}
WorldEditSelection selection = plugin.getWorldEditHandler().getPlayerSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
world = selection.getWorld();
regions = Utils.getWorldEditRegionsInSelection(selection).stream().collect(Collectors.toMap(ProtectedRegion::getId, region -> region));
if(regions.size() == 0) {
plugin.message(player, "cmd-noWERegionsFound");
return;
}
} else {
if(player != null) {
if(args.length == 4) {
world = Bukkit.getWorld(args[3]);
if(world == null) {
plugin.message(sender, "add-incorrectWorld", args[3]);
return;
}
} else {
world = ((Player)sender).getWorld();
}
} else {
if(args.length < 4) {
plugin.message(sender, "add-specifyWorld");
return;
} else {
world = Bukkit.getWorld(args[3]);
if(world == null) {
plugin.message(sender, "add-incorrectWorld", args[3]);
return;
}
}
}
ProtectedRegion region = plugin.getRegionManager(world).getRegion(args[2]);
if(region == null) {
plugin.message(sender, "cmd-noRegion", args[2]);
return;
}
regions.put(args[2], region);
}
final boolean isRent = "rent".equals(args[1].toLowerCase());
final Player finalPlayer = player;
AreaShop.debug("Starting add task with " + regions.size() + " regions");
private void handleCommand(CommandContext<PlayerCommandSource> context) {
Player player = context.sender().sender();
final GeneralRegion.RegionType regionType = context.get(KEY_REGION_TYPE);
World world = WorldFlagUtil.parseOrDetectWorld(context, player);
Map<String, ProtectedRegion> regions;
Optional<ProtectedRegion> inputRegion = context.optional(KEY_REGION);
if (inputRegion.isPresent()) {
regions = new HashMap<>();
regions.put(inputRegion.get().getId(), inputRegion.get());
} else {
WorldSelection selection = WorldSelection.fromPlayer(player, this.worldEditInterface);
regions = Utils.getWorldEditRegionsInSelection(selection.selection()).stream()
.collect(Collectors.toMap(ProtectedRegion::getId, region -> region));
}
if (regions.isEmpty()) {
throw new AreaShopCommandException("cmd-noWERegionsFound");
}
AreaShop.debug("Starting add task with " + regions.size() + " regions");
AddTaskState state = createState(player, regionType, world);
int batchSize = plugin.getConfig().getInt("adding.regionsPerTick");
Do.forAll(
batchSize,
regions.entrySet(),
regionEntry -> processEntry(regionEntry, state),
() -> onCompletion(state)
);
}
TreeSet<GeneralRegion> regionsSuccess = new TreeSet<>();
TreeSet<GeneralRegion> regionsAlready = new TreeSet<>();
TreeSet<GeneralRegion> regionsAlreadyOtherWorld = new TreeSet<>();
TreeSet<String> namesBlacklisted = new TreeSet<>();
TreeSet<String> namesNoPermission = new TreeSet<>();
Do.forAll(
plugin.getConfig().getInt("adding.regionsPerTick"),
regions.entrySet(),
regionEntry -> {
String regionName = regionEntry.getKey();
ProtectedRegion region = regionEntry.getValue();
// Determine if the player is an owner or member of the region
boolean isMember = finalPlayer != null && plugin.getWorldGuardHandler().containsMember(region, finalPlayer.getUniqueId());
boolean isOwner = finalPlayer != null && plugin.getWorldGuardHandler().containsMember(region, finalPlayer.getUniqueId());
String type;
if(isRent) {
type = "rent";
} else {
type = "buy";
}
FileManager.AddResult result = plugin.getFileManager().checkRegionAdd(sender, region, world, isRent ? GeneralRegion.RegionType.RENT : GeneralRegion.RegionType.BUY);
if(result == FileManager.AddResult.ALREADYADDED) {
regionsAlready.add(plugin.getFileManager().getRegion(regionName));
} else if(result == FileManager.AddResult.ALREADYADDEDOTHERWORLD) {
regionsAlreadyOtherWorld.add(plugin.getFileManager().getRegion(regionName));
} else if(result == FileManager.AddResult.BLACKLISTED) {
namesBlacklisted.add(regionName);
} else if(result == FileManager.AddResult.NOPERMISSION) {
namesNoPermission.add(regionName);
} else {
// Check if the player should be landlord
boolean landlord = (!sender.hasPermission("areashop.create" + type)
&& ((sender.hasPermission("areashop.create" + type + ".owner") && isOwner)
|| (sender.hasPermission("areashop.create" + type + ".member") && isMember)));
List<UUID> existing = new ArrayList<>();
existing.addAll(plugin.getWorldGuardHandler().getOwners(region).asUniqueIdList());
existing.addAll(plugin.getWorldGuardHandler().getMembers(region).asUniqueIdList());
if(isRent) {
RentRegion rent = new RentRegion(regionName, world);
// Set landlord
if(landlord) {
rent.setLandlord(finalPlayer.getUniqueId(), finalPlayer.getName());
}
// Run commands
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
plugin.getFileManager().addRent(rent);
rent.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
private AddTaskState createState(
@Nonnull Player player,
@Nonnull GeneralRegion.RegionType regionType,
@Nonnull World world
) {
Set<GeneralRegion> regionsSuccess = new TreeSet<>();
Set<GeneralRegion> regionsAlready = new TreeSet<>();
Set<GeneralRegion> regionsAlreadyOtherWorld = new TreeSet<>();
Set<GeneralRegion> regionsRentCancelled = new TreeSet<>(); // Denied by an event listener
Set<GeneralRegion> regionsBuyCancelled = new TreeSet<>(); // Denied by an event listener
Set<String> namesBlacklisted = new TreeSet<>();
Set<String> namesNoPermission = new TreeSet<>();
Set<String> namesAddCancelled = new TreeSet<>(); // Denied by an event listener
return new AddTaskState(
player,
regionType,
regionsSuccess,
regionsAlready,
regionsAlreadyOtherWorld,
regionsRentCancelled,
regionsBuyCancelled,
namesBlacklisted,
namesNoPermission,
namesAddCancelled,
world
);
}
rent.update();
private void processEntry(@Nonnull Map.Entry<String, ProtectedRegion> regionEntry,
@Nonnull AddTaskState taskState) {
Player player = taskState.sender();
Set<GeneralRegion> regionsAlready = taskState.regionsAlready();
Set<GeneralRegion> regionsAlreadyOtherWorld = taskState.regionsAlreadyOtherWorld();
Set<String> namesBlacklisted = taskState.namesBlacklisted();
Set<String> namesNoPermission = taskState.namesNoPermission();
GeneralRegion.RegionType regionType = taskState.regionType();
World world = taskState.world();
String regionName = regionEntry.getKey();
ProtectedRegion region = regionEntry.getValue();
// Determine if the player is an owner or member of the region
boolean isMember = this.worldGuardInterface.containsMember(region, player.getUniqueId());
boolean isOwner = this.worldGuardInterface.containsOwner(region, player.getUniqueId());
String type = regionType.toString().toLowerCase(Locale.ENGLISH);
IFileManager.AddResult result = this.plugin.getFileManager()
.checkRegionAdd(
player,
region,
world,
regionType
);
switch (result) {
case ALREADYADDED -> regionsAlready.add(plugin.getFileManager().getRegion(regionName));
case ALREADYADDEDOTHERWORLD -> regionsAlreadyOtherWorld.add(plugin.getFileManager().getRegion(regionName));
case BLACKLISTED -> namesBlacklisted.add(regionName);
case NOPERMISSION -> namesNoPermission.add(regionName);
default -> {
// Check if the player should be landlord
boolean landlord = (!player.hasPermission("areashop.create" + type)
&& ((player.hasPermission("areashop.create" + type + ".owner") && isOwner)
|| (player.hasPermission("areashop.create" + type + ".member") && isMember)));
List<UUID> existing = new ArrayList<>();
existing.addAll(worldGuardInterface.getOwners(region).asUniqueIdList());
existing.addAll(worldGuardInterface.getMembers(region).asUniqueIdList());
debugResult(player, regionName, landlord, existing, isMember, isOwner, regionType);
if (regionType == GeneralRegion.RegionType.BUY) {
proccessBuy(region, landlord, existing, taskState);
} else if (regionType == GeneralRegion.RegionType.RENT) {
processRent(region, landlord, existing, taskState);
}
}
}
}
// Run commands
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
private void debugResult(
@Nonnull Player player,
@Nonnull String regionName,
boolean landlord,
List<UUID> existing,
boolean isMember,
boolean isOwner,
@Nonnull GeneralRegion.RegionType regionType
) {
String type = regionType.name().toLowerCase(Locale.ENGLISH);
AreaShop.debug("regionAddLandlordStatus:",
regionName,
"landlord:",
landlord,
"existing:",
existing,
"isMember:",
isMember,
"isOwner:",
isOwner,
"createPermission:",
player.hasPermission("areashop.create" + type),
"ownerPermission:",
player.hasPermission("areashop.create" + type + ".owner"),
"memberPermission:",
player.hasPermission("areashop.create" + type + ".member"));
}
// Add existing owners/members if any
if(!landlord && !existing.isEmpty()) {
// TODO also execute rent events to notify other plugins?
private void onCompletion(@Nonnull AddTaskState taskState) {
CommandSender player = taskState.sender();
GeneralRegion.RegionType regionType = taskState.regionType;
Set<GeneralRegion> regionsSuccess = taskState.regionsSuccess();
Set<GeneralRegion> regionsAlready = taskState.regionsAlready();
Set<GeneralRegion> regionsAlreadyOtherWorld = taskState.regionsAlreadyOtherWorld();
Set<GeneralRegion> regionsRentCancelled = taskState.regionsRentCancelled(); // Denied by an event listener
Set<GeneralRegion> regionsBuyCancelled = taskState.regionsBuyCancelled(); // Denied by an event listener
Set<String> namesBlacklisted = taskState.namesBlacklisted();
Set<String> namesNoPermission = taskState.namesNoPermission();
Set<String> namesAddCancelled = taskState.namesAddCancelled(); // Denied by an event listener
if (!regionsSuccess.isEmpty()) {
this.messageBridge.message(player,
"add-success",
regionType.name().toLowerCase(Locale.ENGLISH),
Utils.combinedMessage(regionsSuccess, "region"));
}
if (!regionsAlready.isEmpty()) {
this.messageBridge.message(player,
"add-failed",
Utils.combinedMessage(regionsAlready, "region"));
}
if (!regionsAlreadyOtherWorld.isEmpty()) {
this.messageBridge.message(player,
"add-failedOtherWorld",
Utils.combinedMessage(regionsAlreadyOtherWorld, "region"));
}
if (!regionsRentCancelled.isEmpty()) {
this.messageBridge.message(player,
"add-rentCancelled",
Utils.combinedMessage(regionsRentCancelled, "region"));
}
if (!regionsBuyCancelled.isEmpty()) {
this.messageBridge.message(player,
"add-buyCancelled",
Utils.combinedMessage(regionsBuyCancelled, "region"));
}
if (!namesBlacklisted.isEmpty()) {
this.messageBridge.message(player,
"add-blacklisted",
Utils.createCommaSeparatedList(namesBlacklisted));
}
if (!namesNoPermission.isEmpty()) {
this.messageBridge.message(player,
"add-noPermissionRegions",
Utils.createCommaSeparatedList(namesNoPermission));
this.messageBridge.message(player, "add-noPermissionOwnerMember");
}
if (!namesAddCancelled.isEmpty()) {
this.messageBridge.message(player,
"add-rentCancelled",
Utils.createCommaSeparatedList(namesAddCancelled));
}
}
// Run commands
rent.runEventCommands(GeneralRegion.RegionEvent.RENTED, true);
private void processRent(
@Nonnull ProtectedRegion region,
boolean landlord,
List<UUID> existing,
@Nonnull AddTaskState taskState
) {
Player player = taskState.sender();
Set<GeneralRegion> regionsSuccess = taskState.regionsSuccess();
Set<GeneralRegion> regionsRentCancelled = taskState.regionsRentCancelled(); // Denied by an event listener
Set<String> namesAddCancelled = taskState.namesAddCancelled(); // Denied by an event listener
World world = taskState.world();
String regionName = region.getId();
RentRegion rent = regionFactory.createRentRegion(regionName, world);
// Set landlord
if (landlord) {
rent.setLandlord(player.getUniqueId(), player.getName());
}
// Add values to the rent and send it to FileManager
rent.setRentedUntil(Calendar.getInstance().getTimeInMillis() + rent.getDuration());
rent.setRenter(existing.remove(0));
rent.updateLastActiveTime();
AddingRegionEvent event = plugin.getFileManager().addRegion(rent);
if (event.isCancelled()) {
namesAddCancelled.add(rent.getName());
return;
}
rent.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
rent.update();
// Add others as friends
for(UUID friend : existing) {
rent.getFriendsFeature().addFriend(friend, null);
}
// Add existing owners/members if any
if (!landlord && !existing.isEmpty()) {
UUID rentBy = existing.removeFirst();
OfflinePlayer rentByPlayer = Bukkit.getOfflinePlayer(rentBy);
// Fire schematic event and updated times extended
rent.handleSchematicEvent(GeneralRegion.RegionEvent.RENTED);
RentingRegionEvent rentingRegionEvent = new RentingRegionEvent(rent,
rentByPlayer,
false);
Bukkit.getPluginManager().callEvent(rentingRegionEvent);
if (rentingRegionEvent.isCancelled()) {
regionsRentCancelled.add(rent);
} else {
// Add values to the rent and send it to FileManager
rent.setRentedUntil(Calendar.getInstance()
.getTimeInMillis() + rent.getDuration());
rent.setRenter(rentBy);
rent.updateLastActiveTime();
// Notify about updates
rent.update();
// Fire schematic event and updated times extended
rent.handleSchematicEvent(GeneralRegion.RegionEvent.RENTED);
rent.runEventCommands(GeneralRegion.RegionEvent.RENTED, false);
}
// Add others as friends
for (UUID friend : existing) {
rent.getFriendsFeature().addFriend(friend, null);
}
regionsSuccess.add(rent);
} else {
BuyRegion buy = new BuyRegion(regionName, world);
// Set landlord
if(landlord) {
buy.setLandlord(finalPlayer.getUniqueId(), finalPlayer.getName());
}
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
rent.notifyAndUpdate(new RentedRegionEvent(rent, false));
}
}
plugin.getFileManager().addBuy(buy);
buy.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
regionsSuccess.add(rent);
}
buy.update();
private void proccessBuy(
@Nonnull ProtectedRegion region,
boolean landlord,
List<UUID> existing,
@Nonnull AddTaskState taskState
) {
Player player = taskState.sender();
Set<GeneralRegion> regionsSuccess = taskState.regionsSuccess();
Set<GeneralRegion> regionsBuyCancelled = taskState.regionsBuyCancelled(); // Denied by an event listener
Set<String> namesAddCancelled = taskState.namesAddCancelled(); // Denied by an event listener
World world = taskState.world();
String regionName = region.getId();
BuyRegion buy = regionFactory.createBuyRegion(regionName, world);
// Set landlord
if (landlord) {
buy.setLandlord(player.getUniqueId(), player.getName());
}
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
AddingRegionEvent event = plugin.getFileManager().addRegion(buy);
if (event.isCancelled()) {
namesAddCancelled.add(buy.getName());
return;
}
// Add existing owners/members if any
if(!landlord && !existing.isEmpty()) {
// TODO also execute buy events to notify for other plugins?
buy.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
buy.update();
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.BOUGHT, true);
// Add existing owners/members if any
if (!landlord && !existing.isEmpty()) {
UUID buyBy = existing.removeFirst();
OfflinePlayer buyByPlayer = Bukkit.getOfflinePlayer(buyBy);
// Set the owner
buy.setBuyer(existing.remove(0));
buy.updateLastActiveTime();
// Add others as friends
for(UUID friend : existing) {
buy.getFriendsFeature().addFriend(friend, null);
}
BuyingRegionEvent buyingRegionEvent = new BuyingRegionEvent(buy,
buyByPlayer);
Bukkit.getPluginManager().callEvent(buyingRegionEvent);
if (buyingRegionEvent.isCancelled()) {
regionsBuyCancelled.add(buy);
} else {
// Set the owner
buy.setBuyer(buyBy);
buy.updateLastActiveTime();
// Notify about updates
buy.update();
// Update everything
buy.handleSchematicEvent(GeneralRegion.RegionEvent.BOUGHT);
// Update everything
buy.handleSchematicEvent(GeneralRegion.RegionEvent.BOUGHT);
// Add others as friends
for (UUID friend : existing) {
buy.getFriendsFeature().addFriend(friend, null);
}
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.BOUGHT, false);
}
buy.notifyAndUpdate(new BoughtRegionEvent(buy));
}
}
regionsSuccess.add(buy);
}
}
},
() -> {
if(!regionsSuccess.isEmpty()) {
plugin.message(sender, "add-success", args[1], Utils.combinedMessage(regionsSuccess, "region"));
}
if(!regionsAlready.isEmpty()) {
plugin.message(sender, "add-failed", Utils.combinedMessage(regionsAlready, "region"));
}
if(!regionsAlreadyOtherWorld.isEmpty()) {
plugin.message(sender, "add-failedOtherWorld", Utils.combinedMessage(regionsAlreadyOtherWorld, "region"));
}
if(!namesBlacklisted.isEmpty()) {
plugin.message(sender, "add-blacklisted", Utils.createCommaSeparatedList(namesBlacklisted));
}
if(!namesNoPermission.isEmpty()) {
plugin.message(sender, "add-noPermissionRegions", Utils.createCommaSeparatedList(namesNoPermission));
plugin.message(sender, "add-noPermissionOwnerMember");
}
}
);
}
regionsSuccess.add(buy);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
if(sender.hasPermission("areashop.createrent")) {
result.add("rent");
}
if(sender.hasPermission("areashop.createbuy")) {
result.add("buy");
}
} else if(toComplete == 3) {
if(sender instanceof Player) {
Player player = (Player)sender;
if(sender.hasPermission("areashop.createrent") || sender.hasPermission("areashop.createbuy")) {
for(ProtectedRegion region : plugin.getRegionManager(player.getWorld()).getRegions().values()) {
result.add(region.getId());
}
}
}
}
return result;
}
@Override
public String stringDescription() {
return "Add a region";
}
public String getHelp(CommandSender target) {
if (target.hasPermission("areashop.createrent")
|| target.hasPermission("areashop.createrent.member")
|| target.hasPermission("areashop.createrent.owner")
|| target.hasPermission("areashop.createbuy")
|| target.hasPermission("areashop.createbuy.member")
|| target.hasPermission("areashop.createbuy.owner")) {
return "help-add";
}
return null;
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("add");
}
private record AddTaskState(
@Nonnull Player sender,
@Nonnull GeneralRegion.RegionType regionType,
@Nonnull Set<GeneralRegion> regionsSuccess,
@Nonnull Set<GeneralRegion> regionsAlready,
@Nonnull Set<GeneralRegion> regionsAlreadyOtherWorld,
@Nonnull Set<GeneralRegion> regionsRentCancelled,
@Nonnull Set<GeneralRegion> regionsBuyCancelled,
@Nonnull Set<String> namesBlacklisted,
@Nonnull Set<String> namesNoPermission,
@Nonnull Set<String> namesAddCancelled,
@Nonnull World world) {
}
}
@@ -0,0 +1,142 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.adapters.platform.OfflinePlayerHelper;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.OfflinePlayerParser;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.BukkitSchedulerExecutor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
@Singleton
public class AddFriendCommand extends AreashopCommandBean {
private static final CloudKey<String> KEY_FRIEND = CloudKey.of("friend", String.class);
private final CommandFlag<GeneralRegion> regionFlag;
private final MessageBridge messageBridge;
private final Plugin plugin;
private final BukkitSchedulerExecutor executor;
private final OfflinePlayerHelper offlinePlayerHelper;
@Inject
public AddFriendCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager,
@Nonnull Plugin plugin,
@Nonnull BukkitSchedulerExecutor executor,
@Nonnull OfflinePlayerHelper offlinePlayerHelper
) {
this.messageBridge = messageBridge;
this.plugin = plugin;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
this.executor = executor;
this.offlinePlayerHelper = offlinePlayerHelper;
}
@Override
public String stringDescription() {
return "Allows you to add friends to your regions";
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.addfriendall") || target.hasPermission("areashop.addfriend")) {
return "help-addFriend";
}
return null;
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("addfriend")
.senderType(PlayerCommandSource.class)
.required(KEY_FRIEND, OfflinePlayerParser.parser())
.flag(this.regionFlag)
.handler(this::handleCommand);
}
private void handleCommand(CommandContext<PlayerCommandSource> context) {
Player sender = context.sender().sender();
if (!sender.hasPermission("areashop.addfriend") && !sender.hasPermission("areashop.addfriendall")) {
this.messageBridge.message(sender, "addfriend-noPermission");
return;
}
GeneralRegion region = RegionParseUtil.getOrParseRegion(context, sender, this.regionFlag);
this.offlinePlayerHelper.lookupOfflinePlayerAsync(context.get(KEY_FRIEND))
.whenCompleteAsync((offlinePlayer, exception) -> {
if (exception != null) {
sender.sendMessage("failed to lookup offline player!");
exception.printStackTrace();
return;
}
if (!offlinePlayer.hasPlayedBefore() && !offlinePlayer.isOnline()) {
this.messageBridge.message(sender, "cmd-invalidPlayer", offlinePlayer.getName());
return;
}
processWithFriend(sender, region, offlinePlayer);
}, this.executor);
}
private void processWithFriend(@Nonnull Player sender,
@Nonnull GeneralRegion region,
@Nonnull OfflinePlayer friend
) {
if (sender.hasPermission("areashop.addfriendall") && ((region instanceof RentRegion rentRegion && !rentRegion.isRented())
|| (region instanceof BuyRegion buyRegion && !buyRegion.isSold()))) {
this.messageBridge.message(sender, "addfriend-noOwner", region);
return;
}
if (!sender.hasPermission("areashop.addfriend")) {
this.messageBridge.message(sender, "addfriend-noPermission", region);
return;
}
if (!region.isOwner(sender)) {
this.messageBridge.message(sender, "addfriend-noPermissionOther", region);
return;
}
if (!friend.hasPlayedBefore() && !friend.isOnline() && !plugin.getConfig()
.getBoolean("addFriendNotExistingPlayers")) {
this.messageBridge.message(sender, "addfriend-notVisited", friend.getName(), region);
} else if (region.getFriendsFeature().getFriends().contains(friend.getUniqueId())) {
this.messageBridge.message(sender, "addfriend-alreadyAdded", friend.getName(), region);
} else if (region.isOwner(friend.getUniqueId())) {
this.messageBridge.message(sender, "addfriend-self", friend.getName(), region);
} else if (region.getFriendsFeature().addFriend(friend.getUniqueId(), sender)) {
region.update();
this.messageBridge.message(sender, "addfriend-success", friend.getName(), region);
}
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("addfriend");
}
}
@@ -0,0 +1,132 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.GeneralRegionParser;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.SignProfileUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.features.signs.RegionSign;
import me.wiefferink.areashop.features.signs.SignManager;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.tools.Materials;
import me.wiefferink.areashop.tools.SignUtils;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.util.BlockIterator;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.Optional;
@Singleton
public class AddSignCommand extends AreashopCommandBean {
private static final CloudKey<GeneralRegion> KEY_REGION = CloudKey.of("region", GeneralRegion.class);
private final SignManager signManager;
private final Plugin plugin;
private final IFileManager fileManager;
private final MessageBridge messageBridge;
@Inject
public AddSignCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager,
@Nonnull SignManager signManager,
@Nonnull Plugin plugin
) {
this.messageBridge = messageBridge;
this.signManager = signManager;
this.plugin = plugin;
this.fileManager = fileManager;
}
@Override
public String stringDescription() {
return "Allows you to add signs to existing regions";
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if(target.hasPermission("areashop.addsign")) {
return "help-addsign";
}
return null;
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("addsign")
.senderType(PlayerCommandSource.class)
.optional(KEY_REGION, GeneralRegionParser.generalRegionParser(this.fileManager))
.flag(SignProfileUtil.DEFAULT_FLAG)
.handler(this::handleCommand);
}
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
Player sender = context.sender().sender();
if (!sender.hasPermission("areashop.addsign")) {
throw new AreaShopCommandException("addsign-noPermission");
}
// Get the sign
Block block = null;
BlockIterator blockIterator = new BlockIterator(sender, 100);
while(blockIterator.hasNext() && block == null) {
Block next = blockIterator.next();
if(next.getType() != Material.AIR) {
block = next;
}
}
if(block == null || !Materials.isSign(block.getType())) {
messageBridge.message(sender, "addsign-noSign");
return;
}
GeneralRegion region = RegionParseUtil.getOrParseRegion(context, sender, KEY_REGION);
String profile = SignProfileUtil.getOrParseProfile(context, this.plugin);
Optional<RegionSign> optionalRegionSign = this.signManager.signFromLocation(block.getLocation());
if(optionalRegionSign.isPresent()) {
RegionSign regionSign = optionalRegionSign.get();
messageBridge.message(sender, "addsign-alreadyRegistered", regionSign.getRegion());
return;
}
region.getSignsFeature().addSign(block.getLocation(), block.getType(), SignUtils.getSignFacing(block), profile);
if(profile == null) {
messageBridge.message(sender, "addsign-success", region);
} else {
messageBridge.message(sender, "addsign-successProfile", profile, region);
}
region.update();
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("addsign");
}
}
@@ -1,141 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class AddfriendCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop addfriend";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.addfriendall") || target.hasPermission("areashop.addfriend")) {
return "help-addFriend";
}
return null;
}
@SuppressWarnings("deprecation")
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.addfriend") && !sender.hasPermission("areashop.addfriendall")) {
plugin.message(sender, "addfriend-noPermission");
return;
}
if(args.length < 2) {
plugin.message(sender, "addfriend-help");
return;
}
GeneralRegion region;
if(args.length <= 2) {
if(sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[2]);
return;
}
}
if(sender.hasPermission("areashop.addfriendall")) {
if((region instanceof RentRegion && !((RentRegion)region).isRented())
|| (region instanceof BuyRegion && !((BuyRegion)region).isSold())) {
plugin.message(sender, "addfriend-noOwner", region);
return;
}
OfflinePlayer friend = Bukkit.getOfflinePlayer(args[1]);
if(friend.getLastPlayed() == 0 && !friend.isOnline() && !plugin.getConfig().getBoolean("addFriendNotExistingPlayers")) {
plugin.message(sender, "addfriend-notVisited", args[1], region);
return;
}
if(region.getFriendsFeature().getFriends().contains(friend.getUniqueId())) {
plugin.message(sender, "addfriend-alreadyAdded", friend.getName(), region);
return;
}
if(region.isOwner(friend.getUniqueId())) {
plugin.message(sender, "addfriend-self", friend.getName(), region);
return;
}
if(region.getFriendsFeature().addFriend(friend.getUniqueId(), sender)) {
region.update();
plugin.message(sender, "addfriend-successOther", friend.getName(), region);
}
} else {
if(sender.hasPermission("areashop.addfriend") && sender instanceof Player) {
if(region.isOwner((Player)sender)) {
OfflinePlayer friend = Bukkit.getOfflinePlayer(args[1]);
if(friend.getLastPlayed() == 0 && !friend.isOnline() && !plugin.getConfig().getBoolean("addFriendNotExistingPlayers")) {
plugin.message(sender, "addfriend-notVisited", args[1], region);
return;
}
if(region.getFriendsFeature().getFriends().contains(friend.getUniqueId())) {
plugin.message(sender, "addfriend-alreadyAdded", friend.getName(), region);
return;
}
if(region.isOwner(friend.getUniqueId())) {
plugin.message(sender, "addfriend-self", friend.getName(), region);
return;
}
if(region.getFriendsFeature().addFriend(friend.getUniqueId(), sender)) {
region.update();
plugin.message(sender, "addfriend-success", friend.getName(), region);
}
} else {
plugin.message(sender, "addfriend-noPermissionOther", region);
}
} else {
plugin.message(sender, "addfriend-noPermission", region);
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(toComplete == 3) {
result.addAll(plugin.getFileManager().getRegionNames());
}
return result;
}
}
@@ -1,125 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.features.signs.RegionSign;
import me.wiefferink.areashop.features.signs.SignsFeature;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.material.Sign;
import org.bukkit.util.BlockIterator;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class AddsignCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop addsign";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.addsign")) {
return "help-addsign";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.addsign")) {
plugin.message(sender, "addsign-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
// Get the sign
Block block = null;
BlockIterator blockIterator = new BlockIterator(player, 100);
while(blockIterator.hasNext() && block == null) {
Block next = blockIterator.next();
if(next.getType() != Material.AIR) {
block = next;
}
}
if(block == null || !(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)) {
plugin.message(sender, "addsign-noSign");
return;
}
GeneralRegion region;
if(args.length > 1) {
// Get region by argument
region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[1]);
return;
}
} else {
// Get region by sign position
List<GeneralRegion> regions = Utils.getImportantRegions(block.getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "addsign-noRegions");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "addsign-couldNotDetect", regions.get(0).getName(), regions.get(1).getName());
return;
}
region = regions.get(0);
}
Sign sign = (Sign)block.getState().getData();
String profile = null;
if(args.length > 2) {
profile = args[2];
Set<String> profiles = plugin.getConfig().getConfigurationSection("signProfiles").getKeys(false);
if(!profiles.contains(profile)) {
plugin.message(sender, "addsign-wrongProfile", Utils.createCommaSeparatedList(profiles), region);
return;
}
}
RegionSign regionSign = SignsFeature.getSignByLocation(block.getLocation());
if(regionSign != null) {
plugin.message(sender, "addsign-alreadyRegistered", regionSign.getRegion());
return;
}
region.getSignsFeature().addSign(block.getLocation(), block.getType(), sign.getFacing(), profile);
if(profile == null) {
plugin.message(sender, "addsign-success", region);
} else {
plugin.message(sender, "addsign-successProfile", profile, region);
}
region.update();
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
result.addAll(plugin.getConfig().getStringList("signProfiles"));
}
return result;
}
}
@@ -1,69 +1,69 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
public class BuyCommand extends CommandAreaShop {
@Singleton
public class BuyCommand extends AreashopCommandBean {
@Override
public String getCommandStart() {
return "areashop buy";
}
private final CommandFlag<BuyRegion> buyRegionFlag;
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.buy")) {
return "help-buy";
}
return null;
}
@Inject
public BuyCommand(@Nonnull IFileManager fileManager) {
this.buyRegionFlag = RegionParseUtil.createDefaultBuy(fileManager);
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.buy")) {
plugin.message(sender, "buy-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
if(args.length > 1 && args[1] != null) {
BuyRegion region = plugin.getFileManager().getBuy(args[1]);
if(region == null) {
plugin.message(player, "buy-notBuyable", args[1]);
} else {
region.buy(player);
}
} else {
// get the region by location
List<BuyRegion> regions = Utils.getImportantBuyRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
} else {
regions.get(0).buy(player);
}
}
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if(target.hasPermission("areashop.buy")) {
return "help-buy";
}
return null;
}
@Override
public String stringDescription() {
return "Allows you to buy a region";
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("buy");
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder
.literal("buy")
.flag(this.buyRegionFlag)
.senderType(PlayerCommandSource.class)
.handler(this::handleCommand);
}
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
if (!context.hasPermission("areashop.buy")) {
throw new AreaShopCommandException("buy-noPermission");
}
Player sender = context.sender().sender();
BuyRegion region = RegionParseUtil.getOrParseBuyRegion(context, sender, this.buyRegionFlag);
region.buy(sender);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(!region.isSold()) {
result.add(region.getName());
}
}
}
return result;
}
}
@@ -1,102 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.interactivemessenger.processing.Message;
import org.apache.commons.lang.StringUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Abstract class for generalising command classes.
*/
public abstract class CommandAreaShop {
final AreaShop plugin = AreaShop.getInstance();
private final Map<String, CommandTime> lastUsed;
public CommandAreaShop() {
lastUsed = new HashMap<>();
}
/**
* Check if this Command instance can execute the given command and arguments.
* @param command The command to check for execution
* @param args The arguments to check
* @return true if it can execute the command, false otherwise
*/
public boolean canExecute(Command command, String[] args) {
String commandString = command.getName() + " " + StringUtils.join(args, " ");
if(commandString.length() > getCommandStart().length()) {
return commandString.toLowerCase().startsWith(getCommandStart().toLowerCase() + " ");
}
return commandString.toLowerCase().startsWith(getCommandStart().toLowerCase());
}
/**
* Get a list of string to complete a command with (raw list, not matching ones not filtered out).
* @param toComplete The number of the argument that has to be completed
* @param start The already given start of the command
* @param sender The CommandSender that wants to tab complete
* @return A collection with all the possibilities for argument to complete
*/
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
return new ArrayList<>();
}
/**
* Get the argument that comes after the base command that this command reacts to.
* @return The string that should be in front of the command for this class to act
*/
public abstract String getCommandStart();
/**
* Returns the correct help string key to be used on the help page.
* @param target The CommandSender that the help message is for
* @return The help message key according to the permissions of the reciever
*/
public abstract String getHelp(CommandSender target);
/**
* Execute a (sub)command if the conditions are met.
* @param sender The commandSender that executed the command
* @param args The arguments that are given
*/
public abstract void execute(CommandSender sender, String[] args);
/**
* Confirm a command.
* @param sender To confirm it for, or send a message to confirm
* @param args Command args
* @param message Message to send when confirmation is required
* @return true if confirmed, false if confirmation is required
*/
public boolean confirm(CommandSender sender, String[] args, Message message) {
String command = "/" + getCommandStart() + " " + StringUtils.join(args, " ", 1, args.length);
long now = System.currentTimeMillis();
CommandTime last = lastUsed.get(sender.getName());
if(last != null && last.command.equalsIgnoreCase(command) && last.time > (now - 1000 * 60)) {
return true;
}
message.prefix().append(Message.fromKey("confirm-yes").replacements(command)).send(sender);
lastUsed.put(sender.getName(), new CommandTime(command, now));
return false;
}
private class CommandTime {
public String command;
public long time;
CommandTime(String command, long time) {
this.command = command;
this.time = time;
}
}
}
@@ -1,122 +1,185 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.interfaces.WorldEditSelection;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.GeneralRegionParser;
import me.wiefferink.areashop.commands.util.WorldSelection;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.events.ask.DeletingRegionEvent;
import me.wiefferink.areashop.interfaces.WorldEditInterface;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
public class DelCommand extends CommandAreaShop {
@Singleton
public class DelCommand extends AreashopCommandBean {
@Override
public String getCommandStart() {
return "areashop del";
}
private static final CloudKey<GeneralRegion> KEY_REGION = CloudKey.of("region", GeneralRegion.class);
private final WorldEditInterface worldEditInterface;
private final IFileManager fileManager;
private final MessageBridge messageBridge;
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.destroyrent") || target.hasPermission("areashop.destroybuy") || target.hasPermission("areashop.destroyrent.landlord") || target.hasPermission("areashop.destroybuy.landlord")) {
return "help-del";
}
return null;
}
@Inject
public DelCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull WorldEditInterface worldEditInterface,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.worldEditInterface = worldEditInterface;
this.fileManager = fileManager;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.destroybuy")
&& !sender.hasPermission("areashop.destroybuy.landlord")
@Override
public String stringDescription() {
return "Allows you to delete regions";
}
&& !sender.hasPermission("areashop.destroyrent")
&& !sender.hasPermission("areashop.destroyrent.landlord")) {
plugin.message(sender, "del-noPermission");
return;
}
if(args.length < 2) {
// Only players can have a selection
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-weOnlyByPlayer");
return;
}
Player player = (Player)sender;
WorldEditSelection selection = plugin.getWorldEditHandler().getPlayerSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
List<GeneralRegion> regions = Utils.getRegionsInSelection(selection);
if(regions == null || regions.size() == 0) {
plugin.message(player, "cmd-noRegionsFound");
return;
}
// Start removing the regions that he has permission for
ArrayList<String> namesSuccess = new ArrayList<>();
TreeSet<GeneralRegion> namesFailed = new TreeSet<>();
for(GeneralRegion region : regions) {
boolean isLandlord = region.isLandlord(((Player)sender).getUniqueId());
if(region instanceof RentRegion) {
if(!sender.hasPermission("areashop.destroyrent") && !(isLandlord && sender.hasPermission("areashop.destroyrent.landlord"))) {
namesFailed.add(region);
} else {
plugin.getFileManager().removeRent((RentRegion)region, true);
namesSuccess.add(region.getName());
}
} else if(region instanceof BuyRegion) {
if(!sender.hasPermission("areashop.destroybuy") && !(isLandlord && sender.hasPermission("areashop.destroybuy.landlord"))) {
namesFailed.add(region);
} else {
plugin.getFileManager().removeBuy((BuyRegion)region, true);
namesSuccess.add(region.getName());
}
}
}
// send messages
if(namesSuccess.size() != 0) {
plugin.message(sender, "del-success", Utils.createCommaSeparatedList(namesSuccess));
}
if(namesFailed.size() != 0) {
plugin.message(sender, "del-failed", Utils.combinedMessage(namesFailed, "region"));
}
} else {
GeneralRegion region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[1]);
return;
}
boolean isLandlord = sender instanceof Player && region.isLandlord(((Player)sender).getUniqueId());
if(region instanceof RentRegion) {
// Remove the rent if the player has permission
if(sender.hasPermission("areashop.destroyrent") || (isLandlord && sender.hasPermission("areashop.destroyrent.landlord"))) {
plugin.getFileManager().removeRent((RentRegion)region, true);
plugin.message(sender, "destroy-successRent", region);
} else {
plugin.message(sender, "destroy-noPermissionRent", region);
}
} else if(region instanceof BuyRegion) {
// Remove the buy if the player has permission
if(sender.hasPermission("areashop.destroybuy") || (isLandlord && sender.hasPermission("areashop.destroybuy.landlord"))) {
plugin.getFileManager().removeBuy((BuyRegion)region, true);
plugin.message(sender, "destroy-successBuy", region);
} else {
plugin.message(sender, "destroy-noPermissionBuy", region);
}
}
}
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.destroyrent") || target.hasPermission("areashop.destroybuy") || target.hasPermission(
"areashop.destroyrent.landlord") || target.hasPermission("areashop.destroybuy.landlord")) {
return "help-del";
}
return null;
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getRegionNames();
}
return result;
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("delete", "del");
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("del", "delete")
.optional(KEY_REGION, GeneralRegionParser.generalRegionParser(this.fileManager))
.handler(this::handleCommand);
}
public void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.destroybuy")
&& !sender.hasPermission("areashop.destroybuy.landlord")
&& !sender.hasPermission("areashop.destroyrent")
&& !sender.hasPermission("areashop.destroyrent.landlord")) {
throw new AreaShopCommandException("del-noPermission");
}
Optional<GeneralRegion> inputRegion = context.optional(KEY_REGION);
if (inputRegion.isPresent()) {
handleSingleDeletion(sender, inputRegion.get());
return;
}
List<GeneralRegion> regions;
if (sender instanceof Player player) {
WorldSelection selection = WorldSelection.fromPlayer(player, this.worldEditInterface);
regions = Utils.getWorldEditRegionsInSelection(selection.selection()).stream()
.map(ProtectedRegion::getId)
.map(this.fileManager::getRegion)
.filter(Objects::nonNull)
.toList();
} else {
throw new AreaShopCommandException("cmd-weOnlyByPlayer");
}
if (regions.isEmpty()) {
throw new AreaShopCommandException("cmd-noWERegionsFound");
}
handleMassDeletion(player, regions);
}
private void handleSingleDeletion(@Nonnull CommandSender sender, GeneralRegion region) {
boolean isLandlord = sender instanceof Player player && region.isLandlord(player.getUniqueId());
if (region instanceof RentRegion) {
// Remove the rent if the player has permission
if (sender.hasPermission("areashop.destroyrent") || (isLandlord && sender.hasPermission(
"areashop.destroyrent.landlord"))) {
DeletingRegionEvent event = fileManager.deleteRegion(region, true);
if (event.isCancelled()) {
this.messageBridge.message(sender, "general-cancelled", event.getReason());
} else {
this.messageBridge.message(sender, "destroy-successRent", region);
}
} else {
this.messageBridge.message(sender, "destroy-noPermissionRent", region);
}
} else if (region instanceof BuyRegion) {
// Remove the buy if the player has permission
if (sender.hasPermission("areashop.destroybuy") || (isLandlord && sender.hasPermission(
"areashop.destroybuy.landlord"))) {
DeletingRegionEvent event = fileManager.deleteRegion(region, true);
if (event.isCancelled()) {
messageBridge.message(sender, "general-cancelled", event.getReason());
} else {
messageBridge.message(sender, "destroy-successBuy", region);
}
} else {
messageBridge.message(sender, "destroy-noPermissionBuy", region);
}
}
}
private void handleMassDeletion(@Nonnull Player sender, @Nonnull List<GeneralRegion> regions) {
List<String> namesSuccess = new ArrayList<>();
Set<GeneralRegion> regionsFailed = new TreeSet<>();
Set<GeneralRegion> regionsCancelled = new TreeSet<>();
for (GeneralRegion region : regions) {
if (cannotDelete(sender, region)) {
regionsFailed.add(region);
continue;
}
DeletingRegionEvent event = this.fileManager.deleteRegion(region, true);
if (event.isCancelled()) {
regionsCancelled.add(region);
} else {
namesSuccess.add(region.getName());
}
}
// Send messages
if (!namesSuccess.isEmpty()) {
this.messageBridge.message(sender, "del-success", Utils.createCommaSeparatedList(namesSuccess));
}
if (!regionsFailed.isEmpty()) {
this.messageBridge.message(sender, "del-failed", Utils.combinedMessage(regionsFailed, "region"));
}
if (!regionsCancelled.isEmpty()) {
this.messageBridge.message(sender, "del-cancelled", Utils.combinedMessage(regionsCancelled, "region"));
}
}
private boolean cannotDelete(@Nonnull Player sender, @Nonnull GeneralRegion region) {
boolean isLandlord = region.isLandlord(sender.getUniqueId());
if (region instanceof RentRegion
&& (!sender.hasPermission("areashop.destroyrent") && !(isLandlord && sender.hasPermission(
"areashop.destroyrent.landlord")))) {
return true;
}
return region instanceof BuyRegion
&& (!sender.hasPermission("areashop.destroybuy") && !(isLandlord && sender.hasPermission(
"areashop.destroybuy.landlord")));
}
}
@@ -0,0 +1,193 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.adapters.platform.OfflinePlayerHelper;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.OfflinePlayerParser;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.features.FriendsFeature;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.BukkitSchedulerExecutor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.suggestion.Suggestion;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;
@Singleton
public class DelFriendCommand extends AreashopCommandBean {
private static final CloudKey<String> KEY_PLAYER = CloudKey.of("player", String.class);
private final MessageBridge messageBridge;
private final CommandFlag<GeneralRegion> regionFlag;
private final OfflinePlayerHelper offlinePlayerHelper;
private final BukkitSchedulerExecutor executor;
@Inject
public DelFriendCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager,
@Nonnull OfflinePlayerHelper offlinePlayerHelper,
@Nonnull BukkitSchedulerExecutor executor
) {
this.messageBridge = messageBridge;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
this.offlinePlayerHelper = offlinePlayerHelper;
this.executor = executor;
}
/**
* Check if a person can remove friends.
*
* @param person The person to check
* @param region The region to check for
* @return true if the person can remove friends, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if (person.hasPermission("areashop.delfriendall")) {
return true;
}
if (person instanceof Player player) {
return region.isOwner(player) && player.hasPermission("areashop.delfriend");
}
return false;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.delfriendall") || target.hasPermission("areashop.delfriend")) {
return "help-delFriend";
}
return null;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("deletefriend", "delfriend");
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("delfriend", "deletefriend")
.required(KEY_PLAYER, OfflinePlayerParser.parser(), this::suggestFriends)
.flag(this.regionFlag)
.handler(this::handleCommand);
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.delfriend") && !sender.hasPermission("areashop.delfriendall")) {
throw new AreaShopCommandException("delfriend-noPermission");
}
GeneralRegion region = RegionParseUtil.getOrParseRegion(context, sender, this.regionFlag);
this.offlinePlayerHelper.lookupOfflinePlayerAsync(context.get(KEY_PLAYER))
.whenCompleteAsync((offlinePlayer, exception) -> {
if (exception != null) {
sender.sendMessage("failed to lookup offline player!");
exception.printStackTrace();
return;
}
if (!offlinePlayer.hasPlayedBefore() && !offlinePlayer.isOnline()) {
this.messageBridge.message(sender, "cmd-invalidPlayer", offlinePlayer.getName());
return;
}
processWithSender(sender, region, offlinePlayer);
}, this.executor);
}
private void processWithSender(@Nonnull CommandSender sender,
@Nonnull GeneralRegion region,
@Nonnull OfflinePlayer friend) {
FriendsFeature friendsFeature = region.getFriendsFeature();
if (sender.hasPermission("areashop.delfriendall")) {
if ((region instanceof RentRegion rentRegion && !rentRegion.isRented())
|| (region instanceof BuyRegion buyRegion && !buyRegion.isSold())) {
throw new AreaShopCommandException("delfriend-noOwner", region);
}
if (!friendsFeature.getFriends().contains(friend.getUniqueId())) {
throw new AreaShopCommandException("delfriend-notAdded", friend.getName(), region);
}
if (friendsFeature.deleteFriend(friend.getUniqueId(), sender)) {
region.update();
this.messageBridge.message(sender, "delfriend-successOther", friend.getName(), region);
}
return;
}
if (!sender.hasPermission("areashop.delfriend") || !(sender instanceof Player player)) {
throw new AreaShopCommandException("delfriend-noPermission", region);
}
if (!region.isOwner(player)) {
throw new AreaShopCommandException("delfriend-noPermissionOther", region);
}
if (!friendsFeature.getFriends().contains(friend.getUniqueId())) {
throw new AreaShopCommandException("delfriend-notAdded", friend.getName(), region);
} else if (friendsFeature.deleteFriend(friend.getUniqueId(), sender)) {
region.update();
this.messageBridge.message(sender, "delfriend-success", friend.getName(), region);
}
}
private CompletableFuture<Iterable<Suggestion>> suggestFriends(
@Nonnull CommandContext<CommandSource<?>> context,
@Nonnull CommandInput input
) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.delfriend")) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
GeneralRegion region;
try {
region = RegionParseUtil.getOrParseRegion(context, sender, this.regionFlag);
} catch (AreaShopCommandException ignored) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
if (!sender.hasPermission("areashop.delfriendall")
&& sender instanceof Player player
&& !region.isOwner(player)
) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
String text = input.peekString();
FriendsFeature friendsFeature = region.getFriendsFeature();
Collection<Suggestion> suggestion = friendsFeature.getFriendNames().stream()
.filter(name -> name.startsWith(text))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestion);
}
}
@@ -0,0 +1,102 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.features.signs.RegionSign;
import me.wiefferink.areashop.features.signs.SignManager;
import me.wiefferink.areashop.tools.Materials;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.BlockIterator;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.Optional;
@Singleton
public class DelSignCommand extends AreashopCommandBean {
private final SignManager signManager;
private final MessageBridge messageBridge;
@Inject
public DelSignCommand(@Nonnull MessageBridge messageBridge, @Nonnull SignManager signManager) {
this.signManager = signManager;
this.messageBridge = messageBridge;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("deletesign", "delsign");
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("delsign", "deletesign")
.senderType(PlayerCommandSource.class)
.handler(this::handleCommand);
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.delsign")) {
return "help-delsign";
}
return null;
}
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
Player sender = context.sender().sender();
if (!sender.hasPermission("areashop.delsign")) {
throw new AreaShopCommandException("delsign-noPermission");
}
// Get the sign
Block block = null;
BlockIterator blockIterator = new BlockIterator(sender, 100);
while (blockIterator.hasNext() && block == null) {
Block next = blockIterator.next();
if (!next.getType().isAir()) {
block = next;
}
}
if (block == null || !Materials.isSign(block.getType())) {
throw new AreaShopCommandException("delsign-noSign");
}
Optional<RegionSign> optionalSign = signManager.removeSign(block.getLocation());
if (optionalSign.isEmpty()) {
throw new AreaShopCommandException("delsign-noRegion");
}
RegionSign regionSign = optionalSign.get();
messageBridge.message(sender, "delsign-success", regionSign.getRegion());
regionSign.remove();
// Sometimes the RegionSign data is corrupted. Forcefully set the block to air
block.setType(Material.AIR);
}
}
@@ -1,139 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class DelfriendCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop delfriend";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.delfriendall") || target.hasPermission("areashop.delfriend")) {
return "help-delFriend";
}
return null;
}
/**
* Check if a person can remove friends.
* @param person The person to check
* @param region The region to check for
* @return true if the person can remove friends, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if(person.hasPermission("areashop.delfriendall")) {
return true;
}
if(person instanceof Player) {
Player player = (Player)person;
return region.isOwner(player) && player.hasPermission("areashop.delfriend");
}
return false;
}
@SuppressWarnings("deprecation")
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.delfriend") && !sender.hasPermission("areashop.delfriendall")) {
plugin.message(sender, "delfriend-noPermission");
return;
}
if(args.length < 2) {
plugin.message(sender, "delfriend-help");
return;
}
GeneralRegion region;
if(args.length <= 2) {
if(sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[2]);
return;
}
}
if(sender.hasPermission("areashop.delfriendall")) {
if((region instanceof RentRegion && !((RentRegion)region).isRented())
|| (region instanceof BuyRegion && !((BuyRegion)region).isSold())) {
plugin.message(sender, "delfriend-noOwner", region);
return;
}
OfflinePlayer friend = Bukkit.getOfflinePlayer(args[1]);
if(!region.getFriendsFeature().getFriends().contains(friend.getUniqueId())) {
plugin.message(sender, "delfriend-notAdded", friend.getName(), region);
return;
}
if(region.getFriendsFeature().deleteFriend(friend.getUniqueId(), sender)) {
region.update();
plugin.message(sender, "delfriend-successOther", friend.getName(), region);
}
} else {
if(sender.hasPermission("areashop.delfriend") && sender instanceof Player) {
if(region.isOwner((Player)sender)) {
OfflinePlayer friend = Bukkit.getOfflinePlayer(args[1]);
if(!region.getFriendsFeature().getFriends().contains(friend.getUniqueId())) {
plugin.message(sender, "delfriend-notAdded", friend.getName(), region);
return;
}
if(region.getFriendsFeature().deleteFriend(friend.getUniqueId(), sender)) {
region.update();
plugin.message(sender, "delfriend-success", friend.getName(), region);
}
} else {
plugin.message(sender, "delfriend-noPermissionOther", region);
}
} else {
plugin.message(sender, "delfriend-noPermission", region);
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(toComplete == 3) {
result.addAll(plugin.getFileManager().getRegionNames());
}
return result;
}
}
@@ -1,78 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.features.signs.RegionSign;
import me.wiefferink.areashop.features.signs.SignsFeature;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.BlockIterator;
import java.util.ArrayList;
import java.util.List;
public class DelsignCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop delsign";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.delsign")) {
return "help-delsign";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.delsign")) {
plugin.message(sender, "delsign-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
// Get the sign
Block block = null;
BlockIterator blockIterator = new BlockIterator(player, 100);
while(blockIterator.hasNext() && block == null) {
Block next = blockIterator.next();
if(next.getType() != Material.AIR) {
block = next;
}
}
if(block == null || !(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)) {
plugin.message(sender, "delsign-noSign");
return;
}
RegionSign regionSign = SignsFeature.getSignByLocation(block.getLocation());
if(regionSign == null) {
plugin.message(sender, "delsign-noRegion");
return;
}
plugin.message(sender, "delsign-success", regionSign.getRegion());
regionSign.remove();
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
return new ArrayList<>();
}
}
@@ -1,164 +1,200 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionGroupParser;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.interactivemessenger.processing.Message;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.parser.standard.DoubleParser;
import org.incendo.cloud.parser.standard.EnumParser;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
public class FindCommand extends CommandAreaShop {
@Singleton
public class FindCommand extends AreashopCommandBean {
@Override
public String getCommandStart() {
return "areashop find";
}
private static final CloudKey<GeneralRegion.RegionType> KEY_REGION_TYPE = CloudKey.of("regionType",
GeneralRegion.RegionType.class);
private static final CloudKey<Double> KEY_PRICE = CloudKey.of("maxPrice", Double.class);
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.find")) {
return "help-find";
}
return null;
}
private final Economy economy;
private final IFileManager fileManager;
private final CommandFlag<RegionGroup> regionGroupFlag;
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.find")) {
plugin.message(sender, "find-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
if(args.length <= 1 || args[1] == null || (!args[1].equalsIgnoreCase("buy") && !args[1].equalsIgnoreCase("rent"))) {
plugin.message(sender, "find-help");
return;
}
Player player = (Player)sender;
double balance = 0.0;
if(plugin.getEconomy() != null) {
balance = plugin.getEconomy().getBalance(player);
}
double maxPrice = 0;
boolean maxPriceSet = false;
RegionGroup group = null;
// Parse optional price argument
if(args.length >= 3) {
try {
maxPrice = Double.parseDouble(args[2]);
maxPriceSet = true;
} catch(NumberFormatException e) {
plugin.message(sender, "find-wrongMaxPrice", args[2]);
return;
}
}
// Parse optional group argument
if(args.length >= 4) {
group = plugin.getFileManager().getGroup(args[3]);
if(group == null) {
plugin.message(sender, "find-wrongGroup", args[3]);
return;
}
}
private final MessageBridge messageBridge;
// Find buy regions
if(args[1].equalsIgnoreCase("buy")) {
List<BuyRegion> regions = plugin.getFileManager().getBuys();
List<BuyRegion> results = new ArrayList<>();
for(BuyRegion region : regions) {
if(!region.isSold()
&& ((region.getPrice() <= balance && !maxPriceSet) || (region.getPrice() <= maxPrice && maxPriceSet))
&& (group == null || group.isMember(region))
&& (region.getBooleanSetting("general.findCrossWorld") || player.getWorld().equals(region.getWorld()))) {
results.add(region);
}
}
if(!results.isEmpty()) {
// Draw a random one
BuyRegion region = results.get(new Random().nextInt(results.size()));
Message onlyInGroup = Message.empty();
if(group != null) {
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
}
@Inject
public FindCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull Economy economy,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.economy = economy;
this.fileManager = fileManager;
this.regionGroupFlag = CommandFlag.builder("region")
.withComponent(ParserDescriptor.of(new RegionGroupParser<>(fileManager, "find-wrongGroup"),
RegionGroup.class))
.build();
}
// Teleport
if(maxPriceSet) {
plugin.message(player, "find-successMax", "buy", Utils.formatCurrency(maxPrice), onlyInGroup, region);
} else {
plugin.message(player, "find-success", "buy", Utils.formatCurrency(balance), onlyInGroup, region);
}
region.getTeleportFeature().teleportPlayer(player, region.getBooleanSetting("general.findTeleportToSign"), false);
} else {
Message onlyInGroup = Message.empty();
if(group != null) {
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
}
if(maxPriceSet) {
plugin.message(player, "find-noneFoundMax", "buy", Utils.formatCurrency(maxPrice), onlyInGroup);
} else {
plugin.message(player, "find-noneFound", "buy", Utils.formatCurrency(balance), onlyInGroup);
}
}
}
@Override
public String stringDescription() {
return null;
}
// Find rental regions
else {
List<RentRegion> regions = plugin.getFileManager().getRents();
List<RentRegion> results = new ArrayList<>();
for(RentRegion region : regions) {
if(!region.isRented()
&& ((region.getPrice() <= balance && !maxPriceSet) || (region.getPrice() <= maxPrice && maxPriceSet))
&& (group == null || group.isMember(region))
&& (region.getBooleanSetting("general.findCrossWorld") || player.getWorld().equals(region.getWorld()))) {
results.add(region);
}
}
if(!results.isEmpty()) {
// Draw a random one
RentRegion region = results.get(new Random().nextInt(results.size()));
Message onlyInGroup = Message.empty();
if(group != null) {
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if(target.hasPermission("areashop.find")) {
return "help-find";
}
return null;
}
// Teleport
if(maxPriceSet) {
plugin.message(player, "find-successMax", "rent", Utils.formatCurrency(maxPrice), onlyInGroup, region);
} else {
plugin.message(player, "find-success", "rent", Utils.formatCurrency(balance), onlyInGroup, region);
}
region.getTeleportFeature().teleportPlayer(player, region.getBooleanSetting("general.findTeleportToSign"), false);
} else {
Message onlyInGroup = Message.empty();
if(group != null) {
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
}
if(maxPriceSet) {
plugin.message(player, "find-noneFoundMax", "rent", Utils.formatCurrency(maxPrice), onlyInGroup);
} else {
plugin.message(player, "find-noneFound", "rent", Utils.formatCurrency(balance), onlyInGroup);
}
}
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("find")
.senderType(PlayerCommandSource.class)
.required(KEY_REGION_TYPE, EnumParser.enumParser(GeneralRegion.RegionType.class))
.optional(KEY_PRICE, DoubleParser.doubleParser(0))
.flag(this.regionGroupFlag)
.handler(this::handleCommand);
}
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("find");
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
result.add("buy");
result.add("rent");
}
return result;
}
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
Player sender = context.sender().sender();
if (!sender.hasPermission("areashop.find")) {
throw new AreaShopCommandException("find-noPermission");
}
double balance;
if (economy != null) {
balance = economy.getBalance(sender);
} else {
balance = 0;
}
boolean maxPriceSet = context.contains(KEY_PRICE);
double maxPrice = context.getOrDefault(KEY_PRICE, Double.MAX_VALUE);
RegionGroup group = context.flags().get(this.regionGroupFlag);
GeneralRegion.RegionType regionType = context.get(KEY_REGION_TYPE);
Message onlyInGroup;
if (group != null) {
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(group.getName());
} else {
onlyInGroup = Message.empty();
}
switch (regionType) {
case BUY -> handleBuy(sender, balance, maxPrice, maxPriceSet, onlyInGroup, group);
case RENT -> handleRent(sender, balance, maxPrice, maxPriceSet, onlyInGroup, group);
}
}
private void handleBuy(@Nonnull Player sender,
double balance,
double maxPrice,
boolean maxPriceSet,
@Nonnull Message onlyInGroup,
RegionGroup group
) {
Collection<BuyRegion> regions = fileManager.getBuysRef();
List<BuyRegion> results = new LinkedList<>();
for (BuyRegion region : regions) {
if (!region.isSold()
&& ((region.getPrice() <= balance && !maxPriceSet) || (region.getPrice() <= maxPrice && maxPriceSet))
&& (group == null || group.isMember(region))
&& (region.getBooleanSetting("general.findCrossWorld") || sender.getWorld()
.equals(region.getWorld()))
) {
results.add(region);
}
}
if (results.isEmpty()) {
double currency = maxPriceSet ? maxPrice : balance;
String key = maxPriceSet ? "find-noneFoundMax" : "find-noneFound";
throw new AreaShopCommandException(key, "buy", Utils.formatCurrency(currency), onlyInGroup);
}
// Draw a random one
BuyRegion region = results.get(ThreadLocalRandom.current().nextInt(results.size()));
// Teleport
double currency = maxPriceSet ? maxPrice : balance;
String key = maxPriceSet ? "find-successMax" : "find-success";
this.messageBridge.message(sender,
key,
"buy",
Utils.formatCurrency(currency),
onlyInGroup,
region);
boolean tpToSign = region.getBooleanSetting("general.findTeleportToSign");
region.getTeleportFeature().teleportPlayer(sender, tpToSign, false);
}
private void handleRent(
@Nonnull Player sender,
double balance,
double maxPrice,
boolean maxPriceSet,
@Nonnull Message onlyInGroup,
RegionGroup group
) {
Collection<RentRegion> regions = fileManager.getRentsRef();
List<RentRegion> results = new LinkedList<>();
for (RentRegion region : regions) {
if (!region.isRented()
&& ((region.getPrice() <= balance && !maxPriceSet) || (region.getPrice() <= maxPrice && maxPriceSet))
&& (group == null || group.isMember(region))
&& (region.getBooleanSetting("general.findCrossWorld") || sender.getWorld()
.equals(region.getWorld()))
) {
results.add(region);
}
}
if (results.isEmpty()) {
double currency = maxPriceSet ? maxPrice : balance;
String key = maxPriceSet ? "find-noneFoundMax" : "find-noneFound";
throw new AreaShopCommandException(key, "rent", Utils.formatCurrency(currency), onlyInGroup);
}
// Draw a random one
RentRegion region = results.get(ThreadLocalRandom.current().nextInt(results.size()));
// Teleport
double currency = maxPriceSet ? maxPrice : balance;
String key = maxPriceSet ? "find-successMax" : "find-success";
this.messageBridge.message(sender,
key,
"rent",
Utils.formatCurrency(currency),
onlyInGroup,
region);
boolean tpToSign = region.getBooleanSetting("general.findTeleportToSign");
region.getTeleportFeature().teleportPlayer(sender, tpToSign, false);
}
}
@@ -0,0 +1,154 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionFactory;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.parser.standard.StringParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
@Singleton
public class GroupAddCommand extends AreashopCommandBean {
private static final CloudKey<String> KEY_GROUP = CloudKey.of("group", String.class);
private final IFileManager fileManager;
private final RegionFactory regionFactory;
private final MessageBridge messageBridge;
private final CommandFlag<GeneralRegion> regionFlag;
@Inject
public GroupAddCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager,
@Nonnull RegionFactory regionFactory
) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
this.regionFactory = regionFactory;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
}
@Override
public String stringDescription() {
return null;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if(target.hasPermission("areashop.groupadd")) {
return "help-groupadd";
}
return null;
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("groupadd")
.required(KEY_GROUP, StringParser.stringParser(), this::suggestGroupNames)
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("groupadd");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.groupadd")) {
throw new AreaShopCommandException("groupadd-noPermission");
}
String rawGroup = context.get(KEY_GROUP);
RegionGroup group = fileManager.getGroup(rawGroup);
if (group == null) {
group = regionFactory.createRegionGroup(rawGroup);
fileManager.addGroup(group);
}
GeneralRegion declaredRegion = context.flags().get(this.regionFlag);
if (declaredRegion != null) {
if (!group.addMember(declaredRegion)) {
throw new AreaShopCommandException("groupadd-failed", group.getName(), declaredRegion);
}
declaredRegion.update();
this.messageBridge.message(sender,
"groupadd-success",
group.getName(),
group.getMembers().size(),
declaredRegion);
return;
}
Collection<GeneralRegion> regions = RegionParseUtil.getOrParseRegionsInSel(context, sender, this.regionFlag);
Set<GeneralRegion> regionsSuccess = new TreeSet<>();
Set<GeneralRegion> regionsFailed = new TreeSet<>();
for (GeneralRegion region : regions) {
if (group.addMember(region)) {
regionsSuccess.add(region);
} else {
regionsFailed.add(region);
}
}
if (!regionsSuccess.isEmpty()) {
messageBridge.message(sender,
"groupadd-weSuccess",
group.getName(),
Utils.combinedMessage(regionsSuccess, "region"));
}
if (!regionsFailed.isEmpty()) {
messageBridge.message(sender,
"groupadd-weFailed",
group.getName(),
Utils.combinedMessage(regionsFailed, "region"));
}
// Update all regions, this does it in a task, updating them without lag
fileManager.updateRegions(List.copyOf(regionsSuccess), sender);
}
private CompletableFuture<Iterable<Suggestion>> suggestGroupNames(
@Nonnull CommandContext<CommandSource<?>> context,
@Nonnull CommandInput input
) {
String text = input.peekString();
List<Suggestion> suggestions = this.fileManager.getGroupNames().stream()
.filter(name -> name.startsWith(text))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestions);
}
}
@@ -0,0 +1,154 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionFactory;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.parser.standard.StringParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
@Singleton
public class GroupDelCommand extends AreashopCommandBean {
private static final CloudKey<String> KEY_GROUP = CloudKey.of("group", String.class);
private final IFileManager fileManager;
private final RegionFactory regionFactory;
private final MessageBridge messageBridge;
private final CommandFlag<GeneralRegion> regionFlag;
@Inject
public GroupDelCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager,
@Nonnull RegionFactory regionFactory
) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
this.regionFactory = regionFactory;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
}
@Override
public String stringDescription() {
return null;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if(target.hasPermission("areashop.groupdel")) {
return "help-groupdel";
}
return null;
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("groupdel")
.required(KEY_GROUP, StringParser.stringParser(), this::suggestGroupNames)
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("groupdel");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("groupdel")) {
throw new AreaShopCommandException("groupdel-noPermission");
}
String rawGroup = context.get(KEY_GROUP);
RegionGroup group = fileManager.getGroup(rawGroup);
if (group == null) {
group = regionFactory.createRegionGroup(rawGroup);
fileManager.addGroup(group);
}
GeneralRegion declaredRegion = context.flags().get(this.regionFlag);
if (declaredRegion != null) {
if (!group.removeMember(declaredRegion)) {
throw new AreaShopCommandException("groupdel-failed", group.getName(), declaredRegion);
}
this.messageBridge.message(sender,
"groupdel-success",
group.getName(),
group.getMembers().size(),
declaredRegion);
return;
}
Collection<GeneralRegion> regions = RegionParseUtil.getOrParseRegionsInSel(context, sender, this.regionFlag);
Set<GeneralRegion> regionsSuccess = new TreeSet<>();
Set<GeneralRegion> regionsFailed = new TreeSet<>();
for (GeneralRegion region : regions) {
if (group.removeMember(region)) {
regionsSuccess.add(region);
} else {
regionsFailed.add(region);
}
}
if (!regionsSuccess.isEmpty()) {
messageBridge.message(sender,
"groupdel-weSuccess",
group.getName(),
Utils.combinedMessage(regionsSuccess, "region"));
}
if (!regionsFailed.isEmpty()) {
messageBridge.message(sender,
"groupdel-weFailed",
group.getName(),
Utils.combinedMessage(regionsFailed, "region"));
}
// Update all regions, this does it in a task, updating them without lag
fileManager.updateRegions(List.copyOf(regionsSuccess), sender);
group.saveRequired();
}
private CompletableFuture<Iterable<Suggestion>> suggestGroupNames(
@Nonnull CommandContext<CommandSource<?>> context,
@Nonnull CommandInput input
) {
String text = input.peekString();
List<Suggestion> suggestions = this.fileManager.getGroupNames().stream()
.filter(name -> name.startsWith(text))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestions);
}
}
@@ -0,0 +1,91 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionGroupParser;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.ParserDescriptor;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.Set;
@Singleton
public class GroupInfoCommand extends AreashopCommandBean {
private static final CloudKey<RegionGroup> KEY_GROUP = CloudKey.of("group", RegionGroup.class);
private final IFileManager fileManager;
private final MessageBridge messageBridge;
@Inject
public GroupInfoCommand(@Nonnull MessageBridge messageBridge, @Nonnull IFileManager fileManager) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
}
@Override
public String stringDescription() {
return null;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if(target.hasPermission("areashop.groupinfo")) {
return "help-groupinfo";
}
return null;
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
ParserDescriptor<CommandSource<?>, RegionGroup> regionGroupParser = ParserDescriptor.of(
new RegionGroupParser<>(this.fileManager, "groupinfo-noGroup"),
RegionGroup.class);
return builder
.literal("groupinfo")
.required(KEY_GROUP, regionGroupParser)
.handler(this::handleCommand);
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("groupinfo");
}
public void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
if (!context.hasPermission("groupinfo")) {
throw new AreaShopCommandException("groupinfo-noPermission");
}
RegionGroup group = context.get(KEY_GROUP);
Set<String> members = group.getMembers();
if (members.isEmpty()) {
throw new AreaShopCommandException("groupinfo-noMembers", group.getName());
}
String seperatedMembers = Utils.createCommaSeparatedList(members);
this.messageBridge.message(context.sender().sender(), "groupinfo-members", group.getName(), seperatedMembers);
}
}
@@ -0,0 +1,78 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import javax.annotation.Nonnull;
import java.util.List;
@Singleton
public class GroupListCommand extends AreashopCommandBean {
private final MessageBridge messageBridge;
private final IFileManager fileManager;
@Inject
public GroupListCommand(@Nonnull MessageBridge messageBridge, @Nonnull IFileManager fileManager) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
}
@Override
public String stringDescription() {
return null;
}
@Override
public String getHelpKey(CommandSender target) {
if(target.hasPermission("areashop.grouplist")) {
return "help-grouplist";
}
return null;
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("grouplist", "groups")
.handler(this::handleCommand);
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("grouplist", "groups");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
if (!context.hasPermission("areashop.grouplist")) {
throw new AreaShopCommandException("grouplist-noPermission");
}
List<String> groups = this.fileManager.getGroupNames();
CommandSender sender = context.sender().sender();
if(groups.isEmpty()) {
messageBridge.message(sender, "grouplist-noGroups");
} else {
messageBridge.message(sender, "grouplist-success", Utils.createCommaSeparatedList(groups));
}
}
}
@@ -1,113 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.interfaces.WorldEditSelection;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
public class GroupaddCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop groupadd";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.groupadd")) {
return "help-groupadd";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.groupadd")) {
plugin.message(sender, "groupadd-noPermission");
return;
}
if(args.length < 2 || args[1] == null) {
plugin.message(sender, "groupadd-help");
return;
}
RegionGroup group = plugin.getFileManager().getGroup(args[1]);
if(group == null) {
group = new RegionGroup(plugin, args[1]);
plugin.getFileManager().addGroup(group);
}
if(args.length == 2) {
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-weOnlyByPlayer");
return;
}
Player player = (Player)sender;
WorldEditSelection selection = plugin.getWorldEditHandler().getPlayerSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
List<GeneralRegion> regions = Utils.getRegionsInSelection(selection);
if(regions.size() == 0) {
plugin.message(player, "cmd-noRegionsFound");
return;
}
TreeSet<GeneralRegion> regionsSuccess = new TreeSet<>();
TreeSet<GeneralRegion> regionsFailed = new TreeSet<>();
for(GeneralRegion region : regions) {
if(group.addMember(region)) {
regionsSuccess.add(region);
} else {
regionsFailed.add(region);
}
}
if(regionsSuccess.size() != 0) {
plugin.message(player, "groupadd-weSuccess", group.getName(), Utils.combinedMessage(regionsSuccess, "region"));
}
if(regionsFailed.size() != 0) {
plugin.message(player, "groupadd-weFailed", group.getName(), Utils.combinedMessage(regionsFailed, "region"));
}
// Update all regions, this does it in a task, updating them without lag
plugin.getFileManager().updateRegions(new ArrayList<>(regionsSuccess), player);
} else {
GeneralRegion region = plugin.getFileManager().getRegion(args[2]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[2]);
return;
}
if(group.addMember(region)) {
region.update();
plugin.message(sender, "groupadd-success", group.getName(), group.getMembers().size(), region);
} else {
plugin.message(sender, "groupadd-failed", group.getName(), region);
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getGroupNames();
} else if(toComplete == 3) {
result = plugin.getFileManager().getRegionNames();
}
return result;
}
}
@@ -1,115 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.interfaces.WorldEditSelection;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
public class GroupdelCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop groupdel";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.groupdel")) {
return "help-groupdel";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.groupdel")) {
plugin.message(sender, "groupdel-noPermission");
return;
}
if(args.length < 2 || args[1] == null) {
plugin.message(sender, "groupdel-help");
return;
}
RegionGroup group = plugin.getFileManager().getGroup(args[1]);
if(group == null) {
plugin.message(sender, "groupdel-wrongGroup", args[1]);
return;
}
if(args.length == 2) {
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-weOnlyByPlayer");
return;
}
Player player = (Player)sender;
WorldEditSelection selection = plugin.getWorldEditHandler().getPlayerSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
List<GeneralRegion> regions = Utils.getRegionsInSelection(selection);
if(regions.size() == 0) {
plugin.message(player, "cmd-noRegionsFound");
return;
}
TreeSet<GeneralRegion> regionsSuccess = new TreeSet<>();
TreeSet<GeneralRegion> regionsFailed = new TreeSet<>();
for(GeneralRegion region : regions) {
if(group.removeMember(region)) {
regionsSuccess.add(region);
} else {
regionsFailed.add(region);
}
}
if(regionsSuccess.size() != 0) {
plugin.message(player, "groupdel-weSuccess", group.getName(), Utils.combinedMessage(regionsSuccess, "region"));
}
if(regionsFailed.size() != 0) {
plugin.message(player, "groupdel-weFailed", group.getName(), Utils.combinedMessage(regionsFailed, "region"));
}
// Update all regions, this does it in a task, updating them without lag
plugin.getFileManager().updateRegions(new ArrayList<>(regionsSuccess), player);
group.saveRequired();
} else {
GeneralRegion region = plugin.getFileManager().getRegion(args[2]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[2]);
return;
}
if(group.removeMember(region)) {
region.update();
plugin.message(sender, "groupdel-success", group.getName(), group.getMembers().size(), region);
} else {
plugin.message(sender, "groupdel-failed", group.getName(), region);
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getGroupNames();
} else if(toComplete == 3) {
result = plugin.getFileManager().getRegionNames();
}
return result;
}
}
@@ -1,69 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class GroupinfoCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop groupinfo";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.groupinfo")) {
return "help-groupinfo";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.groupinfo")) {
plugin.message(sender, "groupinfo-noPermission");
return;
}
if(args.length < 2 || args[1] == null) {
plugin.message(sender, "groupinfo-help");
return;
}
RegionGroup group = plugin.getFileManager().getGroup(args[1]);
if(group == null) {
plugin.message(sender, "groupinfo-noGroup", args[1]);
return;
}
Set<String> members = group.getMembers();
if(members.size() == 0) {
plugin.message(sender, "groupinfo-noMembers", group.getName());
} else {
plugin.message(sender, "groupinfo-members", group.getName(), Utils.createCommaSeparatedList(members));
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getGroupNames();
}
return result;
}
}
@@ -1,53 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
public class GrouplistCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop grouplist";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.grouplist")) {
return "help-grouplist";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.grouplist")) {
plugin.message(sender, "grouplist-noPermission");
return;
}
List<String> groups = plugin.getFileManager().getGroupNames();
if(groups.size() == 0) {
plugin.message(sender, "grouplist-noGroups");
} else {
plugin.message(sender, "grouplist-success", Utils.createCommaSeparatedList(groups));
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
return new ArrayList<>();
}
}
@@ -1,24 +1,58 @@
package me.wiefferink.areashop.commands;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.AreashopCommands;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.jetbrains.annotations.NotNull;
public class HelpCommand extends CommandAreaShop {
import javax.annotation.Nonnull;
@Override
public String getCommandStart() {
return "areashop help";
}
@Singleton
public class HelpCommand extends AreashopCommandBean {
private final AreashopCommands commands;
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.help")) {
return "help-help";
}
return null;
}
@Inject
public HelpCommand(@Nonnull AreashopCommands commands) {
this.commands = commands;
}
@Override
public void execute(CommandSender sender, String[] args) {
plugin.getCommandManager().showHelp(sender);
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.help")) {
return "help-help";
}
return null;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("help")
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("help");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.help")) {
throw new AreaShopCommandException("help-noPermission");
}
this.commands.showHelp(sender);
}
}
@@ -1,70 +1,88 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.interactivemessenger.processing.Message;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AcceptedValuesParser;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.regions.ImportJobFactory;
import org.bukkit.command.CommandSender;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.ParserDescriptor;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import javax.annotation.Nonnull;
import java.util.List;
public class ImportCommand extends CommandAreaShop {
@Singleton
public class ImportCommand extends AreashopCommandBean {
/* RegionGroup priority usage:
0: Settings from /config.yml
1: Settings from /worlds/<world>/config.yml
2: Settings from /worlds/<world>/parent-regions.yml (if their priority is set it is added to this value)
*/
private static final CloudKey<String> KEY_SOURCE = CloudKey.of("source", String.class);
@Override
public String getCommandStart() {
return "areashop import";
}
/* RegionGroup priority usage:
0: Settings from /config.yml
1: Settings from /worlds/<world>/config.yml
2: Settings from /worlds/<world>/parent-regions.yml (if their priority is set it is added to this value)
*/
private final ImportJobFactory importJobFactory;
private final MessageBridge messageBridge;
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.import")) {
return "help-import";
}
return null;
}
@Inject
public ImportCommand(@Nonnull MessageBridge messageBridge, @Nonnull ImportJobFactory importJobFactory) {
this.messageBridge = messageBridge;
this.importJobFactory = importJobFactory;
}
// TODO
// - Landlord?
// - Friends
// - Region flags?
// - Settings from the 'permissions' section in RegionForSale/config.yml?
@Override
public String stringDescription() {
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.import")) {
plugin.message(sender, "import-noPermission");
return;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if(target.hasPermission("areashop.import")) {
return "help-import";
}
return null;
}
if(args.length < 2) {
plugin.message(sender, "import-help");
return;
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
withConfirmation();
var sourceParser = AcceptedValuesParser.ofConstant(List.of("RegionForSale"), "import-wrongSource", true);
return builder.literal("import")
.required(KEY_SOURCE, ParserDescriptor.of(sourceParser, String.class))
.handler(this::handleCommand);
}
if(!"RegionForSale".equalsIgnoreCase(args[1])) {
plugin.message(sender, "import-wrongSource");
return;
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("import");
}
if(!confirm(sender, args, Message.fromKey("import-confirm"))) {
return;
}
// TODO:
// - Landlord?
// - Friends
// - Region flags?
// - Settings from the 'permissions' section in RegionForSale/config.yml?
ImportJob importJob = new ImportJob(sender);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result.add("RegionForSale");
}
return result;
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.import")) {
this.messageBridge.message(sender, "import-noPermission");
return;
}
String importSource = context.get(KEY_SOURCE);
if (!"RegionForSale".equalsIgnoreCase(importSource)) {
throw new AreaShopCommandException("import-wrongSource");
}
importJobFactory.createImportJob(sender).execute();
}
}
@@ -0,0 +1,86 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import org.bukkit.command.CommandSender;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
@Singleton
public class InfoBaseCommand extends AreashopCommandBean {
private final MessageBridge messageBridge;
@Inject
public InfoBaseCommand(
@Nonnull MessageBridge messageBridge
) {
this.messageBridge = messageBridge;
}
@Override
public String stringDescription() {
return null;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.info")) {
return "help-info";
}
return null;
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("info").handler(this::handleCommand);
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("info");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.info")) {
messageBridge.message(sender, "info-noPermission");
return;
}
this.messageBridge.message(sender, "info-help");
}
}
@@ -1,460 +1,272 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionGroupParser;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.areashop.tools.SimpleMessageBridge;
import me.wiefferink.interactivemessenger.processing.Message;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.parser.standard.EnumParser;
import org.incendo.cloud.parser.standard.IntegerParser;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import javax.annotation.Nonnull;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
// TODO fix '/as info' help message hitting replacement limit (improve depth tracking?)
// TODO add info about autoExtend
public class InfoCommand extends CommandAreaShop {
@Singleton
public class InfoCommand extends AreashopCommandBean {
@Override
public String getCommandStart() {
return "areashop info";
}
private static final CommandFlag<Integer> FLAG_PAGE = CommandFlag.builder("page")
.withComponent(IntegerParser.integerParser(1))
.build();
private static final CloudKey<RegionStateFilterType> KEY_TYPE = CloudKey.of("type", RegionStateFilterType.class);
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.info")) {
return "help-info";
}
return null;
}
private final MessageBridge messageBridge;
private final IFileManager fileManager;
/**
* Display a page of a list of regions.
* @param sender The CommandSender to send the messages to
* @param regions The regions to display
* @param filterGroup The group to filter the regions by
* @param keyHeader The header to print above the page
* @param pageInput The page number, if any
* @param baseCommand The command to execute for next/previous page (/areashop will be added)
*/
private void showSortedPagedList(CommandSender sender, List<? extends GeneralRegion> regions, RegionGroup filterGroup, String keyHeader, String pageInput, String baseCommand) {
int maximumItems = 20;
int itemsPerPage = maximumItems - 2;
int page = 1;
if(pageInput != null && Utils.isNumeric(pageInput)) {
try {
page = Integer.parseInt(pageInput);
} catch(NumberFormatException e) {
plugin.message(sender, "info-wrongPage", pageInput);
return;
}
}
if(filterGroup != null) {
regions.removeIf(generalRegion -> !filterGroup.isMember(generalRegion));
}
if(regions.isEmpty()) {
plugin.message(sender, "info-noRegions");
} else {
// First sort by type, then by name
regions.sort((one, two) -> {
int typeCompare = getTypeOrder(two).compareTo(getTypeOrder(one));
if(typeCompare != 0) {
return typeCompare;
} else {
return one.getName().compareTo(two.getName());
}
});
// Header
Message limitedToGroup = Message.empty();
if(filterGroup != null) {
limitedToGroup = Message.fromKey("info-limitedToGroup").replacements(filterGroup.getName());
}
plugin.message(sender, keyHeader, limitedToGroup);
// Page entries
int totalPages = (int)Math.ceil(regions.size() / (double)itemsPerPage); // Clip page to correct boundaries, not much need to tell the user
if(regions.size() == itemsPerPage + 1) { // 19 total items is mapped to 1 page of 19
itemsPerPage++;
totalPages = 1;
}
page = Math.max(1, Math.min(totalPages, page));
int linesPrinted = 1; // header
for(int i = (page - 1) * itemsPerPage; i < page * itemsPerPage && i < regions.size(); i++) {
String state;
GeneralRegion region = regions.get(i);
if(region.getType() == GeneralRegion.RegionType.RENT) {
if(region.getOwner() == null) {
state = "Forrent";
} else {
state = "Rented";
}
} else {
if(region.getOwner() == null) {
state = "Forsale";
} else if(!((BuyRegion)region).isInResellingMode()) {
state = "Sold";
} else {
state = "Reselling";
}
}
plugin.messageNoPrefix(sender, "info-entry" + state, region);
linesPrinted++;
}
Message footer = Message.empty();
// Previous button
if(page > 1) {
footer.append(Message.fromKey("info-pagePrevious").replacements(baseCommand + " " + (page - 1)));
} else {
footer.append(Message.fromKey("info-pageNoPrevious"));
}
// Page status
if(totalPages > 1) {
String pageString = "" + page;
for(int i = pageString.length(); i < (totalPages + "").length(); i++) {
pageString = "0" + pageString;
}
footer.append(Message.fromKey("info-pageStatus").replacements(page, totalPages));
if(page < totalPages) {
footer.append(Message.fromKey("info-pageNext").replacements(baseCommand + " " + (page + 1)));
} else {
footer.append(Message.fromKey("info-pageNoNext"));
}
// Fill up space if the page is not full (aligns header nicely)
for(int i = linesPrinted; i < maximumItems - 1; i++) {
sender.sendMessage(" ");
}
footer.send(sender);
}
}
}
private final CommandFlag<RegionGroup> filterGroupFlag;
/**
* Get an integer to order by type, usable for Comparators.
* @param region The region to get the order for
* @return An integer for sorting by type
*/
private Integer getTypeOrder(GeneralRegion region) {
if(region.getType() == GeneralRegion.RegionType.RENT) {
if(region.getOwner() == null) {
return 1;
} else {
return 2;
}
} else {
if(region.getOwner() == null) {
return 3;
} else if(!((BuyRegion)region).isInResellingMode()) {
return 4;
} else {
return 5;
}
}
}
@Inject
public InfoCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
this.filterGroupFlag = CommandFlag.builder("group")
.withComponent(ParserDescriptor.of(new RegionGroupParser<>(fileManager, "info-noFiltergroup"),
RegionGroup.class))
.build();
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.info")) {
plugin.message(sender, "info-noPermission");
return;
}
if(args.length > 1 && args[1] != null) {
// Get filter group (only used by some commands)
RegionGroup filterGroup = null;
Set<String> groupFilters = new HashSet<>(Arrays.asList("all", "rented", "forrent", "sold", "forsale", "reselling"));
if(groupFilters.contains(args[1].toLowerCase()) && args.length > 2) {
if(!Utils.isNumeric(args[2])) {
filterGroup = plugin.getFileManager().getGroup(args[2]);
if(filterGroup == null) {
plugin.message(sender, "info-noFiltergroup", args[2]);
return;
}
// Pass page number to args[2] if available
if(args.length > 3) {
args[2] = args[3];
}
}
}
@Override
public String stringDescription() {
return null;
}
// All regions
if(args[1].equalsIgnoreCase("all")) {
showSortedPagedList(sender, plugin.getFileManager().getRegions(), filterGroup, "info-allHeader", (args.length > 2 ? args[2] : null), "info all");
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
return null;
}
// Rented regions
else if(args[1].equalsIgnoreCase("rented")) {
List<RentRegion> regions = plugin.getFileManager().getRents();
regions.removeIf(RentRegion::isAvailable);
showSortedPagedList(sender, regions, filterGroup, "info-rentedHeader", (args.length > 2 ? args[2] : null), "info rented");
}
// Forrent regions
else if(args[1].equalsIgnoreCase("forrent")) {
List<RentRegion> regions = plugin.getFileManager().getRents();
regions.removeIf(RentRegion::isRented);
showSortedPagedList(sender, regions, filterGroup, "info-forrentHeader", (args.length > 2 ? args[2] : null), "info forrent");
}
// Sold regions
else if(args[1].equalsIgnoreCase("sold")) {
List<BuyRegion> regions = plugin.getFileManager().getBuys();
regions.removeIf(BuyRegion::isAvailable);
showSortedPagedList(sender, regions, filterGroup, "info-soldHeader", (args.length > 2 ? args[2] : null), "info sold");
}
// Forsale regions
else if(args[1].equalsIgnoreCase("forsale")) {
List<BuyRegion> regions = plugin.getFileManager().getBuys();
regions.removeIf(BuyRegion::isSold);
showSortedPagedList(sender, regions, filterGroup, "info-forsaleHeader", (args.length > 2 ? args[2] : null), "info forsale");
}
// Reselling regions
else if(args[1].equalsIgnoreCase("reselling")) {
List<BuyRegion> regions = plugin.getFileManager().getBuys();
regions.removeIf(region -> !region.isInResellingMode());
showSortedPagedList(sender, regions, filterGroup, "info-resellingHeader", (args.length > 2 ? args[2] : null), "info reselling");
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("info")
.required(KEY_TYPE, EnumParser.enumParser(RegionStateFilterType.class))
.flag(FLAG_PAGE)
.flag(this.filterGroupFlag)
.handler(this::handleCommand);
}
// List of regions without a group
else if(args[1].equalsIgnoreCase("nogroup")) {
List<GeneralRegion> regions = plugin.getFileManager().getRegions();
for(RegionGroup group : plugin.getFileManager().getGroups()) {
regions.removeAll(group.getMemberRegions());
}
if(regions.isEmpty()) {
plugin.message(sender, "info-nogroupNone");
} else {
showSortedPagedList(sender, regions, filterGroup, "info-nogroupHeader", (args.length > 2 ? args[2] : null), "info nogroup");
}
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("info");
}
// Region info
else if(args[1].equalsIgnoreCase("region")) {
if(args.length > 1) {
RentRegion rent = null;
BuyRegion buy = null;
if(args.length > 2) {
rent = plugin.getFileManager().getRent(args[2]);
buy = plugin.getFileManager().getBuy(args[2]);
} else {
if(sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
if(regions.get(0) instanceof RentRegion) {
rent = (RentRegion)regions.get(0);
} else if(regions.get(0) instanceof BuyRegion) {
buy = (BuyRegion)regions.get(0);
}
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.info")) {
messageBridge.message(sender, "info-noPermission");
return;
}
RegionStateFilterType filterType = context.get(KEY_TYPE);
processOtherFilters(context, filterType);
}
if(rent == null && buy == null) {
plugin.message(sender, "info-regionNotExisting", args[2]);
return;
}
private void processOtherFilters(@Nonnull CommandContext<CommandSource<?>> context,
@Nonnull RegionStateFilterType filterType) {
RegionGroup filterGroup = context.flags().get(this.filterGroupFlag);
int page = context.flags().getValue(FLAG_PAGE).orElse(1);
Stream<? extends GeneralRegion> toShow = switch (filterType) {
case ALL -> fileManager.getRegionsRef().stream();
case SOLD -> fileManager.getBuysRef().stream().filter(BuyRegion::isSold);
case RENTED -> fileManager.getRentsRef().stream().filter(RentRegion::isRented);
case FORRENT -> fileManager.getRentsRef().stream().filter(RentRegion::isAvailable);
case FORSALE -> fileManager.getBuysRef().stream().filter(BuyRegion::isAvailable);
case RESELLING -> fileManager.getBuysRef().stream().filter(BuyRegion::isInResellingMode);
case NOGROUP -> {
List<GeneralRegion> regions = new LinkedList<>(fileManager.getRegions());
for (RegionGroup group : fileManager.getGroups()) {
regions.removeAll(group.getMemberRegions());
}
yield regions.stream();
}
};
String header = switch (filterType) {
case ALL -> "info-allHeader";
case SOLD -> "info-soldHeader";
case RENTED -> "info-rentedHeader";
case FORRENT -> "info-forrentHeader";
case FORSALE -> "info-forsaleHeader";
case RESELLING -> "info-resellingHeader";
case NOGROUP -> "info-nogroupHeader";
};
String baseCommand = switch (filterType) {
case ALL -> "info all";
case SOLD -> "info sold";
case RENTED -> "info rented";
case FORRENT -> "info forrent";
case FORSALE -> "info forsale";
case RESELLING -> "info reselling";
case NOGROUP -> "info nogroup";
};
showSortedPagedList(context.sender().sender(), toShow, filterGroup, header, page, baseCommand);
}
if(rent != null) {
plugin.message(sender, "info-regionHeaderRent", rent);
if(rent.isRented()) {
plugin.messageNoPrefix(sender, "info-regionRented", rent);
plugin.messageNoPrefix(sender, "info-regionExtending", rent);
// Money back
if(UnrentCommand.canUse(sender, rent)) {
plugin.messageNoPrefix(sender, "info-regionMoneyBackRentClick", rent);
} else {
plugin.messageNoPrefix(sender, "info-regionMoneyBackRent", rent);
}
// Friends
if(!rent.getFriendsFeature().getFriendNames().isEmpty()) {
String messagePart = "info-friend";
if(DelfriendCommand.canUse(sender, rent)) {
messagePart = "info-friendRemove";
}
plugin.messageNoPrefix(sender, "info-regionFriends", rent, Utils.combinedMessage(rent.getFriendsFeature().getFriendNames(), messagePart));
}
} else {
plugin.messageNoPrefix(sender, "info-regionCanBeRented", rent);
}
if(rent.getLandlordName() != null) {
plugin.messageNoPrefix(sender, "info-regionLandlord", rent);
}
// Maximum extends
if(rent.getMaxExtends() != -1) {
if(rent.getMaxExtends() == 0) {
plugin.messageNoPrefix(sender, "info-regionNoExtending", rent);
} else if(rent.isRented()) {
plugin.messageNoPrefix(sender, "info-regionExtendsLeft", rent);
} else {
plugin.messageNoPrefix(sender, "info-regionMaxExtends", rent);
}
}
// If maxExtends is zero it does not make sense to show this message
if(rent.getMaxRentTime() != -1 && rent.getMaxExtends() != 0) {
plugin.messageNoPrefix(sender, "info-regionMaxRentTime", rent);
}
if(rent.getInactiveTimeUntilUnrent() != -1) {
plugin.messageNoPrefix(sender, "info-regionInactiveUnrent", rent);
}
// Teleport
Message tp = Message.fromKey("info-prefix");
boolean foundSomething = false;
if(TeleportCommand.canUse(sender, rent)) {
foundSomething = true;
tp.append(Message.fromKey("info-regionTeleport").replacements(rent));
}
if(SetteleportCommand.canUse(sender, rent)) {
if(foundSomething) {
tp.append(", ");
}
foundSomething = true;
tp.append(Message.fromKey("info-setRegionTeleport").replacements(rent));
}
if(foundSomething) {
tp.append(".");
tp.send(sender);
}
// Signs
List<String> signLocations = new ArrayList<>();
for(Location location : rent.getSignsFeature().getSignLocations()) {
signLocations.add(Message.fromKey("info-regionSignLocation").replacements(location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ()).getPlain());
}
if(!signLocations.isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionSigns", Utils.createCommaSeparatedList(signLocations));
}
// Groups
if(sender.hasPermission("areashop.groupinfo") && !rent.getGroupNames().isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionGroups", Utils.createCommaSeparatedList(rent.getGroupNames()));
}
// Restoring
if(rent.isRestoreEnabled()) {
plugin.messageNoPrefix(sender, "info-regionRestoringRent", rent);
}
// Restrictions
if(!rent.isRented()) {
if(rent.restrictedToRegion()) {
plugin.messageNoPrefix(sender, "info-regionRestrictedRegionRent", rent);
} else if(rent.restrictedToWorld()) {
plugin.messageNoPrefix(sender, "info-regionRestrictedWorldRent", rent);
}
}
plugin.messageNoPrefix(sender, "info-regionFooterRent", rent);
} else if(buy != null) {
plugin.message(sender, "info-regionHeaderBuy", buy);
if(buy.isSold()) {
if(buy.isInResellingMode()) {
plugin.messageNoPrefix(sender, "info-regionReselling", buy);
plugin.messageNoPrefix(sender, "info-regionReselPrice", buy);
} else {
plugin.messageNoPrefix(sender, "info-regionBought", buy);
}
// Money back
if(!buy.getBooleanSetting("buy.sellDisabled")) {
if (SellCommand.canUse(sender, buy)) {
plugin.messageNoPrefix(sender, "info-regionMoneyBackBuyClick", buy);
} else {
plugin.messageNoPrefix(sender, "info-regionMoneyBackBuy", buy);
}
}
// Friends
if(!buy.getFriendsFeature().getFriendNames().isEmpty()) {
String messagePart = "info-friend";
if(DelfriendCommand.canUse(sender, buy)) {
messagePart = "info-friendRemove";
}
plugin.messageNoPrefix(sender, "info-regionFriends", buy, Utils.combinedMessage(buy.getFriendsFeature().getFriendNames(), messagePart));
}
} else {
plugin.messageNoPrefix(sender, "info-regionCanBeBought", buy);
}
if(buy.getLandlord() != null) {
plugin.messageNoPrefix(sender, "info-regionLandlord", buy);
}
if(buy.getInactiveTimeUntilSell() != -1) {
plugin.messageNoPrefix(sender, "info-regionInactiveSell", buy);
}
// Teleport
Message tp = Message.fromKey("info-prefix");
boolean foundSomething = false;
if(TeleportCommand.canUse(sender, buy)) {
foundSomething = true;
tp.append(Message.fromKey("info-regionTeleport").replacements(buy));
}
if(SetteleportCommand.canUse(sender, buy)) {
if(foundSomething) {
tp.append(", ");
}
foundSomething = true;
tp.append(Message.fromKey("info-setRegionTeleport").replacements(buy));
}
if(foundSomething) {
tp.append(".");
tp.send(sender);
}
// Signs
List<String> signLocations = new ArrayList<>();
for(Location location : buy.getSignsFeature().getSignLocations()) {
signLocations.add(Message.fromKey("info-regionSignLocation").replacements(location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ()).getPlain());
}
if(!signLocations.isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionSigns", Utils.createCommaSeparatedList(signLocations));
}
// Groups
if(sender.hasPermission("areashop.groupinfo") && !buy.getGroupNames().isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionGroups", Utils.createCommaSeparatedList(buy.getGroupNames()));
}
// Restoring
if(buy.isRestoreEnabled()) {
plugin.messageNoPrefix(sender, "info-regionRestoringBuy", buy);
}
// Restrictions
if(!buy.isSold()) {
if(buy.restrictedToRegion()) {
plugin.messageNoPrefix(sender, "info-regionRestrictedRegionBuy", buy);
} else if(buy.restrictedToWorld()) {
plugin.messageNoPrefix(sender, "info-regionRestrictedWorldBuy", buy);
}
}
plugin.messageNoPrefix(sender, "info-regionFooterBuy", buy);
}
} else {
plugin.message(sender, "info-regionHelp");
}
} else {
plugin.message(sender, "info-help");
}
} else {
plugin.message(sender, "info-help");
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result.addAll(Arrays.asList("all", "rented", "forrent", "sold", "forsale", "player", "region", "nogroup", "reselling"));
} else if(toComplete == 3) {
if(start[2].equalsIgnoreCase("player")) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(start[2].equalsIgnoreCase("region")) {
result.addAll(plugin.getFileManager().getBuyNames());
result.addAll(plugin.getFileManager().getRentNames());
}
}
return result;
}
/**
* Display a page of a list of regions.
*
* @param sender The CommandSender to send the messages to
* @param regionStream The regions to display
* @param filterGroup The group to filter the regions by
* @param keyHeader The header to print above the page
* @param pageInput The page number, if any
* @param baseCommand The command to execute for next/previous page (/areashop will be added)
*/
private void showSortedPagedList(
CommandSender sender,
Stream<? extends GeneralRegion> regionStream,
RegionGroup filterGroup,
String keyHeader,
int pageInput,
String baseCommand
) {
int page = pageInput;
int maximumItems = 20;
int itemsPerPage = maximumItems - 2;
List<? extends GeneralRegion> regions;
if (filterGroup != null) {
regions = regionStream.filter(generalRegion -> !filterGroup.isMember(generalRegion)).toList();
} else {
regions = regionStream.toList();
}
if (regions.isEmpty()) {
messageBridge.message(sender, "info-noRegions");
return;
}
// First sort by type, then by name
regions = regions.stream().sorted((one, two) -> {
int typeCompare = getTypeOrder(two).compareTo(getTypeOrder(one));
if (typeCompare != 0) {
return typeCompare;
} else {
return one.getName().compareTo(two.getName());
}
}).toList();
// Header
Message limitedToGroup = Message.empty();
if (filterGroup != null) {
limitedToGroup = Message.fromKey("info-limitedToGroup").replacements(filterGroup.getName());
}
messageBridge.message(sender, keyHeader, limitedToGroup);
// Page entries
int totalPages = (int) Math.ceil(regions.size() / (double) itemsPerPage); // Clip page to correct boundaries, not much need to tell the user
if (regions.size() == itemsPerPage + 1) { // 19 total items is mapped to 1 page of 19
itemsPerPage++;
totalPages = 1;
}
page = Math.max(1, Math.min(totalPages, page));
int linesPrinted = 1; // header
for (int i = (page - 1) * itemsPerPage; i < page * itemsPerPage && i < regions.size(); i++) {
String state;
GeneralRegion region = regions.get(i);
if (region.getType() == GeneralRegion.RegionType.RENT) {
if (region.getOwner() == null) {
state = "Forrent";
} else {
state = "Rented";
}
} else {
if (region.getOwner() == null) {
state = "Forsale";
} else if (!((BuyRegion) region).isInResellingMode()) {
state = "Sold";
} else {
state = "Reselling";
}
}
messageBridge.messageNoPrefix(sender, "info-entry" + state, region);
linesPrinted++;
}
Message footer = Message.empty();
// Previous button
if (page > 1) {
footer.append(Message.fromKey("info-pagePrevious").replacements(baseCommand + " --page " + (page - 1)));
} else {
footer.append(Message.fromKey("info-pageNoPrevious"));
}
// Page status
if (totalPages > 1) {
StringBuilder pageString = new StringBuilder("" + page);
for (int i = pageString.length(); i < (totalPages + "").length(); i++) {
pageString.insert(0, "0");
}
footer.append(Message.fromKey("info-pageStatus").replacements(page, totalPages));
if (page < totalPages) {
footer.append(Message.fromKey("info-pageNext").replacements(baseCommand + " --page " + (page + 1)));
} else {
footer.append(Message.fromKey("info-pageNoNext"));
}
// Fill up space if the page is not full (aligns header nicely)
for (int i = linesPrinted; i < maximumItems - 1; i++) {
sender.sendMessage(" ");
}
SimpleMessageBridge.send(footer, sender);
}
}
/**
* Get an integer to order by type, usable for Comparators.
*
* @param region The region to get the order for
* @return An integer for sorting by type
*/
private Integer getTypeOrder(GeneralRegion region) {
if (region.getType() == GeneralRegion.RegionType.RENT) {
if (region.getOwner() == null) {
return 1;
} else {
return 2;
}
} else {
if (region.getOwner() == null) {
return 3;
} else if (!((BuyRegion) region).isInResellingMode()) {
return 4;
} else {
return 5;
}
}
}
private enum RegionStateFilterType {
ALL,
RENTED,
FORRENT,
SOLD,
FORSALE,
RESELLING,
NOGROUP
}
}
@@ -0,0 +1,113 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.adapters.platform.OfflinePlayerHelper;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.OfflinePlayerParser;
import me.wiefferink.areashop.commands.util.RegionInfoUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.tools.BukkitSchedulerExecutor;
import org.bukkit.command.CommandSender;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import javax.annotation.Nonnull;
@Singleton
public class InfoPlayerCommand extends AreashopCommandBean {
private static final CloudKey<String> KEY_PLAYER = CloudKey.of("player", String.class);
private final MessageBridge messageBridge;
private final IFileManager fileManager;
private final OfflinePlayerHelper offlinePlayerHelper;
private final BukkitSchedulerExecutor executor;
@Inject
public InfoPlayerCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager,
@Nonnull OfflinePlayerHelper offlinePlayerHelper,
@Nonnull BukkitSchedulerExecutor executor
) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
this.offlinePlayerHelper = offlinePlayerHelper;
this.executor = executor;
}
@Override
public String stringDescription() {
return null;
}
@Override
public String getHelpKey(CommandSender target) {
return null;
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("info").literal("player")
.required(KEY_PLAYER, OfflinePlayerParser.parser())
.handler(this::handleCommand);
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("info region");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.info")) {
messageBridge.message(sender, "info-noPermission");
return;
}
this.offlinePlayerHelper.lookupOfflinePlayerAsync(context.get(KEY_PLAYER))
.whenCompleteAsync((offlinePlayer, exception) -> {
if (exception != null) {
sender.sendMessage("failed to lookup offline player!");
exception.printStackTrace();
return;
}
if (!offlinePlayer.hasPlayedBefore() && !offlinePlayer.isOnline()) {
this.messageBridge.message(sender, "cmd-invalidPlayer", offlinePlayer.getName());
return;
}
RegionInfoUtil.showRegionInfo(this.messageBridge, this.fileManager, sender, offlinePlayer);
}, this.executor);
}
}
@@ -0,0 +1,273 @@
package me.wiefferink.areashop.commands;
import io.github.bakedlibs.dough.blocks.BlockPosition;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.SimpleMessageBridge;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.interactivemessenger.processing.Message;
import org.bukkit.command.CommandSender;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
@Singleton
public class InfoRegionCommand extends AreashopCommandBean {
private final CommandFlag<GeneralRegion> regionFlag;
private final MessageBridge messageBridge;
@Inject
public InfoRegionCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
}
@Override
public String stringDescription() {
return null;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
return null;
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("info").literal("region")
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("info region");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.info")) {
messageBridge.message(sender, "info-noPermission");
return;
}
// Region info
GeneralRegion region = RegionParseUtil.getOrParseRegion(context, sender, this.regionFlag);
if (region instanceof RentRegion rent) {
handleRent(sender, rent);
} else if (region instanceof BuyRegion buy) {
handleBuy(sender, buy);
}
}
private void handleBuy(@Nonnull CommandSender sender, @Nonnull BuyRegion buy) {
messageBridge.message(sender, "info-regionHeaderBuy", buy);
if (buy.isSold()) {
if (buy.isInResellingMode()) {
messageBridge.messageNoPrefix(sender, "info-regionReselling", buy);
messageBridge.messageNoPrefix(sender, "info-regionReselPrice", buy);
} else {
messageBridge.messageNoPrefix(sender, "info-regionBought", buy);
}
// Money back
if (!buy.getBooleanSetting("buy.sellDisabled")) {
if (SellCommand.canUse(sender, buy)) {
messageBridge.messageNoPrefix(sender, "info-regionMoneyBackBuyClick", buy);
} else {
messageBridge.messageNoPrefix(sender, "info-regionMoneyBackBuy", buy);
}
}
// Friends
if (!buy.getFriendsFeature().getFriendNames().isEmpty()) {
String messagePart = "info-friend";
if (DelFriendCommand.canUse(sender, buy)) {
messagePart = "info-friendRemove";
}
messageBridge.messageNoPrefix(sender,
"info-regionFriends",
buy,
Utils.combinedMessage(buy.getFriendsFeature().getFriendNames(), messagePart));
}
} else {
messageBridge.messageNoPrefix(sender, "info-regionCanBeBought", buy);
}
if (buy.getLandlord() != null) {
messageBridge.messageNoPrefix(sender, "info-regionLandlord", buy);
}
if (buy.getInactiveTimeUntilSell() != -1) {
messageBridge.messageNoPrefix(sender, "info-regionInactiveSell", buy);
}
// Restoring
if (buy.isRestoreEnabled()) {
messageBridge.messageNoPrefix(sender, "info-regionRestoringBuy", buy);
}
// Restrictions
if (!buy.isSold()) {
if (buy.restrictedToRegion()) {
messageBridge.messageNoPrefix(sender, "info-regionRestrictedRegionBuy", buy);
} else if (buy.restrictedToWorld()) {
messageBridge.messageNoPrefix(sender, "info-regionRestrictedWorldBuy", buy);
}
}
messageBridge.messageNoPrefix(sender, "info-regionFooterBuy", buy);
}
private void handleRent(@Nonnull CommandSender sender, @Nonnull RentRegion rent) {
messageBridge.message(sender, "info-regionHeaderRent", rent);
if (rent.isRented()) {
messageBridge.messageNoPrefix(sender, "info-regionRented", rent);
messageBridge.messageNoPrefix(sender, "info-regionExtending", rent);
// Money back
if (UnrentCommand.canUse(sender, rent)) {
messageBridge.messageNoPrefix(sender, "info-regionMoneyBackRentClick", rent);
} else {
messageBridge.messageNoPrefix(sender, "info-regionMoneyBackRent", rent);
}
// Friends
if (!rent.getFriendsFeature().getFriendNames().isEmpty()) {
String messagePart = "info-friend";
if (DelFriendCommand.canUse(sender, rent)) {
messagePart = "info-friendRemove";
}
messageBridge.messageNoPrefix(sender,
"info-regionFriends",
rent,
Utils.combinedMessage(rent.getFriendsFeature().getFriendNames(), messagePart));
}
} else {
messageBridge.messageNoPrefix(sender, "info-regionCanBeRented", rent);
}
if (rent.getLandlordName() != null) {
messageBridge.messageNoPrefix(sender, "info-regionLandlord", rent);
}
// Maximum extends
if (rent.getMaxExtends() != -1) {
if (rent.getMaxExtends() == 0) {
messageBridge.messageNoPrefix(sender, "info-regionNoExtending", rent);
} else if (rent.isRented()) {
messageBridge.messageNoPrefix(sender, "info-regionExtendsLeft", rent);
} else {
messageBridge.messageNoPrefix(sender, "info-regionMaxExtends", rent);
}
}
// If maxExtends is zero it does not make sense to show this message
if (rent.getMaxRentTime() != -1 && rent.getMaxExtends() != 0) {
messageBridge.messageNoPrefix(sender, "info-regionMaxRentTime", rent);
}
if (rent.getInactiveTimeUntilUnrent() != -1) {
messageBridge.messageNoPrefix(sender, "info-regionInactiveUnrent", rent);
}
displayMiscInfo(sender, rent);
// Restoring
if (rent.isRestoreEnabled()) {
messageBridge.messageNoPrefix(sender, "info-regionRestoringRent", rent);
}
// Restrictions
if (!rent.isRented()) {
if (rent.restrictedToRegion()) {
messageBridge.messageNoPrefix(sender, "info-regionRestrictedRegionRent", rent);
} else if (rent.restrictedToWorld()) {
messageBridge.messageNoPrefix(sender, "info-regionRestrictedWorldRent", rent);
}
}
messageBridge.messageNoPrefix(sender, "info-regionFooterRent", rent);
}
private void displayMiscInfo(@Nonnull CommandSender sender, @Nonnull GeneralRegion region) {
displayTeleportInfo(sender, region);
displaySignInfo(sender, region);
displayGroupInfo(sender, region);
}
private void displayGroupInfo(@Nonnull CommandSender sender, @Nonnull GeneralRegion region) {// Groups
if (sender.hasPermission("areashop.groupinfo") && !region.getGroupNames().isEmpty()) {
messageBridge.messageNoPrefix(sender,
"info-regionGroups",
Utils.createCommaSeparatedList(region.getGroupNames()));
}
}
private void displaySignInfo(@Nonnull CommandSender sender, @Nonnull GeneralRegion region) {
// Signs
List<String> signLocations = new ArrayList<>();
for (BlockPosition location : region.getSignsFeature().signManager().allSignLocations()) {
signLocations.add(Message.fromKey("info-regionSignLocation")
.replacements(location.getWorld().getName(),
location.getX(),
location.getY(),
location.getZ())
.getPlain());
}
if (!signLocations.isEmpty()) {
messageBridge.messageNoPrefix(sender,
"info-regionSigns",
Utils.createCommaSeparatedList(signLocations));
}
}
private void displayTeleportInfo(@Nonnull CommandSender sender, @Nonnull GeneralRegion region) {
// Teleport
Message tp = Message.fromKey("info-prefix");
boolean foundSomething = false;
if (TeleportCommand.canUse(sender, region)) {
foundSomething = true;
tp.append(Message.fromKey("info-regionTeleport").replacements(region));
}
if (SetTeleportCommand.canUse(sender, region)) {
if (foundSomething) {
tp.append(", ");
}
foundSomething = true;
tp.append(Message.fromKey("info-setRegionTeleport").replacements(region));
}
if (foundSomething) {
tp.append(".");
SimpleMessageBridge.send(tp, sender);
}
}
}
@@ -0,0 +1,94 @@
package me.wiefferink.areashop.commands;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.SignProfileUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.managers.SignLinkerManager;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
@Singleton
public class LinkSignsCommand extends AreashopCommandBean {
private final SignLinkerManager signLinkerManager;
private final AreaShop plugin;
private final CommandFlag<String> profileFlag;
@Inject
public LinkSignsCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull SignLinkerManager signLinkerManager,
@Nonnull AreaShop plugin
) {
this.signLinkerManager = signLinkerManager;
this.plugin = plugin;
this.profileFlag = SignProfileUtil.createDefault(plugin);
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("linksign")
.senderType(PlayerCommandSource.class)
.flag(this.profileFlag)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("linksign");
}
@Override
public String getHelpKey(CommandSender target) {
if (target.hasPermission("areashop.linksigns")) {
return "help-linksigns";
}
return null;
}
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
Player player = context.sender().sender();
if (!player.hasPermission("linksigns")) {
throw new AreaShopCommandException("linksigns-noPermission");
}
if (signLinkerManager.isInSignLinkMode(player)) {
signLinkerManager.exitSignLinkMode(player);
return;
}
// Get the profile
String profile = SignProfileUtil.getOrParseProfile(context, this.plugin);
this.signLinkerManager.enterSignLinkMode(player, profile);
}
}
@@ -1,87 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.interactivemessenger.processing.Message;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class LinksignsCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop linksigns";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.linksigns")) {
return "help-linksigns";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.linksigns")) {
plugin.message(sender, "linksigns-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
if(plugin.getSignlinkerManager().isInSignLinkMode(player)) {
plugin.getSignlinkerManager().exitSignLinkMode(player);
} else {
// Get the profile
String profile = null;
if(args.length > 1) {
profile = args[1];
ConfigurationSection signProfilesSection = plugin.getConfig().getConfigurationSection("signProfiles");
if(signProfilesSection != null) {
Set<String> profiles = signProfilesSection.getKeys(false);
if(!profiles.contains(profile)) {
ArrayList<String> message = new ArrayList<>();
for(String p : profiles) {
if(!message.isEmpty()) {
message.add(", ");
}
message.addAll(Message.fromKey("addsign-profile").replacements(p).get());
}
plugin.message(sender, "addsign-wrongProfile", Message.fromList(message));
return;
}
}
}
plugin.getSignlinkerManager().enterSignLinkMode(player, profile);
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
result.addAll(plugin.getConfig().getStringList("signProfiles"));
}
return result;
}
}
@@ -1,119 +1,100 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.adapters.platform.OfflinePlayerHelper;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.OfflinePlayerParser;
import me.wiefferink.areashop.commands.util.RegionInfoUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.tools.BukkitSchedulerExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
public class MeCommand extends CommandAreaShop {
@Singleton
public class MeCommand extends AreashopCommandBean {
@Override
public String getCommandStart() {
return "areashop me";
}
private static final CloudKey<String> KEY_PLAYER = CloudKey.of("player", String.class);
private final IFileManager fileManager;
private final MessageBridge messageBridge;
private final OfflinePlayerHelper offlinePlayerHelper;
private final BukkitSchedulerExecutor executor;
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.me")) {
return "help-me";
}
return null;
}
@Inject
public MeCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager,
@Nonnull OfflinePlayerHelper offlinePlayerHelper,
@Nonnull BukkitSchedulerExecutor executor
) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
this.offlinePlayerHelper = offlinePlayerHelper;
this.executor = executor;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.me")) {
plugin.message(sender, "me-noPermission");
return;
}
OfflinePlayer player = null;
if(!(sender instanceof Player)) {
if(args.length <= 1) {
plugin.message(sender, "me-notAPlayer");
return;
}
} else {
player = (OfflinePlayer)sender;
}
if(args.length > 1) {
player = Bukkit.getOfflinePlayer(args[1]);
if(player == null) {
plugin.message(sender, "me-noPlayer", args[1]);
return;
}
}
if(player == null) {
return;
}
@Override
public String stringDescription() {
return null;
}
// Get the regions owned by the player
Set<RentRegion> rentRegions = new HashSet<>();
for(RentRegion region : plugin.getFileManager().getRents()) {
if(region.isOwner(player)) {
rentRegions.add(region);
}
}
Set<BuyRegion> buyRegions = new HashSet<>();
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(region.isOwner(player)) {
buyRegions.add(region);
}
}
// Get the regions the player is added as friend
Set<GeneralRegion> friendRegions = new HashSet<>();
for(GeneralRegion region : plugin.getFileManager().getRegions()) {
if(region.getFriendsFeature().getFriends().contains(player.getUniqueId())) {
friendRegions.add(region);
}
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("me")
.senderType(PlayerCommandSource.class)
.optional(KEY_PLAYER, OfflinePlayerParser.parser())
.handler(this::handleCommand);
}
// Send messages
boolean foundSome = !rentRegions.isEmpty() || !buyRegions.isEmpty() || !friendRegions.isEmpty();
if(foundSome) {
plugin.message(sender, "me-header", player.getName());
}
if(!rentRegions.isEmpty()) {
for(RentRegion region : rentRegions) {
plugin.messageNoPrefix(sender, "me-rentLine", region);
}
}
if(!buyRegions.isEmpty()) {
for(BuyRegion region : buyRegions) {
plugin.messageNoPrefix(sender, "me-buyLine", region);
}
}
if(!friendRegions.isEmpty()) {
for(GeneralRegion region : friendRegions) {
plugin.messageNoPrefix(sender, "me-friendLine", region);
}
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("me");
}
if(!foundSome) {
plugin.message(sender, "me-nothing", player.getName());
} else {
plugin.messageNoPrefix(sender, "me-clickHint");
}
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.me")) {
return "help-me";
}
return null;
}
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
Player sender = context.sender().sender();
if (!sender.hasPermission("areashop.me")) {
throw new AreaShopCommandException("me-noPermission");
}
if (!context.contains(KEY_PLAYER)) {
RegionInfoUtil.showRegionInfo(this.messageBridge, this.fileManager, sender, sender);
return;
}
this.offlinePlayerHelper.lookupOfflinePlayerAsync(context.get(KEY_PLAYER))
.whenCompleteAsync((offlinePlayer, exception) -> {
if (exception != null) {
sender.sendMessage("failed to lookup offline player!");
exception.printStackTrace();
return;
}
if (!offlinePlayer.hasPlayedBefore() && !offlinePlayer.isOnline()) {
this.messageBridge.message(sender, "cmd-invalidPlayer", offlinePlayer.getName());
return;
}
RegionInfoUtil.showRegionInfo(this.messageBridge, this.fileManager, sender, offlinePlayer);
}, this.executor);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
}
return result;
}
}
@@ -1,64 +1,62 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.tools.Utils;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.tools.SimpleMessageBridge;
import me.wiefferink.interactivemessenger.processing.Message;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.bukkit.parser.PlayerParser;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.standard.StringParser;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
public class MessageCommand extends CommandAreaShop {
@Singleton
public class MessageCommand extends AreashopCommandBean {
@Override
public String getCommandStart() {
return "areashop message";
}
private static final CloudKey<Player> KEY_PLAYER = CloudKey.of("player", Player.class);
private static final CloudKey<String> KEY_MESSAGE = CloudKey.of("message", String.class);
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.message")) {
return null; // Internal command, no need to show in the help list
}
public String getHelpKey(@NotNull CommandSender target) {
// Internal command, no need to show in the help list
return null;
}
@Override
public void execute(final CommandSender sender, final String[] args) {
if(!sender.hasPermission("areashop.message")) {
plugin.message(sender, "message-noPermission");
return;
}
if(args.length < 3) {
plugin.message(sender, "message-help");
return;
}
Player player = Bukkit.getPlayer(args[1]);
if(player == null) {
plugin.message(sender, "message-notOnline", args[1]);
return;
}
String[] messageArgs = new String[args.length - 2];
System.arraycopy(args, 2, messageArgs, 0, args.length - 2);
String message = StringUtils.join(messageArgs, " ");
Message.fromString(message).send(player);
public String stringDescription() {
return null;
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("message")
.required(KEY_PLAYER, PlayerParser.playerParser())
.required(KEY_MESSAGE, StringParser.greedyStringParser())
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("message");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if(!sender.hasPermission("areashop.message")) {
throw new AreaShopCommandException("message-noPermission");
}
return result;
Player player = context.get(KEY_PLAYER);
String message = context.get(KEY_MESSAGE);
Message m = Message.fromString(message);
SimpleMessageBridge.send(m, player);
}
}
@@ -0,0 +1,138 @@
package me.wiefferink.areashop.commands;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.adapters.platform.OfflinePlayerHelper;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.ArgumentParseExceptionHandler;
import me.wiefferink.areashop.commands.util.OfflinePlayerParser;
import me.wiefferink.areashop.commands.util.RegionCreationUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.RegionFactory;
import me.wiefferink.areashop.tools.BukkitSchedulerExecutor;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.exception.CommandExecutionException;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.standard.DoubleParser;
import org.incendo.cloud.parser.standard.StringParser;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@Singleton
public class QuickBuyCommand extends AreashopCommandBean {
private static final CloudKey<String> KEY_REGION = CloudKey.of("region", String.class);
private static final CloudKey<Double> KEY_PRICE = CloudKey.of("price", Double.class);
private static final CloudKey<String> KEY_LANDLORD = CloudKey.of("landlord", String.class);
private final RegionFactory regionFactory;
private final IFileManager fileManager;
private final MessageBridge messageBridge;
private final RegionCreationUtil regionCreationUtil;
private final BukkitSchedulerExecutor executor;
private final OfflinePlayerHelper offlinePlayerHelper;
@Inject
public QuickBuyCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull RegionFactory regionFactory,
@Nonnull IFileManager fileManager,
@Nonnull RegionCreationUtil regionCreationUtil,
@Nonnull BukkitSchedulerExecutor executor,
@Nonnull OfflinePlayerHelper offlinePlayerHelper
) {
this.messageBridge = messageBridge;
this.regionFactory = regionFactory;
this.fileManager = fileManager;
this.regionCreationUtil = regionCreationUtil;
this.executor = executor;
this.offlinePlayerHelper = offlinePlayerHelper;
}
@Override
public String stringDescription() {
return null;
}
@Nonnull
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("quickbuy")
.permission("permission")
.senderType(PlayerCommandSource.class)
.required(KEY_REGION, StringParser.stringParser())
.required(KEY_PRICE, DoubleParser.doubleParser(0))
.required(KEY_LANDLORD, OfflinePlayerParser.parser())
.handler(this::handleCommand);
}
// /as quickbuy <name> <price> <duration> <landlord>
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
Player player = context.sender().sender();
if (!player.hasPermission("areashop.quickbuy")) {
player.sendMessage("Insufficient permission");
return;
}
this.regionCreationUtil.createRegion(context, player, KEY_REGION)
.exceptionally(throwable -> {
if (throwable instanceof AreaShopCommandException exception) {
ArgumentParseExceptionHandler.handleException(this.messageBridge, context.sender(), exception);
} else {
throw new CommandExecutionException(throwable, context);
}
return null;
}).thenAcceptAsync(region -> {
// Error handled previously
if (region == null) {
this.messageBridge.message(player, "quickadd-failedCreateWGRegion");
return;
}
double price = context.get(KEY_PRICE);
this.offlinePlayerHelper.lookupOfflinePlayerAsync(context.get(KEY_LANDLORD))
.whenCompleteAsync((landlord, exception) -> {
if (exception != null) {
player.sendMessage("failed to lookup offline player!");
exception.printStackTrace();
return;
}
if (!landlord.isOnline() && !landlord.hasPlayedBefore()) {
this.messageBridge.message(player, "me-noPlayer", landlord.getName());
return;
}
String regionName = region.getId();
World world = player.getWorld();
BuyRegion buyRegion = this.regionFactory.createBuyRegion(regionName, world);
buyRegion.setPrice(price);
buyRegion.setLandlord(landlord.getUniqueId(), landlord.getName());
this.fileManager.addRegion(buyRegion);
this.messageBridge.message(player, "add-success", "buy", regionName);
}, this.executor);
}, this.executor);
}
@Nullable
@Override
public String getHelpKey(@Nonnull CommandSender target) {
if (target.hasPermission("areashop.quickbuy")) {
return "help-quickbuy";
}
return null;
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("quickbuy");
}
}
@@ -0,0 +1,93 @@
package me.wiefferink.areashop.commands;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.sk89q.worldguard.protection.managers.RegionManager;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.GeneralRegionParser;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.events.ask.DeletingRegionEvent;
import me.wiefferink.areashop.interfaces.WorldGuardInterface;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.description.Description;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@Singleton
public class QuickDeleteCommand extends AreashopCommandBean {
private static final CloudKey<GeneralRegion> KEY_REGION = CloudKey.of("region", GeneralRegion.class);
private static final CommandFlag<Void> FLAG_RETURN_MONEY = CommandFlag.builder("return-money")
.withDescription(Description.of(
"If this flag is present, money is returned to the player if someone is currently holding this region"))
.build();
private final IFileManager fileManager;
private final WorldGuardInterface worldGuardInterface;
private final MessageBridge messageBridge;
@Inject
public QuickDeleteCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager,
@Nonnull WorldGuardInterface worldGuardInterface
) {
this.fileManager = fileManager;
this.worldGuardInterface = worldGuardInterface;
this.messageBridge = messageBridge;
}
@Override
public String stringDescription() {
return null;
}
@Nonnull
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("quickdelete", "quickdel")
.permission("areashop.quickdelete")
.senderType(PlayerCommandSource.class)
.required(KEY_REGION, GeneralRegionParser.generalRegionParser(this.fileManager))
.handler(this::handleCommand);
}
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
Player player = context.sender().sender();
GeneralRegion region = context.get(KEY_REGION);
boolean giveMoneyBack = context.flags().isPresent(FLAG_RETURN_MONEY);
DeletingRegionEvent event = this.fileManager.deleteRegion(region, giveMoneyBack);
if (event.isCancelled()) {
throw new AreaShopCommandException("general-cancelled", event.getReason());
}
this.messageBridge.message(player, "destroy-successRent", region);
RegionManager regionManager = this.worldGuardInterface.getRegionManager(region.getWorld());
regionManager.removeRegion(region.getRegion().getId());
this.messageBridge.message(player, "quickdelete-WGRegionDeleted", region.getName());
}
@Nullable
@Override
public String getHelpKey(@Nonnull CommandSender target) {
return "help-quickdelete";
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("quickdelete", "quickdel");
}
}
@@ -0,0 +1,146 @@
package me.wiefferink.areashop.commands;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.adapters.platform.OfflinePlayerHelper;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.ArgumentParseExceptionHandler;
import me.wiefferink.areashop.commands.util.DurationInputParser;
import me.wiefferink.areashop.commands.util.OfflinePlayerParser;
import me.wiefferink.areashop.commands.util.RegionCreationUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.RegionFactory;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.BukkitSchedulerExecutor;
import me.wiefferink.areashop.tools.DurationInput;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.exception.CommandExecutionException;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.standard.DoubleParser;
import org.incendo.cloud.parser.standard.StringParser;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@Singleton
public class QuickRentCommand extends AreashopCommandBean {
private static final CloudKey<String> KEY_REGION = CloudKey.of("region", String.class);
private static final CloudKey<Double> KEY_PRICE = CloudKey.of("price", Double.class);
private static final CloudKey<DurationInput> KEY_DURATION = CloudKey.of("duration", DurationInput.class);
private static final CloudKey<String> KEY_LANDLORD = CloudKey.of("landlord", String.class);
private final RegionFactory regionFactory;
private final IFileManager fileManager;
private final MessageBridge messageBridge;
private final RegionCreationUtil regionCreationUtil;
private final BukkitSchedulerExecutor executor;
private final OfflinePlayerHelper offlinePlayerHelper;
@Inject
public QuickRentCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull RegionFactory regionFactory,
@Nonnull IFileManager fileManager,
@Nonnull RegionCreationUtil regionCreationUtil,
@Nonnull BukkitSchedulerExecutor executor,
@Nonnull OfflinePlayerHelper offlinePlayerHelper
) {
this.messageBridge = messageBridge;
this.regionFactory = regionFactory;
this.fileManager = fileManager;
this.regionCreationUtil = regionCreationUtil;
this.executor = executor;
this.offlinePlayerHelper = offlinePlayerHelper;
}
@Override
public String stringDescription() {
return null;
}
@Nonnull
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("quickrent")
.permission("permission")
.senderType(PlayerCommandSource.class)
.required(KEY_REGION, StringParser.stringParser())
.required(KEY_PRICE, DoubleParser.doubleParser(0))
.required(KEY_DURATION, DurationInputParser.durationInputParser())
.required(KEY_LANDLORD, OfflinePlayerParser.parser())
.handler(this::handleCommand);
}
// /as quickrent <name> <price> <duration> <landlord>
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
Player player = context.sender().sender();
if (!player.hasPermission("areashop.quickrent")) {
player.sendMessage("Insufficient permission");
return;
}
this.regionCreationUtil.createRegion(context, player, KEY_REGION)
.exceptionally(throwable -> {
if (throwable instanceof AreaShopCommandException exception) {
ArgumentParseExceptionHandler.handleException(this.messageBridge, context.sender(), exception);
} else {
throw new CommandExecutionException(throwable, context);
}
return null;
}).thenAcceptAsync(region -> {
// Error handled previously
if (region == null) {
this.messageBridge.message(player, "quickadd-failedCreateWGRegion");
return;
}
double price = context.get(KEY_PRICE);
DurationInput duration = context.get(KEY_DURATION);
this.offlinePlayerHelper.lookupOfflinePlayerAsync(context.get(KEY_LANDLORD))
.whenCompleteAsync((landlord, exception) -> {
if (exception != null) {
player.sendMessage("failed to lookup offline player!");
exception.printStackTrace();
return;
}
if (!landlord.hasPlayedBefore() && !landlord.isOnline()) {
this.messageBridge.message(player, "cmd-invalidPlayer", landlord.getName());
return;
}
String regionName = region.getId();
World world = player.getWorld();
RentRegion rentRegion = this.regionFactory.createRentRegion(regionName, world);
rentRegion.setPrice(price);
rentRegion.setLandlord(landlord.getUniqueId(), landlord.getName());
rentRegion.setDuration(duration.toTinySpacedString());
this.fileManager.addRegion(rentRegion);
this.messageBridge.message(player, "add-success", "rent", regionName);
}, this.executor);
}, this.executor);
}
@Nullable
@Override
public String getHelpKey(@Nonnull CommandSender target) {
if (target.hasPermission("areashop.quickrent")) {
return "help-quickrent";
}
return null;
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("quickrent");
}
}
@@ -1,7 +1,8 @@
# Commands
This module contains all AreaShop commands.
AreaShop uses https://cloud.incendo.org/
* `CommandAreaShop` is extended by all other classes, and implements some general functionality and defines which methods should be implemented.
* `util/AreashopCommandBean` is extended by all other classes, and implements some general functionality and defines which methods should be implemented.
* Other classes implement specific sub-commands, supply their help messages and tab completion.
* `CommandManager` class in the `managers` package handles incoming commands and dispatches them to the classes in this package.
* `util/AreashopCommands` class in handles all command registration
@@ -1,29 +1,59 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
public class ReloadCommand extends CommandAreaShop {
import javax.annotation.Nonnull;
@Override
public String getCommandStart() {
return "areashop reload";
}
@Singleton
public class ReloadCommand extends AreashopCommandBean {
private final AreaShop plugin;
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.reload")) {
return "help-reload";
}
return null;
}
@Inject
public ReloadCommand(@Nonnull AreaShop plugin) {
this.plugin = plugin;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(sender.hasPermission("areashop.reload")) {
// Reload the configuration files and update all region flags/signs
plugin.reload(sender);
} else {
plugin.message(sender, "reload-noPermission");
}
}
@Override
public String stringDescription() {
return null;
}
@Nonnull
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("reload")
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("reload");
}
@Override
public String getHelpKey(CommandSender target) {
if (target.hasPermission("areashop.reload")) {
return "help-reload";
}
return null;
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
if (!context.hasPermission("areashop.reload")) {
throw new AreaShopCommandException("reload-noPermission");
}
this.plugin.reload(context.sender().sender());
}
}
@@ -1,69 +1,69 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
public class RentCommand extends CommandAreaShop {
@Singleton
public class RentCommand extends AreashopCommandBean {
@Override
public String getCommandStart() {
return "areashop rent";
}
private final CommandFlag<RentRegion> rentRegionFlag;
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.rent")) {
return "help-rent";
}
return null;
}
@Inject
public RentCommand(@Nonnull IFileManager fileManager) {
this.rentRegionFlag = RegionParseUtil.createDefaultRent(fileManager);
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.rent")) {
plugin.message(sender, "rent-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
if(args.length > 1 && args[1] != null) {
RentRegion rent = plugin.getFileManager().getRent(args[1]);
if(rent == null) {
plugin.message(sender, "rent-notRentable", args[1]);
} else {
rent.rent(player);
}
} else {
// get the region by location
List<RentRegion> regions = Utils.getImportantRentRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
} else {
regions.get(0).rent(player);
}
}
}
@Override
public String stringDescription() {
return "Allows you to rent a region";
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if(target.hasPermission("areashop.rent")) {
return "help-rent";
}
return null;
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("rent");
}
@Override
protected @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder
.literal("rent")
.flag(this.rentRegionFlag)
.senderType(PlayerCommandSource.class)
.handler(this::handleCommand);
}
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
if (!context.hasPermission("areashop.rent")) {
throw new AreaShopCommandException("rent-noPermission");
}
Player sender = context.sender().sender();
RentRegion region = RegionParseUtil.getOrParseRentRegion(context, sender, this.rentRegionFlag);
region.rent(sender);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(RentRegion region : plugin.getFileManager().getRents()) {
if(!region.isRented()) {
result.add(region.getName());
}
}
}
return result;
}
}
@@ -1,120 +1,130 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.BuyRegionParser;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.parser.standard.DoubleParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public class ResellCommand extends CommandAreaShop {
@Singleton
public class ResellCommand extends AreashopCommandBean {
@Override
public String getCommandStart() {
return "areashop resell";
}
private static final CloudKey<Double> KEY_PRICE = CloudKey.of("price", Double.class);
private final CommandFlag<BuyRegion> regionFlag;
private final MessageBridge messageBridge;
private final IFileManager fileManager;
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.resellall") || target.hasPermission("areashop.resell")) {
return "help-resell";
}
return null;
}
@Inject
public ResellCommand(@Nonnull MessageBridge messageBridge, @Nonnull IFileManager fileManager) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
ParserDescriptor<CommandSource<?>, BuyRegion> regionParser = ParserDescriptor.of(
new BuyRegionParser<>(fileManager, this::suggestBuyRegions),
BuyRegion.class
);
this.regionFlag = CommandFlag.<CommandSource<?>>builder("region").withComponent(regionParser).build();
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.resell") && !sender.hasPermission("areashop.resellall")) {
plugin.message(sender, "resell-noPermissionOther");
return;
}
@Override
public String stringDescription() {
return null;
}
if(args.length <= 1) {
plugin.message(sender, "resell-help");
return;
}
double price;
try {
price = Double.parseDouble(args[1]);
} catch(NumberFormatException e) {
plugin.message(sender, "resell-wrongPrice", args[1]);
return;
}
@Override
@Nonnull
protected Command.Builder<? extends CommandSource<?>> configureCommand(@Nonnull Command.Builder<CommandSource<?>> builder) {
return builder.literal("resell")
.required(KEY_PRICE, DoubleParser.doubleParser(0))
.flag(this.regionFlag)
.handler(this::handleCommand);
}
if(price < 0) {
plugin.message(sender, "resell-wrongPrice", args[1]);
return;
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("resell");
}
BuyRegion buy;
if(args.length <= 2) {
if(sender instanceof Player) {
// get the region by location
List<BuyRegion> regions = Utils.getImportantBuyRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
buy = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
buy = plugin.getFileManager().getBuy(args[2]);
if(buy == null) {
plugin.message(sender, "resell-notRegistered", args[2]);
return;
}
}
if(buy == null) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
}
if(!buy.isSold()) {
plugin.message(sender, "resell-notBought", buy);
return;
}
if(sender.hasPermission("areashop.resellall")) {
buy.enableReselling(price);
buy.update();
plugin.message(sender, "resell-success", buy);
} else if(sender.hasPermission("areashop.resell") && sender instanceof Player) {
if(!buy.isOwner((Player)sender)) {
plugin.message(sender, "resell-noPermissionOther", buy);
return;
}
if(buy.getBooleanSetting("buy.resellDisabled")) {
plugin.message(sender, "resell-disabled", buy);
return;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.resellall") || target.hasPermission("areashop.resell")) {
return "help-resell";
}
return null;
}
buy.enableReselling(price);
buy.update();
plugin.message(sender, "resell-success", buy);
} else {
plugin.message(sender, "resell-noPermission", buy);
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 3) {
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(region.isSold() && !region.isInResellingMode()) {
result.add(region.getName());
}
}
}
return result;
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.resell") && !sender.hasPermission("areashop.resellall")) {
messageBridge.message(sender, "resell-noPermissionOther");
return;
}
double price = context.get(KEY_PRICE);
BuyRegion buy = RegionParseUtil.getOrParseBuyRegion(context, sender, this.regionFlag);
if (!buy.isSold()) {
messageBridge.message(sender, "resell-notBought", buy);
return;
}
if (sender.hasPermission("areashop.resellall")) {
buy.enableReselling(price);
buy.update();
messageBridge.message(sender, "resell-success", buy);
} else if (sender.hasPermission("areashop.resell") && sender instanceof Player player) {
if (!buy.isOwner(player)) {
messageBridge.message(sender, "resell-noPermissionOther", buy);
return;
}
if (buy.getBooleanSetting("buy.resellDisabled")) {
messageBridge.message(sender, "resell-disabled", buy);
return;
}
buy.enableReselling(price);
buy.update();
messageBridge.message(sender, "resell-success", buy);
} else {
messageBridge.message(sender, "resell-noPermission", buy);
}
}
private CompletableFuture<Iterable<Suggestion>> suggestBuyRegions(
@Nonnull CommandContext<CommandSource<?>> context,
@Nonnull CommandInput input
) {
String text = input.peekString();
List<Suggestion> suggestions = this.fileManager.getBuysRef().stream()
.filter(region -> region.isSold() && !region.isInResellingMode())
.map(GeneralRegion::getName)
.filter(name -> name.startsWith(text))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestions);
}
}
@@ -0,0 +1,80 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.GeneralRegionParser;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.standard.EnumParser;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
@Singleton
public class SchematicEventCommand extends AreashopCommandBean {
private static final CloudKey<GeneralRegion> KEY_REGION = CloudKey.of("region", GeneralRegion.class);
private static final CloudKey<GeneralRegion.RegionEvent> KEY_EVENT_TYPE = CloudKey.of("eventType",
GeneralRegion.RegionEvent.class);
private final MessageBridge messageBridge;
private final IFileManager fileManager;
@Inject
public SchematicEventCommand(@Nonnull MessageBridge messageBridge, @Nonnull IFileManager fileManager) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("schemevent")
.required(KEY_REGION, GeneralRegionParser.generalRegionParser(this.fileManager))
.required(KEY_EVENT_TYPE, EnumParser.enumParser(GeneralRegion.RegionEvent.class))
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("schemevent");
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.schematicevents")) {
return "help-schemevent";
}
return null;
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.schematicevents")) {
throw new AreaShopCommandException("schemevent-noPermission");
}
GeneralRegion region = context.get(KEY_REGION);
GeneralRegion.RegionEvent event = context.get(KEY_EVENT_TYPE);
if (region.getRegion() == null) {
throw new AreaShopCommandException("general-noRegion", region);
}
region.handleSchematicEvent(event);
region.update();
this.messageBridge.message(sender, "schemevent-success", event.getValue(), region);
}
}
@@ -1,86 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SchematiceventCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop schemevent";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.schematicevents")) {
return "help-schemevent";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.schematicevents")) {
plugin.message(sender, "schemevent-noPermission");
return;
}
if(args.length < 3 || args[1] == null || args[2] == null) {
plugin.message(sender, "schemevent-help");
return;
}
GeneralRegion region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[1]);
return;
}
if(region.getRegion() == null) {
plugin.message(sender, "general-noRegion", region);
return;
}
GeneralRegion.RegionEvent event = null;
boolean exception = false;
try {
event = GeneralRegion.RegionEvent.valueOf(args[2].toUpperCase());
} catch(IllegalArgumentException e) {
exception = true;
}
// Check for a totally wrong event or a non matching event
if(exception) {
ArrayList<String> values = new ArrayList<>();
for(GeneralRegion.RegionEvent value : GeneralRegion.RegionEvent.values()) {
values.add(value.getValue().toLowerCase());
}
plugin.message(sender, "schemevent-wrongEvent", args[2], Utils.createCommaSeparatedList(values), region);
return;
}
region.handleSchematicEvent(event);
region.update();
plugin.message(sender, "schemevent-success", args[2], region);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
GeneralRegion region = plugin.getFileManager().getRegion(start[2]);
if(region != null) {
if(region instanceof RentRegion) {
result.addAll(Arrays.asList("created", "deleted", "rented", "unrented"));
} else if(region instanceof BuyRegion) {
result.addAll(Arrays.asList("created", "deleted", "bought", "sold"));
}
}
}
return result;
}
}
@@ -1,96 +1,116 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.BuyRegionParser;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.suggestion.Suggestion;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public class SellCommand extends CommandAreaShop {
@Singleton
public class SellCommand extends AreashopCommandBean {
@Override
public String getCommandStart() {
return "areashop sell";
}
private final MessageBridge messageBridge;
private final IFileManager fileManager;
private final CommandFlag<BuyRegion> buyRegionFlag;
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.sell") || target.hasPermission("areashop.sellown")) {
return "help-sell";
}
return null;
}
@Inject
public SellCommand(@Nonnull MessageBridge messageBridge, @Nonnull IFileManager fileManager) {
ParserDescriptor<CommandSource<?>, BuyRegion> regionParser =
ParserDescriptor.of(new BuyRegionParser<>(fileManager, this::suggestBuyRegions), BuyRegion.class);
this.messageBridge = messageBridge;
this.fileManager = fileManager;
this.buyRegionFlag = CommandFlag.<CommandSource<?>>builder("region").withComponent(regionParser).build();
}
/**
* Check if a person can sell the region.
* @param person The person to check
* @param region The region to check for
* @return true if the person can sell it, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if(person.hasPermission("areashop.sell")) {
return true;
}
if(person instanceof Player) {
Player player = (Player)person;
return region.isOwner(player) && person.hasPermission("areashop.sellown");
}
return false;
}
/**
* Check if a person can sell the region.
*
* @param person The person to check
* @param region The region to check for
* @return true if the person can sell it, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if (person.hasPermission("areashop.sell")) {
return true;
}
if (person instanceof Player player) {
return region.isOwner(player) && person.hasPermission("areashop.sellown");
}
return false;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.sell") && !sender.hasPermission("areashop.sellown")) {
plugin.message(sender, "sell-noPermission");
return;
}
BuyRegion buy;
if(args.length <= 1) {
if(sender instanceof Player) {
// get the region by location
List<BuyRegion> regions = Utils.getImportantBuyRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
buy = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
buy = plugin.getFileManager().getBuy(args[1]);
}
if(buy == null) {
plugin.message(sender, "sell-notRegistered");
return;
}
if(!buy.isSold()) {
plugin.message(sender, "sell-notBought", buy);
return;
}
buy.sell(true, sender);
}
@Override
public String stringDescription() {
return null;
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(region.isSold()) {
result.add(region.getName());
}
}
}
return result;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("sell")
.flag(this.buyRegionFlag)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("sell");
}
@Override
public String getHelpKey(CommandSender target) {
if (target.hasPermission("areashop.sell") || target.hasPermission("areashop.sellown")) {
return "help-sell";
}
return null;
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.sell") && !sender.hasPermission("areashop.sellown")) {
this.messageBridge.message(sender, "sell-noPermission");
return;
}
BuyRegion buy = RegionParseUtil.getOrParseBuyRegion(context, sender, this.buyRegionFlag);
if (!buy.isSold()) {
messageBridge.message(sender, "sell-notBought", buy);
return;
}
buy.sell(true, sender);
}
private CompletableFuture<Iterable<Suggestion>> suggestBuyRegions(
@Nonnull CommandContext<CommandSource<?>> context,
@Nonnull CommandInput input
) {
String text = input.peekString();
List<Suggestion> suggestions = this.fileManager.getBuysRef().stream()
.filter(BuyRegion::isSold)
.map(GeneralRegion::getName)
.filter(name -> name.startsWith(text))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestions);
}
}
@@ -0,0 +1,129 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.DurationInput;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.parser.standard.StringParser;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.concurrent.TimeUnit;
@Singleton
public class SetDurationCommand extends AreashopCommandBean {
private static final CloudKey<String> KEY_DURATION = CloudKey.of("duration", String.class);
private final MessageBridge messageBridge;
private final CommandFlag<RentRegion> regionFlag;
@Inject
public SetDurationCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.regionFlag = RegionParseUtil.createDefaultRent(fileManager);
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.setduration")) {
return "help-setduration";
}
return null;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("setduration")
.required(KEY_DURATION, StringParser.stringParser())
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("setduration");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.setduration") && (!sender.hasPermission("areashop.setduration.landlord") && sender instanceof Player)) {
this.messageBridge.message(sender, "setduration-noPermission");
return;
}
RentRegion rent = RegionParseUtil.getOrParseRentRegion(context, sender, this.regionFlag);
if (!sender.hasPermission("areashop.setduration")
&& !(sender instanceof Player player
&& rent.isLandlord(player.getUniqueId()))
) {
this.messageBridge.message(sender, "setduration-noLandlord", rent);
return;
}
String rawDuration = context.get(KEY_DURATION);
if ("default".equalsIgnoreCase(rawDuration) || "reset".equalsIgnoreCase(rawDuration)) {
rent.setDuration(null);
rent.update();
this.messageBridge.message(sender, "setduration-successRemoved", rent);
return;
}
DurationInput duration = parseInternalDuration(rawDuration);
sender.sendMessage(duration.toTinySpacedString());
rent.setDuration(duration.toTinySpacedString());
rent.update();
this.messageBridge.message(sender, "setduration-success", rent);
}
private DurationInput parseInternalDuration(String rawDuration) {
int start = 0;
for (int i = 0; i < rawDuration.length(); i++) {
if (Character.isAlphabetic(rawDuration.charAt(i))) {
start = i;
break;
}
}
if (start == 0) {
throw new AreaShopCommandException("setduration-wrongFormat", rawDuration);
}
String duration = rawDuration.substring(0, start);
String durationUnit = rawDuration.substring(start);
int durationInt;
try {
durationInt = Integer.parseInt(duration);
} catch (NumberFormatException ex) {
throw new AreaShopCommandException("setduration-wrongAmount", duration);
}
TimeUnit timeUnit = DurationInput.getTimeUnit(durationUnit)
.orElseThrow(() -> new AreaShopCommandException("setduration-wrongFormat", durationUnit));
boolean invalid = !switch (timeUnit) {
case DAYS, HOURS, MINUTES, SECONDS -> true;
default -> false;
};
if (invalid) {
throw new AreaShopCommandException("setduration-wrongFormat", durationUnit);
}
return new DurationInput(durationInt, timeUnit);
}
}
@@ -0,0 +1,100 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.adapters.platform.OfflinePlayerHelper;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.OfflinePlayerParser;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.tools.BukkitSchedulerExecutor;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
@Singleton
public class SetLandlordCommand extends AreashopCommandBean {
private static final CloudKey<String> KEY_PLAYER = CloudKey.of("player", String.class);
private final MessageBridge messageBridge;
private final CommandFlag<GeneralRegion> regionFlag;
private final OfflinePlayerHelper offlinePlayerHelper;
private final BukkitSchedulerExecutor executor;
@Inject
public SetLandlordCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager,
@Nonnull OfflinePlayerHelper offlinePlayerHelper,
@Nonnull BukkitSchedulerExecutor executor
) {
this.messageBridge = messageBridge;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
this.offlinePlayerHelper = offlinePlayerHelper;
this.executor = executor;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.setlandlord")) {
return "help-setlandlord";
}
return null;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("setlandlord")
.required(KEY_PLAYER, OfflinePlayerParser.parser())
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("setlandlord");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.setlandlord")) {
throw new AreaShopCommandException("setlandlord-noPermission");
}
GeneralRegion region = RegionParseUtil.getOrParseRegion(context, sender, this.regionFlag);
this.offlinePlayerHelper.lookupOfflinePlayerAsync(context.get(KEY_PLAYER))
.whenCompleteAsync((landlord, exception) -> {
if (exception != null) {
sender.sendMessage("failed to lookup offline player!");
exception.printStackTrace();
return;
}
if (!landlord.hasPlayedBefore() && !landlord.isOnline()) {
this.messageBridge.message(sender, "cmd-invalidPlayer", landlord.getName());
return;
}
String playerName = landlord.getName();
region.setLandlord(landlord.getUniqueId(), playerName);
region.update();
this.messageBridge.message(sender, "setlandlord-success", playerName, region);
}, this.executor);
}
}
@@ -0,0 +1,88 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.RentRegion;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.parser.standard.IntegerParser;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
@Singleton
public class SetMaxExtends extends AreashopCommandBean {
private static final CloudKey<Integer> KEY_EXTENDS = CloudKey.of("extends", Integer.class);
private final MessageBridge messageBridge;
private final CommandFlag<RentRegion> regionFlag;
@Inject
public SetMaxExtends(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.regionFlag = RegionParseUtil.createDefaultRent(fileManager);
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.setmaxextends")) {
return "help-setmaxextends";
}
return null;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("setmaxextends")
.required(KEY_EXTENDS, IntegerParser.integerParser(0))
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("setmaxextends");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.setmaxextends") && (!sender.hasPermission("areashop.setmaxextends.landlord") && sender instanceof Player)) {
this.messageBridge.message(sender, "setmaxextends-noPermission");
return;
}
RentRegion rent = RegionParseUtil.getOrParseRentRegion(context, sender, this.regionFlag);
if (!sender.hasPermission("areashop.setmaxextends")
&& !(sender instanceof Player player
&& rent.isLandlord(player.getUniqueId()))
) {
this.messageBridge.message(sender, "setmaxextends-noLandlord", rent);
return;
}
int extend = context.get(KEY_EXTENDS);
sender.sendMessage();
rent.setMaxExtends(extend);
rent.update();
this.messageBridge.message(sender, "setmaxextends-success", rent);
}
}
@@ -0,0 +1,142 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.adapters.platform.OfflinePlayerHelper;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.OfflinePlayerParser;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.BukkitSchedulerExecutor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.Calendar;
import java.util.UUID;
@Singleton
public class SetOwnerCommand extends AreashopCommandBean {
private static final CloudKey<String> KEY_PLAYER = CloudKey.of("player", String.class);
private final CommandFlag<GeneralRegion> regionFlag;
private final MessageBridge messageBridge;
private final OfflinePlayerHelper offlinePlayerHelper;
private final BukkitSchedulerExecutor executor;
@Inject
public SetOwnerCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager,
@Nonnull OfflinePlayerHelper offlinePlayerHelper,
@Nonnull BukkitSchedulerExecutor executor
) {
this.messageBridge = messageBridge;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
this.offlinePlayerHelper = offlinePlayerHelper;
this.executor = executor;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.setownerrent") || target.hasPermission("areashop.setownerbuy")) {
return "help-setowner";
}
return null;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("setowner")
.required(KEY_PLAYER, OfflinePlayerParser.parser())
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("setowner");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.setownerrent") && !sender.hasPermission("areashop.setownerbuy")) {
this.messageBridge.message(sender, "setowner-noPermission");
return;
}
GeneralRegion region = RegionParseUtil.getOrParseRegion(context, sender, this.regionFlag);
if (region instanceof RentRegion && !sender.hasPermission("areashop.setownerrent")) {
this.messageBridge.message(sender, "setowner-noPermissionRent", region);
return;
}
if (region instanceof BuyRegion && !sender.hasPermission("areashop.setownerbuy")) {
this.messageBridge.message(sender, "setowner-noPermissionBuy", region);
return;
}
this.offlinePlayerHelper.lookupOfflinePlayerAsync(context.get(KEY_PLAYER))
.whenCompleteAsync((offlinePlayer, exception) -> {
if (exception != null) {
sender.sendMessage("failed to lookup offline player!");
exception.printStackTrace();
return;
}
if (!offlinePlayer.hasPlayedBefore() && !offlinePlayer.isOnline()) {
this.messageBridge.message(sender, "cmd-invalidPlayer", offlinePlayer.getName());
return;
}
setOwner(sender, offlinePlayer, region);
}, this.executor);
}
private void setOwner(@Nonnull CommandSender sender, @Nonnull OfflinePlayer player, GeneralRegion region) {
final UUID uuid = player.getUniqueId();
if (region instanceof RentRegion rent) {
if (rent.isRenter(uuid)) {
// extend
rent.setRentedUntil(rent.getRentedUntil() + rent.getDuration());
rent.setRenter(uuid);
this.messageBridge.message(sender, "setowner-succesRentExtend", region);
} else {
// change
if (!rent.isRented()) {
rent.setRentedUntil(Calendar.getInstance().getTimeInMillis() + rent.getDuration());
}
rent.setRenter(uuid);
this.messageBridge.message(sender, "setowner-succesRent", region);
}
} else if (region instanceof BuyRegion buy) {
buy.setBuyer(uuid);
this.messageBridge.message(sender, "setowner-succesBuy", region);
}
region.getFriendsFeature().deleteFriend(region.getOwner(), null);
region.update();
region.saveRequired();
}
}
@@ -0,0 +1,106 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.parser.standard.StringParser;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
@Singleton
public class SetPriceCommand extends AreashopCommandBean {
private static final CloudKey<String> KEY_PRICE = CloudKey.of("price", String.class);
private final CommandFlag<GeneralRegion> regionFlag;
private final MessageBridge messageBridge;
@Inject
public SetPriceCommand(@Nonnull MessageBridge messageBridge, @Nonnull IFileManager fileManager) {
this.messageBridge = messageBridge;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
}
@Override
public String getHelpKey(CommandSender target) {
if (target.hasPermission("areashop.setprice")) {
return "help-setprice";
}
return null;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("setprice")
.required(KEY_PRICE, StringParser.stringParser())
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("setprice");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.setprice") && (!sender.hasPermission("areashop.setprice.landlord") && sender instanceof Player)) {
this.messageBridge.message(sender, "setprice-noPermission");
return;
}
GeneralRegion region = RegionParseUtil.getOrParseRegion(context, sender, this.regionFlag);
if (!sender.hasPermission("areashop.setprice")
&& !(sender instanceof Player player && region.isLandlord(player.getUniqueId()))) {
this.messageBridge.message(sender, "setprice-noLandlord", region);
return;
}
String rawPrice = context.get(KEY_PRICE);
if ("default".equalsIgnoreCase(rawPrice) || "reset".equalsIgnoreCase(rawPrice)) {
if (region instanceof RentRegion rentRegion) {
rentRegion.setPrice(null);
} else if (region instanceof BuyRegion buyRegion) {
buyRegion.setPrice(null);
}
region.update();
this.messageBridge.message(sender, "setprice-successRemoved", region);
return;
}
double price;
try {
price = Double.parseDouble(rawPrice);
} catch (NumberFormatException e) {
this.messageBridge.message(sender, "setprice-wrongPrice", rawPrice, region);
return;
}
if (region instanceof RentRegion rentRegion) {
rentRegion.setPrice(price);
this.messageBridge.message(sender, "setprice-successRent", region);
} else if (region instanceof BuyRegion buyRegion) {
buyRegion.setPrice(price);
this.messageBridge.message(sender, "setprice-successBuy", region);
}
region.update();
}
}
@@ -0,0 +1,130 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.GeneralRegionParser;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.standard.StringParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@Singleton
public class SetRestoreCommand extends AreashopCommandBean {
private static final List<String> RESTORE_TYPES = List.of("true", "false", "general");
private static final CloudKey<GeneralRegion> KEY_REGION = CloudKey.of("region", GeneralRegion.class);
private static final CloudKey<String> KEY_RESTORE = CloudKey.of("restore", String.class);
private static final CloudKey<String> KEY_PROFILE = CloudKey.of("profile", String.class);
private final MessageBridge messageBridge;
private final IFileManager fileManager;
@Inject
public SetRestoreCommand(@Nonnull MessageBridge messageBridge, @Nonnull IFileManager fileManager) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.setrestore")) {
return "help-setrestore";
}
return null;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("setrestore")
.required(KEY_REGION, GeneralRegionParser.generalRegionParser(this.fileManager))
.required(KEY_RESTORE, StringParser.stringParser(), this::suggestRestoreType)
.optional(KEY_PROFILE, StringParser.stringParser(), this::suggestSchematicProfiles)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("setrestore");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.setrestore")) {
throw new AreaShopCommandException("setrestore-noPermission");
}
GeneralRegion region = context.get(KEY_REGION);
String restoreType = context.get(KEY_RESTORE);
Optional<String> optionalProfile = context.optional(KEY_PROFILE);
Boolean value = null;
if (restoreType.equalsIgnoreCase("true")) {
value = true;
} else if (restoreType.equalsIgnoreCase("false")) {
value = false;
}
region.setRestoreSetting(value);
String valueString = "general";
if (value != null) {
valueString = value + "";
}
if (optionalProfile.isPresent()) {
String profile = optionalProfile.get();
region.setSchematicProfile(profile);
this.messageBridge.message(sender, "setrestore-successProfile", valueString, profile, region);
} else {
this.messageBridge.message(sender, "setrestore-success", valueString, region);
}
region.update();
}
private CompletableFuture<Iterable<Suggestion>> suggestRestoreType(
@Nonnull CommandContext<CommandSource<?>> context,
@Nonnull CommandInput input
) {
String text = input.peekString();
List<Suggestion> suggestions = RESTORE_TYPES.stream()
.filter(type -> type.startsWith(text))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestions);
}
private CompletableFuture<Iterable<Suggestion>> suggestSchematicProfiles(
@Nonnull CommandContext<CommandSource<?>> context,
@Nonnull CommandInput input
) {
ConfigurationSection schemProfiles = fileManager.getConfig().getConfigurationSection("schematicProfiles");
if (schemProfiles == null) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
String text = input.peekString();
List<Suggestion> suggestions = schemProfiles.getKeys(false).stream()
.filter(profile -> profile.startsWith(text))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestions);
}
}
@@ -0,0 +1,126 @@
package me.wiefferink.areashop.commands;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
@Singleton
public class SetTeleportCommand extends AreashopCommandBean {
private static final CommandFlag<Void> FLAG_RESET = CommandFlag.builder("reset").build();
private final CommandFlag<GeneralRegion> regionFlag;
private final MessageBridge messageBridge;
@Inject
public SetTeleportCommand(@Nonnull MessageBridge messageBridge, @Nonnull IFileManager fileManager) {
this.messageBridge = messageBridge;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
}
/**
* Check if a person can set the teleport location of the region.
*
* @param person The person to check
* @param region The region to check for
* @return true if the person can set the teleport location, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if (!(person instanceof Player player)) {
return false;
}
return player.hasPermission("areashop.setteleportall")
|| region.isOwner(player) && player.hasPermission("areashop.setteleport");
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.setteleportall") || target.hasPermission("areashop.setteleport")) {
return "help-setteleport";
}
return null;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("settp")
.senderType(PlayerCommandSource.class)
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("settp");
}
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
Player player = context.sender().sender();
if (!player.hasPermission("areashop.setteleport") && !player.hasPermission("areashop.setteleportall")) {
this.messageBridge.message(player, "setteleport-noPermission");
return;
}
GeneralRegion region = RegionParseUtil.getOrParseRegion(context, player, this.regionFlag);
boolean owner;
if (region instanceof RentRegion rentRegion) {
owner = player.getUniqueId().equals(rentRegion.getRenter());
} else if (region instanceof BuyRegion buyRegion) {
owner = player.getUniqueId().equals(buyRegion.getBuyer());
} else {
// FIXME log error
return;
}
if (!player.hasPermission("areashop.setteleport")) {
throw new AreaShopCommandException("setteleport-noPermission", region);
} else if (!owner && !player.hasPermission("areashop.setteleportall")) {
throw new AreaShopCommandException("setteleport-noPermissionOther", region);
}
boolean reset = context.flags().contains(FLAG_RESET);
if (reset) {
region.getTeleportFeature().setTeleport(null);
region.update();
this.messageBridge.message(player, "setteleport-reset", region);
}
ProtectedRegion wgRegion = region.getRegion();
Location location = player.getLocation();
if (!player.hasPermission("areashop.setteleportoutsideregion") && (wgRegion == null || !wgRegion.contains(
location.getBlockX(),
location.getBlockY(),
location.getBlockZ()))
) {
this.messageBridge.message(player, "setteleport-notInside", region);
return;
}
region.getTeleportFeature().setTeleport(location);
region.update();
this.messageBridge.message(player, "setteleport-success", region);
}
}
@@ -0,0 +1,77 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.parser.standard.BooleanParser;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
@Singleton
public class SetTransferCommand extends AreashopCommandBean {
private static final CloudKey<Boolean> KEY_ENABLED = CloudKey.of("enabled", Boolean.class);
private final MessageBridge messageBridge;
private final CommandFlag<GeneralRegion> regionFlag;
@Inject
public SetTransferCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
}
@Override
public String getHelpKey(CommandSender target) {
if (target.hasPermission("areashop.settransfer")) {
return "help-settransfer";
}
return null;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("settransfer")
.required(KEY_ENABLED, BooleanParser.booleanParser(true))
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("settransfer");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.settransfer")) {
throw new AreaShopCommandException("settransfer-noPermission");
}
GeneralRegion region = RegionParseUtil.getOrParseRegion(context, sender, this.regionFlag);
boolean enabled = context.get(KEY_ENABLED);
region.setTransferEnabled(enabled);
messageBridge.message(sender, "settransfer-success", enabled, region);
region.update();
}
}
@@ -1,105 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class SetdurationCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop setduration";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setduration")) {
return "help-setduration";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.setduration") && (!sender.hasPermission("areashop.setduration.landlord") && sender instanceof Player)) {
plugin.message(sender, "setduration-noPermission");
return;
}
if(args.length < 3 || args[1] == null || args[2] == null) {
plugin.message(sender, "setduration-help");
return;
}
int regionArgument = 3;
if(args.length >= 2 && ("default".equalsIgnoreCase(args[1]) || "reset".equalsIgnoreCase(args[1]))) {
regionArgument = 2;
}
RentRegion rent;
if(args.length <= regionArgument) {
if(sender instanceof Player) {
// get the region by location
List<RentRegion> regions = Utils.getImportantRentRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
rent = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
rent = plugin.getFileManager().getRent(args[regionArgument]);
}
if(rent == null) {
plugin.message(sender, "setduration-notRegistered", args[regionArgument]);
return;
}
if(!sender.hasPermission("areashop.setduration") && !(sender instanceof Player && rent.isLandlord(((Player)sender).getUniqueId()))) {
plugin.message(sender, "setduration-noLandlord", rent);
return;
}
if("default".equalsIgnoreCase(args[1]) || "reset".equalsIgnoreCase(args[1])) {
rent.setDuration(null);
rent.update();
plugin.message(sender, "setduration-successRemoved", rent);
return;
}
try {
Integer.parseInt(args[1]);
} catch(NumberFormatException e) {
plugin.message(sender, "setduration-wrongAmount", args[1], rent);
return;
}
if(!Utils.checkTimeFormat(args[1] + " " + args[2])) {
plugin.message(sender, "setduration-wrongFormat", args[1] + " " + args[2], rent);
return;
}
rent.setDuration(args[1] + " " + args[2]);
rent.update();
plugin.message(sender, "setduration-success", rent);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getRentNames();
} else if(toComplete == 4) {
result.addAll(plugin.getConfig().getStringList("minutes"));
result.addAll(plugin.getConfig().getStringList("hours"));
result.addAll(plugin.getConfig().getStringList("days"));
result.addAll(plugin.getConfig().getStringList("months"));
result.addAll(plugin.getConfig().getStringList("years"));
}
return result;
}
}
@@ -1,87 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class SetlandlordCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop setlandlord";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setlandlord")) {
return "help-setlandlord";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.setlandlord")) {
plugin.message(sender, "setlandlord-noPermission");
return;
}
if(args.length < 2) {
plugin.message(sender, "setlandlord-help");
return;
}
@SuppressWarnings("deprecation")
OfflinePlayer player = Bukkit.getOfflinePlayer(args[1]);
GeneralRegion region;
if(args.length < 3) {
if(sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
}
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[2]);
return;
}
String playerName = player.getName();
if(playerName == null || playerName.isEmpty()) {
playerName = args[1];
}
region.setLandlord(player.getUniqueId(), playerName);
region.update();
plugin.message(sender, "setlandlord-success", playerName, region);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(toComplete == 3) {
result.addAll(plugin.getFileManager().getRegionNames());
}
return result;
}
}
@@ -1,134 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;
public class SetownerCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop setowner";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setownerrent") || target.hasPermission("areashop.setownerbuy")) {
return "help-setowner";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.setownerrent") && !sender.hasPermission("areashop.setownerbuy")) {
plugin.message(sender, "setowner-noPermission");
return;
}
GeneralRegion region;
if(args.length < 2) {
plugin.message(sender, "setowner-help");
return;
}
if(args.length == 2) {
if(sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
}
if(region == null) {
plugin.message(sender, "setowner-notRegistered");
return;
}
if(region instanceof RentRegion && !sender.hasPermission("areashop.setownerrent")) {
plugin.message(sender, "setowner-noPermissionRent", region);
return;
}
if(region instanceof BuyRegion && !sender.hasPermission("areashop.setownerbuy")) {
plugin.message(sender, "setowner-noPermissionBuy", region);
return;
}
UUID uuid = null;
@SuppressWarnings("deprecation")
OfflinePlayer player = Bukkit.getOfflinePlayer(args[1]);
if(player != null) {
uuid = player.getUniqueId();
}
if(uuid == null) {
plugin.message(sender, "setowner-noPlayer", args[1], region);
return;
}
if(region instanceof RentRegion) {
RentRegion rent = (RentRegion)region;
if(rent.isRenter(uuid)) {
// extend
rent.setRentedUntil(rent.getRentedUntil() + rent.getDuration());
rent.setRenter(uuid);
plugin.message(sender, "setowner-succesRentExtend", region);
} else {
// change
if(!rent.isRented()) {
rent.setRentedUntil(Calendar.getInstance().getTimeInMillis() + rent.getDuration());
}
rent.setRenter(uuid);
plugin.message(sender, "setowner-succesRent", region);
}
}
if(region instanceof BuyRegion) {
BuyRegion buy = (BuyRegion)region;
buy.setBuyer(uuid);
plugin.message(sender, "setowner-succesBuy", region);
}
region.getFriendsFeature().deleteFriend(region.getOwner(), null);
region.update();
region.saveRequired();
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(toComplete == 3) {
result.addAll(plugin.getFileManager().getRegionNames());
}
return result;
}
}
@@ -1,103 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class SetpriceCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop setprice";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setprice")) {
return "help-setprice";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.setprice") && (!sender.hasPermission("areashop.setprice.landlord") && sender instanceof Player)) {
plugin.message(sender, "setprice-noPermission");
return;
}
if(args.length < 2 || args[1] == null) {
plugin.message(sender, "setprice-help");
return;
}
GeneralRegion region;
if(args.length < 3) {
if(sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
}
if(region == null) {
plugin.message(sender, "setprice-notRegistered", args[2]);
return;
}
if(!sender.hasPermission("areashop.setprice") && !(sender instanceof Player && region.isLandlord(((Player)sender).getUniqueId()))) {
plugin.message(sender, "setprice-noLandlord", region);
return;
}
if("default".equalsIgnoreCase(args[1]) || "reset".equalsIgnoreCase(args[1])) {
if(region instanceof RentRegion) {
((RentRegion)region).setPrice(null);
} else if(region instanceof BuyRegion) {
((BuyRegion)region).setPrice(null);
}
region.update();
plugin.message(sender, "setprice-successRemoved", region);
return;
}
double price;
try {
price = Double.parseDouble(args[1]);
} catch(NumberFormatException e) {
plugin.message(sender, "setprice-wrongPrice", args[1], region);
return;
}
if(region instanceof RentRegion) {
((RentRegion)region).setPrice(price);
plugin.message(sender, "setprice-successRent", region);
} else if(region instanceof BuyRegion) {
((BuyRegion)region).setPrice(price);
plugin.message(sender, "setprice-successBuy", region);
}
region.update();
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 3) {
result = plugin.getFileManager().getRegionNames();
}
return result;
}
}
@@ -1,73 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
public class SetrestoreCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop setrestore";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setrestore")) {
return "help-setrestore";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.setrestore")) {
plugin.message(sender, "setrestore-noPermission");
return;
}
if(args.length <= 2 || args[1] == null || args[2] == null) {
plugin.message(sender, "setrestore-help");
return;
}
GeneralRegion region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(sender, "setrestore-notRegistered", args[1]);
return;
}
Boolean value = null;
if(args[2].equalsIgnoreCase("true")) {
value = true;
} else if(args[2].equalsIgnoreCase("false")) {
value = false;
}
region.setRestoreSetting(value);
String valueString = "general";
if(value != null) {
valueString = value + "";
}
if(args.length > 3) {
region.setSchematicProfile(args[3]);
plugin.message(sender, "setrestore-successProfile", valueString, args[3], region);
} else {
plugin.message(sender, "setrestore-success", valueString, region);
}
region.update();
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getRegionNames();
} else if(toComplete == 3) {
result.add("true");
result.add("false");
result.add("general");
} else if(toComplete == 4) {
result.addAll(plugin.getConfig().getConfigurationSection("schematicProfiles").getKeys(false));
}
return result;
}
}
@@ -1,118 +0,0 @@
package me.wiefferink.areashop.commands;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class SetteleportCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop settp";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.teleportall") || target.hasPermission("areashop.teleport")) {
return "help-setteleport";
}
return null;
}
/**
* Check if a person can set the teleport location of the region.
* @param person The person to check
* @param region The region to check for
* @return true if the person can set the teleport location, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if(!(person instanceof Player)) {
return false;
}
Player player = (Player)person;
return player.hasPermission("areashop.setteleportall")
|| region.isOwner(player) && player.hasPermission("areashop.setteleport");
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.setteleport") && !sender.hasPermission("areashop.setteleportall")) {
plugin.message(sender, "setteleport-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "onlyByPlayer");
return;
}
Player player = (Player)sender;
GeneralRegion region;
if(args.length < 2) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
region = plugin.getFileManager().getRegion(args[1]);
}
boolean owner;
if(region == null) {
plugin.message(player, "setteleport-noRentOrBuy", args[1]);
return;
}
if(region instanceof RentRegion) {
owner = player.getUniqueId().equals(((RentRegion)region).getRenter());
} else {
owner = player.getUniqueId().equals(((BuyRegion)region).getBuyer());
}
if(!player.hasPermission("areashop.setteleport")) {
plugin.message(player, "setteleport-noPermission", region);
return;
} else if(!owner && !player.hasPermission("areashop.setteleportall")) {
plugin.message(player, "setteleport-noPermissionOther", region);
return;
}
ProtectedRegion wgRegion = region.getRegion();
if(args.length > 2 && args[2] != null && (args[2].equalsIgnoreCase("reset") || args[2].equalsIgnoreCase("yes") || args[2].equalsIgnoreCase("true"))) {
region.getTeleportFeature().setTeleport(null);
region.update();
plugin.message(player, "setteleport-reset", region);
return;
}
if(!player.hasPermission("areashop.setteleportoutsideregion") && (wgRegion == null || !wgRegion.contains(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()))) {
plugin.message(player, "setteleport-notInside", region);
return;
}
region.getTeleportFeature().setTeleport(player.getLocation());
region.update();
plugin.message(player, "setteleport-success", region);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
result.add("reset");
}
return result;
}
}
@@ -1,253 +1,285 @@
package me.wiefferink.areashop.commands;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import me.wiefferink.areashop.AreaShop;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.events.ask.AddingRegionEvent;
import me.wiefferink.areashop.interfaces.WorldEditInterface;
import me.wiefferink.areashop.interfaces.WorldEditSelection;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.interfaces.WorldGuardInterface;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionFactory;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.interactivemessenger.processing.Message;
import org.bukkit.Location;
import org.bukkit.block.BlockFace;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.parser.standard.EnumParser;
import org.incendo.cloud.parser.standard.IntegerParser;
import org.incendo.cloud.parser.standard.StringParser;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import java.util.Optional;
public class StackCommand extends CommandAreaShop {
@Singleton
public class StackCommand extends AreashopCommandBean {
@Override
public String getCommandStart() {
return "areashop stack";
}
private static final CloudKey<Integer> KEY_AMOUNT = CloudKey.of("amount", Integer.class);
private static final CloudKey<Integer> KEY_GAP = CloudKey.of("gap", Integer.class);
private static final CloudKey<String> KEY_NAME = CloudKey.of("name", String.class);
private static final CloudKey<GeneralRegion.RegionType> KEY_TYPE = CloudKey.of("type",
GeneralRegion.RegionType.class);
private static final CommandFlag<String> FLAG_GROUP = CommandFlag.builder("group")
.withComponent(StringParser.stringParser())
.build();
private final MessageBridge messageBridge;
private final Plugin plugin;
private final WorldEditInterface worldEditInterface;
private final WorldGuardInterface worldGuardInterface;
private final RegionFactory regionFactory;
private final IFileManager fileManager;
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.stack")) {
return "help-stack";
}
return null;
}
@Inject
public StackCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull Plugin plugin,
@Nonnull WorldEditInterface worldEditInterface,
@Nonnull WorldGuardInterface worldGuardInterface,
@Nonnull RegionFactory regionFactory,
@Nonnull IFileManager fileManager
@Override
public void execute(CommandSender sender, String[] args) {
// Check permission
if(!sender.hasPermission("areashop.stack")) {
plugin.message(sender, "stack-noPermission");
return;
}
// Only from ingame
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
final Player player = (Player)sender;
// Specify enough arguments
if(args.length < 5) {
plugin.message(sender, "stack-help");
return;
}
// Check amount
int tempAmount = -1;
try {
tempAmount = Integer.parseInt(args[1]);
} catch(NumberFormatException e) {
// Incorrect number
}
if(tempAmount <= 0) {
plugin.message(player, "stack-wrongAmount", args[1]);
return;
}
// Check gap
int gap;
try {
gap = Integer.parseInt(args[2]);
} catch(NumberFormatException e) {
plugin.message(player, "stack-wrongGap", args[2]);
return;
}
// Check region type
if(!"rent".equalsIgnoreCase(args[4]) && !"buy".equalsIgnoreCase(args[4])) {
plugin.message(sender, "stack-help");
return;
}
// Get WorldEdit selection
final WorldEditSelection selection = plugin.getWorldEditHandler().getPlayerSelection(player);
if(selection == null) {
plugin.message(player, "stack-noSelection");
return;
}
// Get or create group
RegionGroup group = null;
if(args.length > 5) {
group = plugin.getFileManager().getGroup(args[5]);
if(group == null) {
group = new RegionGroup(plugin, args[5]);
plugin.getFileManager().addGroup(group);
}
}
// Get facing of the player (must be clearly one of the four directions to make sure it is no mistake)
BlockFace facing = Utils.yawToFacing(player.getLocation().getYaw());
if(player.getLocation().getPitch() > 45) {
facing = BlockFace.DOWN;
} else if(player.getLocation().getPitch() < -45) {
facing = BlockFace.UP;
}
if(!(facing == BlockFace.NORTH || facing == BlockFace.EAST || facing == BlockFace.SOUTH || facing == BlockFace.WEST || facing == BlockFace.UP || facing == BlockFace.DOWN)) {
plugin.message(player, "stack-unclearDirection", facing.toString().toLowerCase().replace('_', '-'));
return;
}
Vector shift = new BlockVector(0, 0, 0);
if(facing == BlockFace.SOUTH) {
shift = shift.setZ(-selection.getLength() - gap);
} else if(facing == BlockFace.WEST) {
shift = shift.setX(selection.getWidth() + gap);
} else if(facing == BlockFace.NORTH) {
shift = shift.setZ(selection.getLength() + gap);
} else if(facing == BlockFace.EAST) {
shift = shift.setX(-selection.getWidth() - gap);
} else if(facing == BlockFace.DOWN) {
shift = shift.setY(-selection.getHeight() - gap);
} else if(facing == BlockFace.UP) {
shift = shift.setY(selection.getHeight() + gap);
}
AreaShop.debug(" calculated shift vector: " + shift + ", with facing=" + facing);
// Create regions and add them to AreaShop
final String nameTemplate = args[3];
) {
this.messageBridge = messageBridge;
this.plugin = plugin;
this.worldEditInterface = worldEditInterface;
this.worldGuardInterface = worldGuardInterface;
this.regionFactory = regionFactory;
this.fileManager = fileManager;
}
final int regionsPerTick = plugin.getConfig().getInt("adding.regionsPerTick");
final boolean rentRegions = "rent".equalsIgnoreCase(args[4]);
final int amount = tempAmount;
final RegionGroup finalGroup = group;
final Vector finalShift = shift;
String type;
if(rentRegions) {
type = "rent";
} else {
type = "buy";
}
Message groupsMessage = Message.empty();
if(group != null) {
groupsMessage = Message.fromKey("stack-addToGroup").replacements(group.getName());
}
plugin.message(player, "stack-accepted", amount, type, gap, nameTemplate, groupsMessage);
plugin.message(player, "stack-addStart", amount, regionsPerTick * 20);
@NotNull
private static Vector calculateShift(BlockFace facing, WorldEditSelection selection, int gap) {
Vector shift = new Vector(0, 0, 0);
if (facing == BlockFace.SOUTH) {
shift = shift.setZ(-selection.getLength() - gap);
} else if (facing == BlockFace.WEST) {
shift = shift.setX(selection.getWidth() + gap);
} else if (facing == BlockFace.NORTH) {
shift = shift.setZ(selection.getLength() + gap);
} else if (facing == BlockFace.EAST) {
shift = shift.setX(-selection.getWidth() - gap);
} else if (facing == BlockFace.DOWN) {
shift = shift.setY(-selection.getHeight() - gap);
} else if (facing == BlockFace.UP) {
shift = shift.setY(selection.getHeight() + gap);
}
return shift;
}
Location minimumLocation = selection.getMinimumLocation();
Vector minimumVector = new Vector(minimumLocation.getX(), minimumLocation.getY(), minimumLocation.getZ());
Location maximumLocation = selection.getMaximumLocation();
Vector maximumVector = new Vector(maximumLocation.getX(), maximumLocation.getY(), maximumLocation.getZ());
new BukkitRunnable() {
private int current = -1;
private final RegionManager manager = AreaShop.getInstance().getRegionManager(selection.getWorld());
private int counter = 1;
private int tooLow = 0;
private int tooHigh = 0;
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.stack")) {
return "help-stack";
}
return null;
}
@Override
public void run() {
for(int i = 0; i < regionsPerTick; i++) {
current++;
if(current < amount) {
// Create the region name
String counterName = counter + "";
int minimumLength = plugin.getConfig().getInt("stackRegionNumberLength");
while(counterName.length() < minimumLength) {
counterName = "0" + counterName;
}
String regionName;
if(nameTemplate.contains("#")) {
regionName = nameTemplate.replace("#", counterName);
} else {
regionName = nameTemplate + counterName;
}
while(manager.getRegion(regionName) != null || AreaShop.getInstance().getFileManager().getRegion(regionName) != null) {
counter++;
counterName = counter + "";
minimumLength = plugin.getConfig().getInt("stackRegionNumberLength");
while(counterName.length() < minimumLength) {
counterName = "0" + counterName;
}
if(nameTemplate.contains("#")) {
regionName = nameTemplate.replace("#", counterName);
} else {
regionName = nameTemplate + counterName;
}
}
// Add the region to WorldGuard (at startposition shifted by the number of this region times the blocks it should shift)
BlockVector minimum = new BlockVector(minimumVector.add(finalShift.multiply(current)));
BlockVector maximum = new BlockVector(maximumVector.add(finalShift.multiply(current)));
// Check for out of bounds
if(minimum.getBlockY() < 0) {
tooLow++;
continue;
} else if(maximum.getBlockY() > 256) {
tooHigh++;
continue;
}
ProtectedCuboidRegion region = new ProtectedCuboidRegion(regionName, minimum, maximum);
manager.addRegion(region);
// Add the region to AreaShop
if(rentRegions) {
RentRegion rent = new RentRegion(regionName, selection.getWorld());
if(finalGroup != null) {
finalGroup.addMember(rent);
}
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
plugin.getFileManager().addRent(rent);
rent.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
rent.update();
} else {
BuyRegion buy = new BuyRegion(regionName, selection.getWorld());
if(finalGroup != null) {
finalGroup.addMember(buy);
}
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
plugin.getFileManager().addBuy(buy);
buy.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
buy.update();
}
}
}
if(current >= amount) {
if(player.isOnline()) {
int added = amount - tooLow - tooHigh;
Message wrong = Message.empty();
if(tooHigh > 0) {
wrong.append(Message.fromKey("stack-tooHigh").replacements(tooHigh));
}
if(tooLow > 0) {
wrong.append(Message.fromKey("stack-tooLow").replacements(tooLow));
}
plugin.message(player, "stack-addComplete", added, wrong);
}
this.cancel();
}
}
}.runTaskTimer(plugin, 1, 1);
}
@Override
public String stringDescription() {
return null;
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 5) {
result.add("rent");
result.add("buy");
} else if(toComplete == 6) {
result.addAll(plugin.getFileManager().getGroupNames());
}
return result;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("stack")
.senderType(PlayerCommandSource.class)
.required(KEY_AMOUNT, IntegerParser.integerParser(0))
.required(KEY_GAP, IntegerParser.integerParser(0))
.required(KEY_NAME, StringParser.stringParser())
.required(KEY_TYPE, EnumParser.enumParser(GeneralRegion.RegionType.class))
.flag(FLAG_GROUP)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("stack");
}
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
Player player = context.sender().sender();
if (!player.hasPermission("areashop.stack")) {
throw new AreaShopCommandException("stack-noPermission");
}
int amount = context.get(KEY_AMOUNT);
int gap = context.get(KEY_GAP);
String name = context.get(KEY_NAME);
GeneralRegion.RegionType regionType = context.get(KEY_TYPE);
Optional<String> optionalGroup = context.flags().getValue(FLAG_GROUP);
// Get WorldEdit selection
final WorldEditSelection selection = worldEditInterface.getPlayerSelection(player);
if (selection == null) {
this.messageBridge.message(player, "stack-noSelection");
return;
}
// Get or create group
RegionGroup group = null;
if (optionalGroup.isPresent()) {
String groupName = optionalGroup.get();
group = fileManager.getGroup(groupName);
if (group == null) {
group = regionFactory.createRegionGroup(groupName);
fileManager.addGroup(group);
}
}
// Get facing of the player (must be clearly one of the four directions to make sure it is no mistake)
BlockFace facing = Utils.yawToFacing(player.getLocation().getYaw());
if (player.getLocation().getPitch() > 45) {
facing = BlockFace.DOWN;
} else if (player.getLocation().getPitch() < -45) {
facing = BlockFace.UP;
}
if (!(facing == BlockFace.NORTH || facing == BlockFace.EAST || facing == BlockFace.SOUTH || facing == BlockFace.WEST || facing == BlockFace.UP || facing == BlockFace.DOWN)) {
this.messageBridge.message(player,
"stack-unclearDirection",
facing.toString().toLowerCase().replace('_', '-'));
return;
}
Vector shift = calculateShift(facing, selection, gap);
BukkitRunnable task = stackTask(player, name, amount, selection, regionType, shift, group);
task.runTaskTimer(plugin, 1, 1);
}
private BukkitRunnable stackTask(
@Nonnull Player player,
@Nonnull String name,
int amount,
@Nonnull WorldEditSelection selection,
GeneralRegion.RegionType regionType,
@Nonnull Vector shift,
@Nullable RegionGroup group
) {
final int regionsPerTick = plugin.getConfig().getInt("adding.regionsPerTick");
Location minimumLocation = selection.getMinimumLocation();
Vector minimumVector = new Vector(minimumLocation.getX(), minimumLocation.getY(), minimumLocation.getZ());
Location maximumLocation = selection.getMaximumLocation();
Vector maximumVector = new Vector(maximumLocation.getX(), maximumLocation.getY(), maximumLocation.getZ());
return new BukkitRunnable() {
private final RegionManager manager = worldGuardInterface.getRegionManager(selection.getWorld());
private int current = -1;
private int counter = 1;
private int tooLow = 0;
private int tooHigh = 0;
@Override
public void run() {
for (int i = 0; i < regionsPerTick; i++) {
current++;
if (current >= amount) {
continue;
}
// Create the region name
String regionName = countToName(name, counter);
while (manager.getRegion(regionName) != null || fileManager.getRegion(regionName) != null) {
counter++;
regionName = countToName(name, counter);
}
// Add the region to WorldGuard (at startposition shifted by the number of this region times the blocks it should shift)
Vector minimum = minimumVector.clone().add(shift.clone().multiply(current));
Vector maximum = maximumVector.clone().add(shift.clone().multiply(current));
// Check for out of bounds
if (minimum.getBlockY() < 0) {
tooLow++;
continue;
} else if (maximum.getBlockY() > 256) {
tooHigh++;
continue;
}
ProtectedCuboidRegion region = worldGuardInterface.createCuboidRegion(regionName, minimum, maximum);
manager.addRegion(region);
// Add the region to AreaShop
GeneralRegion newRegion;
if (regionType == GeneralRegion.RegionType.BUY) {
newRegion = regionFactory.createRentRegion(regionName, selection.getWorld());
} else {
newRegion = regionFactory.createBuyRegion(regionName, selection.getWorld());
}
if (group != null) {
group.addMember(newRegion);
}
AddingRegionEvent event = fileManager.addRegion(newRegion);
if (event.isCancelled()) {
messageBridge.message(player, "general-cancelled", event.getReason());
continue;
}
newRegion.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
newRegion.update();
}
if (current >= amount) {
if (player.isOnline()) {
int added = amount - tooLow - tooHigh;
Message wrong = Message.empty();
if (tooHigh > 0) {
wrong.append(Message.fromKey("stack-tooHigh").replacements(tooHigh));
}
if (tooLow > 0) {
wrong.append(Message.fromKey("stack-tooLow").replacements(tooLow));
}
messageBridge.message(player, "stack-addComplete", added, wrong);
}
this.cancel();
}
}
};
}
/**
* Build a name from a count, with the right length.
*
* @param template Template to put the name in (# to put the count there, otherwise count is appended)
* @param count Number to use
* @return name with prepended 0's
*/
private String countToName(String template, int count) {
StringBuilder counterName = new StringBuilder().append(count);
int minimumLength = plugin.getConfig().getInt("stackRegionNumberLength");
while (counterName.length() < minimumLength) {
counterName.insert(0, "0");
}
if (template.contains("#")) {
return template.replace("#", counterName);
} else {
return template + counterName;
}
}
}
@@ -0,0 +1,131 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.BuyRegionParser;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.suggestion.Suggestion;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Singleton
public class StopResellCommand extends AreashopCommandBean {
private final MessageBridge messageBridge;
private final IFileManager fileManager;
private final CommandFlag<BuyRegion> regionFlag;
@Inject
public StopResellCommand(@Nonnull MessageBridge messageBridge, @Nonnull IFileManager fileManager) {
ParserDescriptor<CommandSource<?>, BuyRegion> regionParser =
ParserDescriptor.of(new BuyRegionParser<>(fileManager, this::suggestBuyRegions), BuyRegion.class);
this.messageBridge = messageBridge;
this.fileManager = fileManager;
this.regionFlag = CommandFlag.<CommandSource<?>>builder("region")
.withComponent(regionParser)
.build();
}
@Override
public String getHelpKey(CommandSender target) {
if (target.hasPermission("areashop.stopresellall") || target.hasPermission("areashop.stopresell")) {
return "help-stopResell";
}
return null;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("stopresell")
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("stopresell");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.stopresell") && !sender.hasPermission("areashop.stopresellall")) {
this.messageBridge.message(sender, "stopresell-noPermissionOther");
return;
}
BuyRegion buy = RegionParseUtil.getOrParseBuyRegion(context, sender, this.regionFlag);
if (!buy.isInResellingMode()) {
this.messageBridge.message(sender, "stopresell-notResell", buy);
return;
}
if (sender.hasPermission("areashop.stopresellall")) {
buy.disableReselling();
buy.update();
this.messageBridge.message(sender, "stopresell-success", buy);
} else if (sender.hasPermission("areashop.stopresell") && sender instanceof Player player) {
if (buy.isOwner(player)) {
buy.disableReselling();
buy.update();
this.messageBridge.message(sender, "stopresell-success", buy);
} else {
this.messageBridge.message(sender, "stopresell-noPermissionOther", buy);
}
} else {
this.messageBridge.message(sender, "stopresell-noPermission", buy);
}
}
private CompletableFuture<Iterable<Suggestion>> suggestBuyRegions(
@Nonnull CommandContext<CommandSource<?>> context,
@Nonnull CommandInput input
) {
String text = input.peekString();
List<Suggestion> suggestions = this.fileManager.getBuysRef().stream()
.filter(region -> region.isSold() && region.isInResellingMode())
.map(GeneralRegion::getName)
.filter(name -> name.startsWith(text))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestions);
}
}
@@ -1,111 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class StopresellCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop stopresell";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.stopresellall") || target.hasPermission("areashop.stopresell")) {
return "help-stopResell";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.stopresell") && !sender.hasPermission("areashop.stopresellall")) {
plugin.message(sender, "stopresell-noPermissionOther");
return;
}
BuyRegion buy;
if(args.length <= 1) {
if(sender instanceof Player) {
// get the region by location
List<BuyRegion> regions = Utils.getImportantBuyRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
buy = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
buy = plugin.getFileManager().getBuy(args[1]);
if(buy == null) {
plugin.message(sender, "stopresell-notRegistered", args[1]);
return;
}
}
if(buy == null) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
}
if(!buy.isInResellingMode()) {
plugin.message(sender, "stopresell-notResell", buy);
return;
}
if(sender.hasPermission("areashop.stopresellall")) {
buy.disableReselling();
buy.update();
plugin.message(sender, "stopresell-success", buy);
} else if(sender.hasPermission("areashop.stopresell") && sender instanceof Player) {
if(buy.isOwner((Player)sender)) {
buy.disableReselling();
buy.update();
plugin.message(sender, "stopresell-success", buy);
} else {
plugin.message(sender, "stopresell-noPermissionOther", buy);
}
} else {
plugin.message(sender, "stopresell-noPermission", buy);
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(region.isSold() && region.isInResellingMode()) {
result.add(region.getName());
}
}
}
return result;
}
}
@@ -1,81 +1,96 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.GeneralRegionParser;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
public class TeleportCommand extends CommandAreaShop {
@Singleton
public class TeleportCommand extends AreashopCommandBean {
@Override
public String getCommandStart() {
return "areashop tp";
}
private static final CloudKey<GeneralRegion> KEY_REGION = CloudKey.of("region", GeneralRegion.class);
private static final CommandFlag<Void> KEY_TO_SIGN = CommandFlag.builder("to-sign").build();
private final MessageBridge messageBridge;
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.teleportall") || target.hasPermission("areashop.teleport")) {
return "help-teleport";
}
return null;
}
private final IFileManager fileManager;
/**
* Check if a person can teleport to the region (assuming he is not teleporting to a sign).
* @param person The person to check
* @param region The region to check for
* @return true if the person can teleport to it, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if(!(person instanceof Player)) {
return false;
}
Player player = (Player)person;
return player.hasPermission("areashop.teleportall")
|| region.isOwner(player) && player.hasPermission("areashop.teleport")
|| region.isAvailable() && player.hasPermission("areashop.teleportavailable")
|| region.getFriendsFeature().getFriends().contains(player.getUniqueId()) && player.hasPermission("areashop.teleportfriend");
}
@Inject
public TeleportCommand(@Nonnull MessageBridge messageBridge, @Nonnull IFileManager fileManager) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.teleport") && !sender.hasPermission("areashop.teleportall") && !sender.hasPermission("areashop.teleportavailable") && !sender.hasPermission("areashop.teleportavailablesign") && !sender.hasPermission("areashop.teleportsign") && !sender.hasPermission("areashop.teleportsignall") && !sender.hasPermission("areashop.teleportfriend") && !sender.hasPermission("teleportfriendsign")) {
plugin.message(sender, "teleport-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
if(args.length <= 1 || args[1] == null) {
plugin.message(sender, "teleport-help");
return;
}
Player player = (Player)sender;
GeneralRegion region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(player, "teleport-noRentOrBuy", args[1]);
return;
}
if(args.length >= 3 && (args[2].equalsIgnoreCase("sign") || args[2].equalsIgnoreCase("yes") || args[2].equalsIgnoreCase("true"))) {
region.getTeleportFeature().teleportPlayer(player, true);
} else {
region.getTeleportFeature().teleportPlayer(player, false);
}
/**
* Check if a person can teleport to the region (assuming he is not teleporting to a sign).
*
* @param person The person to check
* @param region The region to check for
* @return true if the person can teleport to it, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if (!(person instanceof Player player)) {
return false;
}
return player.hasPermission("areashop.teleportall")
|| region.isOwner(player) && player.hasPermission("areashop.teleport")
|| region.isAvailable() && player.hasPermission("areashop.teleportavailable")
|| region.getFriendsFeature().getFriends().contains(player.getUniqueId()) && player.hasPermission(
"areashop.teleportfriend");
}
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.teleportall") || target.hasPermission("areashop.teleport")) {
return "help-teleport";
}
return null;
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
result.add("sign");
}
return result;
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("tp", "teleport")
.senderType(PlayerCommandSource.class)
.required(KEY_REGION, GeneralRegionParser.generalRegionParser(this.fileManager))
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("teleport", "tp");
}
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
Player player = context.sender().sender();
if (!player.hasPermission("areashop.teleport") && !player.hasPermission("areashop.teleportall") && !player.hasPermission(
"areashop.teleportavailable") && !player.hasPermission("areashop.teleportavailablesign") && !player.hasPermission(
"areashop.teleportsign") && !player.hasPermission("areashop.teleportsignall") && !player.hasPermission(
"areashop.teleportfriend") && !player.hasPermission("teleportfriendsign")) {
this.messageBridge.message(player, "teleport-noPermission");
return;
}
GeneralRegion region = context.get(KEY_REGION);
boolean toSign = context.flags().contains(KEY_TO_SIGN);
region.getTeleportFeature().teleportPlayer(player, toSign);
}
}
@@ -0,0 +1,124 @@
package me.wiefferink.areashop.commands;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.GeneralRegionParser;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.features.homeaccess.HomeAccessFeature;
import me.wiefferink.areashop.features.homeaccess.HomeAccessType;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.component.CommandComponent;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.description.Description;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.parser.standard.EnumParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
@Singleton
public final class ToggleHomeCommand extends AreashopCommandBean {
private static final CloudKey<HomeAccessType> KEY_ACCESS_TYPE = CloudKey.of("accessType", HomeAccessType.class);
private final MessageBridge messageBridge;
private final IFileManager fileManager;
private final CommandFlag<GeneralRegion> regionFlag;
@Inject
public ToggleHomeCommand(@Nonnull MessageBridge messageBridge, @Nonnull IFileManager fileManager) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
this.regionFlag = CommandFlag.<CommandSource<?>>builder("region")
.withComponent(
CommandComponent.<CommandSource<?>, GeneralRegion>builder()
.name("region")
.description(Description.EMPTY)
.valueType(GeneralRegion.class)
.parser(GeneralRegionParser.generalRegionParser(fileManager))
.suggestionProvider(this::suggestRegions)
.build()
).build();
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (!target.hasPermission("sethomecontrol.control")) {
return null;
}
return "help-togglehome";
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("togglehome")
.required(KEY_ACCESS_TYPE, EnumParser.enumParser(HomeAccessType.class))
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("togglehome");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.togglehome")) {
throw new AreaShopCommandException("togglehome-noPermission");
}
final HomeAccessType accessType = context.get(KEY_ACCESS_TYPE);
final GeneralRegion region = RegionParseUtil.getOrParseRegion(context, sender, this.regionFlag);
if (!(sender instanceof Player) && !sender.hasPermission("sethome.control.other")) {
return;
}
if (sender instanceof Player player && !region.isOwner(player)) {
throw new AreaShopCommandException("togglehome-noPermission");
}
region.getOrCreateFeature(HomeAccessFeature.class).homeAccessType(accessType);
this.messageBridge.message(sender, "togglehome-success", accessType.name());
}
private CompletableFuture<Iterable<Suggestion>> suggestRegions(
@Nonnull CommandContext<CommandSource<?>> context,
@Nonnull CommandInput input
) {
String text = input.peekString();
CommandSender sender = context.sender().sender();
Stream<GeneralRegion> regions;
if (sender.hasPermission("sethome.control.other")) {
regions = this.fileManager.getRegionsRef().stream();
} else if (!sender.hasPermission("sethome.control.other") && sender instanceof Player player) {
regions = this.fileManager.getRegionsRef().stream()
.filter(region -> region.isOwner(player.getUniqueId()));
} else {
regions = Stream.empty();
}
List<Suggestion> suggestions = regions.map(GeneralRegion::getName)
.filter(name -> name.startsWith(text))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestions);
}
}
@@ -0,0 +1,167 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.adapters.platform.OfflinePlayerHelper;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.GeneralRegionParser;
import me.wiefferink.areashop.commands.util.OfflinePlayerParser;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.suggestion.Suggestion;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@Singleton
public class TransferCommand extends AreashopCommandBean {
private static final CloudKey<String> KEY_PLAYER = CloudKey.of("player", String.class);
private final MessageBridge messageBridge;
private final IFileManager fileManager;
private final CommandFlag<GeneralRegion> regionFlag;
private final OfflinePlayerHelper offlinePlayerHelper;
@Inject
public TransferCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager,
@Nonnull OfflinePlayerHelper offlinePlayerHelper
) {
ParserDescriptor<PlayerCommandSource, GeneralRegion> regionParser =
ParserDescriptor.of(new GeneralRegionParser<>(fileManager, this::suggestRegions), GeneralRegion.class);
this.messageBridge = messageBridge;
this.fileManager = fileManager;
this.regionFlag = CommandFlag.<PlayerCommandSource>builder("region")
.withComponent(regionParser)
.build();
this.offlinePlayerHelper = offlinePlayerHelper;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (!target.hasPermission("areashop.transfer")) {
return null;
}
return "help-transfer";
}
@Override
public String stringDescription() {
return null;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("transfer")
.senderType(PlayerCommandSource.class)
.required(KEY_PLAYER, OfflinePlayerParser.parser())
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("transfer");
}
private void handleCommand(@Nonnull CommandContext<PlayerCommandSource> context) {
Player sender = context.sender().sender();
if (!sender.hasPermission("areashop.transfer")) {
throw new AreaShopCommandException("transfer-noPermission");
}
GeneralRegion region = RegionParseUtil.getOrParseRegion(context, sender, this.regionFlag);
if (!region.isTransferEnabled()) {
throw new AreaShopCommandException("transfer-disabled");
}
this.offlinePlayerHelper.lookupOfflinePlayerAsync(context.get(KEY_PLAYER))
.whenComplete((offlinePlayer, exception) -> {
if (exception != null) {
sender.sendMessage("failed to lookup offline player!");
exception.printStackTrace();
return;
}
if (!offlinePlayer.hasPlayedBefore() &&!offlinePlayer.isOnline()) {
this.messageBridge.message(sender, "cmd-invalidPlayer", offlinePlayer.getName());
return;
}
performTransfer(sender, offlinePlayer, region);
});
}
private void performTransfer(
@Nonnull Player sender,
@Nonnull OfflinePlayer targetPlayer,
@Nonnull GeneralRegion region
) {
String targetPlayerName = targetPlayer.getName();
if (Objects.equals(sender, targetPlayer)) {
throw new AreaShopCommandException("transfer-transferSelf");
}
if (!targetPlayer.hasPlayedBefore() && !targetPlayer.isOnline()) {
// Unknown player
throw new AreaShopCommandException("transfer-noPlayer", targetPlayerName);
}
if (region.isLandlord(sender.getUniqueId())) {
// Transfer ownership if same as landlord
region.getFriendsFeature().deleteFriend(region.getOwner(), null);
region.setOwner(targetPlayer.getUniqueId());
region.setLandlord(targetPlayer.getUniqueId(), targetPlayerName);
this.messageBridge.message(sender, "transfer-transferred-owner", targetPlayerName, region);
this.messageBridge.messagePersistent(targetPlayer, "transfer-transferred-owner", targetPlayerName, region);
region.update();
region.saveRequired();
return;
}
if (!region.isOwner(sender.getUniqueId())) {
// Cannot transfer tenant if we aren't the current tenant
throw new AreaShopCommandException("transfer-notCurrentTenant");
}
region.getFriendsFeature().deleteFriend(region.getOwner(), null);
// Swap the owner/occupant (renter or buyer)
region.setOwner(targetPlayer.getUniqueId());
this.messageBridge.message(sender, "transfer-transferred-tenant", targetPlayerName, region);
this.messageBridge.messagePersistent(targetPlayer, "transfer-transferred-tenant", targetPlayerName, region);
region.update();
region.saveRequired();
}
private CompletableFuture<Iterable<Suggestion>> suggestRegions(
@Nonnull CommandContext<PlayerCommandSource> context,
@Nonnull CommandInput input
) {
String text = input.peekString();
UUID uuid = context.sender().sender().getUniqueId();
List<Suggestion> suggestions = this.fileManager.getRegions()
.stream()
.filter(region -> region.isOwner(uuid) || region.isLandlord(uuid))
.map(GeneralRegion::getName)
.filter(name -> name.startsWith(text))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestions);
}
}
@@ -1,96 +1,114 @@
package me.wiefferink.areashop.commands;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.commands.util.AreaShopCommandException;
import me.wiefferink.areashop.commands.util.AreashopCommandBean;
import me.wiefferink.areashop.commands.util.RegionParseUtil;
import me.wiefferink.areashop.commands.util.RentRegionParser;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.suggestion.Suggestion;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public class UnrentCommand extends CommandAreaShop {
@Singleton
public class UnrentCommand extends AreashopCommandBean {
private final IFileManager fileManager;
private final CommandFlag<RentRegion> regionFlag;
@Override
public String getCommandStart() {
return "areashop unrent";
}
@Inject
public UnrentCommand(@Nonnull IFileManager fileManager) {
ParserDescriptor<CommandSource<?>, RentRegion> regionParser =
ParserDescriptor.of(new RentRegionParser<>(fileManager, this::suggestRegions), RentRegion.class);
this.fileManager = fileManager;
this.regionFlag = CommandFlag.<CommandSource<?>>builder("region")
.withComponent(regionParser)
.build();
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.unrent") || target.hasPermission("areashop.unrentown")) {
return "help-unrent";
}
return null;
}
/**
* Check if a person can unrent the region.
*
* @param person The person to check
* @param region The region to check for
* @return true if the person can unrent it, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if (person.hasPermission("areashop.unrent")) {
return true;
}
if (person instanceof Player player) {
return region.isOwner(player) && person.hasPermission("areashop.unrentown");
}
return false;
}
/**
* Check if a person can unrent the region.
* @param person The person to check
* @param region The region to check for
* @return true if the person can unrent it, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if(person.hasPermission("areashop.unrent")) {
return true;
}
if(person instanceof Player) {
Player player = (Player)person;
return region.isOwner(player) && person.hasPermission("areashop.unrentown");
}
return false;
}
@Override
public String getHelpKey(CommandSender target) {
if (target.hasPermission("areashop.unrent") || target.hasPermission("areashop.unrentown")) {
return "help-unrent";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.unrent") && !sender.hasPermission("areashop.unrentown")) {
plugin.message(sender, "unrent-noPermission");
return;
}
RentRegion rent;
if(args.length <= 1) {
if(sender instanceof Player) {
// get the region by location
List<RentRegion> regions = Utils.getImportantRentRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
rent = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
rent = plugin.getFileManager().getRent(args[1]);
}
if(rent == null) {
plugin.message(sender, "unrent-notRegistered");
return;
}
if(!rent.isRented()) {
plugin.message(sender, "unrent-notRented", rent);
return;
}
rent.unRent(true, sender);
}
@Override
public String stringDescription() {
return null;
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(RentRegion region : plugin.getFileManager().getRents()) {
if(region.isRented()) {
result.add(region.getName());
}
}
}
return result;
}
@Override
protected Command.Builder<? extends CommandSource<?>> configureCommand(Command.@NotNull Builder<CommandSource<?>> builder) {
return builder.literal("unrent")
.flag(this.regionFlag)
.handler(this::handleCommand);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("unrent");
}
private void handleCommand(@Nonnull CommandContext<CommandSource<?>> context) {
CommandSender sender = context.sender().sender();
if (!sender.hasPermission("areashop.unrent") && !sender.hasPermission("areashop.unrentown")) {
throw new AreaShopCommandException("unrent-noPermission");
}
RentRegion rent = RegionParseUtil.getOrParseRentRegion(context, sender, this.regionFlag);
if (!rent.isRented()) {
throw new AreaShopCommandException("unrent-notRented", rent);
}
rent.unRent(true, sender);
}
@Nonnull
private CompletableFuture<Iterable<Suggestion>> suggestRegions(
@Nonnull CommandContext<CommandSource<?>> context,
@Nonnull CommandInput input
) {
String text = input.peekString();
List<Suggestion> suggestions = this.fileManager.getRentsRef().stream()
.filter(RentRegion::isRented)
.map(GeneralRegion::getName)
.filter(name -> name.startsWith(text))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestions);
}
}
@@ -0,0 +1,88 @@
package me.wiefferink.areashop.commands.util;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.ArgumentParseResult;
import org.incendo.cloud.parser.ArgumentParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.incendo.cloud.suggestion.SuggestionProvider;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
public class AcceptedValuesParser<C> implements ArgumentParser<C, String>, SuggestionProvider<C> {
private final Supplier< Collection<String>> valuesProvider;
private final boolean caseSensitive;
private final String failureMessageKey;
private AcceptedValuesParser(
@Nonnull Supplier< Collection<String>> valuesProvider,
@Nonnull String failureMessageKey,
boolean caseSensitive
) {
this.valuesProvider = valuesProvider;
this.failureMessageKey = failureMessageKey;
this.caseSensitive = caseSensitive;
}
public static <C> AcceptedValuesParser<C> ofConstant(
@Nonnull Collection<String> acceptedValues,
@Nonnull String failureMessageKey,
boolean caseSensitive
) {
Collection<String> copy = List.copyOf(acceptedValues);
return new AcceptedValuesParser<>(() -> copy, failureMessageKey, caseSensitive);
}
public static <C> AcceptedValuesParser<C> of(
@Nonnull Supplier< Collection<String>> supplier,
@Nonnull String failureMessageKey,
boolean caseSensitive
) {
return new AcceptedValuesParser<>(supplier, failureMessageKey, caseSensitive);
}
public static <C> AcceptedValuesParser<C> ofCached(
@Nonnull Supplier< Collection<String>> supplier,
@Nonnull String failureMessageKey,
boolean caseSensitive
) {
return ofConstant(supplier.get(), failureMessageKey, caseSensitive);
}
@Override
public @Nonnull ArgumentParseResult<String> parse(@Nonnull CommandContext<C> commandContext,
@Nonnull CommandInput commandInput) {
String toTest;
if (this.caseSensitive) {
toTest = commandInput.peekString().toLowerCase(Locale.ENGLISH);
} else {
toTest = commandInput.peekString();
}
Collection<String> acceptedValues = this.valuesProvider.get();
if (acceptedValues.contains(toTest)) {
return ArgumentParseResult.success(toTest);
}
return ArgumentParseResult.failure(new AreaShopCommandException(this.failureMessageKey));
}
@Override
public @Nonnull CompletableFuture<Iterable<Suggestion>> suggestionsFuture(
@Nonnull CommandContext<C> context,
@Nonnull CommandInput input
) {
String text = input.peekString();
Iterable<Suggestion> suggestions = this.valuesProvider.get().stream()
.filter(s -> s.startsWith(text))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestions);
}
}
@@ -0,0 +1,31 @@
package me.wiefferink.areashop.commands.util;
import org.checkerframework.checker.nullness.qual.Nullable;
import javax.annotation.Nonnull;
public class AreaShopCommandException extends RuntimeException {
private static final Object[] EMPTY = new Object[0];
private final String messageKey;
private final Object[] replacements;
public AreaShopCommandException(@Nonnull String messageKey, @Nullable Object... replacements) {
this.messageKey = messageKey;
this.replacements = replacements == null ? EMPTY : replacements;
}
public String messageKey() {
return this.messageKey;
}
public Object[] replacements() {
return this.replacements;
}
@Override
public String getMessage() {
return this.messageKey;
}
}
@@ -0,0 +1,50 @@
package me.wiefferink.areashop.commands.util;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandBean;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.processors.confirmation.ConfirmationManager;
import javax.annotation.Nonnull;
/**
* An extension of {@link CommandBean} which does extra pre-processing of the commands.
* Adapted from <a href="https://github.com/Incendo/kitchensink">KitchenSink</a>
*/
public abstract class AreashopCommandBean extends CommandBean<CommandSource<?>> implements HelpProvider {
private boolean requireConfirmation;
protected void withConfirmation() {
this.requireConfirmation = true;
}
@Override
protected final @Nonnull Command.Builder<? extends CommandSource<?>> configure(
final @Nonnull Command.Builder<CommandSource<?>> builder
) {
return this.configureCommand(builder)
.meta(CloudKey.of("bukkit_description", String.class), this.stringDescription())
.meta(ConfirmationManager.META_CONFIRMATION_REQUIRED, this.requireConfirmation);
}
/**
* Returns a simple string description of this command.
*
* <p>This is primarily used in the platform-native help menus.</p>
*
* @return command description
*/
public abstract String stringDescription();
/**
* Configures the command and returns the updated builder.
*
* @param builder builder to configure
* @return the updated builder
*/
protected abstract @Nonnull Command.Builder<? extends CommandSource<?>> configureCommand(
@Nonnull Command.Builder<CommandSource<?>> builder
);
}
@@ -0,0 +1,178 @@
package me.wiefferink.areashop.commands.util;
import com.google.common.cache.CacheBuilder;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.AddCommand;
import me.wiefferink.areashop.commands.AddFriendCommand;
import me.wiefferink.areashop.commands.AddSignCommand;
import me.wiefferink.areashop.commands.BuyCommand;
import me.wiefferink.areashop.commands.DelCommand;
import me.wiefferink.areashop.commands.DelFriendCommand;
import me.wiefferink.areashop.commands.DelSignCommand;
import me.wiefferink.areashop.commands.FindCommand;
import me.wiefferink.areashop.commands.GroupAddCommand;
import me.wiefferink.areashop.commands.GroupDelCommand;
import me.wiefferink.areashop.commands.GroupInfoCommand;
import me.wiefferink.areashop.commands.GroupListCommand;
import me.wiefferink.areashop.commands.HelpCommand;
import me.wiefferink.areashop.commands.InfoBaseCommand;
import me.wiefferink.areashop.commands.InfoCommand;
import me.wiefferink.areashop.commands.InfoPlayerCommand;
import me.wiefferink.areashop.commands.InfoRegionCommand;
import me.wiefferink.areashop.commands.LinkSignsCommand;
import me.wiefferink.areashop.commands.MeCommand;
import me.wiefferink.areashop.commands.MessageCommand;
import me.wiefferink.areashop.commands.QuickBuyCommand;
import me.wiefferink.areashop.commands.QuickDeleteCommand;
import me.wiefferink.areashop.commands.QuickRentCommand;
import me.wiefferink.areashop.commands.ReloadCommand;
import me.wiefferink.areashop.commands.RentCommand;
import me.wiefferink.areashop.commands.ResellCommand;
import me.wiefferink.areashop.commands.SchematicEventCommand;
import me.wiefferink.areashop.commands.SellCommand;
import me.wiefferink.areashop.commands.SetDurationCommand;
import me.wiefferink.areashop.commands.SetLandlordCommand;
import me.wiefferink.areashop.commands.SetOwnerCommand;
import me.wiefferink.areashop.commands.SetPriceCommand;
import me.wiefferink.areashop.commands.SetRestoreCommand;
import me.wiefferink.areashop.commands.SetTeleportCommand;
import me.wiefferink.areashop.commands.SetTransferCommand;
import me.wiefferink.areashop.commands.StackCommand;
import me.wiefferink.areashop.commands.StopResellCommand;
import me.wiefferink.areashop.commands.TeleportCommand;
import me.wiefferink.areashop.commands.ToggleHomeCommand;
import me.wiefferink.areashop.commands.TransferCommand;
import me.wiefferink.areashop.commands.UnrentCommand;
import me.wiefferink.areashop.commands.SetMaxExtends;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.CommandSourceMapper;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import org.incendo.cloud.exception.ArgumentParseException;
import org.incendo.cloud.exception.CommandExecutionException;
import org.incendo.cloud.exception.InvalidCommandSenderException;
import org.incendo.cloud.exception.handling.ExceptionController;
import org.incendo.cloud.exception.handling.ExceptionHandler;
import org.incendo.cloud.execution.ExecutionCoordinator;
import org.incendo.cloud.paper.PaperCommandManager;
import org.incendo.cloud.processors.cache.GuavaCache;
import org.incendo.cloud.processors.confirmation.ConfirmationConfiguration;
import org.incendo.cloud.processors.confirmation.ConfirmationManager;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
@Singleton
public class AreashopCommands {
private static final List<Class<? extends AreashopCommandBean>> COMMAND_CLASSES = List.of(
AddCommand.class,
AddFriendCommand.class,
AddSignCommand.class,
BuyCommand.class,
DelCommand.class,
DelFriendCommand.class,
DelSignCommand.class,
FindCommand.class,
GroupAddCommand.class,
GroupDelCommand.class,
GroupInfoCommand.class,
GroupListCommand.class,
HelpCommand.class,
InfoCommand.class,
InfoBaseCommand.class,
InfoPlayerCommand.class,
InfoRegionCommand.class,
LinkSignsCommand.class,
MeCommand.class,
MessageCommand.class,
QuickBuyCommand.class,
QuickDeleteCommand.class,
QuickRentCommand.class,
ReloadCommand.class,
RentCommand.class,
ResellCommand.class,
SchematicEventCommand.class,
SellCommand.class,
SetDurationCommand.class,
SetLandlordCommand.class,
SetOwnerCommand.class,
SetPriceCommand.class,
SetRestoreCommand.class,
SetTeleportCommand.class,
SetTransferCommand.class,
StackCommand.class,
StopResellCommand.class,
TeleportCommand.class,
ToggleHomeCommand.class,
TransferCommand.class,
UnrentCommand.class,
SetMaxExtends.class
);
private final MessageBridge messageBridge;
private final Injector injector;
private final PaperCommandManager<CommandSource<?>> commandManager;
private final List<AreashopCommandBean> commands = new ArrayList<>();
private HelpRenderer helpRenderer;
@Inject
AreashopCommands(@Nonnull Injector injector, @Nonnull Plugin plugin, @Nonnull MessageBridge messageBridge) {
this.injector = injector;
this.commandManager = PaperCommandManager.builder(new CommandSourceMapper())
.executionCoordinator(ExecutionCoordinator.simpleCoordinator())
.buildOnEnable(plugin);
this.messageBridge = messageBridge;
}
public void registerCommands() {
this.commands.clear();
initCommandManager();
var builder = this.commandManager.commandBuilder("areashop", "as");
for (Class<? extends AreashopCommandBean> commandClass : COMMAND_CLASSES) {
AreashopCommandBean commandBean = injector.getInstance(commandClass);
this.commands.add(commandBean);
var configuredBuilder = commandBean.configureCommand(builder);
this.commandManager.command(configuredBuilder);
}
// Show help by default
this.commandManager.command(builder.handler(context -> showHelp(context.sender().sender())));
this.helpRenderer = new HelpRenderer(this.messageBridge, this.commands);
}
private void initCommandManager() {
ExceptionController<CommandSource<?>> exceptionController = this.commandManager.exceptionController();
// We need to unwrap ArgumentParseException because they wrap the custom exception messages
exceptionController.registerHandler(InvalidCommandSenderException.class,
new InvalidCommandSenderHandler(this.messageBridge));
exceptionController.registerHandler(AreaShopCommandException.class,
new ArgumentParseExceptionHandler<>(this.messageBridge));
exceptionController.registerHandler(ArgumentParseException.class,
ExceptionHandler.unwrappingHandler(AreaShopCommandException.class));
exceptionController.registerHandler(CommandExecutionException.class,
ExceptionHandler.unwrappingHandler(AreaShopCommandException.class));
var confirmationConfiguration = ConfirmationConfiguration.<CommandSource<?>>builder()
.cache(GuavaCache.of(CacheBuilder.newBuilder().build()))
.noPendingCommandNotifier(x -> {
})
.confirmationRequiredNotifier((x, y) -> {
})
.build();
var confirmationManager = ConfirmationManager.confirmationManager(confirmationConfiguration);
commandManager.registerCommandPostProcessor(confirmationManager.createPostprocessor());
}
public void showHelp(@Nonnull CommandSender sender) {
if (this.helpRenderer == null) {
throw new IllegalStateException("Command handler not yet initialized!");
}
this.helpRenderer.showHelp(sender);
}
}
@@ -0,0 +1,37 @@
package me.wiefferink.areashop.commands.util;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import org.incendo.cloud.exception.handling.ExceptionContext;
import org.incendo.cloud.exception.handling.ExceptionHandler;
import javax.annotation.Nonnull;
public class ArgumentParseExceptionHandler<C extends CommandSource<?>> implements ExceptionHandler<C, AreaShopCommandException> {
private final MessageBridge messageBridge;
public ArgumentParseExceptionHandler(@Nonnull MessageBridge messageBridge) {
this.messageBridge = messageBridge;
}
public static void handleException(
@Nonnull MessageBridge messageBridge,
@Nonnull CommandSource<?> sender,
@Nonnull AreaShopCommandException exception
) {
String key = exception.messageKey();
Object[] replacements = exception.replacements();
if (replacements.length == 0) {
messageBridge.message(sender.sender(), key);
return;
}
// Pass the values as a var-args and not as a string[]
messageBridge.message(sender.sender(), key, replacements);
}
@Override
public void handle(@Nonnull ExceptionContext<C, AreaShopCommandException> context) {
handleException(this.messageBridge, context.context().sender(), context.exception());
}
}
@@ -0,0 +1,55 @@
package me.wiefferink.areashop.commands.util;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.ArgumentParseResult;
import org.incendo.cloud.parser.ArgumentParser;
import org.incendo.cloud.suggestion.SuggestionProvider;
import javax.annotation.Nonnull;
public class BuyRegionParser<C> implements ArgumentParser<C, BuyRegion> {
private final IFileManager fileManager;
private final SuggestionProvider<C> suggestionProvider;
public BuyRegionParser(@Nonnull IFileManager fileManager, @Nonnull SuggestionProvider<C> suggestionProvider) {
this.fileManager = fileManager;
this.suggestionProvider = suggestionProvider;
}
public BuyRegionParser(@Nonnull IFileManager fileManager) {
this(fileManager, defaultSuggestionProvider(fileManager));
}
private static <C> SuggestionProvider<C> defaultSuggestionProvider(@Nonnull IFileManager fileManager) {
return SuggestionProvider.blockingStrings((ctx, input) -> {
String text = input.peekString();
return fileManager.getBuyNames()
.stream()
.filter(name -> name.startsWith(text))
.toList();
}
);
}
@Override
public @Nonnull ArgumentParseResult<BuyRegion> parse(@Nonnull CommandContext<C> commandContext,
@Nonnull CommandInput commandInput) {
String input = commandInput.peekString();
BuyRegion region = this.fileManager.getBuy(input);
if (region != null) {
commandInput.readString();
return ArgumentParseResult.success(region);
}
AreaShopCommandException exception = new AreaShopCommandException("buy-noBuyable", input);
return ArgumentParseResult.failure(exception);
}
@Override
public @Nonnull SuggestionProvider<C> suggestionProvider() {
return this.suggestionProvider;
}
}
@@ -0,0 +1,82 @@
package me.wiefferink.areashop.commands.util;
import me.wiefferink.areashop.tools.DurationInput;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.ArgumentParseResult;
import org.incendo.cloud.parser.ArgumentParser;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.suggestion.Suggestion;
import org.incendo.cloud.suggestion.SuggestionProvider;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class DurationInputParser<C> implements ArgumentParser<C, DurationInput>, SuggestionProvider<C> {
public static <C> ParserDescriptor<C, DurationInput> durationInputParser() {
return ParserDescriptor.of(new DurationInputParser<>(), DurationInput.class);
}
@Override
public @NonNull ArgumentParseResult<@NonNull DurationInput> parse(@NonNull CommandContext<@NonNull C> commandContext,
@NonNull CommandInput commandInput) {
String input = commandInput.peekString();
int index = 0;
for (int i = 0; i < input.length(); i++) {
if (Character.isAlphabetic(input.charAt(i))) {
index = i;
break;
}
}
if (index == commandInput.length() - 1) {
return ArgumentParseResult.failure(new AreaShopCommandException("setduration-wrongAmount", input));
}
String duration = input.substring(0, index);
String durationUnit = input.substring(index);
int durationInt;
try {
durationInt = Integer.parseInt(duration);
} catch (NumberFormatException ex) {
return ArgumentParseResult.failure(new AreaShopCommandException("setduration-wrongAmount", duration));
}
Optional<TimeUnit> timeUnit = DurationInput.getTimeUnit(durationUnit.toLowerCase(Locale.ENGLISH));
if (timeUnit.isEmpty()) {
return ArgumentParseResult.failure(new AreaShopCommandException("setduration-wrongFormat", durationUnit));
}
DurationInput durationInput = new DurationInput(durationInt, timeUnit.get());
commandInput.readString();
return ArgumentParseResult.success(durationInput);
}
@Override
public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture(
@NonNull CommandContext<C> context,
@NonNull CommandInput input
) {
String text = input.peekString();
int firstText = 0;
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (Character.isAlphabetic(c)) {
firstText = c;
break;
}
}
if (firstText == 0) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
String timeUnit = text.substring(firstText);
List<String> suffixes = DurationInput.SUFFIXES;
List<Suggestion> suggestions = suffixes.stream()
.filter(suffix -> suffix.startsWith(timeUnit))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestions);
}
}
@@ -0,0 +1,54 @@
package me.wiefferink.areashop.commands.util;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.ArgumentParseResult;
import org.incendo.cloud.parser.ArgumentParser;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.suggestion.SuggestionProvider;
import javax.annotation.Nonnull;
public class GeneralRegionParser<C> implements ArgumentParser<C, GeneralRegion> {
protected final IFileManager fileManager;
private final SuggestionProvider<C> suggestionProvider;
public GeneralRegionParser(@Nonnull IFileManager fileManager, @Nonnull SuggestionProvider<C> suggestionProvider) {
this.fileManager = fileManager;
this.suggestionProvider = suggestionProvider;
}
public GeneralRegionParser(@Nonnull IFileManager fileManager) {
this(fileManager, defaultProvider(fileManager));
}
public static <C> ParserDescriptor<C, GeneralRegion> generalRegionParser(@Nonnull IFileManager fileManager) {
return ParserDescriptor.of(new GeneralRegionParser<>(fileManager), GeneralRegion.class);
}
@Nonnull
private static <C> SuggestionProvider<C> defaultProvider(@Nonnull IFileManager fileManager) {
return SuggestionProvider.blockingStrings((ctx, input) -> fileManager.getRegionNames());
}
@Override
public @Nonnull ArgumentParseResult<GeneralRegion> parse(@Nonnull CommandContext<C> commandContext,
@Nonnull CommandInput commandInput) {
String input = commandInput.peekString();
GeneralRegion region = this.fileManager.getRegion(input);
if (region != null) {
commandInput.readString();
return ArgumentParseResult.success(region);
}
AreaShopCommandException exception = new AreaShopCommandException("cmd-notRegistered", input);
return ArgumentParseResult.failure(exception);
}
@Override
public @Nonnull SuggestionProvider<C> suggestionProvider() {
return this.suggestionProvider;
}
}
@@ -0,0 +1,44 @@
package me.wiefferink.areashop.commands.util;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.interactivemessenger.source.LanguageManager;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.component.CommandComponent;
import org.incendo.cloud.exception.CommandParseException;
import org.incendo.cloud.exception.handling.ExceptionContext;
import org.incendo.cloud.exception.handling.ExceptionHandler;
public class HelpForwardingHandler<C> implements ExceptionHandler<C, CommandParseException> {
private final LanguageManager languageManager;
private final MessageBridge messageBridge;
public HelpForwardingHandler(@NonNull MessageBridge messageBridge, @NonNull LanguageManager languageManager) {
this.languageManager = languageManager;
this.messageBridge = messageBridge;
}
@Override
public void handle(@NonNull ExceptionContext<C, CommandParseException> context) throws Throwable {
CommandParseException exception = context.exception();
// walk back to the first literal
CommandComponent<?> literal = null;
for (CommandComponent<?> component : exception.currentChain()) {
if (component.type() == CommandComponent.ComponentType.LITERAL) {
literal = component;
break;
}
}
// If we can't find the label, rethrow the exception
if (literal == null) {
throw exception;
}
String name = literal.name();
String helpKey = name + "-help";
if (languageManager.getMessage(helpKey).isEmpty()) {
// We don't have a help message, rethrow the exception
throw exception;
}
this.messageBridge.message(context.context().sender(), helpKey);
}
}
@@ -0,0 +1,13 @@
package me.wiefferink.areashop.commands.util;
import org.bukkit.command.CommandSender;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public interface HelpProvider {
@Nullable String getHelpKey(@Nonnull CommandSender target);
}
@@ -0,0 +1,41 @@
package me.wiefferink.areashop.commands.util;
import me.wiefferink.areashop.MessageBridge;
import org.bukkit.command.CommandSender;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
public class HelpRenderer {
private final MessageBridge messageBridge;
private final List<HelpProvider> providers;
public HelpRenderer(@Nonnull MessageBridge messageBridge, @Nonnull List<? extends HelpProvider> providers) {
this.providers = List.copyOf(providers);
this.messageBridge = messageBridge;
}
public void showHelp(@Nonnull CommandSender target) {
if (!target.hasPermission("areashop.help")) {
this.messageBridge.message(target, "help-noPermission");
return;
}
// Add all messages to a list
List<String> messages = new ArrayList<>();
this.messageBridge.message(target, "help-header");
this.messageBridge.message(target, "help-alias");
for (HelpProvider provider : providers) {
String help = provider.getHelpKey(target);
if (help != null && !help.isEmpty()) {
messages.add(help);
}
}
// Send the messages to the target
for (String message : messages) {
this.messageBridge.messageNoPrefix(target, message);
}
}
}
@@ -0,0 +1,30 @@
package me.wiefferink.areashop.commands.util;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.exception.InvalidCommandSenderException;
import org.incendo.cloud.exception.handling.ExceptionContext;
import org.incendo.cloud.exception.handling.ExceptionHandler;
import javax.annotation.Nonnull;
public class InvalidCommandSenderHandler implements ExceptionHandler<CommandSource<?>, InvalidCommandSenderException> {
private final MessageBridge messageBridge;
public InvalidCommandSenderHandler(@Nonnull MessageBridge messageBridge) {
this.messageBridge = messageBridge;
}
@Override
public void handle(@NonNull ExceptionContext<CommandSource<?>, InvalidCommandSenderException> context) throws Throwable {
InvalidCommandSenderException exception = context.exception();
if (exception.requiredSenderTypes().contains(PlayerCommandSource.class)) {
this.messageBridge.message(exception.commandSender(), "cmd-onlyByPlayer");
return;
}
throw exception;
}
}
@@ -0,0 +1,38 @@
package me.wiefferink.areashop.commands.util;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.ArgumentParseResult;
import org.incendo.cloud.parser.ArgumentParser;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.suggestion.BlockingSuggestionProvider;
public class OfflinePlayerParser<C> implements ArgumentParser<C, String>, BlockingSuggestionProvider.Strings<C> {
public static <C> ParserDescriptor<C, String> parser() {
return ParserDescriptor.of(new OfflinePlayerParser<>(), String.class);
}
@Override
public @NonNull ArgumentParseResult<@NonNull String> parse(@NonNull CommandContext<@NonNull C> commandContext,
@NonNull CommandInput commandInput) {
final String input = commandInput.readString();
if (input.length() > 16) {
return ArgumentParseResult.failure(new AreaShopCommandException("cmd-invalidPlayer", input));
}
return ArgumentParseResult.success(input);
}
@Override
public @NonNull Iterable<@NonNull String> stringSuggestions(@NonNull CommandContext<C> commandContext,
@NonNull CommandInput input) {
return Bukkit.getServer().getOnlinePlayers().stream()
.map(Player::getName)
.toList();
}
}
@@ -0,0 +1,40 @@
package me.wiefferink.areashop.commands.util;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.ArgumentParseResult;
import org.incendo.cloud.parser.ArgumentParser;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.suggestion.SuggestionProvider;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
public class ParserWrapper<C, T> implements ArgumentParser<C, T> {
private final SuggestionProvider<C> suggestionProvider;
private final ParserDescriptor<C, T> parser;
public static <C, T> ParserDescriptor<C, T> wrap(@Nonnull ParserDescriptor<C, T> parser, @Nonnull SuggestionProvider<C> suggestionProvider) {
ArgumentParser<C, T> wrapped = new ParserWrapper<>(parser, suggestionProvider);
return ParserDescriptor.of(wrapped, parser.valueType());
}
public ParserWrapper(@Nonnull ParserDescriptor<C, T> parser, @Nonnull SuggestionProvider<C> suggestionProvider) {
this.parser = parser;
this.suggestionProvider = suggestionProvider;
}
@Override
public @NonNull ArgumentParseResult<@NonNull T> parse(@NonNull CommandContext<@NonNull C> commandContext,
@NonNull CommandInput commandInput) {
return this.parser.parser().parse(commandContext, commandInput);
}
@NotNull
@Override
public SuggestionProvider<C> suggestionProvider() {
return this.suggestionProvider;
}
}
@@ -0,0 +1,63 @@
package me.wiefferink.areashop.commands.util;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import me.wiefferink.areashop.interfaces.WorldGuardInterface;
import me.wiefferink.areashop.managers.IFileManager;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import javax.annotation.Nonnull;
import java.util.concurrent.CompletableFuture;
@Singleton
public class RegionCreationUtil {
private final Plugin plugin;
private final IFileManager fileManager;
private final Server server;
private final WorldGuardInterface worldGuardInterface;
@Inject
public RegionCreationUtil(
@Nonnull WorldGuardInterface worldGuardInterface,
@Nonnull IFileManager fileManager,
@Nonnull Server server,
@Nonnull Plugin plugin
) {
this.worldGuardInterface = worldGuardInterface;
this.fileManager = fileManager;
this.plugin = plugin;
this.server = server;
}
public CompletableFuture<ProtectedRegion> createRegion(
@Nonnull CommandContext<?> context,
@Nonnull Player sender,
@Nonnull CloudKey<String> regionKey
) {
World world = sender.getWorld();
String regionName = context.get(regionKey);
if (this.fileManager.getRegion(regionName) != null) {
return CompletableFuture.failedFuture(new AreaShopCommandException("add-failed", regionName));
}
this.server.dispatchCommand(sender, String.format("rg define %s", regionName));
CompletableFuture<ProtectedRegion> future = new CompletableFuture<>();
this.server.getScheduler().runTaskLater(this.plugin, () -> {
ProtectedRegion region = this.worldGuardInterface.getRegionManager(world).getRegion(regionName);
if (region == null) {
future.completeExceptionally(new AreaShopCommandException("quickadd-failedCreateWGRegion"));
return;
}
future.complete(region);
}, 10);
return future;
}
}
@@ -0,0 +1,54 @@
package me.wiefferink.areashop.commands.util;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.RegionGroup;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.ArgumentParseResult;
import org.incendo.cloud.parser.ArgumentParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.incendo.cloud.suggestion.SuggestionProvider;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public class RegionGroupParser<C> implements ArgumentParser<C, RegionGroup>, SuggestionProvider<C> {
private final IFileManager fileManager;
private final String failureMessageKey;
public RegionGroupParser(@Nonnull IFileManager fileManager, @Nonnull String failureMessageKey) {
this.fileManager = fileManager;
this.failureMessageKey = failureMessageKey;
}
@Override
public @Nonnull ArgumentParseResult<RegionGroup> parse(
@Nonnull CommandContext<C> commandContext,
@Nonnull CommandInput commandInput
) {
String input = commandInput.peekString();
RegionGroup regionGroup = this.fileManager.getGroup(input);
if (regionGroup != null) {
commandInput.readString();
return ArgumentParseResult.success(regionGroup);
}
return ArgumentParseResult.failure(new AreaShopCommandException(this.failureMessageKey, input));
}
@Override
public @Nonnull CompletableFuture<Iterable<Suggestion>> suggestionsFuture(
@Nonnull CommandContext<C> context,
@Nonnull CommandInput input
) {
String text = input.peekString();
List<Suggestion> suggestions = this.fileManager.getGroupNames().stream()
.filter(name -> name.startsWith(text))
.map(Suggestion::suggestion)
.toList();
return CompletableFuture.completedFuture(suggestions);
}
}
@@ -0,0 +1,69 @@
package me.wiefferink.areashop.commands.util;
import me.wiefferink.areashop.MessageBridge;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import javax.annotation.Nonnull;
import java.util.HashSet;
import java.util.Set;
public class RegionInfoUtil {
public static void showRegionInfo(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager,
@Nonnull CommandSender sender,
@Nonnull OfflinePlayer owner
) {
// Get the regions owned by the player
Set<RentRegion> rentRegions = new HashSet<>();
for(RentRegion region : fileManager.getRentsRef()) {
if(region.isOwner(owner)) {
rentRegions.add(region);
}
}
Set<BuyRegion> buyRegions = new HashSet<>();
for(BuyRegion region : fileManager.getBuysRef()) {
if(region.isOwner(owner)) {
buyRegions.add(region);
}
}
// Get the regions the player is added as friend
Set<GeneralRegion> friendRegions = new HashSet<>();
for(GeneralRegion region : fileManager.getRegionsRef()) {
if(region.getFriendsFeature().getFriends().contains(owner.getUniqueId())) {
friendRegions.add(region);
}
}
// Send messages
boolean foundSome = !rentRegions.isEmpty() || !buyRegions.isEmpty() || !friendRegions.isEmpty();
if(!foundSome) {
messageBridge.message(sender, "me-nothing", owner.getName());
return;
}
messageBridge.message(sender, "me-header", owner.getName());
if(!rentRegions.isEmpty()) {
for(RentRegion region : rentRegions) {
messageBridge.messageNoPrefix(sender, "me-rentLine", region);
}
}
if(!buyRegions.isEmpty()) {
for(BuyRegion region : buyRegions) {
messageBridge.messageNoPrefix(sender, "me-buyLine", region);
}
}
if(!friendRegions.isEmpty()) {
for(GeneralRegion region : friendRegions) {
messageBridge.messageNoPrefix(sender, "me-friendLine", region);
}
}
messageBridge.messageNoPrefix(sender, "me-clickHint");
}
}
@@ -0,0 +1,165 @@
package me.wiefferink.areashop.commands.util;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.parser.flag.CommandFlag;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.List;
public final class RegionParseUtil {
private RegionParseUtil() {
throw new IllegalStateException("Cannot instantiate static utility class");
}
@Nonnull
public static CommandFlag<GeneralRegion> createDefault(@Nonnull IFileManager fileManager) {
return CommandFlag.builder("region")
.withComponent(GeneralRegionParser.generalRegionParser(fileManager))
.build();
}
@Nonnull
public static Collection<GeneralRegion> getOrParseRegionsInSel(
@Nonnull CommandContext<?> context,
@Nonnull CommandSender sender,
@Nonnull CommandFlag<GeneralRegion> regionFlag
) {
if (!(sender instanceof Player player)) {
throw new AreaShopCommandException("cmd-weOnlyByPlayer");
}
GeneralRegion declaredRegion = context.flags().get(regionFlag);
if (declaredRegion != null) {
return List.of(declaredRegion);
}
Location location = player.getLocation();
List<GeneralRegion> regions = Utils.getImportantRegions(location);
if (!regions.isEmpty()) {
return regions;
}
throw new AreaShopCommandException("cmd-noRegionsAtLocation");
}
@Nonnull
public static GeneralRegion getOrParseRegion(
@Nonnull CommandContext<?> context,
@Nonnull CommandSender sender,
@Nonnull CommandFlag<GeneralRegion> flag
) throws AreaShopCommandException {
GeneralRegion region = context.flags().get(flag);
if (region != null) {
return region;
}
if (!(sender instanceof Entity entity)) {
throw new AreaShopCommandException("cmd-automaticRegionOnlyByPlayer");
}
Location location = entity.getLocation();
List<GeneralRegion> regions = Utils.getImportantRegions(location);
String errorMessageKey;
if (regions.isEmpty()) {
errorMessageKey = "cmd-noRegionsAtLocation";
} else if (regions.size() > 1) {
errorMessageKey = "cmd-moreRegionsAtLocation";
} else {
return regions.getFirst();
}
throw new AreaShopCommandException(errorMessageKey);
}
@Nonnull
public static GeneralRegion getOrParseRegion(
@Nonnull CommandContext<?> context,
@Nonnull CommandSender sender,
@Nonnull CloudKey<GeneralRegion> key
) throws AreaShopCommandException {
GeneralRegion region = context.getOrDefault(key, null);
if (region != null) {
return region;
}
if (!(sender instanceof Entity entity)) {
throw new AreaShopCommandException("cmd-automaticRegionOnlyByPlayer");
}
Location location = entity.getLocation();
List<GeneralRegion> regions = Utils.getImportantRegions(location);
String errorMessageKey;
if (regions.isEmpty()) {
errorMessageKey = "cmd-noRegionsAtLocation";
} else if (regions.size() > 1) {
errorMessageKey = "cmd-moreRegionsAtLocation";
} else {
return regions.getFirst();
}
throw new AreaShopCommandException(errorMessageKey);
}
@Nonnull
public static CommandFlag<BuyRegion> createDefaultBuy(@Nonnull IFileManager fileManager) {
return CommandFlag.builder("region")
.withComponent(ParserDescriptor.of(new BuyRegionParser<>(fileManager), BuyRegion.class))
.build();
}
@Nonnull
public static CommandFlag<RentRegion> createDefaultRent(@Nonnull IFileManager fileManager) {
return CommandFlag.builder("region")
.withComponent(ParserDescriptor.of(new RentRegionParser<>(fileManager), RentRegion.class))
.build();
}
@Nonnull
public static BuyRegion getOrParseBuyRegion(
@Nonnull CommandContext<?> context,
@Nonnull CommandSender sender,
@Nonnull CommandFlag<BuyRegion> flag) {
BuyRegion buyRegion = context.flags().get(flag);
if (buyRegion != null) {
return buyRegion;
}
if (!(sender instanceof Player player)) {
throw new AreaShopCommandException("cmd-automaticRegionOnlyByPlayer");
}
List<BuyRegion> regions = Utils.getImportantBuyRegions(player.getLocation());
if (regions.isEmpty()) {
throw new AreaShopCommandException("cmd-noRegionsAtLocation");
} else if (regions.size() != 1) {
throw new AreaShopCommandException("cmd-moreRegionsAtLocation");
}
return regions.getFirst();
}
@Nonnull
public static RentRegion getOrParseRentRegion(
@Nonnull CommandContext<?> context,
@Nonnull CommandSender sender,
@Nonnull CommandFlag<RentRegion> flag) {
RentRegion rentRegion = context.flags().get(flag);
if (rentRegion != null) {
return rentRegion;
}
if (!(sender instanceof Player player)) {
throw new AreaShopCommandException("cmd-automaticRegionOnlyByPlayer");
}
List<RentRegion> regions = Utils.getImportantRentRegions(player.getLocation());
if (regions.isEmpty()) {
throw new AreaShopCommandException("cmd-noRegionsAtLocation");
} else if (regions.size() != 1) {
throw new AreaShopCommandException("cmd-moreRegionsAtLocation");
}
return regions.getFirst();
}
}
@@ -0,0 +1,55 @@
package me.wiefferink.areashop.commands.util;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.RentRegion;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.ArgumentParseResult;
import org.incendo.cloud.parser.ArgumentParser;
import org.incendo.cloud.suggestion.SuggestionProvider;
import javax.annotation.Nonnull;
public class RentRegionParser<C> implements ArgumentParser<C, RentRegion> {
private final IFileManager fileManager;
private final SuggestionProvider<C> suggestionProvider;
public RentRegionParser(@Nonnull IFileManager fileManager, @Nonnull SuggestionProvider<C> suggestionProvider) {
this.fileManager = fileManager;
this.suggestionProvider = suggestionProvider;
}
public RentRegionParser(@Nonnull IFileManager fileManager) {
this(fileManager, defaultSuggestionProvider(fileManager));
}
private static <C> SuggestionProvider<C> defaultSuggestionProvider(@Nonnull IFileManager fileManager) {
return SuggestionProvider.blockingStrings((ctx, input) -> {
String text = input.peekString();
return fileManager.getRentNames()
.stream()
.filter(name -> name.startsWith(text))
.toList();
}
);
}
@Override
public @Nonnull ArgumentParseResult<RentRegion> parse(@Nonnull CommandContext<C> commandContext,
@Nonnull CommandInput commandInput) {
String input = commandInput.peekString();
RentRegion region = this.fileManager.getRent(input);
if (region != null) {
commandInput.readString();
return ArgumentParseResult.success(region);
}
AreaShopCommandException exception = new AreaShopCommandException("rent-notRentable", input);
return ArgumentParseResult.failure(exception);
}
@Override
public @Nonnull SuggestionProvider<C> suggestionProvider() {
return this.suggestionProvider;
}
}
@@ -0,0 +1,69 @@
package me.wiefferink.areashop.commands.util;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.plugin.Plugin;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.parser.standard.StringParser;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
import java.util.function.Supplier;
public final class SignProfileUtil {
public static final CommandFlag<String> DEFAULT_FLAG = CommandFlag.builder("profile")
.withComponent(StringParser.stringParser(StringParser.StringMode.SINGLE))
.build();
private SignProfileUtil() {
throw new IllegalArgumentException("Static utility class cannot be instantiated");
}
@Nonnull
public static CommandFlag<String> createDefault(@Nonnull Plugin plugin) {
Supplier<Collection<String>> valueSupplier = () -> {
ConfigurationSection section = plugin.getConfig().getConfigurationSection("signProfiles");
if (section == null) {
return Collections.emptyList();
}
return section.getKeys(false);
};
return CommandFlag.builder("profile")
.withComponent(
ParserDescriptor.of(
AcceptedValuesParser.of(valueSupplier, "addsign-wrongProfile", false),
String.class)
)
.build();
}
@Nullable
public static String getOrParseProfile(@Nonnull CommandContext<?> context,
@Nonnull Plugin plugin) {
return getOrParseProfile(context, DEFAULT_FLAG, plugin);
}
@Nullable
public static String getOrParseProfile(
@Nonnull CommandContext<?> context,
@Nonnull CommandFlag<String> flag,
@Nonnull Plugin plugin
) throws AreaShopCommandException {
String profile = context.flags().get(flag);
if (profile == null) {
return null;
}
Set<String> profiles = plugin.getConfig().getConfigurationSection("signProfiles").getKeys(false);
if (profiles.contains(profile.toLowerCase(Locale.ENGLISH))) {
return profile.toLowerCase(Locale.ENGLISH);
}
throw new AreaShopCommandException("addsign-wrongProfile");
}
}
@@ -0,0 +1,39 @@
package me.wiefferink.areashop.commands.util;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.incendo.cloud.bukkit.parser.WorldParser;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.parser.flag.CommandFlag;
import javax.annotation.Nonnull;
public final class WorldFlagUtil {
public static final CommandFlag<World> DEFAULT_WORLD_FLAG = CommandFlag.builder("world")
.withComponent(WorldParser.worldParser())
.build();
private WorldFlagUtil() {
throw new IllegalStateException("Cannot instantiate static util class");
}
@Nonnull
public static World parseOrDetectWorld(@Nonnull CommandContext<?> context, @Nonnull Entity sender) {
return parseOrDetectWorld(context, sender, DEFAULT_WORLD_FLAG);
}
@Nonnull
public static World parseOrDetectWorld(
@Nonnull CommandContext<?> context,
@Nonnull Entity sender,
@Nonnull CommandFlag<World> flag
) {
World world = context.flags().get(flag);
if (world != null) {
return world;
}
return sender.getWorld();
}
}
@@ -0,0 +1,73 @@
package me.wiefferink.areashop.commands.util;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import me.wiefferink.areashop.commands.util.commandsource.EntityCommandSource;
import me.wiefferink.areashop.interfaces.WorldGuardInterface;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.ArgumentParseResult;
import org.incendo.cloud.parser.ArgumentParser;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.suggestion.SuggestionProvider;
import javax.annotation.Nonnull;
import java.util.Collections;
public class WorldGuardRegionParser<C extends EntityCommandSource> implements ArgumentParser<C, ProtectedRegion> {
private final WorldGuardInterface worldGuardInterface;
private final CommandFlag<World> worldFlag;
public WorldGuardRegionParser(
@Nonnull CommandFlag<World> worldFlag,
@Nonnull WorldGuardInterface worldGuardInterface
) {
this.worldFlag = worldFlag;
this.worldGuardInterface = worldGuardInterface;
}
public static <C extends EntityCommandSource> ParserDescriptor<C, ProtectedRegion> worldGuardRegionParser(
@Nonnull CommandFlag<World> worldFlag,
@Nonnull WorldGuardInterface worldGuardInterface
) {
return ParserDescriptor.of(new WorldGuardRegionParser<>(worldFlag, worldGuardInterface), ProtectedRegion.class);
}
@Override
public @Nonnull ArgumentParseResult<ProtectedRegion> parse(@Nonnull CommandContext<C> commandContext,
@Nonnull CommandInput commandInput) {
Entity sender = commandContext.sender().sender();
World world = WorldFlagUtil.parseOrDetectWorld(commandContext, sender, worldFlag);
String regionName = commandInput.peekString();
RegionManager regionManager = this.worldGuardInterface.getRegionManager(world);
if (regionManager == null) {
return ArgumentParseResult.failure(new IllegalArgumentException("No region manager for world: " + world.getName()));
}
ProtectedRegion protectedRegion = regionManager.getRegion(regionName);
if (protectedRegion != null) {
commandInput.readString();
return ArgumentParseResult.success(protectedRegion);
}
AreaShopCommandException exception = new AreaShopCommandException("cmd-noRegion", regionName);
return ArgumentParseResult.failure(exception);
}
@Override
public @Nonnull SuggestionProvider<C> suggestionProvider() {
return SuggestionProvider.blockingStrings((commandContext, input) -> {
Entity sender = commandContext.sender().sender();
if (!(sender instanceof Player player)) {
return Collections.emptyList();
}
return this.worldGuardInterface.getRegionManager(player.getWorld()).getRegions()
.values()
.stream()
.map(ProtectedRegion::getId)
.toList();
});
}
}
@@ -0,0 +1,23 @@
package me.wiefferink.areashop.commands.util;
import me.wiefferink.areashop.interfaces.WorldEditInterface;
import me.wiefferink.areashop.interfaces.WorldEditSelection;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.yaml.snakeyaml.parser.ParserException;
import javax.annotation.Nonnull;
public record WorldSelection(@Nonnull World world, @Nonnull WorldEditSelection selection) {
public static WorldSelection fromPlayer(@Nonnull Player player,
@Nonnull WorldEditInterface worldEditInterface) throws ParserException {
WorldEditSelection selection = worldEditInterface.getPlayerSelection(player);
if (selection == null) {
throw new AreaShopCommandException("cmd-noSelection");
}
World world = selection.getWorld();
return new WorldSelection(world, selection);
}
}
@@ -0,0 +1,16 @@
package me.wiefferink.areashop.commands.util.commandsource;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import org.bukkit.command.CommandSender;
import javax.annotation.Nonnull;
public interface CommandSource<C extends CommandSender> {
@Nonnull
CommandSourceStack sourceStack();
@Nonnull
C sender();
}
@@ -0,0 +1,27 @@
package me.wiefferink.areashop.commands.util.commandsource;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.SenderMapper;
public class CommandSourceMapper implements SenderMapper<CommandSourceStack, CommandSource<?>> {
@Override
public @NonNull CommandSource<?> map(@NonNull CommandSourceStack base) {
CommandSender sender = base.getSender();
if (sender instanceof Player) {
return new PlayerCommandSource(base);
} else if (sender instanceof Entity) {
return new EntityCommandSource(base);
}
return new GenericCommandSource(base);
}
@Override
public @NonNull CommandSourceStack reverse(@NonNull CommandSource<?> mapped) {
return mapped.sourceStack();
}
}
@@ -0,0 +1,15 @@
package me.wiefferink.areashop.commands.util.commandsource;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import org.bukkit.command.CommandSender;
import javax.annotation.Nonnull;
public record CommandSourceWrapper(@Nonnull CommandSourceStack commandSourceStack) {
@Nonnull
public CommandSender sender() {
return commandSourceStack().getSender();
}
}
Loaded 100 of 249 files, more files were not shown because too many files have changed in this diff. Show more