Compare commits

...

109 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
47 changed files with 2055 additions and 1275 deletions

View File

@ -1,26 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
**Description**
<!-- A clear and concise description of what the bug is. -->
**Steps to reproduce the behavior:**
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem. -->
**Server Information:**
Do `bbox version` in the console and paste the result here:
**Additional context**
<!-- Add any other context about the problem here. -->

View File

@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

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

View File

@ -1,21 +0,0 @@
language: java
sudo: false
addons:
sonarcloud:
organization: "bentobox-world"
jdk:
- openjdk8
- openjdk11
matrix:
allow_failures:
- jdk: openjdk11
script:
mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent install sonar:sonar -Dsonar.projectKey=BentoBoxWorld_Warps
cache:
directories:
- '$HOME/.m2/repository'
- '$HOME/.sonar/cache'

View File

@ -5,6 +5,8 @@ to disable use by gamemode.
## How to use ## 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 1. Place the jar in the addons folder of the BentoBox plugin
2. Restart the server 2. Restart the server
3. The addon will create a data folder and inside the folder will be a config.yml 3. The addon will create a data folder and inside the folder will be a config.yml

104
pom.xml
View File

@ -54,19 +54,23 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>17</java.version>
<!-- Non-minecraft related dependencies --> <!-- Non-minecraft related dependencies -->
<powermock.version>2.0.2</powermock.version> <powermock.version>2.0.9</powermock.version>
<!-- More visible way how to change dependency versions --> <!-- More visible way how to change dependency versions -->
<spigot.version>1.14.4-R0.1-SNAPSHOT</spigot.version> <spigot.version>1.19.4-R0.1-SNAPSHOT</spigot.version>
<bentobox.version>1.6.0</bentobox.version> <bentobox.version>2.0.0-SNAPSHOT</bentobox.version>
<level.version>1.5.0</level.version> <level.version>2.7.0-SNAPSHOT</level.version>
<!-- Revision variable removes warning about dynamic version --> <!-- Revision variable removes warning about dynamic version -->
<revision>${build.version}-SNAPSHOT</revision> <revision>${build.version}-SNAPSHOT</revision>
<!-- Do not change unless you want different name for local builds. --> <!-- Do not change unless you want different name for local builds. -->
<build.number>-LOCAL</build.number> <build.number>-LOCAL</build.number>
<!-- This allows to change between versions. --> <!-- This allows to change between versions. -->
<build.version>1.9.4</build.version> <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> </properties>
<!-- Profiles will allow to automatically change build version. --> <!-- Profiles will allow to automatically change build version. -->
@ -109,30 +113,6 @@
<build.number></build.number> <build.number></build.number>
</properties> </properties>
</profile> </profile>
<profile>
<id>sonar</id>
<properties>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<sonar.organization>bentobox-world</sonar.organization>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.6.0.1398</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>sonar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles> </profiles>
<repositories> <repositories>
@ -162,7 +142,7 @@
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId> <artifactId>mockito-core</artifactId>
<version>3.0.0</version> <version>3.11.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -196,7 +176,7 @@
<dependency> <dependency>
<groupId>org.eclipse.jdt</groupId> <groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.annotation</artifactId> <artifactId>org.eclipse.jdt.annotation</artifactId>
<version>2.2.200</version> <version>2.2.600</version>
</dependency> </dependency>
</dependencies> </dependencies>
@ -246,7 +226,39 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version> <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>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@ -256,15 +268,18 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>3.0.1</version> <version>3.1.1</version>
<configuration> <configuration>
<show>public</show> <source>16</source>
<show>private</show>
<failOnError>false</failOnError> <failOnError>false</failOnError>
<additionalJOption>-Xdoclint:none</additionalJOption> <additionalJOption>-Xdoclint:none</additionalJOption>
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
<id>attach-javadocs</id> <id>attach-javadocs</id>
<phase>install</phase>
<goals> <goals>
<goal>jar</goal> <goal>jar</goal>
</goals> </goals>
@ -284,14 +299,6 @@
</execution> </execution>
</executions> </executions>
</plugin> </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> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId> <artifactId>maven-install-plugin</artifactId>
@ -305,7 +312,7 @@
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.3</version> <version>0.8.10</version>
<configuration> <configuration>
<append>true</append> <append>true</append>
<excludes> <excludes>
@ -316,16 +323,21 @@
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
<id>pre-unit-test</id> <id>prepare-agent</id>
<goals> <goals>
<goal>prepare-agent</goal> <goal>prepare-agent</goal>
</goals> </goals>
</execution> </execution>
<execution> <execution>
<id>post-unit-test</id> <id>report</id>
<goals> <goals>
<goal>report</goal> <goal>report</goal>
</goals> </goals>
<configuration>
<formats>
<format>XML</format>
</formats>
</configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>

View File

@ -1,79 +0,0 @@
package world.bentobox.warps;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import world.bentobox.bentobox.database.Database;
import world.bentobox.warps.objects.SignCache;
public class SignCacheManager {
private Map<World, Map<UUID, SignCacheItem>> cachedSigns = new HashMap<>();
private Warp addon;
// Database handler for level data
private Database<SignCache> handler;
public SignCacheManager(Warp addon) {
this.addon = addon;
handler = new Database<>(addon, SignCache.class);
// Load the sign caches
loadCache();
}
private void loadCache() {
handler.loadObjects().forEach(w -> {
World world = Bukkit.getWorld(w.getUniqueId());
if (world != null) {
cachedSigns.put(world, w.getSigns());
}
});
}
void saveCache() {
cachedSigns.forEach((w, m) -> handler.saveObject(new SignCache(w, m)));
}
Material getSignIcon(World world, UUID warpOwner) {
// Add the worlds if we haven't seen this before
cachedSigns.putIfAbsent(world, new HashMap<>());
if (cachedSigns.get(world).containsKey(warpOwner)) {
return cachedSigns.get(world).get(warpOwner).getType();
}
// Not in cache
SignCacheItem sc = addon.getWarpSignsManager().getSignInfo(world, warpOwner);
cachedSigns.get(world).put(warpOwner, sc);
return sc.getType();
}
/**
* Gets sign text and cache it
* @param playerUUID
* @return sign text in a list
*/
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).getSignText();
}
SignCacheItem result = addon.getWarpSignsManager().getSignInfo(world, playerUUID);
cachedSigns.get(world).put(playerUUID, result);
return result.getSignText();
}
/**
* Removes sign text from the cache
* @param world - world
* @param key - uuid of owner
*/
void removeWarp(World world, UUID key) {
cachedSigns.putIfAbsent(world, new HashMap<>());
cachedSigns.get(world).remove(key);
}
}

View File

@ -7,16 +7,23 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import world.bentobox.bentobox.api.addons.Addon; import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.configuration.Config; 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.bentobox.util.Util;
import world.bentobox.level.Level; import world.bentobox.level.Level;
import world.bentobox.warps.commands.WarpCommand; import world.bentobox.warps.commands.WarpCommand;
import world.bentobox.warps.commands.WarpsCommand; import world.bentobox.warps.commands.WarpsCommand;
import world.bentobox.warps.config.Settings; import world.bentobox.warps.config.Settings;
import world.bentobox.warps.listeners.WarpSignsListener; 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 * Addin to BentoBox that enables welcome warp signs
@ -38,16 +45,16 @@ public class Warp extends Addon {
*/ */
public static final String WELCOME_WARP_SIGNS = "welcomewarpsigns"; public static final String WELCOME_WARP_SIGNS = "welcomewarpsigns";
/**
* Warp panel Manager
*/
private WarpPanelManager warpPanelManager;
/** /**
* Worlds Sign manager. * Worlds Sign manager.
*/ */
private WarpSignsManager warpSignsManager; private WarpSignsManager warpSignsManager;
/**
* Sign Cache Manager
*/
private SignCacheManager signCacheManager;
/** /**
* This variable stores in which worlds this addon is working. * This variable stores in which worlds this addon is working.
*/ */
@ -68,6 +75,11 @@ public class Warp extends Addon {
*/ */
private Config<Settings> settingsConfig; private Config<Settings> settingsConfig;
/**
* Create Warp Flag
*/
private Flag createWarpFlag;
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Section: Methods // Section: Methods
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -84,7 +96,7 @@ public class Warp extends Addon {
// Save default config.yml // Save default config.yml
this.saveDefaultConfig(); this.saveDefaultConfig();
// Load the plugin's config // Load the plugin's config
if (this.loadSettings() && settings.isAllowInOtherWorlds()) { if (this.loadSettings() && getSettings().isAllowInOtherWorlds()) {
// Load the master warp and warps command // Load the master warp and warps command
new WarpCommand(this); new WarpCommand(this);
new WarpsCommand(this); new WarpsCommand(this);
@ -100,11 +112,11 @@ public class Warp extends Addon {
{ {
super.onReload(); super.onReload();
if (this.hooked) { if (this.hooked || getSettings().isAllowInOtherWorlds()) {
this.warpSignsManager.saveWarpList(); this.warpSignsManager.saveWarpList();
this.loadSettings(); this.loadSettings();
this.getLogger().info("WelcomeWarp addon reloaded."); this.getLogger().info("Warps addon reloaded.");
} }
} }
@ -132,24 +144,38 @@ public class Warp extends Addon {
} }
}); });
if (hooked) if (hooked || getSettings().isAllowInOtherWorlds())
{ {
// Start warp signs // Start warp signs
warpSignsManager = new WarpSignsManager(this, this.getPlugin()); warpSignsManager = new WarpSignsManager(this, this.getPlugin());
warpPanelManager = new WarpPanelManager(this); signCacheManager = new SignCacheManager(this);
// Load the listener // Load the listener
this.registerListener(new WarpSignsListener(this)); 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 @Override
public void onDisable(){ public void onDisable(){
// Save the warps // Save the warps
if (warpSignsManager != null) if (warpSignsManager != null) {
warpSignsManager.saveWarpList(); warpSignsManager.saveWarpList();
if (warpPanelManager != null) }
warpPanelManager.saveCache();
} }
@ -167,17 +193,21 @@ public class Warp extends Addon {
this.setState(State.DISABLED); this.setState(State.DISABLED);
return false; return false;
} }
// Save existing panels.
this.saveResource("panels/warps_panel.yml", false);
settingsConfig.saveConfigObject(settings); settingsConfig.saveConfigObject(settings);
return true; return true;
} }
/** /**
* Get warp panel manager * Get sign cache manager
* @return Warp Panel Manager * @return Sign Cache Manager
*/ */
public WarpPanelManager getWarpPanelManager() { public SignCacheManager getSignCacheManager() {
return warpPanelManager; return signCacheManager;
} }
public WarpSignsManager getWarpSignsManager() { public WarpSignsManager getWarpSignsManager() {
@ -204,14 +234,32 @@ public class Warp extends Addon {
return settings; return settings;
} }
/**
* @return the createWarpFlag
*/
public Flag getCreateWarpFlag() {
return createWarpFlag;
}
/** /**
* Get the island level * Get the island level
* @param world - world * @param world - world
* @param uniqueId - player's UUID * @param uniqueId - player's UUID
* @return island level or null if there is no level plugin * @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) { public Long getLevel(World world, UUID uniqueId) {
return this.getPlugin().getAddonsManager().getAddonByName(LEVEL_ADDON_NAME).map(l -> ((Level) l).getIslandLevel(world, uniqueId)).orElse(null); // 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) /* (non-Javadoc)
@ -238,20 +286,14 @@ public class Warp extends Addon {
return null; return null;
} }
} }
switch(requestLabel) { return switch (requestLabel) {
case "getSortedWarps": case "getSortedWarps" -> getWarpSignsManager().getSortedWarps(world);
return getWarpSignsManager().getSortedWarps(world); case "getWarp" -> uuid == null ? null : getWarpSignsManager().getWarp(world, uuid);
case "getWarp": case "getWarpMap" -> getWarpSignsManager().getWarpMap(world);
return uuid == null ? null : getWarpSignsManager().getWarp(world, uuid); case "hasWarp" -> uuid == null ? null : getWarpSignsManager().hasWarp(world, uuid);
case "getWarpMap": case "listWarps" -> getWarpSignsManager().listWarps(world);
return getWarpSignsManager().getWarpMap(world); default -> null;
case "hasWarp": };
return uuid == null ? null : getWarpSignsManager().hasWarp(world, uuid);
case "listWarps":
return getWarpSignsManager().listWarps(world);
default:
return null;
}
} }

View File

@ -1,130 +0,0 @@
package world.bentobox.warps;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
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 SignCacheManager signCacheManager;
public WarpPanelManager(Warp addon) {
this.addon = addon;
signCacheManager = new SignCacheManager(addon);
}
private PanelItem getPanelItem(World world, UUID warpOwner) {
PanelItemBuilder pib = new PanelItemBuilder()
.name(addon.getSettings().getNameFormat() + addon.getPlugin().getPlayers().getName(warpOwner))
.description(signCacheManager.getSign(world, warpOwner))
.clickHandler((panel, clicker, click, slot) -> hander(world, clicker, warpOwner));
Material icon = signCacheManager.getSignIcon(world, warpOwner);
if (icon.equals(Material.PLAYER_HEAD)) {
return pib.icon(addon.getPlayers().getName(warpOwner)).build();
} else {
return pib.icon(icon).build();
}
}
private boolean hander(World world, User clicker, UUID warpOwner) {
clicker.closeInventory();
String playerCommand = addon.getPlugin().getIWM().getAddon(world).map(gm -> gm.getPlayerCommand().map(c -> c.getLabel()).orElse("")).orElse("");
String command = addon.getSettings().getWarpCommand() + " " + addon.getPlayers().getName(warpOwner);
clicker.getPlayer().performCommand((playerCommand.isEmpty() ? "" : playerCommand + " ") + command);
//addon.getWarpSignsManager().warpPlayer(world, clicker, warpOwner);
return true;
}
private PanelItem getRandomButton(World world, User user, UUID warpOwner) {
///give @p minecraft:player_head{display:{Name:"{\"text\":\"Question Mark\"}"},SkullOwner:"MHF_Question"} 1
return new PanelItemBuilder()
.name(addon.getSettings().getNameFormat() + user.getTranslation("warps.random"))
.clickHandler((panel, clicker, click, slot) -> hander(world, clicker, warpOwner))
.icon(Material.END_CRYSTAL).build();
}
/**
* 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));
UUID randomWarp = null;
// Add random UUID
if (!warps.isEmpty() && addon.getSettings().isRandomAllowed()) {
randomWarp = warps.get(new Random().nextInt(warps.size()));
warps.add(0, randomWarp);
}
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") + " " + (index + 1));
int i = index * PANEL_MAX_SIZE;
for (; i < (index * PANEL_MAX_SIZE + PANEL_MAX_SIZE) && i < warps.size(); i++) {
if (i == 0 && randomWarp != null) {
panelBuilder.item(getRandomButton(world, user, randomWarp));
} else {
panelBuilder.item(getPanelItem(world, warps.get(i)));
}
}
final int panelNum = index;
// Add signs
if (i < warps.size()) {
// Next
panelBuilder.item(new PanelItemBuilder()
.name(user.getTranslation("warps.next"))
.icon(new ItemStack(Material.STONE))
.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(user.getTranslation("warps.previous"))
.icon(new ItemStack(Material.COBBLESTONE))
.clickHandler((panel, clicker, click, slot) -> {
user.closeInventory();
showWarpPanel(world, user, panelNum-1);
return true;
}).build());
}
panelBuilder.build();
}
/**
* Removes sign text from the cache
* @param world - world
* @param key - uuid of owner
*/
public void removeWarp(World world, UUID key) {
signCacheManager.removeWarp(world, key);
}
public void saveCache() {
signCacheManager.saveCache();
}
}

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

@ -4,7 +4,6 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
import org.bukkit.World; import org.bukkit.World;
@ -17,11 +16,10 @@ import world.bentobox.warps.Warp;
* The /is warp <name> command * The /is warp <name> command
* *
* @author tastybento * @author tastybento
*
*/ */
public class WarpCommand extends DelayedTeleportCommand { public class WarpCommand extends DelayedTeleportCommand {
private Warp addon; private final Warp addon;
public WarpCommand(Warp addon, CompositeCommand bsbIslandCmd) { public WarpCommand(Warp addon, CompositeCommand bsbIslandCmd) {
super(bsbIslandCmd, addon.getSettings().getWarpCommand()); super(bsbIslandCmd, addon.getSettings().getWarpCommand());
@ -52,12 +50,22 @@ public class WarpCommand extends DelayedTeleportCommand {
user.sendMessage("warps.warpTip", "[text]", addon.getSettings().getWelcomeLine()); user.sendMessage("warps.warpTip", "[text]", addon.getSettings().getWelcomeLine());
return false; return false;
} else { } else {
// Check if this is part of a name // Attemp to find warp with exact player's name
UUID foundWarp = warpList.stream().filter(u -> getPlayers().getName(u).equalsIgnoreCase(args.get(0)) UUID foundWarp = warpList.stream().filter(u -> getPlayers().getName(u).equalsIgnoreCase(args.get(0))).findFirst().orElse(null);
|| getPlayers().getName(u).toLowerCase().startsWith(args.get(0).toLowerCase())).findFirst().orElse(null);
if (foundWarp == null) { if (foundWarp == null) {
user.sendMessage("warps.error.does-not-exist");
return false; // 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 { } else {
// Warp exists! // Warp exists!
this.delayCommand(user, () -> addon.getWarpSignsManager().warpPlayer(world, user, foundWarp)); this.delayCommand(user, () -> addon.getWarpSignsManager().warpPlayer(world, user, foundWarp));
@ -72,7 +80,7 @@ public class WarpCommand extends DelayedTeleportCommand {
@Override @Override
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) { public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
World world = getWorld() == null ? user.getWorld() : getWorld(); World world = getWorld() == null ? user.getWorld() : getWorld();
return Optional.of(addon.getWarpSignsManager().listWarps(world).stream().map(getPlayers()::getName).collect(Collectors.toList())); return Optional.of(addon.getWarpSignsManager().listWarps(world).stream().map(getPlayers()::getName).toList());
} }

View File

@ -4,9 +4,11 @@ import java.util.List;
import org.bukkit.World; import org.bukkit.World;
import world.bentobox.warps.Warp;
import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.api.user.User;
import world.bentobox.warps.Warp;
import world.bentobox.warps.panels.WarpsPanel;
/** /**
* Handles the warps command * Handles the warps command
@ -15,7 +17,7 @@ import world.bentobox.bentobox.api.user.User;
*/ */
public class WarpsCommand extends CompositeCommand { public class WarpsCommand extends CompositeCommand {
private Warp addon; private final Warp addon;
public WarpsCommand(Warp addon, CompositeCommand bsbIslandCmd) { public WarpsCommand(Warp addon, CompositeCommand bsbIslandCmd) {
super(bsbIslandCmd, addon.getSettings().getWarpsCommand()); super(bsbIslandCmd, addon.getSettings().getWarpsCommand());
@ -32,7 +34,7 @@ public class WarpsCommand extends CompositeCommand {
*/ */
@Override @Override
public void setup() { public void setup() {
this.setPermission(this.getParent() == null ? Warp.WELCOME_WARP_SIGNS + ".warp" : "island.warp"); this.setPermission(this.getParent() == null ? Warp.WELCOME_WARP_SIGNS + ".warps" : "island.warps");
this.setOnlyPlayer(true); this.setOnlyPlayer(true);
this.setDescription("warps.help.description"); this.setDescription("warps.help.description");
} }
@ -43,12 +45,17 @@ public class WarpsCommand extends CompositeCommand {
@Override @Override
public boolean execute(User user, String label, List<String> args) { public boolean execute(User user, String label, List<String> args) {
World world = getWorld() == null ? user.getWorld() : getWorld(); World world = getWorld() == null ? user.getWorld() : getWorld();
if (addon.getWarpSignsManager().listWarps(world).isEmpty()) { if (addon
.getWarpSignsManager()
.listWarps(world)
.isEmpty()) {
user.sendMessage("warps.error.no-warps-yet"); user.sendMessage("warps.error.no-warps-yet");
user.sendMessage("warps.warpTip", "[text]", addon.getSettings().getWelcomeLine()); user.sendMessage("warps.warpTip", "[text]", addon.getSettings().getWelcomeLine());
return false; return false;
} }
addon.getWarpPanelManager().showWarpPanel(world, user, 0);
WarpsPanel.openPanel(this.addon, world, user);
return true; return true;
} }

View File

@ -23,20 +23,19 @@ public class Settings implements ConfigObject
@ConfigEntry(path = "warplevelrestriction") @ConfigEntry(path = "warplevelrestriction")
private int warpLevelRestriction = 10; 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("")
@ConfigComment("Text that player must put on sign to make it a warp sign") @ConfigComment("Text that player must put on sign to make it a warp sign")
@ConfigComment("Not case sensitive!") @ConfigComment("Not case sensitive!")
@ConfigEntry(path = "welcomeLine") @ConfigEntry(path = "welcomeLine")
private String welcomeLine = "[Welcome]"; private String welcomeLine = "[Welcome]";
@ConfigComment("")
@ConfigComment("Icon that will be displayed in Warps list. SIGN counts for any kind of sign and the type of")
@ConfigComment("wood used will be reflected in the panel if the server supports it.")
@ConfigComment("It uses native Minecraft material strings, but using string 'PLAYER_HEAD', it is possible to")
@ConfigComment("use player heads instead. Beware that Mojang API rate limiting may prevent heads from loading.")
@ConfigEntry(path = "icon")
private String icon = "SIGN";
@ConfigComment("") @ConfigComment("")
@ConfigComment("This list stores GameModes in which Level addon should not work.") @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("To disable addon it is necessary to write its name in new line that starts with -. Example:")
@ -45,23 +44,12 @@ public class Settings implements ConfigObject
@ConfigEntry(path = "disabled-gamemodes") @ConfigEntry(path = "disabled-gamemodes")
private Set<String> disabledGameModes = new HashSet<>(); private Set<String> disabledGameModes = new HashSet<>();
@ConfigComment("")
@ConfigComment("Warp panel name formatting.")
@ConfigComment("Example: &c will make names red. &f is white")
@ConfigEntry(path = "name-format")
private String nameFormat = "&f";
@ConfigComment("") @ConfigComment("")
@ConfigComment("Warp panel default lore formatting.") @ConfigComment("Warp panel default lore formatting.")
@ConfigComment("Example: &c will make lore red. &f is white") @ConfigComment("Example: &c will make lore red. &f is white")
@ConfigEntry(path = "lore-format") @ConfigEntry(path = "lore-format")
private String loreFormat = "&f"; private String loreFormat = "&f";
@ConfigComment("")
@ConfigComment("Allow random teleport - adds a button to the warp panel that goes to a random warp sign")
@ConfigEntry(path = "random-allowed")
private boolean randomAllowed = true;
@ConfigComment("") @ConfigComment("")
@ConfigComment("Allow use in other worlds. Players must have the welcomewarpsigns.warp permission.") @ConfigComment("Allow use in other worlds. Players must have the welcomewarpsigns.warp permission.")
@ConfigEntry(path = "allow-in-other-worlds") @ConfigEntry(path = "allow-in-other-worlds")
@ -74,7 +62,6 @@ public class Settings implements ConfigObject
@ConfigEntry(path = "warps-command") @ConfigEntry(path = "warps-command")
String warpsCommand = "warps"; String warpsCommand = "warps";
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Section: Constructor // Section: Constructor
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -155,42 +142,6 @@ public class Settings implements ConfigObject
} }
/**
* This method returns the icon object.
* @return the icon object.
*/
public String getIcon()
{
return icon;
}
/**
* This method sets the icon object value.
* @param icon the icon object new value.
*/
public void setIcon(String icon)
{
this.icon = icon;
}
/**
* @return the nameFormat
*/
public String getNameFormat() {
return nameFormat;
}
/**
* @param nameFormat the nameFormat to set
*/
public void setNameFormat(String nameFormat) {
this.nameFormat = nameFormat;
}
/** /**
* @return the loreFormat * @return the loreFormat
*/ */
@ -207,22 +158,6 @@ public class Settings implements ConfigObject
} }
/**
* @return the randomAllowed
*/
public boolean isRandomAllowed() {
return randomAllowed;
}
/**
* @param randomAllowed the randomAllowed to set
*/
public void setRandomAllowed(boolean randomAllowed) {
this.randomAllowed = randomAllowed;
}
/** /**
* @return the allowInOtherWorlds * @return the allowInOtherWorlds
*/ */
@ -270,5 +205,17 @@ public class Settings implements ConfigObject
this.warpsCommand = 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

@ -18,13 +18,13 @@ import world.bentobox.warps.Warp;
public class WarpCreateEvent extends Event{ public class WarpCreateEvent extends Event{
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private Location warpLoc; private final Location warpLoc;
private UUID creator; private final UUID creator;
/** /**
* @param plugin - BSkyBlock plugin objects * @param plugin - BSkyBlock plugin objects
* @param warpLoc * @param warpLoc warp location
* @param creator * @param creator UUID of creator
*/ */
public WarpCreateEvent(Warp plugin, Location warpLoc, UUID creator){ public WarpCreateEvent(Warp plugin, Location warpLoc, UUID creator){
this.warpLoc = warpLoc; this.warpLoc = warpLoc;

View File

@ -40,7 +40,7 @@ public class WarpInitiateEvent extends Event implements Cancellable {
/** /**
* Set a different location to where the player will go * Set a different location to where the player will go
* @param warpLoc * @param warpLoc warp location
*/ */
public void setWarpLoc(Location warpLoc) { public void setWarpLoc(Location warpLoc) {
this.warpLoc = warpLoc; this.warpLoc = warpLoc;

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 world.bentobox.warps.event;
import java.util.List;
import java.util.UUID;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import world.bentobox.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 objects
* @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

@ -5,8 +5,8 @@ import java.util.UUID;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.warps.Warp; import org.eclipse.jdt.annotation.Nullable;
/** /**
* This event is fired when a Warp is removed (when a warp sign is broken) * This event is fired when a Warp is removed (when a warp sign is broken)
@ -18,32 +18,48 @@ import world.bentobox.warps.Warp;
public class WarpRemoveEvent extends Event{ public class WarpRemoveEvent extends Event{
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private Location warpLoc; private final Location warpLoc;
private UUID remover; private final UUID remover;
private final UUID owner;
/** /**
* @param plugin - BSkyBlock plugin objects * @param warpLoc - Warp location
* @param warpLoc * @param remover - UUID of remover
* @param 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.warpLoc = warpLoc;
this.remover = remover; this.remover = remover;
this.owner = owner;
} }
/** /**
* Get the location of the removed Warp * Get the location of the removed Warp
* @return removed warp's location * @return removed warp's location
*/ */
public Location getWarpLocation(){return this.warpLoc;} @NonNull
public Location getWarpLocation(){
return this.warpLoc;
}
/** /**
* Get who has removed the warp * Get who has removed the warp
* @return the warp's remover * @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() { public HandlerList getHandlers() {
return handlers; return handlers;
} }

View File

@ -1,11 +1,12 @@
package world.bentobox.warps.listeners; package world.bentobox.warps.listeners;
import java.util.Map; import java.util.*;
import java.util.UUID; import java.util.stream.Collectors;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Tag;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.Sign; import org.bukkit.block.Sign;
@ -15,11 +16,17 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.SignChangeEvent; 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.BentoBox;
import world.bentobox.bentobox.api.events.team.TeamEvent.TeamKickEvent; import world.bentobox.bentobox.api.events.addon.AddonEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent.TeamLeaveEvent; 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.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.Util; import world.bentobox.bentobox.util.Util;
import world.bentobox.warps.Warp; import world.bentobox.warps.Warp;
import world.bentobox.warps.event.WarpRemoveEvent; import world.bentobox.warps.event.WarpRemoveEvent;
@ -32,9 +39,11 @@ import world.bentobox.warps.event.WarpRemoveEvent;
*/ */
public class WarpSignsListener implements Listener { public class WarpSignsListener implements Listener {
private BentoBox plugin; private static final String WARPS_DEACTIVATE = "warps.deactivate";
private Warp addon; private final BentoBox plugin;
private final Warp addon;
/** /**
* @param addon - addon * @param addon - addon
@ -44,20 +53,49 @@ public class WarpSignsListener implements Listener {
this.plugin = addon.getPlugin(); 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) @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPlayerLeave(TeamLeaveEvent e) { public void onPlayerLeave(TeamLeaveEvent e) {
// Remove any warp signs from this game mode // Remove any warp signs from this game mode
addon.getWarpSignsManager().removeWarp(e.getIsland().getWorld(), e.getPlayerUUID()); addon.getWarpSignsManager().removeWarp(e.getIsland().getWorld(), e.getPlayerUUID());
User.getInstance(e.getPlayerUUID()).sendMessage("warps.deactivate"); Objects.requireNonNull(User.getInstance(e.getPlayerUUID())).sendMessage(WARPS_DEACTIVATE);
} }
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPlayerLeave(TeamKickEvent e) { public void onPlayerLeave(TeamKickEvent e) {
// Remove any warp signs from this game mode // Remove any warp signs from this game mode
addon.getWarpSignsManager().removeWarp(e.getIsland().getWorld(), e.getPlayerUUID()); addon.getWarpSignsManager().removeWarp(e.getIsland().getWorld(), e.getPlayerUUID());
User.getInstance(e.getPlayerUUID()).sendMessage("warps.deactivate"); Objects.requireNonNull(User.getInstance(e.getPlayerUUID())).sendMessage(WARPS_DEACTIVATE);
} }
/** /**
* Checks to see if a sign has been broken * Checks to see if a sign has been broken
* @param e - event * @param e - event
@ -68,21 +106,21 @@ public class WarpSignsListener implements Listener {
boolean inWorld = addon.getPlugin().getIWM().inWorld(b.getWorld()); boolean inWorld = addon.getPlugin().getIWM().inWorld(b.getWorld());
// Signs only // Signs only
// FIXME: When we drop support for 1.13, switch to Tag.SIGNS // FIXME: When we drop support for 1.13, switch to Tag.SIGNS
if (!e.getBlock().getType().name().contains("SIGN") if (!b.getType().name().contains("SIGN")
|| (inWorld && !addon.inRegisteredWorld(b.getWorld())) || (inWorld && !addon.inRegisteredWorld(b.getWorld()))
|| (!inWorld && !addon.getSettings().isAllowInOtherWorlds()) ) { || (!inWorld && !addon.getSettings().isAllowInOtherWorlds())
|| !isWarpSign(b)) {
return; return;
} }
User user = User.getInstance(e.getPlayer()); User user = User.getInstance(e.getPlayer());
if (isWarpSign(b)) { UUID owner = addon.getWarpSignsManager().getWarpOwnerUUID(b.getLocation()).orElse(null);
if (isPlayersSign(e.getPlayer(), b, inWorld)) { if (isPlayersSign(e.getPlayer(), b, inWorld)) {
addon.getWarpSignsManager().removeWarp(b.getLocation()); addon.getWarpSignsManager().removeWarp(b.getLocation());
Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(addon, b.getLocation(), user.getUniqueId())); Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(b.getLocation(), user.getUniqueId(), owner));
} else { } else {
// Someone else's sign - not allowed // Someone else's sign - not allowed
user.sendMessage("warps.error.no-remove"); user.sendMessage("warps.error.no-remove");
e.setCancelled(true); e.setCancelled(true);
}
} }
} }
@ -113,9 +151,9 @@ public class WarpSignsListener implements Listener {
return; return;
} }
String title = e.getLine(0); String title = e.getLine(0);
User user = User.getInstance(e.getPlayer()); User user = Objects.requireNonNull(User.getInstance(e.getPlayer()));
// Check if someone is changing their own sign // Check if someone is changing their own sign
if (title.equalsIgnoreCase(addon.getSettings().getWelcomeLine())) { if (title != null && title.equalsIgnoreCase(addon.getSettings().getWelcomeLine())) {
// Welcome sign detected - check permissions // Welcome sign detected - check permissions
if (noPerms(user, b.getWorld(), inWorld)) { if (noPerms(user, b.getWorld(), inWorld)) {
return; return;
@ -124,13 +162,16 @@ public class WarpSignsListener implements Listener {
e.setLine(0, ChatColor.RED + addon.getSettings().getWelcomeLine()); e.setLine(0, ChatColor.RED + addon.getSettings().getWelcomeLine());
return; 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 // Check if the player already has a sign
final Location oldSignLoc = addon.getWarpSignsManager().getWarp(b.getWorld(), user.getUniqueId()); final Location oldSignLoc = addon.getWarpSignsManager().getWarp(b.getWorld(), user.getUniqueId());
if (oldSignLoc == null) { 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 // A sign already exists. Check if it still there and if
// so, // so,
// deactivate it // deactivate it
@ -142,18 +183,60 @@ public class WarpSignsListener implements Listener {
if (oldSign.getLine(0).equalsIgnoreCase(ChatColor.GREEN + addon.getSettings().getWelcomeLine())) { if (oldSign.getLine(0).equalsIgnoreCase(ChatColor.GREEN + addon.getSettings().getWelcomeLine())) {
oldSign.setLine(0, ChatColor.RED + addon.getSettings().getWelcomeLine()); oldSign.setLine(0, ChatColor.RED + addon.getSettings().getWelcomeLine());
oldSign.update(true, false); oldSign.update(true, false);
user.sendMessage("warps.deactivate"); user.sendMessage(WARPS_DEACTIVATE);
addon.getWarpSignsManager().removeWarp(oldSignBlock.getWorld(), user.getUniqueId()); addon.getWarpSignsManager().removeWarp(oldSignBlock.getWorld(), user.getUniqueId());
Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(addon, oldSign.getLocation(), 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 // Set up the new warp sign
addSign(e, user, b);
} }
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) { private boolean noLevelOrIsland(User user, World world) {
// Get level if level addon is available // Get level if level addon is available
Long level = addon.getLevel(Util.getWorld(world), user.getUniqueId()); Long level = addon.getLevel(Util.getWorld(world), user.getUniqueId());
@ -195,8 +278,18 @@ public class WarpSignsListener implements Listener {
user.sendMessage("warps.success"); user.sendMessage("warps.success");
e.setLine(0, ChatColor.GREEN + addon.getSettings().getWelcomeLine()); e.setLine(0, ChatColor.GREEN + addon.getSettings().getWelcomeLine());
for (int i = 1; i<4; i++) { for (int i = 1; i<4; i++) {
e.setLine(i, ChatColor.translateAlternateColorCodes('&', e.getLine(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 // Else null player
} }

View File

@ -1,4 +1,4 @@
package world.bentobox.warps; package world.bentobox.warps.managers;
import java.util.List; import java.util.List;
@ -12,18 +12,28 @@ import com.google.gson.annotations.Expose;
* *
*/ */
public class SignCacheItem { public class SignCacheItem {
@Expose @Expose
private final List<String> signText; private final List<String> signText;
@Expose @Expose
private final Material type; private final Material type;
/** /**
* @param signText * @param signText sign text
* @param type * @param type material of sign
*/ */
public SignCacheItem(List<String> signText, Material type) { public SignCacheItem(List<String> signText, Material type) {
this.signText = signText; this.signText = signText;
this.type = type; this.type = type;
} }
/**
* This sign is not real
*/
public SignCacheItem() {
this.signText = null;
this.type = null;
}
/** /**
* @return the signText * @return the signText
*/ */
@ -36,5 +46,12 @@ public class SignCacheItem {
public Material getType() { public Material getType() {
return type; 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

@ -1,18 +1,19 @@
package world.bentobox.warps; package world.bentobox.warps.managers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -20,11 +21,12 @@ import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.Tag;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign; import org.bukkit.block.Sign;
import org.bukkit.permissions.PermissionAttachmentInfo; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
@ -35,9 +37,11 @@ import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.lists.Flags; import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.util.Util; import world.bentobox.bentobox.util.Util;
import world.bentobox.warps.Warp;
import world.bentobox.warps.event.WarpInitiateEvent; import world.bentobox.warps.event.WarpInitiateEvent;
import world.bentobox.warps.event.WarpListEvent;
import world.bentobox.warps.objects.WarpsData; import world.bentobox.warps.objects.WarpsData;
import world.bentobox.warps.panels.Utils;
/** /**
* Handles warping. Players can add one sign * Handles warping. Players can add one sign
@ -48,13 +52,13 @@ import world.bentobox.warps.objects.WarpsData;
public class WarpSignsManager { public class WarpSignsManager {
private static final int MAX_WARPS = 600; private static final int MAX_WARPS = 600;
private static final String WARPS = "warps"; private static final String WARPS = "warps";
private BentoBox plugin; private final BentoBox plugin;
// Map of all warps stored as player, warp sign Location // Map of all warps stored as player, warp sign Location
private Map<World, Map<UUID, Location>> worldsWarpList; private Map<World, Map<UUID, Location>> worldsWarpList;
// Database handler for level data // Database handler for level data
private Database<WarpsData> handler; private final Database<WarpsData> handler;
private Warp addon; private final Warp addon;
private WarpsData warpsData = new WarpsData(); private WarpsData warpsData = new WarpsData();
/** /**
@ -74,6 +78,7 @@ public class WarpSignsManager {
public WarpSignsManager(Warp addon, BentoBox plugin) { public WarpSignsManager(Warp addon, BentoBox plugin) {
this.addon = addon; this.addon = addon;
this.plugin = plugin; this.plugin = plugin;
this.worldsWarpList = new HashMap<>();
// Set up the database handler // Set up the database handler
// Note that these are saved by the BentoBox database // Note that these are saved by the BentoBox database
handler = new Database<>(addon, WarpsData.class); handler = new Database<>(addon, WarpsData.class);
@ -128,18 +133,32 @@ public class WarpSignsManager {
.findFirst().map(en -> plugin.getPlayers().getName(en.getKey())).orElse(""); .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 * Get sorted list of warps with most recent players listed first
* @return UUID list * @return UUID list
*/ */
@NonNull public CompletableFuture<List<UUID>> getSortedWarps(@NonNull World world) {
public 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 // 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); getWarpMap(world).values().removeIf(Objects::isNull);
// Bigger value of time means a more recent login // Bigger value of time means a more recent login
TreeMap<Long, UUID> map = new TreeMap<>(); TreeMap<Long, UUID> map = new TreeMap<>();
getWarpMap(world).entrySet().forEach(en -> { getWarpMap(world).forEach((uuid, value) -> {
UUID uuid = en.getKey();
// If never played, will be zero // If never played, will be zero
long lastPlayed = addon.getServer().getOfflinePlayer(uuid).getLastPlayed(); long lastPlayed = addon.getServer().getOfflinePlayer(uuid).getLastPlayed();
// This aims to avoid the chance that players logged off at exactly the same time // This aims to avoid the chance that players logged off at exactly the same time
@ -153,11 +172,8 @@ public class WarpSignsManager {
if (list.size() > MAX_WARPS) { if (list.size() > MAX_WARPS) {
list.subList(0, MAX_WARPS).clear(); list.subList(0, MAX_WARPS).clear();
} }
// Fire event // Return to main thread
WarpListEvent event = new WarpListEvent(addon, list); Bukkit.getScheduler().runTask(plugin, () -> r.complete(list));
Bukkit.getPluginManager().callEvent(event);
// Get the result of any changes by listeners
list = event.getWarps();
return list; return list;
} }
@ -171,23 +187,28 @@ public class WarpSignsManager {
public Set<UUID> listWarps(@NonNull World world) { public Set<UUID> listWarps(@NonNull World world) {
// Remove any null locations // Remove any null locations
getWarpMap(world).values().removeIf(Objects::isNull); 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()); 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 * Load the warps and check if they still exist
*/ */
void loadWarpList() { public void loadWarpList() {
addon.log("Loading warps..."); addon.log("Loading warps...");
worldsWarpList = new HashMap<>(); worldsWarpList = new HashMap<>();
if (handler.objectExists(WARPS)) { if (handler.objectExists(WARPS)) {
warpsData = handler.loadObject(WARPS); warpsData = handler.loadObject(WARPS);
// Load into map // Load into map
if (warpsData != null) { if (warpsData != null) {
warpsData.getWarpSigns().forEach((k,v) -> { warpsData.getWarpSigns().forEach((location,uuid) -> {
if (k != null && k.getWorld() != null && k.getBlock().getType().name().contains("SIGN")) { 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 // Add to map
getWarpMap(k.getWorld()).put(v, k); getWarpMap(location.getWorld()).put(uuid, location);
} }
}); });
} else { } else {
@ -198,7 +219,7 @@ public class WarpSignsManager {
/** /**
* Changes the sign to red if it exists * Changes the sign to red if it exists
* @param loc * @param loc location to pop
*/ */
private void popSign(Location loc) { private void popSign(Location loc) {
Block b = loc.getBlock(); Block b = loc.getBlock();
@ -214,7 +235,7 @@ public class WarpSignsManager {
/** /**
* Removes a warp at a location. * Removes a warp at a location.
* *
* @param loc * @param loc location to remove
*/ */
public void removeWarp(Location loc) { public void removeWarp(Location loc) {
popSign(loc); popSign(loc);
@ -223,13 +244,11 @@ public class WarpSignsManager {
Entry<UUID, Location> en = it.next(); Entry<UUID, Location> en = it.next();
if (en.getValue().equals(loc)) { if (en.getValue().equals(loc)) {
// Inform player // Inform player
User user = User.getInstance(addon.getServer().getPlayer(en.getKey())); Optional.ofNullable(addon.getServer().getPlayer(en.getKey()))
if (user != null) { .map(User::getInstance)
// Inform the player .ifPresent(user -> user.sendMessage("warps.sign-removed"));
user.sendMessage("warps.sign-removed");
}
// Remove sign from warp panel cache // Remove sign from warp panel cache
addon.getWarpPanelManager().removeWarp(loc.getWorld(), en.getKey()); addon.getSignCacheManager().removeWarp(loc.getWorld(), en.getKey());
it.remove(); it.remove();
} }
} }
@ -239,23 +258,34 @@ public class WarpSignsManager {
/** /**
* Remove warp sign owned by UUID * Remove warp sign owned by UUID
* *
* @param uuid * @param uuid UUID of owner to remove
*/ */
public void removeWarp(World world, UUID uuid) { public void removeWarp(World world, UUID uuid) {
if (getWarpMap(world).containsKey(uuid)) { if (getWarpMap(world).containsKey(uuid)) {
popSign(getWarpMap(world).get(uuid)); popSign(getWarpMap(world).get(uuid));
getWarpMap(world).remove(uuid); getWarpMap(world).remove(uuid);
// Remove sign from warp panel cache
addon.getWarpPanelManager().removeWarp(world, uuid);
} }
// Remove sign from warp panel cache
addon.getSignCacheManager().removeWarp(world, uuid);
saveWarpList(); 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 * Saves the warp lists to the database
*/ */
public void saveWarpList() { public void saveWarpList() {
handler.saveObject(warpsData .save(worldsWarpList)); handler.saveObjectAsync(warpsData.save(worldsWarpList));
addon.getSignCacheManager().saveCache();
} }
/** /**
@ -267,47 +297,44 @@ public class WarpSignsManager {
*/ */
@NonNull @NonNull
public SignCacheItem getSignInfo(@NonNull World world, @NonNull UUID uuid) { public SignCacheItem getSignInfo(@NonNull World world, @NonNull UUID uuid) {
List<String> result = new ArrayList<>();
//get the sign info //get the sign info
Location signLocation = getWarp(world, uuid); Location signLocation = getWarp(world, uuid);
if (signLocation != null && signLocation.getBlock().getType().name().contains("SIGN")) { if (signLocation == null || !signLocation.getBlock().getType().name().contains("SIGN")) {
Sign sign = (Sign)signLocation.getBlock().getState(); return new SignCacheItem();
result.addAll(Arrays.asList(sign.getLines())); }
// Clean up - remove the [WELCOME] line Sign sign = (Sign)signLocation.getBlock().getState();
result.remove(0); List<String> result = new ArrayList<>(Arrays.asList(sign.getLines()));
// Remove any trailing blank lines // Clean up - remove the [WELCOME] line
result.removeIf(String::isEmpty); result.remove(0);
// Set the initial color per lore setting // Remove any trailing blank lines
for (int i = 0; i< result.size(); i++) { result.removeIf(String::isEmpty);
result.set(i, ChatColor.translateAlternateColorCodes('&', addon.getSettings().getLoreFormat()) + result.get(i)); // Set the initial color per lore setting
} for (int i = 0; i< result.size(); i++) {
// Get the sign type result.set(i, ChatColor.translateAlternateColorCodes('&', addon.getSettings().getLoreFormat()) + result.get(i));
}
String prefix = plugin.getIWM().getAddon(world).map(Addon::getPermissionPrefix).orElse(""); // Get the sign type
String prefix = plugin.getIWM().getAddon(world).map(Addon::getPermissionPrefix).orElse("");
Material icon;
Material icon;
if (!prefix.isEmpty())
{ if (!prefix.isEmpty())
icon = Material.matchMaterial( {
this.getPermissionValue(User.getInstance(uuid), icon = Material.matchMaterial(
prefix + "island.warp", Utils.getPermissionValue(User.getInstance(uuid), prefix + "island.warp",
this.addon.getSettings().getIcon())); Material.OAK_SIGN.name()));
} }
else else
{ {
icon = Material.matchMaterial(this.addon.getSettings().getIcon()); icon = null;
} }
if (icon == null || icon.name().contains("SIGN")) { if (icon != null && icon.name().contains("SIGN")) {
return new SignCacheItem(result, Material.valueOf(sign.getType().name().replace("WALL_", ""))); return new SignCacheItem(result, Material.valueOf(sign.getType().name().replace("WALL_", "")));
} else { }
return new SignCacheItem(result, icon); else
} {
} else { return new SignCacheItem(result, icon);
addon.getWarpSignsManager().removeWarp(world, uuid);
} }
return new SignCacheItem(Collections.emptyList(), Material.AIR);
} }
/** /**
@ -323,21 +350,37 @@ public class WarpSignsManager {
float yaw = Util.blockFaceToFloat(directionFacing); float yaw = Util.blockFaceToFloat(directionFacing);
final Location actualWarp = new Location(inFront.getWorld(), inFront.getBlockX() + 0.5D, inFront.getBlockY(), final Location actualWarp = new Location(inFront.getWorld(), inFront.getBlockX() + 0.5D, inFront.getBlockY(),
inFront.getBlockZ() + 0.5D, yaw, 30F); inFront.getBlockZ() + 0.5D, yaw, 30F);
user.teleport(actualWarp); //BentoBox prevents people from teleporting to an island when
if (pvp) { //the user is banned from the island for example.
user.sendMessage("protection.flags.PVP_OVERWORLD.active"); //By checking if the teleport succeeded before sending the messages,
user.getWorld().playSound(user.getLocation(), Sound.ENTITY_ARROW_HIT, 1F, 1F); //we prevent issues where no one teleported, but people still
} else { //get messages about it.
user.getWorld().playSound(user.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F); Util.teleportAsync(user.getPlayer(), actualWarp, TeleportCause.COMMAND).thenAccept(tpResult -> {
} if(Boolean.FALSE.equals(tpResult)) return;
User warpOwner = User.getInstance(signOwner);
if (!warpOwner.equals(user)) { User warpOwner = Objects.requireNonNull(User.getInstance(signOwner));
warpOwner.sendMessage("warps.player-warped", "[name]", user.getName()); // 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 owner by owner * Warps a user to the warp owned by owner
* *
* @param world - world to check * @param world - world to check
* @param user - user who is warping * @param user - user who is warping
@ -364,7 +407,7 @@ public class WarpSignsManager {
boolean pvp = false; boolean pvp = false;
if (island != null) { if (island != null) {
// Check for PVP // Check for PVP
switch (warpSpot.getWorld().getEnvironment()) { switch (Objects.requireNonNull(warpSpot.getWorld()).getEnvironment()) {
case NETHER: case NETHER:
pvp = island.isAllowed(Flags.PVP_NETHER); pvp = island.isAllowed(Flags.PVP_NETHER);
break; break;
@ -381,7 +424,7 @@ public class WarpSignsManager {
} }
// Find out which direction the warp is facing // Find out which direction the warp is facing
Block b = warpSpot.getBlock(); Block b = warpSpot.getBlock();
if (b.getType().name().contains("WALL_SIGN")) { if (Tag.WALL_SIGNS.isTagged(b.getType())) {
org.bukkit.block.data.type.WallSign s = (org.bukkit.block.data.type.WallSign) b.getBlockData(); org.bukkit.block.data.type.WallSign s = (org.bukkit.block.data.type.WallSign) b.getBlockData();
BlockFace directionFacing = s.getFacing(); BlockFace directionFacing = s.getFacing();
Location inFront = b.getRelative(directionFacing).getLocation(); Location inFront = b.getRelative(directionFacing).getLocation();
@ -394,7 +437,13 @@ public class WarpSignsManager {
warpPlayer(user, oneDown, owner, directionFacing, pvp); warpPlayer(user, oneDown, owner, directionFacing, pvp);
return; return;
} }
} else if (b.getType().name().contains("SIGN")) { } 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(); org.bukkit.block.data.type.Sign s = (org.bukkit.block.data.type.Sign) b.getBlockData();
BlockFace directionFacing = s.getRotation(); BlockFace directionFacing = s.getRotation();
Location inFront = b.getRelative(directionFacing).getLocation(); Location inFront = b.getRelative(directionFacing).getLocation();
@ -414,12 +463,12 @@ public class WarpSignsManager {
final Location actualWarp = new Location(warpSpot.getWorld(), warpSpot.getBlockX() + 0.5D, warpSpot.getBlockY(), final Location actualWarp = new Location(warpSpot.getWorld(), warpSpot.getBlockX() + 0.5D, warpSpot.getBlockY(),
warpSpot.getBlockZ() + 0.5D); warpSpot.getBlockZ() + 0.5D);
if (pvp) { if (pvp) {
user.sendMessage("protection.flags.PVP_OVERWORLD.active"); user.sendMessage("protection.flags.PVP_OVERWORLD.enabled");
user.getWorld().playSound(user.getLocation(), Sound.ENTITY_ARROW_HIT, 1F, 1F); user.getWorld().playSound(Objects.requireNonNull(user.getLocation()), Sound.ENTITY_ARROW_HIT, 1F, 1F);
} else { } else {
user.getWorld().playSound(user.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F); user.getWorld().playSound(Objects.requireNonNull(user.getLocation()), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F);
} }
user.teleport(actualWarp); Util.teleportAsync(user.getPlayer(), actualWarp, TeleportCause.COMMAND);
} }
} }
@ -431,54 +480,4 @@ public class WarpSignsManager {
public boolean hasWarp(@NonNull World world, @NonNull UUID playerUUID) { public boolean hasWarp(@NonNull World world, @NonNull UUID playerUUID) {
return getWarpMap(world).containsKey(playerUUID); return getWarpMap(world).containsKey(playerUUID);
} }
// ---------------------------------------------------------------------
// Section: Other methods
// ---------------------------------------------------------------------
/**
* 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.
*/
private String getPermissionValue(@NonNull User user, @NonNull String permissionPrefix, @NonNull 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

@ -9,8 +9,10 @@ import org.bukkit.World;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import world.bentobox.bentobox.database.objects.DataObject; import world.bentobox.bentobox.database.objects.DataObject;
import world.bentobox.warps.SignCacheItem; import world.bentobox.bentobox.database.objects.Table;
import world.bentobox.warps.managers.SignCacheItem;
@Table(name = "WarpSignCache")
public class SignCache implements DataObject { public class SignCache implements DataObject {
@Expose @Expose

View File

@ -10,7 +10,9 @@ import org.bukkit.World;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import world.bentobox.bentobox.database.objects.DataObject; import world.bentobox.bentobox.database.objects.DataObject;
import world.bentobox.bentobox.database.objects.Table;
@Table(name = "WarpsData")
public class WarpsData implements DataObject { public class WarpsData implements DataObject {
@Expose @Expose
@ -44,10 +46,11 @@ public class WarpsData implements DataObject {
/** /**
* Puts all the data from the map into this objects ready for saving * Puts all the data from the map into this objects ready for saving
* @param worldsWarpList * @param worldsWarpList 2D map of warp locations by world vs UUID
* @return this class filled with data * @return this class filled with data
*/ */
public WarpsData save(Map<World, Map<UUID, Location>> worldsWarpList) { public WarpsData save(Map<World, Map<UUID, Location>> worldsWarpList) {
getWarpSigns().clear();
worldsWarpList.values().forEach(world -> world.forEach((uuid,location) -> warpSigns.put(location, uuid))); worldsWarpList.values().forEach(world -> world.forEach((uuid,location) -> warpSigns.put(location, uuid)));
return this; 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

@ -2,43 +2,19 @@ name: Warps
main: world.bentobox.warps.Warp main: world.bentobox.warps.Warp
version: ${version}${build.number} version: ${version}${build.number}
icon: OAK_SIGN icon: OAK_SIGN
api-version: 1.17
authors: tastybento authors: tastybento
softdepend: AcidIsland, BSkyBlock, CaveBlock, SkyGrid, AOneBlock softdepend: AcidIsland, BSkyBlock, CaveBlock, SkyGrid, AOneBlock
permissions: permissions:
bskyblock.island.warp: '[gamemode].island.warp':
description: Player can use warp or warps commands description: Player can use warp command
default: true default: true
bskyblock.island.addwarp: '[gamemode].island.warps':
description: Player can create a welcome warp sign description: Player can use the warps command
default: true default: true
'[gamemode].island.addwarp':
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
caveblock.island.warp:
description: Player can use warp or warps commands
default: true
caveblock.island.addwarp:
description: Player can create a welcome warp sign
default: true
skygrid.island.warp:
description: Player can use warp or warps commands
default: true
skygrid.island.addwarp:
description: Player can create a welcome warp sign
default: true
aoneblock.island.warp:
description: Player can use warp or warps commands
default: true
aoneblock.island.addwarp:
description: Player can create a welcome warp sign description: Player can create a welcome warp sign
default: true default: true

View File

@ -7,33 +7,25 @@
# Warp Restriction - needed levels to be able to create a warp # 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 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 # Text that player must put on sign to make it a warp sign
# Not case sensitive! # Not case sensitive!
welcomeLine: '[Welcome]' welcomeLine: '[Welcome]'
# #
# 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.
icon: 'SIGN'
#
# This list stores GameModes in which Level addon should not work. # 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: # To disable addon it is necessary to write its name in new line that starts with -. Example:
# disabled-gamemodes: # disabled-gamemodes:
# - BSkyBlock # - BSkyBlock
disabled-gamemodes: [] disabled-gamemodes: []
# #
# Warp panel name formatting.
# Example: &c will make names red, &f is white
name-format: &f
#
# Warp panel default lore formatting. # Warp panel default lore formatting.
# Example: &c will make lore red. &f is white # Example: &c will make lore red. &f is white
lore-format: &f lore-format: "&f"
#
# Allow random teleport - adds a button to the warp panel that goes to a random warp sign
random-allowed: true
# #
# Allow use in other worlds. Players must have the welcomewarpsigns.warp permission. # Allow use in other worlds. Players must have the welcomewarpsigns.warp permission.
allow-in-other-worlds: false allow-in-other-worlds: false

View File

@ -1,30 +1,46 @@
# ---
# 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: warp:
help: help:
description: Warpt dich zu dem Warp Schild von dem Spieler description: Warpt dich zu dem Warp Schild von dem Spieler
parameters: <Spielername> parameters: "<player name>"
warps: warps:
deactivate: '&c Altes Warp Schild deaktiviert!' deactivate: "&c Altes Warp Schild deaktiviert!"
error: error:
does-not-exist: '&c Oh nein! Dieser Warp existiert nicht mehr!' does-not-exist: "&c Oh nein! Dieser Warp existiert nicht mehr!"
no-permission: '&c Hierfür hast du keine Rechte!' no-permission: "&c Hierfür hast du keine Rechte!"
no-remove: '&c Du kannst dieses Schild nicht entfernen!' no-remove: "&c Du kannst dieses Schild nicht entfernen!"
no-warps-yet: '&c Es sind noch keine Warps verfügbar' no-warps-yet: "&c Es sind noch keine Warps verfügbar"
not-enough-level: '&c Dein Insel-Level ist nicht hoch gneug!' not-enough-level: "&c Dein Insel-Level ist nicht hoch gneug!"
not-on-island: '&c Dafür musst du auf deiner Insel sein!' not-on-island: "&c Dafür musst du auf deiner Insel sein!"
not-safe: '&c Dieser Warp ist nicht sicher!' 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. your-level-is: "&c Dein Insel-Level ist erst [level] und muss höher als [required]
Nutze das Level Kommando.' sein. Nutze das Level Kommando."
help: help:
description: Öffnet das Warps Panel description: Öffnet das Warps Panel
next: '&6 Nächste Seite' player-warped: "&2 [name] hat sich zu deinem Warp Schild gewarpt!"
player-warped: '&2 [name] hat sich zu deinem Warp Schild gewarpt!' sign-removed: "&c Warp Schild entfernt!"
previous: '&6 Vorherige Seite' success: "&a Erfolg!"
random: '&4 Zufälliger Warp' warpTip: "&6 Platziere ein Warp Schild mit [text] in der ersten Zeile"
sign-removed: '&c Warp Schild entfernt!' warpToPlayersSign: "&6 Warpe zu [player]'s Schild"
success: '&a Erfolg!' gui:
title: Warp Schilder titles:
warpTip: '&6 Platziere ein Warp Schild mit [text] in der ersten Zeile' warp-title: "&0&l Warp-Schild"
warpToPlayersSign: '&6 Warpe zu [player]''s 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

@ -17,17 +17,51 @@ warps:
not-enough-level: "&c Your island level is not high enough!" 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-on-island: "&c You must be on your island to do that!"
not-safe: "&c That warp is not safe!" not-safe: "&c That warp is not safe!"
your-level-is: "&c You island level is only [level] and must be higher than [required]. Run the level command." your-level-is: "&c Your island level is only [level] and must be higher than [required]. Run the level command."
help: not-correct-rank: "&c You do not have the correct rank to set a warp!"
help:
description: "open the warps panel" description: "open the warps panel"
next: "&6 Next page" player-warped: "&2 [name] warped to your [gamemode] warp sign!"
player-warped: "&2 [name] warped to your warp sign!"
previous: "&6 Previous page"
random: "&4 Random Warp"
sign-removed: "&c Warp sign removed!" sign-removed: "&c Warp sign removed!"
success: "&a Success!" success: "&a Success!"
title: "Warp Signs"
warpTip: "&6 Place a warp sign with [text] on the top" warpTip: "&6 Place a warp sign with [text] on the top"
warpToPlayersSign: "&6 Warping to [player]'s sign" 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

@ -1,30 +1,53 @@
########################################################################################################### ---
# Este es un archivo YML. Tenga cuidado al editar. Revisa tus ediciones en un verificador de YAML como # warp:
# el de http://yaml-online-parser.appspot.com # help:
########################################################################################################### description: Teletransportarte hacia el warp del jugador
parameters: "<player name>"
warp: warps:
help: deactivate: "&c ¡Antiguo cartel de teletransportación desactivado!"
description: "Teletransportarte hacia el warp del jugador" error:
parameters: <name> does-not-exist: "&c ¡Oh, chasquido! ¡Ese teletransporte ya no existe!"
warps: no-permission: "&c ¡No tienes permisos para hacer eso!"
deactivate: "&cViejo cartel a sido desactivado!" no-remove: "&c ¡No puedes quitar ese cartel!"
error: no-warps-yet: "&c No hay teletransportes disponibles todavía"
does-not-exist: "&cOh snap! Ese warp ya no existe!" not-enough-level: "&c ¡Tu nivel de isla no es lo suficientemente alto!"
no-permission: "&CNo tienes permiso para hacer eso!" not-on-island: "&c ¡Debes estar en tu isla para hacer eso!"
no-remove: "&CNo puedes quitar ese cartel!" not-safe: "&c ¡Ese teletransporte no es seguro!"
no-warps-yet: "&CNo hay warps disponibles aun" your-level-is: "&c Tu nivel de isla es solo [level] y debe ser mayor que [required].
not-enough-level: "&CTu nivel de isla no es lo suficientemente alto!" Ejecuta el comando de nivel."
not-on-island: "&CDebes estar en tu isla para hacer eso!" not-correct-rank: "&c ¡No tienes el rango correcto para crear un teletransporte!"
not-safe: "&cEse warp no es seguro!" help:
your-level-is: "&cTu nivel de isla es solo [level] y debe ser mayor que [required]" description: Abre el panel de warps
help: player-warped: "&2 [name] se ha teletransportado a tu cartel de teletransportación
description: "Abre el panel de warps" de [gamemode]!"
next: "&6Siguiente página" sign-removed: "&c Cartel de teletransportación eliminado!"
player-warped: "&2[name] teletransportarte a tu warp!" success: "&a Éxito!"
previous: "&6Pagina anterior" warpTip: "&6 Coloca un cartel con [text] en la parte superior"
sign-removed: "&CCartel removido!" warpToPlayersSign: "&6 Teletransportandote al cartel del jugador [player]"
success: "&AExito!" gui:
title: "Carteles de Warps" titles:
warpTip: "&6Coloca un cartel con este texto [text] arriba" warp-title: "&0&l Carteles de Teletransporte"
warpToPlayersSign: "&6Teletransportandote al warp de [player]" 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

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

View File

@ -1,15 +1,11 @@
########################################################################################### ---
# This is a YML file. Be careful when editing. Check your edits in a YAML checker like # warp:
# the one at http://yaml-online-parser.appspot.com # help:
########################################################################################### description: Teleportálás a játékos teleport táblájához
parameters: "<játékosnév>"
warp: warps:
help:
description: "Teleportálás a játékos teleport táblájához"
parameters: <player name>
warps:
deactivate: "&cRégi teleport tábla deaktiválva!" deactivate: "&cRégi teleport tábla deaktiválva!"
error: error:
does-not-exist: "&cAjjaj! Ez a teleport nem létezik!" does-not-exist: "&cAjjaj! Ez a teleport nem létezik!"
no-permission: "&cNincs jogod ehhez!" no-permission: "&cNincs jogod ehhez!"
no-remove: "&cNem törölheted ezt a táblát!" no-remove: "&cNem törölheted ezt a táblát!"
@ -17,17 +13,16 @@ warps:
not-enough-level: "&cA szigeted szintje nem elég magas!" not-enough-level: "&cA szigeted szintje nem elég magas!"
not-on-island: "&cEhhez szigeten kell lenned!" not-on-island: "&cEhhez szigeten kell lenned!"
not-safe: "&cEz a teleport nem biztonságos!" not-safe: "&cEz a teleport nem biztonságos!"
your-level-is: "&cJelenleg a sziget szinted [level], és nagyobbnak kell lennie, mint [required]." your-level-is: "&cJelenleg a sziget szinted [level], és nagyobbnak kell lennie,
help: mint [required]."
description: "Teleportok panel megnyitása" help:
description: Teleportok panel megnyitása
next: "&6Következő oldal" next: "&6Következő oldal"
player-warped: "&2[name] teleportált a teleport tábládhoz!" player-warped: "&2[name] teleportált a teleport tábládhoz!"
previous: "&6Előző oldal" previous: "&6Előző oldal"
random: "&4Véletlenszerű Teleport" random: "&4Véletlenszerű Teleport"
sign-removed: "&cTeleport tábla törölve!" sign-removed: "&cTeleport tábla törölve!"
success: "&aSikeres!" success: "&aSikeres!"
title: "Teleport Táblák" title: Teleport Táblák
warpTip: "&6Helyezz le egy teleport táblát a következő szöveggel [text] a tetején" 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" 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,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

@ -1,27 +1,46 @@
---
warp: warp:
help: help:
description: teleportuje cię do tabliczki innego gracza description: teleportuje cię do tabliczki innego gracza
parameters: <gracz> parameters: "<gracz>"
warps: warps:
deactivate: '&c Stary teleport zdezaktywowany!' deactivate: "&c Stary teleport został zdezaktywowany!"
error: error:
does-not-exist: '&c Ten teleport nie istnieje.' does-not-exist: "&c Ten teleport nie istnieje."
no-permission: '&c Brak uprawnień!' no-permission: "&c Brak uprawnień!"
no-remove: '&c Nie możesz usunąć tej tabliczki!' no-remove: "&c Nie możesz usunąć tej tabliczki!"
no-warps-yet: '&c Nie ma jeszcze teleportów.' no-warps-yet: "&c Nie ma jeszcze stworzonych teleportów."
not-enough-level: '&c Twój poziom wyspy nie jest wystarczająco wysoki!' 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-on-island: "&c Musisz być na wyspie, by to zrobić."
not-safe: '&c Ten teleport nie jest bezpieczny!' not-safe: "&c Ten teleport nie jest bezpieczny!"
your-level-is: '&c Twój poziom wyspy to [level], a musi wynosić co namniej [required]. your-level-is: "&c Twój poziom wyspy to [level], a musi wynosić co najmniej [required].
Użyj komendy /is level.' Użyj komendy /is level."
help: help:
description: otwiera panel warpów description: otwiera panel warpów
next: '&6 Następna strona' player-warped: "&2 [name] teleportował się do twojej tabliczki!"
player-warped: '&2 [name] teleportował się do twojej tabliczki!' sign-removed: "&c Usunięto tabliczkę!"
previous: '&6 Poprzednia strona' success: "&a Sukces!"
random: '&4 Losowy teleport' warpTip: "&6 Postaw tabliczkę z napisem [text]"
sign-removed: '&c Usunięto tabliczkę!' warpToPlayersSign: "&6 Teleportowanie do tabliczki gracza [player]"
success: '&a Sukces!' gui:
title: Tabliczki teleportacyjne titles:
warpTip: '&6 Postaw tabliczkę z napisem [text]' warp-title: "&0&l Lista dostępnych wysp"
warpToPlayersSign: '&6 Teleportowanie do tabliczki gracza [player]' 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

@ -1,16 +1,12 @@
########################################################################################### ---
# This is a YML file. Be careful when editing. Check your edits in a YAML checker like # warp:
# the one at http://yaml-online-parser.appspot.com # help:
########################################################################################### description: Oyuncunun bölge tabelası.
parameters: "<name>"
warp: warps:
help:
description: "Oyuncunun bölge tabelası."
parameters: <name>
warps:
deactivate: "&cEski ada warpı silindi!" deactivate: "&cEski ada warpı silindi!"
error: error:
does-not-exist: "&4Malasef sorun oluştu. Tekrar dene." does-not-exist: "&cÜzgünüm. Böyle bir bölge artık yok!"
no-permission: "&4Buna yetkin yok!" no-permission: "&4Buna yetkin yok!"
no-remove: "&4Bu tabelayı kıramazsın!" no-remove: "&4Bu tabelayı kıramazsın!"
no-warps-yet: "&4Böyle bir bölge henüz yok." no-warps-yet: "&4Böyle bir bölge henüz yok."
@ -18,14 +14,13 @@ warps:
not-on-island: "&4Adanda değilsin." not-on-island: "&4Adanda değilsin."
not-safe: "&4Ada bölgesi güvenli değil!" not-safe: "&4Ada bölgesi güvenli değil!"
your-level-is: "&9Ada levelin &e[level] &9ve &e[required]&9'den fazla olması gerek!" your-level-is: "&9Ada levelin &e[level] &9ve &e[required]&9'den fazla olması gerek!"
help: help:
description: "Bölge panelini açar." description: Bölge panelini açar.
next: "&6Sonraki Sayfa" next: "&6Sonraki Sayfa"
player-warped: "&d[name] &9ada bölgene ışınlandı!" player-warped: "&d[name] &9ada bölgene ışınlandı!"
previous: "&6Önceki sayfa" previous: "&6Önceki sayfa"
random: "&4Rastgele bölgeye git!"
sign-removed: "&4Ada tabelası kaldırıldı!" sign-removed: "&4Ada tabelası kaldırıldı!"
success: "&9Başarılı!" title: "&dOyuncu bölgeleri &8- &5"
title: "&3&lSon&b&lCesurlar &e&lBölgeler &5" warpTip: "&6Ada bölgesi açmak için tabelanın en üstüne &a[text] &9yaz!"
warpTip: "&9Ada warpı açmak için tabelanın en üstüne &e[text] &9yaz!"
warpToPlayersSign: "&d[player] &9bölgesine gidiliyor!" 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

@ -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,256 +0,0 @@
package world.bentobox.warps;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
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.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
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.database.AbstractDatabaseHandler;
import world.bentobox.bentobox.database.DatabaseSetup;
import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.warps.config.Settings;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, DatabaseSetup.class})
public class WarpPanelManagerTest {
@Mock
private WarpSignsManager wsm;
@Mock
private Warp addon;
@Mock
private Player player;
@Mock
private User user;
@Mock
private World world;
@Mock
private Inventory top;
private UUID uuid;
@Mock
private Settings settings;
@Mock
private static AbstractDatabaseHandler<Object> handler;
@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
*/
@Before
public void setUp() throws Exception {
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(any())).thenReturn(list);
// User and player
when(user.getPlayer()).thenReturn(player);
when(user.getTranslation(Mockito.any())).thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
return invocation.getArgument(0, String.class);
}});
// BentoBox
BentoBox plugin = mock(BentoBox.class);
PlayersManager pm = mock(PlayersManager.class);
when(pm.getName(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(any())).thenReturn(imeta);
when(Bukkit.getItemFactory()).thenReturn(itemF);
// Inventory
when(top.getSize()).thenReturn(9);
when(Bukkit.createInventory(any(), Mockito.anyInt(), any())).thenReturn(top);
when(settings.getIcon()).thenReturn("SIGN");
when(addon.getSettings()).thenReturn(settings);
Location location = mock(Location.class);
Block block = mock(Block.class);
Material sign_type;
try {
sign_type = Material.valueOf("SIGN");
} catch (Exception e) {
sign_type = Material.valueOf("OAK_SIGN");
}
when(block.getType()).thenReturn(sign_type);
when(location.getBlock()).thenReturn(block);
// Sign block
when(wsm.getWarp(any(), any())).thenReturn(location);
// Sign cache
SignCacheItem sc = mock(SignCacheItem.class);
when(sc.getSignText()).thenReturn(Collections.singletonList("[welcome]"));
when(sc.getType()).thenReturn(sign_type);
when(wsm.getSignInfo(any(), any())).thenReturn(sc);
}
/**
* Test method for {@link WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}.
*/
@Test
public void testShowWarpPanelFirst() {
ArgumentCaptor<ItemStack> argument = ArgumentCaptor.forClass(ItemStack.class);
WarpPanelManager wpm = new WarpPanelManager(addon);
wpm.showWarpPanel(world, user, 0);
verify(player).openInventory(Mockito.eq(top));
// Just next sign
verify(top, Mockito.times(53)).setItem(Mockito.anyInt(),argument.capture());
assertEquals(Material.STONE, argument.getAllValues().get(52).getType());
}
/**
* Test method for {@link WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}.
*/
@Test
public void testShowWarpPanelFirstRandom() {
when(settings.isRandomAllowed()).thenReturn(true);
ArgumentCaptor<ItemStack> argument = ArgumentCaptor.forClass(ItemStack.class);
WarpPanelManager wpm = new WarpPanelManager(addon);
wpm.showWarpPanel(world, user, 0);
verify(player).openInventory(Mockito.eq(top));
// Check crystal
verify(top, Mockito.atLeastOnce()).setItem(anyInt(), argument.capture());
assertEquals(Material.END_CRYSTAL, argument.getAllValues().get(0).getType());
}
/**
* Test method for {@link WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}.
*/
@Test
public void testShowWarpPanelNoRandom() {
when(settings.isRandomAllowed()).thenReturn(false);
ArgumentCaptor<ItemStack> argument = ArgumentCaptor.forClass(ItemStack.class);
WarpPanelManager wpm = new WarpPanelManager(addon);
wpm.showWarpPanel(world, user, 0);
verify(player).openInventory(Mockito.eq(top));
// Check crystal
verify(top, Mockito.atLeastOnce()).setItem(anyInt(), argument.capture());
assertFalse(argument.getAllValues().get(0).getType().equals(Material.END_CRYSTAL));
}
/**
* Test method for {@link WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}.
*/
@Test
public void testShowWarpPanelMiddle() {
ArgumentCaptor<ItemStack> argument = ArgumentCaptor.forClass(ItemStack.class);
WarpPanelManager wpm = new WarpPanelManager(addon);
wpm.showWarpPanel(world, user, 1);
verify(player).openInventory(Mockito.eq(top));
// includes previous and next signs
verify(top, Mockito.times(54)).setItem(Mockito.anyInt(), argument.capture());
assertEquals(Material.STONE, argument.getAllValues().get(52).getType());
assertEquals(Material.COBBLESTONE, argument.getAllValues().get(53).getType());
}
/**
* Test method for {@link WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}.
*/
@Test
public void testShowWarpPanelLast() {
ArgumentCaptor<ItemStack> argument = ArgumentCaptor.forClass(ItemStack.class);
WarpPanelManager wpm = new WarpPanelManager(addon);
wpm.showWarpPanel(world, user, 3);
verify(player).openInventory(Mockito.eq(top));
// Final amount, just previous sign
verify(top, Mockito.times(46)).setItem(Mockito.anyInt(), argument.capture());
assertEquals(Material.COBBLESTONE, argument.getAllValues().get(45).getType());
}
/**
* Test method for {@link 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
verify(wsm, Mockito.times(45)).getSignInfo(any(), any());
}
/**
* Test method for {@link 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
verify(wsm, Mockito.times(46)).getSignInfo(any(), any());
}
}

View File

@ -13,11 +13,11 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -25,12 +25,14 @@ import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.Tag;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign; import org.bukkit.block.Sign;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.junit.After; import org.junit.After;
@ -59,8 +61,11 @@ import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.bentobox.util.Util; import world.bentobox.bentobox.util.Util;
import world.bentobox.warps.config.Settings; import world.bentobox.warps.config.Settings;
import world.bentobox.warps.event.WarpInitiateEvent; import world.bentobox.warps.event.WarpInitiateEvent;
import world.bentobox.warps.managers.SignCacheManager;
import world.bentobox.warps.managers.WarpSignsManager;
import world.bentobox.warps.objects.WarpsData; import world.bentobox.warps.objects.WarpsData;
/** /**
* @author tastybento * @author tastybento
* *
@ -78,13 +83,13 @@ public class WarpSignsManagerTest {
@Mock @Mock
private static AbstractDatabaseHandler<Object> handler; private static AbstractDatabaseHandler<Object> handler;
private WarpSignsManager wsm; private WarpSignsManager wsm;
@Mock @Mock
private Logger logger; private Logger logger;
@Mock @Mock
private WarpsData load; private WarpsData load;
private UUID uuid = UUID.randomUUID(); private final UUID uuid = UUID.randomUUID();
@Mock @Mock
private Location location; private Location location;
@Mock @Mock
@ -96,7 +101,7 @@ public class WarpSignsManagerTest {
@Mock @Mock
private Player player; private Player player;
@Mock @Mock
private WarpPanelManager wpm; private SignCacheManager wpm;
@Mock @Mock
private PlayersManager pm; private PlayersManager pm;
@Mock @Mock
@ -110,7 +115,7 @@ public class WarpSignsManagerTest {
@Mock @Mock
private Island island; private Island island;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@BeforeClass @BeforeClass
public static void beforeClass() { public static void beforeClass() {
@ -122,22 +127,26 @@ public class WarpSignsManagerTest {
when(DatabaseSetup.getDatabase()).thenReturn(dbSetup); when(DatabaseSetup.getDatabase()).thenReturn(dbSetup);
when(dbSetup.getHandler(any())).thenReturn(handler); when(dbSetup.getHandler(any())).thenReturn(handler);
} }
/** /**
* @throws java.lang.Exception * @throws java.lang.Exception exception
*/ */
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
Whitebox.setInternalState(BentoBox.class, "instance", plugin); Whitebox.setInternalState(BentoBox.class, "instance", plugin);
when(addon.getPlugin()).thenReturn(plugin); when(addon.getPlugin()).thenReturn(plugin);
when(addon.getLogger()).thenReturn(logger); when(addon.getLogger()).thenReturn(logger);
// Player // Player
when(player.getUniqueId()).thenReturn(uuid); when(player.getUniqueId()).thenReturn(uuid);
when(player.isOnline()).thenReturn(true);
when(player.canSee(any(Player.class))).thenReturn(true);
User.setPlugin(plugin);
User.getInstance(player); User.getInstance(player);
// Locales // Locales
LocalesManager lm = mock(LocalesManager.class); 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(lm.get(Mockito.any(), Mockito.any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
when(plugin.getLocalesManager()).thenReturn(lm); when(plugin.getLocalesManager()).thenReturn(lm);
// Return the same string // Return the same string
@ -145,24 +154,27 @@ public class WarpSignsManagerTest {
when(phm.replacePlaceholders(any(), anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class)); when(phm.replacePlaceholders(any(), anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
when(plugin.getPlaceholdersManager()).thenReturn(phm); when(plugin.getPlaceholdersManager()).thenReturn(phm);
// Server // Server
when(addon.getServer()).thenReturn(server); when(addon.getServer()).thenReturn(server);
when(server.getPlayer(any(UUID.class))).thenReturn(player); when(server.getPlayer(any(UUID.class))).thenReturn(player);
// Util // Util
PowerMockito.mockStatic(Util.class); PowerMockito.mockStatic(Util.class);
when(Util.getWorld(any())).thenAnswer((Answer<World>) invocation -> invocation.getArgument(0, World.class)); when(Util.getWorld(any())).thenAnswer((Answer<World>) invocation -> invocation.getArgument(0, World.class));
when(Util.sameWorld(any(), any())).thenReturn(true); when(Util.sameWorld(any(), any())).thenReturn(true);
when(Util.translateColorCodes(any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
// Location // Location
when(location.getWorld()).thenReturn(world); when(location.getWorld()).thenReturn(world);
when(location.getBlock()).thenReturn(block); when(location.getBlock()).thenReturn(block);
when(location.getBlockX()).thenReturn(23); when(location.getBlockX()).thenReturn(23);
when(location.getBlockY()).thenReturn(24); when(location.getBlockY()).thenReturn(24);
when(location.getBlockZ()).thenReturn(25); when(location.getBlockZ()).thenReturn(25);
when(player.getLocation()).thenReturn(location);
when(world.getEnvironment()).thenReturn(Environment.NORMAL); when(world.getEnvironment()).thenReturn(Environment.NORMAL);
when(world.isChunkLoaded(anyInt(), anyInt())).thenReturn(true);
// Block // Block
when(block.getType()).thenReturn(Material.ACACIA_SIGN); when(block.getType()).thenReturn(Material.ACACIA_SIGN);
when(block.getLocation()).thenReturn(location); when(block.getLocation()).thenReturn(location);
@ -176,27 +188,29 @@ public class WarpSignsManagerTest {
when(signBd.getRotation()).thenReturn(BlockFace.EAST); when(signBd.getRotation()).thenReturn(BlockFace.EAST);
when(block.getBlockData()).thenReturn(signBd); when(block.getBlockData()).thenReturn(signBd);
when(block.getRelative(any())).thenReturn(block); when(block.getRelative(any())).thenReturn(block);
// Handler // Handler
when(handler.objectExists(eq("warps"))).thenReturn(true); when(handler.objectExists("warps")).thenReturn(true);
Map<Location, UUID> warpMap = Collections.singletonMap(location, uuid); Map<Location, UUID> warpMap = Collections.singletonMap(location, uuid);
when(load.getWarpSigns()).thenReturn(warpMap); when(load.getWarpSigns()).thenReturn(warpMap);
when(handler.loadObject(anyString())).thenReturn(load); when(handler.loadObject(anyString())).thenReturn(load);
// Settings // Settings
when(addon.getSettings()).thenReturn(settings); when(addon.getSettings()).thenReturn(settings);
when(settings.getWelcomeLine()).thenReturn("[Welcome]"); when(settings.getWelcomeLine()).thenReturn("[Welcome]");
when(settings.getLoreFormat()).thenReturn("&f"); when(settings.getLoreFormat()).thenReturn("&f");
when(settings.getIcon()).thenReturn("SIGN");
// Bukkit
// Bukkit PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getPluginManager()).thenReturn(pim); when(Bukkit.getPluginManager()).thenReturn(pim);
// Tags
when(Tag.STANDING_SIGNS.isTagged(Material.ACACIA_SIGN)).thenReturn(true);
// Players Manager // Players Manager
when(plugin.getPlayers()).thenReturn(pm); when(plugin.getPlayers()).thenReturn(pm);
when(pm.getName(eq(uuid))).thenReturn("tastybento"); when(pm.getName(uuid)).thenReturn("tastybento");
// Offline player // Offline player
when(server.getOfflinePlayer(any(UUID.class))).thenReturn(offlinePlayer); when(server.getOfflinePlayer(any(UUID.class))).thenReturn(offlinePlayer);
when(offlinePlayer.getLastPlayed()).thenReturn(System.currentTimeMillis()); when(offlinePlayer.getLastPlayed()).thenReturn(System.currentTimeMillis());
@ -204,28 +218,28 @@ public class WarpSignsManagerTest {
// IWM // IWM
when(plugin.getIWM()).thenReturn(iwm); when(plugin.getIWM()).thenReturn(iwm);
when(iwm.getPermissionPrefix(any())).thenReturn("bskyblock."); when(iwm.getPermissionPrefix(any())).thenReturn("bskyblock.");
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
// Island Manager // Island Manager
when(addon.getIslands()).thenReturn(im); when(addon.getIslands()).thenReturn(im);
when(im.getIsland(any(), any(UUID.class))).thenReturn(island); when(im.getIsland(any(), any(UUID.class))).thenReturn(island);
when(im.isSafeLocation(any())).thenReturn(true); when(im.isSafeLocation(any())).thenReturn(true);
// WarpPanelManager // WarpPanelManager
when(addon.getWarpPanelManager()).thenReturn(wpm); when(addon.getSignCacheManager()).thenReturn(wpm);
wsm = new WarpSignsManager(addon, plugin); wsm = new WarpSignsManager(addon, plugin);
} }
/** /**
* @throws java.lang.Exception
*/ */
@After @After
public void tearDown() throws Exception { public void tearDown() {
User.clearUsers(); User.clearUsers();
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#getWarpMap(org.bukkit.World)}. * Test method for {@link WarpSignsManager#getWarpMap(org.bukkit.World)}.
*/ */
@Test @Test
public void testGetWarpMap() { public void testGetWarpMap() {
@ -233,7 +247,7 @@ public class WarpSignsManagerTest {
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#getWarpMap(org.bukkit.World)}. * Test method for {@link WarpSignsManager#getWarpMap(org.bukkit.World)}.
*/ */
@Test @Test
public void testGetWarpMapNullWorld() { public void testGetWarpMapNullWorld() {
@ -243,7 +257,7 @@ public class WarpSignsManagerTest {
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#getWarpMap(org.bukkit.World)}. * Test method for {@link WarpSignsManager#getWarpMap(org.bukkit.World)}.
*/ */
@Test @Test
public void testGetWarpMapWrongBlockType() { public void testGetWarpMapWrongBlockType() {
@ -253,7 +267,7 @@ public class WarpSignsManagerTest {
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#getWarpMap(org.bukkit.World)}. * Test method for {@link WarpSignsManager#getWarpMap(org.bukkit.World)}.
*/ */
@Test @Test
public void testGetWarpMapNullLocation() { public void testGetWarpMapNullLocation() {
@ -262,10 +276,10 @@ public class WarpSignsManagerTest {
wsm = new WarpSignsManager(addon, plugin); wsm = new WarpSignsManager(addon, plugin);
assertTrue("Map is not empty", wsm.getWarpMap(world).isEmpty()); assertTrue("Map is not empty", wsm.getWarpMap(world).isEmpty());
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#getWarpMap(org.bukkit.World)}. * Test method for {@link WarpSignsManager#getWarpMap(org.bukkit.World)}.
* @throws Exception * @throws Exception exception
*/ */
@Test @Test
public void testGetWarpMapNullDatabaseObject() throws Exception { public void testGetWarpMapNullDatabaseObject() throws Exception {
@ -273,64 +287,63 @@ public class WarpSignsManagerTest {
wsm = new WarpSignsManager(addon, plugin); wsm = new WarpSignsManager(addon, plugin);
assertTrue("Map is not empty", wsm.getWarpMap(world).isEmpty()); assertTrue("Map is not empty", wsm.getWarpMap(world).isEmpty());
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#getWarpMap(org.bukkit.World)}. * Test method for {@link WarpSignsManager#getWarpMap(org.bukkit.World)}.
*/ */
@Test @Test
public void testGetWarpMapNothingInDatabase() { public void testGetWarpMapNothingInDatabase() {
when(handler.objectExists(eq("warps"))).thenReturn(false); when(handler.objectExists("warps")).thenReturn(false);
wsm = new WarpSignsManager(addon, plugin); wsm = new WarpSignsManager(addon, plugin);
assertTrue("Map is not empty", wsm.getWarpMap(world).isEmpty()); assertTrue("Map is not empty", wsm.getWarpMap(world).isEmpty());
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#WarpSignsManager(world.bentobox.warps.Warp, world.bentobox.bentobox.BentoBox)}. * Test method for {@link WarpSignsManager#WarpSignsManager(world.bentobox.warps.Warp, world.bentobox.bentobox.BentoBox)}.
* @throws Exception
*/ */
@Test @Test
public void testWarpSignsManager() throws Exception { public void testWarpSignsManager() {
verify(addon).log("Loading warps..."); verify(addon).log("Loading warps...");
verify(load).getWarpSigns(); verify(load).getWarpSigns();
verify(block).getType(); verify(block).getType();
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}. * Test method for {@link WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}.
*/ */
@Test @Test
public void testAddWarpNullPlayer() { public void testAddWarpNullPlayer() {
assertFalse(wsm.addWarp(null, null)); assertFalse(wsm.addWarp(null, null));
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}. * Test method for {@link WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}.
*/ */
@Test @Test
public void testAddWarpNullLocation() { public void testAddWarpNullLocation() {
assertFalse(wsm.addWarp(uuid, null)); assertFalse(wsm.addWarp(uuid, null));
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}. * Test method for {@link WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}.
*/ */
@Test @Test
public void testAddWarpReplaceOldSign() { public void testAddWarpReplaceOldSign() {
assertTrue(wsm.addWarp(uuid, location)); assertTrue(wsm.addWarp(uuid, location));
verify(player).sendMessage("warps.sign-removed"); verify(player).sendMessage("warps.sign-removed");
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}. * Test method for {@link WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}.
*/ */
@Test @Test
public void testAddWarpReplaceOldSignDifferentPlayer() { public void testAddWarpReplaceOldSignDifferentPlayer() {
assertTrue(wsm.addWarp(UUID.randomUUID(), location)); assertTrue(wsm.addWarp(UUID.randomUUID(), location));
verify(player).sendMessage("warps.sign-removed"); verify(player).sendMessage("warps.sign-removed");
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}. * Test method for {@link WarpSignsManager#addWarp(java.util.UUID, org.bukkit.Location)}.
*/ */
@Test @Test
public void testAddWarp() { public void testAddWarp() {
@ -340,7 +353,7 @@ public class WarpSignsManagerTest {
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#getWarp(org.bukkit.World, java.util.UUID)}. * Test method for {@link WarpSignsManager#getWarp(org.bukkit.World, java.util.UUID)}.
*/ */
@Test @Test
public void testGetWarpWorldWorld() { public void testGetWarpWorldWorld() {
@ -348,7 +361,7 @@ public class WarpSignsManagerTest {
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#getWarp(org.bukkit.World, java.util.UUID)}. * Test method for {@link WarpSignsManager#getWarp(org.bukkit.World, java.util.UUID)}.
*/ */
@Test @Test
public void testGetWarp() { public void testGetWarp() {
@ -356,23 +369,24 @@ public class WarpSignsManagerTest {
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#getWarpOwner(org.bukkit.Location)}. * Test method for {@link WarpSignsManager#getWarpOwner(org.bukkit.Location)}.
*/ */
@Test @Test
public void testGetWarpOwner() { public void testGetWarpOwner() {
assertEquals("tastybento", wsm.getWarpOwner(location)); assertEquals("tastybento", wsm.getWarpOwner(location));
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#getSortedWarps(org.bukkit.World)}. * Test method for {@link WarpSignsManager#getSortedWarps(org.bukkit.World)}.
*/ */
@Test @Test
public void testGetSortedWarps() { public void testGetSortedWarps() {
assertEquals(1, wsm.getSortedWarps(world).size()); CompletableFuture<List<UUID>> r = new CompletableFuture<>();
assertEquals(1, wsm.processWarpMap(r, world).size());
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#listWarps(org.bukkit.World)}. * Test method for {@link WarpSignsManager#listWarps(org.bukkit.World)}.
*/ */
@Test @Test
public void testListWarps() { public void testListWarps() {
@ -381,7 +395,7 @@ public class WarpSignsManagerTest {
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#removeWarp(org.bukkit.Location)}. * Test method for {@link WarpSignsManager#removeWarp(org.bukkit.Location)}.
*/ */
@Test @Test
public void testRemoveWarpLocation() { public void testRemoveWarpLocation() {
@ -390,7 +404,7 @@ public class WarpSignsManagerTest {
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#removeWarp(org.bukkit.World, java.util.UUID)}. * Test method for {@link WarpSignsManager#removeWarp(org.bukkit.World, java.util.UUID)}.
*/ */
@Test @Test
public void testRemoveWarpWorldUUID() { public void testRemoveWarpWorldUUID() {
@ -399,10 +413,8 @@ public class WarpSignsManagerTest {
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#saveWarpList()}. * Test method for {@link WarpSignsManager#saveWarpList()}.
* @throws IntrospectionException * @throws Exception general exception
* @throws InvocationTargetException
* @throws Exception
*/ */
@Test @Test
public void testSaveWarpList() throws Exception { public void testSaveWarpList() throws Exception {
@ -411,16 +423,7 @@ public class WarpSignsManagerTest {
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#getSignInfo(org.bukkit.World, java.util.UUID)}. * Test method for {@link WarpSignsManager#warpPlayer(org.bukkit.World, world.bentobox.bentobox.api.user.User, java.util.UUID)}.
*/
@Test
public void testGetSignInfo() {
SignCacheItem sc = wsm.getSignInfo(world, uuid);
assertEquals(Material.ACACIA_SIGN, sc.getType());
}
/**
* Test method for {@link world.bentobox.warps.WarpSignsManager#warpPlayer(org.bukkit.World, world.bentobox.bentobox.api.user.User, java.util.UUID)}.
*/ */
@Test @Test
public void testWarpPlayer() { public void testWarpPlayer() {
@ -428,15 +431,20 @@ public class WarpSignsManagerTest {
when(p.getUniqueId()).thenReturn(UUID.randomUUID()); when(p.getUniqueId()).thenReturn(UUID.randomUUID());
when(p.getWorld()).thenReturn(world); when(p.getWorld()).thenReturn(world);
when(p.getName()).thenReturn("tastybento"); when(p.getName()).thenReturn("tastybento");
when(p.getLocation()).thenReturn(location);
when(p.isOnline()).thenReturn(true);
when(p.canSee(any(Player.class))).thenReturn(true);
@Nullable @Nullable
User u = User.getInstance(p); User u = User.getInstance(p);
PowerMockito.when(Util.teleportAsync(any(), any(), any())).thenReturn(CompletableFuture.completedFuture(true));
wsm.warpPlayer(world, u, uuid); wsm.warpPlayer(world, u, uuid);
verify(p).teleport(any(Location.class)); PowerMockito.verifyStatic(Util.class);
verify(player).sendMessage("warps.player-warped"); Util.teleportAsync(eq(p), any(), eq(TeleportCause.COMMAND));
verify(player).sendMessage(anyString());
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#hasWarp(org.bukkit.World, java.util.UUID)}. * Test method for {@link WarpSignsManager#hasWarp(org.bukkit.World, java.util.UUID)}.
*/ */
@Test @Test
public void testHasWarp() { public void testHasWarp() {
@ -446,7 +454,7 @@ public class WarpSignsManagerTest {
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#loadWarpList()}. * Test method for {@link WarpSignsManager#loadWarpList()}.
*/ */
@Test @Test
public void testLoadWarpListNoWarpTable() { public void testLoadWarpListNoWarpTable() {
@ -456,13 +464,13 @@ public class WarpSignsManagerTest {
// Save // Save
wsm.saveWarpList(); wsm.saveWarpList();
// Default load in constructor check // Default load in constructor check
verify(addon, times(2)).log(eq("Loading warps...")); verify(addon, times(2)).log("Loading warps...");
assertTrue(wsm.getWarpMap(world).isEmpty()); assertTrue(wsm.getWarpMap(world).isEmpty());
} }
/** /**
* Test method for {@link world.bentobox.warps.WarpSignsManager#loadWarpList()}. * Test method for {@link WarpSignsManager#loadWarpList()}.
* @throws Exception * @throws Exception exception
*/ */
@Test @Test
public void testLoadWarpListEmptyWarpTable() throws Exception { public void testLoadWarpListEmptyWarpTable() throws Exception {
@ -472,7 +480,7 @@ public class WarpSignsManagerTest {
// Save // Save
wsm.saveWarpList(); wsm.saveWarpList();
// Default load in constructor check // Default load in constructor check
verify(addon, times(2)).log(eq("Loading warps...")); verify(addon, times(2)).log("Loading warps...");
assertTrue(wsm.getWarpMap(world).isEmpty()); assertTrue(wsm.getWarpMap(world).isEmpty());
} }
} }

View File

@ -4,7 +4,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -39,7 +38,7 @@ import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.IslandWorldManager; import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.PlayersManager; import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.warps.Warp; import world.bentobox.warps.Warp;
import world.bentobox.warps.WarpSignsManager; import world.bentobox.warps.managers.WarpSignsManager;
import world.bentobox.warps.config.Settings; import world.bentobox.warps.config.Settings;
/** /**
@ -53,7 +52,6 @@ public class WarpCommandTest {
private static final String WELCOME_LINE = "[Welcome]"; private static final String WELCOME_LINE = "[Welcome]";
@Mock @Mock
private CompositeCommand ic; private CompositeCommand ic;
private UUID uuid;
@Mock @Mock
private User user; private User user;
@Mock @Mock
@ -78,10 +76,9 @@ public class WarpCommandTest {
private BukkitScheduler sch; private BukkitScheduler sch;
/** /**
* @throws java.lang.Exception
*/ */
@Before @Before
public void setUp() throws Exception { public void setUp() {
// Set up plugin // Set up plugin
BentoBox plugin = mock(BentoBox.class); BentoBox plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin); Whitebox.setInternalState(BentoBox.class, "instance", plugin);
@ -100,7 +97,7 @@ public class WarpCommandTest {
when(plugin.getIWM()).thenReturn(iwm); when(plugin.getIWM()).thenReturn(iwm);
// Player // Player
uuid = UUID.randomUUID(); UUID uuid = UUID.randomUUID();
when(user.getUniqueId()).thenReturn(uuid); when(user.getUniqueId()).thenReturn(uuid);
when(user.getWorld()).thenReturn(world); when(user.getWorld()).thenReturn(world);
@ -116,7 +113,7 @@ public class WarpCommandTest {
set.add(UUID.randomUUID()); set.add(UUID.randomUUID());
set.add(UUID.randomUUID()); set.add(UUID.randomUUID());
set.add(UUID.randomUUID()); set.add(UUID.randomUUID());
when(wsm.listWarps(eq(world))).thenReturn(set); when(wsm.listWarps(world)).thenReturn(set);
// Players Manager // Players Manager
when(plugin.getPlayers()).thenReturn(pm); when(plugin.getPlayers()).thenReturn(pm);
@ -181,7 +178,7 @@ public class WarpCommandTest {
public void testExecuteUserStringListOfStringNoArgs() { public void testExecuteUserStringListOfStringNoArgs() {
warpCommandWarpCompositeCommand(); warpCommandWarpCompositeCommand();
wc.execute(user, "warp", Collections.emptyList()); wc.execute(user, "warp", Collections.emptyList());
verify(user).sendMessage(eq("commands.help.header"), eq(TextVariables.LABEL), eq("BSkyBlock")); verify(user).sendMessage("commands.help.header", TextVariables.LABEL, "BSkyBlock");
} }
/** /**
@ -191,7 +188,6 @@ public class WarpCommandTest {
public void testExecuteUserStringListOfStringKnownPlayer() { public void testExecuteUserStringListOfStringKnownPlayer() {
warpCommandWarpCompositeCommand(); warpCommandWarpCompositeCommand();
assertTrue(wc.execute(user, "warp", Collections.singletonList("tastybento"))); assertTrue(wc.execute(user, "warp", Collections.singletonList("tastybento")));
//verify(wsm).warpPlayer(eq(world), eq(user), any());
} }
/** /**
@ -201,7 +197,6 @@ public class WarpCommandTest {
public void testExecuteUserStringListOfStringKnownPlayerWarp() { public void testExecuteUserStringListOfStringKnownPlayerWarp() {
warpCommandWarp(); warpCommandWarp();
assertTrue(wc.execute(user, "warp", Collections.singletonList("tastybento"))); assertTrue(wc.execute(user, "warp", Collections.singletonList("tastybento")));
//verify(wsm).warpPlayer(eq(world), eq(user), any());
} }
/** /**
@ -211,7 +206,6 @@ public class WarpCommandTest {
public void testExecuteUserStringListOfStringKnownPlayerMixedCase() { public void testExecuteUserStringListOfStringKnownPlayerMixedCase() {
warpCommandWarpCompositeCommand(); warpCommandWarpCompositeCommand();
assertTrue(wc.execute(user, "warp", Collections.singletonList("tAsTyBEnTo"))); assertTrue(wc.execute(user, "warp", Collections.singletonList("tAsTyBEnTo")));
//verify(wsm).warpPlayer(eq(world), eq(user), any());
} }
/** /**
@ -219,9 +213,9 @@ public class WarpCommandTest {
*/ */
@Test @Test
public void testExecuteUserStringListOfStringKnownPlayerStartOnly() { public void testExecuteUserStringListOfStringKnownPlayerStartOnly() {
when(pm.getName(any())).thenReturn("tastybento");
warpCommandWarpCompositeCommand(); warpCommandWarpCompositeCommand();
assertTrue(wc.execute(user, "warp", Collections.singletonList("tAsTy"))); assertTrue(wc.execute(user, "warp", Collections.singletonList("tAsTy")));
//verify(wsm).warpPlayer(eq(world), eq(user), any());
} }
@ -232,7 +226,7 @@ public class WarpCommandTest {
public void testExecuteUserStringListOfStringUnknownPlayer() { public void testExecuteUserStringListOfStringUnknownPlayer() {
warpCommandWarpCompositeCommand(); warpCommandWarpCompositeCommand();
assertFalse(wc.execute(user, "warp", Collections.singletonList("LSPVicky"))); assertFalse(wc.execute(user, "warp", Collections.singletonList("LSPVicky")));
verify(user).sendMessage(eq("warps.error.does-not-exist")); verify(user).sendMessage("warps.error.does-not-exist");
} }
/** /**
@ -240,11 +234,11 @@ public class WarpCommandTest {
*/ */
@Test @Test
public void testExecuteUserStringListOfStringNoWarpsYet() { public void testExecuteUserStringListOfStringNoWarpsYet() {
when(wsm.listWarps(eq(world))).thenReturn(Collections.emptySet()); when(wsm.listWarps(world)).thenReturn(Collections.emptySet());
warpCommandWarpCompositeCommand(); warpCommandWarpCompositeCommand();
assertFalse(wc.execute(user, "warp", Collections.singletonList("LSPVicky"))); assertFalse(wc.execute(user, "warp", Collections.singletonList("LSPVicky")));
verify(user).sendMessage(eq("warps.error.no-warps-yet")); verify(user).sendMessage("warps.error.no-warps-yet");
verify(user).sendMessage(eq("warps.warpTip"), eq("[text]"), eq(WELCOME_LINE)); verify(user).sendMessage("warps.warpTip", "[text]", WELCOME_LINE);
} }
/** /**

View File

@ -3,15 +3,12 @@ package world.bentobox.warps.commands;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.util.Collections; import java.util.*;
import java.util.HashSet; import java.util.concurrent.CompletableFuture;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.World; import org.bukkit.World;
@ -30,9 +27,9 @@ import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.CommandsManager; import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.IslandWorldManager; import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.PlayersManager; import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.warps.managers.SignCacheManager;
import world.bentobox.warps.Warp; import world.bentobox.warps.Warp;
import world.bentobox.warps.WarpPanelManager; import world.bentobox.warps.managers.WarpSignsManager;
import world.bentobox.warps.WarpSignsManager;
import world.bentobox.warps.config.Settings; import world.bentobox.warps.config.Settings;
/** /**
@ -63,13 +60,12 @@ public class WarpsCommandTest {
@Mock @Mock
private PlayersManager pm; private PlayersManager pm;
@Mock @Mock
private WarpPanelManager wpm; private SignCacheManager wpm;
/** /**
* @throws java.lang.Exception
*/ */
@Before @Before
public void setUp() throws Exception { public void setUp() {
// Set up plugin // Set up plugin
BentoBox plugin = mock(BentoBox.class); BentoBox plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin); Whitebox.setInternalState(BentoBox.class, "instance", plugin);
@ -99,10 +95,15 @@ public class WarpsCommandTest {
set.add(UUID.randomUUID()); set.add(UUID.randomUUID());
set.add(UUID.randomUUID()); set.add(UUID.randomUUID());
set.add(UUID.randomUUID()); set.add(UUID.randomUUID());
when(wsm.listWarps(eq(world))).thenReturn(set); 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 // Warp Panel Manager
when(addon.getWarpPanelManager()).thenReturn(wpm); when(addon.getSignCacheManager()).thenReturn(wpm);
} }
@ -122,7 +123,7 @@ public class WarpsCommandTest {
@Test @Test
public void testSetupWarpCompositeCommand() { public void testSetupWarpCompositeCommand() {
warpCommandWarpsCompositeCommand(); warpCommandWarpsCompositeCommand();
assertEquals("bskyblock.island.warp", wc.getPermission()); assertEquals("bskyblock.island.warps", wc.getPermission());
assertTrue(wc.isOnlyPlayer()); assertTrue(wc.isOnlyPlayer());
assertEquals("warps.help.description", wc.getDescription()); assertEquals("warps.help.description", wc.getDescription());
} }
@ -133,7 +134,7 @@ public class WarpsCommandTest {
@Test @Test
public void testSetupWarp() { public void testSetupWarp() {
warpCommandWarps(); warpCommandWarps();
assertEquals(Warp.WELCOME_WARP_SIGNS + ".warp", wc.getPermission()); assertEquals(Warp.WELCOME_WARP_SIGNS + ".warps", wc.getPermission());
assertTrue(wc.isOnlyPlayer()); assertTrue(wc.isOnlyPlayer());
assertEquals("warps.help.description", wc.getDescription()); assertEquals("warps.help.description", wc.getDescription());
} }
@ -144,11 +145,11 @@ public class WarpsCommandTest {
*/ */
@Test @Test
public void testExecuteUserStringListOfStringNoWarpsYet() { public void testExecuteUserStringListOfStringNoWarpsYet() {
when(wsm.listWarps(eq(world))).thenReturn(Collections.emptySet()); when(wsm.listWarps(world)).thenReturn(Collections.emptySet());
warpCommandWarpsCompositeCommand(); warpCommandWarpsCompositeCommand();
assertFalse(wc.execute(user, "warps", Collections.emptyList())); assertFalse(wc.execute(user, "warps", Collections.emptyList()));
verify(user).sendMessage(eq("warps.error.no-warps-yet")); verify(user).sendMessage("warps.error.no-warps-yet");
verify(user).sendMessage(eq("warps.warpTip"), eq("[text]"), eq(WELCOME_LINE)); verify(user).sendMessage("warps.warpTip", "[text]", WELCOME_LINE);
} }
/** /**
@ -156,11 +157,11 @@ public class WarpsCommandTest {
*/ */
@Test @Test
public void testExecuteUserStringListOfStringNoWarpsYetNoAddon() { public void testExecuteUserStringListOfStringNoWarpsYetNoAddon() {
when(wsm.listWarps(eq(world))).thenReturn(Collections.emptySet()); when(wsm.listWarps(world)).thenReturn(Collections.emptySet());
warpCommandWarps(); warpCommandWarps();
assertFalse(wc.execute(user, "warps", Collections.emptyList())); assertFalse(wc.execute(user, "warps", Collections.emptyList()));
verify(user).sendMessage(eq("warps.error.no-warps-yet")); verify(user).sendMessage("warps.error.no-warps-yet");
verify(user).sendMessage(eq("warps.warpTip"), eq("[text]"), eq(WELCOME_LINE)); verify(user).sendMessage("warps.warpTip", "[text]", WELCOME_LINE);
} }
/** /**
@ -170,7 +171,6 @@ public class WarpsCommandTest {
public void testExecuteUserStringListOfString() { public void testExecuteUserStringListOfString() {
warpCommandWarpsCompositeCommand(); warpCommandWarpsCompositeCommand();
assertTrue(wc.execute(user, "warps", Collections.emptyList())); assertTrue(wc.execute(user, "warps", Collections.emptyList()));
verify(wpm).showWarpPanel(world, user, 0);
} }
/** /**
@ -180,7 +180,6 @@ public class WarpsCommandTest {
public void testExecuteUserStringListOfStringNoAddon() { public void testExecuteUserStringListOfStringNoAddon() {
warpCommandWarps(); warpCommandWarps();
assertTrue(wc.execute(user, "warps", Collections.emptyList())); assertTrue(wc.execute(user, "warps", Collections.emptyList()));
verify(wpm).showWarpPanel(world, user, 0);
} }
} }

View File

@ -5,12 +5,10 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.*;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.never;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -37,23 +35,24 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito; import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunner;
import world.bentobox.bentobox.BentoBox; 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.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.IslandWorldManager; import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager; import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.LocalesManager; import world.bentobox.bentobox.managers.LocalesManager;
import world.bentobox.bentobox.managers.PlaceholdersManager; import world.bentobox.bentobox.managers.PlaceholdersManager;
import world.bentobox.bentobox.util.Util; import world.bentobox.bentobox.util.Util;
import world.bentobox.warps.Warp; import world.bentobox.warps.Warp;
import world.bentobox.warps.WarpSignsManager; import world.bentobox.warps.managers.WarpSignsManager;
import world.bentobox.warps.config.Settings; import world.bentobox.warps.config.Settings;
import world.bentobox.warps.listeners.WarpSignsListener;
/** /**
* @author tastybento * @author tastybento
@ -75,7 +74,6 @@ public class WarpSignsListenerTest {
@Mock @Mock
private WarpSignsManager wsm; private WarpSignsManager wsm;
private PluginManager pm; private PluginManager pm;
private UUID uuid;
private String[] lines; private String[] lines;
@Mock @Mock
private FileConfiguration config; private FileConfiguration config;
@ -85,9 +83,11 @@ public class WarpSignsListenerTest {
private IslandsManager im; private IslandsManager im;
@Mock @Mock
private IslandWorldManager iwm; private IslandWorldManager iwm;
@Mock
private Island island;
@Before @Before
public void setUp() throws Exception { public void setUp() {
// Bukkit // Bukkit
PowerMockito.mockStatic(Bukkit.class); PowerMockito.mockStatic(Bukkit.class);
pm = mock(PluginManager.class); pm = mock(PluginManager.class);
@ -116,10 +116,10 @@ public class WarpSignsListenerTest {
when(block.getWorld()).thenReturn(world); when(block.getWorld()).thenReturn(world);
// Player // Player
when(player.hasPermission(anyString())).thenReturn(false); when(player.hasPermission(anyString())).thenReturn(false);
uuid = UUID.randomUUID(); UUID uuid = UUID.randomUUID();
when(player.getUniqueId()).thenReturn(uuid); when(player.getUniqueId()).thenReturn(uuid);
s = mock(Sign.class); s = mock(Sign.class);
when(s.getLine(Mockito.anyInt())).thenReturn(ChatColor.GREEN + "[WELCOME]"); when(s.getLine(anyInt())).thenReturn(ChatColor.GREEN + "[WELCOME]");
when(block.getState()).thenReturn(s); when(block.getState()).thenReturn(s);
// warp signs manager // warp signs manager
when(addon.getWarpSignsManager()).thenReturn(wsm); when(addon.getWarpSignsManager()).thenReturn(wsm);
@ -130,7 +130,7 @@ public class WarpSignsListenerTest {
when(block.getLocation()).thenReturn(location); when(block.getLocation()).thenReturn(location);
list.put(uuid, location); list.put(uuid, location);
// Player is in world // Player is in world
when(wsm.getWarpMap(Mockito.eq(world))).thenReturn(list); when(wsm.getWarpMap(world)).thenReturn(list);
//Player has a warp sign already here //Player has a warp sign already here
when(wsm.getWarp(any(), any())).thenReturn(location); when(wsm.getWarp(any(), any())).thenReturn(location);
// Unique spot // Unique spot
@ -140,12 +140,7 @@ public class WarpSignsListenerTest {
when(addon.getPlugin()).thenReturn(plugin); when(addon.getPlugin()).thenReturn(plugin);
User.setPlugin(plugin); User.setPlugin(plugin);
LocalesManager lm = mock(LocalesManager.class); LocalesManager lm = mock(LocalesManager.class);
when(lm.get(any(), any())).thenAnswer(new Answer<String>(){ when(lm.get(any(), any())).thenReturn(null);
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
return invocation.getArgument(1, String.class);
}});
when(plugin.getLocalesManager()).thenReturn(lm); when(plugin.getLocalesManager()).thenReturn(lm);
// Lines // Lines
@ -155,6 +150,9 @@ public class WarpSignsListenerTest {
when(settings.getWelcomeLine()).thenReturn("[WELCOME]"); when(settings.getWelcomeLine()).thenReturn("[WELCOME]");
when(addon.getSettings()).thenReturn(settings); when(addon.getSettings()).thenReturn(settings);
island = mock(Island.class);
when(im.getIslandAt(any())).thenReturn(Optional.of(island));
// On island // On island
when(plugin.getIslands()).thenReturn(im); when(plugin.getIslands()).thenReturn(im);
when(im.userIsOnIsland(any(World.class), any(User.class))).thenReturn(true); when(im.userIsOnIsland(any(World.class), any(User.class))).thenReturn(true);
@ -167,12 +165,15 @@ public class WarpSignsListenerTest {
when(iwm.getAddon(any())).thenReturn(Optional.empty()); when(iwm.getAddon(any())).thenReturn(Optional.empty());
when(iwm.inWorld(any(World.class))).thenReturn(true); when(iwm.inWorld(any(World.class))).thenReturn(true);
Answer<String> answer = invocation -> invocation.getArgument(1, String.class);
// Util // Util
PowerMockito.mockStatic(Util.class); PowerMockito.mockStatic(Util.class);
when(Util.getWorld(any())).thenReturn(world); 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 // Locales
Answer<String> answer = invocation -> invocation.getArgument(1, String.class);
when(lm.get(any(User.class), anyString())).thenAnswer(answer); when(lm.get(any(User.class), anyString())).thenAnswer(answer);
when(plugin.getLocalesManager()).thenReturn(lm); when(plugin.getLocalesManager()).thenReturn(lm);
@ -204,7 +205,7 @@ public class WarpSignsListenerTest {
when(addon.inRegisteredWorld(any())).thenReturn(false); when(addon.inRegisteredWorld(any())).thenReturn(false);
wsl.onSignBreak(e); wsl.onSignBreak(e);
assertFalse(e.isCancelled()); assertFalse(e.isCancelled());
verify(addon).inRegisteredWorld(Mockito.eq(world)); verify(addon).inRegisteredWorld(world);
} }
@Test @Test
@ -214,7 +215,7 @@ public class WarpSignsListenerTest {
when(s.getLine(Mockito.anyInt())).thenReturn(ChatColor.RED + "[WELCOME]"); when(s.getLine(Mockito.anyInt())).thenReturn(ChatColor.RED + "[WELCOME]");
wsl.onSignBreak(e); wsl.onSignBreak(e);
assertFalse(e.isCancelled()); assertFalse(e.isCancelled());
verify(s).getLine(Mockito.eq(0)); verify(s).getLine(0);
verify(settings).getWelcomeLine(); verify(settings).getWelcomeLine();
} }
@ -227,7 +228,7 @@ public class WarpSignsListenerTest {
when(s.getLocation()).thenReturn(mock(Location.class)); when(s.getLocation()).thenReturn(mock(Location.class));
wsl.onSignBreak(e); wsl.onSignBreak(e);
assertFalse(e.isCancelled()); assertFalse(e.isCancelled());
verify(wsm).getWarpMap(Mockito.eq(world)); verify(wsm).getWarpMap(world);
verify(s).getLocation(); verify(s).getLocation();
} }
@ -287,7 +288,7 @@ public class WarpSignsListenerTest {
SignChangeEvent e = new SignChangeEvent(block, player, lines); SignChangeEvent e = new SignChangeEvent(block, player, lines);
when(addon.inRegisteredWorld(any())).thenReturn(false); when(addon.inRegisteredWorld(any())).thenReturn(false);
wsl.onSignWarpCreate(e); wsl.onSignWarpCreate(e);
verify(addon).inRegisteredWorld(Mockito.eq(world)); verify(addon).inRegisteredWorld(world);
} }
@Test @Test
@ -303,6 +304,54 @@ public class WarpSignsListenerTest {
assertEquals(ChatColor.GREEN + "[WELCOME]", e.getLine(0)); 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 @Test
public void testOnCreateNotGameWorldNotAllowed() { public void testOnCreateNotGameWorldNotAllowed() {
when(settings.isAllowInOtherWorlds()).thenReturn(false); when(settings.isAllowInOtherWorlds()).thenReturn(false);