Compare commits

..
419 Commits
Author SHA1 Message Date
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
263 changed files with 15375 additions and 10583 deletions

No files matched your search

+1 -1
View File
@@ -2,7 +2,7 @@
name: Bug report
about: Report a problem in the plugin
title: ''
labels: 'Type: Bug'
labels: 'NEW, Type: Bug'
assignees: ''
---
+1 -1
View File
@@ -2,7 +2,7 @@
name: Feature request
about: Suggest an idea
title: ''
labels: 'Type: Feature'
labels: 'NEW, Type: Feature'
assignees: ''
---
+1 -1
View File
@@ -2,7 +2,7 @@
name: Support question
about: Ask help with the setup or usage of the plugin
title: ''
labels: 'Type: Support'
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.9") {
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.20.4-R0.1-SNAPSHOT")
testImplementation("com.github.seeseemelk:MockBukkit-v1.20:3.86.1")
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")
downloadPlugins {
github("EssentialsX", "essentials", "2.20.1", "EssentialsX-2.20.1.jar")
github("MilkBowl", "Vault", "1.7.3", "Vault.jar")
// WorldEdit 7.3.3
url("https://mediafilez.forgecdn.net/files/5400/331/worldedit-bukkit-7.3.3.jar")
// WorldGuard 7.0.10
url("https://mediafilez.forgecdn.net/files/5344/377/worldguard-bukkit-7.0.10-dist.jar")
}
}
}
-311
View File
@@ -1,311 +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.6.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+ -->
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<scope>system</scope>
<version>any</version>
<systemPath>${project.basedir}/../dependencies/craftbukkit-1.7.9-R0.2-SNAPSHOT.jar</systemPath>
<type>jar</type>
<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>
<!-- WorldEdit/WorldGuard -->
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>worldedit</artifactId>
<scope>system</scope>
<version>any</version>
<systemPath>${project.basedir}/../dependencies/worldedit-bukkit-7.0.0-beta-04.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-beta-02.jar</systemPath>
</dependency>
<!-- Interfaces that specific WorldGuard and WorldEdit versions are built against -->
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-interface</artifactId>
<version>latest</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<!-- WorldGuard implementations -->
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-5</artifactId>
<version>latest</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-6</artifactId>
<version>latest</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-6_1_3</artifactId>
<version>latest</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-7_beta_1</artifactId>
<version>latest</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-7_beta_2</artifactId>
<version>latest</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<!-- WorldEdit implementations -->
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldedit-5</artifactId>
<version>latest</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldedit-6</artifactId>
<version>latest</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldedit-7_beta_1</artifactId>
<version>latest</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldedit-7_beta_4</artifactId>
<version>latest</version>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-fastasyncworldedit</artifactId>
<version>latest</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<!-- Vault -->
<dependency>
<groupId>net.milkbowl.vault</groupId>
<artifactId>VaultAPI</artifactId>
<scope>system</scope>
<version>any</version>
<systemPath>${project.basedir}/../dependencies/VaultAPI-1.4.jar</systemPath>
</dependency>
<!-- bStats -->
<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,40 @@
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.FeatureManager;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.managers.FileManager;
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,38 +51,48 @@ 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 java.util.Arrays;
import javax.annotation.Nonnull;
import java.io.File;
import java.io.IOException;
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 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";
@@ -73,6 +101,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
@@ -142,249 +171,161 @@ 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));
// Find WorldEdit integration version to load
String weVersion = null;
String rawWeVersion = null;
String weBeta = null;
Plugin plugin = getServer().getPluginManager().getPlugin("WorldEdit");
if(!(plugin instanceof WorldEditPlugin) || !plugin.isEnabled()) {
error("WorldEdit plugin is not present or has not loaded correctly");
error = true;
// 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;
}
final MinecraftPlatform platform;
if (PaperLib.isPaper()) {
platform = new PaperPlatform(this);
info("Detected Paper; using the PaperPlatform impl");
} else {
worldEdit = (WorldEditPlugin)plugin;
rawWeVersion = worldEdit.getDescription().getVersion();
// Find beta version
Pattern pattern = Pattern.compile("beta-?\\d+");
Matcher matcher = pattern.matcher(rawWeVersion);
if (matcher.find()) {
weBeta = matcher.group();
}
// 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 if ("beta-01".equalsIgnoreCase(weBeta)) {
weVersion = "7_beta_1";
} else {
// beta-02 and beta-03 also have the new vector system already
weVersion = "7_beta_4";
}
weVersion = "WorldEditHandler" + weVersion;
}
// Find WorldGuard integration version to load
String wgVersion = null;
String rawWgVersion = null;
int major = 0;
int minor = 0;
int fixes = 0;
Integer build = null;
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 {
rawWgVersion = worldGuard.getDescription().getVersion();
if(rawWgVersion.contains("-SNAPSHOT;")) {
String buildNumber = rawWgVersion.substring(rawWgVersion.indexOf("-SNAPSHOT;") + 10);
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: " + rawWgVersion + ", buildNumber: " + buildNumber);
}
}
}
// Clear stuff from the version string that is not a number
String[] versionParts = rawWgVersion.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: " + rawWgVersion);
}
// Determine correct implementation to use
if(rawWgVersion.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 if ("beta-01".equalsIgnoreCase(weBeta)) {
// When using WorldEdit beta-01, we need to use the WorldGuard variant with the old vector system
wgVersion = "7_beta_1";
} else {
// Even though the WorldGuard file is called beta-02, the reported version is still beta-01!
wgVersion = "7_beta_2";
}
} catch(Exception e) { // If version detection fails, at least try to load the latest version
warn("Parsing the WorldGuard version failed, assuming version 7_beta_2:", rawWgVersion);
wgVersion = "7_beta_2";
}
wgVersion = "WorldGuardHandler" + wgVersion;
}
// Check if FastAsyncWorldEdit is installed
boolean fawe;
try {
Class.forName("com.boydti.fawe.Fawe" );
fawe = true;
} catch (ClassNotFoundException ignore) {
fawe = false;
}
if (fawe) {
boolean useNewIntegration = true;
List<String> standardIntegrationVersions = Arrays.asList("1.7", "1.8", "1.9", "1.10", "1.11", "1.12");
for(String standardIntegrationVersion : standardIntegrationVersions) {
String version = Bukkit.getBukkitVersion();
// Detects '1.8', '1.8.3', '1.8-pre1' style versions
if(version.equals(standardIntegrationVersion)
|| version.startsWith(standardIntegrationVersion + ".")
|| version.startsWith(standardIntegrationVersion + "-")) {
useNewIntegration = false;
break;
}
}
if (useNewIntegration) {
weVersion = "FastAsyncWorldEditHandler";
wgVersion = "FastAsyncWorldEditWorldGuardHandler";
}
}
// Load WorldEdit
try {
final Class<?> clazz = Class.forName("me.wiefferink.areashop.handlers." + 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;
}
// Load WorldGuard
try {
final Class<?> clazz = Class.forName("me.wiefferink.areashop.handlers." + 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;
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:" + rawWgVersion + ", major:" + major + ", minor:" + minor + ", fixes:" + fixes + ", build:" + build + ")");
}
if(weVersion != null) {
AreaShop.debug("Loaded WorldEditHandler", weVersion, "(raw version:" + rawWeVersion + ", beta:" + weBeta + ")");
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);
// 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);
// 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);
}
});
}
}
@@ -394,10 +335,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
@@ -422,6 +387,7 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
/**
* Called on shutdown or reload of the server.
*/
@Override
public void onDisable() {
Bukkit.getServer().getScheduler().cancelTasks(this);
@@ -430,27 +396,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
@@ -475,16 +432,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")
);
}
@@ -496,10 +490,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;
}
@@ -512,6 +511,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
@@ -525,10 +530,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
@@ -545,19 +556,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;
}
@@ -567,17 +572,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;
}
@@ -588,9 +601,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();
@@ -623,7 +636,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;
}
@@ -653,6 +666,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;
@@ -728,26 +748,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.
@@ -771,16 +771,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, " "));
}
/**
@@ -788,7 +796,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, " "));
}
/**
@@ -796,7 +804,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, " "));
}
/**
@@ -818,7 +826,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,302 +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().containsOwner(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());
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
);
}
AreaShop.debug("regionAddLandlordStatus:", regionName,
"landlord:", landlord,
"existing:", existing,
"isMember:", isMember,
"isOwner:", isOwner,
"createPermission:", sender.hasPermission("areashop.create" + type),
"ownerPermission:", sender.hasPermission("areashop.create" + type + ".owner"),
"memberPermission:", sender.hasPermission("areashop.create" + type + ".member"));
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);
}
}
}
}
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 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"));
}
rent.update();
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.CREATED, false);
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 existing owners/members if any
if(!landlord && !existing.isEmpty()) {
// TODO also execute rent events to notify other plugins?
AddingRegionEvent event = plugin.getFileManager().addRegion(rent);
if (event.isCancelled()) {
namesAddCancelled.add(rent.getName());
return;
}
rent.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
rent.update();
// Run commands
rent.runEventCommands(GeneralRegion.RegionEvent.RENTED, true);
// Add existing owners/members if any
if (!landlord && !existing.isEmpty()) {
UUID rentBy = existing.removeFirst();
OfflinePlayer rentByPlayer = Bukkit.getOfflinePlayer(rentBy);
// Add values to the rent and send it to FileManager
rent.setRentedUntil(Calendar.getInstance().getTimeInMillis() + rent.getDuration());
rent.setRenter(existing.remove(0));
rent.updateLastActiveTime();
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();
// Add others as friends
for(UUID friend : existing) {
rent.getFriendsFeature().addFriend(friend, null);
}
// Fire schematic event and updated times extended
rent.handleSchematicEvent(GeneralRegion.RegionEvent.RENTED);
// Fire schematic event and updated times extended
rent.handleSchematicEvent(GeneralRegion.RegionEvent.RENTED);
// Add others as friends
for (UUID friend : existing) {
rent.getFriendsFeature().addFriend(friend, null);
}
// Notify about updates
rent.update();
rent.notifyAndUpdate(new RentedRegionEvent(rent, false));
}
}
rent.runEventCommands(GeneralRegion.RegionEvent.RENTED, false);
}
regionsSuccess.add(rent);
}
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);
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());
}
plugin.getFileManager().addBuy(buy);
buy.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
AddingRegionEvent event = plugin.getFileManager().addRegion(buy);
if (event.isCancelled()) {
namesAddCancelled.add(buy.getName());
return;
}
buy.update();
buy.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
buy.update();
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
// Add existing owners/members if any
if (!landlord && !existing.isEmpty()) {
UUID buyBy = existing.removeFirst();
OfflinePlayer buyByPlayer = Bukkit.getOfflinePlayer(buyBy);
// Add existing owners/members if any
if(!landlord && !existing.isEmpty()) {
// TODO also execute buy events to notify for other plugins?
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();
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.BOUGHT, true);
// Update everything
buy.handleSchematicEvent(GeneralRegion.RegionEvent.BOUGHT);
// Set the owner
buy.setBuyer(existing.remove(0));
buy.updateLastActiveTime();
// Add others as friends
for(UUID friend : existing) {
buy.getFriendsFeature().addFriend(friend, null);
}
// Add others as friends
for (UUID friend : existing) {
buy.getFriendsFeature().addFriend(friend, null);
}
// Notify about updates
buy.update();
buy.notifyAndUpdate(new BoughtRegionEvent(buy));
}
}
// Update everything
buy.handleSchematicEvent(GeneralRegion.RegionEvent.BOUGHT);
regionsSuccess.add(buy);
}
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.BOUGHT, false);
}
@Override
public String stringDescription() {
return "Add a region";
}
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");
}
}
);
}
public String getHelp(CommandSender target) {
if (target.hasPermission("areashop.createrent")
|| target.hasPermission("areashop.createrent.member")
|| target.hasPermission("areashop.createrent.owner")
@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;
}
|| 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,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.RegionParseUtil;
import me.wiefferink.areashop.commands.util.ValidatedOfflinePlayerParser;
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.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<OfflinePlayer> KEY_FRIEND = CloudKey.of("friend", OfflinePlayer.class);
private final CommandFlag<GeneralRegion> regionFlag;
private final MessageBridge messageBridge;
private final Plugin plugin;
@Inject
public AddFriendCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager,
@Nonnull Plugin plugin
) {
this.messageBridge = messageBridge;
this.plugin = plugin;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
}
@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, ValidatedOfflinePlayerParser.validatedOfflinePlayerParser())
.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);
OfflinePlayer friend = context.get(KEY_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,126 +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.Materials;
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 || !Materials.isSign(block.getType())) {
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,168 @@
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.ValidatedOfflinePlayerParser;
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 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<OfflinePlayer> KEY_PLAYER = CloudKey.of("player", OfflinePlayer.class);
private final MessageBridge messageBridge;
private final CommandFlag<GeneralRegion> regionFlag;
@Inject
public DelFriendCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
}
/**
* 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, ValidatedOfflinePlayerParser.validatedOfflinePlayerParser(), 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);
OfflinePlayer friend = context.get(KEY_PLAYER);
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,79 +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.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 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 || !Materials.isSign(block.getType())) {
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(), "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,95 @@
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.RegionInfoUtil;
import me.wiefferink.areashop.commands.util.ValidatedOfflinePlayerParser;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import org.bukkit.OfflinePlayer;
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<OfflinePlayer> KEY_PLAYER = CloudKey.of("player", OfflinePlayer.class);
private final MessageBridge messageBridge;
private final IFileManager fileManager;
@Inject
public InfoPlayerCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
}
@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, ValidatedOfflinePlayerParser.validatedOfflinePlayerParser())
.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;
}
OfflinePlayer offlinePlayer = context.get(KEY_PLAYER);
RegionInfoUtil.showRegionInfo(this.messageBridge, this.fileManager, sender, offlinePlayer);
}
}
@@ -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,78 @@
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 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.RegionInfoUtil;
import me.wiefferink.areashop.commands.util.ValidatedOfflinePlayerParser;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.commands.util.commandsource.PlayerCommandSource;
import me.wiefferink.areashop.managers.IFileManager;
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.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<OfflinePlayer> KEY_PLAYER = CloudKey.of("player", OfflinePlayer.class);
private final IFileManager fileManager;
private final MessageBridge messageBridge;
@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
) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
}
@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, ValidatedOfflinePlayerParser.validatedOfflinePlayerParser())
.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");
}
OfflinePlayer player = context.getOrDefault(KEY_PLAYER, sender);
RegionInfoUtil.showRegionInfo(this.messageBridge, this.fileManager, sender, player);
}
@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,129 @@
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.ArgumentParseExceptionHandler;
import me.wiefferink.areashop.commands.util.RegionCreationUtil;
import me.wiefferink.areashop.commands.util.ValidatedOfflinePlayerParser;
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.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.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<OfflinePlayer> KEY_LANDLORD = CloudKey.of("landlord", OfflinePlayer.class);
private final RegionFactory regionFactory;
private final IFileManager fileManager;
private final MessageBridge messageBridge;
private final RegionCreationUtil regionCreationUtil;
private final BukkitSchedulerExecutor executor;
@Inject
public QuickBuyCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull RegionFactory regionFactory,
@Nonnull IFileManager fileManager,
@Nonnull RegionCreationUtil regionCreationUtil,
@Nonnull BukkitSchedulerExecutor executor
) {
this.messageBridge = messageBridge;
this.regionFactory = regionFactory;
this.fileManager = fileManager;
this.regionCreationUtil = regionCreationUtil;
this.executor = executor;
}
@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, ValidatedOfflinePlayerParser.validatedOfflinePlayerParser())
.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);
OfflinePlayer landlord = context.get(KEY_LANDLORD);
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);
}
@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,136 @@
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.ArgumentParseExceptionHandler;
import me.wiefferink.areashop.commands.util.DurationInputParser;
import me.wiefferink.areashop.commands.util.RegionCreationUtil;
import me.wiefferink.areashop.commands.util.ValidatedOfflinePlayerParser;
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.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.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<OfflinePlayer> KEY_LANDLORD = CloudKey.of("landlord", OfflinePlayer.class);
private final RegionFactory regionFactory;
private final IFileManager fileManager;
private final MessageBridge messageBridge;
private final RegionCreationUtil regionCreationUtil;
private final BukkitSchedulerExecutor executor;
@Inject
public QuickRentCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull RegionFactory regionFactory,
@Nonnull IFileManager fileManager,
@Nonnull RegionCreationUtil regionCreationUtil,
@Nonnull BukkitSchedulerExecutor executor
) {
this.messageBridge = messageBridge;
this.regionFactory = regionFactory;
this.fileManager = fileManager;
this.regionCreationUtil = regionCreationUtil;
this.executor = executor;
}
@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, ValidatedOfflinePlayerParser.validatedOfflinePlayerParser())
.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);
OfflinePlayer landlord = context.get(KEY_LANDLORD);
if (!landlord.isOnline() && !landlord.hasPlayedBefore()) {
this.messageBridge.message(player, "me-noPlayer");
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);
}
@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,82 @@
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.ValidatedOfflinePlayerParser;
import me.wiefferink.areashop.commands.util.commandsource.CommandSource;
import me.wiefferink.areashop.managers.IFileManager;
import me.wiefferink.areashop.regions.GeneralRegion;
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;
@Singleton
public class SetLandlordCommand extends AreashopCommandBean {
private static final CloudKey<OfflinePlayer> KEY_PLAYER = CloudKey.of("player", OfflinePlayer.class);
private final MessageBridge messageBridge;
private final CommandFlag<GeneralRegion> regionFlag;
@Inject
public SetLandlordCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
}
@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, ValidatedOfflinePlayerParser.validatedOfflinePlayerParser())
.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);
OfflinePlayer player = context.get(KEY_PLAYER);
String playerName = player.getName();
region.setLandlord(player.getUniqueId(), playerName);
region.update();
this.messageBridge.message(sender, "setlandlord-success", playerName, region);
}
}
@@ -0,0 +1,123 @@
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.ValidatedOfflinePlayerParser;
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.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<OfflinePlayer> KEY_PLAYER = CloudKey.of("player", OfflinePlayer.class);
private final CommandFlag<GeneralRegion> regionFlag;
private final MessageBridge messageBridge;
@Inject
public SetOwnerCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.regionFlag = RegionParseUtil.createDefault(fileManager);
}
@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, ValidatedOfflinePlayerParser.validatedOfflinePlayerParser())
.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;
}
OfflinePlayer player = context.get(KEY_PLAYER);
if (!player.hasPlayedBefore()) {
this.messageBridge.message(sender, "setowner-noPlayer", player.getName(), region);
return;
}
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 == 3) {
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"));
} else if(toComplete == 4) {
result = plugin.getFileManager().getRentNames();
}
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;
}
}
@@ -2,251 +2,284 @@ package me.wiefferink.areashop.commands;
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 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);
}
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)
Vector minimum = minimumVector.clone().add(finalShift.clone().multiply(current));
Vector maximum = maximumVector.clone().add(finalShift.clone().multiply(current));
// Check for out of bounds
if(minimum.getBlockY() < 0) {
tooLow++;
continue;
} else if(maximum.getBlockY() > 256) {
tooHigh++;
continue;
}
ProtectedCuboidRegion region = plugin.getWorldGuardHandler().createCuboidRegion(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,143 @@
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.ValidatedOfflinePlayerParser;
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<OfflinePlayer> KEY_PLAYER = CloudKey.of("player", OfflinePlayer.class);
private final MessageBridge messageBridge;
private final IFileManager fileManager;
private final CommandFlag<GeneralRegion> regionFlag;
@Inject
public TransferCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager
) {
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();
}
@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, ValidatedOfflinePlayerParser.validatedOfflinePlayerParser())
.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");
}
OfflinePlayer targetPlayer = context.get(KEY_PLAYER);
String targetPlayerName = targetPlayer.getName();
if (Objects.equals(sender, targetPlayer)) {
throw new AreaShopCommandException("transfer-transferSelf");
}
if (!targetPlayer.hasPlayedBefore()) {
// 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,176 @@
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.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
);
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(ArgumentParseException.class,
ExceptionHandler.unwrappingHandler(AreaShopCommandException.class));
exceptionController.registerHandler(CommandExecutionException.class,
ExceptionHandler.unwrappingHandler(AreaShopCommandException.class));
exceptionController.registerHandler(InvalidCommandSenderException.class,
new InvalidCommandSenderHandler(this.messageBridge));
exceptionController.registerHandler(AreaShopCommandException.class,
new ArgumentParseExceptionHandler<>(this.messageBridge));
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,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,64 @@
package me.wiefferink.areashop.commands.util;
import org.bukkit.Bukkit;
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.bukkit.BukkitCommandContextKeys;
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;
import java.util.Collections;
public class ValidatedOfflinePlayerParser<C> implements ArgumentParser<C, OfflinePlayer>, BlockingSuggestionProvider.Strings<C> {
public static <C> ParserDescriptor<C, OfflinePlayer> validatedOfflinePlayerParser() {
return ParserDescriptor.of(new ValidatedOfflinePlayerParser<>(), OfflinePlayer.class);
}
@Override
@SuppressWarnings("deprecation")
public @NonNull ArgumentParseResult<OfflinePlayer> parse(
final @NonNull CommandContext<C> commandContext,
final @NonNull CommandInput commandInput
) {
final String input = commandInput.readString();
if (input.length() > 16) {
return ArgumentParseResult.failure(new AreaShopCommandException("cmd-invalidPlayer", input));
}
final Player onlinePlayer = Bukkit.getPlayerExact(input);
if (onlinePlayer != null) {
return ArgumentParseResult.success(onlinePlayer);
}
final OfflinePlayer player;
try {
player = Bukkit.getOfflinePlayer(input);
} catch (final Exception e) {
return ArgumentParseResult.failure(new AreaShopCommandException("cmd-invalidPlayer", input));
}
if (!player.hasPlayedBefore()) {
return ArgumentParseResult.failure(new AreaShopCommandException("cmd-invalidPlayer", input));
}
return ArgumentParseResult.success(player);
}
@Override
public @NonNull Iterable<@NonNull String> stringSuggestions(
final @NonNull CommandContext<C> commandContext,
final @NonNull CommandInput input
) {
if (!commandContext.contains(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER)) {
return Collections.emptyList();
}
final CommandSender sender = commandContext.get(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER);
return Bukkit.getOnlinePlayers().stream()
.filter(onlinePlayer -> !(sender instanceof Player player && !((Player) sender).canSee(player)))
.map(Player::getName)
.toList();
}
}
@@ -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();
}
}
@@ -0,0 +1,23 @@
package me.wiefferink.areashop.commands.util.commandsource;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
public sealed class EntityCommandSource extends GenericCommandSource permits PlayerCommandSource {
public EntityCommandSource(@Nonnull CommandSourceStack sourceStack) {
super(sourceStack);
if (!(sourceStack.getSender() instanceof Entity)) {
throw new IllegalArgumentException("Source stack sender is not an entity!");
}
}
@NotNull
@Override
public Entity sender() {
return (Entity) super.sender();
}
}
Loaded 100 of 263 files, more files were not shown because too many files have changed in this diff. Show more