Compare commits

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

Signed-off-by: dependabot[bot] <support@github.com>
2020-02-26 11:02:43 +01:00
Thijs Wiefferink b9547e2c67 Remove github action experiment 2019-08-16 18:22:19 +02:00
Thijs Wiefferink 221785ae55 Add test workflow maven build 2019-08-16 17:42:22 +02:00
Thijs Wiefferink 0d04676bce Fix including bukkit into the AreaShop jar 2019-06-23 22:27:35 +02:00
Thijs Wiefferink c8cd68c17b Fixup javadoc build 2019-06-23 22:07:34 +02:00
Thijs Wiefferink 539887449c pom.xml: build with craftbukkit 1.13 2019-06-23 21:59:04 +02:00
Thijs Wiefferink 4cda8a9292 Fix sign handling for 1.14
- Setup modules to load different classes for different Bukkit/Spigot versions
- Create BukkitHandler to get/set the sign facing and get the block it is attached to
- Fix `/as addsign` to use new sign methods
- Fix sign updates to use new sign methods
- Implement full forwards and backwards compatibility of the saved sign material type
    - On Bukkit 1.12 and lower all special wood types are translated to the standard sign
    - On Bukkit 1.13 the internal sign name is translated (and special wood types to the standard one)
    - On Bukkit 1.14 the signs of 1.13- are translated to the OAK variants
- Cleanup the .gitignore files inside of the module folders
2019-06-23 21:53:48 +02:00
Thijs Wiefferink fe131dc157 BuyRegion/RentRegion: fix %player% placeholders for selling/unrenting confirmation messages 2019-06-16 21:40:58 +02:00
Thijs Wiefferink 41ced9ee6c Update checkstyle from 7.6 to 8.21 2019-06-01 17:08:30 +02:00
Thijs Wiefferink 03de0ff252 default.yml: fix spelling mistake 2019-06-01 16:24:15 +02:00
Thijs Wiefferink b057271394 Fix permission check of /as rent, fix 'already bought' check of /as buy 2019-02-20 19:33:37 +01:00
Thijs Wiefferink d7cdff0b22 /as setteleport: fix check that hides it from /as help 2019-02-08 22:29:57 +01:00
Thijs Wiefferink 1035b6b41b Move event commands to a feature class, add two events
- Move eventCommandProfile code to a separate class
- Add AddingRegionEvent
- Add DeletingRegionEvent
- Cleanup a couple of duplicate code paths (merge RentRegion/BuyRegion branches)
2019-01-28 23:37:43 +01:00
Thijs Wiefferink e0bad7397c Refactoring based on SonarLint and Intellij IDEA inspections 2019-01-26 21:23:49 +01:00
Thijs Wiefferink b7124e8cdd Remove mcstats.org metrics class, I don't believe they will be online again 2019-01-26 20:11:26 +01:00
Thijs Wiefferink f0952c32c9 Update issue templates
Add 'NEW' label to issues created using the template
2019-01-13 22:26:54 +01:00
Thijs Wiefferink d3dfa86a65 Set version to 2.6.0 2019-01-13 17:34:50 +01:00
Thijs Wiefferink 8f73b8af3c documentation/release.md: add instructions for releasing a new version 2019-01-13 17:34:37 +01:00
Thijs Wiefferink 51b24c74b4 langHeader.yml: add the template used to generate the language file headers to the repository 2019-01-13 17:33:54 +01:00
Thijs Wiefferink 9beb1eb61b Move the changelog from the wiki to the repository 2019-01-13 17:33:09 +01:00
Thijs Wiefferink de5fdafca0 Pull translations from Transifex 2019-01-08 21:18:19 +01:00
Thijs Wiefferink 0aea914d20 Add FastAsyncWorldEdit support on Spigot 1.13
- FastAsyncWorldEdit now supported on Spigot 1.13
- Improved support for the beta-01 versions of WorldGuard and WorldEdit
- Resolves #436
2019-01-08 00:19:48 +01:00
Thijs Wiefferink b4efe7d5bf Add default labels to issue templates 2019-01-05 16:27:05 +01:00
Thijs Wiefferink ec7983e126 Fix handling of sign updates at places where they will pop off immediately
1. When placing back a missing sign it could be placed in the middle of the air
2. BlockPhysicsEvent would fire immediately (synchronously) breaking the sign
3. Sign update would break because the sign has not actually been placed
2019-01-01 19:32:34 +01:00
Thijs Wiefferink e45c353030 Fix detecting region by location when using WorldEdit 7 beta-2 or later
- The WorldEdit 7 beta-2 handler was inheriting a function from the handler of older version that uses the old Vector class
- Fixes #466
- Fixes #467
2019-01-01 19:30:16 +01:00
Thijs Wiefferink 44b1cb0fc8 /as add: fix setting player as landlord when he is an owner of the region
- Fixes #427
- Adds a debug message to check the behavior easily in the future
2018-12-28 17:11:48 +01:00
Thijs Wiefferink c7299fa56c Update Discord image to a widget image 2018-12-27 23:14:56 +01:00
pmme 12bf467714 Simplify WorldEdit 7 flushQueue vs. flushSession 2018-12-27 22:47:14 +01:00
Thijs Wiefferink 5b327db316 signs: instead of cancelling indirect break, remove the sign to prevent lagg 2018-12-27 19:44:30 +01:00
Thijs Wiefferink b4f33589a1 Cleanup old directory 2018-12-27 17:45:19 +01:00
Thijs Wiefferink 530c74ccd2 Add support for the WorldEdit vector refactor update
- Add WorldEdit and WorldGuard module that supports the new vector system
- WorldGuard/WordEdit dependencies are in the repository itself to make builds more reliable
- Change code that uses WorldEdit vectors to use Spigot vectors
- Rename all modules to areashop-[worldguard|worldedit]-<version>
- Change maven versions of internal modules to 'latest' to be less confusing
2018-12-27 17:42:24 +01:00
Thijs Wiefferink fa4857cbce Simplify code in the handler for WorldEdit 7 2018-12-27 15:00:53 +01:00
Thijs Wiefferink 93fd4e96cb Fix restoring schematics for the latest WorldEdit dev builds
- Fixes #447
- Thanks pmme and x1p for reporting the issue!
2018-10-28 17:58:09 +01:00
Thijs Wiefferink a6863ae782 Also put the Vault dependency into /dependencies
- Now it should be easy again to built AreaShop yourself, only need to run BuildTools for 1.13.0 and it should work
2018-10-28 01:15:12 +02:00
Thijs Wiefferink e5e2c4ca08 Fixup dependencies, use Bukkit/CraftBukkit 1.7.9 instead of 1.8
- 1.7.9 is the lowest supported version, so it is good to use that as base
2018-10-28 00:53:30 +02:00
Thijs Wiefferink b0341e2a3e Fix compatibility with 1.13 Material class
- Fixes sign handling to properly detect and store signs, fixes #440
- Fixes safe teleporting (also improves block detection, making it even safer)
2018-10-28 00:12:24 +02:00
Thijs Wiefferink c8e1ebb068 Change WorldGuard/WorldEdit/Bukkit dependencies to file links
- Fixes the issue that olders WorldEdit and Bukkit versions are not available on Maven anymore
- This speeds up the build a lot
2018-10-28 00:00:41 +02:00
Thijs Wiefferink 39c8eb5f73 Fix tab complete types for /as setduration 2018-10-22 23:44:31 +02:00
Thijs Wiefferink 2483cf1614 Try to add compatibility with the FAWE schematic format 2018-10-21 21:59:45 +02:00
Thijs Wiefferink 769f8ee4ca Set version to 2.5.0, ready for release! 2018-10-20 21:58:14 +02:00
Thijs Wiefferink 2c04b87a9f Add the latest Transifex translations for DE, ES and FR 2018-10-20 21:57:05 +02:00
Thijs Wiefferink 8ce1ed0264 Fix showing /as del and /as add in /help for landlords 2018-10-20 18:36:51 +02:00
Thijs Wiefferink 035f8e1932 Possibly fix default value for areashop.limits.default (documentation is inconsistent for not op) 2018-10-20 18:36:51 +02:00
Thijs Wiefferink 4d3482994f Smaller discord image 2018-10-20 15:53:14 +02:00
Thijs Wiefferink 45f1c510e5 Add link to the AreaShop Discord 2018-10-20 15:49:36 +02:00
Thijs Wiefferink 5c13223b9e Fix for 1.13.1, depend on WorldGuard and WorldEdit 7 beta-01 2018-10-20 14:54:52 +02:00
Thijs Wiefferink 8c47ae9b3c Add README.md files in a couple of packages, closes #128 2018-08-12 16:41:03 +02:00
Thijs Wiefferink 28d03a6a3a Small fixes suggested by Intellij IDEA 2018-08-12 16:23:43 +02:00
Thijs Wiefferink aa585e9b11 Deal with empty date/time settings (handle as 'unlimited'/'disabled')
- Fixes #412
2018-08-12 16:17:02 +02:00
Thijs Wiefferink 36d2ce60b9 Disable copying entities (WorldEdit 7), and enable removing entities (WorldEdit 6)
- Fixes security problem of #273:
    - Throw item into a region
    - Rent/buy the region -> it gets saved as schematic
    - Pick up items
    - Unrent/sell the region -> items appear again
    - Pick up second set of items, they got duplicated
2018-08-11 22:31:15 +02:00
Thijs Wiefferink bdea9448a4 Update WorldEdit 7 to build 3817, update WorldGuard 7 to build 1735 2018-08-11 22:19:25 +02:00
Thijs Wiefferink bd2f40f5c8 Use new schematic format when using WorldEdit 7 2018-08-11 22:18:48 +02:00
Thijs Wiefferink 9e908cee73 Fix getting region by location for WorldGuard 7 2018-08-11 22:17:13 +02:00
Thijs Wiefferink 0d326d973d Fix saving/restoring schematics with WorldEdit 7 2018-08-05 12:23:32 +02:00
Thijs Wiefferink 27eaa27765 Add WorldGuard 7 and WorldEdit 7 support, now 1.13 works
- Closes #411
2018-08-05 00:34:50 +02:00
Thijs Wiefferink fb35153eb2 Pull translations from Transifex 2018-07-22 17:52:25 +02:00
Thijs Wiefferink aec6295516 Remove dependency on javafx 2018-06-17 17:14:23 +02:00
Thijs Wiefferink 38cd77e487 Fix compilation error in the import command 2018-06-01 19:54:02 +02:00
Thijs Wiefferink 6b9866a4c4 Ignore hidden files in the /regions directory (like .DS_Store) 2018-05-29 22:58:15 +02:00
Thijs Wiefferink 5aceb81cfd Import: setup permanent region settings when not rentable and buyable 2018-05-29 22:21:43 +02:00
Thijs Wiefferink 50f6bce64e Fix region limits, thanks @ZachryWilsn for reporting! 2018-05-29 21:59:55 +02:00
Thijs Wiefferink f713edc5b5 Disable moneyback message in /as info if sellDisabled is true 2018-05-26 01:33:23 +02:00
Thijs Wiefferink 012920a51c Cleanups because of Intellij IDEA inspections 2018-05-23 23:46:57 +02:00
Thijs Wiefferink 6154454f96 Indicate if a region has already been added with another world
- Closes #287
2018-05-23 22:53:07 +02:00
Thijs Wiefferink e34daeb5ff Update readme to use issue template selection link 2018-05-23 22:38:12 +02:00
Thijs Wiefferink 0a2dc22c59 Setup issue templates 2018-05-23 22:29:29 +02:00
Thijs Wiefferink 2482bd88c2 Add option to ignore regions for limit calculation
Set `countForLimit` to `false` in default.yml, a group or the region file to ignore it for limits
2018-05-23 22:13:42 +02:00
Thijs Wiefferink e86281ab28 Safer sign update, don't assume location/world still exists 2018-05-12 14:41:45 +02:00
Thijs Wiefferink 5a9ca74b75 Add option to disable selling and reselling your own regions 2018-05-10 20:07:10 +02:00
Thijs Wiefferink d301be2304 Add licence, issues and CI to the root pom file 2018-04-03 22:44:16 +02:00
Thijs Wiefferink a23c6fa66f Hide progress messages of region update, speed up region updates 2018-04-02 20:05:38 +02:00
Thijs Wiefferink cd63517041 Fix list of region names for error indicating missing worlds 2018-04-02 20:00:22 +02:00
Thijs Wiefferink e3043c476b Fix available languages link 2018-04-02 12:10:34 +02:00
Thijs Wiefferink 3be7573863 Parse currency prefix and suffix with InteractiveMessenger
- Allows proper colors and escaping
2018-03-09 11:50:08 +01:00
Thijs Wiefferink 51161fffee Remove unused chunkunload event 2018-03-09 11:08:15 +01:00
Thijs Wiefferink c82067ad0b Add back Paypal donate button 2018-02-17 19:04:18 +01:00
Thijs Wiefferink 46dbb8d22c More customizable metric suffixes, better currency formatting
- 'metricSymbols' section in 'config.yml' to customize the used suffixes for large numbers
- Remove trailing zeros from numbers with metric suffix
- Properly handle rounding of 1.235 to 1.24 (different double to BigDecimal conversion)
- Closes #373
2018-02-12 14:44:48 +01:00
Thijs Wiefferink cace086466 Add UTF8 awareness flag in plugin.yml
- I think it only does something if you use JavaPlugin#getConfig(), but it does not harm either
2018-02-12 12:49:04 +01:00
Thijs Wiefferink 06a716b1fd Make %uuid% available to schematics when selling a region
- Schematic save/restore would happen after removing the owner, which means %uuid% would be null
- Unrenting already does the save/restore before removing the renter, so now it is more consistent
- Thanks to Behoston on Github for reporting the issue
- Closes #383
2018-02-01 13:59:48 +01:00
Thijs Wiefferink 4530717045 Command confirmation for /as import
- Can also be used for all WordEdit based add/delete actions in the future
2018-01-26 16:16:11 +01:00
Thijs Wiefferink 741bbd879f Fix hashCode() of RegionSign 2018-01-26 14:33:27 +01:00
Thijs Wiefferink 8474edd29d Save region name as given to /as add and /as stack
- Previously the WorldGuard region id was used, converting the name to lowercase
2018-01-26 13:55:41 +01:00
Thijs Wiefferink d4df691166 FIx usage of > in javadocs 2018-01-26 12:15:10 +01:00
Thijs Wiefferink 3e247e6cb1 Move sign listeners into SignsFeature
- Fix removing signs not removing it from the signsByChunk map
2018-01-26 12:08:22 +01:00
Thijs Wiefferink f3527134e8 Prevent chunk loading by sign updates
- When sign needs update, only do it if the chunk is already loaded
- If a chunk gets loaded (by a player or something else), update any signs in that chunk
- Improve some javadocs, let checkstyle require @param, @throws and @returns
2018-01-22 18:12:15 +01:00
Thijs Wiefferink 0e14b121b8 InfoCommand: fix showing list of signs (was only showing the first one) 2018-01-22 18:08:16 +01:00
Thijs Wiefferink 8cc632fc05 Pull latest translations from Transifex (automated script) 2018-01-22 16:31:03 +01:00
Thijs Wiefferink 77c1b3f288 Fix error in help message of the import command 2018-01-22 16:10:02 +01:00
Thijs Wiefferink 21339cbf7c Fix incorrect message reference for /as message 2018-01-22 16:07:52 +01:00
Thijs Wiefferink 0351188671 Update live support link 2018-01-21 22:10:02 +01:00
Thijs Wiefferink 47e1d80821 Add live support chat link to 99messages 2018-01-18 16:16:40 +01:00
Thijs Wiefferink 1d0472b052 Improve feedback when placing [as] sign for region that is not added 2017-12-22 12:25:30 +01:00
Thijs Wiefferink 22dcfc76af Fix confirmation messages of /as del (failed refactor)
Thanks Noudux for reporting it!
2017-12-21 18:09:55 +01:00
Thijs Wiefferink 6b59176048 Fix startup error: call init method of the scheduling library 2017-11-27 10:02:51 +01:00
Thijs Wiefferink 5dc4d11408 Fix missing spaces in /as message messages 2017-11-26 23:49:42 +01:00
Thijs Wiefferink 00bd305381 Use Map#putIfAbsent where applicable 2017-11-26 16:01:05 +01:00
Thijs Wiefferink 9daa50b23b Use BukkitDo scheduling library
- Much cleaner code for scheduling tasks,
- Makes proper use of Java 8 functionality
2017-11-26 15:47:51 +01:00
Thijs Wiefferink 33b73a0369 Remove Paypal donate button 2017-11-25 17:07:54 +01:00
Thijs Wiefferink 591540af30 Partially fix problem with importing regions from RegionForSale
- When checking the type of a region AreaShop would only look at the settings of the region, not the settings of the world, parent regions and config.yml
- Checking parent regions for these settings should still be added (requires bigger changes)
2017-11-23 22:54:55 +01:00
Thijs Wiefferink 4e1e50e993 Fix /as linksigns <profile> for configs without signProfiles
The `signProfiles` section is not in the default config.yml file anymore, so getting that section can return null
2017-11-20 09:19:35 +01:00
Thijs Wiefferink 9a52ca3d9b Add missing @return Javadoc for RegionGroup#getAutoRegions() 2017-11-10 00:04:39 +01:00
Thijs Wiefferink 858b019806 Add option to teleport X blocks away from the sign
- Implements #364
- Option `general.teleportSignDistance` to `default.yml` to set the number of blocks to teleport away from the sign
- Changes the pitch/yaw of the player so that he faces the sign
- Handles wall and floor signs in any direction
- Improve SignsFeature code structure
2017-11-09 23:56:18 +01:00
Thijs Wiefferink b1dfe93088 Add RegionForSale import, rental auto-extend and other things
- `/as import RegionForSale`, as requested in #98:
    - Imports all regions from RegionForSale
    - Converts almost all settings to their AreaShop equivalent
    - Handles parent regions
- Add `rent.autoExtend` for use with rental regions to automatically extend the rent when the time is out, start of #29, still need the command
    - Vault compatible permissions plugin is required to let this work while the player is offline
    - All permissions, limits and the player balance are checked as during a normal rent
- Add option to region groups to automatically add all regions of a certain world
- BREAKING: Region events now use OfflinePlayer instead of Player
- Automatically import existing region owners/members when adding a region to AreaShop

There are still a couple of things missing in the import and it needs to be tested a lot.
2017-10-20 13:41:30 +02:00
Thijs Wiefferink 0bf2314f2a Add licence (as already listed on BukkitDev) 2017-10-16 11:56:04 +02:00
Thijs Wiefferink 33ddb8ae88 Fix %volume% for polygon regions
- WorldGuard does not implement volume() for Polygon regions, always returns 0
- Volume result is cached, calculating it for polygon regions could be slow
2017-10-05 16:53:42 +02:00
Thijs Wiefferink 234e4b6261 Prevent indirectly breaking signs with non-solid blocks
- Fixes #358
2017-10-05 13:43:27 +02:00
Thijs Wiefferink ed2ffaeaa3 Move base command to EN.yml for /as info paging 2017-10-05 13:15:51 +02:00
Thijs Wiefferink e073438862 Add %volume% variable to get the number of blocks in a region
- Works properly for polygon regions
2017-10-05 12:20:03 +02:00
Thijs Wiefferink 07194f07da Add region masking to schematic restore
- When restoring a schematic the paste is masked to the region blocks, so that only blocks that are actually inside the region are pasted (necessary for polygon regions)
- Closes #20
2017-10-01 19:49:05 +02:00
Thijs Wiefferink dfa3e0be66 Checkstyle fix 2017-09-04 17:09:31 +02:00
Thijs Wiefferink 8eef029400 Fix %month% variable using 0-11 instead of 1-12
- Fixes #354, thanks skippyaut
2017-09-04 16:58:39 +02:00
Thijs Wiefferink c8d869ce15 Fix usage of teleport location set by '/as settp'
- It was accidentally trying to get the teleport location from the plugin config file instead of the region config file.
- Also added the possibility to set the teleport location in groups and default.yml
2017-08-05 20:25:06 +02:00
Thijs Wiefferink 053d75181d Update to InteractiveMessenger 1.1-SNAPSHOT
- Ensures AreaShop is rebuild when InteractiveMessenger updates
- Fixes crash bug that was in InteractiveMessenger
- Fixes #334
2017-07-30 17:25:49 +02:00
Thijs Wiefferink f0128c221b Update README.md 2017-06-23 14:59:16 +02:00
Thijs Wiefferink ce6c01c5d0 Add Transifex translation stats image 2017-06-23 14:54:19 +02:00
Thijs Wiefferink b835c4dded Only reset WorldGuard flag/groupFlag if not already empty 2017-06-12 22:05:09 +02:00
Thijs Wiefferink 07e6782714 Fix /as setowner for regions that are not rented yet
Add a rental period to the time when setting owner of a rental region that is not rented yet, otherwise it would get expired immediately
2017-06-12 21:58:42 +02:00
Thijs Wiefferink 4002956aeb Fix javadoc comments 2017-06-12 20:42:36 +02:00
Thijs Wiefferink 0b96b9cb42 Github update checker, Java 8
- Add Github update checker, closes #201, it is implemented to allow reuse by other plugins, it will probably move to a separate repository later
- Switch to Java 8, if people did not update already they probably never will
- Add used Bukkit version as property, use that in all pom files
- Add Task class with methods to easily use BukkitRunnable (not all code is migrated to this pattern yet)
2017-06-12 20:39:28 +02:00
Thijs Wiefferink 0c192c2444 Cleanup setOwners/setMembers, only edit WorldGuard region if different
- Improve code layout for changing owners and members of WorldGuard regions
- Only edit flags and other WorldGuard region settings if they are different than the current option, this prevents useless saves in WorldGuard (which shows a message in console)
2017-06-12 20:39:28 +02:00
Thijs Wiefferink 2381aaeacc Remove link to Shop plugin because it is not fixed yet 2017-04-30 14:15:35 +02:00
Thijs Wiefferink 906b331758 Fix line endings in config.yml 2017-04-20 23:35:49 +02:00
Thijs Wiefferink f0f2e09be0 Always add English time indicators
- Internal timers specified using settings in hiddenConfig.yml use the English words, so if you remove the English words from config.yml timers do not run (regions not expiring, no notifications, no file saving)
- Warn in console when an unknown time specifier is found, might get spammy but at least gets the point across
2017-04-20 23:23:57 +02:00
Thijs Wiefferink 395cc6de07 Fix usage of 'resale' in 'default.yml' for 'flagProfile' section
- 'resale' was used instead of 'resell' (as defined in GeneralRegion#RegionState) in the 'flagProfile' section, causing the flags not getting applied when the region is in reselling state.
- Added fallback to 'resale' section if 'resell' section is not present (to properly read old config.yml/default.yml files)
- Fixed usage of '%resaleprice%' in the resale greeting, should be '%resellprice%'
- Fixes #303, thanks electro2560 for the great bug report!
2017-04-20 15:26:26 +02:00
Thijs Wiefferink 3b9d6187ca Fix checkstyle fail 2017-04-17 21:34:32 +02:00
Thijs Wiefferink 9d1585f513 Fix groups file getting cleared on server start
- Fixes #299
- Because of an earlier change the groups file is loaded before regions are loaded on server start, and region groups remove themselves if there are no valid regions in them anymore.
- Keep groups even though they are empty (so that configuration done in the group is not lost)
2017-04-17 21:32:15 +02:00
Thijs Wiefferink 9d6955039a Fix '/as groupdel' with non-existing group creating an empty one 2017-04-17 21:26:24 +02:00
Thijs Wiefferink 747b47057b Allow # in region name for /as stack to determine counter position 2017-04-11 21:22:35 +02:00
Thijs Wiefferink a973e254e6 Fix '/as addfriend' not allowing you to add players that are playing for the first time
- Fixes #297
2017-04-02 22:34:02 +02:00
Thijs Wiefferink a5105af3ad Add 'use' flag to default.yml again since people mess it up 2017-03-29 20:18:14 +02:00
Thijs Wiefferink 0bb0a05b76 Cleanup checkstyle from pom.xml in AreaShop module 2017-03-29 20:17:42 +02:00
Thijs Wiefferink dad502ec0c Add checkstyle to enforce formatting, change all formatting to comply 2017-03-29 20:15:44 +02:00
Thijs Wiefferink f471b9bbf0 Don't show 'in advance renting:' in '/as info' if maxExtends is zero
- Thanks to R0bstar for noticing this weird weird message combination
2017-03-09 16:14:30 +01:00
Thijs Wiefferink f69d1c41e6 Code cleanup and stricter visibility of methods/variables 2017-03-09 16:01:36 +01:00
Thijs Wiefferink 4ea6f59c49 Remove GeneralRegion#is{Rent|Buy}Region()
- It served no purpose and prevents IDEs from detecting type safety
2017-03-09 15:29:01 +01:00
Thijs Wiefferink 0b7158290f Add some more bStats statistics 2017-03-09 15:09:05 +01:00
Thijs Wiefferink e6757d23de Add bStats analytics
- Add bStats analytics because MCStats is down constantly
- Add custom graphs:
  - Language pie chart
  - Number of registered regions
  - Number of rental regions
  - Number of buy regions
- Closes #287
- In the future MCStats can be removed, for now I would like to keep complete data there for the times it does work
- Could add more graphs in the future for number of friends and things like that
2017-03-02 18:14:07 +01:00
Thijs Wiefferink 7cda35f4da Remove duplicate link in the readme 2017-02-12 20:04:35 +01:00
Thijs Wiefferink ee293d14b9 Fix link to CI in the readme 2017-02-12 20:03:46 +01:00
Thijs Wiefferink 2e0fce4955 Update repository url 2017-02-09 14:59:53 +01:00
Thijs Wiefferink 7afdefc9ed Add missing javadoc to loadFiles methods 2017-02-02 23:03:55 +01:00
Thijs Wiefferink 11f80e7ed1 Start using InteractiveMessenger
- Messaging functionality has been split into the InteractiveMessenger project: https://github.com/NLthijs48/InteractiveMessenger
- Jenkins build server has been changed to publish a Maven repository: http://jenkins.wiefferink.me/plugin/repository/everything
2017-02-02 22:59:00 +01:00
Thijs Wiefferink 40d45c7786 Fix using landlordName setting without using landlord (uuid) setting 2017-02-02 17:20:26 +01:00
Thijs Wiefferink 6b8e161e43 Ensure buy/rent/resell price is never below zero
This prevents problems with negative payment or withdrawal in Vault if input validation of a command is not good enough or if a price has manually been set below zero.
2017-02-02 17:18:26 +01:00
Thijs Wiefferink e1b2f7391c Improve message when you cannot rent/buy a region
The message did not specify which region cannot be rented/bought, which has now been added.
2017-02-02 16:45:15 +01:00
leNic 89ae8b9b4a Fixed reselling with negative prices (#280)
Prevents setting a negative resell price,. Some economy plugins accept a withdraw with a negative number, which has bad consequences (for example EssentialsEco does not accept it).
2017-01-28 20:25:24 +01:00
Thijs Wiefferink fab415bf19 Speed up expiration and expireWarning tasks
The expire task was triggering more often than the expireWarning task, causing lost warnings when warnings with a low time are specified
2017-01-23 14:26:25 +01:00
Thijs Wiefferink c7aa92be81 Indicate in default.yml that expressions can be used for region prices 2017-01-13 19:25:31 +01:00
Thijs Wiefferink 705c8d6891 Update README.md 2017-01-13 18:42:04 +01:00
Thijs Wiefferink 429d87c9ff Improve feature list 2017-01-13 18:41:16 +01:00
Thijs Wiefferink 1fdd8b32cc Add prices depending on a formula
- Price can be specified with an expression (JavaScript syntax)
- You can also use a block of JavaScript code, the value of the last line is used as result (for more complex logic)
- Supported settings: rent.price, buy.price, rent.moneyBack, buy.moneyBack (need more? ask me)
- Before evaluating the expression all region variables as defined in the config.yml file will be replaced (allows you to use %width% etc)
- Added %timesExtended% variable for use in expressions (to know how long the user is renting for)
- '/as setprice' and signs still only allow number input to prevent security problems (this means actual config access is required to do anything of harm with JavaScript)
- Closes #23
2017-01-13 16:56:02 +01:00
Thijs Wiefferink 7900f78a8c Change default WorldGuard flags to include block-place and block-break
Way too many people set the block-break and block-place flags on bigger or even the global region to deny (which is unnecessary and wrong relatively, for global use 'passthrough: deny' instead) so this patches up those mistakes by setting them at the AreaShop region
2017-01-13 16:06:18 +01:00
Thijs Wiefferink 3a65a88849 Fix replacing variables into language variables
- Previously it would insert it as a message, causing the language variable to be split up into multiple parts (which prevents recognizing it later)
- If a Message is marked as inline with Message#inline() it will be inserted without breaking up the message
2016-12-27 16:17:04 +01:00
Thijs Wiefferink 7b491d0389 Lazily instantiate feature classes to improve performance 2016-12-27 16:15:17 +01:00
Thijs Wiefferink fd02c51492 Add setting to prevent cross-world teleportation with '/as find'
- If a region is in another world and 'findCrossWorld' is off, it will be filtered from the results
- 'teleportCrossWorld' will not be checked anymore if the teleport is called from '/as find'
- Resolves  #234
2016-12-26 23:29:40 +01:00
Thijs Wiefferink bb1f592807 Add setting to prevent cross-world teleportation with '/as tp'
Related to #234
2016-12-26 23:20:12 +01:00
Thijs Wiefferink 16c7a044ea Add and make use of escaping in messages
- Add escaping support to FancyMessageFormat: put a backslash before a tag and it will not be interpreted, also works for color codes (&2 and §2) and variables
- Make use of escaping in the Message class to properly handle user input as plaintext (previously user input that got printed back also got interpreted, like colors apply to it)
- All replacements given to Message are escaped, unless you wrap them in a Message before it.
- Replacement limits and infinite replacing detection have changed slightly
2016-12-26 22:56:35 +01:00
Thijs Wiefferink 152f183670 Fix region update after /as reload, cleanup unused code 2016-12-25 23:02:23 +01:00
Thijs Wiefferink 09b6e4c584 Fix string setting as profile in default.yml
- This has been broken in b525c5902c
- Fixes #267
2016-12-25 22:40:11 +01:00
Thijs Wiefferink aeb70196a3 Fix shutdown exception in SignsFeature 2016-12-24 19:59:04 +01:00
Thijs Wiefferink 62148ea577 Move teleportation code to a feature class 2016-12-23 23:25:41 +01:00
Thijs Wiefferink fcc9fb0945 Refactor to introduce Manager and RegionFeature
- Manager to serve as abstract class for managers (like FileManager), implements a lifecycle to allow for shutdown operations (like save all files)
- RegionFeature to server as abstract class for region features
- Improve instantiation and lifecycle of features (global features and region specific ones)
- This is preparation for moving more region functionality into feature specific classes (which makes GeneralRegion smaller and easier to maintain)
2016-12-23 16:03:22 +01:00
Thijs Wiefferink b525c5902c Fix default settings leaking when getting configuration sections
- Default settings and custom settings are in separate YamlConfiguration instances now to prevent leaking
- When getting a configuration section you now know that either it is from the current default.yml file or the default.yml file in the jar (querying settings from the section will always have the same source)
- Fixed a startup null pointer
- Fixed #266
2016-12-23 14:07:26 +01:00
Thijs Wiefferink b18a7cc6d5 Fix [break] in hover lines
Hover lines are still a bit broken when trying to insert complex messages into them, this is hard to do in a proper way though.
2016-12-10 15:19:34 +01:00
Thijs Wiefferink 54b6e84558 File loading improvements to be more robust 2016-12-04 21:14:31 +01:00
Thijs Wiefferink bae3c0a199 Ask for config files in the issue template 2016-12-04 17:56:37 +01:00
Very Evil Olaf 508270a280 Update ISSUE_TEMPLATE.md (#258)
Note that 'latest' is not a correct version
2016-12-04 17:48:36 +01:00
Thijs Wiefferink 87b2cb9ecd Prevent exceptions if a schematicProfile does not exist 2016-12-04 17:31:22 +01:00
Thijs Wiefferink 271b17b6be Set version to 2.4.0 and update language files 2016-12-02 14:37:27 +01:00
Desjardins Jérôme 1dfedea50c Create a permission for teleporting to available regions (#241)
* Update GeneralRegion.java
Add Available abstract function
Check Permission modification

Update BuyRegion.java
Add Available function for selled

Update RentRegion.java
Add Available function for rented

Update TeleportCommand.java
Check new permission

Finish feature teleport available region

* Fix translation
2016-11-19 17:15:23 +01:00
Thijs Wiefferink d9abe2e347 FIx problem with null regionFlags sections 2016-11-14 18:02:59 +01:00
Thijs Wiefferink 1ba2e21ae9 Make profile based settings easier to understand
- Remove 'signProfiles', 'flagProfiles', 'eventCommandProfiles', 'schematicProfiles' and 'expirationWarningProfiles' from the config.yml file
- Add the removed profile contents directly to the setting without the trailing 's' in the default.yml file (this prevents the need to understand the creation of profiles, and then assigning them, taking out a step in the thought process of users)
- Added method in GeneralRegion to get a ConfigurationSection from the region file, group files or default file while also taking into account the translation from a string to a profile that is defined in the config.yml file. This ensures backwards compatibility with current config files (the old style will not be promoted anymore though).
- The 'expirationWarningProfiles' does not have the subkeys 'warnPlayer' and 'commands' anymore, it is just a list of commands now, using the '/areashop message' command to warn a player.
- Add a workaround for the empty sign problem after unrent/sell of a region while having restore enabled, an AsyncWorldEdit plugin installed and signs inside the region (sign will be updated again half a second after unrent/sell).
2016-11-13 00:44:35 +01:00
Thijs Wiefferink fcdfdc6094 Update language files
- Swedish is added
- German, French and Russian are improved
2016-11-07 14:13:03 +01:00
Thijs Wiefferink 8a7e2ba5c2 Indicate limits when a MaxChangedBlocksException is thrown by WorldEdit 2016-11-07 13:52:54 +01:00
Thijs Wiefferink 0950452692 Fix a couple of problems caused by vertical /as stack addition 2016-10-31 21:07:08 +01:00
Thijs Wiefferink 293978f068 Decouple Message class from replacement providers
- Instead of applying replacements by testing for a replacement that has the GeneralRegion type, it now checks for a ReplacementProvider instances (one step closer to making Message independent of AreaShop).
- Replacements are handled one by one with a switch-case instead of getting them from a map, helps performance a lot.
2016-10-25 20:57:58 +02:00
Thijs Wiefferink 5efe14b8e9 Add up and down direction for '/as stack'
Prevents creating regions above and below the world limits, still needs
testing.
Progress for #105
2016-10-24 15:02:49 +02:00
Thijs Wiefferink 839d510151 Switch from Bukkit to Spigot Maven repo since it is down
Also switched from Bukkit 1.7.9 to Bukkit 1.8.0 because that is the lowest version available on the Spigot repo
2016-10-17 23:45:08 +02:00
Thijs Wiefferink 9180d9b8ee Fix small language file issue
When you only have a formatting code before a language variable, the hover/click effects will accidentally be applied to one text part earlier
2016-10-16 18:29:26 +02:00
Thijs Wiefferink 7aa786f4ce Fix default config trying to execute /as message as player
Fixes #221
2016-09-04 22:43:03 +02:00
Thijs Wiefferink 10ea8540e7 Add tab completion for '/as me [player]'
Closes #220
2016-09-04 00:59:04 +02:00
Thijs Wiefferink dba00769f6 Fix problem with line breaks 2016-09-03 20:58:45 +02:00
Thijs Wiefferink 44c70c6a33 Cleanup messages about region that does not exist in WorldGuard 2016-09-03 19:46:05 +02:00
Thijs Wiefferink 570f7b4055 Don't extend rent when using '/as setowner' to set a different owner
Also remove new owner from the friends list.
Fixes #219
2016-09-03 19:19:40 +02:00
Thijs Wiefferink feafa012dd Fix issue with \n on 1.7.x servers
- Each line of a message will now be sent separately instead of using '\n' in the text
- Drastically reduced the number of StringBuilders that are instantiated during message construction
- Fixes #222
2016-09-03 17:22:40 +02:00
Thijs Wiefferink 82b340ce1a Messages: also parse section signs into color tags properly
Fixes line-wrapping removing color in some cases
2016-09-02 21:43:58 +02:00
Thijs Wiefferink 93809f27fc Rename events to be consistent with commands
- AddFriendEvent -> AddedFriendEvent
- DeleteFriendEvent -> DeletedFriendEvent
- RemovedRegionEvent -> DeletedRegionEvent
2016-08-28 22:45:20 +02:00
Thijs Wiefferink f8ed3654fd Fix compilation error 2016-08-28 22:31:06 +02:00
Thijs Wiefferink 58a1afccf3 Invert inheritance of RegionEvent and CancellabelRegionEvent/NotifyRegionEvent 2016-08-28 22:29:45 +02:00
Thijs Wiefferink d9c3573225 Change RegionUpdateEvent to UpdateRegionEvent
This breaks plugins using the event
2016-08-28 22:21:33 +02:00
Thijs Wiefferink 1577443203 Generalize events better
Adds generic classes for events with a region (BuyRegion, RentRegion or GeneralRegion)
2016-08-28 22:11:17 +02:00
Thijs Wiefferink ab7a92c57d Update README.md 2016-08-26 19:49:21 +02:00
Thijs Wiefferink 2e09b0f60f Update README.md 2016-08-26 19:48:59 +02:00
Thijs Wiefferink 6e5c35f95b Add extension plugins section 2016-08-26 19:45:37 +02:00
Thijs Wiefferink 066ceedafd Add 'build' flag by default to prevent inheriting from parent regions. 2016-08-21 22:20:25 +02:00
Thijs Wiefferink c8ebe24bd3 Put break in '/as info' help message in the right spot 2016-08-19 20:52:07 +02:00
Thijs Wiefferink ad7db5ee23 Attempt to fix unable to add new players with '/as addfriend' 2016-08-16 22:43:09 +02:00
Thijs Wiefferink f80a8178ff Fix formatting not clearing on new lines 2016-08-13 22:28:15 +02:00
Thijs Wiefferink 05c8e1a7e4 Make loggin methods more generic 2016-08-10 16:07:39 +02:00
Thijs Wiefferink 9904805310 Improve version detection of WorldGuard
- First detect version 5
- Then detect lower than 6.1.3
- Else check build number:
  - Build number exists and lower than 1672: 6
  - Build number exists and Is 1672: broken
  - Else: 6_1_3
2016-08-09 22:56:21 +02:00
Thijs Wiefferink 0df2f429c0 Only print build number warning if we found it 2016-08-09 22:38:33 +02:00
Thijs Wiefferink b3408a2648 Fix compilation error and WorldGuard version detection 2016-08-09 21:52:53 +02:00
Thijs Wiefferink e1f89e7904 Cleanup some leftover logging in an old style 2016-08-08 22:06:31 +02:00
275 changed files with 25238 additions and 15335 deletions

No files matched your search

+39
View File
@@ -0,0 +1,39 @@
---
name: Bug report
about: Report a problem in the plugin
title: ''
labels: 'NEW, Type: Bug'
assignees: ''
---
**Current behavior**
<!--- Tell what happens currently and/or show the stacktrace if an error occured -->
**Expected behavior**
<!--- Tell what you expected to happen instead -->
**Steps to reproduce**
<!--- Exactly show how this bug can be triggered -->
1.
2.
3.
4.
**Your environment**
<!--- Indicate which versions you use -->
<!--- Attention: "LATEST" or "NEWEST" are invalid answers! -->
<!--- Use '/version' for the Platform version and '/version <plugin>' for plugin versions -->
* Server platform (Bukkit, Spigot, etc.):
* Server version:
* AreaShop version:
* WorldEdit version:
* WorldGuard version:
* Vault version:
**Your config files**
<!--- Attach a '.zip' file of the '/plugins/AreaShop' and '/plugins/WorldGuard' directories to show your configuration setup -->
+15
View File
@@ -0,0 +1,15 @@
---
name: Feature request
about: Suggest an idea
title: ''
labels: 'NEW, Type: Feature'
assignees: ''
---
**Describe the problem you are trying to solve with this feature request**
<!-- When I know the problem you are trying to solve I can help you to think about the best solution -->
**Describe the solution you'd like**
<!-- Describe the config settings, commands and other features that should be added -->
@@ -0,0 +1,31 @@
---
name: Support question
about: Ask help with the setup or usage of the plugin
title: ''
labels: 'NEW, Type: Support'
assignees: ''
---
**Current behavior**
<!--- Tell what happens currently -->
**Desired behavior**
<!--- Tell what you want to happen instead -->
**Your environment**
<!--- Indicate which versions you use -->
<!--- Attention: "LATEST" or "NEWEST" are invalid answers! -->
<!--- Use '/version' for the Platform version and '/version <plugin>' for plugin versions -->
* Server platform (Bukkit, Spigot, etc.):
* Server version:
* AreaShop version:
* WorldEdit version:
* WorldGuard version:
* Vault version:
**Your config files**
<!--- Attach a '.zip' file of the '/plugins/AreaShop' and '/plugins/WorldGuard' directories to show your configuration setup -->
+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
+189 -26
View File
@@ -1,33 +1,196 @@
# Maven stuff
/target
*.pydevproject
.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
# External tool builders
.externalToolBuilders/
### 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
# Locally stored "Eclipse launch configurations"
*.launch
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# CDT-specific
.cproject
# AWS User-specific
.idea/**/aws.xml
# PDT-specific
.buildpath
# 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
# 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.8") {
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.20.6")
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")
}
}
}
-230
View File
@@ -1,230 +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.3.2</version> <!-- Main plugin version -->
<parent>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-parent</artifactId>
<version>parent</version>
</parent>
<dependencies>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.7.9-R0.2</version>
<type>jar</type>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-5</artifactId>
<version>WorldGuard-5</version>
<type>jar</type>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-6</artifactId>
<version>WorldGuard-6</version>
<type>jar</type>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-6_1_3</artifactId>
<version>WorldGuard-6_1_3</version>
<type>jar</type>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-interface</artifactId>
<version>AreaShopInterface</version>
<type>jar</type>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldedit-5</artifactId>
<version>WorldEdit-5</version>
<type>jar</type>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldedit-6</artifactId>
<version>WorldEdit-6</version>
<type>jar</type>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>worldedit</artifactId>
<version>6.0.0-SNAPSHOT</version>
<scope>provided</scope>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>worldguard</artifactId>
<version>6.0.0-SNAPSHOT</version>
<scope>provided</scope>
<type>jar</type>
</dependency>
<dependency>
<groupId>net.milkbowl.vault</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.4</version>
<scope>provided</scope>
</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>
</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;
}
}
File diff suppressed because it is too large. Load diff
@@ -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,231 +1,445 @@
package me.wiefferink.areashop.commands;
import com.sk89q.worldedit.bukkit.selections.Selection;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
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.bukkit.scheduler.BukkitRunnable;
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 {
public AddCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop add";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.createrent") || target.hasPermission("areashop.createbuy")) {
return "help-add";
}
return null;
}
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 void execute(final CommandSender sender, final String[] args) {
if( !sender.hasPermission("areashop.createrent")
&& !sender.hasPermission("areashop.createrent.member")
&& !sender.hasPermission("areashop.createrent.owner")
&& !sender.hasPermission("areashop.createbuy")
&& !sender.hasPermission("areashop.createbuy.member")
&& !sender.hasPermission("areashop.createbuy.owner")) {
plugin.message(sender, "add-noPermission");
return;
}
if(args.length < 2 || args[1] == null || (!"rent".equals(args[1].toLowerCase()) && !"buy".equals(args[1].toLowerCase()))) {
plugin.message(sender, "add-help");
return;
}
List<ProtectedRegion> regions = new ArrayList<>();
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;
}
Selection selection = plugin.getWorldEdit().getSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
world = selection.getWorld();
regions = Utils.getWERegionsInSelection(selection);
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.getWorldGuard().getRegionManager(world).getRegion(args[2]);
if(region == null) {
plugin.message(sender, "add-noRegion", args[2]);
return;
}
regions.add(region);
}
final boolean isRent = "rent".equals(args[1].toLowerCase());
final List<ProtectedRegion> finalRegions = regions;
final Player finalPlayer = player;
final World finalWorld = world;
AreaShop.debug("Starting add task with " + regions.size() + " regions");
new BukkitRunnable() {
private int current = 0;
private TreeSet<GeneralRegion> regionsSuccess = new TreeSet<>();
private TreeSet<GeneralRegion> regionsAlready = new TreeSet<>();
private TreeSet<String> namesBlacklisted = new TreeSet<>();
private TreeSet<String> namesNoPermission = new TreeSet<>();
private TreeSet<String> namesExternal = new TreeSet<>();
@Override
public void run() {
for(int i=0; i<plugin.getConfig().getInt("adding.regionsPerTick"); i++) {
if(current < finalRegions.size()) {
ProtectedRegion region = finalRegions.get(current);
// Determine if the player is an owner or member of the region
boolean isMember = finalPlayer != null && plugin.getWorldGuardHandler().containsMember(region, finalPlayer.getUniqueId());
boolean isOwner = finalPlayer != null && plugin.getWorldGuardHandler().containsMember(region, finalPlayer.getUniqueId());
String type;
if(isRent) {
type = "rent";
} else {
type = "buy";
}
FileManager.AddResult result = plugin.getFileManager().checkRegionAdd(sender, region, isRent ? GeneralRegion.RegionType.RENT : GeneralRegion.RegionType.BUY);
if(result == FileManager.AddResult.ALREADYADDED) {
regionsAlready.add(plugin.getFileManager().getRegion(region.getId()));
} else if(result == FileManager.AddResult.BLACKLISTED) {
namesBlacklisted.add(region.getId());
} else if(result == FileManager.AddResult.NOPERMISSION) {
namesNoPermission.add(region.getId());
} 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)));
if(isRent) {
RentRegion rent = new RentRegion(plugin, region.getId(), finalWorld);
// 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);
@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;
}
rent.update();
@Override
public String getHelpKey(@NotNull CommandSender target) {
if(target.hasPermission("areashop.createrent")
|| target.hasPermission("areashop.createrent.member")
|| target.hasPermission("areashop.createrent.owner")
// Run commands
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
regionsSuccess.add(rent);
} else {
BuyRegion buy = new BuyRegion(plugin, region.getId(), finalWorld);
// Set landlord
if(landlord) {
buy.setLandlord(finalPlayer.getUniqueId(), finalPlayer.getName());
}
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
plugin.getFileManager().addBuy(buy);
buy.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
|| target.hasPermission("areashop.createbuy")
|| target.hasPermission("areashop.createbuy.member")
|| target.hasPermission("areashop.createbuy.owner")) {
return "help-add";
}
return null;
}
buy.update();
@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);
}
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
regionsSuccess.add(buy);
}
}
current++;
}
}
if(current >= finalRegions.size()) {
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(!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");
}
this.cancel();
}
}
}.runTaskTimer(plugin, 1, 1);
}
@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.getWorldGuard().getRegionManager(player.getWorld()).getRegions().values()) {
result.add(region.getId());
}
}
}
}
return result;
}
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)
);
}
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
);
}
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);
}
}
}
}
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"));
}
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));
}
}
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());
}
AddingRegionEvent event = plugin.getFileManager().addRegion(rent);
if (event.isCancelled()) {
namesAddCancelled.add(rent.getName());
return;
}
rent.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
rent.update();
// Add existing owners/members if any
if (!landlord && !existing.isEmpty()) {
UUID rentBy = existing.removeFirst();
OfflinePlayer rentByPlayer = Bukkit.getOfflinePlayer(rentBy);
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();
// 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);
}
rent.notifyAndUpdate(new RentedRegionEvent(rent, false));
}
}
regionsSuccess.add(rent);
}
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());
}
AddingRegionEvent event = plugin.getFileManager().addRegion(buy);
if (event.isCancelled()) {
namesAddCancelled.add(buy.getName());
return;
}
buy.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
buy.update();
// Add existing owners/members if any
if (!landlord && !existing.isEmpty()) {
UUID buyBy = existing.removeFirst();
OfflinePlayer buyByPlayer = Bukkit.getOfflinePlayer(buyBy);
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();
// Update everything
buy.handleSchematicEvent(GeneralRegion.RegionEvent.BOUGHT);
// Add others as friends
for (UUID friend : existing) {
buy.getFriendsFeature().addFriend(friend, null);
}
buy.notifyAndUpdate(new BoughtRegionEvent(buy));
}
}
regionsSuccess.add(buy);
}
@Override
public String stringDescription() {
return "Add a region";
}
public String getHelp(CommandSender target) {
if (target.hasPermission("areashop.createrent")
|| target.hasPermission("areashop.createrent.member")
|| target.hasPermission("areashop.createrent.owner")
|| target.hasPermission("areashop.createbuy")
|| target.hasPermission("areashop.createbuy.member")
|| target.hasPermission("areashop.createbuy.owner")) {
return "help-add";
}
return null;
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("add");
}
private record AddTaskState(
@Nonnull Player sender,
@Nonnull GeneralRegion.RegionType regionType,
@Nonnull Set<GeneralRegion> regionsSuccess,
@Nonnull Set<GeneralRegion> regionsAlready,
@Nonnull Set<GeneralRegion> regionsAlreadyOtherWorld,
@Nonnull Set<GeneralRegion> regionsRentCancelled,
@Nonnull Set<GeneralRegion> regionsBuyCancelled,
@Nonnull Set<String> namesBlacklisted,
@Nonnull Set<String> namesNoPermission,
@Nonnull Set<String> namesAddCancelled,
@Nonnull World world) {
}
}
@@ -0,0 +1,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,146 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
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 {
public AddfriendCommand(AreaShop plugin) {
super(plugin);
}
@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.getAllApplicableRegions(((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.isRentRegion() && !((RentRegion)region).isRented())
|| (region.isBuyRegion() && !((BuyRegion)region).isSold())) {
plugin.message(sender, "addfriend-noOwner", region);
return;
}
OfflinePlayer friend = Bukkit.getOfflinePlayer(args[1]);
if(friend.getLastPlayed() == 0 && !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 && !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,130 +0,0 @@
package me.wiefferink.areashop.commands;
import com.sk89q.worldedit.bukkit.selections.CuboidSelection;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.features.SignsFeature;
import me.wiefferink.areashop.regions.GeneralRegion;
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 {
public AddsignCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop addsign";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.addsign")) {
return "help-addsign";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.addsign")) {
plugin.message(sender, "addsign-noPermission");
return;
}
if (!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
// Get the sign
Block block = null;
BlockIterator blockIterator = new BlockIterator(player, 100);
while(blockIterator.hasNext() && block == null) {
Block next = blockIterator.next();
if(next.getType() != Material.AIR) {
block = next;
}
}
if(block == null || !(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)) {
plugin.message(sender, "addsign-noSign");
return;
}
GeneralRegion region;
if(args.length > 1) {
// Get region by argument
region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[1]);
return;
}
} else {
// Get region by sign position
List<GeneralRegion> regions = Utils.getASRegionsInSelection(new CuboidSelection(block.getWorld(), block.getLocation(), 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;
}
}
SignsFeature.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,74 +1,69 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
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 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 {
public BuyCommand(AreaShop plugin) {
super(plugin);
}
@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;
}
@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");
} else {
region.buy(player);
}
} else {
// get the region by location
List<BuyRegion> regions = Utils.getApplicableBuyRegions(((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);
}
}
}
@Inject
public BuyCommand(@Nonnull IFileManager fileManager) {
this.buyRegionFlag = RegionParseUtil.createDefaultBuy(fileManager);
}
@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,68 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
/**
* Abstract class for generalising command classes
*/
public abstract class CommandAreaShop {
AreaShop plugin;
/**
* Save the instance of the main plugin class
* @param plugin The main plugin
*/
public CommandAreaShop(AreaShop plugin) {
this.plugin = plugin;
}
public boolean canExecute(Command command, String[] args) {
String commandString = command.getName();
for(String argument : args) {
commandString += " " + argument;
}
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);
}
@@ -1,127 +1,185 @@
package me.wiefferink.areashop.commands;
import com.sk89q.worldedit.bukkit.selections.Selection;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
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 {
public DelCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop del";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.destroyrent") || target.hasPermission("areashop.destroybuy")) {
return "help-del";
}
return null;
}
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 void execute(CommandSender sender, String[] args) {
if( !sender.hasPermission("areashop.destroybuy")
&& !sender.hasPermission("areashop.destroybuy.landlord")
&& !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;
Selection selection = plugin.getWorldEdit().getSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
List<GeneralRegion> regions = Utils.getASRegionsInSelection(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.isRentRegion()) {
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.isBuyRegion()) {
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.isRentRegion()) {
// 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.isBuyRegion()) {
// 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 List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getRegionNames();
}
return result;
}
@Inject
public DelCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull WorldEditInterface worldEditInterface,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.worldEditInterface = worldEditInterface;
this.fileManager = fileManager;
}
@Override
public String stringDescription() {
return "Allows you to delete regions";
}
@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
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,144 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
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 {
public DelfriendCommand(AreaShop plugin) {
super(plugin);
}
@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.getAllApplicableRegions(((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.isRentRegion() && !((RentRegion)region).isRented())
|| (region.isBuyRegion() && !((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,82 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.features.SignsFeature;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.BlockIterator;
import java.util.ArrayList;
import java.util.List;
public class DelsignCommand extends CommandAreaShop {
public DelsignCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop delsign";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.delsign")) {
return "help-delsign";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.delsign")) {
plugin.message(sender, "delsign-noPermission");
return;
}
if (!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
// Get the sign
Block block = null;
BlockIterator blockIterator = new BlockIterator(player, 100);
while(blockIterator.hasNext() && block == null) {
Block next = blockIterator.next();
if(next.getType() != Material.AIR) {
block = next;
}
}
if(block == null || !(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)) {
plugin.message(sender, "delsign-noSign");
return;
}
SignsFeature.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,158 +1,200 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.messages.Message;
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 {
public FindCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop find";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.find")) {
return "help-find";
}
return null;
}
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 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;
}
}
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))) {
results.add(region);
}
}
if(!results.isEmpty()) {
// Draw a random one
BuyRegion region = results.get(new Random().nextInt(results.size()));
Message onlyInGroup = Message.none();
if(group != null) {
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
}
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.teleportPlayer(player, region.getBooleanSetting("general.findTeleportToSign"), false);
} else {
Message onlyInGroup = Message.none();
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);
}
}
} 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))) {
results.add(region);
}
}
if(!results.isEmpty()) {
// Draw a random one
RentRegion region = results.get(new Random().nextInt(results.size()));
Message onlyInGroup = Message.none();
if(group != null) {
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
}
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.teleportPlayer(player, region.getBooleanSetting("general.findTeleportToSign"), false);
} else {
Message onlyInGroup = Message.none();
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);
}
}
}
private final Economy economy;
private final IFileManager fileManager;
private final CommandFlag<RegionGroup> regionGroupFlag;
}
@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 final MessageBridge messageBridge;
@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();
}
@Override
public String stringDescription() {
return null;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if(target.hasPermission("areashop.find")) {
return "help-find";
}
return null;
}
@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");
}
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,118 +0,0 @@
package me.wiefferink.areashop.commands;
import com.sk89q.worldedit.bukkit.selections.Selection;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionGroup;
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 {
public GroupaddCommand(AreaShop plugin) {
super(plugin);
}
@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;
Selection selection = plugin.getWorldEdit().getSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
List<GeneralRegion> regions = Utils.getASRegionsInSelection(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,119 +0,0 @@
package me.wiefferink.areashop.commands;
import com.sk89q.worldedit.bukkit.selections.Selection;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionGroup;
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 {
public GroupdelCommand(AreaShop plugin) {
super(plugin);
}
@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) {
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;
Selection selection = plugin.getWorldEdit().getSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
List<GeneralRegion> regions = Utils.getASRegionsInSelection(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,73 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.regions.RegionGroup;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
public class GroupinfoCommand extends CommandAreaShop {
public GroupinfoCommand(AreaShop plugin) {
super(plugin);
}
@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;
}
List<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,58 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
public class GrouplistCommand extends CommandAreaShop {
public GrouplistCommand(AreaShop plugin) {
super(plugin);
}
@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,29 +1,58 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
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;
public HelpCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop help";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.help")) {
return "help-help";
}
return null;
}
@Singleton
public class HelpCommand extends AreashopCommandBean {
private final AreashopCommands commands;
@Override
public void execute(CommandSender sender, String[] args) {
plugin.getCommandManager().showHelp(sender);
}
@Inject
public HelpCommand(@Nonnull AreashopCommands commands) {
this.commands = commands;
}
@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);
}
}
@@ -0,0 +1,97 @@
package me.wiefferink.areashop.commands;
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 javax.annotation.Nonnull;
import java.util.List;
@Singleton
public class ImportCommand extends AreashopCommandBean {
private static final CloudKey<String> KEY_SOURCE = CloudKey.of("source", String.class);
/* 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;
@Inject
public ImportCommand(@Nonnull MessageBridge messageBridge, @Nonnull ImportJobFactory importJobFactory) {
this.messageBridge = messageBridge;
this.importJobFactory = importJobFactory;
}
@Override
public String stringDescription() {
return null;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if(target.hasPermission("areashop.import")) {
return "help-import";
}
return null;
}
@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);
}
@Override
protected @Nonnull CommandProperties properties() {
return CommandProperties.of("import");
}
// TODO:
// - Landlord?
// - Friends
// - Region flags?
// - Settings from the 'permissions' section in RegionForSale/config.yml?
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,513 +1,272 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.messages.Message;
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 org.bukkit.Location;
import me.wiefferink.areashop.tools.SimpleMessageBridge;
import me.wiefferink.interactivemessenger.processing.Message;
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.*;
import javax.annotation.Nonnull;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Stream;
public class InfoCommand extends CommandAreaShop {
@Singleton
public class InfoCommand extends AreashopCommandBean {
public InfoCommand(AreaShop plugin) {
super(plugin);
}
@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
*/
private void showSortedPagedList(CommandSender sender, List<? extends GeneralRegion> regions, RegionGroup filterGroup, String keyHeader, String pageInput, String baseCommand) {
int MAX_ITEMS = 20;
int ITEMS_PER_PAGE = MAX_ITEMS-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) {
for(Iterator<? extends GeneralRegion> it = regions.iterator(); it.hasNext(); ) {
if(!filterGroup.isMember(it.next())) {
it.remove();
}
}
}
if(regions.isEmpty()) {
plugin.message(sender, "info-noRegions");
} else {
long start = Calendar.getInstance().getTimeInMillis();
// First sort by type, then by name
Collections.sort(regions, new Comparator<GeneralRegion>() {
@Override
public int compare(GeneralRegion one, GeneralRegion two) {
int typeCompare = getTypeOrder(two).compareTo(getTypeOrder(one));
if(typeCompare != 0) {
return typeCompare;
} else {
return one.getName().compareTo(two.getName());
}
}
});
// Header
Message limitedToGroup = Message.none();
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)ITEMS_PER_PAGE); // Clip page to correct boundaries, not much need to tell the user
if(regions.size() == ITEMS_PER_PAGE+1) { // 19 total items is mapped to 1 page of 19
ITEMS_PER_PAGE++;
totalPages = 1;
}
page = Math.max(1, Math.min(totalPages, page));
int linesPrinted = 1; // header
for(int i = (page-1)*ITEMS_PER_PAGE; i < page*ITEMS_PER_PAGE && 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.none();
// 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 < MAX_ITEMS-1; i++) {
sender.sendMessage(" ");
}
footer.send(sender);
long end = Calendar.getInstance().getTimeInMillis();
}
}
}
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;
}
}
}
@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];
}
}
}
// All regions
if(args[1].equalsIgnoreCase("all")) {
showSortedPagedList(sender, plugin.getFileManager().getRegions(), filterGroup, "info-allHeader", (args.length > 2 ? args[2] : null), "/areashop info all");
}
// Rented regions
else if(args[1].equalsIgnoreCase("rented")) {
List<RentRegion> regions = plugin.getFileManager().getRents();
for(Iterator<RentRegion> it = regions.iterator(); it.hasNext(); ) {
if(!it.next().isRented()) {
it.remove();
}
}
showSortedPagedList(sender, regions, filterGroup, "info-rentedHeader", (args.length > 2 ? args[2] : null), "/areashop info rented");
}
// Forrent regions
else if(args[1].equalsIgnoreCase("forrent")) {
List<RentRegion> regions = plugin.getFileManager().getRents();
for(Iterator<RentRegion> it = regions.iterator(); it.hasNext(); ) {
if(it.next().isRented()) {
it.remove();
}
}
showSortedPagedList(sender, regions, filterGroup, "info-forrentHeader", (args.length > 2 ? args[2] : null), "/areashop info forrent");
}
// Sold regions
else if(args[1].equalsIgnoreCase("sold")) {
List<BuyRegion> regions = plugin.getFileManager().getBuys();
for(Iterator<BuyRegion> it = regions.iterator(); it.hasNext(); ) {
if(!it.next().isSold()) {
it.remove();
}
}
showSortedPagedList(sender, regions, filterGroup, "info-soldHeader", (args.length > 2 ? args[2] : null), "/areashop info sold");
}
// Forsale regions
else if(args[1].equalsIgnoreCase("forsale")) {
List<BuyRegion> regions = plugin.getFileManager().getBuys();
for(Iterator<BuyRegion> it = regions.iterator(); it.hasNext(); ) {
if(it.next().isSold()) {
it.remove();
}
}
showSortedPagedList(sender, regions, filterGroup, "info-forsaleHeader", (args.length > 2 ? args[2] : null), "/areashop info forsale");
}
// Reselling regions
else if(args[1].equalsIgnoreCase("reselling")) {
List<BuyRegion> regions = plugin.getFileManager().getBuys();
for(Iterator<BuyRegion> it = regions.iterator(); it.hasNext(); ) {
if(!it.next().isInResellingMode()) {
it.remove();
}
}
showSortedPagedList(sender, regions, filterGroup, "info-resellingHeader", (args.length > 2 ? args[2] : null), "/areashop info reselling");
}
@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();
}
// 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), "/areashop info nogroup");
}
}
@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")
.required(KEY_TYPE, EnumParser.enumParser(RegionStateFilterType.class))
.flag(FLAG_PAGE)
.flag(this.filterGroupFlag)
.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;
}
RegionStateFilterType filterType = context.get(KEY_TYPE);
processOtherFilters(context, filterType);
}
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);
}
/**
* 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
}
// 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.getAllApplicableRegions(((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).isRentRegion()) {
rent = (RentRegion)regions.get(0);
} else if(regions.get(0).isBuyRegion()) {
buy = (BuyRegion)regions.get(0);
}
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
}
if(rent == null && buy == null) {
plugin.message(sender, "info-regionNotExisting", args[2]);
return;
}
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(rent.getMaxRentTime() != -1) {
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", signLocations.toArray());
}
// Groups
if(sender.hasPermission("areashop.groupinfo") && !rent.getGroupNames().isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionGroups", Utils.createCommaSeparatedList(rent.getGroupNames()));
}
// Restoring
if(rent.isRestoreEnabled()) {
if(sender.hasPermission("areashop.setrestore")) {
plugin.messageNoPrefix(sender, "info-regionRestoringRent", rent, Message.fromKey("info-regionRestoringProfile").replacements(rent.getRestoreProfile()));
} else {
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(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", signLocations.toArray());
}
// Groups
if(sender.hasPermission("areashop.groupinfo") && !buy.getGroupNames().isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionGroups", Utils.createCommaSeparatedList(buy.getGroupNames()));
}
// Restoring
if(buy.isRestoreEnabled()) {
if(sender.hasPermission("areashop.setrestore")) {
plugin.messageNoPrefix(sender, "info-regionRestoringBuy", buy, Message.fromKey("info-regionRestoringProfile").replacements(buy.getRestoreProfile()));
} else {
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");
}
}
/**
* Create a comma-space separated list from a collection of strings
* @param list The collection with strings
* @return A comma-space separated list of the strings in the collection
*/
public String createCommaString(Collection<String> list) {
String result = "";
boolean first = true;
for(String part : list) {
if(first) {
result += part;
first = false;
} else {
result += ", " + part;
}
}
return result;
}
@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;
}
}
@@ -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,88 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.messages.Message;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class LinksignsCommand extends CommandAreaShop {
public LinksignsCommand(AreaShop plugin) {
super(plugin);
}
@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];
Set<String> profiles = plugin.getConfig().getConfigurationSection("signProfiles").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,114 +1,78 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
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.HashSet;
import java.util.Set;
import javax.annotation.Nonnull;
public class MeCommand extends CommandAreaShop {
@Singleton
public class MeCommand extends AreashopCommandBean {
public MeCommand(AreaShop plugin) {
super(plugin);
}
@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;
}
@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;
}
@Inject
public MeCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
}
// 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() != null && region.getFriendsFeature().getFriends().contains(player.getUniqueId())) {
friendRegions.add(region);
}
}
@Override
public String stringDescription() {
return null;
}
// 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 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);
}
if(!foundSome) {
plugin.message(sender, "me-nothing", player.getName());
} else {
plugin.messageNoPrefix(sender, "me-clickHint");
}
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("me");
}
public static void show() {
@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);
}
}
}
@@ -1,69 +1,62 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.messages.Message;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
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.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 {
public MessageCommand(AreaShop plugin) {
super(plugin);
}
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 getCommandStart() {
return "areashop message";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.message")) {
return "help-message";
}
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");
}
}
@@ -0,0 +1,8 @@
# Commands
This module contains all AreaShop commands.
AreaShop uses https://cloud.incendo.org/
* `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.
* `util/AreashopCommands` class in handles all command registration
@@ -1,34 +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;
public ReloadCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop reload";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.reload")) {
return "help-reload";
}
return null;
}
@Singleton
public class ReloadCommand extends AreashopCommandBean {
private final AreaShop 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");
}
}
@Inject
public ReloadCommand(@Nonnull AreaShop plugin) {
this.plugin = plugin;
}
@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,74 +1,69 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
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 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 {
public RentCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop rent";
}
private final CommandFlag<RentRegion> rentRegionFlag;
@Inject
public RentCommand(@Nonnull IFileManager fileManager) {
this.rentRegionFlag = RegionParseUtil.createDefaultRent(fileManager);
}
@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 String getHelp(CommandSender target) {
if(target.hasPermission("areashop.rent")) {
return "help-rent";
}
return null;
}
@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");
} else {
rent.rent(player);
}
} else {
// get the region by location
List<RentRegion> regions = Utils.getApplicableRentRegions(((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 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,113 +1,130 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
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.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 {
public ResellCommand(AreaShop plugin) {
super(plugin);
}
@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;
@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 String stringDescription() {
return null;
}
@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);
}
@Override
protected @NonNull CommandProperties properties() {
return CommandProperties.of("resell");
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.resellall") || target.hasPermission("areashop.resell")) {
return "help-resell";
}
return null;
}
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);
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.resellall") || target.hasPermission("areashop.resell")) {
return "help-resell";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.resell") && !sender.hasPermission("areashop.resellall")) {
plugin.message(sender, "resell-noPermissionOther");
return;
}
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;
}
BuyRegion buy;
if(args.length <= 2) {
if (sender instanceof Player) {
// get the region by location
List<BuyRegion> regions = Utils.getApplicableBuyRegions(((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)) {
buy.enableReselling(price);
buy.update();
plugin.message(sender, "resell-success", buy);
} else {
plugin.message(sender, "resell-noPermissionOther", 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;
}
}
@@ -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,89 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SchematiceventCommand extends CommandAreaShop {
public SchematiceventCommand(AreaShop plugin) {
super(plugin);
}
@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.isRentRegion()) {
result.addAll(Arrays.asList("created", "deleted", "rented", "unrented"));
} else if(region.isBuyRegion()) {
result.addAll(Arrays.asList("created", "deleted", "bought", "sold"));
}
}
}
return result;
}
}
@@ -1,101 +1,116 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
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 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 {
public SellCommand(AreaShop plugin) {
super(plugin);
}
@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;
}
@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.getApplicableBuyRegions(((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 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;
}
/**
* 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 String stringDescription() {
return null;
}
@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,110 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.regions.RentRegion;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class SetdurationCommand extends CommandAreaShop {
public SetdurationCommand(AreaShop plugin) {
super(plugin);
}
@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.getApplicableRentRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
rent = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
rent = plugin.getFileManager().getRent(args[regionArgument]);
}
if(rent == null) {
plugin.message(sender, "setduration-notRegistered", args[regionArgument]);
return;
}
if(!sender.hasPermission("areashop.setduration") && !(sender instanceof Player && rent.isLandlord(((Player)sender).getUniqueId()))) {
plugin.message(sender, "setduration-noLandlord", rent);
return;
}
if("default".equalsIgnoreCase(args[1]) || "reset".equalsIgnoreCase(args[1])) {
rent.setDuration(null);
rent.update();
plugin.message(sender, "setduration-successRemoved", rent);
return;
}
try {
Integer.parseInt(args[1]);
} catch(NumberFormatException e) {
plugin.message(sender, "setduration-wrongAmount", args[1], rent);
return;
}
if(!Utils.checkTimeFormat(args[1]+" "+args[2])) {
plugin.message(sender, "setduration-wrongFormat", args[1]+" "+args[2], rent);
return;
}
rent.setDuration(args[1]+" "+args[2]);
rent.update();
plugin.message(sender, "setduration-success", rent);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getRentNames();
} else if(toComplete == 4) {
result.addAll(plugin.getConfig().getStringList("minutes"));
result.addAll(plugin.getConfig().getStringList("hours"));
result.addAll(plugin.getConfig().getStringList("days"));
result.addAll(plugin.getConfig().getStringList("months"));
result.addAll(plugin.getConfig().getStringList("years"));
}
return result;
}
}
@@ -1,92 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.regions.GeneralRegion;
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 {
public SetlandlordCommand(AreaShop plugin) {
super(plugin);
}
@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.getAllApplicableRegions(((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,145 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
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 {
public SetownerCommand(AreaShop plugin) {
super(plugin);
}
@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.getAllApplicableRegions(((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.isRentRegion() && !sender.hasPermission("areashop.setownerrent")) {
plugin.message(sender, "setowner-noPermissionRent", region);
return;
}
if(region.isBuyRegion() && !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.isRentRegion()) {
RentRegion rent = (RentRegion)region;
if(rent.isRenter(uuid)) {
// extend
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(rent.getRentedUntil() + rent.getDuration());
rent.setRentedUntil(calendar.getTimeInMillis());
rent.setRenter(uuid);
rent.update();
plugin.message(sender, "setowner-succesRentExtend", region);
} else {
// change
Calendar calendar = Calendar.getInstance();
long current = calendar.getTimeInMillis();
if(rent.isRented()) {
current = rent.getRentedUntil();
}
calendar.setTimeInMillis(current + rent.getDuration());
rent.setRentedUntil(calendar.getTimeInMillis());
rent.setRenter(uuid);
rent.update();
plugin.message(sender, "setowner-succesRent", region);
}
}
if(region.isBuyRegion()) {
BuyRegion buy = (BuyRegion)region;
buy.setBuyer(uuid);
buy.update();
plugin.message(sender, "setowner-succesBuy", 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,108 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
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 java.util.ArrayList;
import java.util.List;
public class SetpriceCommand extends CommandAreaShop {
public SetpriceCommand(AreaShop plugin) {
super(plugin);
}
@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.getAllApplicableRegions(((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.isRentRegion()) {
((RentRegion)region).removePrice();
} else if(region.isBuyRegion()) {
((BuyRegion)region).removePrice();
}
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.isRentRegion()) {
((RentRegion)region).setPrice(price);
plugin.message(sender, "setprice-successRent", region);
} else if(region.isBuyRegion()) {
((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,78 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
public class SetrestoreCommand extends CommandAreaShop {
public SetrestoreCommand(AreaShop plugin) {
super(plugin);
}
@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,123 +0,0 @@
package me.wiefferink.areashop.commands;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
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 java.util.ArrayList;
import java.util.List;
public class SetteleportCommand extends CommandAreaShop {
public SetteleportCommand(AreaShop plugin) {
super(plugin);
}
@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.getAllApplicableRegions(((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.isRentRegion()) {
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.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.setTeleport(player.getLocation());
region.update();
plugin.message(player, "setteleport-success", region);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
result.add("reset");
}
return result;
}
}
@@ -1,220 +1,285 @@
package me.wiefferink.areashop.commands;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.bukkit.selections.Selection;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.messages.Message;
import me.wiefferink.areashop.regions.BuyRegion;
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.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 {
public StackCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop stack";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.stack")) {
return "help-stack";
}
return null;
}
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 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 Selection selection = plugin.getWorldEdit().getSelection(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(!(facing == BlockFace.NORTH || facing == BlockFace.EAST || facing == BlockFace.SOUTH || facing == BlockFace.WEST)) {
plugin.message(player, "stack-unclearDirection", facing.toString().toLowerCase().replace('_', '-'));
return;
}
final Location shift = new Location(selection.getWorld(), 0, 0, 0);
if(facing == BlockFace.SOUTH) {
shift.setZ(-selection.getLength() - gap);
} else if(facing == BlockFace.WEST) {
shift.setX(selection.getWidth() + gap);
} else if(facing == BlockFace.NORTH) {
shift.setZ(selection.getLength() + gap);
} else if(facing == BlockFace.EAST) {
shift.setX(-selection.getWidth() - gap);
}
AreaShop.debug(" calculated shift vector: " + shift + ", with facing=" + facing);
// Create regions and add them to AreaShop
final String namePrefix = args[3];
final int regionsPerTick = plugin.getConfig().getInt("adding.regionsPerTick");
final boolean rentRegions = "rent".equalsIgnoreCase(args[4]);
final int amount = tempAmount;
final RegionGroup finalGroup = group;
String type;
if(rentRegions) {
type = "rent";
} else {
type = "buy";
}
Message groupsMessage = Message.none();
if(group != null) {
groupsMessage = Message.fromKey("stack-addToGroup").replacements(group.getName());
}
plugin.message(player, "stack-accepted", amount, type, gap, namePrefix, groupsMessage);
plugin.message(player, "stack-addStart", amount, regionsPerTick*20);
new BukkitRunnable() {
private int current = 0;
private RegionManager manager = AreaShop.getInstance().getWorldGuard().getRegionManager(selection.getWorld());
private int counter = 1;
@Override
public void run() {
for(int i=0; i<regionsPerTick; i++) {
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 = namePrefix + 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;
}
regionName = namePrefix + counterName;
}
// Add the region to WorldGuard (at startposition shifted by the number of this region times the blocks it should shift)
ProtectedCuboidRegion region = new ProtectedCuboidRegion(regionName,
new BlockVector(
selection.getMinimumPoint().getBlockX() + shift.getBlockX()*current,
selection.getMinimumPoint().getBlockY() + shift.getBlockY()*current,
selection.getMinimumPoint().getBlockZ() + shift.getBlockZ()*current
),
new BlockVector(
selection.getMaximumPoint().getBlockX() + shift.getBlockX()*current,
selection.getMaximumPoint().getBlockY() + shift.getBlockY()*current,
selection.getMaximumPoint().getBlockZ() + shift.getBlockZ()*current
)
);
manager.addRegion(region);
// Add the region to AreaShop
if(rentRegions) {
RentRegion rent = new RentRegion(plugin, region.getId(), 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(plugin, region.getId(), 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();
}
current++;
}
}
if(current >= amount) {
if(player.isOnline()) {
plugin.message(player, "stack-addComplete");
}
this.cancel();
}
}
}.runTaskTimer(plugin, 1, 1);
}
@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;
}
@Inject
public StackCommand(
@Nonnull MessageBridge messageBridge,
@Nonnull Plugin plugin,
@Nonnull WorldEditInterface worldEditInterface,
@Nonnull WorldGuardInterface worldGuardInterface,
@Nonnull RegionFactory regionFactory,
@Nonnull IFileManager fileManager
) {
this.messageBridge = messageBridge;
this.plugin = plugin;
this.worldEditInterface = worldEditInterface;
this.worldGuardInterface = worldGuardInterface;
this.regionFactory = regionFactory;
this.fileManager = fileManager;
}
@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;
}
@Override
public String getHelpKey(@NotNull CommandSender target) {
if (target.hasPermission("areashop.stack")) {
return "help-stack";
}
return null;
}
@Override
public String stringDescription() {
return null;
}
@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,116 +0,0 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
import me.wiefferink.areashop.regions.BuyRegion;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class StopresellCommand extends CommandAreaShop {
public StopresellCommand(AreaShop plugin) {
super(plugin);
}
@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.getApplicableBuyRegions(((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,85 +1,96 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
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 {
public TeleportCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop tp";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.teleportall") || target.hasPermission("areashop.teleport")) {
return "help-teleport";
}
return null;
}
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;
/**
* 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.getFriendsFeature().getFriends().contains(player.getUniqueId()) && player.hasPermission("areashop.teleportfriend");
}
private final IFileManager fileManager;
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.teleport") && !sender.hasPermission("areashop.teleportall") && !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.teleportPlayer(player, true);
} else {
region.teleportPlayer(player, false);
}
@Inject
public TeleportCommand(@Nonnull MessageBridge messageBridge, @Nonnull IFileManager fileManager) {
this.messageBridge = messageBridge;
this.fileManager = fileManager;
}
}
@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;
}
/**
* 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 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,101 +1,114 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.Utils;
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 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;
public UnrentCommand(AreaShop plugin) {
super(plugin);
}
@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.getApplicableRentRegions(((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 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
public String stringDescription() {
return null;
}
@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 275 files, more files were not shown because too many files have changed in this diff. Show more