Compare commits

...

212 Commits

Author SHA1 Message Date
tastybento 519a2d05fc Version 1.15.0 2024-02-03 08:30:12 -08:00
tastybento 86c089b694 Update tipped arrows in GUI Panel 2024-01-21 09:09:17 -08:00
tastybento 3417633c4d Version 1.14.1 2024-01-21 09:09:12 -08:00
tastybento b16d5102b1
Merge pull request #129 from BentoBoxWorld/tastybento-patch-1
Update addon.yml
2024-01-12 14:37:29 -08:00
tastybento 4375eba030
Update addon.yml
Fix because the warps command got its own perm from a1e03af
2024-01-12 14:36:38 -08:00
tastybento bc1e92ee8d Add support for hanging signs.
Warps to below the sign.
2024-01-06 22:00:24 +09:00
tastybento b88497397f
Merge pull request #126 from BentoBoxWorld/gitlocalize-27267
Add Ukrainian locale
2023-11-26 10:00:25 -08:00
GIGABAIT b45c88025f Translate uk.yml via GitLocalize 2023-11-26 11:18:41 +00:00
tastybento 3c9515295d Merge branch 'develop' of https://github.com/BentoBoxWorld/Warps.git into develop 2023-11-12 13:25:11 -08:00
tastybento 82a0630ca3 BentoBox API 2.0.0 2023-11-12 13:25:03 -08:00
BONNe 6dbdb0f8aa
Update WarpsCommandTest.java 2023-11-05 22:00:28 +02:00
BONNe a1e03af13a
Update WarpsCommand.java 2023-11-05 21:35:59 +02:00
tastybento 2558d9d1ab
Merge pull request #124 from rchomczyk/fix-pl-translation
Improve polish translation
2023-09-04 07:46:24 -07:00
Rafał Chomczyk d346b7864e
Fix invalid placeholder name for warp's description; improve translations by a little, fix typo 2023-09-03 17:50:30 +02:00
BONNe 0e1cd1353c
Version Up 2023-07-26 15:37:35 +03:00
tastybento 9657d11af7
Update pom.xml 2023-07-10 21:39:57 -07:00
tastybento ab1a1e203c Update Jacoco 2023-07-10 21:24:40 -07:00
tastybento 1a90acb65f Update GitHub Action versions 2023-06-24 13:49:47 -07:00
tastybento ae172b9fdf Minor variable rename 2023-06-24 13:49:33 -07:00
tastybento ecebbcd039
Merge pull request #122 from BentoBoxWorld/gitlocalize-24193
Spanish
2023-05-29 09:40:06 -07:00
tastybento 3faed651aa
Merge pull request #123 from BentoBoxWorld/gitlocalize-24194
Indonesian
2023-05-29 09:39:49 -07:00
Dusty 0585fd7f3a Translate id.yml via GitLocalize 2023-05-29 16:35:40 +00:00
Espan 2f59225718 Translate es.yml via GitLocalize 2023-05-29 16:35:13 +00:00
tastybento 9e57851c62 Update GitHub build script to Java 17 2023-04-16 11:02:01 -07:00
tastybento b998b46fd5 User BentoBox release build 2023-04-16 11:00:06 -07:00
tastybento cb165e52b0 Updated POM; fixed tests. 2023-04-15 13:08:55 -07:00
BONNe ebb3f05d78
Merge pull request #119 from BentoBoxWorld/return-to-plugin
Return to plugin.yml
2023-04-08 19:10:40 +03:00
BONNe fe6b020ac8
Update WarpsPladdon.java 2023-04-08 19:10:32 +03:00
BONNe d2dde61d8b
Update pom.xml 2023-04-08 19:10:15 +03:00
BONNe e58010547b
Create plugin.yml 2023-04-08 19:09:38 +03:00
tastybento 5a9f6495ad Updated pladdon dependencies. Removed unused imports. 2023-03-25 10:12:07 -07:00
tastybento ff4850d32a Use addon name in annotation 2023-03-25 09:59:53 -07:00
DevSolaris 7a26acefd9
Flip bool expression (#114) 2023-02-12 10:44:49 -08:00
tastybento 2be57a66d2 Fix SonarCloud bugs and smells. 2023-02-09 17:44:25 -08:00
tastybento 67c5c9f8c3 Updated Jacoco POM 2023-02-09 17:38:25 -08:00
tastybento 62f1f2e966
Add ${argLine} to get jacoco coverage 2023-02-09 15:13:34 -08:00
BONNe 5a37c3da75
Merge pull request #118 from BentoBoxWorld/gitlocalize-22781
Update NL
2023-01-24 15:18:17 +02:00
DevSolaris 94e9208941 Translate nl.yml via GitLocalize 2023-01-24 13:18:06 +00:00
BONNe 225b4d66f8
Update Warp.java 2023-01-19 23:15:38 +02:00
BONNe d3b45396fd
Add missing import 2023-01-19 23:10:00 +02:00
BONNe d2b9540650
Update locale 2023-01-19 23:06:57 +02:00
BONNe 363a628244
Improve create warps flag.
Rename the flag to PLACE_WARP as it is a more proper name.
Also, add a click handler that limits setting value from member to owner, as visitors should not be allowed.

Also, set default value outside island range as false.
2023-01-19 23:06:45 +02:00
DevSolaris 8be844b59f
Closes #69 - Fix message from being sent when the user is banned. (#116) 2023-01-19 21:59:39 +01:00
DevSolaris b3a36c75bb
Create set warp flag (#117) 2023-01-19 21:56:31 +01:00
DevSolaris 7dbb5d39ad
Add gamemode placeholder to message (#115) 2023-01-18 22:14:50 +01:00
BONNe fb1090717b
Merge pull request #113 from BentoBoxWorld/gitlocalize-20471
Update Polish translation
2022-08-23 10:54:09 +03:00
mt-gitlocalize 39b94e09d8 Translate pl.yml via GitLocalize 2022-08-23 07:53:37 +00:00
wiktorm12 5716214527 Translate pl.yml via GitLocalize 2022-08-23 07:53:37 +00:00
BONNe 153e8be6a0
Init next version 2022-05-17 12:32:25 +03:00
BONNe 0dea651274
Fix build number for warps
1.11.2 was already released.
2022-05-17 12:20:13 +03:00
BONNe 63b51fb26e
Merge pull request #109 from BentoBoxWorld/gitlocalize-18727
Update German translation
2022-04-09 12:32:55 +03:00
Patrick 15a699037a Translate de.yml via GitLocalize 2022-04-09 09:30:14 +00:00
BONNe cbaf6ce16c Implement customizable Warps Panel.
Relates to #BentoBox/issues/1931
These changes includes to removing some obsolete config settings and locales string.
Also, moved some classes around to clean up directory.
2022-03-11 12:34:16 +02:00
Huynh Tien b12a6dcff9
Update id.yml (#108) 2022-01-28 07:13:25 -08:00
gitlocalize-app[bot] 89bcc54e23
Translate it.yml via GitLocalize (#107)
Co-authored-by: Pirlas <alexpirlas@outlook.it>
2022-01-01 16:47:50 -08:00
gitlocalize-app[bot] 6db80f73f8
Taiwan translation (#106)
* Translate zh-TW.yml via GitLocalize

* Translate zh-TW.yml via GitLocalize

Co-authored-by: Shaowing <lien78520@gmail.com>
Co-authored-by: mt-gitlocalize <mt@gitlocalize.com>
2022-01-01 16:47:40 -08:00
gitlocalize-app[bot] 87d04302d2
Indonesian Translation (#105)
* Translate id.yml via GitLocalize

* Translate id.yml via GitLocalize

* Translate id.yml via GitLocalize

Co-authored-by: Alunite? <xcionsspro30@gmail.com>
Co-authored-by: mt-gitlocalize <mt@gitlocalize.com>
Co-authored-by: gitlocalize-app[bot] <55277160+gitlocalize-app[bot]@users.noreply.github.com>
2022-01-01 16:47:29 -08:00
gitlocalize-app[bot] 9b0f00f2a0
Translate hu.yml via GitLocalize (#104)
Co-authored-by: driverdakid <tamascsiszar99@icloud.com>
2022-01-01 16:47:18 -08:00
gitlocalize-app[bot] 048f7237da
French translation (#103)
* Translate fr.yml via GitLocalize

* Translate fr.yml via GitLocalize

Co-authored-by: Aksel <afgameytb@gmail.com>
Co-authored-by: HipppB <hippolyte.bach@eleve.isep.fr>
2022-01-01 16:47:08 -08:00
gitlocalize-app[bot] 49d461d224
Translate tr.yml via GitLocalize (#102)
Co-authored-by: Over_Brave <soncesurlar@gmail.com>
2022-01-01 16:46:54 -08:00
Huynh Tien 6cfaa0e9c0
Fix null player on removeWarp (#100) 2021-12-31 08:25:05 -08:00
tastybento 9290503be3 Fix plugin.yml 2021-12-21 14:13:48 -08:00
tastybento 079dba0f41 Merge branch 'develop' of https://github.com/BentoBoxWorld/Warps.git into develop 2021-10-01 19:04:19 -07:00
tastybento 60c427c2a9 Build to BentoBox 1.18 API 2021-10-01 19:04:09 -07:00
KrazyxWolf 6caa652162
Update es.yml (#98) 2021-08-26 18:02:37 -07:00
tastybento 4ebaa22f37 Renamed plugin Pladdon 2021-08-12 18:48:39 -07:00
tastybento f0780d91ba Version 1.11.2 2021-08-12 18:48:29 -07:00
tastybento 55ec1ded61 Remove this deprecated event. 2021-08-08 18:28:29 -07:00
tastybento d936fbecc1 More code cleanup 2021-08-08 18:28:19 -07:00
tastybento 6c4c42ff64 Clean up tests. 2021-08-08 18:19:55 -07:00
tastybento 00938e67da Code smell reduction. 2021-08-08 18:09:28 -07:00
tastybento 3cd93f39dd Objects.requireNonNull for User 2021-08-08 17:36:03 -07:00
tastybento 0003c91cca Make Warps a Pladdon. 2021-08-08 16:40:13 -07:00
tastybento f6207ababd Update to Java 16 for GitHub Action building 2021-07-09 09:07:43 -07:00
tastybento 9333265e4d Fix PVP message when teleporting to an island. 2021-07-09 09:00:56 -07:00
tastybento 8c8f25f6d4 Version 1.11.1 2021-07-09 09:00:43 -07:00
tastybento afec2f56f5 Java 16 Minecraft 17 2021-06-20 11:29:45 -07:00
tastybento fc4f6c634a Return null if Level addon is not operating in world 2021-06-05 08:37:42 -07:00
tastybento 757a39e7f9 Github workflows sonar cloud 2021-03-06 12:37:51 -08:00
Huynh Tien 9db549ea0d
Add files via upload (#95) 2021-02-03 12:14:32 -08:00
tastybento 7fbe4b5b88 Fixes sync errors and blank warps
https://github.com/BentoBoxWorld/Warps/issues/93
https://github.com/BentoBoxWorld/Warps/issues/92
https://github.com/BentoBoxWorld/Warps/issues/75
2021-01-09 15:33:27 -08:00
tastybento 82bd4c8b31 Shows GUI correctly 2021-01-09 11:37:41 -08:00
tastybento 4ad5d864ab Use SignCacheItem
Indicate whether it is real or not.
2021-01-09 11:19:35 -08:00
tastybento dcd5bd1514 Run offlinePlayer code async to avoid blocking IO 2021-01-09 10:38:47 -08:00
tastybento 2506d2ac9e Deprecated and removed WarpListEvent
Cannot be fired because this part of the code needs to run async.

https://github.com/BentoBoxWorld/Warps/issues/93
2021-01-08 22:14:03 -08:00
tastybento c882ca3288 Added owner to WarpRemoveEvent
https://github.com/BentoBoxWorld/Warps/issues/91
2021-01-03 17:54:33 -08:00
tastybento 4817c2c913 Version 1.11.0 2021-01-03 17:54:05 -08:00
tastybento 86612b72e3 Move warp panel creation async and reworked test class. 2021-01-01 15:36:14 -08:00
tastybento 02a27f3df7 Version 1.15.6 2021-01-01 15:35:38 -08:00
tastybento 2d3d2f10d6 Use BentoBox 1.15.4 2020-12-30 22:58:49 -08:00
tastybento 36284d963b Merge branch 'develop' of https://github.com/BentoBoxWorld/Warps.git into develop 2020-12-27 11:14:43 -08:00
tastybento 73aab77c99 Updated to BentoBox 1.15.4 API 2020-12-27 11:14:19 -08:00
gitlocalize-app[bot] 1591bfc36d
Translate tr.yml via GitLocalize (#90)
Co-authored-by: Over_Brave <soncesurlar@gmail.com>
2020-12-09 11:51:43 -08:00
Yasin e459c53c77
WarpCreateEvent (#88) 2020-09-10 18:34:56 -07:00
Gabriele C 45b968820b
Don't validate unloaded signs on startup (#85)
* Don't validate unloaded signs in startup

* Actually stop loading chunks

* Fix crash issues due to unwanted chunk loads in the sign ChunkLoadEvent listener

* Delay chunk handling, fixes CMEs
2020-09-07 09:14:44 -07:00
tastybento bee85b0db1 Do not send warp message if player is hidden.
https://github.com/BentoBoxWorld/Warps/issues/87
2020-08-29 08:58:44 -07:00
tastybento abf4b882c0 Fixes test 2020-08-06 21:06:19 -07:00
wellnesscookie fd06c0cdd7
Fixes unwanted parsing when warping to an island (#86)
* Fixes incorrect parsing when warping to similiar players

* Removes debug lines
2020-08-06 12:14:50 -07:00
tastybento 27afafadce 1.14.0 BentoBox API 2020-07-07 18:43:34 -07:00
tastybento b482a1b3e4 Version 1.10.0 2020-06-26 16:24:32 -07:00
tastybento 4cb6b66bc7 BentoBox 1.14 API 2020-06-10 21:31:20 -07:00
NotMyFault 262889c49f
Fix typo (#82) 2020-06-04 07:26:57 -07:00
tastybento 619acc55cd Version 1.9.7 2020-06-02 14:35:17 -07:00
tastybento 8f38353b73 Fixes tests 2020-06-02 14:34:21 -07:00
tastybento 6d4b7c2a19 WIP 2020-06-02 13:00:09 -07:00
tastybento 94f0ff4e22 Sign Cache could get out of sync with signs.
https://github.com/BentoBoxWorld/Warps/issues/80
2020-05-27 16:48:20 -07:00
tastybento 74675abce6 Version 1.9.6 2020-05-27 16:47:55 -07:00
tastybento 9c4a224c97 Fixes bug where Warps would not hook with no game modes
https://github.com/BentoBoxWorld/Warps/issues/77
2020-05-20 18:57:56 -07:00
tastybento 75feedbec0 Version 1.9.5 2020-05-20 18:57:10 -07:00
tastybento 826b86ae64 Merge remote-tracking branch 'origin/develop' 2020-05-19 19:34:45 -07:00
tastybento df6936ff1f Merge branch 'develop' of https://github.com/BentoBoxWorld/Warps.git into develop 2020-05-19 19:34:09 -07:00
tastybento 77b834a7bd Version 1.9.4. 2020-05-19 19:33:59 -07:00
John 23b2d19b0d
Add german (de) translation (#74) 2020-04-29 20:40:06 -07:00
Krystian 45813ee39a
Add Polish translation (#73) 2020-04-20 07:36:28 -07:00
tastybento eea1ea25e1 Updated permissions 2020-04-19 08:36:17 -07:00
tastybento c62de9d021 Merge remote-tracking branch 'origin/develop'
Conflicts:
	.gitignore
2020-04-19 08:30:32 -07:00
tastybento 88bae57218 Updated gitignore 2020-04-19 08:29:18 -07:00
Clément P 6dab2f3ce7
Add Gitignore (#72) 2020-04-06 17:35:37 -07:00
tastybento 40c0b8d791 Fixes bug where database table existed but had no valid data in it.
Fixes https://github.com/BentoBoxWorld/Warps/issues/71
2020-04-02 12:54:55 -07:00
tastybento f3fe87c757
Czech translation. Credit @Polda18 2020-01-30 10:22:26 -08:00
tastybento 79b8c0cd87 Added saving of the warp sign cache to database.
Relates to https://github.com/BentoBoxWorld/Warps/issues/68
2020-01-28 17:11:23 -08:00
tastybento ef523d4332 Removed warp sign for players who leave a team or are kicked.
Fixes https://github.com/BentoBoxWorld/Warps/issues/67
2020-01-14 17:34:28 -08:00
tastybento a51930fa05 Version 1.9.3 2020-01-14 17:11:06 -08:00
tastybento 490caf098e Made listeners package 2020-01-14 17:03:06 -08:00
gitlocalize-app[bot] 685f2beb5f Translate lv.yml via GitLocalize (#66)
Co-authored-by: BONNe <bonne@bonne.id.lv>
2020-01-10 16:29:24 -08:00
gitlocalize-app[bot] a63a6c2372 Translate zh-CN.yml via GitLocalize (#65) 2019-12-27 12:28:24 -08:00
tastybento b2d5c145a5 Ties into the BentoBox delayed teleport settings.
https://github.com/BentoBoxWorld/Warps/issues/52
2019-12-08 16:02:55 -08:00
Florian CUNY d8b56f5448 Update name in pom from WelcomeWarpSigns to Warps (#64) 2019-12-08 15:19:28 -08:00
tastybento 46333baa52 Merge remote-tracking branch 'origin/master' into develop 2019-12-08 08:45:14 -08:00
tastybento bf6d7994dd Version 1.9.1
Changes stand alone command to /wwarp and /wwarps to match original
Welcome Warp Signs plugin.
2019-12-08 08:44:08 -08:00
András Marczinkó 0176019d19 Update hu.yml (#63)
Removed spaces after color codes.
2019-12-06 13:39:46 -08:00
András Marczinkó 2d796471c5 Update hu.yml (#62) 2019-12-06 08:30:38 -08:00
tastybento 51b37ff2c6 Version 1.9.0 2019-12-02 13:46:07 -08:00
tastybento a74037fd1b Merge remote-tracking branch 'origin/develop' 2019-12-02 13:45:49 -08:00
tastybento d2ef5d9400 Removed blank locale files. 2019-12-02 13:43:22 -08:00
tastybento 8ee9168a55 Merge branch 'develop' of https://github.com/BentoBoxWorld/Warps.git into develop 2019-12-02 13:23:33 -08:00
tastybento d14a6e1282 Cleaned up color codes and added spaces. 2019-12-02 13:23:24 -08:00
tastybento 9e172d3116 Merge branch 'develop' 2019-11-30 09:08:54 -08:00
gitlocalize-app[bot] 8f677e362b Translate ru.yml via GitLocalize (#60) 2019-11-28 15:03:30 -08:00
András Marczinkó cf0755e7ce Translated into Hungarian (#59) 2019-11-24 13:50:18 -08:00
tastybento 8083ce6f01 Merge remote-tracking branch 'origin/develop' 2019-11-22 13:34:47 -08:00
tastybento 037ca558cf
Update bug_report.md 2019-11-17 17:44:27 -08:00
tastybento 3dab96e546
Create id.yml 2019-11-16 18:32:16 -08:00
tastybento c361f0a1a3
Create ro.yml 2019-11-16 18:32:08 -08:00
tastybento ccc1f9c849 Merge branch 'develop' of https://github.com/BentoBoxWorld/Warps.git into develop 2019-11-11 07:58:05 -08:00
tastybento ae1c2fe96f Use BentoBox utility method for BlockFaceToFloat 2019-11-11 07:57:55 -08:00
tastybento eb0930757c Removed sonar_token reference from travis.yml 2019-11-07 16:52:39 -08:00
tastybento c73bf8bad7 Do not register top-level commands if config setting isn't true
https://github.com/BentoBoxWorld/Warps/issues/57
2019-11-07 15:52:49 -08:00
tastybento 455242396f Merge remote-tracking branch 'origin/develop' 2019-11-03 08:58:02 -08:00
tastybento a013a1e6a1 Version up 1.8.1 2019-11-03 08:52:29 -08:00
tastybento 9a234ef950 Added WarpsCommand test class 2019-10-31 17:33:34 -07:00
tastybento d7e0b36623 Added WarpCommand test class 2019-10-31 17:05:12 -07:00
tastybento 55558711cc Code smell - simplified listener 2019-10-31 14:49:26 -07:00
tastybento 6d788b6f66 Fixes potential null bugs 2019-10-31 14:22:32 -07:00
tastybento 85334079da Fixed code smells 2019-10-31 14:12:44 -07:00
tastybento 007f071234 Enabling sonarcloud 2019-10-31 10:18:13 -07:00
tastybento afb03e6d42 Enables warps to operate in any world. Commands can be changed.
https://github.com/BentoBoxWorld/Warps/issues/53
https://github.com/BentoBoxWorld/Warps/issues/54
2019-10-31 10:09:33 -07:00
gitlocalize-app[bot] 197957648b Translate fr.yml via GitLocalize (#55) 2019-10-28 22:11:56 -07:00
DuckSoft 5ee1520d8b Translate zh-CN.yml via GitLocalize (#51) 2019-09-20 07:14:47 -07:00
BONNe 0f00c7bd52 Translate lv.yml via GitLocalize (#50) 2019-09-19 17:08:35 -07:00
tastybento f8243e3035 Added test cases. 2019-09-19 14:45:15 -07:00
tastybento 38c5496118 Added random warp button to warps panel
https://github.com/BentoBoxWorld/Warps/issues/20
2019-09-19 14:23:29 -07:00
tastybento b98d83fffc Added WarpSignsManager test class 2019-09-18 16:48:54 -07:00
tastybento bbc748aae3 Enabled formatting of warp sign text
https://github.com/BentoBoxWorld/Warps/issues/48
2019-09-18 16:48:38 -07:00
tastybento 675f5791bd Version 1.8.0 2019-09-15 16:41:26 -07:00
tastybento d0355e8b9e Listener was not registered using BentoBox API so caused reload issues. 2019-09-15 16:41:17 -07:00
tastybento 6a6ac19ef0 Updated ReadMe 2019-09-13 18:32:40 -07:00
tastybento 0814f22424 Config file was not being read.
Signs removed by breaking blocks under them and then replaced were not
being correctly handled. Now they are deleted and remade. No need for
the "duplicate sign" text.

https://github.com/BentoBoxWorld/Warps/issues/47
https://github.com/BentoBoxWorld/Warps/issues/46
https://github.com/BentoBoxWorld/Warps/issues/32
2019-09-13 18:13:03 -07:00
Florian CUNY 8de53d1a81
Renamed addon to "Warps" to follow the repo's name in addon.yml
+ added icon
2019-09-07 14:21:46 +02:00
BONNe b001aad4d9 Translate lv.yml via GitLocalize (#42) 2019-09-03 07:55:40 -07:00
tastybento b29457cc97 Updated locale files for GitLocalize 2019-09-03 07:35:41 -07:00
BONNe 5dbc762027 Implement ability to change Warp Sign Icon in Warps panel via user permission. (#41)
Permission that will be checked is "[gamemode].island.warp.[material]"
This will not filter out invalid materials.
2019-09-02 09:16:54 -07:00
tastybento 4d1d9a5098 Removed inaccessible API. 2019-08-22 15:21:47 -07:00
tastybento c671e35661 Adds the missing support for PLAYER_HEAD icons
https://github.com/BentoBoxWorld/Warps/issues/38
2019-08-22 15:08:14 -07:00
tastybento 633f2a63e2 Adds an API to request data from the WarpSignsManager class
https://github.com/BentoBoxWorld/Warps/issues/39
2019-08-22 12:53:38 -07:00
tastybento 57bed61167 Added help to /is warp with no parameter. Improved locale clarity 2019-08-20 07:54:51 -07:00
tastybento 8c6fb4f4ee Fixed permission reference 2019-08-20 07:50:11 -07:00
tastybento af3a055bcc Merge branch 'develop' of https://github.com/BentoBoxWorld/addon-welcomewarpsigns.git into develop 2019-08-11 12:51:22 -07:00
tastybento 18c7ee5e0d Updated POM to show build numbers and updated test class 2019-08-11 12:51:14 -07:00
wellnesscookie 9ae7e39259 Fixes wrong permissions (#33) 2019-07-31 09:13:11 -07:00
tastybento 43bc50687c Fixes bug where warp sign text wasn't showing in chat response
https://github.com/BentoBoxWorld/addon-welcomewarpsigns/issues/28
2019-06-30 20:09:07 -07:00
tastybento 4621772fe8 Caches sign type as well as sign text.
https://github.com/BentoBoxWorld/addon-welcomewarpsigns/issues/27
2019-06-26 17:30:11 -07:00
tastybento 29b9c3421e Version 1.5.0 2019-06-09 21:31:43 -07:00
tastybento 54da29e9f3 1.5.0 version 2019-05-15 15:16:59 -07:00
tastybento 45ee5b1186 Hybrid version. Works on 1.13.2 and 1.14.1 2019-05-15 15:16:15 -07:00
tastybento ddffcf3f38 Merge remote-tracking branch 'origin/develop' into 1.14
Conflicts:
	pom.xml
	src/main/java/world/bentobox/warps/config/Settings.java
2019-05-10 18:26:49 -07:00
tastybento 14a992a057 Merge remote-tracking branch 'origin/develop' into 1.14
Conflicts:
	src/main/java/world/bentobox/warps/WarpPanelManager.java
2019-05-10 18:24:46 -07:00
tastybento 6029ae6b2d YAML fix 2019-05-08 12:30:53 -07:00
tastybento 5a7648f998 Spanish locale translation. Credit @SrAcosta. 2019-05-08 12:30:53 -07:00
tastybento a5ff39cbec Uses ConfigObject instead of DatabaseObject for config file. 2019-05-08 12:30:53 -07:00
tastybento 684b17cc34 Fixes tests 2019-05-02 11:43:57 -07:00
tastybento 5b07d33491 Works, but tests do not pass due to Tag issue 2019-04-29 23:23:54 -07:00
BONNe 0f9232d016 Add ability to change icon in Warps panel. (#24) 2019-03-30 14:32:31 -07:00
tastybento aeb5a60e94 Merge remote-tracking branch 'origin/develop' 2019-03-28 20:55:09 -07:00
tastybento bfbf95486f Version 1.4.0 2019-03-28 20:53:51 -07:00
tastybento 622057c906 Checks for null worlds on load. 2019-03-06 22:04:47 -08:00
tastybento 79b568fbdf Updates locales. Fixes nether and end warping.
Fixes issue with warp level checking wrong environment.

Adds warning when warping to PVP enabled islands.

https://github.com/BentoBoxWorld/addon-welcomewarpsigns/issues/21
2019-03-03 18:53:36 -08:00
tastybento 140e05770d Version up
Added codemc public repo.
2019-03-03 17:35:38 -08:00
Florian CUNY 88c8ed89cf Added fr-FR locale 2019-02-22 14:42:09 +01:00
tastybento 479c84e8fe
Merge pull request #15 from BONNe/permissions
Update Addon Permissions
2019-02-03 19:14:58 -08:00
BONNe 2f86f91fa4 Add CaveBlock and SkyGrid permissions. 2019-02-03 17:07:08 +02:00
tastybento 35f0ecb6f0 Fixes config.yml
uniqueId was missing.
2019-02-02 16:11:40 -08:00
tastybento c4d80aea77
Merge pull request #13 from BONNe/develop
Improve WelcomeWarpSign addon
2019-01-31 11:33:49 -08:00
BONNe 9c88792b27 Disable warp teleport while falling if world Flags.PREVENT_TELEPORT_WHEN_FALLING is enabled. 2019-01-31 20:27:15 +02:00
BONNe aa1f0bdcba Rename PluginConfig to Settings.
- Settings is now correct Config for Addon.
Improve Warp class a bit:
- add some javaDoc.
- load only if hooked.
2019-01-31 20:25:32 +02:00
tastybento da996714a1 Check for warp file before loading 2019-01-29 14:04:56 -08:00
tastybento 2bf5299a16 Version up. Fixed POM. 2019-01-29 13:52:44 -08:00
tastybento e80be18712 Updated to lated API 2019-01-16 12:46:39 -08:00
tastybento 6c519b5df1 Added GitHub templates. 2019-01-01 22:39:26 -08:00
Florian CUNY 695e8b4c6b The Flattening + renamed to "WelcomeWarps" + codemc CI 2018-10-31 14:32:21 +01:00
tastybento 9284cf7287 Update POM to new version number for Level addon 2018-10-30 18:27:41 -07:00
tastybento 91274fb414 Fixed for 0.12.0 API. 2018-10-30 18:12:30 -07:00
58 changed files with 5169 additions and 1979 deletions

38
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,38 @@
name: Build
on:
push:
branches:
- develop
- master
pull_request:
types: [opened, synchronize, reopened]
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
distribution: 'adopt'
java-version: '17'
- name: Cache SonarCloud packages
uses: actions/cache@v3
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar

88
.gitignore vendored Normal file
View File

@ -0,0 +1,88 @@
# Git
*.orig
!.gitignore
/.settings/
# Windows
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
*.stackdump
[Dd]esktop.ini
$RECYCLE.BIN/
*.lnk
# Linux
*~
.fuse_hidden*
.directory
.Trash-*
.nfs*
# MacOS
.DS_Store
.AppleDouble
.LSOverride
._*
# Java
*.class
*.log
*.ctxt
.mtj.tmp/
*.jar
*.war
*.nar
*.ear
hs_err_pid*
# Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
# Intellij
*.iml
*.java___jb_tmp___
.idea/*
*.ipr
*.iws
/out/
.idea_modules/
# Eclipse
*.pydevproject
.metadata
.gradle
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.project
.externalToolBuilders/
*.launch
.cproject
.classpath
.buildpath
.target
# NetBeans
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
nb-configuration.xml
.nb-gradle/

View File

@ -1,9 +1,12 @@
# addon-welcomewarpsigns
# Warps
Add-on for BentoBox to add personal warp signs for players of BSkyBlock or AcidIsland.
This add-on will work for both game modes.
This add-on will work for all game modes installed on a BentoBox server. Use config settings
to disable use by gamemode.
## How to use
### Note: Java 16 and Minecraft 17, or later are required.
1. Place the jar in the addons folder of the BentoBox plugin
2. Restart the server
3. The addon will create a data folder and inside the folder will be a config.yml
@ -12,14 +15,36 @@ This add-on will work for both game modes.
## Config.yml
There are only two options in the config:
These are options in the config:
### warplevelrestriction
This is the minimum island level needed to be able to create a warp.
0 or negative values will disable this restriction and 10 is default.
If you do not have the level addon installed, this will have no effect.
### Warp Sign Text - welcomeLine
This is the text a player must put on the first line of the sign to make it a warp sign.
### Icon
Icon that will be displayed in Warps list. SIGN counts for any kind of sign and the type of
wood used will be reflected in the panel if the server supports it.
It uses native Minecraft material strings, but using string 'PLAYER_HEAD', it is possible to
use player heads instead. Beware that Mojang API rate limiting may prevent heads from loading.
Default is 'SIGN'.
### Disabled Game Modes
This list stores GameModes in which Level addon should not work.
To disable addon it is necessary to write its name in new line that starts with -. Example:
```
disabled-gamemodes:
- BSkyBlock
```
Default is that all game modes can use Warps

552
pom.xml
View File

@ -1,226 +1,346 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<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>
<groupId>bskyblock.addon</groupId>
<artifactId>WelcomeWarpSigns</artifactId>
<version>0.0.4-SNAPSHOT</version>
<groupId>world.bentobox</groupId>
<artifactId>warps</artifactId>
<version>${revision}</version>
<name>WelcomeWarpSigns</name>
<description>WelcomeWarpSigns is an add-on for BentoBox, an expandable Minecraft Bukkit plugin for island-type games like ASkyBlock or AcidIsland.</description>
<url>https://github.com/BentoBoxWorld/addon-welcomewarpsigns</url>
<inceptionYear>2018</inceptionYear>
<name>Warps</name>
<description>Warps is an add-on for BentoBox, an expandable Minecraft Bukkit plugin for island-type games like ASkyBlock or AcidIsland.</description>
<url>https://github.com/BentoBoxWorld/Warps</url>
<inceptionYear>2018</inceptionYear>
<scm>
<connection>scm:git:https://github.com/BentoBoxWorld/addon-welcomewarpsigns.git</connection>
<developerConnection>scm:git:git@github.com:BentoBoxWorld/addon-welcomewarpsigns.git</developerConnection>
<url>https://github.com/BentoBoxWorld/addon-welcomewarpsigns</url>
</scm>
<developers>
<developer>
<id>tastybento</id>
<email>tastybento@bentobox.world</email>
<timezone>-8</timezone>
<roles>
<role>Lead Developer</role>
</roles>
</developer>
</developers>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/BentoBoxWorld/addon-welcomewarpsigns/issues</url>
</issueManagement>
<scm>
<connection>scm:git:https://github.com/BentoBoxWorld/Warps.git</connection>
<developerConnection>scm:git:git@github.com:BentoBoxWorld/Warps.git</developerConnection>
<url>https://github.com/BentoBoxWorld/Warps</url>
</scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<powermock.version>1.7.4</powermock.version>
</properties>
<ciManagement>
<system>jenkins</system>
<url>http://ci.codemc.org/job/BentoBoxWorld/job/Warps</url>
</ciManagement>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
</repository>
</repositories>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/BentoBoxWorld/Warps/issues</url>
</issueManagement>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.13-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver</artifactId>
<version>3.8.0</version>
</dependency>
<dependency>
<groupId>world.bentobox</groupId>
<artifactId>bentobox</artifactId>
<version>0.9.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>bskyblock.addon</groupId>
<artifactId>Level</artifactId>
<version>0.0.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<distributionManagement>
<snapshotRepository>
<id>codemc-snapshots</id>
<url>https://repo.codemc.org/repository/maven-snapshots</url>
</snapshotRepository>
<repository>
<id>codemc-releases</id>
<url>https://repo.codemc.org/repository/maven-releases</url>
</repository>
</distributionManagement>
<build>
<defaultGoal>clean package</defaultGoal>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources/locales</directory>
<targetPath>./locales</targetPath>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.0.1</version>
<configuration>
<show>public</show>
<failOnError>false</failOnError>
<additionalJOption>-Xdoclint:none</additionalJOption>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<minimizeJar>false</minimizeJar>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.1</version>
<configuration>
<append>true</append>
</configuration>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>post-unit-test</id>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version>
<!-- Non-minecraft related dependencies -->
<powermock.version>2.0.9</powermock.version>
<!-- More visible way how to change dependency versions -->
<spigot.version>1.19.4-R0.1-SNAPSHOT</spigot.version>
<bentobox.version>2.0.0-SNAPSHOT</bentobox.version>
<level.version>2.7.0-SNAPSHOT</level.version>
<!-- Revision variable removes warning about dynamic version -->
<revision>${build.version}-SNAPSHOT</revision>
<!-- Do not change unless you want different name for local builds. -->
<build.number>-LOCAL</build.number>
<!-- This allows to change between versions. -->
<build.version>1.15.0</build.version>
<!-- Sonar Cloud -->
<sonar.projectKey>BentoBoxWorld_Warps</sonar.projectKey>
<sonar.organization>bentobox-world</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
</properties>
<profiles>
<profile>
<id>sonar</id>
<properties>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<sonar.organization>tastybento-github</sonar.organization>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>5.1</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>sonar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
<!-- Profiles will allow to automatically change build version. -->
<profiles>
<profile>
<!-- ci profile is activated if exist environment variable BUILD_NUMBER. -->
<!-- It replaces ${build.number} that is currently '-LOCAL' with
correct build number from JENKINS machine. -->
<id>ci</id>
<activation>
<property>
<name>env.BUILD_NUMBER</name>
</property>
</activation>
<properties>
<!-- Override only if necessary -->
<build.number>-b${env.BUILD_NUMBER}</build.number>
</properties>
</profile>
<profile>
<!-- Master profile is activated if exist environment variable
GIT_BRANCH and its value is origin/master. -->
<!-- It will replace 'revision' with '${build.version}' so it
removes '-SNAPSHOT' string at the end. -->
<!-- Also, as this is release build, build number can be set
to empty string. -->
<!-- This profile will be used only if exist environment variable
GIT_BRANCH with value origin/master. -->
<id>master</id>
<activation>
<property>
<name>env.GIT_BRANCH</name>
<value>origin/master</value>
</property>
</activation>
<properties>
<!-- Override only if necessary -->
<revision>${build.version}</revision>
<!-- Empties build number variable. -->
<build.number></build.number>
</properties>
</profile>
</profiles>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
</repository>
<repository>
<id>codemc</id>
<url>https://repo.codemc.org/repository/maven-snapshots/</url>
</repository>
<repository>
<id>codemc-public</id>
<url>https://repo.codemc.org/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<!-- Spigot API -->
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>${spigot.version}</version>
<scope>provided</scope>
</dependency>
<!-- Mockito (Unit testing) -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.11.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>world.bentobox</groupId>
<artifactId>bentobox</artifactId>
<version>${bentobox.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>world.bentobox</groupId>
<artifactId>level</artifactId>
<version>${level.version}</version>
<scope>provided</scope>
</dependency>
<!-- Static analysis -->
<!-- We are using Eclipse's annotations. If you're using IDEA, update
your project settings to take these into account for in real time static
analysis -->
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.annotation</artifactId>
<version>2.2.600</version>
</dependency>
</dependencies>
<build>
<!-- By default ${revision} is ${build.version}-SNAPSHOT -->
<!-- If GIT_BRANCH variable is set to origin/master, then it will
be only ${build.version}. -->
<!-- By default ${build.number} is -LOCAL. -->
<!-- If the BUILD_NUMBER variable is set, then it will be -b[number]. -->
<!-- If GIT_BRANCH variable is set to origin/master, then it will
be the empty string. -->
<finalName>${project.name}-${revision}${build.number}</finalName>
<defaultGoal>clean package</defaultGoal>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources/locales</directory>
<targetPath>./locales</targetPath>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<argLine>
${argLine}
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.math=ALL-UNNAMED
--add-opens java.base/java.io=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens
java.base/java.util.stream=ALL-UNNAMED
--add-opens java.base/java.text=ALL-UNNAMED
--add-opens
java.base/java.util.regex=ALL-UNNAMED
--add-opens
java.base/java.nio.channels.spi=ALL-UNNAMED
--add-opens java.base/sun.nio.ch=ALL-UNNAMED
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens
java.base/java.util.concurrent=ALL-UNNAMED
--add-opens java.base/sun.nio.fs=ALL-UNNAMED
--add-opens java.base/sun.nio.cs=ALL-UNNAMED
--add-opens java.base/java.nio.file=ALL-UNNAMED
--add-opens
java.base/java.nio.charset=ALL-UNNAMED
--add-opens
java.base/java.lang.reflect=ALL-UNNAMED
--add-opens
java.logging/java.util.logging=ALL-UNNAMED
--add-opens java.base/java.lang.ref=ALL-UNNAMED
--add-opens java.base/java.util.jar=ALL-UNNAMED
--add-opens java.base/java.util.zip=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<source>16</source>
<show>private</show>
<failOnError>false</failOnError>
<additionalJOption>-Xdoclint:none</additionalJOption>
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<phase>install</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.10</version>
<configuration>
<append>true</append>
<excludes>
<!-- This is required to prevent Jacoco from adding
synthetic fields to a JavaBean class (causes errors in testing) -->
<exclude>**/*Names*</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<goals>
<goal>report</goal>
</goals>
<configuration>
<formats>
<format>XML</format>
</formats>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,132 +0,0 @@
package bentobox.addon.warps;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.bukkit.World;
import bentobox.addon.level.Level;
import bentobox.addon.warps.commands.WarpCommand;
import bentobox.addon.warps.commands.WarpsCommand;
import bentobox.addon.warps.config.PluginConfig;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.util.Util;
/**
* Addin to BSkyBlock that enables welcome warp signs
* @author tastybento
*
*/
public class Warp extends Addon {
private static final String BSKYBLOCK = "BSkyBlock";
private static final String ACIDISLAND = "AcidIsland";
private static final String LEVEL_PLUGIN_NAME = "BentoBox-Level";
// The plugin instance.
private BentoBox plugin;
// Warp panel object
private WarpPanelManager warpPanelManager;
// Warps signs object
private WarpSignsManager warpSignsManager;
private Set<World> registeredWorlds;
private PluginConfig settings;
@Override
public void onEnable() {
// Load the plugin's config
settings = new PluginConfig(this);
// Get the BSkyBlock plugin. This will be available because this plugin depends on it in plugin.yml.
plugin = this.getPlugin();
// Check if it is enabled - it might be loaded, but not enabled.
if (!plugin.isEnabled()) {
this.setEnabled(false);
return;
}
registeredWorlds = new HashSet<>();
// Start warp signs
warpSignsManager = new WarpSignsManager(this, plugin);
warpPanelManager = new WarpPanelManager(this);
// Load the listener
getServer().getPluginManager().registerEvents(new WarpSignsListener(this), plugin);
// Register commands
// BSkyBlock hook in
this.getPlugin().getAddonsManager().getAddonByName(BSKYBLOCK).ifPresent(acidIsland -> {
CompositeCommand bsbIslandCmd = BentoBox.getInstance().getCommandsManager().getCommand("island");
if (bsbIslandCmd != null) {
new WarpCommand(this, bsbIslandCmd);
new WarpsCommand(this, bsbIslandCmd);
registeredWorlds.add(bsbIslandCmd.getWorld());
}
});
// AcidIsland hook in
this.getPlugin().getAddonsManager().getAddonByName(ACIDISLAND).ifPresent(acidIsland -> {
CompositeCommand acidIslandCmd = getPlugin().getCommandsManager().getCommand("ai");
if (acidIslandCmd != null) {
new WarpCommand(this, acidIslandCmd);
new WarpsCommand(this, acidIslandCmd);
registeredWorlds.add(acidIslandCmd.getWorld());
}
});
// Done
}
@Override
public void onDisable(){
// Save the warps
if (warpSignsManager != null)
warpSignsManager.saveWarpList();
}
/**
* Get warp panel manager
* @return
*/
public WarpPanelManager getWarpPanelManager() {
return warpPanelManager;
}
public WarpSignsManager getWarpSignsManager() {
return warpSignsManager;
}
public String getPermPrefix(World world) {
return this.getPlugin().getIWM().getPermissionPrefix(world);
}
/**
* Check if an event is in a registered world
* @param world - world to check
* @return true if it is
*/
public boolean inRegisteredWorld(World world) {
return registeredWorlds.contains(Util.getWorld(world));
}
/**
* @return the settings
*/
public PluginConfig getSettings() {
return settings;
}
/**
* Get the island level
* @param world - world
* @param uniqueId - player's UUID
* @return island level or null if there is no level plugin
*/
public Long getLevel(World world, UUID uniqueId) {
return plugin.getAddonsManager().getAddonByName(LEVEL_PLUGIN_NAME).map(l -> ((Level) l).getIslandLevel(world, uniqueId)).orElse(null);
}
}

View File

@ -1,117 +0,0 @@
package bentobox.addon.warps;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.inventory.ItemStack;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;
public class WarpPanelManager {
private static final int PANEL_MAX_SIZE = 52;
private Warp addon;
// This is a cache of signs
private Map<World, Map<UUID, List<String>>> cachedSigns = new HashMap<>();
public WarpPanelManager(Warp addon) {
this.addon = addon;
}
private PanelItem getPanelItem(World world, UUID warpOwner) {
// Return a sign panel item
return new PanelItemBuilder()
.icon(Material.SIGN)
.name(addon.getPlugin().getPlayers().getName(warpOwner))
.description(getSign(world, warpOwner))
.clickHandler((panel, clicker, click, slot) -> { {
clicker.closeInventory();
addon.getWarpSignsManager().warpPlayer(world, clicker, warpOwner);
return true;
}
}).build();
}
/**
* Gets sign text and cache it
* @param playerUUID
* @return sign text in a list
*/
private List<String> getSign(World world, UUID playerUUID) {
// Add the worlds if we haven't seen this before
cachedSigns.putIfAbsent(world, new HashMap<>());
if (cachedSigns.get(world).containsKey(playerUUID)) {
return cachedSigns.get(world).get(playerUUID);
}
List<String> result = addon.getWarpSignsManager().getSignText(world, playerUUID);
cachedSigns.get(world).put(playerUUID, result);
return result;
}
/**
* Show the warp panel for the user
* @param world - world
* @param user - user
* @param index - page to show - 0 is first
*/
public void showWarpPanel(World world, User user, int index) {
List<UUID> warps = new ArrayList<>(addon.getWarpSignsManager().getSortedWarps(world));
if (index < 0) {
index = 0;
} else if (index > (warps.size() / PANEL_MAX_SIZE)) {
index = warps.size() / PANEL_MAX_SIZE;
}
PanelBuilder panelBuilder = new PanelBuilder()
.user(user)
.name(user.getTranslation("warps.title") + " " + String.valueOf(index + 1));
int i = index * PANEL_MAX_SIZE;
for (; i < (index * PANEL_MAX_SIZE + PANEL_MAX_SIZE) && i < warps.size(); i++) {
panelBuilder.item(getPanelItem(world, warps.get(i)));
}
final int panelNum = index;
// Add signs
if (i < warps.size()) {
// Next
panelBuilder.item(new PanelItemBuilder()
.name("Next")
.icon(new ItemStack(Material.SIGN))
.clickHandler((panel, clicker, click, slot) -> {
user.closeInventory();
showWarpPanel(world, user, panelNum+1);
return true;
}).build());
}
if (i > PANEL_MAX_SIZE) {
// Previous
panelBuilder.item(new PanelItemBuilder()
.name("Previous")
.icon(new ItemStack(Material.SIGN))
.clickHandler((panel, clicker, click, slot) -> {
user.closeInventory();
showWarpPanel(world, user, panelNum-1);
return true;
}).build());
}
panelBuilder.build();
}
/**
* Removes sign text from the cache
* @param key
*/
public void removeWarp(World world, UUID key) {
cachedSigns.putIfAbsent(world, new HashMap<>());
cachedSigns.get(world).remove(key);
}
}

View File

@ -1,165 +0,0 @@
package bentobox.addon.warps;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.SignChangeEvent;
import bentobox.addon.warps.event.WarpRemoveEvent;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User;
/**
* Handles warping. Players can add one sign
*
* @author tastybento
*
*/
public class WarpSignsListener implements Listener {
private BentoBox plugin;
private Warp addon;
/**
* @param addon - addon
*/
public WarpSignsListener(Warp addon) {
this.addon = addon;
this.plugin = addon.getPlugin();
}
/**
* Checks to see if a sign has been broken
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onSignBreak(BlockBreakEvent e) {
Block b = e.getBlock();
// Signs only
if (!b.getType().equals(Material.SIGN) && !b.getType().equals(Material.WALL_SIGN)) {
return;
}
if (!addon.inRegisteredWorld(b.getWorld())) {
return;
}
User user = User.getInstance(e.getPlayer());
Sign s = (Sign) b.getState();
if (s == null) {
return;
}
if (s.getLine(0).equalsIgnoreCase(ChatColor.GREEN + addon.getConfig().getString("welcomeLine"))) {
// Do a quick check to see if this sign location is in
// the list of warp signs
Map<UUID, Location> list = addon.getWarpSignsManager().getWarpMap(b.getWorld());
if (list.containsValue(s.getLocation())) {
// Welcome sign detected - check to see if it is
// this player's sign
if ((list.containsKey(user.getUniqueId()) && list.get(user.getUniqueId()).equals(s.getLocation()))
|| user.isOp() || user.hasPermission(addon.getPermPrefix(e.getBlock().getWorld()) + ".mod.removesign")) {
addon.getWarpSignsManager().removeWarp(s.getLocation());
Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(addon, s.getLocation(), user.getUniqueId()));
} else {
// Someone else's sign - not allowed
user.sendMessage("warps.error.no-remove");
e.setCancelled(true);
}
}
}
}
/**
* Event handler for Sign Changes
*
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onSignWarpCreate(SignChangeEvent e) {
Block b = e.getBlock();
if (!addon.inRegisteredWorld(b.getWorld())) {
return;
}
String title = e.getLine(0);
User user = User.getInstance(e.getPlayer());
// Check if someone is changing their own sign
if (title.equalsIgnoreCase(addon.getConfig().getString("welcomeLine"))) {
// Welcome sign detected - check permissions
if (!(user.hasPermission(addon.getPermPrefix(b.getWorld()) + ".island.addwarp"))) {
user.sendMessage("warps.error.no-permission");
user.sendMessage("general.errors.you-need", "[permission]", addon.getPermPrefix(b.getWorld()) + ".island.addwarp");
return;
}
// Get level is level addon is available
Long level = addon.getLevel(b.getWorld(), user.getUniqueId());
if (level != null && level < addon.getSettings().getWarpLevelRestriction()) {
user.sendMessage("warps.error.not-enough-level");
user.sendMessage("warps.error.your-level-is",
"[level]", String.valueOf(level),
"[required]", String.valueOf(addon.getSettings().getWarpLevelRestriction()));
return;
}
// Check that the player is on their island
if (!(plugin.getIslands().userIsOnIsland(b.getWorld(), user))) {
user.sendMessage("warps.error.not-on-island");
e.setLine(0, ChatColor.RED + addon.getConfig().getString("welcomeLine"));
return;
}
// Check if the player already has a sign
final Location oldSignLoc = addon.getWarpSignsManager().getWarp(b.getWorld(), user.getUniqueId());
if (oldSignLoc == null) {
// First time the sign has been placed or this is a new
// sign
addSign(e, user, b);
} else {
// A sign already exists. Check if it still there and if
// so,
// deactivate it
Block oldSignBlock = oldSignLoc.getBlock();
if (oldSignBlock.getType().equals(Material.SIGN) || oldSignBlock.getType().equals(Material.WALL_SIGN)) {
// The block is still a sign
Sign oldSign = (Sign) oldSignBlock.getState();
if (oldSign != null) {
if (oldSign.getLine(0).equalsIgnoreCase(ChatColor.GREEN + addon.getConfig().getString("welcomeLine"))) {
oldSign.setLine(0, ChatColor.RED + addon.getConfig().getString("welcomeLine"));
oldSign.update(true, false);
user.sendMessage("warps.deactivate");
addon.getWarpSignsManager().removeWarp(oldSignBlock.getWorld(), user.getUniqueId());
Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(addon, oldSign.getLocation(), user.getUniqueId()));
}
}
}
// Set up the new warp sign
addSign(e, user, b);
}
}
}
private void addSign(SignChangeEvent e, User user, Block b) {
if (addon.getWarpSignsManager().addWarp(user.getUniqueId(), b.getLocation())) {
user.sendMessage("warps.success");
e.setLine(0, ChatColor.GREEN + addon.getConfig().getString("welcomeLine"));
for (int i = 1; i<4; i++) {
e.setLine(i, ChatColor.translateAlternateColorCodes('&', e.getLine(i)));
}
} else {
user.sendMessage("warps.error.duplicate");
e.setLine(0, ChatColor.RED + addon.getConfig().getString("welcomeLine"));
for (int i = 1; i<4; i++) {
e.setLine(i, ChatColor.translateAlternateColorCodes('&', e.getLine(i)));
}
}
}
}

View File

@ -1,418 +0,0 @@
package bentobox.addon.warps;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign;
import bentobox.addon.warps.database.object.WarpsData;
import bentobox.addon.warps.event.WarpInitiateEvent;
import bentobox.addon.warps.event.WarpListEvent;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.Util;
/**
* Handles warping. Players can add one sign
*
* @author tastybento
*
*/
public class WarpSignsManager {
private static final int MAX_WARPS = 600;
private BentoBox plugin;
// Map of all warps stored as player, warp sign Location
private Map<World, Map<UUID, Location>> worldsWarpList;
// Database handler for level data
private Database<WarpsData> handler;
private Warp addon;
/**
* Get the warp map for this world
* @param world - world
* @return map of warps
*/
public Map<UUID, Location> getWarpMap(World world) {
worldsWarpList.putIfAbsent(world, new HashMap<>());
return worldsWarpList.get(world);
}
/**
* @param addon - addon
* @param plugin - plugin
*/
public WarpSignsManager(Warp addon, BentoBox plugin) {
this.addon = addon;
this.plugin = plugin;
// Set up the database handler to store and retrieve Island classes
// Note that these are saved by the BSkyBlock database
handler = new Database<>(addon, WarpsData.class);
// Load the warps
loadWarpList();
}
/**
* Stores warps in the warp array. If successful, fires an event
*
* @param playerUUID - the player's UUID
* @param loc - location of warp sign
* @return true if successful, false if not
*/
public boolean addWarp(final UUID playerUUID, final Location loc) {
// Do not allow null players to set warps or warps to be in the same location
if (playerUUID == null || getWarpMap(loc.getWorld()).containsValue(loc)) {
return false;
}
getWarpMap(loc.getWorld()).put(playerUUID, loc);
saveWarpList();
Bukkit.getPluginManager().callEvent(new WarpInitiateEvent(addon, loc, playerUUID));
return true;
}
/**
* Provides the location of the warp for player or null if one is not found
*
* @param world - world to search in
* @param playerUUID - the player's UUID
* - the warp requested
* @return Location of warp or null
*/
public Location getWarp(World world, UUID playerUUID) {
return getWarpMap(world).get(playerUUID);
}
/**
* Get the name of the warp owner by location
* @param location to search
* @return Name of warp owner or empty string if there is none
*/
public String getWarpOwner(Location location) {
return getWarpMap(location.getWorld()).entrySet().stream().filter(en -> en.getValue().equals(location))
.findFirst().map(en -> plugin.getPlayers().getName(en.getKey())).orElse("");
}
/**
* Get sorted list of warps with most recent players listed first
* @return UUID list
*/
public List<UUID> getSortedWarps(World world) {
// Remove any null locations - this can happen if an admin changes the name of the world and signs point to old locations
getWarpMap(world).values().removeIf(Objects::isNull);
// Bigger value of time means a more recent login
TreeMap<Long, UUID> map = new TreeMap<Long, UUID>();
getWarpMap(world).entrySet().forEach(en -> {
UUID uuid = en.getKey();
// If never played, will be zero
long lastPlayed = addon.getServer().getOfflinePlayer(uuid).getLastPlayed();
// This aims to avoid the chance that players logged off at exactly the same time
if (!map.isEmpty() && map.containsKey(lastPlayed)) {
lastPlayed = map.firstKey() - 1;
}
map.put(lastPlayed, uuid);
});
Collection<UUID> result = map.descendingMap().values();
List<UUID> list = new ArrayList<>(result);
if (list.size() > MAX_WARPS) {
list.subList(0, MAX_WARPS).clear();
}
// Fire event
WarpListEvent event = new WarpListEvent(addon, list);
addon.getServer().getPluginManager().callEvent(event);
// Get the result of any changes by listeners
list = event.getWarps();
return list;
}
/**
* Lists all the known warps for this world
* @param world - world
*
* @return UUID set of warps
*/
public Set<UUID> listWarps(World world) {
// Remove any null locations
getWarpMap(world).values().removeIf(Objects::isNull);
return getWarpMap(world).entrySet().stream().filter(e -> Util.sameWorld(world, e.getValue().getWorld())).map(Map.Entry::getKey).collect(Collectors.toSet());
}
/**
* Load the warps and check if they still exist
*/
private void loadWarpList() {
addon.getLogger().info("Loading warps...");
worldsWarpList = new HashMap<>();
WarpsData warps = handler.loadObject("warps");
// Load into map
if (warps != null) {
warps.getWarpSigns().forEach((k,v) -> {
if (k != null && (k.getBlock().getType().equals(Material.SIGN) || k.getBlock().getType().equals(Material.WALL_SIGN))) {
// Add to map
getWarpMap(k.getWorld()).put(v, k);
}
});
}
}
/**
* Changes the sign to red if it exists
* @param loc
*/
private void popSign(Location loc) {
Block b = loc.getBlock();
if (b.getType().equals(Material.SIGN) || b.getType().equals(Material.WALL_SIGN)) {
Sign s = (Sign) b.getState();
if (s != null) {
if (s.getLine(0).equalsIgnoreCase(ChatColor.GREEN + addon.getConfig().getString("welcomeLine"))) {
s.setLine(0, ChatColor.RED + addon.getConfig().getString("welcomeLine"));
s.update(true, false);
}
}
}
}
/**
* Removes a warp at a location.
*
* @param loc
*/
public void removeWarp(Location loc) {
popSign(loc);
Iterator<Entry<UUID, Location>> it = getWarpMap(loc.getWorld()).entrySet().iterator();
while (it.hasNext()) {
Entry<UUID, Location> en = it.next();
if (en.getValue().equals(loc)) {
// Inform player
User user = User.getInstance(addon.getServer().getPlayer(en.getKey()));
if (user != null) {
// Inform the player
user.sendMessage("warps.sign-removed");
}
// Remove sign from warp panel cache
addon.getWarpPanelManager().removeWarp(loc.getWorld(), en.getKey());
it.remove();
}
}
saveWarpList();
}
/**
* Remove warp sign owned by UUID
*
* @param uuid
*/
public void removeWarp(World world, UUID uuid) {
if (getWarpMap(world).containsKey(uuid)) {
popSign(getWarpMap(world).get(uuid));
getWarpMap(world).remove(uuid);
// Remove sign from warp panel cache
addon.getWarpPanelManager().removeWarp(world, uuid);
}
saveWarpList();
}
/**
* Saves the warp lists to the database
*/
public void saveWarpList() {
handler.saveObject(new WarpsData().save(worldsWarpList));
}
/**
* Gets the warp sign text for player's UUID in world
*
* @param world - world to look in
* @param uuid - player's uuid
* @return List of lines
*/
public List<String> getSignText(World world, UUID uuid) {
List<String> result = new ArrayList<>();
//get the sign info
Location signLocation = getWarp(world, uuid);
if (signLocation != null && (signLocation.getBlock().getType().equals(Material.SIGN) || signLocation.getBlock().getType().equals(Material.WALL_SIGN))) {
Sign sign = (Sign)signLocation.getBlock().getState();
result.addAll(Arrays.asList(sign.getLines()));
// Clean up - remove the [WELCOME] line
result.remove(0);
// Remove any trailing blank lines
result.removeIf(String::isEmpty);
} else {
addon.getWarpSignsManager().removeWarp(world, uuid);
}
return result;
}
/**
* Warps a player to a spot in front of a sign.
* @param user - user who is warping
* @param inFront - location in front of sign - previously checked for safety
* @param signOwner - warp sign owner
* @param directionFacing - direction that sign is facing
* @param pvp - true if this location allowed PVP
*/
private void warpPlayer(User user, Location inFront, UUID signOwner, BlockFace directionFacing, boolean pvp) {
// convert blockface to angle
float yaw = blockFaceToFloat(directionFacing);
final Location actualWarp = new Location(inFront.getWorld(), inFront.getBlockX() + 0.5D, inFront.getBlockY(),
inFront.getBlockZ() + 0.5D, yaw, 30F);
user.teleport(actualWarp);
if (pvp) {
user.sendRawMessage(user.getTranslation("protection.flags.PVP_OVERWORLD.active"));
user.getWorld().playSound(user.getLocation(), Sound.ENTITY_ARROW_HIT, 1F, 1F);
} else {
user.getWorld().playSound(user.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F);
}
User warpOwner = User.getInstance(signOwner);
if (!warpOwner.equals(user)) {
warpOwner.sendMessage("warps.player-warped", "[name]", user.getName());
}
}
/**
* Converts block face direction to radial degrees. Returns 0 if block face
* is not radial.
*
* @param face
* @return degrees
*/
private float blockFaceToFloat(BlockFace face) {
switch (face) {
case EAST:
return 90F;
case EAST_NORTH_EAST:
return 67.5F;
case EAST_SOUTH_EAST:
return 0F;
case NORTH:
return 0F;
case NORTH_EAST:
return 45F;
case NORTH_NORTH_EAST:
return 22.5F;
case NORTH_NORTH_WEST:
return 337.5F;
case NORTH_WEST:
return 315F;
case SOUTH:
return 180F;
case SOUTH_EAST:
return 135F;
case SOUTH_SOUTH_EAST:
return 157.5F;
case SOUTH_SOUTH_WEST:
return 202.5F;
case SOUTH_WEST:
return 225F;
case WEST:
return 270F;
case WEST_NORTH_WEST:
return 292.5F;
case WEST_SOUTH_WEST:
return 247.5F;
default:
return 0F;
}
}
/**
* Warps a user to the warp owner by owner
*
* @param world - world to check
* @param user - user who is warping
* @param owner - owner of the warp
*/
public void warpPlayer(World world, User user, UUID owner) {
final Location warpSpot = getWarp(world, owner);
// Check if the warp spot is safe
if (warpSpot == null) {
user.sendMessage("warps.error.does-not-exist");
addon.getWarpSignsManager().removeWarp(world, owner);
return;
}
// Find out if island is locked
// TODO: Fire event
Island island = addon.getPlugin().getIslands().getIsland(world, owner);
boolean pvp = false;
if (island != null) {
//if ((warpSpot.getWorld().equals(IslandWorld.getIslandWorld()) && island.getFlag(SettingsFlag.PVP_OVERWORLD))
// || (warpSpot.getWorld().equals(IslandWorld.getNetherWorld()) && island.getFlag(SettingsFlag.PVP_NETHER))) {
// pvp = true;
//}
}
// Find out which direction the warp is facing
Block b = warpSpot.getBlock();
if (b.getType().equals(Material.SIGN) || b.getType().equals(Material.WALL_SIGN)) {
Sign sign = (Sign) b.getState();
org.bukkit.material.Sign s = (org.bukkit.material.Sign) sign.getData();
BlockFace directionFacing = s.getFacing();
Location inFront = b.getRelative(directionFacing).getLocation();
Location oneDown = b.getRelative(directionFacing).getRelative(BlockFace.DOWN).getLocation();
if ((plugin.getIslands().isSafeLocation(inFront))) {
addon.getWarpSignsManager().warpPlayer(user, inFront, owner, directionFacing, pvp);
return;
} else if (b.getType().equals(Material.WALL_SIGN) && plugin.getIslands().isSafeLocation(oneDown)) {
// Try one block down if this is a wall sign
addon.getWarpSignsManager().warpPlayer(user, oneDown, owner, directionFacing, pvp);
return;
}
} else {
// Warp has been removed
user.sendMessage("warps.error.does-not-exist");
addon.getWarpSignsManager().removeWarp(warpSpot);
return;
}
if (!(plugin.getIslands().isSafeLocation(warpSpot))) {
user.sendMessage("warps.error.NotSafe");
// WALL_SIGN's will always be unsafe if the place in front is obscured.
if (b.getType().equals(Material.SIGN)) {
addon.getLogger().warning(
"Unsafe warp found at " + warpSpot.toString() + " owned by " + addon.getPlugin().getPlayers().getName(owner));
}
return;
} else {
final Location actualWarp = new Location(warpSpot.getWorld(), warpSpot.getBlockX() + 0.5D, warpSpot.getBlockY(),
warpSpot.getBlockZ() + 0.5D);
user.teleport(actualWarp);
if (pvp) {
//user.sendLegacyMessage(user.getTranslation("igs." + SettingsFlag.PVP_OVERWORLD) + " " + user.getTranslation("igs.Allowed"));
user.getWorld().playSound(user.getLocation(), Sound.ENTITY_ARROW_HIT, 1F, 1F);
} else {
user.getWorld().playSound(user.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F);
}
return;
}
}
/**
* Check if a player has a warp
* @param playerUUID - player's UUID
* @return true if they have warp
*/
public boolean hasWarp(World world, UUID playerUUID) {
return getWarpMap(world).containsKey(playerUUID);
}
}

View File

@ -1,75 +0,0 @@
package bentobox.addon.warps.commands;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import bentobox.addon.warps.Warp;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
/**
* The /is warp <name> command
*
* @author tastybento
*
*/
public class WarpCommand extends CompositeCommand {
private Warp addon;
public WarpCommand(Warp plugin, CompositeCommand bsbIslandCmd) {
super(bsbIslandCmd, "warp");
this.addon = plugin;
}
@Override
public void setup() {
this.setPermission("island.warp");
this.setOnlyPlayer(true);
this.setParametersHelp("warp.help.parameters");
this.setDescription("warp.help.description");
}
@Override
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
List<String> options = new ArrayList<>();
final Set<UUID> warpList = addon.getWarpSignsManager().listWarps(getWorld());
for (UUID warp : warpList) {
options.add(addon.getPlugin().getPlayers().getName(warp));
}
return Optional.of(options);
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.size() == 1) {
// Warp somewhere command
Set<UUID> warpList = addon.getWarpSignsManager().listWarps(getWorld());
if (warpList.isEmpty()) {
user.sendMessage("warps.error.no-warps-yet");
user.sendMessage("warps.warpTip", "[text]", getAddon().getConfig().getString("welcomeLine", "[WELCOME]"));
return true;
} else {
// Check if this is part of a name
UUID foundWarp = warpList.stream().filter(u -> getPlayers().getName(u).toLowerCase().equals(args.get(0).toLowerCase())
|| getPlayers().getName(u).toLowerCase().startsWith(args.get(0).toLowerCase())).findFirst().orElse(null);
if (foundWarp == null) {
user.sendMessage("warps.error.does-not-exist");
return false;
} else {
// Warp exists!
addon.getWarpSignsManager().warpPlayer(getWorld(), user, foundWarp);
return true;
}
}
}
return false;
}
}

View File

@ -1,49 +0,0 @@
/**
*
*/
package bentobox.addon.warps.commands;
import java.util.List;
import bentobox.addon.warps.Warp;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
/**
* @author ben
*
*/
public class WarpsCommand extends CompositeCommand {
private Warp plugin;
public WarpsCommand(Warp plugin, CompositeCommand bsbIslandCmd) {
super(bsbIslandCmd, "warps");
this.plugin = plugin;
}
/* (non-Javadoc)
* @see us.tastybento.bskyblock.api.commands.BSBCommand#setup()
*/
@Override
public void setup() {
this.setPermission("island.warp");
this.setOnlyPlayer(true);
this.setDescription("warps.help.description");
}
/* (non-Javadoc)
* @see us.tastybento.bskyblock.api.commands.BSBCommand#execute(us.tastybento.bskyblock.api.commands.User, java.util.List)
*/
@Override
public boolean execute(User user, String label, List<String> args) {
if (plugin.getWarpSignsManager().listWarps(getWorld()).isEmpty()) {
user.sendMessage("warps.error.no-warps-yet");
user.sendMessage("warps.warpTip", "[text]", getAddon().getConfig().getString("welcomeLine", "[WELCOME]"));
} else {
plugin.getWarpPanelManager().showWarpPanel(getWorld(), user,0);
}
return true;
}
}

View File

@ -1,24 +0,0 @@
package bentobox.addon.warps.config;
import bentobox.addon.warps.Warp;
public class PluginConfig {
private int warpLevelRestriction;
/**
* Loads the various settings from the config.yml file into the plugin
*/
public PluginConfig(Warp plugin) {
plugin.saveDefaultConfig();
warpLevelRestriction = plugin.getConfig().getInt("warplevelrestriction",10);
// All done
}
/**
* @return the warpLevelRestriction
*/
public int getWarpLevelRestriction() {
return warpLevelRestriction;
}
}

View File

@ -1,54 +0,0 @@
package bentobox.addon.warps.event;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import bentobox.addon.warps.Warp;
/**
* This event is fired when a Warp is created
* A Listener to this event can use it only to get informations. e.g: broadcast something
*
* @author Poslovitch
*
*/
public class WarpCreateEvent extends Event{
private static final HandlerList handlers = new HandlerList();
private Location warpLoc;
private UUID creator;
/**
* @param plugin - BSkyBlock plugin object
* @param warpLoc
* @param creator
*/
public WarpCreateEvent(Warp plugin, Location warpLoc, UUID creator){
this.warpLoc = warpLoc;
this.creator = creator;
}
/**
* Get the location of the created Warp
* @return created warp's location
*/
public Location getWarpLocation(){return this.warpLoc;}
/**
* Get who has created the warp
* @return the warp's creator
*/
public UUID getCreator(){return this.creator;}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@ -1,75 +0,0 @@
package bentobox.addon.warps.event;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import bentobox.addon.warps.Warp;
/**
* This event is fired when a player tries to do a warp
* A Listener to this event can use it to get informations. e.g: broadcast something
*
* @author tastybento
*
*/
public class WarpInitiateEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
private Location warpLoc;
private final UUID player;
/**
* @param plugin - BSkyBlock plugin object
* @param warpLoc - where the player is warping to
* @param player - the UUID of the player
*/
public WarpInitiateEvent(Warp plugin, Location warpLoc, UUID player){
this.warpLoc = warpLoc;
this.player = player;
}
/**
* Get the location of the Warp
* @return created warp's location
*/
public Location getWarpLoc(){return this.warpLoc;}
/**
* Set a different location to where the player will go
* @param warpLoc
*/
public void setWarpLoc(Location warpLoc) {
this.warpLoc = warpLoc;
}
/**
* Get who is warping
* @return the warping player's uuid
*/
public UUID getPlayer(){return this.player;}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
// TODO Auto-generated method stub
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@ -1,75 +0,0 @@
/*******************************************************************************
* This file is part of ASkyBlock.
*
* ASkyBlock is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ASkyBlock is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ASkyBlock. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
package bentobox.addon.warps.event;
import java.util.List;
import java.util.UUID;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import bentobox.addon.warps.Warp;
/**
* This event is fired when request is made for a sorted list of warps or when
* the API updateWarpPanel method is called.
* A listener to this event can reorder or rewrite the warp list by using setWarps.
* This new order will then be used in the warp panel.
*
* @author tastybento
*
*/
public class WarpListEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private List<UUID> warps;
/**
* @param plugin - BSkyBlock plugin object
* @param warps
*/
public WarpListEvent(Warp plugin, List<UUID> warps) {
this.warps = warps;
}
/**
*The warp list is a collection of player UUID's and the default order is
* that players with the most recent login will be first.
* @return the warps
*/
public List<UUID> getWarps() {
return warps;
}
/**
* @param warps the warps to set
*/
public void setWarps(List<UUID> warps) {
this.warps = warps;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@ -0,0 +1,300 @@
package world.bentobox.warps;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.configuration.Config;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.flags.clicklisteners.CycleClick;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Util;
import world.bentobox.level.Level;
import world.bentobox.warps.commands.WarpCommand;
import world.bentobox.warps.commands.WarpsCommand;
import world.bentobox.warps.config.Settings;
import world.bentobox.warps.listeners.WarpSignsListener;
import world.bentobox.warps.managers.SignCacheManager;
import world.bentobox.warps.managers.WarpSignsManager;
/**
* Addin to BentoBox that enables welcome warp signs
* @author tastybento
*
*/
public class Warp extends Addon {
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* This variable stores string for Level addon.
*/
private static final String LEVEL_ADDON_NAME = "Level";
/**
* Permission prefix for non-game world operation
*/
public static final String WELCOME_WARP_SIGNS = "welcomewarpsigns";
/**
* Worlds Sign manager.
*/
private WarpSignsManager warpSignsManager;
/**
* Sign Cache Manager
*/
private SignCacheManager signCacheManager;
/**
* This variable stores in which worlds this addon is working.
*/
private Set<World> registeredWorlds;
/**
* This variable stores if addon settings.
*/
private Settings settings;
/**
* This variable stores if addon is hooked or not.
*/
private boolean hooked;
/**
* Settings config object
*/
private Config<Settings> settingsConfig;
/**
* Create Warp Flag
*/
private Flag createWarpFlag;
// ---------------------------------------------------------------------
// Section: Methods
// ---------------------------------------------------------------------
/**
* Executes code when loading the addon. This is called before {@link #onEnable()}. This should preferably
* be used to setup configuration and worlds.
*/
@Override
public void onLoad()
{
super.onLoad();
// Save default config.yml
this.saveDefaultConfig();
// Load the plugin's config
if (this.loadSettings() && getSettings().isAllowInOtherWorlds()) {
// Load the master warp and warps command
new WarpCommand(this);
new WarpsCommand(this);
}
}
/**
* Executes code when reloading the addon.
*/
@Override
public void onReload()
{
super.onReload();
if (this.hooked || getSettings().isAllowInOtherWorlds()) {
this.warpSignsManager.saveWarpList();
this.loadSettings();
this.getLogger().info("Warps addon reloaded.");
}
}
@Override
public void onEnable() {
// Check if it is enabled - it might be loaded, but not enabled.
if (!this.getPlugin().isEnabled()) {
this.setState(State.DISABLED);
return;
}
registeredWorlds = new HashSet<>();
// Register commands
this.getPlugin().getAddonsManager().getGameModeAddons().forEach(gameModeAddon -> {
if (!this.settings.getDisabledGameModes().contains(gameModeAddon.getDescription().getName())
&& gameModeAddon.getPlayerCommand().isPresent())
{
this.registeredWorlds.add(gameModeAddon.getOverWorld());
new WarpCommand(this, gameModeAddon.getPlayerCommand().get());
new WarpsCommand(this, gameModeAddon.getPlayerCommand().get());
this.hooked = true;
}
});
if (hooked || getSettings().isAllowInOtherWorlds())
{
// Start warp signs
warpSignsManager = new WarpSignsManager(this, this.getPlugin());
signCacheManager = new SignCacheManager(this);
// Load the listener
this.registerListener(new WarpSignsListener(this));
} else {
logWarning("Addon did not hook into anything and is not running stand-alone");
this.setState(State.DISABLED);
}
this.createWarpFlag = new Flag.Builder("PLACE_WARP", Material.OAK_SIGN)
.addon(this)
.defaultRank(RanksManager.MEMBER_RANK)
.clickHandler(new CycleClick("PLACE_WARP",
RanksManager.MEMBER_RANK,
RanksManager.OWNER_RANK))
.defaultSetting(false)
.mode(Flag.Mode.EXPERT)
.build();
getPlugin().getFlagsManager().registerFlag(this, this.createWarpFlag);
}
@Override
public void onDisable(){
// Save the warps
if (warpSignsManager != null) {
warpSignsManager.saveWarpList();
}
}
/**
* This method loads addon configuration settings in memory.
*/
private boolean loadSettings() {
if (settingsConfig == null) {
settingsConfig = new Config<>(this, Settings.class);
}
this.settings = settingsConfig.loadConfigObject();
if (this.settings == null) {
// Disable
this.logError("WelcomeWarp settings could not load! Addon disabled.");
this.setState(State.DISABLED);
return false;
}
// Save existing panels.
this.saveResource("panels/warps_panel.yml", false);
settingsConfig.saveConfigObject(settings);
return true;
}
/**
* Get sign cache manager
* @return Sign Cache Manager
*/
public SignCacheManager getSignCacheManager() {
return signCacheManager;
}
public WarpSignsManager getWarpSignsManager() {
return warpSignsManager;
}
public String getPermPrefix(World world) {
return this.getPlugin().getIWM().getPermissionPrefix(world);
}
/**
* Check if an event is in a registered world
* @param world - world to check
* @return true if it is
*/
public boolean inRegisteredWorld(World world) {
return registeredWorlds.contains(Util.getWorld(world));
}
/**
* @return the settings
*/
public Settings getSettings() {
return settings;
}
/**
* @return the createWarpFlag
*/
public Flag getCreateWarpFlag() {
return createWarpFlag;
}
/**
* Get the island level
* @param world - world
* @param uniqueId - player's UUID
* @return island level or null if there is no level plugin or Level is not operating in this world
*/
public Long getLevel(World world, UUID uniqueId) {
// Get name of the game mode
String name = this.getPlugin().getIWM().getAddon(world).map(g -> g.getDescription().getName()).orElse("");
return this.getPlugin().getAddonsManager().getAddonByName(LEVEL_ADDON_NAME)
.map(l -> {
final Level addon = (Level) l;
//getGameModes is a list of gamemodes that Level is DISABLED in,
//so we need the opposite of the contains.
if (!name.isEmpty() && !addon.getSettings().getGameModes().contains(name)) {
return addon.getIslandLevel(world, uniqueId);
}
return null;
}).orElse(null);
}
/* (non-Javadoc)
* @see world.bentobox.bentobox.api.addons.Addon#request(java.lang.String, java.util.Map)
*
* This API enables plugins to request data from the WarpSignsManager
*
*/
@Override
public Object request(String requestLabel, Map<String, Object> metaData) {
if (metaData.isEmpty()) return null;
World world = null;
UUID uuid = null;
// Parse keys
if (metaData.containsKey("world")) {
world = Bukkit.getWorld((String)metaData.get("world"));
}
if (world == null) return null;
if (metaData.containsKey("uuid")) {
try {
uuid = UUID.fromString((String)metaData.get("uuid"));
} catch (Exception e) {
logError("Requested UUID is invalid");
return null;
}
}
return switch (requestLabel) {
case "getSortedWarps" -> getWarpSignsManager().getSortedWarps(world);
case "getWarp" -> uuid == null ? null : getWarpSignsManager().getWarp(world, uuid);
case "getWarpMap" -> getWarpSignsManager().getWarpMap(world);
case "hasWarp" -> uuid == null ? null : getWarpSignsManager().hasWarp(world, uuid);
case "listWarps" -> getWarpSignsManager().listWarps(world);
default -> null;
};
}
}

View File

@ -0,0 +1,14 @@
package world.bentobox.warps;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.Pladdon;
public class WarpsPladdon extends Pladdon {
@Override
public Addon getAddon() {
return new Warp();
}
}

View File

@ -0,0 +1,87 @@
package world.bentobox.warps.commands;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import org.bukkit.World;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.DelayedTeleportCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.warps.Warp;
/**
* The /is warp <name> command
*
* @author tastybento
*/
public class WarpCommand extends DelayedTeleportCommand {
private final Warp addon;
public WarpCommand(Warp addon, CompositeCommand bsbIslandCmd) {
super(bsbIslandCmd, addon.getSettings().getWarpCommand());
this.addon = addon;
}
public WarpCommand(Warp addon) {
super(addon, addon.getSettings().getWarpCommand());
this.addon = addon;
}
@Override
public void setup() {
this.setPermission(this.getParent() == null ? Warp.WELCOME_WARP_SIGNS + ".warp" : "island.warp");
this.setOnlyPlayer(true);
this.setParametersHelp("warp.help.parameters");
this.setDescription("warp.help.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.size() == 1) {
World world = getWorld() == null ? user.getWorld() : getWorld();
// Warp somewhere command
Set<UUID> warpList = addon.getWarpSignsManager().listWarps(world);
if (warpList.isEmpty()) {
user.sendMessage("warps.error.no-warps-yet");
user.sendMessage("warps.warpTip", "[text]", addon.getSettings().getWelcomeLine());
return false;
} else {
// Attemp to find warp with exact player's name
UUID foundWarp = warpList.stream().filter(u -> getPlayers().getName(u).equalsIgnoreCase(args.get(0))).findFirst().orElse(null);
if (foundWarp == null) {
// Atempt to find warp which starts with the given name
UUID foundAlernativeWarp = warpList.stream().filter(u -> getPlayers().getName(u).toLowerCase().startsWith(args.get(0).toLowerCase())).findFirst().orElse(null);
if (foundAlernativeWarp == null) {
user.sendMessage("warps.error.does-not-exist");
return false;
} else {
// Alternative warp found!
this.delayCommand(user, () -> addon.getWarpSignsManager().warpPlayer(world, user, foundAlernativeWarp));
return true;
}
} else {
// Warp exists!
this.delayCommand(user, () -> addon.getWarpSignsManager().warpPlayer(world, user, foundWarp));
return true;
}
}
}
showHelp(this, user);
return false;
}
@Override
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
World world = getWorld() == null ? user.getWorld() : getWorld();
return Optional.of(addon.getWarpSignsManager().listWarps(world).stream().map(getPlayers()::getName).toList());
}
}

View File

@ -0,0 +1,62 @@
package world.bentobox.warps.commands;
import java.util.List;
import org.bukkit.World;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.warps.Warp;
import world.bentobox.warps.panels.WarpsPanel;
/**
* Handles the warps command
* @author tastybento
*
*/
public class WarpsCommand extends CompositeCommand {
private final Warp addon;
public WarpsCommand(Warp addon, CompositeCommand bsbIslandCmd) {
super(bsbIslandCmd, addon.getSettings().getWarpsCommand());
this.addon = addon;
}
public WarpsCommand(Warp addon) {
super(addon.getSettings().getWarpsCommand());
this.addon = addon;
}
/* (non-Javadoc)
* @see us.tastybento.bskyblock.api.commands.BSBCommand#setup()
*/
@Override
public void setup() {
this.setPermission(this.getParent() == null ? Warp.WELCOME_WARP_SIGNS + ".warps" : "island.warps");
this.setOnlyPlayer(true);
this.setDescription("warps.help.description");
}
/* (non-Javadoc)
* @see us.tastybento.bskyblock.api.commands.BSBCommand#execute(us.tastybento.bskyblock.api.commands.User, java.util.List)
*/
@Override
public boolean execute(User user, String label, List<String> args) {
World world = getWorld() == null ? user.getWorld() : getWorld();
if (addon
.getWarpSignsManager()
.listWarps(world)
.isEmpty()) {
user.sendMessage("warps.error.no-warps-yet");
user.sendMessage("warps.warpTip", "[text]", addon.getSettings().getWelcomeLine());
return false;
}
WarpsPanel.openPanel(this.addon, world, user);
return true;
}
}

View File

@ -0,0 +1,221 @@
package world.bentobox.warps.config;
import java.util.HashSet;
import java.util.Set;
import world.bentobox.bentobox.api.configuration.ConfigComment;
import world.bentobox.bentobox.api.configuration.ConfigEntry;
import world.bentobox.bentobox.api.configuration.ConfigObject;
import world.bentobox.bentobox.api.configuration.StoreAt;
@StoreAt(filename="config.yml", path="addons/Warps")
@ConfigComment("WelcomeWarps Configuration [version]")
@ConfigComment("This config file is dynamic and saved when the server is shutdown.")
@ConfigComment("You cannot edit it while the server is running because changes will")
@ConfigComment("be lost! Use in-game settings GUI or edit when server is offline.")
@ConfigComment("")
public class Settings implements ConfigObject
{
@ConfigComment("")
@ConfigComment("Warp Restriction - needed levels to be able to create a warp")
@ConfigComment("0 or negative values will disable this restriction 10 is default")
@ConfigEntry(path = "warplevelrestriction")
private int warpLevelRestriction = 10;
@ConfigComment("")
@ConfigComment("Should warps be removed when the island protection settings")
@ConfigComment("change, and the owner of the warp does no longer have")
@ConfigComment("the correct rank")
@ConfigEntry(path = "removeExistingWarpsWhenFlagChanges")
private boolean removeExistingWarpsWhenFlagChanges = false;
@ConfigComment("")
@ConfigComment("Text that player must put on sign to make it a warp sign")
@ConfigComment("Not case sensitive!")
@ConfigEntry(path = "welcomeLine")
private String welcomeLine = "[Welcome]";
@ConfigComment("")
@ConfigComment("This list stores GameModes in which Level addon should not work.")
@ConfigComment("To disable addon it is necessary to write its name in new line that starts with -. Example:")
@ConfigComment("disabled-gamemodes:")
@ConfigComment(" - BSkyBlock")
@ConfigEntry(path = "disabled-gamemodes")
private Set<String> disabledGameModes = new HashSet<>();
@ConfigComment("")
@ConfigComment("Warp panel default lore formatting.")
@ConfigComment("Example: &c will make lore red. &f is white")
@ConfigEntry(path = "lore-format")
private String loreFormat = "&f";
@ConfigComment("")
@ConfigComment("Allow use in other worlds. Players must have the welcomewarpsigns.warp permission.")
@ConfigEntry(path = "allow-in-other-worlds")
private boolean allowInOtherWorlds = false;
@ConfigComment("")
@ConfigComment("Warp and warps commands. You can change them if they clash with other addons or plugins.")
@ConfigEntry(path = "warp-command")
String warpCommand = "warp";
@ConfigEntry(path = "warps-command")
String warpsCommand = "warps";
// ---------------------------------------------------------------------
// Section: Constructor
// ---------------------------------------------------------------------
/**
* Loads the various settings from the config.yml file into the plugin
*/
public Settings()
{
// empty constructor
}
// ---------------------------------------------------------------------
// Section: Methods
// ---------------------------------------------------------------------
/**
* @return the warpLevelRestriction
*/
public int getWarpLevelRestriction()
{
return warpLevelRestriction;
}
/**
* This method sets the warpLevelRestriction object value.
* @param warpLevelRestriction the warpLevelRestriction object new value.
*
*/
public void setWarpLevelRestriction(int warpLevelRestriction)
{
this.warpLevelRestriction = warpLevelRestriction;
}
/**
* This method returns the welcomeLine object.
* @return the welcomeLine object.
*/
public String getWelcomeLine()
{
return welcomeLine;
}
/**
* This method sets the welcomeLine object value.
* @param welcomeLine the welcomeLine object new value.
*
*/
public void setWelcomeLine(String welcomeLine)
{
this.welcomeLine = welcomeLine;
}
/**
* This method returns the disabledGameModes object.
* @return the disabledGameModes object.
*/
public Set<String> getDisabledGameModes()
{
return disabledGameModes;
}
/**
* This method sets the disabledGameModes object value.
* @param disabledGameModes the disabledGameModes object new value.
*
*/
public void setDisabledGameModes(Set<String> disabledGameModes)
{
this.disabledGameModes = disabledGameModes;
}
/**
* @return the loreFormat
*/
public String getLoreFormat() {
return loreFormat;
}
/**
* @param loreFormat the loreFormat to set
*/
public void setLoreFormat(String loreFormat) {
this.loreFormat = loreFormat;
}
/**
* @return the allowInOtherWorlds
*/
public boolean isAllowInOtherWorlds() {
return allowInOtherWorlds;
}
/**
* @param allowInOtherWorlds the allowInOtherWorlds to set
*/
public void setAllowInOtherWorlds(boolean allowInOtherWorlds) {
this.allowInOtherWorlds = allowInOtherWorlds;
}
/**
* @return the warpCommand
*/
public String getWarpCommand() {
return warpCommand;
}
/**
* @param warpCommand the warpCommand to set
*/
public void setWarpCommand(String warpCommand) {
this.warpCommand = warpCommand;
}
/**
* @return the warpsCommand
*/
public String getWarpsCommand() {
return warpsCommand;
}
/**
* @param warpsCommand the warpsCommand to set
*/
public void setWarpsCommand(String warpsCommand) {
this.warpsCommand = warpsCommand;
}
/**
* @return the removeExistingWarpsWhenFlagChanges
*/
public boolean getRemoveExistingWarpsWhenFlagChanges() {
return removeExistingWarpsWhenFlagChanges;
}
/**
* @param removeExistingWarpsWhenFlagChanges the removeExistingWarpsWhenFlagChanges to set
*/
public void setRemoveExistingWarpsWhenFlagChanges(boolean removeExistingWarpsWhenFlagChanges) {
this.removeExistingWarpsWhenFlagChanges = removeExistingWarpsWhenFlagChanges;
}
}

View File

@ -0,0 +1,54 @@
package world.bentobox.warps.event;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import world.bentobox.warps.Warp;
/**
* This event is fired when a Warp is created
* A Listener to this event can use it only to get informations. e.g: broadcast something
*
* @author Poslovitch
*
*/
public class WarpCreateEvent extends Event{
private static final HandlerList handlers = new HandlerList();
private final Location warpLoc;
private final UUID creator;
/**
* @param plugin - BSkyBlock plugin objects
* @param warpLoc warp location
* @param creator UUID of creator
*/
public WarpCreateEvent(Warp plugin, Location warpLoc, UUID creator){
this.warpLoc = warpLoc;
this.creator = creator;
}
/**
* Get the location of the created Warp
* @return created warp's location
*/
public Location getWarpLocation(){return this.warpLoc;}
/**
* Get who has created the warp
* @return the warp's creator
*/
public UUID getCreator(){return this.creator;}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@ -0,0 +1,74 @@
package world.bentobox.warps.event;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import world.bentobox.warps.Warp;
/**
* This event is fired when a player tries to do a warp
* A Listener to this event can use it to get informations. e.g: broadcast something
*
* @author tastybento
*
*/
public class WarpInitiateEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
private Location warpLoc;
private final UUID player;
/**
* @param plugin - BSkyBlock plugin objects
* @param warpLoc - where the player is warping to
* @param player - the UUID of the player
*/
public WarpInitiateEvent(Warp plugin, Location warpLoc, UUID player){
this.warpLoc = warpLoc;
this.player = player;
}
/**
* Get the location of the Warp
* @return created warp's location
*/
public Location getWarpLoc(){return this.warpLoc;}
/**
* Set a different location to where the player will go
* @param warpLoc warp location
*/
public void setWarpLoc(Location warpLoc) {
this.warpLoc = warpLoc;
}
/**
* Get who is warping
* @return the warping player's uuid
*/
public UUID getPlayer(){return this.player;}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@ -1,12 +1,12 @@
package bentobox.addon.warps.event;
package world.bentobox.warps.event;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import bentobox.addon.warps.Warp;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
/**
* This event is fired when a Warp is removed (when a warp sign is broken)
@ -18,32 +18,48 @@ import bentobox.addon.warps.Warp;
public class WarpRemoveEvent extends Event{
private static final HandlerList handlers = new HandlerList();
private Location warpLoc;
private UUID remover;
private final Location warpLoc;
private final UUID remover;
private final UUID owner;
/**
* @param plugin - BSkyBlock plugin object
* @param warpLoc
* @param remover
* @param warpLoc - Warp location
* @param remover - UUID of remover
* @param owner - UUID of warp owner - rarely, may be null
*/
public WarpRemoveEvent(Warp plugin, Location warpLoc, UUID remover){
public WarpRemoveEvent(@NonNull Location warpLoc, UUID remover, @Nullable UUID owner){
this.warpLoc = warpLoc;
this.remover = remover;
this.owner = owner;
}
/**
* Get the location of the removed Warp
* @return removed warp's location
*/
public Location getWarpLocation(){return this.warpLoc;}
@NonNull
public Location getWarpLocation(){
return this.warpLoc;
}
/**
* Get who has removed the warp
* @return the warp's remover
*/
public UUID getRemover(){return this.remover;}
@NonNull
public UUID getRemover(){
return this.remover;
}
@Override
/**
* @return the owner
*/
@Nullable
protected UUID getOwner() {
return owner;
}
@Override
public HandlerList getHandlers() {
return handlers;
}

View File

@ -0,0 +1,297 @@
package world.bentobox.warps.listeners;
import java.util.*;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Tag;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.scheduler.BukkitRunnable;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.events.addon.AddonEvent;
import world.bentobox.bentobox.api.events.flags.FlagProtectionChangeEvent;
import world.bentobox.bentobox.api.events.team.TeamKickEvent;
import world.bentobox.bentobox.api.events.team.TeamLeaveEvent;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.Util;
import world.bentobox.warps.Warp;
import world.bentobox.warps.event.WarpRemoveEvent;
/**
* Handles warping. Players can add one sign
*
* @author tastybento
*
*/
public class WarpSignsListener implements Listener {
private static final String WARPS_DEACTIVATE = "warps.deactivate";
private final BentoBox plugin;
private final Warp addon;
/**
* @param addon - addon
*/
public WarpSignsListener(Warp addon) {
this.addon = addon;
this.plugin = addon.getPlugin();
}
@EventHandler(priority = EventPriority.NORMAL)
public void onChunkLoad(ChunkLoadEvent event) {
// Delay to wait the chunk to be fully loaded
new BukkitRunnable() {
@Override
public void run() {
boolean changed = false;
Iterator<Map.Entry<UUID, Location>> iterator =
addon.getWarpSignsManager().getWarpMap(event.getWorld()).entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<UUID, Location> entry = iterator.next();
UUID uuid = entry.getKey();
Location location = entry.getValue();
if (event.getChunk().getX() == location.getBlockX() >> 4
&& event.getChunk().getZ() == location.getBlockZ() >> 4
&& !Tag.SIGNS.isTagged(location.getBlock().getType())) {
iterator.remove();
// Remove sign from warp panel cache
addon.getSignCacheManager().removeWarp(event.getWorld(), uuid);
changed = true;
}
}
if (changed) {
addon.getWarpSignsManager().saveWarpList();
}
}
}.runTask(plugin);
}
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPlayerLeave(TeamLeaveEvent e) {
// Remove any warp signs from this game mode
addon.getWarpSignsManager().removeWarp(e.getIsland().getWorld(), e.getPlayerUUID());
Objects.requireNonNull(User.getInstance(e.getPlayerUUID())).sendMessage(WARPS_DEACTIVATE);
}
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPlayerLeave(TeamKickEvent e) {
// Remove any warp signs from this game mode
addon.getWarpSignsManager().removeWarp(e.getIsland().getWorld(), e.getPlayerUUID());
Objects.requireNonNull(User.getInstance(e.getPlayerUUID())).sendMessage(WARPS_DEACTIVATE);
}
/**
* Checks to see if a sign has been broken
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onSignBreak(BlockBreakEvent e) {
Block b = e.getBlock();
boolean inWorld = addon.getPlugin().getIWM().inWorld(b.getWorld());
// Signs only
// FIXME: When we drop support for 1.13, switch to Tag.SIGNS
if (!b.getType().name().contains("SIGN")
|| (inWorld && !addon.inRegisteredWorld(b.getWorld()))
|| (!inWorld && !addon.getSettings().isAllowInOtherWorlds())
|| !isWarpSign(b)) {
return;
}
User user = User.getInstance(e.getPlayer());
UUID owner = addon.getWarpSignsManager().getWarpOwnerUUID(b.getLocation()).orElse(null);
if (isPlayersSign(e.getPlayer(), b, inWorld)) {
addon.getWarpSignsManager().removeWarp(b.getLocation());
Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(b.getLocation(), user.getUniqueId(), owner));
} else {
// Someone else's sign - not allowed
user.sendMessage("warps.error.no-remove");
e.setCancelled(true);
}
}
private boolean isPlayersSign(Player player, Block b, boolean inWorld) {
// Welcome sign detected - check to see if it is this player's sign
Map<UUID, Location> list = addon.getWarpSignsManager().getWarpMap(b.getWorld());
String reqPerm = inWorld ? addon.getPermPrefix(b.getWorld()) + "mod.removesign" : Warp.WELCOME_WARP_SIGNS + ".mod.removesign";
return ((list.containsKey(player.getUniqueId()) && list.get(player.getUniqueId()).equals(b.getLocation()))
|| player.isOp() || player.hasPermission(reqPerm));
}
private boolean isWarpSign(Block b) {
Sign s = (Sign) b.getState();
return s.getLine(0).equalsIgnoreCase(ChatColor.GREEN + addon.getSettings().getWelcomeLine())
&& addon.getWarpSignsManager().getWarpMap(b.getWorld()).containsValue(s.getLocation());
}
/**
* Event handler for Sign Changes
*
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onSignWarpCreate(SignChangeEvent e) {
Block b = e.getBlock();
boolean inWorld = addon.getPlugin().getIWM().inWorld(b.getWorld());
if ((inWorld && !addon.inRegisteredWorld(b.getWorld())) || (!inWorld && !addon.getSettings().isAllowInOtherWorlds()) ) {
return;
}
String title = e.getLine(0);
User user = Objects.requireNonNull(User.getInstance(e.getPlayer()));
// Check if someone is changing their own sign
if (title != null && title.equalsIgnoreCase(addon.getSettings().getWelcomeLine())) {
// Welcome sign detected - check permissions
if (noPerms(user, b.getWorld(), inWorld)) {
return;
}
if (inWorld && noLevelOrIsland(user, b.getWorld())) {
e.setLine(0, ChatColor.RED + addon.getSettings().getWelcomeLine());
return;
}
if(!hasCorrectIslandRank(b, user)) {
e.setLine(0, ChatColor.RED + addon.getSettings().getWelcomeLine());
user.sendMessage("warps.error.not-correct-rank");
return;
}
// Check if the player already has a sign
final Location oldSignLoc = addon.getWarpSignsManager().getWarp(b.getWorld(), user.getUniqueId());
if (oldSignLoc != null) {
// A sign already exists. Check if it still there and if
// so,
// deactivate it
Block oldSignBlock = oldSignLoc.getBlock();
// FIXME: When we drop support for 1.13, switch to Tag.SIGNS
if (oldSignBlock.getType().name().contains("SIGN")) {
// The block is still a sign
Sign oldSign = (Sign) oldSignBlock.getState();
if (oldSign.getLine(0).equalsIgnoreCase(ChatColor.GREEN + addon.getSettings().getWelcomeLine())) {
oldSign.setLine(0, ChatColor.RED + addon.getSettings().getWelcomeLine());
oldSign.update(true, false);
user.sendMessage(WARPS_DEACTIVATE);
addon.getWarpSignsManager().removeWarp(oldSignBlock.getWorld(), user.getUniqueId());
@Nullable
UUID owner = addon.getWarpSignsManager().getWarpOwnerUUID(oldSignLoc).orElse(null);
Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(oldSign.getLocation(), user.getUniqueId(), owner));
}
}
// Set up the new warp sign
}
addSign(e, user, b);
}
}
private boolean hasCorrectIslandRank(Block b, User user) {
final Optional<Island> islandOpt = plugin.getIslands().getIslandAt(b.getLocation());
if(islandOpt.isEmpty()) return false;
final Island island = islandOpt.get();
final int userRank = island.getRank(user);
return userRank >= island.getFlag(addon.getCreateWarpFlag());
}
@EventHandler
public void onFlagChange(FlagProtectionChangeEvent e) {
if(!e.getEditedFlag().equals(addon.getCreateWarpFlag())) return;
if(!addon.getSettings().getRemoveExistingWarpsWhenFlagChanges()) return;
final Island island = e.getIsland();
final Map<UUID, Location> islandWarps = addon
.getWarpSignsManager()
.getWarpMap(island.getWorld())
.entrySet()
.stream()
.filter(x -> island.inIslandSpace(x.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
for(Map.Entry<UUID, Location> entry : islandWarps.entrySet()) {
if(island.getRank(entry.getKey()) >= e.getSetTo()) continue;
//The user has a lower rank than the new set value.
//We need to remove the warp.
addon.getWarpSignsManager().removeWarp(island.getWorld(), entry.getKey());
if(Bukkit.getPlayer(entry.getKey()) != null) {
Objects.requireNonNull(User.getInstance(entry.getKey())).sendMessage(WARPS_DEACTIVATE);
}
}
}
private boolean noLevelOrIsland(User user, World world) {
// Get level if level addon is available
Long level = addon.getLevel(Util.getWorld(world), user.getUniqueId());
if (level != null && level < addon.getSettings().getWarpLevelRestriction()) {
user.sendMessage("warps.error.not-enough-level");
user.sendMessage("warps.error.your-level-is",
"[level]", String.valueOf(level),
"[required]", String.valueOf(addon.getSettings().getWarpLevelRestriction()));
return true;
}
// Check that the player is on their island
if (!(plugin.getIslands().userIsOnIsland(world, user))) {
user.sendMessage("warps.error.not-on-island");
return true;
}
return false;
}
/**
* Check if player has permission to execute command
* @param user - user
* @param world - world that the warp is in
* @param inWorld - true if warp is in a game world
* @return true if player does not have the required perms, false otherwise
*/
private boolean noPerms(User user, World world, boolean inWorld) {
String permReq = inWorld ? addon.getPermPrefix(world) + "island.addwarp" : Warp.WELCOME_WARP_SIGNS + ".addwarp";
if (!(user.hasPermission(permReq))) {
user.sendMessage("warps.error.no-permission");
user.sendMessage("general.errors.no-permission", "[permission]", permReq);
return true;
}
return false;
}
private void addSign(SignChangeEvent e, User user, Block b) {
if (addon.getWarpSignsManager().addWarp(user.getUniqueId(), b.getLocation())) {
user.sendMessage("warps.success");
e.setLine(0, ChatColor.GREEN + addon.getSettings().getWelcomeLine());
for (int i = 1; i<4; i++) {
String line = e.getLine(i);
if (line != null) {
e.setLine(i, ChatColor.translateAlternateColorCodes('&', line));
}
}
Map<String, Object> keyValues = new HashMap<>();
keyValues.put("eventName", "WarpCreateEvent");
keyValues.put("targetPlayer", user.getUniqueId());
keyValues.put("location", Util.getStringLocation(b.getLocation()));
new AddonEvent().builder().addon(addon).keyValues(keyValues).build();
}
// Else null player
}
}

View File

@ -0,0 +1,57 @@
package world.bentobox.warps.managers;
import java.util.List;
import org.bukkit.Material;
import com.google.gson.annotations.Expose;
/**
* Stores info on a warp sign
* @author tastybento
*
*/
public class SignCacheItem {
@Expose
private final List<String> signText;
@Expose
private final Material type;
/**
* @param signText sign text
* @param type material of sign
*/
public SignCacheItem(List<String> signText, Material type) {
this.signText = signText;
this.type = type;
}
/**
* This sign is not real
*/
public SignCacheItem() {
this.signText = null;
this.type = null;
}
/**
* @return the signText
*/
public List<String> getSignText() {
return signText;
}
/**
* @return the type
*/
public Material getType() {
return type;
}
/**
* @return the isReal
*/
public boolean isReal() {
return getType() != null;
}
}

View File

@ -0,0 +1,81 @@
package world.bentobox.warps.managers;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.database.Database;
import world.bentobox.warps.Warp;
import world.bentobox.warps.objects.SignCache;
public class SignCacheManager {
private final Map<World, Map<UUID, SignCacheItem>> cachedSigns = new HashMap<>();
private final Warp addon;
// Database handler for level data
private final Database<SignCache> handler;
public SignCacheManager(Warp addon) {
this.addon = addon;
handler = new Database<>(addon, SignCache.class);
// Load the sign caches
loadCache();
}
private void loadCache() {
cachedSigns.clear();
handler.loadObjects().forEach(w -> {
World world = Bukkit.getWorld(w.getUniqueId());
if (world != null) {
w.getSigns().values().removeIf(sci -> sci.getType().equals(Material.AIR));
cachedSigns.put(world, w.getSigns());
}
});
}
public void saveCache() {
cachedSigns.forEach((w, m) -> handler.saveObjectAsync(new SignCache(w, m)));
}
/**
* Get the sign item from cache or get it from the world if it is not in the cache
* @param world - world
* @param warpOwner - warp owner
* @return SignCacheItem
*/
@NonNull
public SignCacheItem getSignItem(World world, UUID warpOwner) {
// Add the worlds if we haven't seen this before
cachedSigns.putIfAbsent(world, new HashMap<>());
// Get from cache if available
if (cachedSigns.get(world).containsKey(warpOwner)) {
return cachedSigns.get(world).get(warpOwner);
}
// Generate and add to cache
SignCacheItem result = addon.getWarpSignsManager().getSignInfo(world, warpOwner);
if (result.isReal()) {
cachedSigns.get(world).put(warpOwner, result);
} else {
cachedSigns.get(world).remove(warpOwner);
}
return result;
}
/**
* Removes sign text from the cache
* @param world - world
* @param key - uuid of owner
* @return true if item is removed from cache
*/
public boolean removeWarp(World world, UUID key) {
if (cachedSigns.containsKey(world)) {
return cachedSigns.get(world).remove(key) != null;
}
return false;
}
}

View File

@ -0,0 +1,483 @@
package world.bentobox.warps.managers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.Tag;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.util.Util;
import world.bentobox.warps.Warp;
import world.bentobox.warps.event.WarpInitiateEvent;
import world.bentobox.warps.objects.WarpsData;
import world.bentobox.warps.panels.Utils;
/**
* Handles warping. Players can add one sign
*
* @author tastybento
*
*/
public class WarpSignsManager {
private static final int MAX_WARPS = 600;
private static final String WARPS = "warps";
private final BentoBox plugin;
// Map of all warps stored as player, warp sign Location
private Map<World, Map<UUID, Location>> worldsWarpList;
// Database handler for level data
private final Database<WarpsData> handler;
private final Warp addon;
private WarpsData warpsData = new WarpsData();
/**
* Get the warp map for this world
* @param world - world
* @return map of warps
*/
@NonNull
public Map<UUID, Location> getWarpMap(@Nullable World world) {
return worldsWarpList.computeIfAbsent(Util.getWorld(world), k -> new HashMap<>());
}
/**
* @param addon - addon
* @param plugin - plugin
*/
public WarpSignsManager(Warp addon, BentoBox plugin) {
this.addon = addon;
this.plugin = plugin;
this.worldsWarpList = new HashMap<>();
// Set up the database handler
// Note that these are saved by the BentoBox database
handler = new Database<>(addon, WarpsData.class);
// Load the warps
loadWarpList();
}
/**
* Stores warps in the warp array. If successful, fires an event
*
* @param playerUUID - the player's UUID
* @param loc - location of warp sign
* @return true if successful, false if not
*/
public boolean addWarp(final UUID playerUUID, final Location loc) {
// Do not allow null players to set warps
if (playerUUID == null || loc == null) {
return false;
}
// Check for warps placed in a location where there was a warp before
if (getWarpMap(loc.getWorld()).containsValue(loc)) {
// remove the warp at this location, then place it
this.removeWarp(loc);
}
getWarpMap(loc.getWorld()).put(playerUUID, loc);
saveWarpList();
Bukkit.getPluginManager().callEvent(new WarpInitiateEvent(addon, loc, playerUUID));
return true;
}
/**
* Provides the location of the warp for player or null if one is not found
*
* @param world - world to search in
* @param playerUUID - the player's UUID
* - the warp requested
* @return Location of warp or null
*/
@Nullable
public Location getWarp(World world, UUID playerUUID) {
return getWarpMap(world).get(playerUUID);
}
/**
* Get the name of the warp owner by location
* @param location to search
* @return Name of warp owner or empty string if there is none
*/
@NonNull
public String getWarpOwner(Location location) {
return getWarpMap(location.getWorld()).entrySet().stream().filter(en -> en.getValue().equals(location))
.findFirst().map(en -> plugin.getPlayers().getName(en.getKey())).orElse("");
}
/**
* Get the optional UUID of the warp owner by location
* @param location to search
* @return Optional UUID of warp owner or empty if there is none
*/
public Optional<UUID> getWarpOwnerUUID(Location location) {
return getWarpMap(location.getWorld()).entrySet().stream().filter(en -> en.getValue().equals(location))
.findFirst().map(Map.Entry::getKey);
}
/**
* Get sorted list of warps with most recent players listed first
* @return UUID list
*/
public CompletableFuture<List<UUID>> getSortedWarps(@NonNull World world) {
CompletableFuture<List<UUID>> r = new CompletableFuture<>();
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> processWarpMap(r, world));
return r;
}
public List<UUID> processWarpMap(CompletableFuture<List<UUID>> r, @NonNull World world) {
// Remove any null locations - this can happen if an admin changes the name of the world and signs point to old locations
getWarpMap(world).values().removeIf(Objects::isNull);
// Bigger value of time means a more recent login
TreeMap<Long, UUID> map = new TreeMap<>();
getWarpMap(world).forEach((uuid, value) -> {
// If never played, will be zero
long lastPlayed = addon.getServer().getOfflinePlayer(uuid).getLastPlayed();
// This aims to avoid the chance that players logged off at exactly the same time
if (!map.isEmpty() && map.containsKey(lastPlayed)) {
lastPlayed = map.firstKey() - 1;
}
map.put(lastPlayed, uuid);
});
Collection<UUID> result = map.descendingMap().values();
List<UUID> list = new ArrayList<>(result);
if (list.size() > MAX_WARPS) {
list.subList(0, MAX_WARPS).clear();
}
// Return to main thread
Bukkit.getScheduler().runTask(plugin, () -> r.complete(list));
return list;
}
/**
* Lists all the known warps for this world
* @param world - world
*
* @return UUID set of warps
*/
@NonNull
public Set<UUID> listWarps(@NonNull World world) {
// Remove any null locations
getWarpMap(world).values().removeIf(Objects::isNull);
return getWarpMap(world).entrySet().stream().filter(e -> Util.sameWorld(world, Objects.requireNonNull(e.getValue().getWorld()))).map(Map.Entry::getKey).collect(Collectors.toSet());
}
/**
* Load the warps and check if they still exist
*/
public void loadWarpList() {
addon.log("Loading warps...");
worldsWarpList = new HashMap<>();
if (handler.objectExists(WARPS)) {
warpsData = handler.loadObject(WARPS);
// Load into map
if (warpsData != null) {
warpsData.getWarpSigns().forEach((location,uuid) -> {
if (location != null && location.getWorld() != null) {
if (location.getWorld().isChunkLoaded(location.getBlockX() >> 4, location.getBlockZ() >> 4)
&& !location.getBlock().getType().name().contains("SIGN")) {
return;
}
// Add to map
getWarpMap(location.getWorld()).put(uuid, location);
}
});
} else {
warpsData = new WarpsData();
}
}
}
/**
* Changes the sign to red if it exists
* @param loc location to pop
*/
private void popSign(Location loc) {
Block b = loc.getBlock();
if (b.getType().name().contains("SIGN")) {
Sign s = (Sign) b.getState();
if (s.getLine(0).equalsIgnoreCase(ChatColor.GREEN + addon.getSettings().getWelcomeLine())) {
s.setLine(0, ChatColor.RED + addon.getSettings().getWelcomeLine());
s.update(true, false);
}
}
}
/**
* Removes a warp at a location.
*
* @param loc location to remove
*/
public void removeWarp(Location loc) {
popSign(loc);
Iterator<Entry<UUID, Location>> it = getWarpMap(loc.getWorld()).entrySet().iterator();
while (it.hasNext()) {
Entry<UUID, Location> en = it.next();
if (en.getValue().equals(loc)) {
// Inform player
Optional.ofNullable(addon.getServer().getPlayer(en.getKey()))
.map(User::getInstance)
.ifPresent(user -> user.sendMessage("warps.sign-removed"));
// Remove sign from warp panel cache
addon.getSignCacheManager().removeWarp(loc.getWorld(), en.getKey());
it.remove();
}
}
saveWarpList();
}
/**
* Remove warp sign owned by UUID
*
* @param uuid UUID of owner to remove
*/
public void removeWarp(World world, UUID uuid) {
if (getWarpMap(world).containsKey(uuid)) {
popSign(getWarpMap(world).get(uuid));
getWarpMap(world).remove(uuid);
}
// Remove sign from warp panel cache
addon.getSignCacheManager().removeWarp(world, uuid);
saveWarpList();
}
/**
* Remove the warp from the warp map
* @param world - world
* @param uuid - uuid of owner
*/
public void removeWarpFromMap(World world, UUID uuid) {
getWarpMap(world).remove(uuid);
}
/**
* Saves the warp lists to the database
*/
public void saveWarpList() {
handler.saveObjectAsync(warpsData.save(worldsWarpList));
addon.getSignCacheManager().saveCache();
}
/**
* Gets the warp sign text and material type for player's UUID in world
*
* @param world - world to look in
* @param uuid - player's uuid
* @return Sign's content and type
*/
@NonNull
public SignCacheItem getSignInfo(@NonNull World world, @NonNull UUID uuid) {
//get the sign info
Location signLocation = getWarp(world, uuid);
if (signLocation == null || !signLocation.getBlock().getType().name().contains("SIGN")) {
return new SignCacheItem();
}
Sign sign = (Sign)signLocation.getBlock().getState();
List<String> result = new ArrayList<>(Arrays.asList(sign.getLines()));
// Clean up - remove the [WELCOME] line
result.remove(0);
// Remove any trailing blank lines
result.removeIf(String::isEmpty);
// Set the initial color per lore setting
for (int i = 0; i< result.size(); i++) {
result.set(i, ChatColor.translateAlternateColorCodes('&', addon.getSettings().getLoreFormat()) + result.get(i));
}
// Get the sign type
String prefix = plugin.getIWM().getAddon(world).map(Addon::getPermissionPrefix).orElse("");
Material icon;
if (!prefix.isEmpty())
{
icon = Material.matchMaterial(
Utils.getPermissionValue(User.getInstance(uuid), prefix + "island.warp",
Material.OAK_SIGN.name()));
}
else
{
icon = null;
}
if (icon != null && icon.name().contains("SIGN")) {
return new SignCacheItem(result, Material.valueOf(sign.getType().name().replace("WALL_", "")));
}
else
{
return new SignCacheItem(result, icon);
}
}
/**
* Warps a player to a spot in front of a sign.
* @param user - user who is warping
* @param inFront - location in front of sign - previously checked for safety
* @param signOwner - warp sign owner
* @param directionFacing - direction that sign is facing
* @param pvp - true if this location allowed PVP
*/
private void warpPlayer(@NonNull User user, @NonNull Location inFront, @NonNull UUID signOwner, @NonNull BlockFace directionFacing, boolean pvp) {
// convert blockface to angle
float yaw = Util.blockFaceToFloat(directionFacing);
final Location actualWarp = new Location(inFront.getWorld(), inFront.getBlockX() + 0.5D, inFront.getBlockY(),
inFront.getBlockZ() + 0.5D, yaw, 30F);
//BentoBox prevents people from teleporting to an island when
//the user is banned from the island for example.
//By checking if the teleport succeeded before sending the messages,
//we prevent issues where no one teleported, but people still
//get messages about it.
Util.teleportAsync(user.getPlayer(), actualWarp, TeleportCause.COMMAND).thenAccept(tpResult -> {
if(Boolean.FALSE.equals(tpResult)) return;
User warpOwner = Objects.requireNonNull(User.getInstance(signOwner));
// Hide invisible players
if (warpOwner.isOnline() && !warpOwner.getPlayer().canSee(user.getPlayer())) {
return;
}
if (pvp) {
user.sendMessage("protection.flags.PVP_OVERWORLD.enabled");
user.getWorld().playSound(Objects.requireNonNull(user.getLocation()), Sound.ENTITY_ARROW_HIT, 1F, 1F);
} else {
user.getWorld().playSound(Objects.requireNonNull(user.getLocation()), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F);
}
if (!warpOwner.equals(user)) {
final String gameMode = BentoBox
.getInstance()
.getIWM()
.getFriendlyName(actualWarp.getWorld());
warpOwner.sendMessage("warps.player-warped", "[name]", user.getName(), "[gamemode]", gameMode);
}
});
}
/**
* Warps a user to the warp owned by owner
*
* @param world - world to check
* @param user - user who is warping
* @param owner - owner of the warp
*/
public void warpPlayer(@NonNull World world, @NonNull User user, @NonNull UUID owner) {
final Location warpSpot = getWarp(world, owner);
// Check if the warp spot is safe
if (warpSpot == null) {
user.sendMessage("warps.error.does-not-exist");
addon.getWarpSignsManager().removeWarp(world, owner);
return;
}
if (this.plugin.getIWM().inWorld(user.getWorld()) &&
Flags.PREVENT_TELEPORT_WHEN_FALLING.isSetForWorld(user.getWorld()) &&
user.getPlayer().getFallDistance() > 0) {
// We're sending the "hint" to the player to tell them they cannot teleport while falling.
user.sendMessage(Flags.PREVENT_TELEPORT_WHEN_FALLING.getHintReference());
return;
}
Island island = addon.getIslands().getIsland(world, owner);
boolean pvp = false;
if (island != null) {
// Check for PVP
switch (Objects.requireNonNull(warpSpot.getWorld()).getEnvironment()) {
case NETHER:
pvp = island.isAllowed(Flags.PVP_NETHER);
break;
case NORMAL:
pvp = island.isAllowed(Flags.PVP_OVERWORLD);
break;
case THE_END:
pvp = island.isAllowed(Flags.PVP_END);
break;
default:
break;
}
}
// Find out which direction the warp is facing
Block b = warpSpot.getBlock();
if (Tag.WALL_SIGNS.isTagged(b.getType())) {
org.bukkit.block.data.type.WallSign s = (org.bukkit.block.data.type.WallSign) b.getBlockData();
BlockFace directionFacing = s.getFacing();
Location inFront = b.getRelative(directionFacing).getLocation();
Location oneDown = b.getRelative(directionFacing).getRelative(BlockFace.DOWN).getLocation();
if ((plugin.getIslands().isSafeLocation(inFront))) {
warpPlayer(user, inFront, owner, directionFacing, pvp);
return;
} else if (plugin.getIslands().isSafeLocation(oneDown)) {
// Try one block down if this is a wall sign
warpPlayer(user, oneDown, owner, directionFacing, pvp);
return;
}
} else if (Tag.ALL_HANGING_SIGNS.isTagged(b.getType())) {
Location below = b.getRelative(BlockFace.DOWN).getRelative(BlockFace.DOWN).getLocation();
if ((addon.getIslands().isSafeLocation(below))) {
warpPlayer(user, below, owner, BlockFace.DOWN, pvp);
return;
}
} else if (Tag.STANDING_SIGNS.isTagged(b.getType())) {
org.bukkit.block.data.type.Sign s = (org.bukkit.block.data.type.Sign) b.getBlockData();
BlockFace directionFacing = s.getRotation();
Location inFront = b.getRelative(directionFacing).getLocation();
if ((addon.getIslands().isSafeLocation(inFront))) {
warpPlayer(user, inFront, owner, directionFacing, pvp);
return;
}
} else {
// Warp has been removed
user.sendMessage("warps.error.does-not-exist");
removeWarp(warpSpot);
return;
}
if (!(plugin.getIslands().isSafeLocation(warpSpot))) {
user.sendMessage("warps.error.not-safe");
} else {
final Location actualWarp = new Location(warpSpot.getWorld(), warpSpot.getBlockX() + 0.5D, warpSpot.getBlockY(),
warpSpot.getBlockZ() + 0.5D);
if (pvp) {
user.sendMessage("protection.flags.PVP_OVERWORLD.enabled");
user.getWorld().playSound(Objects.requireNonNull(user.getLocation()), Sound.ENTITY_ARROW_HIT, 1F, 1F);
} else {
user.getWorld().playSound(Objects.requireNonNull(user.getLocation()), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F);
}
Util.teleportAsync(user.getPlayer(), actualWarp, TeleportCause.COMMAND);
}
}
/**
* Check if a player has a warp
* @param playerUUID - player's UUID
* @return true if they have warp
*/
public boolean hasWarp(@NonNull World world, @NonNull UUID playerUUID) {
return getWarpMap(world).containsKey(playerUUID);
}
}

View File

@ -0,0 +1,56 @@
package world.bentobox.warps.objects;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.bukkit.World;
import com.google.gson.annotations.Expose;
import world.bentobox.bentobox.database.objects.DataObject;
import world.bentobox.bentobox.database.objects.Table;
import world.bentobox.warps.managers.SignCacheItem;
@Table(name = "WarpSignCache")
public class SignCache implements DataObject {
@Expose
private String uniqueId = "";
@Expose
private Map<UUID, SignCacheItem> signs = new HashMap<>();
public SignCache() {
// Required by YAML database
}
public SignCache(World w, Map<UUID, SignCacheItem> m) {
this.uniqueId = w.getName();
this.signs = m;
}
@Override
public String getUniqueId() {
return uniqueId;
}
@Override
public void setUniqueId(String uniqueId) {
this.uniqueId = uniqueId;
}
/**
* @return the signs
*/
public Map<UUID, SignCacheItem> getSigns() {
return signs;
}
/**
* @param signs the signs to set
*/
public void setSigns(Map<UUID, SignCacheItem> signs) {
this.signs = signs;
}
}

View File

@ -1,4 +1,4 @@
package bentobox.addon.warps.database.object;
package world.bentobox.warps.objects;
import java.util.HashMap;
import java.util.Map;
@ -10,15 +10,19 @@ import org.bukkit.World;
import com.google.gson.annotations.Expose;
import world.bentobox.bentobox.database.objects.DataObject;
import world.bentobox.bentobox.database.objects.Table;
@Table(name = "WarpsData")
public class WarpsData implements DataObject {
@Expose
private String uniqueId = "warps";
@Expose
private Map<Location, UUID> warpSigns = new HashMap<>();
public WarpsData() {}
public WarpsData() {
// Required by YAML database
}
@Override
public String getUniqueId() {
@ -31,8 +35,8 @@ public class WarpsData implements DataObject {
}
public Map<Location, UUID> getWarpSigns() {
if (warpSigns == null)
return new HashMap<>();
if (warpSigns == null)
return new HashMap<>();
return warpSigns;
}
@ -41,11 +45,12 @@ public class WarpsData implements DataObject {
}
/**
* Puts all the data from the map into this object ready for saving
* @param worldsWarpList
* Puts all the data from the map into this objects ready for saving
* @param worldsWarpList 2D map of warp locations by world vs UUID
* @return this class filled with data
*/
public WarpsData save(Map<World, Map<UUID, Location>> worldsWarpList) {
getWarpSigns().clear();
worldsWarpList.values().forEach(world -> world.forEach((uuid,location) -> warpSigns.put(location, uuid)));
return this;
}

View File

@ -0,0 +1,76 @@
//
// Created by BONNe
// Copyright - 2021
//
package world.bentobox.warps.panels;
import org.bukkit.permissions.PermissionAttachmentInfo;
import java.util.List;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.user.User;
public class Utils
{
/**
* This method sends a message to the user with appended "prefix" text before message.
* @param user User who receives message.
* @param translationText Translation text of the message.
* @param parameters Parameters for the translation text.
*/
public static void sendMessage(User user, String translationText, String... parameters)
{
user.sendMessage(user.getTranslation( "warps.conversations.prefix") +
user.getTranslation( translationText, parameters));
}
/**
* This method gets string value of given permission prefix. If user does not have given permission or it have all
* (*), then return default value.
*
* @param user User who's permission should be checked.
* @param permissionPrefix Prefix that need to be found.
* @param defaultValue Default value that will be returned if permission not found.
* @return String value that follows permissionPrefix.
*/
public static String getPermissionValue(User user, String permissionPrefix, String defaultValue)
{
if (user.isPlayer())
{
if (permissionPrefix.endsWith("."))
{
permissionPrefix = permissionPrefix.substring(0, permissionPrefix.length() - 1);
}
String permPrefix = permissionPrefix + ".";
List<String> permissions = user.getEffectivePermissions().stream().
map(PermissionAttachmentInfo::getPermission).
filter(permission -> permission.startsWith(permPrefix)).
collect(Collectors.toList());
for (String permission : permissions)
{
if (permission.contains(permPrefix + "*"))
{
// * means all. So continue to search more specific.
continue;
}
String[] parts = permission.split(permPrefix);
if (parts.length > 1)
{
return parts[1];
}
}
}
return defaultValue;
}
}

View File

@ -0,0 +1,598 @@
//
// Created by BONNe
// Copyright - 2021
//
package world.bentobox.warps.panels;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import java.io.File;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.TemplatedPanel;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.panels.builders.TemplatedPanelBuilder;
import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.warps.managers.SignCacheItem;
import world.bentobox.warps.managers.SignCacheManager;
import world.bentobox.warps.Warp;
/**
* This class shows how to set up easy panel by using BentoBox PanelBuilder API
*/
public class WarpsPanel
{
// ---------------------------------------------------------------------
// Section: Constructor
// ---------------------------------------------------------------------
/**
* This is internal constructor. It is used internally in current class to avoid creating objects everywhere.
*
* @param addon VisitAddon object
* @param world World where user will be teleported
* @param user User who opens panel
*/
private WarpsPanel(Warp addon,
World world,
User user)
{
this.addon = addon;
this.manager = this.addon.getSignCacheManager();
this.user = user;
this.world = world;
}
// ---------------------------------------------------------------------
// Section: Methods
// ---------------------------------------------------------------------
/**
* This method collects and validates sign warps that could be displayed in GUI.
* @param completed CompletableFeature that triggers panel opening.
*/
private void collectValidWarps(CompletableFuture<Boolean> completed)
{
this.addon.getWarpSignsManager().getSortedWarps(this.world).
thenAccept(warps ->
{
// Cache and clean the signs
Iterator<UUID> iterator = warps.iterator();
while (iterator.hasNext())
{
UUID warpOwner = iterator.next();
@NonNull
SignCacheItem sign = this.manager.getSignItem(this.world, warpOwner);
if (!sign.isReal())
{
iterator.remove();
this.addon.getWarpSignsManager().removeWarpFromMap(this.world, warpOwner);
}
}
// Assign warps to element list.
this.elementList = warps;
// Build the main body
completed.complete(true);
});
}
/**
* This is wrapper around builder to trigger main GUI building.
*/
private void initBuild()
{
CompletableFuture<Boolean> collectWarps = new CompletableFuture<>();
this.collectValidWarps(collectWarps);
collectWarps.thenAccept(done -> {
if (done)
{
this.build();
}
});
}
/**
* Build method manages current panel opening. It uses BentoBox PanelAPI that is easy to use and users can get nice
* panels.
*/
private void build()
{
// Do not open gui if there is no magic sticks.
if (this.elementList.isEmpty())
{
this.addon.logError("There are no available islands for visiting!");
Utils.sendMessage(this.user, "warps.error.no-warps-yet",
"[gamemode]", this.addon.getPlugin().getIWM().getAddon(this.world).
map(gamemode -> gamemode.getDescription().getName()).
orElse(""));
return;
}
// Start building panel.
TemplatedPanelBuilder panelBuilder = new TemplatedPanelBuilder();
// Set main template.
panelBuilder.template("warps_panel", new File(this.addon.getDataFolder(), "panels"));
panelBuilder.user(this.user);
panelBuilder.world(this.user.getWorld());
// Register button builders
panelBuilder.registerTypeBuilder("WARP", this::createWarpButton);
panelBuilder.registerTypeBuilder("RANDOM", this::createRandomButton);
// Register next and previous builders
panelBuilder.registerTypeBuilder("NEXT", this::createNextButton);
panelBuilder.registerTypeBuilder("PREVIOUS", this::createPreviousButton);
// Register unknown type builder.
panelBuilder.build();
}
// ---------------------------------------------------------------------
// Section: Buttons
// ---------------------------------------------------------------------
/**
* Create next button panel item.
*
* @param template the template
* @param slot the slot
* @return the panel item
*/
@Nullable
private PanelItem createNextButton(@NonNull ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
{
int size = this.elementList.size();
if (size <= slot.amountMap().getOrDefault("WARP", 1) ||
1.0 * size / slot.amountMap().getOrDefault("WARP", 1) <= this.pageIndex + 1)
{
// There are no next elements
return null;
}
int nextPageIndex = this.pageIndex + 2;
PanelItemBuilder builder = new PanelItemBuilder();
if (template.icon() != null)
{
ItemStack clone = template.icon().clone();
if ((Boolean) template.dataMap().getOrDefault("indexing", false))
{
clone.setAmount(nextPageIndex);
}
builder.icon(clone);
}
if (template.title() != null)
{
builder.name(this.user.getTranslation(this.world, template.title()));
}
if (template.description() != null)
{
builder.description(this.user.getTranslation(this.world, template.description(),
"[number]", String.valueOf(nextPageIndex)));
}
// Add ClickHandler
builder.clickHandler((panel, user, clickType, i) ->
{
template.actions().forEach(action -> {
if (clickType == action.clickType() || action.clickType() == ClickType.UNKNOWN)
{
if ("NEXT".equalsIgnoreCase(action.actionType()))
{
// Next button ignores click type currently.
this.pageIndex++;
this.build();
}
}
});
// Always return true.
return true;
});
// Collect tooltips.
List<String> tooltips = template.actions().stream().
filter(action -> action.tooltip() != null).
map(action -> this.user.getTranslation(this.world, action.tooltip())).
filter(text -> !text.isBlank()).
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
// Add tooltips.
if (!tooltips.isEmpty())
{
// Empty line and tooltips.
builder.description("");
builder.description(tooltips);
}
return builder.build();
}
/**
* Create previous button panel item.
*
* @param template the template
* @param slot the slot
* @return the panel item
*/
@Nullable
private PanelItem createPreviousButton(@NonNull ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
{
if (this.pageIndex == 0)
{
// There are no next elements
return null;
}
int previousPageIndex = this.pageIndex;
PanelItemBuilder builder = new PanelItemBuilder();
if (template.icon() != null)
{
ItemStack clone = template.icon().clone();
if ((Boolean) template.dataMap().getOrDefault("indexing", false))
{
clone.setAmount(previousPageIndex);
}
builder.icon(clone);
}
if (template.title() != null)
{
builder.name(this.user.getTranslation(this.world, template.title()));
}
if (template.description() != null)
{
builder.description(this.user.getTranslation(this.world, template.description(),
"[number]", String.valueOf(previousPageIndex)));
}
// Add ClickHandler
// Add ClickHandler
builder.clickHandler((panel, user, clickType, i) ->
{
template.actions().forEach(action -> {
if (clickType == action.clickType() || action.clickType() == ClickType.UNKNOWN)
{
if ("PREVIOUS".equalsIgnoreCase(action.actionType()))
{
// Next button ignores click type currently.
this.pageIndex--;
this.build();
}
}
});
// Always return true.
return true;
});
// Collect tooltips.
List<String> tooltips = template.actions().stream().
filter(action -> action.tooltip() != null).
map(action -> this.user.getTranslation(this.world, action.tooltip())).
filter(text -> !text.isBlank()).
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
// Add tooltips.
if (!tooltips.isEmpty())
{
// Empty line and tooltips.
builder.description("");
builder.description(tooltips);
}
return builder.build();
}
/**
* This method creates and returns warp button.
*
* @return PanelItem that represents warp button.
*/
@Nullable
private PanelItem createWarpButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
{
if (this.elementList.isEmpty())
{
// Does not contain any sticks.
return null;
}
int index = this.pageIndex * slot.amountMap().getOrDefault("WARP", 1) + slot.slot();
if (index >= this.elementList.size())
{
// Out of index.
return null;
}
return this.createWarpButton(template, this.elementList.get(index), "warp");
}
/**
* This method creates and returns random warp button.
*
* @return PanelItem that represents random warp button.
*/
@Nullable
private PanelItem createRandomButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
{
if (this.elementList.size() < 2)
{
// Does not contain any sticks.
return null;
}
int index = random.nextInt(this.elementList.size());
return this.createWarpButton(template, this.elementList.get(index), "random");
}
// ---------------------------------------------------------------------
// Section: Other methods
// ---------------------------------------------------------------------
/**
* This method creates and returns button that switch to next page in view mode.
*
* @return PanelItem that allows to select next owner view page.
*/
private PanelItem createWarpButton(ItemTemplateRecord template, UUID ownerUUID, String type)
{
if (ownerUUID == null)
{
// return as owner has no owner. Empty button will be created.
return null;
}
SignCacheItem signCache = this.manager.getSignItem(this.world, ownerUUID);
if (!signCache.isReal())
{
this.addon.getWarpSignsManager().removeWarpFromMap(this.world, ownerUUID);
// return as signCache is not real anymore.
return null;
}
final String reference = "warps.gui.buttons." + type + ".";
String ownerName = addon.getPlugin().getPlayers().getName(ownerUUID);
// Get settings for owner.
PanelItemBuilder builder = new PanelItemBuilder();
if (template.icon() != null)
{
if (template.icon().getType().equals(Material.PLAYER_HEAD))
{
builder.icon(ownerName);
}
else
{
builder.icon(template.icon().clone());
}
}
else
{
// Check owner for a specific icon
Material material = signCache.getType();
if (material == null)
{
// Set oak sign as icon was not specified.
material = Material.OAK_SIGN;
}
if (material == Material.PLAYER_HEAD)
{
builder.icon(ownerName);
}
else
{
builder.icon(material);
}
}
if (template.title() != null)
{
builder.name(this.user.getTranslation(this.world, template.title(),
"[name]", ownerName));
}
else
{
builder.name(this.user.getTranslation(reference + "name",
"[name]", ownerName));
}
// Process Description of the button.
// Generate [sign_text] text
String descriptionText;
if (template.description() != null)
{
descriptionText = this.user.getTranslationOrNothing(template.description(),
"[name]", ownerName,
"[sign_text]", String.join("\n", signCache.getSignText())).
replaceAll("(?m)^[ \\t]*\\r?\\n", "").
replaceAll("(?<!\\\\)\\|", "\n").
replaceAll("\\\\\\|", "|");
}
else
{
descriptionText = this.user.getTranslationOrNothing(reference + "description",
"[name]", ownerName,
"[sign_text]", String.join("|", signCache.getSignText()));
// Clean up description text and split it into parts.
descriptionText = descriptionText.replaceAll("(?m)^[ \\t]*\\r?\\n", "").
replaceAll("(?<!\\\\)\\|", "\n").
replaceAll("\\\\\\|", "|");
}
builder.description(descriptionText);
// Add ClickHandler
builder.clickHandler((panel, user, clickType, i) ->
{
template.actions().forEach(action -> {
if (clickType == action.clickType() || action.clickType() == ClickType.UNKNOWN)
{
if ("WARP".equalsIgnoreCase(action.actionType()))
{
this.runCommandCall(ownerName);
}
}
});
// Always return true.
return true;
});
// Collect tooltips.
List<String> tooltips = template.actions().stream().
filter(action -> action.tooltip() != null).
map(action -> this.user.getTranslation(this.world, action.tooltip())).
filter(text -> !text.isBlank()).
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
// Add tooltips.
if (!tooltips.isEmpty())
{
// Empty line and tooltips.
builder.description("");
builder.description(tooltips);
}
return builder.build();
}
/**
* This method runs command call that allows player to visit clicked island.
*/
private void runCommandCall(String ownerName)
{
// Get first player command label.
String command = this.addon.getSettings().getWarpCommand().split(" ")[0];
String gamemodeCommand = this.addon.getPlugin().getIWM().getAddon(this.world).
map(gamemode -> gamemode.getPlayerCommand().map(Command::getLabel).orElse("")).
orElse("");
if (gamemodeCommand.isEmpty())
{
this.addon.log(this.user.getName() + " called: `" + command + " " + ownerName + "`");
this.user.performCommand(command + " " + ownerName);
}
else
{
this.addon.log(this.user.getName() + " called: `" + gamemodeCommand + " " + command + " " + ownerName + "`");
this.user.performCommand(gamemodeCommand + " " + command + " " + ownerName);
}
// Close inventory
this.user.closeInventory();
}
// ---------------------------------------------------------------------
// Section: Static methods
// ---------------------------------------------------------------------
/**
* This method is used to open UserPanel outside this class. It will be much easier to open panel with single method
* call then initializing new object.
*
* @param addon Warps object
* @param world World where user will be teleported
* @param user User who opens panel
*/
public static void openPanel(Warp addon,
World world,
User user)
{
new WarpsPanel(addon, world, user).initBuild();
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* This variable allows to access addon object.
*/
private final Warp addon;
/**
* This variable allows to access addon manager object.
*/
private final SignCacheManager manager;
/**
* This variable holds user who opens panel. Without it panel cannot be opened.
*/
private final User user;
/**
* This variable holds world where panel is opened. Without it panel cannot be opened.
*/
private final World world;
/**
* This variable stores filtered elements.
*/
private List<UUID> elementList;
/**
* This variable holds current pageIndex for multi-page island choosing.
*/
private int pageIndex;
/**
* Random for finding random warp.
*/
private static final Random random = new Random();
}

View File

@ -1,22 +1,20 @@
name: BentoBox-WelcomeWarps
main: bentobox.addon.warps.Warp
version: ${version}
name: Warps
main: world.bentobox.warps.Warp
version: ${version}${build.number}
icon: OAK_SIGN
api-version: 1.17
authors: tastybento
softdepend: AcidIsland, BSkyBlock
softdepend: AcidIsland, BSkyBlock, CaveBlock, SkyGrid, AOneBlock
permissions:
bskyblock.island.warp:
description: Player can use warp or warps commands
'[gamemode].island.warp':
description: Player can use warp command
default: true
bskyblock.island.addwarp:
'[gamemode].island.warps':
description: Player can use the warps command
default: true
'[gamemode].island.addwarp':
description: Player can create a welcome warp sign
default: true
acidisland.island.warp:
description: Player can use warp or warps commands
default: true
acidisland.island.addwarp:
description: Player can create a welcome warp sign
default: true

View File

@ -1,9 +1,35 @@
# WelcomeWarps Configuration ${version}
# This config file is dynamic and saved when the server is shutdown.
# You cannot edit it while the server is running because changes will
# be lost! Use in-game settings GUI or edit when server is offline.
#
#
# Warp Restriction - needed levels to be able to create a warp
# 0 or negative values will disable this restriction
# 10 is default
# 0 or negative values will disable this restriction 10 is default
warplevelrestriction: 10
#
# Should warps be removed when the island protection settings
# change, and the owner of the warp does no longer have
# the correct rank
removeExistingWarpsWhenFlagChanges: true
#
# Text that player must put on sign to make it a warp sign
# Not case sensitive!
welcomeLine: [WELCOME]
welcomeLine: '[Welcome]'
#
# This list stores GameModes in which Level addon should not work.
# To disable addon it is necessary to write its name in new line that starts with -. Example:
# disabled-gamemodes:
# - BSkyBlock
disabled-gamemodes: []
#
# Warp panel default lore formatting.
# Example: &c will make lore red. &f is white
lore-format: "&f"
#
# Allow use in other worlds. Players must have the welcomewarpsigns.warp permission.
allow-in-other-worlds: false
#
# Warp and warps commands. You can change them if they clash with other addons or plugins.
warp-command: warp
warps-command: warps

View File

@ -0,0 +1,35 @@
###########################################################################################
# This is a YML file. Be careful when editing. Check your edits in a YAML checker like #
# the one at http://yaml-online-parser.appspot.com #
# #
# Translation by: CZghost #
###########################################################################################
warp:
help:
description: "Teleportovat se na warp ceduli hráče"
parameters: <player name>
warps:
deactivate: "&c Stará warp cedule deaktivována!"
error:
does-not-exist: "&c Sakra! Tento warp již neexistuje!"
no-permission: "&c Na toto nemáš oprávnění!"
no-remove: "&c Nemůžeš odstranit tuto ceduli!"
no-warps-yet: "&c Nejsou k dispozici žádné warpy"
not-enough-level: "&c Úroveň tvého ostrova není dostatečně vysoká!"
not-on-island: "&c K tomuto musíš být na svém ostrově!"
not-safe: "&c Tento warp není bezpečný!"
your-level-is: "&c Úroveň tvého ostrova je jen [level], musí být vyšší než [required]. Spusť příkaz pro úroveň."
help:
description: "otevřít panel warpů"
next: "&6 Další stránka"
player-warped: "&2 [name] se teleportoval na tvou warp ceduli!"
previous: "&6 Předchozí stránka"
random: "&4 Náhodný warp"
sign-removed: "&c Warp cedule odstraněna!"
success: "&a Úspěch!"
title: "Warp cedule"
warpTip: "&6 Polož warp ceduli s [text] na vrchu"
warpToPlayersSign: "&6 Teleportuji tě na ceduli [player]"

View File

@ -0,0 +1,46 @@
---
warp:
help:
description: Warpt dich zu dem Warp Schild von dem Spieler
parameters: "<player name>"
warps:
deactivate: "&c Altes Warp Schild deaktiviert!"
error:
does-not-exist: "&c Oh nein! Dieser Warp existiert nicht mehr!"
no-permission: "&c Hierfür hast du keine Rechte!"
no-remove: "&c Du kannst dieses Schild nicht entfernen!"
no-warps-yet: "&c Es sind noch keine Warps verfügbar"
not-enough-level: "&c Dein Insel-Level ist nicht hoch gneug!"
not-on-island: "&c Dafür musst du auf deiner Insel sein!"
not-safe: "&c Dieser Warp ist nicht sicher!"
your-level-is: "&c Dein Insel-Level ist erst [level] und muss höher als [required]
sein. Nutze das Level Kommando."
help:
description: Öffnet das Warps Panel
player-warped: "&2 [name] hat sich zu deinem Warp Schild gewarpt!"
sign-removed: "&c Warp Schild entfernt!"
success: "&a Erfolg!"
warpTip: "&6 Platziere ein Warp Schild mit [text] in der ersten Zeile"
warpToPlayersSign: "&6 Warpe zu [player]'s Schild"
gui:
titles:
warp-title: "&0&l Warp-Schild"
buttons:
previous:
name: "&f&l Vorherige Seite"
description: "&7 Zur Seite [number] wechseln"
next:
name: "&f&l Nächste Seite"
description: "&7 Zur Seite [number] wechseln"
warp:
name: "&f&l [name]"
description: "[sign_text]"
random:
name: "&f&l Random Warp"
description: "&7 Hmm, wo werde ich erscheinen?"
tips:
click-to-previous: "&e Klicken &7, um die vorherige Seite anzuzeigen."
click-to-next: "&e Klicken &7, um die nächste Seite anzuzeigen."
click-to-warp: "&e Zum Warpen &7 klicken."
conversations:
prefix: "&l&6 [BentoBox]: &r"

View File

@ -3,30 +3,65 @@
# the one at http://yaml-online-parser.appspot.com #
###########################################################################################
warps:
deactivate: "&cOld warp sign deactivated!"
success: "&ASuccess!"
sign-removed: "&CWarp sign removed!"
title: "Warp Signs"
player-warped: "&2[name] warped to your warp sign!"
previous: "&6Previous page"
next: "&6Next page"
warpToPlayersSign: "&6Warping to [player]'s sign"
# The [text] is replaced with the welcome line text from config.yml
warpTip: "&6Place a warp sign with [text] on the top"
error:
does-not-exist: "&cOh snap! That warp no longer exists!"
no-remove: "&CYou cannot remove that sign!"
not-enough-level: "&CYour island level is not high enough!"
no-permission: "&CYou do not have permission to do that!"
not-on-island: "&CYou must be on your island to do that!"
duplicate: "&CDuplicate sign placed"
no-warps-yet: "&CThere are no warps available yet"
your-level-is: "&cYou island level is only [level] and must be higher than [required]"
warp:
help:
description: "warp to the player's warp sign"
parameters: <player name>
warps:
deactivate: "&c Old warp sign deactivated!"
error:
does-not-exist: "&c Oh snap! That warp no longer exists!"
no-permission: "&c You do not have permission to do that!"
no-remove: "&c You cannot remove that sign!"
no-warps-yet: "&c There are no warps available yet"
not-enough-level: "&c Your island level is not high enough!"
not-on-island: "&c You must be on your island to do that!"
not-safe: "&c That warp is not safe!"
your-level-is: "&c Your island level is only [level] and must be higher than [required]. Run the level command."
not-correct-rank: "&c You do not have the correct rank to set a warp!"
help:
description: "open the warps panel"
warp:
help:
parameters: "<name>"
description: "warp to the player's warp sign"
player-warped: "&2 [name] warped to your [gamemode] warp sign!"
sign-removed: "&c Warp sign removed!"
success: "&a Success!"
warpTip: "&6 Place a warp sign with [text] on the top"
warpToPlayersSign: "&6 Warping to [player]'s sign"
gui:
titles:
# The title of warp panel
warp-title: '&0&l Warp Signs'
buttons:
# Button that is used in multi-page GUIs which allows to return to previous page.
previous:
name: "&f&l Previous Page"
description: |-
&7 Switch to [number] page
# Button that is used in multi-page GUIs which allows to go to next page.
next:
name: "&f&l Next Page"
description: |-
&7 Switch to [number] page
# Button for a warp
warp:
name: "&f&l [name]"
description: |-
[sign_text]
# Button for a random warp
random:
name: "&f&l Random Warp"
description: |-
&7 Hmm, where will I appear?
tips:
click-to-previous: "&e Click &7 to view previous page."
click-to-next: "&e Click &7 to view next page."
click-to-warp: "&e Click &7 to warp."
conversations:
# Prefix for messages that are send from server.
prefix: "&l&6 [BentoBox]: &r"
protection:
flags:
PLACE_WARP:
name: Place Warp
description: Allow placing warp sign

View File

@ -0,0 +1,53 @@
---
warp:
help:
description: Teletransportarte hacia el warp del jugador
parameters: "<player name>"
warps:
deactivate: "&c ¡Antiguo cartel de teletransportación desactivado!"
error:
does-not-exist: "&c ¡Oh, chasquido! ¡Ese teletransporte ya no existe!"
no-permission: "&c ¡No tienes permisos para hacer eso!"
no-remove: "&c ¡No puedes quitar ese cartel!"
no-warps-yet: "&c No hay teletransportes disponibles todavía"
not-enough-level: "&c ¡Tu nivel de isla no es lo suficientemente alto!"
not-on-island: "&c ¡Debes estar en tu isla para hacer eso!"
not-safe: "&c ¡Ese teletransporte no es seguro!"
your-level-is: "&c Tu nivel de isla es solo [level] y debe ser mayor que [required].
Ejecuta el comando de nivel."
not-correct-rank: "&c ¡No tienes el rango correcto para crear un teletransporte!"
help:
description: Abre el panel de warps
player-warped: "&2 [name] se ha teletransportado a tu cartel de teletransportación
de [gamemode]!"
sign-removed: "&c Cartel de teletransportación eliminado!"
success: "&a Éxito!"
warpTip: "&6 Coloca un cartel con [text] en la parte superior"
warpToPlayersSign: "&6 Teletransportandote al cartel del jugador [player]"
gui:
titles:
warp-title: "&0&l Carteles de Teletransporte"
buttons:
previous:
name: "&f&l Página Anterior"
description: "&7 Ir a la página [number]"
next:
name: "&f&l Siguiente Página"
description: "&7 Ir a la página [number]"
warp:
name: "&f&l [name]"
description: "[sign_text]"
random:
name: "&f&l Teletransporte aleatorio"
description: "&7 Hmm, ¿Dónde apareceré?"
tips:
click-to-previous: "&e Clic &7 para ver la página anterior."
click-to-next: "&e Clic &7 para ver la página siguiente."
click-to-warp: "&e Clic &7 para teletransportarse."
conversations:
prefix: "&l&6 [BentoBox]: &r"
protection:
flags:
PLACE_WARP:
name: Colocar Teletransporte
description: Permitir colocar un cartel de teletransporte

View File

@ -0,0 +1,28 @@
---
warp:
help:
description: te téléporte au Warp d'un autre joueur
parameters: "<pseudo>"
warps:
deactivate: "&cAncien panneau de Warp désactivé !"
error:
does-not-exist: "&cCe Warp n'existe plus !"
no-permission: "&cVous n'avez pas la permission pour faire cela !"
no-remove: "&cVous ne pouvez pas supprimer ce panneau !"
no-warps-yet: "&cIl n'y a encore aucun Warp sur ce serveur."
not-enough-level: "&cVotre niveau d'île n'est pas assez élevé pour faire cela
!"
not-on-island: "&cVous devez être sur votre île pour faire cela !"
not-safe: "&cCe Warp n'est pas sûr!"
your-level-is: "&cVotre île est seulement niveau [level] et doit être niveau [required]."
help:
description: Ouvre le menu des Warps
next: "&6Page suivante"
player-warped: "& 2 [pseudo] s'est téléporté à votre panneau Warp !"
previous: "&6Page précédente"
random: "&4 Warp aléatoire "
sign-removed: "&cPanneau de Warp supprimé !"
success: "&aSuccès !"
title: Panneau Warp
warpTip: "&6Placez un panneau et écrivez [text] sur la première ligne."
warpToPlayersSign: "&6 Téléportation vers le panneau de [pseudo]"

View File

@ -0,0 +1,28 @@
---
warp:
help:
description: Teleportálás a játékos teleport táblájához
parameters: "<játékosnév>"
warps:
deactivate: "&cRégi teleport tábla deaktiválva!"
error:
does-not-exist: "&cAjjaj! Ez a teleport nem létezik!"
no-permission: "&cNincs jogod ehhez!"
no-remove: "&cNem törölheted ezt a táblát!"
no-warps-yet: "&cJelenleg nem érhetőek el teleportok"
not-enough-level: "&cA szigeted szintje nem elég magas!"
not-on-island: "&cEhhez szigeten kell lenned!"
not-safe: "&cEz a teleport nem biztonságos!"
your-level-is: "&cJelenleg a sziget szinted [level], és nagyobbnak kell lennie,
mint [required]."
help:
description: Teleportok panel megnyitása
next: "&6Következő oldal"
player-warped: "&2[name] teleportált a teleport tábládhoz!"
previous: "&6Előző oldal"
random: "&4Véletlenszerű Teleport"
sign-removed: "&cTeleport tábla törölve!"
success: "&aSikeres!"
title: Teleport Táblák
warpTip: "&6Helyezz le egy teleport táblát a következő szöveggel [text] a tetején"
warpToPlayersSign: "&6Teleportálás [player] táblájához"

View File

@ -0,0 +1,52 @@
---
warp:
help:
description: warp ke tanda warp pemain
parameters: "<player name>"
warps:
deactivate: "&c Tanda warp lama dinonaktifkan!"
error:
does-not-exist: "&c Oh! Warp itu tidak ada lagi!"
no-permission: "&c Kamu tidak punya izin untuk melakukan itu!"
no-remove: "&c Kamu tidak bisa menghapus tanda itu!"
no-warps-yet: "&c Belum ada warps yang tersedia"
not-enough-level: "&c Level pulaumu tidak cukup tinggi!"
not-on-island: "&c Kamu harus berada di pulaumu untuk melakukan itu!"
not-safe: "&c Warp itu tidak aman!"
your-level-is: "&c Level pulau Anda hanya [level] dan harus lebih tinggi dari
[required]. Jalankan perintah level."
not-correct-rank: "&c Kamu tidak punya rank yang benar untuk mengatur warp!"
help:
description: buka panel warps
player-warped: "&2 [name] nge-warp ke tanda warp [gamemode] kamu!"
sign-removed: "&c Tanda warp dihilangkan!"
success: "&a Sukses!"
warpTip: "&6 Tempatkan tanda warp dengan [text] di atas\n"
warpToPlayersSign: "&6 Pergi ke tanda [player]"
gui:
titles:
warp-title: "&0&l Tanda Warp"
buttons:
previous:
name: "&f&l Halaman Sebelumnya"
description: "&7 Beralih ke halaman [number]"
next:
name: "&f&l Halaman Selanjutnya"
description: "&7 Beralih ke halaman [number]"
warp:
name: "&f&l [name]"
description: "[sign_text]"
random:
name: "&f&l Warp Acak"
description: "&7 Hmm, di mana aku akan muncul?"
tips:
click-to-previous: "&e Klik &7 untuk melihat halaman sebelumnya."
click-to-next: "&e Klik &7 untuk melihat halaman selanjutnya."
click-to-warp: "&e Klik &7 untuk warp."
conversations:
prefix: "&l&6 [BentoBox]: &r"
protection:
flags:
PLACE_WARP:
name: Tempatkan Warp
description: Izinkan menempatkan tanda warp

View File

@ -0,0 +1,29 @@
---
warp:
help:
description: teletrasporto al cartello Warp del giocatore
parameters: "<nome giocatore>"
warps:
deactivate: "&c Vecchio cartello Warp disattivato!"
error:
does-not-exist: "&c Quel cartello Warp non esiste più!"
no-permission: "&c Non hai i permessi per farlo!"
no-remove: "&c Non puoi rimuovere quel cartello!"
no-warps-yet: "&c Non ci sono ancora Warp disponibili"
not-enough-level: "&c Il tuo livello dell'isola non è abbastanza alto!"
not-on-island: "&c Devi essere nella tua isola per farlo!"
not-safe: "&c Il Warp non è sicuro!"
your-level-is: "&c Il tuo livello dell''isola è solo di [level] e deve essere
maggiore di [required]. Esegui il comando del calcolo dei livelli per aggiornare
il livello."
help:
description: apri il pannello dei Warp
next: "&6 Pagina Successiva"
player-warped: "&2 [name] teletrasportato al tuo cartello Warp!"
previous: "&6 Pagina Precedente"
random: "&4 Warp Random"
sign-removed: "&c Cartello Warp rimosso!"
success: "&a Successo!"
title: Cartelli Warp
warpTip: "&6 Piazza un cartello Warp con [text] scritto nella prima riga"
warpToPlayersSign: "&6 Teletrasporto al cartello Warp di [player]"

View File

@ -0,0 +1,32 @@
###########################################################################################
# This is a YML file. Be careful when editing. Check your edits in a YAML checker like #
# the one at http://yaml-online-parser.appspot.com #
###########################################################################################
warp:
help:
description: "プレイヤーのワープサインにワープする"
parameters: <名>
warps:
deactivate: "&c前のワープサインが無効になりました!"
error:
does-not-exist: "&cそのワープはもう存在しません"
no-permission: "&C許可がありません"
no-remove: "&Cワープサインは外せません"
no-warps-yet: "&C利用可能なワープはまだありません"
not-enough-level: "&C島のレベルは十分に高くありません"
not-on-island: "&Cあなたの島にいなければなりません"
not-safe: "&cワープは安全ではありません。!"
your-level-is: "&c島レベルはわずか[level]で、[required]より高くなければなりません"
help:
description: "ワープパネルを開く"
next: "&6次のページ"
player-warped: "&2[name]はあなたのワープサインに反った!"
previous: "&6前のページ"
sign-removed: "&Cワープサインを削除!"
success: "&A完了!"
title: "ワープサイン"
warpTip: "&6最初の行に[text]と一緒にワープサインを置きます"
warpToPlayersSign: "&6[player]のサインに反っている"

View File

@ -0,0 +1,28 @@
---
warp:
help:
description: pārvietoties pie spēlētāja uzaicinājuma zīmes
parameters: "<spēlētāja vārds>"
warps:
help:
description: atver uzaicinājumu zīmju sarakstu
title: Uzaicinājuma Zīmes
deactivate: "&c Iepriekšēja uzaicinājuma zīme deaktivizēta!"
error:
does-not-exist: "&c Oh! Šī uzaicinājuma zīme vairs neeksistē!"
no-permission: "&c Tev nav atļaujas veikt šo darbību!"
no-remove: "&c Tu nevari noņemt šo zīmi!"
no-warps-yet: "&c Diemžēl neviens uzaicinājums nav pieejams."
not-enough-level: "&c Tavs salas līmenis nav pietiekošs."
not-on-island: "&c Tev ir jābūt uz savas salas, lai veiktu šo darbību!"
not-safe: "&c Šīs uzaicinājums nav drošs!"
your-level-is: "&c Tavas salas līmenis ir [level], bet ir nepieciešams vismaz
[required]. Mēģini pārrēķināt salas līmeni."
next: "&6 Nākošā lapa"
player-warped: "&2 [name] ieradās pie uzaicinājuma zīmes!"
previous: "&6 Iepriekšējā lapa"
random: "&4 Nejaušs uzaicinājums"
sign-removed: "&c Uzaicinājuma zīme noņemta!"
success: "&a Izdevās!"
warpTip: "&6 Izveido zīmi ar [text] pirmajā rindā"
warpToPlayersSign: "&6 Pārvietojas uz [player] uzaicinājuma zīmi."

View File

@ -0,0 +1,52 @@
---
warp:
help:
description: teleporteer naar een speler zijn warp bord
parameters: "<speler>"
warps:
deactivate: "&c Oude warp bord is gedeactiveerd!"
error:
does-not-exist: "&c Oh nee! Deze warp bestaat niet meer!"
no-permission: "&c Je hebt geen permissies om dit te doen!"
no-remove: "&c Je kan dit bord niet weghalen!"
no-warps-yet: "&c Er bestaan nog geen warps op dit moment"
not-enough-level: "&c Je eiland level is nog niet hoog genoeg!"
not-on-island: "&c Je moet een eiland hebben om dit te doen!"
not-safe: "&c Deze warp is niet veilig!"
your-level-is: "&c Je eiland level is [level], maar het moet op zijn minst [required]
zijn. Gebruik het level commando."
not-correct-rank: "&c Je hebt niet de correcte rank om een warp te maken!"
help:
description: open het warp paneel
player-warped: "&2 [name] teleporteerde naar jou [gamemode] warp!"
sign-removed: "&c Warp bord verwijderd!"
success: "&a Geslaagd!"
warpTip: "&6 Plaats een warp bord met [text] op de eerste regel"
warpToPlayersSign: "&6 Teleporteren naar [player]'s warp"
gui:
titles:
warp-title: "&0&l Warp Borden"
buttons:
previous:
name: "&f&l Vorige pagina"
description: "&7 Ga naar pagina [number]"
next:
name: "&f&l Volgende pagina"
description: "&7 Ga naar pagina [number]"
warp:
name: "&f&l [name]"
description: "[sign_text]"
random:
name: "&f&l Willekeurige Warp"
description: "&7 Hmm, waar ga ik heen?"
tips:
click-to-previous: "&e Klik &7 om naar de vorige pagina te gaan."
click-to-next: "&e Klik &7 om naar de volgende pagina te gaan."
click-to-warp: "&e Klik &7 om te teleporteren."
conversations:
prefix: "&l&6 [BentoBox]: &r"
protection:
flags:
PLACE_WARP:
name: Plaats warp
description: Staat het toe om een warp bord te plaatsen

View File

@ -0,0 +1,46 @@
---
warp:
help:
description: teleportuje cię do tabliczki innego gracza
parameters: "<gracz>"
warps:
deactivate: "&c Stary teleport został zdezaktywowany!"
error:
does-not-exist: "&c Ten teleport nie istnieje."
no-permission: "&c Brak uprawnień!"
no-remove: "&c Nie możesz usunąć tej tabliczki!"
no-warps-yet: "&c Nie ma jeszcze stworzonych teleportów."
not-enough-level: "&c Twój poziom wyspy nie jest wystarczająco wysoki!"
not-on-island: "&c Musisz być na wyspie, by to zrobić."
not-safe: "&c Ten teleport nie jest bezpieczny!"
your-level-is: "&c Twój poziom wyspy to [level], a musi wynosić co najmniej [required].
Użyj komendy /is level."
help:
description: otwiera panel warpów
player-warped: "&2 [name] teleportował się do twojej tabliczki!"
sign-removed: "&c Usunięto tabliczkę!"
success: "&a Sukces!"
warpTip: "&6 Postaw tabliczkę z napisem [text]"
warpToPlayersSign: "&6 Teleportowanie do tabliczki gracza [player]"
gui:
titles:
warp-title: "&0&l Lista dostępnych wysp"
buttons:
previous:
name: "&f&l Poprzednia strona"
description: "&7 Przełącz na stronę [number]"
next:
name: "&f&l następna strona"
description: "&7 Przełącz na stronę [number]"
warp:
name: "&f&l [name]"
description: "[sign_text]"
random:
name: "&f&l Losowa wyspa"
description: "&7 Hmm, gdzie się pojawię?"
tips:
click-to-previous: "&e Kliknij &7, aby wyświetlić poprzednią stronę."
click-to-next: "&e Kliknij &7, aby wyświetlić następną stronę."
click-to-warp: "&e Kliknij &7, aby przenieść."
conversations:
prefix: "&l&6 [BentoBox]: &r"

View File

@ -0,0 +1,28 @@
---
warp:
help:
description: телепортироваться на знак игрока
parameters: "<название>"
warps:
deactivate: "&cСтарый знак телепортации деактивирован!"
error:
does-not-exist: "&cЭтот знак телепорта больше не существует!"
no-permission: "&cУ вас нет разрешения на это!"
no-remove: "&cВы не можете удалить этот знак!"
no-warps-yet: "&cТелепортов пока нет"
not-enough-level: "&cВаш уровень острова не достаточно!"
not-on-island: "&cВы должны быть на вашем острове, чтобы сделать это!"
not-safe: "&cМесто назначения не является безопасным!"
your-level-is: "&cУровень вашего острова всего [level] и должен быть выше [required].
Запустите команду уровня."
help:
description: открыть панель телепорта
next: "&6ледующая страница"
player-warped: "&2[name] телепортируется на ваш знак деформации!"
previous: "&6Предыдущая страница"
sign-removed: "&cЗнак телепорта удален!"
success: "&aУспех!"
title: Телепорт Знаки
warpTip: "&6Поместите знак телепортации с [text] в первой строке"
warpToPlayersSign: "&6Телепортация к знаку [player]"
random: "&4Случайный телепорт"

View File

@ -0,0 +1,26 @@
---
warp:
help:
description: Oyuncunun bölge tabelası.
parameters: "<name>"
warps:
deactivate: "&cEski ada warpı silindi!"
error:
does-not-exist: "&cÜzgünüm. Böyle bir bölge artık yok!"
no-permission: "&4Buna yetkin yok!"
no-remove: "&4Bu tabelayı kıramazsın!"
no-warps-yet: "&4Böyle bir bölge henüz yok."
not-enough-level: "&4Bunu koyman için daha fazla ada leveline ihtiyacın var."
not-on-island: "&4Adanda değilsin."
not-safe: "&4Ada bölgesi güvenli değil!"
your-level-is: "&9Ada levelin &e[level] &9ve &e[required]&9'den fazla olması gerek!"
help:
description: Bölge panelini açar.
next: "&6Sonraki Sayfa"
player-warped: "&d[name] &9ada bölgene ışınlandı!"
previous: "&6Önceki sayfa"
random: "&4Rastgele bölgeye git!"
sign-removed: "&4Ada tabelası kaldırıldı!"
title: "&dOyuncu bölgeleri &8- &5"
warpTip: "&6Ada bölgesi açmak için tabelanın en üstüne &a[text] &9yaz!"
warpToPlayersSign: "&d[player] &9bölgesine gidiliyor!"

View File

@ -0,0 +1,52 @@
---
warp:
help:
description: телепортація на знак варпа гравця
parameters: "<player name>"
warps:
deactivate: "&c Старий знак варпу деактивовано!"
error:
does-not-exist: "&c О, чорт! Того викривлення більше не існує!"
no-permission: "&c Ви не маєте на це дозволу!"
no-remove: "&c Ви не можете видалити цей знак!"
no-warps-yet: "&c Ще немає доступних варпів"
not-enough-level: "&c Рівень вашого острова недостатньо високий!"
not-on-island: "&c Для цього ви повинні бути на своєму острові!"
not-safe: "&c Ця варп небезпечна!"
your-level-is: "&c Рівень вашого острова становить лише [level] і має бути вищим
за [required]. Виконайте команду рівня."
not-correct-rank: "&c Ви не маєте належного рангу, щоб встановити варп!"
help:
description: відкрити панель варпів
player-warped: "&2 [name] телепортовано до вашого знака варпу [gamemode]!"
sign-removed: "&c Знак варпу видалено!"
success: "&a Успіх!"
warpTip: "&6 Розмістіть знак варпу з [text] угорі"
warpToPlayersSign: "&6 Телепортація на знак [player]."
gui:
titles:
warp-title: "&0&l Знаки варпів"
buttons:
previous:
name: "&f&l Попередня сторінка"
description: "&7 Перейти на сторінку [number]."
next:
name: "&f&l Наступна сторінка"
description: "&7 Перейти на сторінку [number]."
warp:
name: "&f&l [name]"
description: "[sign_text]"
random:
name: "&f&l Випадковий варп"
description: "&7 Хм, а де я з'явлюся?"
tips:
click-to-previous: "&e Натисніть &7, щоб переглянути попередню сторінку."
click-to-next: "&e Натисніть &7, щоб переглянути наступну сторінку."
click-to-warp: "&e Натисніть &7, щоб деформувати."
conversations:
prefix: "&l&6 [BentoBox]: &r"
protection:
flags:
PLACE_WARP:
name: Розмістіть варп
description: Дозволити розміщення варпів

View File

@ -0,0 +1,29 @@
#
# This is a YML file. Be careful when editing. Check your edits in a YAML checker like #
# the one at http://yaml-online-parser.appspot.com #
warp:
help:
description: đi đến điểm dịch chuyển của người chơi
parameters: <tên người chơi>
warps:
deactivate: '&cBảng cũ đã vô hiệu hóa!'
error:
does-not-exist: '&cUầy! Điểm dịch chuyển đó không tồn tại!'
no-permission: '&cBạn không có quyền làm điều đó!'
no-remove: '&cBạn không thể xóa bảng đó!'
no-warps-yet: '&cChưa có điểm dịch chuyển nào'
not-enough-level: '&cCấp đảo của bạn không đủ cao!'
not-on-island: '&cBạn phải ở đảo của bạn để làm điều đó!'
not-safe: '&cĐiểm dịch chuyển không an toàn!'
your-level-is: '&cCấp đảo của bạn là [level] và phải cao hơn [required]. Hãy dùng lệnh xem cấp đảo.'
help:
description: mở bảng dịch chuyển
next: '&6Trang kế'
player-warped: '&2[name] đã vào điểm dịch chuyển của bạn!'
previous: '&6Trang trước'
random: '&4Điểm dịch chuyển ngẫu nhiên'
sign-removed: '&cĐã xóa bảng dịch chuyển!'
success: '&aThành công!'
title: Bảng Dịch Chuyển
warpTip: '&6Đặt bảng với dòng chữ [text] ở dòng đầu tiên'
warpToPlayersSign: '&6Đang dịch chuyển đến chỗ của [player]'

View File

@ -1,29 +1,27 @@
###########################################################################################
# 本文件是 YML 格式的文件. 编辑时请务必小心. #
# 请在 http://yaml-online-parser.appspot.com 等 YAML 检查器中检查您的编辑. #
###########################################################################################
warps:
removed: "&C传送木牌已移除"
success: "&A成功!"
sign-removed: "&C传送木牌已移除!"
title: "传送木牌"
previous: "&6上一页"
next: "&6下一页"
warpToPlayersSign: "&6正传送到 [player] 的传送木牌"
warpTip: "&6放置一个第一行是 [text] 的木牌以创建传送木牌"
error:
no-remove: "&C无权移除传送木牌!"
not-enough-level: "&C岛屿等级不够高!"
no-permission: "&C权限不足!"
not-on-island: "&C操作必须在空岛上进行!"
duplicate: "&C木牌重复"
no-warps-yet: "&C暂无可用传送木牌"
your-level-is: "&c岛屿当前等级 [level], 需要等级 [required]"
help:
description: "打开传送面板"
---
warp:
help:
parameters: "<玩家名称>"
description: "传送到该玩家的传送木牌处"
description: 传送到该玩家的传送木牌处
parameters: "<player name>"
warps:
help:
description: 打开传送面板
title: 传送木牌
deactivate: "&c 旧传送牌已停用!"
error:
does-not-exist: "&c 哦不!那个传送点已经没了!"
no-permission: "&c 你无权那样做!"
no-remove: "&c 你拿不掉那个牌子的!"
no-warps-yet: "&c 暂无可用传送点"
not-enough-level: "&c 你的岛等级不够高!"
not-on-island: "&c 你得在自己的岛屿上操作!"
not-safe: "&c 目标传送点不安全!"
your-level-is: "&c 你的岛现在 [level] 级,需要 [required] 级。 试试岛屿等级命令吧。"
next: "&6 次页"
player-warped: "&2 [name] 传送到了你的传送牌!"
previous: "&6 前页"
random: "&4 随机传送"
sign-removed: "&c 拆掉传送牌了!"
success: "&a 成了!"
warpTip: "&6 放个牌子第一行写 [text]"
warpToPlayersSign: "&6 正传送到 [player] 的牌子"

View File

@ -0,0 +1,27 @@
---
warp:
help:
description: 傳送到該玩家的傳送木牌處
parameters: "<player name>"
warps:
deactivate: "&c 舊傳送牌已停用!"
error:
does-not-exist: "&c 哦不!那個傳送點已經沒了!"
no-permission: "&c 你沒有權限這樣做!"
no-remove: "&c 你拿不掉那個牌子的!"
no-warps-yet: "&c 暫無可用傳送點"
not-enough-level: "&c 你的島嶼等級不夠高!"
not-on-island: "&c 你得在自己的島嶼上操作!"
not-safe: "&c 目標傳送點不安全!"
your-level-is: "&c 你的島嶼現在 [level] 級,需要 [required] 級。 試試島嶼等級命令吧。"
help:
description: 打開傳送面板
next: "&6 下一頁"
player-warped: "&2 [name] 傳送到了你的傳送牌!"
previous: "&6 上一頁"
random: "&4 隨機傳送"
sign-removed: "&c 拆掉傳送牌了!"
success: "&成功!"
title: 傳送告示牌
warpTip: "&6 放個牌子第一行寫 [text] "
warpToPlayersSign: "&6 正傳送到 [player] 的牌子"

View File

@ -0,0 +1,79 @@
warps_panel:
title: warps.gui.titles.warp-title
type: INVENTORY
background:
icon: BLACK_STAINED_GLASS_PANE
title: "&b&r" # Empty text
border:
icon: BLACK_STAINED_GLASS_PANE
title: "&b&r" # Empty text
force-shown: []
content:
2:
2: warp_button
3: warp_button
4: warp_button
5: warp_button
6: warp_button
7: warp_button
8: warp_button
3:
1:
icon: tipped_arrow{CustomPotionColor:11546150}
title: warps.gui.buttons.previous.name
description: warps.gui.buttons.previous.description
data:
type: PREVIOUS
indexing: true
actions:
left:
type: PREVIOUS
tooltip: warps.gui.tips.click-to-previous
2: warp_button
3: warp_button
4: warp_button
5: warp_button
6: warp_button
7: warp_button
8: warp_button
9:
icon: tipped_arrow{CustomPotionColor:8439583}
title: warps.gui.buttons.next.name
description: warps.gui.buttons.next.description
data:
type: NEXT
indexing: true
actions:
left:
type: NEXT
tooltip: warps.gui.tips.click-to-next
4:
2: warp_button
3: warp_button
4: warp_button
5: warp_button
6: warp_button
7: warp_button
8: warp_button
6:
5:
icon: DROPPER
title: warps.gui.buttons.random.name
description: warps.gui.buttons.random.description
data:
type: RANDOM
actions:
warp:
click-type: left
tooltip: warps.gui.tips.click-to-warp
reusable:
warp_button:
icon: PLAYER_HEAD
title: warps.gui.buttons.warp.name
description: warps.gui.buttons.warp.description
data:
type: WARP
actions:
warp:
click-type: left
tooltip: warps.gui.tips.click-to-warp

View File

@ -0,0 +1,9 @@
name: BentoBox-Warps
main: world.bentobox.warps.WarpsPladdon
version: ${project.version}${build.number}
api-version: "1.17"
authors: [tastybento]
contributors: ["The BentoBoxWorld Community"]
website: https://bentobox.world
description: ${project.description}

View File

@ -1,167 +0,0 @@
/**
*
*/
package bentobox.addon.warps;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.PlayersManager;
/**
* @author ben
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class})
public class WarpPanelManagerTest {
private WarpSignsManager wsm;
private Warp addon;
private Player player;
private User user;
private World world;
private Inventory top;
private UUID uuid;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
addon = mock(Warp.class);
wsm = mock(WarpSignsManager.class);
when(addon.getWarpSignsManager()).thenReturn(wsm);
// Fill with 200 fake warps (I'm banking on them all being different, but there could be a clash)
List<UUID> list = new ArrayList<>();
for (int i = 0; i< 200; i++) {
list.add(UUID.randomUUID());
}
// One final one
uuid = UUID.randomUUID();
list.add(uuid);
when(wsm.getSortedWarps(Mockito.any())).thenReturn(list);
user = mock(User.class);
player = mock(Player.class);
when(user.getPlayer()).thenReturn(player);
when(user.getTranslation(Mockito.anyVararg())).thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
return invocation.getArgumentAt(0, String.class);
}});
// World
world = mock(World.class);
// BentoBox
BentoBox plugin = mock(BentoBox.class);
PlayersManager pm = mock(PlayersManager.class);
when(pm.getName(Mockito.any())).thenReturn("name");
when(plugin.getPlayers()).thenReturn(pm);
when(addon.getPlugin()).thenReturn(plugin);
// Bukkit
PowerMockito.mockStatic(Bukkit.class);
ItemFactory itemF = mock(ItemFactory.class);
ItemMeta imeta = mock(ItemMeta.class);
when(itemF.getItemMeta(Mockito.any())).thenReturn(imeta);
when(Bukkit.getItemFactory()).thenReturn(itemF);
top = mock(Inventory.class);
when(top.getSize()).thenReturn(9);
when(Bukkit.createInventory(Mockito.any(), Mockito.anyInt(), Mockito.any())).thenReturn(top); }
/**
* Test method for {@link bentobox.addon.warps.WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}.
*/
@Test
public void testShowWarpPanelFirst() {
WarpPanelManager wpm = new WarpPanelManager(addon);
wpm.showWarpPanel(world, user, 0);
Mockito.verify(player).openInventory(Mockito.eq(top));
// Just next sign
Mockito.verify(top, Mockito.times(53)).setItem(Mockito.anyInt(), Mockito.any(ItemStack.class));
}
/**
* Test method for {@link bentobox.addon.warps.WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}.
*/
@Test
public void testShowWarpPanelMiddle() {
WarpPanelManager wpm = new WarpPanelManager(addon);
wpm.showWarpPanel(world, user, 1);
Mockito.verify(player).openInventory(Mockito.eq(top));
// includes previous and next signs
Mockito.verify(top, Mockito.times(54)).setItem(Mockito.anyInt(), Mockito.any(ItemStack.class));
}
/**
* Test method for {@link bentobox.addon.warps.WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}.
*/
@Test
public void testShowWarpPanelLast() {
WarpPanelManager wpm = new WarpPanelManager(addon);
wpm.showWarpPanel(world, user, 3);
Mockito.verify(player).openInventory(Mockito.eq(top));
// Final amount, just previous sign
Mockito.verify(top, Mockito.times(46)).setItem(Mockito.anyInt(), Mockito.any(ItemStack.class));
}
/**
* Test method for {@link bentobox.addon.warps.WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}.
*/
@Test
public void testShowWarpPanelTestCache() {
WarpPanelManager wpm = new WarpPanelManager(addon);
// Do 45 initial lookups of sign text
wpm.showWarpPanel(world, user, 3);
// Get the panel again
wpm.showWarpPanel(world, user, 3);
// Should only check this 45 times because the sign text is cached
Mockito.verify(wsm, Mockito.times(45)).getSignText(Mockito.any(), Mockito.any());
}
/**
* Test method for {@link bentobox.addon.warps.WarpPanelManager#removeWarp(org.bukkit.World, java.util.UUID)}.
*/
@Test
public void testRemoveWarp() {
WarpPanelManager wpm = new WarpPanelManager(addon);
wpm.showWarpPanel(world, user, 3);
wpm.showWarpPanel(world, user, 3);
wpm.removeWarp(world, uuid);
wpm.showWarpPanel(world, user, 3);
// Removing the UUID should force a refresh and therefore 46 lookups
Mockito.verify(wsm, Mockito.times(46)).getSignText(Mockito.any(), Mockito.any());
}
}

View File

@ -1,318 +0,0 @@
package bentobox.addon.warps;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.plugin.PluginManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import bentobox.addon.warps.config.PluginConfig;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.LocalesManager;
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class})
public class WarpSignsListenerTest {
private Warp addon;
private Block block;
private Player player;
private World world;
private Sign s;
private WarpSignsManager wsm;
private PluginManager pm;
private UUID uuid;
private String[] lines;
private FileConfiguration config;
private PluginConfig settings;
private IslandsManager im;
@Before
public void setUp() throws Exception {
addon = mock(Warp.class);
when(addon.inRegisteredWorld(Mockito.any())).thenReturn(true);
config = mock(FileConfiguration.class);
when(config.getString(Mockito.anyString())).thenReturn("[WELCOME]");
when(addon.getConfig()).thenReturn(config);
block = mock(Block.class);
when(block.getType()).thenReturn(Material.WALL_SIGN);
world = mock(World.class);
when(block.getWorld()).thenReturn(world);
player = mock(Player.class);
when(player.hasPermission(Mockito.anyString())).thenReturn(false);
uuid = UUID.randomUUID();
when(player.getUniqueId()).thenReturn(uuid);
s = mock(Sign.class);
when(s.getLine(Mockito.anyInt())).thenReturn(ChatColor.GREEN + "[WELCOME]");
when(block.getState()).thenReturn(s);
wsm = mock(WarpSignsManager.class);
when(addon.getWarpSignsManager()).thenReturn(wsm);
Map<UUID, Location> list = new HashMap<>();
Location location = mock(Location.class);
when(location.getBlock()).thenReturn(block);
when(s.getLocation()).thenReturn(location);
list.put(uuid, location);
// Player is in world
when(wsm.getWarpMap(Mockito.eq(world))).thenReturn(list);
//Player has a warp sign already here
when(wsm.getWarp(Mockito.any(), Mockito.any())).thenReturn(location);
// Unique spot
when(wsm.addWarp(Mockito.any(), Mockito.any())).thenReturn(true);
// Bentobox
BentoBox plugin = mock(BentoBox.class);
when(addon.getPlugin()).thenReturn(plugin);
User.setPlugin(plugin);
LocalesManager lm = mock(LocalesManager.class);
when(lm.get(Mockito.any(), Mockito.any())).thenAnswer(new Answer<String>(){
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
return invocation.getArgumentAt(1, String.class);
}});
when(plugin.getLocalesManager()).thenReturn(lm);
// Bukkit
PowerMockito.mockStatic(Bukkit.class);
pm = mock(PluginManager.class);
when(Bukkit.getPluginManager()).thenReturn(pm);
// Lines
lines = new String[] {"[WELCOME]", "line2", "line3", "line4"};
settings = mock(PluginConfig.class);
when(settings.getWarpLevelRestriction()).thenReturn(10);
when(addon.getSettings()).thenReturn(settings);
im = mock(IslandsManager.class);
// On island
when(plugin.getIslands()).thenReturn(im);
when(im.userIsOnIsland(Mockito.any(World.class), Mockito.any(User.class))).thenReturn(true);
// Sufficient level
when(addon.getLevel(Mockito.any(), Mockito.any())).thenReturn(100L);
}
@Test
public void testWarpSignsListener() {
assertNotNull(new WarpSignsListener(addon));
}
@Test
public void testOnSignBreakNotSign() {
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
when(block.getType()).thenReturn(Material.STONE);
wsl.onSignBreak(e);
assertFalse(e.isCancelled());
Mockito.verify(block, Mockito.times(2)).getType();
}
@Test
public void testOnSignBreakWrongWorld() {
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
when(addon.inRegisteredWorld(Mockito.any())).thenReturn(false);
wsl.onSignBreak(e);
assertFalse(e.isCancelled());
Mockito.verify(addon).inRegisteredWorld(Mockito.eq(world));
}
@Test
public void testOnSignBreakNullState() {
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
when(block.getState()).thenReturn(null);
wsl.onSignBreak(e);
assertFalse(e.isCancelled());
Mockito.verify(block).getState();
}
@Test
public void testOnSignNotWelcomeSign() {
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
when(s.getLine(Mockito.anyInt())).thenReturn(ChatColor.RED + "[WELCOME]");
wsl.onSignBreak(e);
assertFalse(e.isCancelled());
Mockito.verify(s).getLine(Mockito.eq(0));
Mockito.verify(addon).getConfig();
}
@Test
public void testOnSignNotRealWelcomeSign() {
// Right text, but not in the right position
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
when(s.getLocation()).thenReturn(mock(Location.class));
wsl.onSignBreak(e);
assertFalse(e.isCancelled());
Mockito.verify(wsm).getWarpMap(Mockito.eq(world));
Mockito.verify(s).getLocation();
}
@Test
public void testOnSignRemovePlayerSignWrongPlayer() {
when(player.getUniqueId()).thenReturn(UUID.randomUUID());
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
wsl.onSignBreak(e);
assertTrue(e.isCancelled());
Mockito.verify(player).sendMessage("warps.error.no-remove");
}
@Test
public void testOnSignRemovePlayerSignPlayerIsOp() {
when(player.getUniqueId()).thenReturn(UUID.randomUUID());
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
when(player.isOp()).thenReturn(true);
wsl.onSignBreak(e);
// Success!
assertFalse(e.isCancelled());
Mockito.verify(pm).callEvent(Mockito.any());
}
@Test
public void testOnSignRemovePlayerSignPlayerHasPerm() {
when(player.getUniqueId()).thenReturn(UUID.randomUUID());
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
when(player.hasPermission(Mockito.anyString())).thenReturn(true);
wsl.onSignBreak(e);
// Success!
assertFalse(e.isCancelled());
Mockito.verify(pm).callEvent(Mockito.any());
}
@Test
public void testOnSignRemoveCorrectPlayer() {
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
wsl.onSignBreak(e);
// Success!
assertFalse(e.isCancelled());
Mockito.verify(pm).callEvent(Mockito.any());
}
/**
* Sign create
*/
@Test
public void testOnCreateWrongWorld() {
when(player.hasPermission(Mockito.anyString())).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
when(addon.inRegisteredWorld(Mockito.any())).thenReturn(false);
wsl.onSignWarpCreate(e);
Mockito.verify(addon).inRegisteredWorld(Mockito.eq(world));
}
@Test
public void testOnCreateWrongText() {
when(player.hasPermission(Mockito.anyString())).thenReturn(true);
lines = new String[] {"line1", "line2", "line3", "line4"};
when(player.hasPermission(Mockito.anyString())).thenReturn(false);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
wsl.onSignWarpCreate(e);
Mockito.verify(config).getString(Mockito.anyString());
Mockito.verify(player, Mockito.never()).sendMessage(Mockito.anyString());
}
@Test
public void testOnCreateNoPerm() {
when(player.hasPermission(Mockito.anyString())).thenReturn(false);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
wsl.onSignWarpCreate(e);
Mockito.verify(player).sendMessage("warps.error.no-permission");
}
@Test
public void testOnLevelPresentNotHighEnough() {
when(player.hasPermission(Mockito.anyString())).thenReturn(true);
when(addon.getLevel(Mockito.any(), Mockito.any())).thenReturn(1L);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
wsl.onSignWarpCreate(e);
Mockito.verify(player).sendMessage("warps.error.not-enough-level");
}
@Test
public void testOnNoIsland() {
when(im.userIsOnIsland(Mockito.any(World.class), Mockito.any(User.class))).thenReturn(false);
when(player.hasPermission(Mockito.anyString())).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
wsl.onSignWarpCreate(e);
Mockito.verify(player).sendMessage("warps.error.not-on-island");
assertEquals(ChatColor.RED + "[WELCOME]", e.getLine(0));
}
@Test
public void testCreateNoSignAlreadyUniqueSpot() {
when(wsm.getWarp(Mockito.any(), Mockito.any())).thenReturn(null);
when(player.hasPermission(Mockito.anyString())).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
wsl.onSignWarpCreate(e);
Mockito.verify(player).sendMessage("warps.success");
assertEquals(ChatColor.GREEN + "[WELCOME]", e.getLine(0));
}
@Test
public void testCreateNoSignAlreadyDuplicateSpot() {
when(wsm.addWarp(Mockito.any(), Mockito.any())).thenReturn(false);
when(wsm.getWarp(Mockito.any(), Mockito.any())).thenReturn(null);
when(player.hasPermission(Mockito.anyString())).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
wsl.onSignWarpCreate(e);
Mockito.verify(player).sendMessage("warps.error.duplicate");
assertEquals(ChatColor.RED + "[WELCOME]", e.getLine(0));
}
@Test
public void testCreateNoSignDeactivateOldSign() {
when(player.hasPermission(Mockito.anyString())).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
wsl.onSignWarpCreate(e);
Mockito.verify(player).sendMessage("warps.success");
assertEquals(ChatColor.GREEN + "[WELCOME]", e.getLine(0));
Mockito.verify(s).setLine(0, ChatColor.RED + "[WELCOME]");
}
}

View File

@ -0,0 +1,486 @@
package world.bentobox.warps;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.Tag;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.plugin.PluginManager;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.AbstractDatabaseHandler;
import world.bentobox.bentobox.database.DatabaseSetup;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.LocalesManager;
import world.bentobox.bentobox.managers.PlaceholdersManager;
import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.bentobox.util.Util;
import world.bentobox.warps.config.Settings;
import world.bentobox.warps.event.WarpInitiateEvent;
import world.bentobox.warps.managers.SignCacheManager;
import world.bentobox.warps.managers.WarpSignsManager;
import world.bentobox.warps.objects.WarpsData;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, Util.class, DatabaseSetup.class})
public class WarpSignsManagerTest {
@Mock
private Warp addon;
@Mock
private BentoBox plugin;
@Mock
private World world;
@Mock
private static AbstractDatabaseHandler<Object> handler;
private WarpSignsManager wsm;
@Mock
private Logger logger;
@Mock
private WarpsData load;
private final UUID uuid = UUID.randomUUID();
@Mock
private Location location;
@Mock
private Block block;
@Mock
private PluginManager pim;
@Mock
private Server server;
@Mock
private Player player;
@Mock
private SignCacheManager wpm;
@Mock
private PlayersManager pm;
@Mock
private OfflinePlayer offlinePlayer;
@Mock
private Settings settings;
@Mock
private IslandWorldManager iwm;
@Mock
private IslandsManager im;
@Mock
private Island island;
@SuppressWarnings("unchecked")
@BeforeClass
public static void beforeClass() {
// This has to be done beforeClass otherwise the tests will interfere with each other
handler = mock(AbstractDatabaseHandler.class);
// Database
PowerMockito.mockStatic(DatabaseSetup.class);
DatabaseSetup dbSetup = mock(DatabaseSetup.class);
when(DatabaseSetup.getDatabase()).thenReturn(dbSetup);
when(dbSetup.getHandler(any())).thenReturn(handler);
}
/**
* @throws java.lang.Exception exception
*/
@Before
public void setUp() throws Exception {
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
when(addon.getPlugin()).thenReturn(plugin);
when(addon.getLogger()).thenReturn(logger);
// Player
when(player.getUniqueId()).thenReturn(uuid);
when(player.isOnline()).thenReturn(true);
when(player.canSee(any(Player.class))).thenReturn(true);
User.setPlugin(plugin);
User.getInstance(player);
// Locales
LocalesManager lm = mock(LocalesManager.class);
when(lm.getAvailablePrefixes(any())).thenReturn(Collections.emptySet());
when(lm.get(Mockito.any(), Mockito.any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
when(plugin.getLocalesManager()).thenReturn(lm);
// Return the same string
PlaceholdersManager phm = mock(PlaceholdersManager.class);
when(phm.replacePlaceholders(any(), anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
when(plugin.getPlaceholdersManager()).thenReturn(phm);
// Server
when(addon.getServer()).thenReturn(server);
when(server.getPlayer(any(UUID.class))).thenReturn(player);
// Util
PowerMockito.mockStatic(Util.class);
when(Util.getWorld(any())).thenAnswer((Answer<World>) invocation -> invocation.getArgument(0, World.class));
when(Util.sameWorld(any(), any())).thenReturn(true);
when(Util.translateColorCodes(any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
// Location
when(location.getWorld()).thenReturn(world);
when(location.getBlock()).thenReturn(block);
when(location.getBlockX()).thenReturn(23);
when(location.getBlockY()).thenReturn(24);
when(location.getBlockZ()).thenReturn(25);
when(player.getLocation()).thenReturn(location);
when(world.getEnvironment()).thenReturn(Environment.NORMAL);
when(world.isChunkLoaded(anyInt(), anyInt())).thenReturn(true);
// Block
when(block.getType()).thenReturn(Material.ACACIA_SIGN);
when(block.getLocation()).thenReturn(location);
Sign sign = mock(Sign.class);
String[] lines = {"[Welcome]", "line2", "line3", "line4"};
when(sign.getLines()).thenReturn(lines);
when(sign.getLine(anyInt())).thenReturn("[Welcome]");
when(sign.getType()).thenReturn(Material.ACACIA_SIGN);
when(block.getState()).thenReturn(sign);
org.bukkit.block.data.type.Sign signBd = mock(org.bukkit.block.data.type.Sign.class);
when(signBd.getRotation()).thenReturn(BlockFace.EAST);
when(block.getBlockData()).thenReturn(signBd);
when(block.getRelative(any())).thenReturn(block);
// Handler
when(handler.objectExists("warps")).thenReturn(true);
Map<Location, UUID> warpMap = Collections.singletonMap(location, uuid);
when(load.getWarpSigns()).thenReturn(warpMap);
when(handler.loadObject(anyString())).thenReturn(load);
// Settings
when(addon.getSettings()).thenReturn(settings);
when(settings.getWelcomeLine()).thenReturn("[Welcome]");
when(settings.getLoreFormat()).thenReturn("&f");
// Bukkit
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
when(Bukkit.getPluginManager()).thenReturn(pim);
// Tags
when(Tag.STANDING_SIGNS.isTagged(Material.ACACIA_SIGN)).thenReturn(true);
// Players Manager
when(plugin.getPlayers()).thenReturn(pm);
when(pm.getName(uuid)).thenReturn("tastybento");
// Offline player
when(server.getOfflinePlayer(any(UUID.class))).thenReturn(offlinePlayer);
when(offlinePlayer.getLastPlayed()).thenReturn(System.currentTimeMillis());
// IWM
when(plugin.getIWM()).thenReturn(iwm);
when(iwm.getPermissionPrefix(any())).thenReturn("bskyblock.");
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
// Island Manager
when(addon.getIslands()).thenReturn(im);
when(im.getIsland(any(), any(UUID.class))).thenReturn(island);
when(im.isSafeLocation(any())).thenReturn(true);
// WarpPanelManager
when(addon.getSignCacheManager()).thenReturn(wpm);
wsm = new WarpSignsManager(addon, plugin);
}
/**
*/
@After
public void tearDown() {
User.clearUsers();
}
/**
* Test method for {@link WarpSignsManager#getWarpMap(org.bukkit.World)}.
*/
@Test
public void testGetWarpMap() {
assertFalse("Map is empty", wsm.getWarpMap(world).isEmpty());
}
/**
* Test method for {@link WarpSignsManager#getWarpMap(org.bukkit.World)}.
*/
@Test
public void testGetWarpMapNullWorld() {
when(location.getWorld()).thenReturn(null);
wsm = new WarpSignsManager(addon, plugin);
assertTrue("Map is not empty", wsm.getWarpMap(world).isEmpty());
}
/**
* Test method for {@link WarpSignsManager#getWarpMap(org.bukkit.World)}.
*/
@Test
public void testGetWarpMapWrongBlockType() {
when(block.getType()).thenReturn(Material.COAL_ORE);
wsm = new WarpSignsManager(addon, plugin);
assertTrue("Map is not empty", wsm.getWarpMap(world).isEmpty());
}
/**
* Test method for {@link WarpSignsManager#getWarpMap(org.bukkit.World)}.
*/
@Test
public void testGetWarpMapNullLocation() {
Map<Location, UUID> warpMap = Collections.singletonMap(null, uuid);
when(load.getWarpSigns()).thenReturn(warpMap);
wsm = new WarpSignsManager(addon, plugin);
assertTrue("Map is not empty", wsm.getWarpMap(world).isEmpty());
}
/**
* Test method for {@link WarpSignsManager#getWarpMap(org.bukkit.World)}.
* @throws Exception exception
*/
@Test
public void testGetWarpMapNullDatabaseObject() throws Exception {
when(handler.loadObject(anyString())).thenReturn(null);
wsm = new WarpSignsManager(addon, plugin);
assertTrue("Map is not empty", wsm.getWarpMap(world).isEmpty());
}
/**
* Test method for {@link WarpSignsManager#getWarpMap(org.bukkit.World)}.
*/
@Test
public void testGetWarpMapNothingInDatabase() {
when(handler.objectExists("warps")).thenReturn(false);
wsm = new WarpSignsManager(addon, plugin);
assertTrue("Map is not empty", wsm.getWarpMap(world).isEmpty());
}
/**
* Test method for {@link WarpSignsManager#WarpSignsManager(world.bentobox.warps.Warp, world.bentobox.bentobox.BentoBox)}.
*/
@Test
public void testWarpSignsManager() {
verify(addon).log("Loading warps...");
verify(load).getWarpSigns();
verify(block).getType();
}
/**
* Test method for {@link WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}.
*/
@Test
public void testAddWarpNullPlayer() {
assertFalse(wsm.addWarp(null, null));
}
/**
* Test method for {@link WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}.
*/
@Test
public void testAddWarpNullLocation() {
assertFalse(wsm.addWarp(uuid, null));
}
/**
* Test method for {@link WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}.
*/
@Test
public void testAddWarpReplaceOldSign() {
assertTrue(wsm.addWarp(uuid, location));
verify(player).sendMessage("warps.sign-removed");
}
/**
* Test method for {@link WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}.
*/
@Test
public void testAddWarpReplaceOldSignDifferentPlayer() {
assertTrue(wsm.addWarp(UUID.randomUUID(), location));
verify(player).sendMessage("warps.sign-removed");
}
/**
* Test method for {@link WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}.
*/
@Test
public void testAddWarp() {
Location loc = mock(Location.class);
assertTrue(wsm.addWarp(uuid, loc));
verify(pim).callEvent(any(WarpInitiateEvent.class));
}
/**
* Test method for {@link WarpSignsManager#getWarp(org.bukkit.World, java.util.UUID)}.
*/
@Test
public void testGetWarpWorldWorld() {
assertNull(wsm.getWarp(mock(World.class), uuid));
}
/**
* Test method for {@link WarpSignsManager#getWarp(org.bukkit.World, java.util.UUID)}.
*/
@Test
public void testGetWarp() {
assertEquals(location, wsm.getWarp(world, uuid));
}
/**
* Test method for {@link WarpSignsManager#getWarpOwner(org.bukkit.Location)}.
*/
@Test
public void testGetWarpOwner() {
assertEquals("tastybento", wsm.getWarpOwner(location));
}
/**
* Test method for {@link WarpSignsManager#getSortedWarps(org.bukkit.World)}.
*/
@Test
public void testGetSortedWarps() {
CompletableFuture<List<UUID>> r = new CompletableFuture<>();
assertEquals(1, wsm.processWarpMap(r, world).size());
}
/**
* Test method for {@link WarpSignsManager#listWarps(org.bukkit.World)}.
*/
@Test
public void testListWarps() {
assertEquals(1, wsm.listWarps(world).size());
assertEquals(uuid, wsm.listWarps(world).toArray()[0]);
}
/**
* Test method for {@link WarpSignsManager#removeWarp(org.bukkit.Location)}.
*/
@Test
public void testRemoveWarpLocation() {
wsm.removeWarp(location);
assertTrue(wsm.listWarps(world).isEmpty());
}
/**
* Test method for {@link WarpSignsManager#removeWarp(org.bukkit.World, java.util.UUID)}.
*/
@Test
public void testRemoveWarpWorldUUID() {
wsm.removeWarp(world, uuid);
assertTrue(wsm.listWarps(world).isEmpty());
}
/**
* Test method for {@link WarpSignsManager#saveWarpList()}.
* @throws Exception general exception
*/
@Test
public void testSaveWarpList() throws Exception {
wsm.saveWarpList();
verify(handler, Mockito.atLeastOnce()).saveObject(any());
}
/**
* Test method for {@link WarpSignsManager#warpPlayer(org.bukkit.World, world.bentobox.bentobox.api.user.User, java.util.UUID)}.
*/
@Test
public void testWarpPlayer() {
Player p = mock(Player.class);
when(p.getUniqueId()).thenReturn(UUID.randomUUID());
when(p.getWorld()).thenReturn(world);
when(p.getName()).thenReturn("tastybento");
when(p.getLocation()).thenReturn(location);
when(p.isOnline()).thenReturn(true);
when(p.canSee(any(Player.class))).thenReturn(true);
@Nullable
User u = User.getInstance(p);
PowerMockito.when(Util.teleportAsync(any(), any(), any())).thenReturn(CompletableFuture.completedFuture(true));
wsm.warpPlayer(world, u, uuid);
PowerMockito.verifyStatic(Util.class);
Util.teleportAsync(eq(p), any(), eq(TeleportCause.COMMAND));
verify(player).sendMessage(anyString());
}
/**
* Test method for {@link WarpSignsManager#hasWarp(org.bukkit.World, java.util.UUID)}.
*/
@Test
public void testHasWarp() {
assertTrue(wsm.hasWarp(world, uuid));
assertFalse(wsm.hasWarp(mock(World.class), uuid));
assertFalse(wsm.hasWarp(world, UUID.randomUUID()));
}
/**
* Test method for {@link WarpSignsManager#loadWarpList()}.
*/
@Test
public void testLoadWarpListNoWarpTable() {
// Run again but with no database table
when(handler.objectExists(anyString())).thenReturn(false);
wsm = new WarpSignsManager(addon, plugin);
// Save
wsm.saveWarpList();
// Default load in constructor check
verify(addon, times(2)).log("Loading warps...");
assertTrue(wsm.getWarpMap(world).isEmpty());
}
/**
* Test method for {@link WarpSignsManager#loadWarpList()}.
* @throws Exception exception
*/
@Test
public void testLoadWarpListEmptyWarpTable() throws Exception {
// Run again but with no data in table
when(handler.loadObject(anyString())).thenReturn(null);
wsm = new WarpSignsManager(addon, plugin);
// Save
wsm.saveWarpList();
// Default load in constructor check
verify(addon, times(2)).log("Loading warps...");
assertTrue(wsm.getWarpMap(world).isEmpty());
}
}

View File

@ -0,0 +1,256 @@
package world.bentobox.warps.commands;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.plugin.PluginManager;
import org.bukkit.scheduler.BukkitScheduler;
import org.eclipse.jdt.annotation.NonNull;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.warps.Warp;
import world.bentobox.warps.managers.WarpSignsManager;
import world.bentobox.warps.config.Settings;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class})
public class WarpCommandTest {
private static final String WELCOME_LINE = "[Welcome]";
@Mock
private CompositeCommand ic;
@Mock
private User user;
@Mock
private World world;
@Mock
private IslandWorldManager iwm;
@Mock
private Warp addon;
// Command under test
private WarpCommand wc;
@Mock
private Settings settings;
@Mock
private WarpSignsManager wsm;
@Mock
private PlayersManager pm;
@Mock
private PluginManager pim;
@Mock
private world.bentobox.bentobox.Settings s;
@Mock
private BukkitScheduler sch;
/**
*/
@Before
public void setUp() {
// Set up plugin
BentoBox plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Command manager
CommandsManager cm = mock(CommandsManager.class);
when(plugin.getCommandsManager()).thenReturn(cm);
// Addon
when(ic.getAddon()).thenReturn(addon);
when(ic.getPermissionPrefix()).thenReturn("bskyblock.");
when(ic.getWorld()).thenReturn(world);
// IWM friendly name
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
when(iwm.inWorld(any(World.class))).thenReturn(true);
when(plugin.getIWM()).thenReturn(iwm);
// Player
UUID uuid = UUID.randomUUID();
when(user.getUniqueId()).thenReturn(uuid);
when(user.getWorld()).thenReturn(world);
// settings
when(addon.getSettings()).thenReturn(settings);
when(settings.getWarpCommand()).thenReturn("warp");
when(settings.getWelcomeLine()).thenReturn(WELCOME_LINE);
// Warp Signs Manager
when(addon.getWarpSignsManager()).thenReturn(wsm);
@NonNull
Set<UUID> set = new HashSet<>();
set.add(UUID.randomUUID());
set.add(UUID.randomUUID());
set.add(UUID.randomUUID());
when(wsm.listWarps(world)).thenReturn(set);
// Players Manager
when(plugin.getPlayers()).thenReturn(pm);
when(addon.getPlayers()).thenReturn(pm);
// Repeat twice because it is asked twice
when(pm.getName(any())).thenReturn("tastybento", "tastybento", "poslovich", "poslovich", "BONNe", "BONNe", "Joe");
// Bukkit
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getPluginManager()).thenReturn(pim);
when(Bukkit.getScheduler()).thenReturn(sch);
// BentoBox settings
when(plugin.getSettings()).thenReturn(s);
when(s.getDelayTime()).thenReturn(0);
}
@After
public void tearDown() {
Mockito.framework().clearInlineMocks();
}
public void warpCommandWarpCompositeCommand() {
// Command under test
wc = new WarpCommand(addon, ic);
}
public void warpCommandWarp() {
// Command under test
wc = new WarpCommand(addon);
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpCommand#setup()}.
*/
@Test
public void testSetupWarpCompositeCommand() {
warpCommandWarpCompositeCommand();
assertEquals("bskyblock.island.warp", wc.getPermission());
assertTrue(wc.isOnlyPlayer());
assertEquals("warp.help.parameters", wc.getParameters());
assertEquals("warp.help.description", wc.getDescription());
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpCommand#setup()}.
*/
@Test
public void testSetupWarp() {
warpCommandWarp();
assertEquals(Warp.WELCOME_WARP_SIGNS + ".warp", wc.getPermission());
assertTrue(wc.isOnlyPlayer());
assertEquals("warp.help.parameters", wc.getParameters());
assertEquals("warp.help.description", wc.getDescription());
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoArgs() {
warpCommandWarpCompositeCommand();
wc.execute(user, "warp", Collections.emptyList());
verify(user).sendMessage("commands.help.header", TextVariables.LABEL, "BSkyBlock");
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringKnownPlayer() {
warpCommandWarpCompositeCommand();
assertTrue(wc.execute(user, "warp", Collections.singletonList("tastybento")));
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringKnownPlayerWarp() {
warpCommandWarp();
assertTrue(wc.execute(user, "warp", Collections.singletonList("tastybento")));
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringKnownPlayerMixedCase() {
warpCommandWarpCompositeCommand();
assertTrue(wc.execute(user, "warp", Collections.singletonList("tAsTyBEnTo")));
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringKnownPlayerStartOnly() {
when(pm.getName(any())).thenReturn("tastybento");
warpCommandWarpCompositeCommand();
assertTrue(wc.execute(user, "warp", Collections.singletonList("tAsTy")));
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringUnknownPlayer() {
warpCommandWarpCompositeCommand();
assertFalse(wc.execute(user, "warp", Collections.singletonList("LSPVicky")));
verify(user).sendMessage("warps.error.does-not-exist");
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoWarpsYet() {
when(wsm.listWarps(world)).thenReturn(Collections.emptySet());
warpCommandWarpCompositeCommand();
assertFalse(wc.execute(user, "warp", Collections.singletonList("LSPVicky")));
verify(user).sendMessage("warps.error.no-warps-yet");
verify(user).sendMessage("warps.warpTip", "[text]", WELCOME_LINE);
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testTabCompleteUserStringListOfString() {
warpCommandWarpCompositeCommand();
List<String> op = wc.tabComplete(user, "warp", Collections.singletonList("tas")).get();
assertEquals("tastybento", op.get(0));
assertEquals("tastybento", op.get(1));
assertEquals("poslovich", op.get(2));
}
}

View File

@ -0,0 +1,185 @@
package world.bentobox.warps.commands;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.eclipse.jdt.annotation.NonNull;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.warps.managers.SignCacheManager;
import world.bentobox.warps.Warp;
import world.bentobox.warps.managers.WarpSignsManager;
import world.bentobox.warps.config.Settings;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class})
public class WarpsCommandTest {
private static final String WELCOME_LINE = "[Welcome]";
@Mock
private CompositeCommand ic;
@Mock
private User user;
@Mock
private World world;
@Mock
private IslandWorldManager iwm;
@Mock
private Warp addon;
// Command under test
private WarpsCommand wc;
@Mock
private Settings settings;
@Mock
private WarpSignsManager wsm;
@Mock
private PlayersManager pm;
@Mock
private SignCacheManager wpm;
/**
*/
@Before
public void setUp() {
// Set up plugin
BentoBox plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Command manager
CommandsManager cm = mock(CommandsManager.class);
when(plugin.getCommandsManager()).thenReturn(cm);
// Addon
when(ic.getAddon()).thenReturn(addon);
when(ic.getPermissionPrefix()).thenReturn("bskyblock.");
// World
when(world.toString()).thenReturn("world");
// Player
when(user.getWorld()).thenReturn(world);
// settings
when(addon.getSettings()).thenReturn(settings);
when(settings.getWarpsCommand()).thenReturn("warps");
when(settings.getWelcomeLine()).thenReturn(WELCOME_LINE);
// Warp Signs Manager
when(addon.getWarpSignsManager()).thenReturn(wsm);
@NonNull
Set<UUID> set = new HashSet<>();
set.add(UUID.randomUUID());
set.add(UUID.randomUUID());
set.add(UUID.randomUUID());
when(wsm.listWarps(world)).thenReturn(set);
CompletableFuture<List<UUID>> warps = new CompletableFuture<>();
warps.complete(set.stream().toList());
when(wsm.getSortedWarps(world)).thenReturn(warps);
// Warp Panel Manager
when(addon.getSignCacheManager()).thenReturn(wpm);
}
public void warpCommandWarpsCompositeCommand() {
// Command under test
wc = new WarpsCommand(addon, ic);
}
public void warpCommandWarps() {
// Command under test
wc = new WarpsCommand(addon);
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpsCommand#setup()}.
*/
@Test
public void testSetupWarpCompositeCommand() {
warpCommandWarpsCompositeCommand();
assertEquals("bskyblock.island.warps", wc.getPermission());
assertTrue(wc.isOnlyPlayer());
assertEquals("warps.help.description", wc.getDescription());
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpsCommand#setup()}.
*/
@Test
public void testSetupWarp() {
warpCommandWarps();
assertEquals(Warp.WELCOME_WARP_SIGNS + ".warps", wc.getPermission());
assertTrue(wc.isOnlyPlayer());
assertEquals("warps.help.description", wc.getDescription());
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoWarpsYet() {
when(wsm.listWarps(world)).thenReturn(Collections.emptySet());
warpCommandWarpsCompositeCommand();
assertFalse(wc.execute(user, "warps", Collections.emptyList()));
verify(user).sendMessage("warps.error.no-warps-yet");
verify(user).sendMessage("warps.warpTip", "[text]", WELCOME_LINE);
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoWarpsYetNoAddon() {
when(wsm.listWarps(world)).thenReturn(Collections.emptySet());
warpCommandWarps();
assertFalse(wc.execute(user, "warps", Collections.emptyList()));
verify(user).sendMessage("warps.error.no-warps-yet");
verify(user).sendMessage("warps.warpTip", "[text]", WELCOME_LINE);
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfString() {
warpCommandWarpsCompositeCommand();
assertTrue(wc.execute(user, "warps", Collections.emptyList()));
}
/**
* Test method for {@link world.bentobox.warps.commands.WarpsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoAddon() {
warpCommandWarps();
assertTrue(wc.execute(user, "warps", Collections.emptyList()));
}
}

View File

@ -0,0 +1,444 @@
package world.bentobox.warps.listeners;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Server;
import org.bukkit.Tag;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.plugin.PluginManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.events.flags.FlagProtectionChangeEvent;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.LocalesManager;
import world.bentobox.bentobox.managers.PlaceholdersManager;
import world.bentobox.bentobox.util.Util;
import world.bentobox.warps.Warp;
import world.bentobox.warps.managers.WarpSignsManager;
import world.bentobox.warps.config.Settings;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, Util.class, NamespacedKey.class, Tag.class})
public class WarpSignsListenerTest {
@Mock
private Warp addon;
@Mock
private Block block;
@Mock
private Player player;
@Mock
private World world;
private Sign s;
@Mock
private WarpSignsManager wsm;
private PluginManager pm;
private String[] lines;
@Mock
private FileConfiguration config;
@Mock
private Settings settings;
@Mock
private IslandsManager im;
@Mock
private IslandWorldManager iwm;
@Mock
private Island island;
@Before
public void setUp() {
// Bukkit
PowerMockito.mockStatic(Bukkit.class);
pm = mock(PluginManager.class);
when(Bukkit.getPluginManager()).thenReturn(pm);
Server server = mock(Server.class);
when(server.getVersion()).thenReturn("1.14");
when(Bukkit.getServer()).thenReturn(server);
Bukkit.setServer(server);
PowerMockito.mockStatic(NamespacedKey.class);
NamespacedKey keyValue = mock(NamespacedKey.class);
when(NamespacedKey.minecraft(anyString())).thenReturn(keyValue);
when(addon.inRegisteredWorld(any())).thenReturn(true);
when(config.getString(anyString())).thenReturn("[WELCOME]");
when(addon.getConfig()).thenReturn(config);
// Block
Material sign;
try {
sign = Material.valueOf("OAK_WALL_SIGN");
} catch (Exception e) {
sign = Material.valueOf("WALL_SIGN");
}
when(block.getType()).thenReturn(sign);
when(block.getWorld()).thenReturn(world);
// Player
when(player.hasPermission(anyString())).thenReturn(false);
UUID uuid = UUID.randomUUID();
when(player.getUniqueId()).thenReturn(uuid);
s = mock(Sign.class);
when(s.getLine(anyInt())).thenReturn(ChatColor.GREEN + "[WELCOME]");
when(block.getState()).thenReturn(s);
// warp signs manager
when(addon.getWarpSignsManager()).thenReturn(wsm);
Map<UUID, Location> list = new HashMap<>();
Location location = mock(Location.class);
when(location.getBlock()).thenReturn(block);
when(s.getLocation()).thenReturn(location);
when(block.getLocation()).thenReturn(location);
list.put(uuid, location);
// Player is in world
when(wsm.getWarpMap(world)).thenReturn(list);
//Player has a warp sign already here
when(wsm.getWarp(any(), any())).thenReturn(location);
// Unique spot
when(wsm.addWarp(any(), any())).thenReturn(true);
// Bentobox
BentoBox plugin = mock(BentoBox.class);
when(addon.getPlugin()).thenReturn(plugin);
User.setPlugin(plugin);
LocalesManager lm = mock(LocalesManager.class);
when(lm.get(any(), any())).thenReturn(null);
when(plugin.getLocalesManager()).thenReturn(lm);
// Lines
lines = new String[] {"[WELCOME]", "line2", "line3", "line4"};
when(settings.getWarpLevelRestriction()).thenReturn(10);
when(settings.getWelcomeLine()).thenReturn("[WELCOME]");
when(addon.getSettings()).thenReturn(settings);
island = mock(Island.class);
when(im.getIslandAt(any())).thenReturn(Optional.of(island));
// On island
when(plugin.getIslands()).thenReturn(im);
when(im.userIsOnIsland(any(World.class), any(User.class))).thenReturn(true);
// Sufficient level
when(addon.getLevel(any(), any())).thenReturn(100L);
// IWM
when(plugin.getIWM()).thenReturn(iwm);
when(iwm.getAddon(any())).thenReturn(Optional.empty());
when(iwm.inWorld(any(World.class))).thenReturn(true);
Answer<String> answer = invocation -> invocation.getArgument(1, String.class);
// Util
PowerMockito.mockStatic(Util.class);
when(Util.getWorld(any())).thenReturn(world);
when(Util.stripSpaceAfterColorCodes(anyString())).thenAnswer(invocation -> invocation.getArgument(0, String.class));
when(Util.translateColorCodes(any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
// Locales
when(lm.get(any(User.class), anyString())).thenAnswer(answer);
when(plugin.getLocalesManager()).thenReturn(lm);
// Placeholders
PlaceholdersManager placeholdersManager = mock(PlaceholdersManager.class);
when(plugin.getPlaceholdersManager()).thenReturn(placeholdersManager);
when(placeholdersManager.replacePlaceholders(any(), any())).thenAnswer(answer);
}
@Test
public void testWarpSignsListener() {
assertNotNull(new WarpSignsListener(addon));
}
@Test
public void testOnSignBreakNotSign() {
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
when(block.getType()).thenReturn(Material.STONE);
wsl.onSignBreak(e);
assertFalse(e.isCancelled());
}
@Test
public void testOnSignNotGameWorld() {
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
when(addon.inRegisteredWorld(any())).thenReturn(false);
wsl.onSignBreak(e);
assertFalse(e.isCancelled());
verify(addon).inRegisteredWorld(world);
}
@Test
public void testOnSignNotWelcomeSign() {
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
when(s.getLine(Mockito.anyInt())).thenReturn(ChatColor.RED + "[WELCOME]");
wsl.onSignBreak(e);
assertFalse(e.isCancelled());
verify(s).getLine(0);
verify(settings).getWelcomeLine();
}
@Test
public void testOnSignNotRealWelcomeSign() {
// Right text, but not in the right position
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
when(s.getLocation()).thenReturn(mock(Location.class));
wsl.onSignBreak(e);
assertFalse(e.isCancelled());
verify(wsm).getWarpMap(world);
verify(s).getLocation();
}
@Test
public void testOnSignRemovePlayerSignWrongPlayer() {
when(player.getUniqueId()).thenReturn(UUID.randomUUID());
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
wsl.onSignBreak(e);
assertTrue(e.isCancelled());
verify(player).sendMessage("warps.error.no-remove");
}
@Test
public void testOnSignRemovePlayerSignPlayerIsOp() {
when(player.getUniqueId()).thenReturn(UUID.randomUUID());
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
when(player.isOp()).thenReturn(true);
wsl.onSignBreak(e);
// Success!
assertFalse(e.isCancelled());
verify(pm).callEvent(any());
}
@Test
public void testOnSignRemovePlayerSignPlayerHasPerm() {
when(player.getUniqueId()).thenReturn(UUID.randomUUID());
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
when(player.hasPermission(anyString())).thenReturn(true);
wsl.onSignBreak(e);
// Success!
assertFalse(e.isCancelled());
verify(pm).callEvent(any());
}
@Test
public void testOnSignRemoveCorrectPlayer() {
WarpSignsListener wsl = new WarpSignsListener(addon);
BlockBreakEvent e = new BlockBreakEvent(block, player);
wsl.onSignBreak(e);
// Success!
assertFalse(e.isCancelled());
verify(pm).callEvent(any());
}
/**
* Sign create
*/
@Test
public void testOnCreateWrongWorldGameWorld() {
when(player.hasPermission(anyString())).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
when(addon.inRegisteredWorld(any())).thenReturn(false);
wsl.onSignWarpCreate(e);
verify(addon).inRegisteredWorld(world);
}
@Test
public void testOnCreateNotGameWorldAllowed() {
when(settings.isAllowInOtherWorlds()).thenReturn(true);
when(iwm.inWorld(any(World.class))).thenReturn(false);
when(player.hasPermission(anyString())).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
when(addon.inRegisteredWorld(any())).thenReturn(false);
wsl.onSignWarpCreate(e);
verify(player).sendMessage("warps.success");
assertEquals(ChatColor.GREEN + "[WELCOME]", e.getLine(0));
}
@Test
public void testOnCreateWithoutCorrectRankNotAllowed() {
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
when(player.hasPermission(anyString())).thenReturn(true);
when(addon.inRegisteredWorld(any())).thenReturn(true);
when(island.getRank(player.getUniqueId())).thenReturn(0);
when(island.getFlag(any())).thenReturn(1000);
wsl.onSignWarpCreate(e);
verify(player).sendMessage("warps.error.not-correct-rank");
}
@Test
public void testOnFlagChangeWhenSettingIsOffNothingHappens() {
Flag flag = mock(Flag.class);
when(addon.getCreateWarpFlag()).thenReturn(flag);
when(settings.getRemoveExistingWarpsWhenFlagChanges()).thenReturn(false);
WarpSignsListener wsl = new WarpSignsListener(addon);
FlagProtectionChangeEvent e = new FlagProtectionChangeEvent(island, player.getUniqueId(), flag, 1000);
wsl.onFlagChange(e);
verifyNoInteractions(island);
}
@Test
public void testOnFlagChangeWhenSettingIsOnWarpGetsRemoved() {
Flag flag = mock(Flag.class);
when(addon.getCreateWarpFlag()).thenReturn(flag);
when(settings.getRemoveExistingWarpsWhenFlagChanges()).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon);
Map<UUID, Location> warps = Map.of(
player.getUniqueId(), block.getLocation()
);
when(wsm.getWarpMap(any())).thenReturn(warps);
when(island.inIslandSpace(any(Location.class))).thenReturn(true);
FlagProtectionChangeEvent e = new FlagProtectionChangeEvent(island, player.getUniqueId(), flag, 1000);
wsl.onFlagChange(e);
verify(addon.getWarpSignsManager()).removeWarp(any(), any());
}
@Test
public void testOnCreateNotGameWorldNotAllowed() {
when(settings.isAllowInOtherWorlds()).thenReturn(false);
when(iwm.inWorld(any(World.class))).thenReturn(false);
when(player.hasPermission(anyString())).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
when(addon.inRegisteredWorld(any())).thenReturn(false);
wsl.onSignWarpCreate(e);
verify(player, never()).sendMessage("warps.success");
}
@Test
public void testOnCreateNotGameWorldNoPerm() {
when(settings.isAllowInOtherWorlds()).thenReturn(true);
when(iwm.inWorld(any(World.class))).thenReturn(false);
when(player.hasPermission(anyString())).thenReturn(false);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
when(addon.inRegisteredWorld(any())).thenReturn(false);
wsl.onSignWarpCreate(e);
verify(player).sendMessage("warps.error.no-permission");
}
@Test
public void testOnCreateWrongText() {
when(player.hasPermission(anyString())).thenReturn(true);
lines = new String[] {"line1", "line2", "line3", "line4"};
when(player.hasPermission(anyString())).thenReturn(false);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
wsl.onSignWarpCreate(e);
verify(settings).getWelcomeLine();
verify(player, Mockito.never()).sendMessage(anyString());
}
@Test
public void testOnCreateNoPerm() {
when(player.hasPermission(anyString())).thenReturn(false);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
wsl.onSignWarpCreate(e);
verify(player).sendMessage("warps.error.no-permission");
}
@Test
public void testOnLevelPresentNotHighEnough() {
when(player.hasPermission(anyString())).thenReturn(true);
when(addon.getLevel(any(), any())).thenReturn(1L);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
wsl.onSignWarpCreate(e);
verify(player).sendMessage("warps.error.not-enough-level");
}
@Test
public void testOnNoIsland() {
when(im.userIsOnIsland(any(World.class), any(User.class))).thenReturn(false);
when(player.hasPermission(anyString())).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
wsl.onSignWarpCreate(e);
verify(player).sendMessage("warps.error.not-on-island");
assertEquals(ChatColor.RED + "[WELCOME]", e.getLine(0));
}
@Test
public void testCreateNoSignAlreadyUniqueSpot() {
when(wsm.getWarp(any(), any())).thenReturn(null);
when(player.hasPermission(anyString())).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
wsl.onSignWarpCreate(e);
verify(player).sendMessage("warps.success");
assertEquals(ChatColor.GREEN + "[WELCOME]", e.getLine(0));
}
@Test
public void testCreateNoSignDeactivateOldSign() {
when(player.hasPermission(anyString())).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines);
wsl.onSignWarpCreate(e);
verify(player).sendMessage("warps.success");
assertEquals(ChatColor.GREEN + "[WELCOME]", e.getLine(0));
verify(s).setLine(0, ChatColor.RED + "[WELCOME]");
}
}