Compare commits
316 Commits
Author | SHA1 | Date |
---|---|---|
Minecraft_15 | 7e8392d4f0 | |
tastybento | 00f6fee1bf | |
tastybento | f2da5ba104 | |
tastybento | c3e03a4f59 | |
tastybento | 7a241f898d | |
tastybento | d37f9ddcdd | |
tastybento | 0bb6eacaf7 | |
tastybento | 5dee0d2426 | |
tastybento | 1369ffb8c8 | |
tastybento | e2cbd18f17 | |
tastybento | 4d16e9c227 | |
tastybento | a4f8d12138 | |
Huynh Tien | 1bd6219f94 | |
add5tar | 2d1f618676 | |
tastybento | 774bbd034c | |
tastybento | 02a19d1bdb | |
tastybento | 952a2a6e81 | |
tastybento | 3061e80097 | |
tastybento | 79f988f460 | |
tastybento | ae030eb548 | |
tastybento | 76e0bad88a | |
tastybento | 2b373f62d9 | |
tastybento | 5f83a81f18 | |
tastybento | 82174649b4 | |
tastybento | cec620162b | |
gitlocalize-app[bot] | cfb35909f0 | |
tastybento | 117d15f3d0 | |
tastybento | 9d1a5c7476 | |
tastybento | 26d4839f6a | |
tastybento | 43c898ecf7 | |
tastybento | 77884f0a11 | |
tastybento | 1a4077be8c | |
tastybento | 3a3c8a320c | |
tastybento | eb71b35c5c | |
tastybento | cdd4366a2a | |
tastybento | 8f567cc328 | |
PapiCapi | 913eed9c77 | |
tastybento | 2b0a6d82ef | |
tastybento | a3537f5b80 | |
tastybento | 1b02f11220 | |
tastybento | 0c42ad866a | |
tastybento | deb09992f1 | |
tastybento | f87603de83 | |
tastybento | 1b20605791 | |
gitlocalize-app[bot] | 951b0f5549 | |
gitlocalize-app[bot] | 30217ba509 | |
gitlocalize-app[bot] | f8d50a43d6 | |
gitlocalize-app[bot] | dfd30d148b | |
tastybento | 5a66bf162b | |
tastybento | ad3d02c29a | |
tastybento | 34b2b52979 | |
tastybento | 95c9e55cfe | |
tastybento | 3c79c68e80 | |
BONNe | 78c67b6d2f | |
ceze88 | 9c42a8d007 | |
tastybento | c093796a6e | |
tastybento | 713a409584 | |
tastybento | 0cdb15403b | |
DevSolaris | a493c12f6e | |
tastybento | 42249a8fc9 | |
tastybento | f469e37702 | |
gitlocalize-app[bot] | 29b148052a | |
gitlocalize-app[bot] | f1db2a9284 | |
tastybento | dc9d460e1e | |
evlad | fba73948c6 | |
tastybento | ac6bead52e | |
tastybento | 93869cb34a | |
tastybento | f3ee8a381c | |
tastybento | 3988659dcc | |
tastybento | 51338d280d | |
gitlocalize-app[bot] | 97d9522563 | |
gitlocalize-app[bot] | 32690630d6 | |
BONNe | 2ca4e0a070 | |
BONNe | dae3db6c98 | |
DeadSilenceIV | 90ae98e599 | |
BONNe | 47053fde31 | |
KrazyxWolf | cc90579f51 | |
BONNe | 1914fc11e0 | |
BONNe | 4948689fe8 | |
tastybento | fcf6e76599 | |
tastybento | d9288c7e61 | |
BONNe | eb8c105be5 | |
BONNe | 15ff515078 | |
BONNe | 43fcde5781 | |
BONNe | e16fad882e | |
tastybento | 0a79b7fa58 | |
tastybento | 5d9aa00c13 | |
tastybento | 490fe6c942 | |
tastybento | 336e8d47bf | |
tastybento | a3d06ee41a | |
gitlocalize-app[bot] | 6f174e2b3a | |
gitlocalize-app[bot] | 322ea825ea | |
gitlocalize-app[bot] | 488c6ac9d3 | |
gitlocalize-app[bot] | 840a8c1d79 | |
gitlocalize-app[bot] | 34da24d719 | |
gitlocalize-app[bot] | cbaf14e5f0 | |
tastybento | 185fc91342 | |
tastybento | 7e92a45736 | |
tastybento | 5ce71798a6 | |
Pierre Dedrie | 4a21e4b30c | |
tastybento | b534eb70d4 | |
tastybento | 50074ac1df | |
Rubén | cc977d8562 | |
Huynh Tien | 4de5b80ab4 | |
tastybento | 893d8d46a0 | |
tastybento | b1d117d344 | |
tastybento | 11618085ff | |
tastybento | 750f07ba7c | |
tastybento | 60f2a268b9 | |
tastybento | 4c59d4d4ae | |
tastybento | 9b8bbdac5f | |
tastybento | d212fcee99 | |
tastybento | 1b29f7f6ac | |
tastybento | b16d458cae | |
tastybento | 4a4794f771 | |
tastybento | 7b6f921b10 | |
tastybento | bd6c264f4d | |
tastybento | d55f66f868 | |
tastybento | 76a2688556 | |
tastybento | 4661bcd109 | |
tastybento | 383ede3d59 | |
tastybento | 0ce89dea7f | |
tastybento | 389d06d0a2 | |
tastybento | 9b7557f470 | |
tastybento | fa0e6cb85f | |
tastybento | 7379f6c3e8 | |
tastybento | 54ac6f5499 | |
tastybento | 3892da597c | |
tastybento | 452bf88197 | |
tastybento | 1246496373 | |
tastybento | 7265b5ae16 | |
tastybento | fb60dbddf9 | |
tastybento | 04596915ce | |
tastybento | eba7e1d531 | |
tastybento | e0736fca4c | |
tastybento | 33a3425619 | |
tastybento | 9bff48b7b0 | |
tastybento | fdf5da43c6 | |
tastybento | f2b3903c6f | |
tastybento | ff670c04d8 | |
tastybento | 5452b3a9d9 | |
tastybento | 39423508b9 | |
tastybento | 6dc8aa7f09 | |
tastybento | 12525271c8 | |
tastybento | 311455e921 | |
tastybento | e002ade414 | |
tastybento | 52ee81501b | |
tastybento | 49c7d8a09e | |
tastybento | d9137e83ed | |
tastybento | cb9a49d6ec | |
tastybento | 01004e00ac | |
Alberto | aeb48c6f3e | |
Alberto | 25ba4dc7eb | |
tastybento | 4b196f4f31 | |
tastybento | 7973ef1154 | |
Andrzej | bd31363b34 | |
gitlocalize-app[bot] | ff1f813751 | |
gitlocalize-app[bot] | ac601d438d | |
tastybento | e2d3150fa2 | |
tastybento | bfed6c75eb | |
tastybento | 920f3675f7 | |
tastybento | 0d1a10ff6f | |
tastybento | b5e161d59e | |
tastybento | aed06b74c0 | |
tastybento | 5485627376 | |
tastybento | 732d2ea039 | |
tastybento | 4efc5cbc06 | |
tastybento | 8f85e90830 | |
tastybento | 284f18c680 | |
tastybento | 6c168731d8 | |
tastybento | 000463e10c | |
tastybento | 49e56b515a | |
tastybento | 9b1e24810a | |
tastybento | dab0e84bc0 | |
tastybento | 507cefd128 | |
tastybento | 811918eec6 | |
tastybento | 6800bdd3ce | |
tastybento | ee4c6ef02c | |
tastybento | 3cc887b6d3 | |
tastybento | 35da2246c5 | |
tastybento | 6160a3acee | |
tastybento | 5e56943c63 | |
tastybento | 52a5da55bd | |
tastybento | 9fb7d7897d | |
tastybento | 6efa22e77f | |
tastybento | ad69385607 | |
tastybento | 45577e446f | |
tastybento | 85cd89bdf7 | |
tastybento | 7f75caab36 | |
tastybento | fb765561af | |
tastybento | 39e294eaf6 | |
tastybento | ee5217519a | |
tastybento | 3c1cdaafab | |
tastybento | 66b098ec73 | |
tastybento | 071d3d06d5 | |
tastybento | f0e983db44 | |
tastybento | baf0ba0974 | |
tastybento | 631b664059 | |
tastybento | 854638be89 | |
tastybento | 256c0f1aea | |
tastybento | 1a7d48a0ec | |
tastybento | a6be22bfe5 | |
tastybento | 73fad8a808 | |
tastybento | 56530cecc1 | |
tastybento | d5c4e3a53c | |
tastybento | 08b7c99c3f | |
tastybento | c19ae41cbb | |
tastybento | f78b2c8231 | |
tastybento | 0a768b0648 | |
tastybento | b92d412f0a | |
tastybento | 0a4b0af931 | |
tastybento | 8788110a92 | |
tastybento | b2811edf99 | |
Krystian | fb8377f67b | |
tastybento | a5abd10678 | |
tastybento | fe6ad81141 | |
tastybento | c463170fdd | |
tastybento | 6e64d274e8 | |
tastybento | 5f5d2542d2 | |
tastybento | d06d6883f4 | |
tastybento | e93e606b02 | |
tastybento | 95875b10ec | |
tastybento | 40681190c1 | |
tastybento | b3b6502ef3 | |
tastybento | 82cbb487de | |
tastybento | dad302a5fe | |
tastybento | 21c4737446 | |
Dalton Burchard | f779f0ca95 | |
tastybento | 1de94afe7e | |
tastybento | b6f4c15469 | |
tastybento | fe0f084781 | |
tastybento | ccc3ef65be | |
DuckSoft | 4bf86bb07f | |
gitlocalize-app[bot] | c06e69e1b5 | |
tastybento | d8b838cc36 | |
tastybento | 187e491bea | |
tastybento | 1791108ef6 | |
Florian CUNY | 816a077ddd | |
Gabriele C | 3edb12581d | |
tastybento | eba6e11ec9 | |
tastybento | 09583aa3a7 | |
tastybento | 5c9c84c98a | |
tastybento | 002da7594f | |
tastybento | dab37e6af4 | |
tastybento | 1a9cd23205 | |
tastybento | c8c7bef765 | |
András Marczinkó | 61d3fb5779 | |
Florian CUNY | cc1cca1453 | |
Florian CUNY | dae58b8dff | |
Florian CUNY | 801bfe6a39 | |
Florian CUNY | 8181fbc431 | |
Florian CUNY | f97a252840 | |
tastybento | 67535ddec8 | |
Josh | 0eb3881a56 | |
tastybento | a83e119b00 | |
tastybento | 43a8cb4153 | |
tastybento | 7803e71a7c | |
tastybento | b3d82a6456 | |
gitlocalize-app[bot] | 2cea8e942f | |
gitlocalize-app[bot] | 9066c8ddf2 | |
tastybento | 1282cb95b5 | |
tastybento | 255711afa4 | |
tastybento | 05437ca14a | |
tastybento | d227606f7a | |
tastybento | 7ef2e35d92 | |
tastybento | d6117e69d8 | |
tastybento | 838507cc4a | |
tastybento | d4c9bd654d | |
tastybento | e383f79e3e | |
tastybento | 4e33df1927 | |
tastybento | 55f6a124bf | |
tastybento | 91a69adae1 | |
tastybento | a443e434f9 | |
tastybento | c7f597e2ac | |
tastybento | 10a7b451ba | |
tastybento | 62bf2a6e88 | |
tastybento | dda2e66548 | |
tastybento | 01dd6597d4 | |
tastybento | 1f8accedc5 | |
tastybento | ca46b3c107 | |
tastybento | 62f65e23ac | |
tastybento | 737df3b778 | |
tastybento | bdb319b8a1 | |
Florian CUNY | e428d52a45 | |
Florian CUNY | 407c2640f1 | |
tastybento | 960f5cbe78 | |
tastybento | 94114c65e1 | |
tastybento | 8e2f4a4b5e | |
tastybento | 378a855bde | |
tastybento | cc93175098 | |
BONNe | 0bd5bd4d10 | |
BONNe | 7e29ba3ade | |
tastybento | dc97ddcccd | |
tastybento | 39de2b9cc8 | |
tastybento | d49859bc78 | |
tastybento | ef81d6c985 | |
tastybento | d5e5410b6c | |
tastybento | 8e837857c0 | |
tastybento | c4a8e6914b | |
tastybento | 904522367d | |
tastybento | 76cfc506fb | |
tastybento | cb2ea7dc5b | |
tastybento | c0bcb8db93 | |
tastybento | b950177ead | |
BONNe | f0b6194444 | |
tastybento | da83f66f8c | |
tastybento | 4fe46bd1a9 | |
tastybento | 5adf2a3ef9 | |
tastybento | 908027e6ba | |
tastybento | 1e1e53cf57 | |
tastybento | d811b30d3f | |
tastybento | 33f1a0dfb8 | |
tastybento | 392e22e366 | |
Pierre LAGOUTTE | f83d2ddddd | |
tastybento | 6415efee28 | |
tastybento | 671e17398e |
|
@ -1,33 +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:**
|
||||
|
||||
[Please complete the following information:]
|
||||
- Database being used (YAML, JSON, MySQL, MongoDB): []
|
||||
- OS: [e.g. iOS]
|
||||
- Java Version: [e.g. Java 8]
|
||||
- BentoBox version: [e.g. 1.7.2.21]
|
||||
- Addons installed? [Do '/bentobox version' and copy/paste from the console]
|
||||
- Other plugins? [Do '/plugins' and copy/paste from the console]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
|
@ -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.
|
|
@ -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
|
|
@ -0,0 +1,88 @@
|
|||
# Git
|
||||
*.orig
|
||||
!.gitignore
|
||||
/.settings/
|
||||
|
||||
# Windows
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
*.stackdump
|
||||
[Dd]esktop.ini
|
||||
$RECYCLE.BIN/
|
||||
*.lnk
|
||||
|
||||
# Linux
|
||||
*~
|
||||
.fuse_hidden*
|
||||
.directory
|
||||
.Trash-*
|
||||
.nfs*
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
._*
|
||||
|
||||
# Java
|
||||
*.class
|
||||
*.log
|
||||
*.ctxt
|
||||
.mtj.tmp/
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
hs_err_pid*
|
||||
|
||||
# Maven
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
|
||||
# Intellij
|
||||
*.iml
|
||||
*.java___jb_tmp___
|
||||
.idea/*
|
||||
*.ipr
|
||||
*.iws
|
||||
/out/
|
||||
.idea_modules/
|
||||
|
||||
# Eclipse
|
||||
*.pydevproject
|
||||
.metadata
|
||||
.gradle
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.settings/
|
||||
.loadpath
|
||||
.project
|
||||
.externalToolBuilders/
|
||||
*.launch
|
||||
.cproject
|
||||
.classpath
|
||||
.buildpath
|
||||
.target
|
||||
|
||||
# NetBeans
|
||||
nbproject/private/
|
||||
build/
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
nbactions.xml
|
||||
nb-configuration.xml
|
||||
.nb-gradle/
|
||||
/.idea/
|
20
.travis.yml
20
.travis.yml
|
@ -1,20 +0,0 @@
|
|||
language: java
|
||||
sudo: false
|
||||
addons:
|
||||
sonarcloud:
|
||||
organization: "tastybento-github"
|
||||
token:
|
||||
secure: $SONAR_TOKEN
|
||||
branches:
|
||||
- develop
|
||||
- master
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
|
||||
script:
|
||||
- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package -P sonar sonar:sonar -B
|
||||
- echo "${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}"
|
||||
cache:
|
||||
directories:
|
||||
- '$HOME/.m2/repository'
|
||||
- '$HOME/.sonar/cache'
|
41
README.md
41
README.md
|
@ -1,7 +1,19 @@
|
|||
# Level
|
||||
Add-on for BentoBox to calculate island levels for BSkyBlock and AcidIsland. This add-on will work
|
||||
[![Build Status](https://ci.codemc.org/buildStatus/icon?job=BentoBoxWorld/Level)](https://ci.codemc.org/job/BentoBoxWorld/job/Level/)[
|
||||
![Bugs](https://sonarcloud.io/api/project_badges/measure?project=BentoBoxWorld_Level&metric=bugs)](https://sonarcloud.io/dashboard?id=BentoBoxWorld_Level)
|
||||
[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=BentoBoxWorld_Level&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=BentoBoxWorld_Level)
|
||||
[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=BentoBoxWorld_Level&metric=ncloc)](https://sonarcloud.io/dashboard?id=BentoBoxWorld_Level)
|
||||
|
||||
## About
|
||||
|
||||
Add-on for BentoBox to calculate island levels for BentoBox game modes like BSkyBlock and AcidIsland. It counts blocks and assigns a value to them.
|
||||
Players gain levels by accumulating points and can lose levels too if their points go down. This add-on will work
|
||||
for game modes listed in the config.yml.
|
||||
|
||||
Full documentation for Level can be found at [docs.bentobox.world](https://docs.bentobox.world/en/latest/addons/Level/).
|
||||
|
||||
Official download releases are at [download.bentobox.world](download.bentobox.world).
|
||||
|
||||
## How to use
|
||||
|
||||
1. Place the level addon jar in the addons folder of the BentoBox plugin
|
||||
|
@ -14,6 +26,31 @@ for game modes listed in the config.yml.
|
|||
|
||||
1. Read the release notes carefully, but you may have to delete the old config.yml to use a new one.
|
||||
|
||||
## Permissions
|
||||
Permissions are given automatically to players as listed below for BSkyBlock, AcidIsland and CaveBlock. If your permissions plugin strips permissions then you may have to allocate these manually. Note that if a player doesn't have the `intopten` permission, they will not be listed in the top ten.
|
||||
|
||||
```
|
||||
permissions:
|
||||
bskyblock.intopten:
|
||||
description: Player is in the top ten.
|
||||
default: true
|
||||
bskyblock.island.level:
|
||||
description: Player can use level command
|
||||
default: true
|
||||
bskyblock.island.top:
|
||||
description: Player can use top ten command
|
||||
default: true
|
||||
bskyblock.island.value:
|
||||
description: Player can use value command
|
||||
default: true
|
||||
bskyblock.admin.level:
|
||||
description: Player can use admin level command
|
||||
default: true
|
||||
bskyblock.admin.topten:
|
||||
description: Player can use admin top ten command
|
||||
default: true
|
||||
```
|
||||
|
||||
## Config.yml
|
||||
|
||||
The config.yml has the following sections:
|
||||
|
@ -34,7 +71,7 @@ This section defines a number of overall settings for the add-on.
|
|||
|
||||
* Underwater block multiplier - default value = 1. If this value is > 1 then blocks below sea level will have a greater value.
|
||||
* Level cost - Value of one island level. Default 100. Minimum value is 1.
|
||||
* Level wait - Cooldown between level requests in seconds
|
||||
* Level wait - Cool down between level requests in seconds
|
||||
* Death penalty - How many block values a player will lose per death. Default value of 100 means that for every death, the player will lose 1 level (if levelcost is 100)
|
||||
* Sum Team Deaths - if true, all the team member deaths are summed. If false, only the leader's deaths counts.
|
||||
* Max deaths - If player dies more than this, it doesn't count anymore.
|
||||
|
|
604
pom.xml
604
pom.xml
|
@ -1,185 +1,445 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>world.bentobox</groupId>
|
||||
<artifactId>level</artifactId>
|
||||
<version>1.5.0-SNAPSHOT</version>
|
||||
<groupId>world.bentobox</groupId>
|
||||
<artifactId>level</artifactId>
|
||||
<version>${revision}</version>
|
||||
|
||||
<name>Level</name>
|
||||
<description>Level is an add-on for BentoBox, an expandable Minecraft Bukkit plugin for island-type games like SkyBlock or AcidIsland.</description>
|
||||
<url>https://github.com/BentoBoxWorld/Level</url>
|
||||
<inceptionYear>2017</inceptionYear>
|
||||
<name>Level</name>
|
||||
<description>Level is an add-on for BentoBox, an expandable Minecraft Bukkit plugin for island-type games like SkyBlock or AcidIsland.</description>
|
||||
<url>https://github.com/BentoBoxWorld/Level</url>
|
||||
<inceptionYear>2017</inceptionYear>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:https://github.com/BentoBoxWorld/Level.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:BentoBoxWorld/Level.git</developerConnection>
|
||||
<url>https://github.com/BentoBoxWorld/Level</url>
|
||||
</scm>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>tastybento</id>
|
||||
<email>tastybento@bentobox.world</email>
|
||||
<timezone>-8</timezone>
|
||||
<roles>
|
||||
<role>Lead Developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<ciManagement>
|
||||
<system>jenkins</system>
|
||||
<url>http://ci.codemc.org/job/BentoBoxWorld/job/Level</url>
|
||||
</ciManagement>
|
||||
<scm>
|
||||
<connection>scm:git:https://github.com/BentoBoxWorld/Level.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:BentoBoxWorld/Level.git</developerConnection>
|
||||
<url>https://github.com/BentoBoxWorld/Level</url>
|
||||
</scm>
|
||||
|
||||
<issueManagement>
|
||||
<system>GitHub</system>
|
||||
<url>https://github.com/BentoBoxWorld/Level/issues</url>
|
||||
</issueManagement>
|
||||
<ciManagement>
|
||||
<system>jenkins</system>
|
||||
<url>http://ci.codemc.org/job/BentoBoxWorld/job/Level</url>
|
||||
</ciManagement>
|
||||
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>codemc-snapshots</id>
|
||||
<url>https://repo.codemc.org/repository/maven-snapshots</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>codemc-releases</id>
|
||||
<url>https://repo.codemc.org/repository/maven-releases</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
<issueManagement>
|
||||
<system>GitHub</system>
|
||||
<url>https://github.com/BentoBoxWorld/Level/issues</url>
|
||||
</issueManagement>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<powermock.version>1.7.4</powermock.version>
|
||||
</properties>
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>codemc-snapshots</id>
|
||||
<url>https://repo.codemc.org/repository/maven-snapshots</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>codemc-releases</id>
|
||||
<url>https://repo.codemc.org/repository/maven-releases</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>codemc-repo</id>
|
||||
<url>https://repo.codemc.org/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>codemc-public</id>
|
||||
<url>https://repo.codemc.org/repository/maven-public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
<!-- Non-minecraft related dependencies -->
|
||||
<powermock.version>2.0.9</powermock.version>
|
||||
<!-- More visible way how to change dependency versions -->
|
||||
<spigot.version>1.20.4-R0.1-SNAPSHOT</spigot.version>
|
||||
<bentobox.version>2.4.0-SNAPSHOT</bentobox.version>
|
||||
<!-- Warps addon version -->
|
||||
<warps.version>1.12.0</warps.version>
|
||||
<!-- Visit addon version -->
|
||||
<visit.version>1.6.0</visit.version>
|
||||
<!-- Panel Utils version -->
|
||||
<panelutils.version>1.1.0</panelutils.version>
|
||||
<!-- Revision variable removes warning about dynamic version -->
|
||||
<revision>${build.version}-SNAPSHOT</revision>
|
||||
<!-- Do not change unless you want different name for local builds. -->
|
||||
<build.number>-LOCAL</build.number>
|
||||
<!-- This allows to change between versions. -->
|
||||
<build.version>2.14.0</build.version>
|
||||
<sonar.projectKey>BentoBoxWorld_Level</sonar.projectKey>
|
||||
<sonar.organization>bentobox-world</sonar.organization>
|
||||
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.14.1-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>${powermock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito</artifactId>
|
||||
<version>${powermock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>world.bentobox</groupId>
|
||||
<artifactId>bentobox</artifactId>
|
||||
<version>1.5.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<!-- Profiles will allow to automatically change build version. -->
|
||||
<profiles>
|
||||
<profile>
|
||||
<!-- ci profile is activated if exist environment variable BUILD_NUMBER. -->
|
||||
<!-- It replaces ${build.number} that is currently '-LOCAL' with
|
||||
correct build number from JENKINS machine. -->
|
||||
<id>ci</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>env.BUILD_NUMBER</name>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<!-- Override only if necessary -->
|
||||
<build.number>-b${env.BUILD_NUMBER}</build.number>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- Master profile is activated if exist environment variable
|
||||
GIT_BRANCH and its value is origin/master. -->
|
||||
<!-- It will replace 'revision' with '${build.version}' so it
|
||||
removes '-SNAPSHOT' string at the end. -->
|
||||
<!-- Also, as this is release build, build number can be set
|
||||
to empty string. -->
|
||||
<!-- This profile will be used only if exist environment variable
|
||||
GIT_BRANCH with value origin/master. -->
|
||||
<id>master</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>env.GIT_BRANCH</name>
|
||||
<value>origin/master</value>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<!-- Override only if necessary -->
|
||||
<revision>${build.version}</revision>
|
||||
<!-- Empties build number variable. -->
|
||||
<build.number></build.number>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<defaultGoal>clean package</defaultGoal>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources/locales</directory>
|
||||
<targetPath>./locales</targetPath>
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<configuration>
|
||||
<show>public</show>
|
||||
<failOnError>false</failOnError>
|
||||
<additionalJOption>-Xdoclint:none</additionalJOption>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>apache.snapshots</id>
|
||||
<url>https://repository.apache.org/snapshots/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
</project>
|
||||
<repositories>
|
||||
<!--Wild Stacker repo -->
|
||||
<repository>
|
||||
<id>bg-repo</id>
|
||||
<url>https://repo.bg-software.com/repository/api/</url>
|
||||
</repository>
|
||||
<!-- RoseStacker repo -->
|
||||
<repository>
|
||||
<id>rosewood-repo</id>
|
||||
<url>https://repo.rosewooddev.io/repository/public/</url>
|
||||
</repository>
|
||||
<!-- UltimateStacker repo -->
|
||||
<repository>
|
||||
<id>songoda-plugins</id>
|
||||
<url>https://repo.songoda.com/repository/minecraft-plugins/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>codemc-repo</id>
|
||||
<url>https://repo.codemc.org/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>codemc-public</id>
|
||||
<url>https://repo.codemc.org/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spigot API -->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>${spigot.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Mockito (Unit testing) -->
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>3.11.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>${powermock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito2</artifactId>
|
||||
<version>${powermock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>world.bentobox</groupId>
|
||||
<artifactId>bentobox</artifactId>
|
||||
<version>${bentobox.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>world.bentobox</groupId>
|
||||
<artifactId>warps</artifactId>
|
||||
<version>${warps.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>world.bentobox</groupId>
|
||||
<artifactId>visit</artifactId>
|
||||
<version>${visit.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>lv.id.bonne</groupId>
|
||||
<artifactId>panelutils</artifactId>
|
||||
<version>${panelutils.version}</version>
|
||||
</dependency>
|
||||
<!-- Wild Stacker dependency -->
|
||||
<dependency>
|
||||
<groupId>com.bgsoftware</groupId>
|
||||
<artifactId>WildStackerAPI</artifactId>
|
||||
<version>2023.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Static analysis -->
|
||||
<!-- We are using Eclipse's annotations. If you're using IDEA, update
|
||||
your project settings to take these into account for in real time static
|
||||
analysis -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jdt</groupId>
|
||||
<artifactId>org.eclipse.jdt.annotation</artifactId>
|
||||
<version>2.2.600</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.DeadSilenceIV</groupId>
|
||||
<artifactId>AdvancedChestsAPI</artifactId>
|
||||
<version>2.9-BETA</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.rosewood</groupId>
|
||||
<artifactId>rosestacker</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Ultimate Stacker dependency -->
|
||||
<dependency>
|
||||
<groupId>com.craftaro</groupId>
|
||||
<artifactId>UltimateStacker-API</artifactId>
|
||||
<version>1.0.0-20240329.173606-35</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<!-- By default ${revision} is ${build.version}-SNAPSHOT -->
|
||||
<!-- If GIT_BRANCH variable is set to origin/master, then it will
|
||||
be only ${build.version}. -->
|
||||
|
||||
<!-- By default ${build.number} is -LOCAL. -->
|
||||
<!-- If the BUILD_NUMBER variable is set, then it will be -b[number]. -->
|
||||
<!-- If GIT_BRANCH variable is set to origin/master, then it will
|
||||
be the empty string. -->
|
||||
<finalName>${project.name}-${revision}${build.number}</finalName>
|
||||
|
||||
<defaultGoal>clean package</defaultGoal>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources/locales</directory>
|
||||
<targetPath>./locales</targetPath>
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<configuration>
|
||||
<release>${java.version}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M5</version>
|
||||
<configuration>
|
||||
<argLine>
|
||||
${argLine}
|
||||
--add-opens java.base/java.lang=ALL-UNNAMED
|
||||
--add-opens java.base/java.math=ALL-UNNAMED
|
||||
--add-opens java.base/java.io=ALL-UNNAMED
|
||||
--add-opens java.base/java.util=ALL-UNNAMED
|
||||
--add-opens
|
||||
java.base/java.util.stream=ALL-UNNAMED
|
||||
--add-opens java.base/java.text=ALL-UNNAMED
|
||||
--add-opens
|
||||
java.base/java.util.regex=ALL-UNNAMED
|
||||
--add-opens
|
||||
java.base/java.nio.channels.spi=ALL-UNNAMED
|
||||
--add-opens java.base/sun.nio.ch=ALL-UNNAMED
|
||||
--add-opens java.base/java.net=ALL-UNNAMED
|
||||
--add-opens
|
||||
java.base/java.util.concurrent=ALL-UNNAMED
|
||||
--add-opens java.base/sun.nio.fs=ALL-UNNAMED
|
||||
--add-opens java.base/sun.nio.cs=ALL-UNNAMED
|
||||
--add-opens java.base/java.nio.file=ALL-UNNAMED
|
||||
--add-opens
|
||||
java.base/java.nio.charset=ALL-UNNAMED
|
||||
--add-opens
|
||||
java.base/java.lang.reflect=ALL-UNNAMED
|
||||
--add-opens
|
||||
java.logging/java.util.logging=ALL-UNNAMED
|
||||
--add-opens java.base/java.lang.ref=ALL-UNNAMED
|
||||
--add-opens java.base/java.util.jar=ALL-UNNAMED
|
||||
--add-opens java.base/java.util.zip=ALL-UNNAMED
|
||||
</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<configuration>
|
||||
<doclint>none</doclint> <!-- Turnoff all checks -->
|
||||
<failOnError>false</failOnError>
|
||||
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
|
||||
<source>17</source>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.3.1-SNAPSHOT</version>
|
||||
<configuration>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>lv.id.bonne:panelutils:*</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<transformers>
|
||||
<!-- Add a transformer to exclude any other manifest files (possibly from dependencies). -->
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
|
||||
<resource>MANIFEST.MF</resource>
|
||||
</transformer>
|
||||
<!-- Add a transformer to include your custom manifest file. -->
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
|
||||
<resource>META-INF/MANIFEST.MF</resource>
|
||||
<file>src/main/resources/META-INF/MANIFEST.MF</file>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.10</version>
|
||||
<configuration>
|
||||
<append>true</append>
|
||||
<excludes>
|
||||
<!-- This is required to prevent Jacoco from adding
|
||||
synthetic fields to a JavaBean class (causes errors in testing) -->
|
||||
<exclude>**/*Names*</exclude>
|
||||
<!-- Prevents the Material is too large to mock error -->
|
||||
<exclude>org/bukkit/Material*</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<formats>
|
||||
<format>XML</format>
|
||||
</formats>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -1,223 +1,451 @@
|
|||
package world.bentobox.level;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import world.bentobox.bentobox.api.addons.Addon;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.configuration.Config;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.Database;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.level.commands.admin.AdminLevelCommand;
|
||||
import world.bentobox.level.commands.admin.AdminTopCommand;
|
||||
import world.bentobox.level.commands.island.IslandLevelCommand;
|
||||
import world.bentobox.level.commands.island.IslandTopCommand;
|
||||
import world.bentobox.level.commands.island.IslandValueCommand;
|
||||
import world.bentobox.level.config.Settings;
|
||||
import world.bentobox.level.listeners.IslandTeamListeners;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
import world.bentobox.level.calculators.Pipeliner;
|
||||
import world.bentobox.level.commands.AdminLevelCommand;
|
||||
import world.bentobox.level.commands.AdminLevelStatusCommand;
|
||||
import world.bentobox.level.commands.AdminSetInitialLevelCommand;
|
||||
import world.bentobox.level.commands.AdminStatsCommand;
|
||||
import world.bentobox.level.commands.AdminTopCommand;
|
||||
import world.bentobox.level.commands.IslandLevelCommand;
|
||||
import world.bentobox.level.commands.IslandTopCommand;
|
||||
import world.bentobox.level.commands.IslandValueCommand;
|
||||
import world.bentobox.level.config.BlockConfig;
|
||||
import world.bentobox.level.config.ConfigSettings;
|
||||
import world.bentobox.level.listeners.IslandActivitiesListeners;
|
||||
import world.bentobox.level.listeners.JoinLeaveListener;
|
||||
import world.bentobox.level.listeners.MigrationListener;
|
||||
import world.bentobox.level.objects.LevelsData;
|
||||
import world.bentobox.level.placeholders.LevelPlaceholder;
|
||||
import world.bentobox.level.placeholders.TopTenNamePlaceholder;
|
||||
import world.bentobox.level.placeholders.TopTenPlaceholder;
|
||||
import world.bentobox.level.requests.LevelRequestHandler;
|
||||
import world.bentobox.level.requests.TopTenRequestHandler;
|
||||
|
||||
import world.bentobox.visit.VisitAddon;
|
||||
import world.bentobox.warps.Warp;
|
||||
|
||||
/**
|
||||
* Addon to BSkyBlock/AcidIsland that enables island level scoring and top ten functionality
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class Level extends Addon {
|
||||
|
||||
// Settings
|
||||
private Settings settings;
|
||||
// The 10 in top ten
|
||||
public static final int TEN = 10;
|
||||
|
||||
// Database handler for level data
|
||||
private Database<LevelsData> handler;
|
||||
// Settings
|
||||
private ConfigSettings settings;
|
||||
private Config<ConfigSettings> configObject = new Config<>(this, ConfigSettings.class);
|
||||
private BlockConfig blockConfig;
|
||||
private Pipeliner pipeliner;
|
||||
private LevelsManager manager;
|
||||
private boolean stackersEnabled;
|
||||
private boolean advChestEnabled;
|
||||
private boolean roseStackersEnabled;
|
||||
private boolean ultimateStackerEnabled;
|
||||
private final List<GameModeAddon> registeredGameModes = new ArrayList<>();
|
||||
|
||||
// A cache of island levels.
|
||||
private Map<UUID, LevelsData> levelsCache;
|
||||
/**
|
||||
* Local variable that stores if warpHook is present.
|
||||
*/
|
||||
private Warp warpHook;
|
||||
|
||||
// The Top Ten object
|
||||
private TopTen topTen;
|
||||
/**
|
||||
* Local variable that stores if visitHook is present.
|
||||
*/
|
||||
private VisitAddon visitHook;
|
||||
|
||||
// Level calculator
|
||||
private LevelPresenter levelCalc;
|
||||
@Override
|
||||
public void onLoad() {
|
||||
// Save the default config from config.yml
|
||||
saveDefaultConfig();
|
||||
if (loadSettings()) {
|
||||
// Disable
|
||||
logError("Level settings could not load! Addon disabled.");
|
||||
setState(State.DISABLED);
|
||||
} else {
|
||||
configObject.saveConfigObject(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a user's island
|
||||
* @param world - the world where this island is
|
||||
* @param user - the user who is asking, or null if none
|
||||
* @param playerUUID - the target island member's UUID
|
||||
*/
|
||||
public void calculateIslandLevel(World world, User user, UUID playerUUID) {
|
||||
levelCalc.calculateIslandLevel(world, user, playerUUID);
|
||||
}
|
||||
// Save existing panels.
|
||||
this.saveResource("panels/top_panel.yml", false);
|
||||
this.saveResource("panels/detail_panel.yml", false);
|
||||
this.saveResource("panels/value_panel.yml", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get level from cache for a player
|
||||
* @param targetPlayer - target player
|
||||
* @return Level of player
|
||||
*/
|
||||
public long getIslandLevel(World world, UUID targetPlayer) {
|
||||
LevelsData ld = getLevelsData(targetPlayer);
|
||||
return ld == null ? 0L : ld.getLevel(world);
|
||||
}
|
||||
private boolean loadSettings() {
|
||||
// Load settings again to get worlds
|
||||
settings = configObject.loadConfigObject();
|
||||
|
||||
/**
|
||||
* Load a player from the cache or database
|
||||
* @param targetPlayer - UUID of target player
|
||||
* @return LevelsData object or null if not found
|
||||
*/
|
||||
public LevelsData getLevelsData(UUID targetPlayer) {
|
||||
// Get from database if not in cache
|
||||
if (!levelsCache.containsKey(targetPlayer) && handler.objectExists(targetPlayer.toString())) {
|
||||
levelsCache.put(targetPlayer, handler.loadObject(targetPlayer.toString()));
|
||||
}
|
||||
// Return cached value or null
|
||||
return levelsCache.get(targetPlayer);
|
||||
}
|
||||
return settings == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the settings
|
||||
*/
|
||||
public final Settings getSettings() {
|
||||
return settings;
|
||||
}
|
||||
@Override
|
||||
public void onEnable() {
|
||||
loadBlockSettings();
|
||||
// Start pipeline
|
||||
pipeliner = new Pipeliner(this);
|
||||
// Start Manager
|
||||
manager = new LevelsManager(this);
|
||||
// Register listeners
|
||||
this.registerListener(new IslandActivitiesListeners(this));
|
||||
this.registerListener(new JoinLeaveListener(this));
|
||||
this.registerListener(new MigrationListener(this));
|
||||
|
||||
public TopTen getTopTen() {
|
||||
return topTen;
|
||||
}
|
||||
// Register commands for GameModes
|
||||
registeredGameModes.clear();
|
||||
getPlugin().getAddonsManager().getGameModeAddons().stream()
|
||||
.filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName())).forEach(gm -> {
|
||||
log("Level hooking into " + gm.getDescription().getName());
|
||||
registerCommands(gm);
|
||||
new PlaceholderManager(this).registerPlaceholders(gm);
|
||||
registeredGameModes.add(gm);
|
||||
});
|
||||
// Register request handlers
|
||||
registerRequestHandler(new LevelRequestHandler(this));
|
||||
registerRequestHandler(new TopTenRequestHandler(this));
|
||||
|
||||
@Override
|
||||
public void onDisable(){
|
||||
// Save the cache
|
||||
if (levelsCache != null) {
|
||||
save();
|
||||
}
|
||||
if (topTen != null) {
|
||||
topTen.saveTopTen();
|
||||
}
|
||||
}
|
||||
// Check if WildStackers is enabled on the server
|
||||
// I only added support for counting blocks into the island level
|
||||
// Someone else can PR if they want spawners added to the Leveling system :)
|
||||
if (!settings.getDisabledPluginHooks().contains("WildStacker")) {
|
||||
stackersEnabled = Bukkit.getPluginManager().isPluginEnabled("WildStacker");
|
||||
if (stackersEnabled) {
|
||||
log("Hooked into WildStackers.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
// Load the plugin's config
|
||||
settings = new Settings(this);
|
||||
// Get the BSkyBlock database
|
||||
// Set up the database handler to store and retrieve Island classes
|
||||
// Note that these are saved by the BSkyBlock database
|
||||
handler = new Database<>(this, LevelsData.class);
|
||||
// Initialize the cache
|
||||
levelsCache = new HashMap<>();
|
||||
// Load the calculator
|
||||
levelCalc = new LevelPresenter(this, this.getPlugin());
|
||||
// Start the top ten and register it for clicks
|
||||
topTen = new TopTen(this);
|
||||
registerListener(topTen);
|
||||
// Register commands for AcidIsland and BSkyBlock
|
||||
getPlugin().getAddonsManager().getGameModeAddons().stream()
|
||||
.filter(gm -> settings.getGameModes().contains(gm.getDescription().getName()))
|
||||
.forEach(gm -> {
|
||||
log("Level hooking into " + gm.getDescription().getName());
|
||||
gm.getAdminCommand().ifPresent(adminCommand -> {
|
||||
new AdminLevelCommand(this, adminCommand);
|
||||
new AdminTopCommand(this, adminCommand);
|
||||
});
|
||||
gm.getPlayerCommand().ifPresent(playerCmd -> {
|
||||
new IslandLevelCommand(this, playerCmd);
|
||||
new IslandTopCommand(this, playerCmd);
|
||||
new IslandValueCommand(this, playerCmd);
|
||||
});
|
||||
// Register placeholders
|
||||
if (getPlugin().getPlaceholdersManager() != null) {
|
||||
getPlugin().getPlaceholdersManager().registerPlaceholder(this, gm.getDescription().getName().toLowerCase() + "-island-level", new LevelPlaceholder(this, gm));
|
||||
// Top Ten
|
||||
for (int i = 1; i < 11; i++) {
|
||||
getPlugin().getPlaceholdersManager().registerPlaceholder(this, gm.getDescription().getName().toLowerCase() + "-island-level-top-value-" + i, new TopTenPlaceholder(this, gm, i));
|
||||
getPlugin().getPlaceholdersManager().registerPlaceholder(this, gm.getDescription().getName().toLowerCase() + "-island-level-top-name-" + i, new TopTenNamePlaceholder(this, gm, i));
|
||||
}
|
||||
}
|
||||
});
|
||||
// Check if AdvancedChests is enabled on the server
|
||||
if (!settings.getDisabledPluginHooks().contains("AdvancedChests")) {
|
||||
Plugin advChest = Bukkit.getPluginManager().getPlugin("AdvancedChests");
|
||||
advChestEnabled = advChest != null;
|
||||
if (advChestEnabled) {
|
||||
// Check version
|
||||
if (compareVersions(advChest.getDescription().getVersion(), "23.0") > 0) {
|
||||
log("Hooked into AdvancedChests.");
|
||||
} else {
|
||||
logError("Could not hook into AdvancedChests " + advChest.getDescription().getVersion()
|
||||
+ " - requires version 23.0 or later");
|
||||
advChestEnabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register new island listener
|
||||
registerListener(new IslandTeamListeners(this));
|
||||
registerListener(new JoinLeaveListener(this));
|
||||
// Check if RoseStackers is enabled
|
||||
if (!settings.getDisabledPluginHooks().contains("RoseStacker")) {
|
||||
roseStackersEnabled = Bukkit.getPluginManager().isPluginEnabled("RoseStacker");
|
||||
if (roseStackersEnabled) {
|
||||
log("Hooked into RoseStackers.");
|
||||
}
|
||||
}
|
||||
|
||||
// Register request handlers
|
||||
registerRequestHandler(new LevelRequestHandler(this));
|
||||
registerRequestHandler(new TopTenRequestHandler(this));
|
||||
// Check if UltimateStacker is enabled
|
||||
if (!settings.getDisabledPluginHooks().contains("UltimateStacker")) {
|
||||
ultimateStackerEnabled = Bukkit.getPluginManager().isPluginEnabled("UltimateStacker");
|
||||
if (ultimateStackerEnabled) {
|
||||
log("Hooked into UltimateStacker.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Done
|
||||
}
|
||||
@Override
|
||||
public void allLoaded() {
|
||||
super.allLoaded();
|
||||
|
||||
/**
|
||||
* Save the levels to the database
|
||||
*/
|
||||
private void save(){
|
||||
// No async for now
|
||||
levelsCache.values().forEach(handler::saveObject);
|
||||
}
|
||||
if (this.isEnabled()) {
|
||||
this.hookExtensions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the player's level to a value
|
||||
* @param world - world
|
||||
* @param targetPlayer - target player
|
||||
* @param level - level
|
||||
*/
|
||||
public void setIslandLevel(World world, UUID targetPlayer, long level) {
|
||||
if (world == null || targetPlayer == null) {
|
||||
this.logError("Level: request to store a null " + world + " " + targetPlayer);
|
||||
return;
|
||||
}
|
||||
LevelsData ld = getLevelsData(targetPlayer);
|
||||
if (ld == null) {
|
||||
ld = new LevelsData(targetPlayer, level, world);
|
||||
} else {
|
||||
ld.setLevel(world, level);
|
||||
}
|
||||
// Add to cache
|
||||
levelsCache.put(targetPlayer, ld);
|
||||
topTen.addEntry(world, targetPlayer, getIslandLevel(world, targetPlayer));
|
||||
handler.saveObject(ld);
|
||||
}
|
||||
/**
|
||||
* This method tries to hook into addons and plugins
|
||||
*/
|
||||
private void hookExtensions() {
|
||||
// Try to find Visit addon and if it does not exist, display a warning
|
||||
this.getAddonByName("Visit").ifPresentOrElse(addon -> {
|
||||
this.visitHook = (VisitAddon) addon;
|
||||
this.log("Level Addon hooked into Visit addon.");
|
||||
}, () -> this.visitHook = null);
|
||||
|
||||
/**
|
||||
* Zeros the initial island level
|
||||
* @param island - island
|
||||
* @param level - initial calculated island level
|
||||
*/
|
||||
public void setInitialIslandLevel(Island island, long level) {
|
||||
if (island.getWorld() == null || island.getOwner() == null) {
|
||||
this.logError("Level: request to store a null (initial) " + island.getWorld() + " " + island.getOwner());
|
||||
return;
|
||||
}
|
||||
setIslandLevel(island.getWorld(), island.getOwner(), 0L);
|
||||
levelsCache.get(island.getOwner()).setInitialLevel(island.getWorld(), level);
|
||||
}
|
||||
// Try to find Warps addon and if it does not exist, display a warning
|
||||
this.getAddonByName("Warps").ifPresentOrElse(addon -> {
|
||||
this.warpHook = (Warp) addon;
|
||||
this.log("Level Addon hooked into Warps addon.");
|
||||
}, () -> this.warpHook = null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the initial island level
|
||||
* @param island - island
|
||||
* @return level or 0 by default
|
||||
*/
|
||||
public long getInitialIslandLevel(Island island) {
|
||||
return levelsCache.containsKey(island.getOwner()) ? levelsCache.get(island.getOwner()).getInitialLevel(island.getWorld()) : 0L;
|
||||
}
|
||||
|
||||
public Database<LevelsData> getHandler() {
|
||||
return handler;
|
||||
}
|
||||
/**
|
||||
* Compares versions
|
||||
*
|
||||
* @param version1 version 1
|
||||
* @param version2 version 2
|
||||
* @return {@code <0 if version 1 is older than version 2, =0 if the same, >0 if version 1 is newer than version 2}
|
||||
*/
|
||||
public static int compareVersions(String version1, String version2) {
|
||||
int comparisonResult = 0;
|
||||
|
||||
public void uncachePlayer(UUID uniqueId) {
|
||||
if (levelsCache.containsKey(uniqueId) && levelsCache.get(uniqueId) != null) {
|
||||
handler.saveObject(levelsCache.get(uniqueId));
|
||||
}
|
||||
levelsCache.remove(uniqueId);
|
||||
}
|
||||
String[] version1Splits = version1.split("\\.");
|
||||
String[] version2Splits = version2.split("\\.");
|
||||
int maxLengthOfVersionSplits = Math.max(version1Splits.length, version2Splits.length);
|
||||
|
||||
for (int i = 0; i < maxLengthOfVersionSplits; i++) {
|
||||
Integer v1 = i < version1Splits.length ? Integer.parseInt(version1Splits[i]) : 0;
|
||||
Integer v2 = i < version2Splits.length ? Integer.parseInt(version2Splits[i]) : 0;
|
||||
int compare = v1.compareTo(v2);
|
||||
if (compare != 0) {
|
||||
comparisonResult = compare;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return comparisonResult;
|
||||
}
|
||||
|
||||
private void registerCommands(GameModeAddon gm) {
|
||||
gm.getAdminCommand().ifPresent(adminCommand -> {
|
||||
new AdminLevelCommand(this, adminCommand);
|
||||
new AdminTopCommand(this, adminCommand);
|
||||
new AdminLevelStatusCommand(this, adminCommand);
|
||||
if (getSettings().isZeroNewIslandLevels()) {
|
||||
new AdminSetInitialLevelCommand(this, adminCommand);
|
||||
}
|
||||
new AdminStatsCommand(this, adminCommand);
|
||||
});
|
||||
gm.getPlayerCommand().ifPresent(playerCmd -> {
|
||||
new IslandLevelCommand(this, playerCmd);
|
||||
new IslandTopCommand(this, playerCmd);
|
||||
new IslandValueCommand(this, playerCmd);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
// Stop the pipeline
|
||||
this.getPipeliner().stop();
|
||||
}
|
||||
|
||||
private void loadBlockSettings() {
|
||||
// Save the default blockconfig.yml
|
||||
this.saveResource("blockconfig.yml", false);
|
||||
|
||||
YamlConfiguration blockValues = new YamlConfiguration();
|
||||
try {
|
||||
File file = new File(this.getDataFolder(), "blockconfig.yml");
|
||||
blockValues.load(file);
|
||||
// Load the block config class
|
||||
blockConfig = new BlockConfig(this, blockValues, file);
|
||||
} catch (IOException | InvalidConfigurationException e) {
|
||||
// Disable
|
||||
logError("Level blockconfig.yml settings could not load! Addon disabled.");
|
||||
setState(State.DISABLED);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the blockConfig
|
||||
*/
|
||||
public BlockConfig getBlockConfig() {
|
||||
return blockConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the settings
|
||||
*/
|
||||
public ConfigSettings getSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the pipeliner
|
||||
*/
|
||||
public Pipeliner getPipeliner() {
|
||||
return pipeliner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the manager
|
||||
*/
|
||||
public LevelsManager getManager() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the config settings - used for tests only
|
||||
*
|
||||
* @param configSettings - config settings
|
||||
*/
|
||||
void setSettings(ConfigSettings configSettings) {
|
||||
this.settings = configSettings;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the stackersEnabled
|
||||
*/
|
||||
public boolean isStackersEnabled() {
|
||||
return stackersEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the advChestEnabled
|
||||
*/
|
||||
public boolean isAdvChestEnabled() {
|
||||
return advChestEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get level from cache for a player.
|
||||
*
|
||||
* @param targetPlayer - target player UUID
|
||||
* @return Level of player or zero if player is unknown or UUID is null
|
||||
*/
|
||||
public long getIslandLevel(World world, @Nullable UUID targetPlayer) {
|
||||
return getManager().getIslandLevel(world, targetPlayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the player's level to a value
|
||||
*
|
||||
* @param world - world
|
||||
* @param targetPlayer - target player
|
||||
* @param level - level
|
||||
*/
|
||||
public void setIslandLevel(World world, UUID targetPlayer, long level) {
|
||||
getManager().setIslandLevel(world, targetPlayer, level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeros the initial island level
|
||||
*
|
||||
* @param island - island
|
||||
* @param level - initial calculated island level
|
||||
*/
|
||||
public void setInitialIslandLevel(@NonNull Island island, long level) {
|
||||
getManager().setInitialIslandLevel(island, level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the initial island level
|
||||
*
|
||||
* @param island - island
|
||||
* @return level or 0 by default
|
||||
*/
|
||||
public long getInitialIslandLevel(@NonNull Island island) {
|
||||
return getManager().getInitialLevel(island);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a user's island
|
||||
*
|
||||
* @param world - the world where this island is
|
||||
* @param user - not used! See depecration message
|
||||
* @param playerUUID - the target island member's UUID
|
||||
* @deprecated Do not use this anymore. Use
|
||||
* getManager().calculateLevel(playerUUID, island)
|
||||
*/
|
||||
@Deprecated(since = "2.3.0", forRemoval = true)
|
||||
public void calculateIslandLevel(World world, @Nullable User user, @NonNull UUID playerUUID) {
|
||||
Island island = getIslands().getIsland(world, playerUUID);
|
||||
if (island != null)
|
||||
getManager().calculateLevel(playerUUID, island);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the levels data for the target player
|
||||
*
|
||||
* @param targetPlayer - UUID of target player
|
||||
* @return LevelsData object or null if not found. Only island levels are set!
|
||||
* @deprecated Do not use this anymore. Use {@link #getIslandLevel(World, UUID)}
|
||||
*/
|
||||
@Deprecated(since = "2.3.0", forRemoval = true)
|
||||
public LevelsData getLevelsData(UUID targetPlayer) {
|
||||
LevelsData ld = new LevelsData(targetPlayer);
|
||||
getPlugin().getAddonsManager().getGameModeAddons().stream()
|
||||
.filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName())).forEach(gm -> {
|
||||
if (getSettings().isZeroNewIslandLevels()) {
|
||||
Island island = getIslands().getIsland(gm.getOverWorld(), targetPlayer);
|
||||
if (island != null) {
|
||||
ld.setInitialLevel(gm.getOverWorld(), this.getInitialIslandLevel(island));
|
||||
}
|
||||
}
|
||||
ld.setLevel(gm.getOverWorld(), this.getIslandLevel(gm.getOverWorld(), targetPlayer));
|
||||
});
|
||||
return ld;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the registeredGameModes
|
||||
*/
|
||||
public List<GameModeAddon> getRegisteredGameModes() {
|
||||
return registeredGameModes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Level addon is active in game mode
|
||||
*
|
||||
* @param gm Game Mode Addon
|
||||
* @return true if active, false if not
|
||||
*/
|
||||
public boolean isRegisteredGameMode(GameModeAddon gm) {
|
||||
return registeredGameModes.contains(gm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if Level addon is active in world
|
||||
*
|
||||
* @param world world
|
||||
* @return true if active, false if not
|
||||
*/
|
||||
public boolean isRegisteredGameModeWorld(World world) {
|
||||
return registeredGameModes.stream().map(GameModeAddon::getOverWorld).anyMatch(w -> Util.sameWorld(world, w));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the roseStackersEnabled
|
||||
*/
|
||||
public boolean isRoseStackersEnabled() {
|
||||
return roseStackersEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ultimateStackerEnabled
|
||||
*/
|
||||
public boolean isUltimateStackerEnabled() {
|
||||
return ultimateStackerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method Level#getVisitHook returns the visitHook of this object.
|
||||
*
|
||||
* @return {@code Visit} of this object, {@code null} otherwise.
|
||||
*/
|
||||
public VisitAddon getVisitHook() {
|
||||
return this.visitHook;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method Level#getWarpHook returns the warpHook of this object.
|
||||
*
|
||||
* @return {@code Warp} of this object, {@code null} otherwise.
|
||||
*/
|
||||
public Warp getWarpHook() {
|
||||
return this.warpHook;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package world.bentobox.level;
|
||||
|
||||
import world.bentobox.bentobox.api.addons.Addon;
|
||||
import world.bentobox.bentobox.api.addons.Pladdon;
|
||||
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class LevelPladdon extends Pladdon {
|
||||
@Override
|
||||
public Addon getAddon() {
|
||||
return new Level();
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
package world.bentobox.level;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.level.calculators.PlayerLevel;
|
||||
|
||||
class LevelPresenter {
|
||||
|
||||
private int levelWait;
|
||||
private final Level addon;
|
||||
private final BentoBox plugin;
|
||||
|
||||
// Level calc cool down
|
||||
private final HashMap<UUID, Long> levelWaitTime = new HashMap<>();
|
||||
|
||||
public LevelPresenter(Level addon, BentoBox plugin) {
|
||||
this.addon = addon;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the island level
|
||||
* @param world - world to check
|
||||
* @param sender - asker of the level info
|
||||
* @param targetPlayer - target player
|
||||
*/
|
||||
public void calculateIslandLevel(World world, final User sender, UUID targetPlayer) {
|
||||
// Get permission prefix for this world
|
||||
String permPrefix = plugin.getIWM().getPermissionPrefix(world);
|
||||
// Check if target has island
|
||||
boolean inTeam = false;
|
||||
if (!plugin.getIslands().hasIsland(world, targetPlayer)) {
|
||||
// Player may be in a team
|
||||
if (plugin.getIslands().inTeam(world, targetPlayer)) {
|
||||
targetPlayer = plugin.getIslands().getOwner(world, targetPlayer);
|
||||
inTeam = true;
|
||||
} else {
|
||||
sender.sendMessage("general.errors.player-has-no-island");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Player asking for their own island calc
|
||||
if (inTeam || !sender.isPlayer() || sender.getUniqueId().equals(targetPlayer) || sender.isOp() || sender.hasPermission(permPrefix + "mod.info")) {
|
||||
// Newer better system - uses chunks
|
||||
if (!onLevelWaitTime(sender) || levelWait <= 0 || sender.isOp() || sender.hasPermission(permPrefix + "mod.info")) {
|
||||
sender.sendMessage("island.level.calculating");
|
||||
setLevelWaitTime(sender);
|
||||
new PlayerLevel(addon, plugin.getIslands().getIsland(world, targetPlayer), targetPlayer, sender);
|
||||
} else {
|
||||
// Cooldown
|
||||
sender.sendMessage("island.level.cooldown", "[time]", String.valueOf(getLevelWaitTime(sender)));
|
||||
}
|
||||
|
||||
} else {
|
||||
// Asking for the level of another player
|
||||
sender.sendMessage("island.level.island-level-is","[level]", String.valueOf(addon.getIslandLevel(world, targetPlayer)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets cool down for the level command
|
||||
*
|
||||
* @param user - user
|
||||
*/
|
||||
private void setLevelWaitTime(final User user) {
|
||||
levelWaitTime.put(user.getUniqueId(), Calendar.getInstance().getTimeInMillis() + levelWait * 1000);
|
||||
}
|
||||
|
||||
private boolean onLevelWaitTime(final User sender) {
|
||||
if (levelWaitTime.containsKey(sender.getUniqueId())) {
|
||||
return levelWaitTime.get(sender.getUniqueId()) > Calendar.getInstance().getTimeInMillis();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private long getLevelWaitTime(final User sender) {
|
||||
if (levelWaitTime.containsKey(sender.getUniqueId())) {
|
||||
if (levelWaitTime.get(sender.getUniqueId()) > Calendar.getInstance().getTimeInMillis()) {
|
||||
return (levelWaitTime.get(sender.getUniqueId()) - Calendar.getInstance().getTimeInMillis()) / 1000;
|
||||
}
|
||||
|
||||
return 0L;
|
||||
}
|
||||
|
||||
return 0L;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,512 @@
|
|||
package world.bentobox.level;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.text.DecimalFormat;
|
||||
import java.time.Instant;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import world.bentobox.bentobox.database.Database;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.level.calculators.Results;
|
||||
import world.bentobox.level.events.IslandLevelCalculatedEvent;
|
||||
import world.bentobox.level.events.IslandPreLevelEvent;
|
||||
import world.bentobox.level.objects.IslandLevels;
|
||||
import world.bentobox.level.objects.LevelsData;
|
||||
import world.bentobox.level.objects.TopTenData;
|
||||
import world.bentobox.level.util.CachedData;
|
||||
|
||||
public class LevelsManager {
|
||||
private static final String INTOPTEN = "intopten";
|
||||
private static final TreeMap<BigInteger, String> LEVELS;
|
||||
private static final BigInteger THOUSAND = BigInteger.valueOf(1000);
|
||||
static {
|
||||
LEVELS = new TreeMap<>();
|
||||
|
||||
LEVELS.put(THOUSAND, "k");
|
||||
LEVELS.put(THOUSAND.pow(2), "M");
|
||||
LEVELS.put(THOUSAND.pow(3), "G");
|
||||
LEVELS.put(THOUSAND.pow(4), "T");
|
||||
}
|
||||
private final Level addon;
|
||||
|
||||
// Database handler for level data
|
||||
private final Database<IslandLevels> handler;
|
||||
// A cache of island levels.
|
||||
private final Map<String, IslandLevels> levelsCache;
|
||||
// Top ten lists
|
||||
private final Map<World, TopTenData> topTenLists;
|
||||
// Cache for top tens
|
||||
private Map<World, CachedData> cache = new HashMap<>();
|
||||
|
||||
public LevelsManager(Level addon) {
|
||||
this.addon = addon;
|
||||
// Get the BentoBox database
|
||||
// Set up the database handler to store and retrieve data
|
||||
// Note that these are saved by the BentoBox database
|
||||
handler = new Database<>(addon, IslandLevels.class);
|
||||
// Initialize the cache
|
||||
levelsCache = new HashMap<>();
|
||||
// Initialize top ten lists
|
||||
topTenLists = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public void migrate() {
|
||||
Database<LevelsData> oldDb = new Database<>(addon, LevelsData.class);
|
||||
oldDb.loadObjects().forEach(ld -> {
|
||||
try {
|
||||
UUID owner = UUID.fromString(ld.getUniqueId());
|
||||
// Step through each world
|
||||
ld.getLevels().keySet().stream()
|
||||
// World
|
||||
.map(Bukkit::getWorld).filter(Objects::nonNull)
|
||||
// Island
|
||||
.map(w -> addon.getIslands().getIsland(w, owner)).filter(Objects::nonNull).forEach(i -> {
|
||||
// Make new database entry
|
||||
World w = i.getWorld();
|
||||
IslandLevels il = new IslandLevels(i.getUniqueId());
|
||||
il.setInitialLevel(ld.getInitialLevel(w));
|
||||
il.setLevel(ld.getLevel(w));
|
||||
il.setMdCount(ld.getMdCount(w));
|
||||
il.setPointsToNextLevel(ld.getPointsToNextLevel(w));
|
||||
il.setUwCount(ld.getUwCount(w));
|
||||
// Save it
|
||||
handler.saveObjectAsync(il);
|
||||
});
|
||||
// Now delete the old database entry
|
||||
oldDb.deleteID(ld.getUniqueId());
|
||||
} catch (Exception e) {
|
||||
addon.logError("Could not migrate level data database! " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an island to a top ten
|
||||
*
|
||||
* @param island - island to add
|
||||
* @param lv - level
|
||||
* @return true if successful, false if not added
|
||||
*/
|
||||
private boolean addToTopTen(Island island, long lv) {
|
||||
if (island != null && island.getOwner() != null && hasTopTenPerm(island.getWorld(), island.getOwner())) {
|
||||
topTenLists.computeIfAbsent(island.getWorld(), k -> new TopTenData(island.getWorld())).getTopTen()
|
||||
.put(island.getUniqueId(), lv);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the island level, set all island member's levels to the result and
|
||||
* try to add the owner to the top ten
|
||||
*
|
||||
* @param targetPlayer - uuid of targeted player - owner or team member
|
||||
* @param island - island to calculate
|
||||
* @return completable future with the results of the calculation
|
||||
*/
|
||||
public CompletableFuture<Results> calculateLevel(UUID targetPlayer, Island island) {
|
||||
CompletableFuture<Results> result = new CompletableFuture<>();
|
||||
// Fire pre-level calc event
|
||||
IslandPreLevelEvent e = new IslandPreLevelEvent(targetPlayer, island);
|
||||
Bukkit.getPluginManager().callEvent(e);
|
||||
if (e.isCancelled()) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
// Add island to the pipeline
|
||||
addon.getPipeliner().addIsland(island).thenAccept(r -> {
|
||||
// Results are irrelevant because the island is unowned or deleted, or
|
||||
// IslandLevelCalcEvent is cancelled
|
||||
if (r == null || fireIslandLevelCalcEvent(targetPlayer, island, r)) {
|
||||
result.complete(null);
|
||||
}
|
||||
// Save result
|
||||
setIslandResults(island, r);
|
||||
// Save the island scan details
|
||||
result.complete(r);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires the IslandLevelCalculatedEvent and returns true if it is canceled
|
||||
*
|
||||
* @param targetPlayer - target player
|
||||
* @param island - island
|
||||
* @param results - results set
|
||||
* @return true if canceled
|
||||
*/
|
||||
private boolean fireIslandLevelCalcEvent(UUID targetPlayer, Island island, Results results) {
|
||||
// Fire post calculation event
|
||||
IslandLevelCalculatedEvent ilce = new IslandLevelCalculatedEvent(targetPlayer, island, results);
|
||||
Bukkit.getPluginManager().callEvent(ilce);
|
||||
if (ilce.isCancelled())
|
||||
return true;
|
||||
// Set the values if they were altered
|
||||
results.setLevel((Long) ilce.getKeyValues().getOrDefault("level", results.getLevel()));
|
||||
results.setInitialLevel((Long) ilce.getKeyValues().getOrDefault("initialLevel", results.getInitialLevel()));
|
||||
results.setDeathHandicap((int) ilce.getKeyValues().getOrDefault("deathHandicap", results.getDeathHandicap()));
|
||||
results.setPointsToNextLevel(
|
||||
(Long) ilce.getKeyValues().getOrDefault("pointsToNextLevel", results.getPointsToNextLevel()));
|
||||
results.setTotalPoints((Long) ilce.getKeyValues().getOrDefault("totalPoints", results.getTotalPoints()));
|
||||
return ((Boolean) ilce.getKeyValues().getOrDefault("isCancelled", false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string representation of the level. May be converted to shorthand
|
||||
* notation, e.g., 104556 = 10.5k
|
||||
*
|
||||
* @param lvl - long value to represent
|
||||
* @return string of the level.
|
||||
*/
|
||||
public String formatLevel(@Nullable Long lvl) {
|
||||
if (lvl == null)
|
||||
return "";
|
||||
String level = String.valueOf(lvl);
|
||||
// Asking for the level of another player
|
||||
if (addon.getSettings().isShorthand()) {
|
||||
BigInteger levelValue = BigInteger.valueOf(lvl);
|
||||
|
||||
Map.Entry<BigInteger, String> stage = LEVELS.floorEntry(levelValue);
|
||||
|
||||
if (stage != null) { // level > 1000
|
||||
// 1 052 -> 1.0k
|
||||
// 1 527 314 -> 1.5M
|
||||
// 3 874 130 021 -> 3.8G
|
||||
// 4 002 317 889 -> 4.0T
|
||||
level = new DecimalFormat("#.#").format(
|
||||
levelValue.divide(stage.getKey().divide(THOUSAND)).doubleValue() / 1000.0) + stage.getValue();
|
||||
}
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the initial level of the island. Used to zero island levels
|
||||
*
|
||||
* @param island - island
|
||||
* @return initial level of island
|
||||
*/
|
||||
public long getInitialLevel(Island island) {
|
||||
return getLevelsData(island).getInitialLevel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get level of island from cache for a player.
|
||||
*
|
||||
* @param world - world where the island is
|
||||
* @param targetPlayer - target player UUID
|
||||
* @return Level of the player's island or zero if player is unknown or UUID is
|
||||
* null
|
||||
*/
|
||||
public long getIslandLevel(@NonNull World world, @Nullable UUID targetPlayer) {
|
||||
if (targetPlayer == null)
|
||||
return 0L;
|
||||
// Get the island
|
||||
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
||||
return island == null ? 0L : getLevelsData(island).getLevel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum level ever given to this island
|
||||
*
|
||||
* @param world - world where the island is
|
||||
* @param targetPlayer - target player UUID
|
||||
* @return Max level of the player's island or zero if player is unknown or UUID
|
||||
* is null
|
||||
*/
|
||||
public long getIslandMaxLevel(@NonNull World world, @Nullable UUID targetPlayer) {
|
||||
if (targetPlayer == null)
|
||||
return 0L;
|
||||
// Get the island
|
||||
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
||||
return island == null ? 0L : getLevelsData(island).getMaxLevel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted string of the target player's island level
|
||||
*
|
||||
* @param world - world where the island is
|
||||
* @param targetPlayer - target player's UUID
|
||||
* @return Formatted level of player or zero if player is unknown or UUID is
|
||||
* null
|
||||
*/
|
||||
public String getIslandLevelString(@NonNull World world, @Nullable UUID targetPlayer) {
|
||||
return formatLevel(getIslandLevel(world, targetPlayer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a level data for the island from the cache or database.
|
||||
*
|
||||
* @param island - UUID of island
|
||||
* @return IslandLevels object
|
||||
*/
|
||||
@NonNull
|
||||
public IslandLevels getLevelsData(@NonNull Island island) {
|
||||
String id = island.getUniqueId();
|
||||
if (levelsCache.containsKey(id)) {
|
||||
return levelsCache.get(id);
|
||||
}
|
||||
// Get from database if not in cache
|
||||
if (handler.objectExists(id)) {
|
||||
IslandLevels ld = handler.loadObject(id);
|
||||
if (ld != null) {
|
||||
levelsCache.put(id, ld);
|
||||
} else {
|
||||
handler.deleteID(id);
|
||||
levelsCache.put(id, new IslandLevels(id));
|
||||
}
|
||||
} else {
|
||||
levelsCache.put(id, new IslandLevels(id));
|
||||
}
|
||||
// Return cached value
|
||||
return levelsCache.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of points required until the next level since the last level
|
||||
* calc
|
||||
*
|
||||
* @param world - world where the island is
|
||||
* @param targetPlayer - target player UUID
|
||||
* @return string with the number required or blank if the player is unknown
|
||||
*/
|
||||
public String getPointsToNextString(@NonNull World world, @Nullable UUID targetPlayer) {
|
||||
if (targetPlayer == null)
|
||||
return "";
|
||||
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
||||
return island == null ? "" : String.valueOf(getLevelsData(island).getPointsToNextLevel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the weighted top ten for this world. Weighting is based on number of
|
||||
* players per team.
|
||||
*
|
||||
* @param world - world requested
|
||||
* @param size - size of the top ten
|
||||
* @return sorted top ten map. The key is the island unique ID
|
||||
*/
|
||||
@NonNull
|
||||
public Map<Island, Long> getWeightedTopTen(@NonNull World world, int size) {
|
||||
createAndCleanRankings(world);
|
||||
Map<Island, Long> weightedTopTen = topTenLists.get(world).getTopTen().entrySet().stream()
|
||||
.map(en -> addon.getIslands().getIslandById(en.getKey()).map(island -> {
|
||||
|
||||
long value = (long) (en.getValue() / (double) Math.max(1, island.getMemberSet().size())); // Calculate
|
||||
// weighted
|
||||
// value
|
||||
return new AbstractMap.SimpleEntry<>(island, value);
|
||||
}).orElse(null)) // Handle islands that do not exist according to this ID - old deleted ones
|
||||
.filter(Objects::nonNull) // Filter out null entries
|
||||
.filter(en -> en.getValue() > 0) // Filter out entries with non-positive values
|
||||
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue())) // Sort in descending order of values
|
||||
.limit(size) // Limit to the top 'size' entries
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, // In case of key
|
||||
// collision, choose
|
||||
// the first one
|
||||
LinkedHashMap::new // Preserves the order of entries
|
||||
));
|
||||
|
||||
// Return the unmodifiable map
|
||||
return Collections.unmodifiableMap(weightedTopTen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the top ten for this world. Returns offline players or players with the
|
||||
* intopten permission.
|
||||
*
|
||||
* @param world - world requested
|
||||
* @param size - size of the top ten
|
||||
* @return sorted top ten map. The key is the island unique ID
|
||||
*/
|
||||
@NonNull
|
||||
public Map<String, Long> getTopTen(@NonNull World world, int size) {
|
||||
createAndCleanRankings(world);
|
||||
CachedData cachedData = cache.get(world);
|
||||
Instant now = Instant.now();
|
||||
|
||||
if (cachedData != null && cachedData.getLastUpdated().plusSeconds(1).isAfter(now)) {
|
||||
return cachedData.getCachedMap();
|
||||
} else {
|
||||
Map<String, Long> newTopTen = calculateTopTen(world, size);
|
||||
cache.put(world, new CachedData(newTopTen, now));
|
||||
return newTopTen;
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Long> calculateTopTen(@NonNull World world, int size) {
|
||||
return Collections.unmodifiableMap(topTenLists.get(world).getTopTen().entrySet().stream()
|
||||
.filter(l -> l.getValue() > 0).sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
|
||||
.limit(size)
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)));
|
||||
}
|
||||
|
||||
void createAndCleanRankings(@NonNull World world) {
|
||||
topTenLists.computeIfAbsent(world, TopTenData::new);
|
||||
// Remove player from top ten if they are online and do not have the perm
|
||||
topTenLists.get(world).getTopTen().keySet().removeIf(u -> addon.getIslands().getIslandById(u)
|
||||
.filter(i -> i.getOwner() == null || !hasTopTenPerm(world, i.getOwner())).isPresent());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the topTenLists
|
||||
*/
|
||||
public Map<World, TopTenData> getTopTenLists() {
|
||||
return topTenLists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rank of the player in the rankings
|
||||
*
|
||||
* @param world - world
|
||||
* @param uuid - player UUID
|
||||
* @return rank placing - note - placing of 1 means top ranked
|
||||
*/
|
||||
public int getRank(@NonNull World world, UUID uuid) {
|
||||
createAndCleanRankings(world);
|
||||
Stream<Entry<String, Long>> stream = topTenLists.get(world).getTopTen().entrySet().stream()
|
||||
.filter(l -> l.getValue() > 0).sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
|
||||
// Get player's current island
|
||||
Island island = addon.getIslands().getIsland(world, uuid);
|
||||
String id = island == null ? null : island.getUniqueId();
|
||||
return (int) (stream.takeWhile(x -> !x.getKey().equals(id)).map(Map.Entry::getKey).count() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if player has the correct top ten perm to have their level saved
|
||||
*
|
||||
* @param world
|
||||
* @param targetPlayer
|
||||
* @return true if player has the perm or the player is offline
|
||||
*/
|
||||
boolean hasTopTenPerm(@NonNull World world, @NonNull UUID targetPlayer) {
|
||||
String permPrefix = addon.getPlugin().getIWM().getPermissionPrefix(world);
|
||||
return Bukkit.getPlayer(targetPlayer) == null
|
||||
|| Bukkit.getPlayer(targetPlayer).hasPermission(permPrefix + INTOPTEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all the top tens from the database
|
||||
*/
|
||||
public void loadTopTens() {
|
||||
topTenLists.clear();
|
||||
Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> {
|
||||
addon.log("Generating rankings");
|
||||
handler.loadObjects().forEach(il -> {
|
||||
if (il.getLevel() > 0) {
|
||||
// Load islands, but don't cache them
|
||||
addon.getIslands().getIslandById(il.getUniqueId(), false)
|
||||
.ifPresent(i -> this.addToTopTen(i, il.getLevel()));
|
||||
}
|
||||
});
|
||||
topTenLists.keySet().forEach(w -> addon.log("Generated rankings for " + w.getName()));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an island from a world's top ten
|
||||
*
|
||||
* @param world - world
|
||||
* @param uuid - the island's uuid
|
||||
*/
|
||||
public void removeEntry(World world, String uuid) {
|
||||
if (topTenLists.containsKey(world)) {
|
||||
topTenLists.get(world).getTopTen().remove(uuid);
|
||||
// Invalidate the cache because of this deletion
|
||||
cache.remove(world);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an initial island level
|
||||
*
|
||||
* @param island - the island to set. Must have a non-null world
|
||||
* @param lv - initial island level
|
||||
*/
|
||||
public void setInitialIslandLevel(@NonNull Island island, long lv) {
|
||||
if (island.getWorld() == null)
|
||||
return;
|
||||
levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new).setInitialLevel(lv);
|
||||
handler.saveObjectAsync(levelsCache.get(island.getUniqueId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the island level for the owner of the island that targetPlayer is a
|
||||
* member
|
||||
*
|
||||
* @param world - world
|
||||
* @param island - island
|
||||
* @param lv - level
|
||||
*/
|
||||
public void setIslandLevel(@NonNull World world, @NonNull UUID targetPlayer, long lv) {
|
||||
// Get the island
|
||||
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
||||
if (island != null) {
|
||||
String id = island.getUniqueId();
|
||||
IslandLevels il = levelsCache.computeIfAbsent(id, IslandLevels::new);
|
||||
// Remove the initial level
|
||||
if (addon.getSettings().isZeroNewIslandLevels()) {
|
||||
il.setLevel(lv - il.getInitialLevel());
|
||||
} else {
|
||||
il.setLevel(lv);
|
||||
}
|
||||
handler.saveObjectAsync(levelsCache.get(id));
|
||||
// Update TopTen
|
||||
addToTopTen(island, levelsCache.get(id).getLevel());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the island level for the owner of the island that targetPlayer is a
|
||||
* member
|
||||
*
|
||||
* @param world - world
|
||||
* @param owner - owner of the island
|
||||
* @param r - results of the calculation
|
||||
*/
|
||||
private void setIslandResults(Island island, Results r) {
|
||||
if (island == null)
|
||||
return;
|
||||
IslandLevels ld = levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new);
|
||||
ld.setLevel(r.getLevel());
|
||||
ld.setUwCount(Maps.asMap(r.getUwCount().elementSet(), elem -> r.getUwCount().count(elem)));
|
||||
ld.setMdCount(Maps.asMap(r.getMdCount().elementSet(), elem -> r.getMdCount().count(elem)));
|
||||
ld.setPointsToNextLevel(r.getPointsToNextLevel());
|
||||
ld.setTotalPoints(r.getTotalPoints());
|
||||
levelsCache.put(island.getUniqueId(), ld);
|
||||
handler.saveObjectAsync(ld);
|
||||
// Update TopTen
|
||||
addToTopTen(island, ld.getLevel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes island from cache when it is deleted
|
||||
*
|
||||
* @param uniqueId - id of island
|
||||
*/
|
||||
public void deleteIsland(String uniqueId) {
|
||||
levelsCache.remove(uniqueId);
|
||||
handler.deleteID(uniqueId);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
package world.bentobox.level;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.managers.PlaceholdersManager;
|
||||
import world.bentobox.bentobox.managers.RanksManager;
|
||||
import world.bentobox.level.objects.IslandLevels;
|
||||
import world.bentobox.level.objects.TopTenData;
|
||||
|
||||
/**
|
||||
* Handles Level placeholders
|
||||
*
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class PlaceholderManager {
|
||||
|
||||
private final Level addon;
|
||||
private final BentoBox plugin;
|
||||
|
||||
public PlaceholderManager(Level addon) {
|
||||
this.addon = addon;
|
||||
this.plugin = addon.getPlugin();
|
||||
}
|
||||
|
||||
protected void registerPlaceholders(GameModeAddon gm) {
|
||||
if (plugin.getPlaceholdersManager() == null)
|
||||
return;
|
||||
PlaceholdersManager bpm = plugin.getPlaceholdersManager();
|
||||
// Island Level
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_island_level",
|
||||
user -> addon.getManager().getIslandLevelString(gm.getOverWorld(), user.getUniqueId()));
|
||||
// Unformatted island level
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_island_level_raw",
|
||||
user -> String.valueOf(addon.getManager().getIslandLevel(gm.getOverWorld(), user.getUniqueId())));
|
||||
// Total number of points counted before applying level formula
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_island_total_points", user -> {
|
||||
IslandLevels data = addon.getManager().getLevelsData(addon.getIslands().getIsland(gm.getOverWorld(), user));
|
||||
return data.getTotalPoints() + "";
|
||||
});
|
||||
// Points to the next level for player
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_points_to_next_level",
|
||||
user -> addon.getManager().getPointsToNextString(gm.getOverWorld(), user.getUniqueId()));
|
||||
// Maximum level this island has ever been. Current level maybe lower.
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_island_level_max",
|
||||
user -> String.valueOf(addon.getManager().getIslandMaxLevel(gm.getOverWorld(), user.getUniqueId())));
|
||||
|
||||
// Visited Island Level
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_visited_island_level",
|
||||
user -> getVisitedIslandLevel(gm, user));
|
||||
|
||||
// Register Top Ten Placeholders
|
||||
for (int i = 1; i < 11; i++) {
|
||||
final int rank = i;
|
||||
// Name
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_name_" + i,
|
||||
u -> getRankName(gm.getOverWorld(), rank, false));
|
||||
// Island Name
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_island_name_" + i,
|
||||
u -> getRankIslandName(gm.getOverWorld(), rank, false));
|
||||
// Members
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_members_" + i,
|
||||
u -> getRankMembers(gm.getOverWorld(), rank, false));
|
||||
// Level
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_value_" + i,
|
||||
u -> getRankLevel(gm.getOverWorld(), rank, false));
|
||||
// Weighted Level Name (Level / number of members)
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_weighted_name_" + i,
|
||||
u -> getRankName(gm.getOverWorld(), rank, true));
|
||||
// Weighted Island Name
|
||||
bpm.registerPlaceholder(addon,
|
||||
gm.getDescription().getName().toLowerCase() + "_top_weighted_island_name_" + i,
|
||||
u -> getRankIslandName(gm.getOverWorld(), rank, true));
|
||||
// Weighted Members
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_weighted_members_" + i,
|
||||
u -> getRankMembers(gm.getOverWorld(), rank, true));
|
||||
// Weighted Level (Level / number of members)
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_weighted_value_" + i,
|
||||
u -> getRankLevel(gm.getOverWorld(), rank, true));
|
||||
}
|
||||
|
||||
// Personal rank
|
||||
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_rank_value",
|
||||
u -> getRankValue(gm.getOverWorld(), u));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the owner of the island who holds the rank in this world.
|
||||
*
|
||||
* @param world world
|
||||
* @param rank rank 1 to 10
|
||||
* @param weighted if true, then the weighted rank name is returned
|
||||
* @return rank name
|
||||
*/
|
||||
String getRankName(World world, int rank, boolean weighted) {
|
||||
// Ensure rank is within bounds
|
||||
rank = Math.max(1, Math.min(rank, Level.TEN));
|
||||
if (weighted) {
|
||||
return addon.getManager().getWeightedTopTen(world, Level.TEN).keySet().stream().skip(rank - 1L).limit(1L)
|
||||
.findFirst().map(Island::getOwner).map(addon.getPlayers()::getName).orElse("");
|
||||
}
|
||||
@Nullable
|
||||
UUID owner = addon.getManager().getTopTen(world, Level.TEN).keySet().stream().skip(rank - 1L).limit(1L)
|
||||
.findFirst().flatMap(addon.getIslands()::getIslandById).map(Island::getOwner).orElse(null);
|
||||
|
||||
return addon.getPlayers().getName(owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the island name for this rank
|
||||
*
|
||||
* @param world world
|
||||
* @param rank rank 1 to 10
|
||||
* @param weighted if true, then the weighted rank name is returned
|
||||
* @return name of island or nothing if there isn't one
|
||||
*/
|
||||
String getRankIslandName(World world, int rank, boolean weighted) {
|
||||
// Ensure rank is within bounds
|
||||
rank = Math.max(1, Math.min(rank, Level.TEN));
|
||||
if (weighted) {
|
||||
return addon.getManager().getWeightedTopTen(world, Level.TEN).keySet().stream().skip(rank - 1L).limit(1L)
|
||||
.findFirst().map(Island::getName).orElse("");
|
||||
}
|
||||
return addon.getManager().getTopTen(world, Level.TEN).keySet().stream().skip(rank - 1L).limit(1L).findFirst()
|
||||
.flatMap(addon.getIslands()::getIslandById).map(Island::getName).orElse("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a comma separated string of island member names
|
||||
*
|
||||
* @param world world
|
||||
* @param rank rank to request
|
||||
* @param weighted if true, then the weighted rank name is returned
|
||||
* @return comma separated string of island member names
|
||||
*/
|
||||
String getRankMembers(World world, int rank, boolean weighted) {
|
||||
// Ensure rank is within bounds
|
||||
rank = Math.max(1, Math.min(rank, Level.TEN));
|
||||
if (weighted) {
|
||||
return addon.getManager().getWeightedTopTen(world, Level.TEN).keySet().stream().skip(rank - 1L).limit(1L)
|
||||
.findFirst()
|
||||
.map(is -> is.getMembers().entrySet().stream().filter(e -> e.getValue() >= RanksManager.MEMBER_RANK)
|
||||
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).map(Map.Entry::getKey)
|
||||
.map(addon.getPlayers()::getName).collect(Collectors.joining(",")))
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
Optional<Island> island = addon.getManager().getTopTen(world, Level.TEN).keySet().stream().skip(rank - 1L)
|
||||
.limit(1L).findFirst().flatMap(addon.getIslands()::getIslandById);
|
||||
|
||||
if (island.isPresent()) {
|
||||
// Sort members by rank
|
||||
return island.get().getMembers().entrySet().stream().filter(e -> e.getValue() >= RanksManager.MEMBER_RANK)
|
||||
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).map(Map.Entry::getKey)
|
||||
.map(addon.getPlayers()::getName).collect(Collectors.joining(","));
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the level for the rank requested
|
||||
*
|
||||
* @param world world
|
||||
* @param rank rank wanted
|
||||
* @param weighted true if weighted (level/number of team members)
|
||||
* @return level for the rank requested
|
||||
*/
|
||||
String getRankLevel(World world, int rank, boolean weighted) {
|
||||
// Ensure rank is within bounds
|
||||
rank = Math.max(1, Math.min(rank, Level.TEN));
|
||||
if (weighted) {
|
||||
return addon.getManager().formatLevel(addon.getManager().getWeightedTopTen(world, Level.TEN).values()
|
||||
.stream().skip(rank - 1L).limit(1L).findFirst().orElse(null));
|
||||
}
|
||||
return addon.getManager().formatLevel(addon.getManager().getTopTen(world, Level.TEN).values().stream()
|
||||
.skip(rank - 1L).limit(1L).findFirst().orElse(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rank of the player in a world
|
||||
*
|
||||
* @param world world
|
||||
* @param user player
|
||||
* @return rank where 1 is the top rank.
|
||||
*/
|
||||
private String getRankValue(World world, User user) {
|
||||
if (user == null) {
|
||||
return "";
|
||||
}
|
||||
// Get the island level for this user
|
||||
long level = addon.getManager().getIslandLevel(world, user.getUniqueId());
|
||||
return String.valueOf(addon.getManager().getTopTenLists().getOrDefault(world, new TopTenData(world)).getTopTen()
|
||||
.values().stream().filter(l -> l > level).count() + 1);
|
||||
}
|
||||
|
||||
String getVisitedIslandLevel(GameModeAddon gm, User user) {
|
||||
if (user == null || !gm.inWorld(user.getWorld()))
|
||||
return "";
|
||||
return addon.getIslands().getIslandAt(user.getLocation())
|
||||
.map(island -> addon.getManager().getIslandLevelString(gm.getOverWorld(), island.getOwner()))
|
||||
.orElse("0");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,161 +0,0 @@
|
|||
package world.bentobox.level;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
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;
|
||||
import world.bentobox.bentobox.database.Database;
|
||||
import world.bentobox.level.objects.TopTenData;
|
||||
|
||||
/**
|
||||
* Handles all Top Ten List functions
|
||||
*
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class TopTen implements Listener {
|
||||
private final Level addon;
|
||||
// Top ten list of players
|
||||
private Map<World,TopTenData> topTenList;
|
||||
private final int[] SLOTS = new int[] {4, 12, 14, 19, 20, 21, 22, 23, 24, 25};
|
||||
private final Database<TopTenData> handler;
|
||||
|
||||
public TopTen(Level addon) {
|
||||
this.addon = addon;
|
||||
// Set up the database handler to store and retrieve the TopTenList class
|
||||
// Note that these are saved in the BSkyBlock database
|
||||
handler = new Database<>(addon, TopTenData.class);
|
||||
loadTopTen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a player to the top ten, if the level is good enough
|
||||
*
|
||||
* @param ownerUUID - owner UUID
|
||||
* @param l - level
|
||||
*/
|
||||
public void addEntry(World world, UUID ownerUUID, long l) {
|
||||
// Check if player is an island owner or not
|
||||
if (!addon.getIslands().isOwner(world, ownerUUID)) {
|
||||
return;
|
||||
}
|
||||
// Set up world data
|
||||
topTenList.putIfAbsent(world, new TopTenData());
|
||||
topTenList.get(world).setUniqueId(world.getName());
|
||||
|
||||
// Try and see if the player is online
|
||||
Player player = addon.getServer().getPlayer(ownerUUID);
|
||||
if (player != null && !player.hasPermission(addon.getPlugin().getIWM().getPermissionPrefix(world) + ".intopten")) {
|
||||
topTenList.get(world).remove(ownerUUID);
|
||||
return;
|
||||
}
|
||||
topTenList.get(world).addLevel(ownerUUID, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the Top Ten list
|
||||
* @param world - world
|
||||
* @param user - the requesting player
|
||||
*/
|
||||
public void getGUI(World world, final User user, String permPrefix) {
|
||||
// Check world
|
||||
topTenList.putIfAbsent(world, new TopTenData());
|
||||
topTenList.get(world).setUniqueId(world.getName());
|
||||
|
||||
PanelBuilder panel = new PanelBuilder()
|
||||
.name(user.getTranslation("island.top.gui-title"))
|
||||
.user(user);
|
||||
|
||||
int i = 1;
|
||||
Iterator<Entry<UUID, Long>> it = topTenList.get(world).getTopTen().entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<UUID, Long> m = it.next();
|
||||
UUID topTenUUID = m.getKey();
|
||||
// Remove from TopTen if the player is online and has the permission
|
||||
Player entry = addon.getServer().getPlayer(topTenUUID);
|
||||
boolean show = true;
|
||||
if (entry != null) {
|
||||
if (!entry.hasPermission(permPrefix + "intopten")) {
|
||||
it.remove();
|
||||
show = false;
|
||||
}
|
||||
}
|
||||
if (show) {
|
||||
panel.item(SLOTS[i-1], getHead(i, m.getValue(), topTenUUID, user, world));
|
||||
if (i++ == 10) break;
|
||||
}
|
||||
}
|
||||
panel.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the head panel item
|
||||
* @param rank - the top ten rank of this player/team. Can be used in the name of the island for vanity.
|
||||
* @param level - the level of the island
|
||||
* @param playerUUID - the UUID of the top ten player
|
||||
* @param asker - the asker of the top ten
|
||||
* @return PanelItem
|
||||
*/
|
||||
private PanelItem getHead(int rank, Long level, UUID playerUUID, User asker, World world) {
|
||||
final String name = addon.getPlayers().getName(playerUUID);
|
||||
List<String> description = new ArrayList<>();
|
||||
if (name != null) {
|
||||
description.add(asker.getTranslation("island.top.gui-heading", "[name]", name, "[rank]", String.valueOf(rank)));
|
||||
description.add(asker.getTranslation("island.top.island-level","[level]", String.valueOf(level)));
|
||||
if (addon.getIslands().inTeam(world, playerUUID)) {
|
||||
List<String> memberList = new ArrayList<>();
|
||||
for (UUID members : addon.getIslands().getMembers(world, playerUUID)) {
|
||||
memberList.add(ChatColor.AQUA + addon.getPlayers().getName(members));
|
||||
}
|
||||
description.addAll(memberList);
|
||||
}
|
||||
}
|
||||
PanelItemBuilder builder = new PanelItemBuilder()
|
||||
.icon(name)
|
||||
.name(name)
|
||||
.description(description);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public TopTenData getTopTenList(World world) {
|
||||
return topTenList.get(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all the top tens from the database
|
||||
*/
|
||||
private void loadTopTen() {
|
||||
topTenList = new HashMap<>();
|
||||
handler.loadObjects().forEach(tt -> topTenList.put(Bukkit.getWorld(tt.getUniqueId()), tt));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes ownerUUID from the top ten list
|
||||
*
|
||||
* @param ownerUUID - uuid to remove
|
||||
*/
|
||||
public void removeEntry(World world, UUID ownerUUID) {
|
||||
topTenList.putIfAbsent(world, new TopTenData());
|
||||
topTenList.get(world).setUniqueId(world.getName());
|
||||
topTenList.get(world).remove(ownerUUID);
|
||||
}
|
||||
|
||||
public void saveTopTen() {
|
||||
topTenList.values().forEach(handler::saveObject);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,398 +0,0 @@
|
|||
package world.bentobox.level.calculators;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChunkSnapshot;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import com.google.common.collect.HashMultiset;
|
||||
import com.google.common.collect.Multiset;
|
||||
import com.google.common.collect.Multiset.Entry;
|
||||
import com.google.common.collect.Multisets;
|
||||
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.util.Pair;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
|
||||
public class CalcIslandLevel {
|
||||
|
||||
private static final int MAX_CHUNKS = 200;
|
||||
private static final long SPEED = 1;
|
||||
private static final String LINE_BREAK = "==================================";
|
||||
private boolean checking;
|
||||
private final BukkitTask task;
|
||||
|
||||
private final Level addon;
|
||||
|
||||
private final Set<Pair<Integer, Integer>> chunksToScan;
|
||||
private final Island island;
|
||||
private final World world;
|
||||
private final Results result;
|
||||
private final Runnable onExit;
|
||||
|
||||
// Copy the limits hash map
|
||||
private final HashMap<Material, Integer> limitCount;
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the island's level
|
||||
* Results are available in {@link CalcIslandLevel.Results}
|
||||
* @param addon - Level addon
|
||||
* @param island - island to be calculated
|
||||
* @param onExit - what to run when done
|
||||
*/
|
||||
public CalcIslandLevel(final Level addon, final Island island, final Runnable onExit) {
|
||||
this.addon = addon;
|
||||
this.island = island;
|
||||
this.world = island.getCenter().getWorld();
|
||||
this.limitCount = new HashMap<>(addon.getSettings().getBlockLimits());
|
||||
this.onExit = onExit;
|
||||
|
||||
// Results go here
|
||||
result = new Results();
|
||||
|
||||
// Set the initial island handicap
|
||||
result.initialLevel = addon.getInitialIslandLevel(island);
|
||||
|
||||
// Get chunks to scan
|
||||
chunksToScan = getChunksToScan(island);
|
||||
|
||||
// Start checking
|
||||
checking = true;
|
||||
|
||||
// Start a recurring task until done or cancelled
|
||||
task = addon.getServer().getScheduler().runTaskTimer(addon.getPlugin(), () -> {
|
||||
Set<ChunkSnapshot> chunkSnapshot = new HashSet<>();
|
||||
if (checking) {
|
||||
Iterator<Pair<Integer, Integer>> it = chunksToScan.iterator();
|
||||
if (!it.hasNext()) {
|
||||
// Nothing left
|
||||
tidyUp();
|
||||
return;
|
||||
}
|
||||
// Add chunk snapshots to the list
|
||||
while (it.hasNext() && chunkSnapshot.size() < MAX_CHUNKS) {
|
||||
Pair<Integer, Integer> pair = it.next();
|
||||
if (!world.isChunkLoaded(pair.x, pair.z)) {
|
||||
world.loadChunk(pair.x, pair.z);
|
||||
chunkSnapshot.add(world.getChunkAt(pair.x, pair.z).getChunkSnapshot());
|
||||
world.unloadChunk(pair.x, pair.z);
|
||||
} else {
|
||||
chunkSnapshot.add(world.getChunkAt(pair.x, pair.z).getChunkSnapshot());
|
||||
}
|
||||
it.remove();
|
||||
}
|
||||
// Move to next step
|
||||
checking = false;
|
||||
checkChunksAsync(chunkSnapshot);
|
||||
}
|
||||
}, 0L, SPEED);
|
||||
}
|
||||
|
||||
private void checkChunksAsync(final Set<ChunkSnapshot> chunkSnapshot) {
|
||||
// Run async task to scan chunks
|
||||
addon.getServer().getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> {
|
||||
for (ChunkSnapshot chunk: chunkSnapshot) {
|
||||
scanChunk(chunk);
|
||||
}
|
||||
// Nothing happened, change state
|
||||
checking = true;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void scanChunk(ChunkSnapshot chunk) {
|
||||
for (int x = 0; x< 16; x++) {
|
||||
// Check if the block coordinate is inside the protection zone and if not, don't count it
|
||||
if (chunk.getX() * 16 + x < island.getMinProtectedX() || chunk.getX() * 16 + x >= island.getMinProtectedX() + island.getProtectionRange() * 2) {
|
||||
continue;
|
||||
}
|
||||
for (int z = 0; z < 16; z++) {
|
||||
// Check if the block coordinate is inside the protection zone and if not, don't count it
|
||||
if (chunk.getZ() * 16 + z < island.getMinProtectedZ() || chunk.getZ() * 16 + z >= island.getMinProtectedZ() + island.getProtectionRange() * 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int y = 0; y < island.getCenter().getWorld().getMaxHeight(); y++) {
|
||||
Material blockData = chunk.getBlockType(x, y, z);
|
||||
int seaHeight = addon.getPlugin().getIWM().getSeaHeight(world);
|
||||
boolean belowSeaLevel = seaHeight > 0 && y <= seaHeight;
|
||||
// Air is free
|
||||
if (!blockData.equals(Material.AIR)) {
|
||||
checkBlock(blockData, belowSeaLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkBlock(Material md, boolean belowSeaLevel) {
|
||||
int count = limitCount(md);
|
||||
if (belowSeaLevel) {
|
||||
result.underWaterBlockCount += count;
|
||||
result.uwCount.add(md);
|
||||
} else {
|
||||
result.rawBlockCount += count;
|
||||
result.mdCount.add(md);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a block has been limited or not and whether a block has any value or not
|
||||
* @param md Material
|
||||
* @return value of the block if can be counted
|
||||
*/
|
||||
private int limitCount(Material md) {
|
||||
if (limitCount.containsKey(md)) {
|
||||
int count = limitCount.get(md);
|
||||
if (count > 0) {
|
||||
limitCount.put(md, --count);
|
||||
return getValue(md);
|
||||
} else {
|
||||
result.ofCount.add(md);
|
||||
return 0;
|
||||
}
|
||||
} else if (addon.getSettings().getBlockValues().containsKey(md)) {
|
||||
return getValue(md);
|
||||
} else {
|
||||
result.ncCount.add(md);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value of a material
|
||||
* World blocks trump regular block values
|
||||
* @param md - Material to check
|
||||
* @return value of a material
|
||||
*/
|
||||
private int getValue(Material md) {
|
||||
if (addon.getSettings().getWorldBlockValues().containsKey(world) && addon.getSettings().getWorldBlockValues().get(world).containsKey(md)) {
|
||||
return addon.getSettings().getWorldBlockValues().get(world).get(md);
|
||||
}
|
||||
return addon.getSettings().getBlockValues().getOrDefault(md, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a set of all the chunks in island
|
||||
* @param island - island
|
||||
* @return - set of pairs of x,z coordinates to check
|
||||
*/
|
||||
private Set<Pair<Integer, Integer>> getChunksToScan(Island island) {
|
||||
Set<Pair<Integer, Integer>> chunkSnapshot = new HashSet<>();
|
||||
for (int x = island.getMinProtectedX(); x < (island.getMinProtectedX() + island.getProtectionRange() * 2 + 16); x += 16) {
|
||||
for (int z = island.getMinProtectedZ(); z < (island.getMinProtectedZ() + island.getProtectionRange() * 2 + 16); z += 16) {
|
||||
Pair<Integer, Integer> pair = new Pair<>(world.getBlockAt(x, 0, z).getChunk().getX(), world.getBlockAt(x, 0, z).getChunk().getZ());
|
||||
chunkSnapshot.add(pair);
|
||||
}
|
||||
}
|
||||
return chunkSnapshot;
|
||||
}
|
||||
|
||||
private void tidyUp() {
|
||||
// Cancel
|
||||
task.cancel();
|
||||
// Finalize calculations
|
||||
result.rawBlockCount += (long)(result.underWaterBlockCount * addon.getSettings().getUnderWaterMultiplier());
|
||||
|
||||
// Set the death penalty
|
||||
if (this.addon.getSettings().isSumTeamDeaths())
|
||||
{
|
||||
for (UUID uuid : this.island.getMemberSet())
|
||||
{
|
||||
this.result.deathHandicap += this.addon.getPlayers().getDeaths(this.world, uuid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// At this point, it may be that the island has become unowned.
|
||||
this.result.deathHandicap = this.island.getOwner() == null ? 0 :
|
||||
this.addon.getPlayers().getDeaths(this.world, this.island.getOwner());
|
||||
}
|
||||
|
||||
// Just lazy check for min death count.
|
||||
this.result.deathHandicap = Math.min(this.result.deathHandicap, this.addon.getSettings().getMaxDeaths());
|
||||
|
||||
long blockAndDeathPoints = this.result.rawBlockCount;
|
||||
|
||||
if (this.addon.getSettings().getDeathPenalty() > 0)
|
||||
{
|
||||
// Proper death penalty calculation.
|
||||
blockAndDeathPoints -= this.result.deathHandicap * this.addon.getSettings().getDeathPenalty();
|
||||
}
|
||||
|
||||
this.result.level = blockAndDeathPoints / this.addon.getSettings().getLevelCost() - this.island.getLevelHandicap() - result.initialLevel;
|
||||
|
||||
|
||||
// Calculate how many points are required to get to the next level
|
||||
this.result.pointsToNextLevel = this.addon.getSettings().getLevelCost() -
|
||||
(blockAndDeathPoints % this.addon.getSettings().getLevelCost());
|
||||
|
||||
// Report
|
||||
result.report = getReport();
|
||||
// All done.
|
||||
if (onExit != null) {
|
||||
Bukkit.getScheduler().runTask(addon.getPlugin(), onExit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<String> getReport() {
|
||||
List<String> reportLines = new ArrayList<>();
|
||||
// provide counts
|
||||
reportLines.add("Level Log for island in " + addon.getPlugin().getIWM().getFriendlyName(island.getWorld()) + " at " + Util.xyz(island.getCenter().toVector()));
|
||||
reportLines.add("Island owner UUID = " + island.getOwner());
|
||||
reportLines.add("Total block value count = " + String.format("%,d",result.rawBlockCount));
|
||||
reportLines.add("Level cost = " + addon.getSettings().getLevelCost());
|
||||
reportLines.add("Deaths handicap = " + result.deathHandicap);
|
||||
reportLines.add("Initial island level = " + (0L - result.initialLevel));
|
||||
reportLines.add("Level calculated = " + result.level);
|
||||
reportLines.add(LINE_BREAK);
|
||||
int total = 0;
|
||||
if (!result.uwCount.isEmpty()) {
|
||||
reportLines.add("Underwater block count (Multiplier = x" + addon.getSettings().getUnderWaterMultiplier() + ") value");
|
||||
reportLines.add("Total number of underwater blocks = " + String.format("%,d",result.uwCount.size()));
|
||||
reportLines.addAll(sortedReport(total, result.uwCount));
|
||||
}
|
||||
reportLines.add("Regular block count");
|
||||
reportLines.add("Total number of blocks = " + String.format("%,d",result.mdCount.size()));
|
||||
reportLines.addAll(sortedReport(total, result.mdCount));
|
||||
|
||||
reportLines.add("Blocks not counted because they exceeded limits: " + String.format("%,d",result.ofCount.size()));
|
||||
Iterable<Multiset.Entry<Material>> entriesSortedByCount = result.ofCount.entrySet();
|
||||
Iterator<Entry<Material>> it = entriesSortedByCount.iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<Material> type = it.next();
|
||||
Integer limit = addon.getSettings().getBlockLimits().get(type.getElement());
|
||||
String explain = ")";
|
||||
if (limit == null) {
|
||||
Material generic = type.getElement();
|
||||
limit = addon.getSettings().getBlockLimits().get(generic);
|
||||
explain = " - All types)";
|
||||
}
|
||||
reportLines.add(type.getElement().toString() + ": " + String.format("%,d",type.getCount()) + " blocks (max " + limit + explain);
|
||||
}
|
||||
reportLines.add(LINE_BREAK);
|
||||
reportLines.add("Blocks on island that are not in config.yml");
|
||||
reportLines.add("Total number = " + String.format("%,d",result.ncCount.size()));
|
||||
entriesSortedByCount = result.ncCount.entrySet();
|
||||
it = entriesSortedByCount.iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<Material> type = it.next();
|
||||
reportLines.add(type.getElement().toString() + ": " + String.format("%,d",type.getCount()) + " blocks");
|
||||
}
|
||||
reportLines.add(LINE_BREAK);
|
||||
|
||||
return reportLines;
|
||||
}
|
||||
|
||||
private Collection<String> sortedReport(int total, Multiset<Material> MaterialCount) {
|
||||
Collection<String> r = new ArrayList<>();
|
||||
Iterable<Multiset.Entry<Material>> entriesSortedByCount = Multisets.copyHighestCountFirst(MaterialCount).entrySet();
|
||||
for (Entry<Material> en : entriesSortedByCount) {
|
||||
Material type = en.getElement();
|
||||
|
||||
int value = 0;
|
||||
if (addon.getSettings().getBlockValues().containsKey(type)) {
|
||||
// Specific
|
||||
value = addon.getSettings().getBlockValues().get(type);
|
||||
}
|
||||
r.add(type.toString() + ":"
|
||||
+ String.format("%,d", en.getCount()) + " blocks x " + value + " = " + (value * en.getCount()));
|
||||
total += (value * en.getCount());
|
||||
}
|
||||
r.add("Subtotal = " + total);
|
||||
r.add(LINE_BREAK);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the result
|
||||
*/
|
||||
public Results getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Results class
|
||||
*
|
||||
*/
|
||||
public class Results {
|
||||
private List<String> report;
|
||||
private final Multiset<Material> mdCount = HashMultiset.create();
|
||||
private final Multiset<Material> uwCount = HashMultiset.create();
|
||||
private final Multiset<Material> ncCount = HashMultiset.create();
|
||||
private final Multiset<Material> ofCount = HashMultiset.create();
|
||||
private long rawBlockCount = 0;
|
||||
private long underWaterBlockCount = 0;
|
||||
private long level = 0;
|
||||
private int deathHandicap = 0;
|
||||
private long pointsToNextLevel = 0;
|
||||
private long initialLevel = 0;
|
||||
|
||||
/**
|
||||
* @return the deathHandicap
|
||||
*/
|
||||
public int getDeathHandicap() {
|
||||
return deathHandicap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the report
|
||||
*/
|
||||
public List<String> getReport() {
|
||||
return report;
|
||||
}
|
||||
/**
|
||||
* Set level
|
||||
* @param level - level
|
||||
*/
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
/**
|
||||
* @return the level
|
||||
*/
|
||||
public long getLevel() {
|
||||
return level;
|
||||
}
|
||||
/**
|
||||
* @return the pointsToNextLevel
|
||||
*/
|
||||
public long getPointsToNextLevel() {
|
||||
return pointsToNextLevel;
|
||||
}
|
||||
|
||||
public long getInitialLevel() {
|
||||
return initialLevel;
|
||||
}
|
||||
|
||||
public void setInitialLevel(long initialLevel) {
|
||||
this.initialLevel = initialLevel;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Results [report=" + report + ", mdCount=" + mdCount + ", uwCount=" + uwCount + ", ncCount="
|
||||
+ ncCount + ", ofCount=" + ofCount + ", rawBlockCount=" + rawBlockCount + ", underWaterBlockCount="
|
||||
+ underWaterBlockCount + ", level=" + level + ", deathHandicap=" + deathHandicap
|
||||
+ ", pointsToNextLevel=" + pointsToNextLevel + ", initialLevel=" + initialLevel + "]";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
package world.bentobox.level.calculators;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
/**
|
||||
* Utility class to evaluate equations
|
||||
*/
|
||||
public class EquationEvaluator {
|
||||
|
||||
private static class Parser {
|
||||
private final String input;
|
||||
private int pos = -1;
|
||||
private int currentChar;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Parser() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public Parser(String input) {
|
||||
this.input = input;
|
||||
moveToNextChar();
|
||||
}
|
||||
|
||||
private void moveToNextChar() {
|
||||
currentChar = (++pos < input.length()) ? input.charAt(pos) : -1;
|
||||
}
|
||||
|
||||
private boolean tryToEat(int charToEat) {
|
||||
while (currentChar == ' ') {
|
||||
moveToNextChar();
|
||||
}
|
||||
if (currentChar == charToEat) {
|
||||
moveToNextChar();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public double evaluate() throws ParseException {
|
||||
double result = parseExpression();
|
||||
if (pos < input.length()) {
|
||||
throw new ParseException("Unexpected character: " + (char) currentChar, pos);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private double parseExpression() throws ParseException {
|
||||
double result = parseTerm();
|
||||
while (true) {
|
||||
if (tryToEat('+')) {
|
||||
result += parseTerm();
|
||||
} else if (tryToEat('-')) {
|
||||
result -= parseTerm();
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private double parseFactor() throws ParseException {
|
||||
if (tryToEat('+')) {
|
||||
return parseFactor(); // unary plus
|
||||
}
|
||||
if (tryToEat('-')) {
|
||||
return -parseFactor(); // unary minus
|
||||
}
|
||||
double x;
|
||||
int startPos = this.pos;
|
||||
if (tryToEat('(')) { // parentheses
|
||||
x = parseExpression();
|
||||
tryToEat(')');
|
||||
} else if ((currentChar >= '0' && currentChar <= '9') || currentChar == '.') { // numbers
|
||||
while ((currentChar >= '0' && currentChar <= '9') || currentChar == '.') {
|
||||
moveToNextChar();
|
||||
}
|
||||
x = Double.parseDouble(input.substring(startPos, this.pos));
|
||||
} else if (currentChar >= 'a' && currentChar <= 'z') { // functions
|
||||
while (currentChar >= 'a' && currentChar <= 'z') {
|
||||
moveToNextChar();
|
||||
}
|
||||
String func = input.substring(startPos, this.pos);
|
||||
x = parseFactor();
|
||||
x = switch (func) {
|
||||
case "sqrt" -> Math.sqrt(x);
|
||||
case "sin" -> Math.sin(Math.toRadians(x));
|
||||
case "cos" -> Math.cos(Math.toRadians(x));
|
||||
case "tan" -> Math.tan(Math.toRadians(x));
|
||||
case "log" -> Math.log(x);
|
||||
default -> throw new ParseException("Unknown function: " + func, startPos);
|
||||
};
|
||||
} else {
|
||||
throw new ParseException("Unexpected: " + (char) currentChar, startPos);
|
||||
}
|
||||
|
||||
if (tryToEat('^')) {
|
||||
x = Math.pow(x, parseFactor()); // exponentiation
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
private double parseTerm() throws ParseException {
|
||||
double x = parseFactor();
|
||||
for (;;) {
|
||||
if (tryToEat('*'))
|
||||
x *= parseFactor(); // multiplication
|
||||
else if (tryToEat('/'))
|
||||
x /= parseFactor(); // division
|
||||
else
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static double eval(final String equation) throws ParseException {
|
||||
return new Parser(equation).evaluate();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,659 @@
|
|||
package world.bentobox.level.calculators;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.ChunkSnapshot;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Container;
|
||||
import org.bukkit.block.CreatureSpawner;
|
||||
import org.bukkit.block.ShulkerBox;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Slab;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.BlockStateMeta;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import com.bgsoftware.wildstacker.api.WildStackerAPI;
|
||||
import com.bgsoftware.wildstacker.api.objects.StackedBarrel;
|
||||
import com.google.common.collect.Multiset;
|
||||
import com.google.common.collect.Multiset.Entry;
|
||||
import com.google.common.collect.Multisets;
|
||||
|
||||
import dev.rosewood.rosestacker.api.RoseStackerAPI;
|
||||
import us.lynuxcraft.deadsilenceiv.advancedchests.AdvancedChestsAPI;
|
||||
import us.lynuxcraft.deadsilenceiv.advancedchests.chest.AdvancedChest;
|
||||
import us.lynuxcraft.deadsilenceiv.advancedchests.chest.gui.page.ChestPage;
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.util.Pair;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.calculators.Results.Result;
|
||||
|
||||
public class IslandLevelCalculator {
|
||||
private static final String LINE_BREAK = "==================================";
|
||||
public static final long MAX_AMOUNT = 10000000;
|
||||
private static final List<Material> CHESTS = Arrays.asList(Material.CHEST, Material.CHEST_MINECART,
|
||||
Material.TRAPPED_CHEST, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX,
|
||||
Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX,
|
||||
Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX,
|
||||
Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX,
|
||||
Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.RED_SHULKER_BOX,
|
||||
Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX, Material.COMPOSTER, Material.BARREL,
|
||||
Material.DISPENSER, Material.DROPPER, Material.SMOKER, Material.BLAST_FURNACE);
|
||||
private static final int CHUNKS_TO_SCAN = 100;
|
||||
private final Level addon;
|
||||
private final Queue<Pair<Integer, Integer>> chunksToCheck;
|
||||
private final Island island;
|
||||
private final Map<Material, Integer> limitCount;
|
||||
private final CompletableFuture<Results> r;
|
||||
|
||||
private final Results results;
|
||||
private long duration;
|
||||
private final boolean zeroIsland;
|
||||
private final Map<Environment, World> worlds = new EnumMap<>(Environment.class);
|
||||
private final int seaHeight;
|
||||
private final List<Location> stackedBlocks = new ArrayList<>();
|
||||
private final Set<Chunk> chestBlocks = new HashSet<>();
|
||||
private BukkitTask finishTask;
|
||||
|
||||
/**
|
||||
* Constructor to get the level for an island
|
||||
*
|
||||
* @param addon - Level addon
|
||||
* @param island - the island to scan
|
||||
* @param r - completable result that will be completed when the
|
||||
* calculation is complete
|
||||
* @param zeroIsland - true if the calculation is due to an island zeroing
|
||||
*/
|
||||
public IslandLevelCalculator(Level addon, Island island, CompletableFuture<Results> r, boolean zeroIsland) {
|
||||
this.addon = addon;
|
||||
this.island = island;
|
||||
this.r = r;
|
||||
this.zeroIsland = zeroIsland;
|
||||
results = new Results();
|
||||
duration = System.currentTimeMillis();
|
||||
chunksToCheck = getChunksToScan(island);
|
||||
this.limitCount = new EnumMap<>(addon.getBlockConfig().getBlockLimits());
|
||||
// Get the initial island level
|
||||
results.initialLevel.set(addon.getInitialIslandLevel(island));
|
||||
// Set up the worlds
|
||||
worlds.put(Environment.NORMAL, Util.getWorld(island.getWorld()));
|
||||
// Nether
|
||||
if (addon.getSettings().isNether()) {
|
||||
World nether = addon.getPlugin().getIWM().getNetherWorld(island.getWorld());
|
||||
if (nether != null) {
|
||||
worlds.put(Environment.NETHER, nether);
|
||||
}
|
||||
}
|
||||
// End
|
||||
if (addon.getSettings().isEnd()) {
|
||||
World end = addon.getPlugin().getIWM().getEndWorld(island.getWorld());
|
||||
if (end != null) {
|
||||
worlds.put(Environment.THE_END, end);
|
||||
}
|
||||
}
|
||||
// Sea Height
|
||||
seaHeight = addon.getPlugin().getIWM().getSeaHeight(island.getWorld());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the level based on the raw points
|
||||
*
|
||||
* @param blockAndDeathPoints - raw points counted on island
|
||||
* @return level of island
|
||||
*/
|
||||
private long calculateLevel(long blockAndDeathPoints) {
|
||||
String calcString = addon.getSettings().getLevelCalc();
|
||||
String withValues = calcString.replace("blocks", String.valueOf(blockAndDeathPoints)).replace("level_cost",
|
||||
String.valueOf(this.addon.getSettings().getLevelCost()));
|
||||
long evalWithValues;
|
||||
try {
|
||||
evalWithValues = (long) EquationEvaluator.eval(withValues);
|
||||
return evalWithValues - (addon.getSettings().isZeroNewIslandLevels() ? results.initialLevel.get() : 0);
|
||||
|
||||
} catch (ParseException e) {
|
||||
addon.getPlugin().logStacktrace(e);
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds value to the results based on the material and whether the block is
|
||||
* below sea level or not
|
||||
*
|
||||
* @param mat - material of the block
|
||||
* @param belowSeaLevel - true if below sea level
|
||||
*/
|
||||
private void checkBlock(Material mat, boolean belowSeaLevel) {
|
||||
int count = limitCount(mat);
|
||||
if (belowSeaLevel) {
|
||||
results.underWaterBlockCount.addAndGet(count);
|
||||
results.uwCount.add(mat);
|
||||
} else {
|
||||
results.rawBlockCount.addAndGet(count);
|
||||
results.mdCount.add(mat);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a set of all the chunks in island
|
||||
*
|
||||
* @param island - island
|
||||
* @return - set of pairs of x,z coordinates to check
|
||||
*/
|
||||
private Queue<Pair<Integer, Integer>> getChunksToScan(Island island) {
|
||||
Queue<Pair<Integer, Integer>> chunkQueue = new ConcurrentLinkedQueue<>();
|
||||
for (int x = island.getMinProtectedX(); x < (island.getMinProtectedX() + island.getProtectionRange() * 2
|
||||
+ 16); x += 16) {
|
||||
for (int z = island.getMinProtectedZ(); z < (island.getMinProtectedZ() + island.getProtectionRange() * 2
|
||||
+ 16); z += 16) {
|
||||
chunkQueue.add(new Pair<>(x >> 4, z >> 4));
|
||||
}
|
||||
}
|
||||
return chunkQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the island
|
||||
*/
|
||||
public Island getIsland() {
|
||||
return island;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the completable result for this calculation
|
||||
*
|
||||
* @return the r
|
||||
*/
|
||||
public CompletableFuture<Results> getR() {
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full analysis report
|
||||
*
|
||||
* @return a list of lines
|
||||
*/
|
||||
private List<String> getReport() {
|
||||
List<String> reportLines = new ArrayList<>();
|
||||
// provide counts
|
||||
reportLines.add("Level Log for island in " + addon.getPlugin().getIWM().getFriendlyName(island.getWorld())
|
||||
+ " at " + Util.xyz(island.getCenter().toVector()));
|
||||
reportLines.add("Island owner UUID = " + island.getOwner());
|
||||
reportLines.add("Total block value count = " + String.format("%,d", results.rawBlockCount.get()));
|
||||
reportLines.add("Formula to calculate island level: " + addon.getSettings().getLevelCalc());
|
||||
reportLines.add("Level cost = " + addon.getSettings().getLevelCost());
|
||||
reportLines.add("Deaths handicap = " + results.deathHandicap.get());
|
||||
if (addon.getSettings().isZeroNewIslandLevels()) {
|
||||
reportLines.add("Initial island level = " + (0L - addon.getManager().getInitialLevel(island)));
|
||||
}
|
||||
reportLines.add("Previous level = " + addon.getManager().getIslandLevel(island.getWorld(), island.getOwner()));
|
||||
reportLines.add("New level = " + results.getLevel());
|
||||
reportLines.add(LINE_BREAK);
|
||||
int total = 0;
|
||||
if (!results.uwCount.isEmpty()) {
|
||||
reportLines.add("Underwater block count (Multiplier = x" + addon.getSettings().getUnderWaterMultiplier()
|
||||
+ ") value");
|
||||
reportLines.add("Total number of underwater blocks = " + String.format("%,d", results.uwCount.size()));
|
||||
reportLines.addAll(sortedReport(total, results.uwCount));
|
||||
}
|
||||
reportLines.add("Regular block count");
|
||||
reportLines.add("Total number of blocks = " + String.format("%,d", results.mdCount.size()));
|
||||
reportLines.addAll(sortedReport(total, results.mdCount));
|
||||
|
||||
reportLines.add(
|
||||
"Blocks not counted because they exceeded limits: " + String.format("%,d", results.ofCount.size()));
|
||||
Iterable<Multiset.Entry<Material>> entriesSortedByCount = results.ofCount.entrySet();
|
||||
Iterator<Entry<Material>> it = entriesSortedByCount.iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<Material> type = it.next();
|
||||
Integer limit = addon.getBlockConfig().getBlockLimits().get(type.getElement());
|
||||
String explain = ")";
|
||||
if (limit == null) {
|
||||
Material generic = type.getElement();
|
||||
limit = addon.getBlockConfig().getBlockLimits().get(generic);
|
||||
explain = " - All types)";
|
||||
}
|
||||
reportLines.add(type.getElement().toString() + ": " + String.format("%,d", type.getCount())
|
||||
+ " blocks (max " + limit + explain);
|
||||
}
|
||||
reportLines.add(LINE_BREAK);
|
||||
reportLines.add("Blocks on island that are not in config.yml");
|
||||
reportLines.add("Total number = " + String.format("%,d", results.ncCount.size()));
|
||||
entriesSortedByCount = results.ncCount.entrySet();
|
||||
it = entriesSortedByCount.iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<Material> type = it.next();
|
||||
reportLines.add(type.getElement().toString() + ": " + String.format("%,d", type.getCount()) + " blocks");
|
||||
}
|
||||
reportLines.add(LINE_BREAK);
|
||||
|
||||
return reportLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the results
|
||||
*/
|
||||
public Results getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value of a material World blocks trump regular block values
|
||||
*
|
||||
* @param md - Material to check
|
||||
* @return value of a material
|
||||
*/
|
||||
private int getValue(Material md) {
|
||||
Integer value = addon.getBlockConfig().getValue(island.getWorld(), md);
|
||||
if (value == null) {
|
||||
// Not in config
|
||||
results.ncCount.add(md);
|
||||
return 0;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a chunk async
|
||||
*
|
||||
* @param env - the environment
|
||||
* @param pairList - chunk coordinate
|
||||
* @return a future chunk or future null if there is no chunk to load, e.g.,
|
||||
* there is no island nether
|
||||
*/
|
||||
private CompletableFuture<List<Chunk>> getWorldChunk(Environment env, Queue<Pair<Integer, Integer>> pairList) {
|
||||
if (worlds.containsKey(env)) {
|
||||
CompletableFuture<List<Chunk>> r2 = new CompletableFuture<>();
|
||||
List<Chunk> chunkList = new ArrayList<>();
|
||||
World world = worlds.get(env);
|
||||
// Get the chunk, and then coincidentally check the RoseStacker
|
||||
loadChunks(r2, world, pairList, chunkList);
|
||||
return r2;
|
||||
}
|
||||
return CompletableFuture.completedFuture(Collections.emptyList());
|
||||
}
|
||||
|
||||
private void loadChunks(CompletableFuture<List<Chunk>> r2, World world, Queue<Pair<Integer, Integer>> pairList,
|
||||
List<Chunk> chunkList) {
|
||||
if (pairList.isEmpty()) {
|
||||
r2.complete(chunkList);
|
||||
return;
|
||||
}
|
||||
Pair<Integer, Integer> p = pairList.poll();
|
||||
Util.getChunkAtAsync(world, p.x, p.z, world.getEnvironment().equals(Environment.NETHER)).thenAccept(chunk -> {
|
||||
if (chunk != null) {
|
||||
chunkList.add(chunk);
|
||||
roseStackerCheck(chunk);
|
||||
}
|
||||
loadChunks(r2, world, pairList, chunkList); // Iteration
|
||||
});
|
||||
}
|
||||
|
||||
private void roseStackerCheck(Chunk chunk) {
|
||||
if (addon.isRoseStackersEnabled()) {
|
||||
RoseStackerAPI.getInstance().getStackedBlocks(Collections.singletonList(chunk)).forEach(e -> {
|
||||
// Blocks below sea level can be scored differently
|
||||
boolean belowSeaLevel = seaHeight > 0 && e.getLocation().getY() <= seaHeight;
|
||||
// Check block once because the base block will be counted in the chunk snapshot
|
||||
for (int _x = 0; _x < e.getStackSize() - 1; _x++) {
|
||||
checkBlock(e.getBlock().getType(), belowSeaLevel);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a block has been limited or not and whether a block has any value
|
||||
* or not
|
||||
*
|
||||
* @param md Material
|
||||
* @return value of the block if can be counted
|
||||
*/
|
||||
private int limitCount(Material md) {
|
||||
if (limitCount.containsKey(md)) {
|
||||
int count = limitCount.get(md);
|
||||
if (count > 0) {
|
||||
limitCount.put(md, --count);
|
||||
return getValue(md);
|
||||
} else {
|
||||
results.ofCount.add(md);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return getValue(md);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan all containers in a chunk and count their blocks
|
||||
*
|
||||
* @param chunk - the chunk to scan
|
||||
*/
|
||||
private void scanChests(Chunk chunk) {
|
||||
// Count blocks in chests
|
||||
for (BlockState bs : chunk.getTileEntities()) {
|
||||
if (bs instanceof Container container) {
|
||||
if (addon.isAdvChestEnabled()) {
|
||||
AdvancedChest<?, ?> aChest = AdvancedChestsAPI.getChestManager().getAdvancedChest(bs.getLocation());
|
||||
if (aChest != null && aChest.getChestType().getName().equals("NORMAL")) {
|
||||
aChest.getPages().stream().map(ChestPage::getItems).forEach(c -> {
|
||||
for (Object i : c) {
|
||||
countItemStack((ItemStack) i);
|
||||
}
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Regular chest
|
||||
container.getSnapshotInventory().forEach(this::countItemStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void countItemStack(ItemStack i) {
|
||||
if (i == null || !i.getType().isBlock())
|
||||
return;
|
||||
|
||||
for (int c = 0; c < i.getAmount(); c++) {
|
||||
if (addon.getSettings().isIncludeShulkersInChest()
|
||||
&& i.getItemMeta() instanceof BlockStateMeta blockStateMeta
|
||||
&& blockStateMeta.getBlockState() instanceof ShulkerBox shulkerBox) {
|
||||
shulkerBox.getSnapshotInventory().forEach(this::countItemStack);
|
||||
}
|
||||
|
||||
checkBlock(i.getType(), false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the chunk chests and count the blocks. Note that the chunks are a list
|
||||
* of all the island chunks in a particular world, so the memory usage is high,
|
||||
* but I think most servers can handle it.
|
||||
*
|
||||
* @param chunks - a list of chunks to scan
|
||||
* @return future that completes when the scan is done and supplies a boolean
|
||||
* that will be true if the scan was successful, false if not
|
||||
*/
|
||||
private CompletableFuture<Boolean> scanChunk(List<Chunk> chunks) {
|
||||
// If the chunk hasn't been generated, return
|
||||
if (chunks == null || chunks.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
// Count blocks in chunk
|
||||
CompletableFuture<Boolean> result = new CompletableFuture<>();
|
||||
/*
|
||||
* At this point, we need to grab a snapshot of each chunk and then scan it
|
||||
* async. At the end, we make the CompletableFuture true to show it is done. I'm
|
||||
* not sure how much lag this will cause, but as all the chunks are loaded,
|
||||
* maybe not that much.
|
||||
*/
|
||||
List<ChunkPair> preLoad = chunks.stream().map(c -> new ChunkPair(c.getWorld(), c, c.getChunkSnapshot()))
|
||||
.toList();
|
||||
Bukkit.getScheduler().runTaskAsynchronously(BentoBox.getInstance(), () -> {
|
||||
preLoad.forEach(this::scanAsync);
|
||||
// Once they are all done, return to the main thread.
|
||||
Bukkit.getScheduler().runTask(addon.getPlugin(), () -> result.complete(true));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
record ChunkPair(World world, Chunk chunk, ChunkSnapshot chunkSnapshot) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the blocks on the island
|
||||
*
|
||||
* @param cp chunk to scan
|
||||
*/
|
||||
private void scanAsync(ChunkPair cp) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
// Check if the block coordinate is inside the protection zone and if not, don't
|
||||
// count it
|
||||
if (cp.chunkSnapshot.getX() * 16 + x < island.getMinProtectedX() || cp.chunkSnapshot.getX() * 16
|
||||
+ x >= island.getMinProtectedX() + island.getProtectionRange() * 2) {
|
||||
continue;
|
||||
}
|
||||
for (int z = 0; z < 16; z++) {
|
||||
// Check if the block coordinate is inside the protection zone and if not, don't
|
||||
// count it
|
||||
if (cp.chunkSnapshot.getZ() * 16 + z < island.getMinProtectedZ() || cp.chunkSnapshot.getZ() * 16
|
||||
+ z >= island.getMinProtectedZ() + island.getProtectionRange() * 2) {
|
||||
continue;
|
||||
}
|
||||
// Only count to the highest block in the world for some optimization
|
||||
for (int y = cp.world.getMinHeight(); y < cp.world.getMaxHeight(); y++) {
|
||||
BlockData blockData = cp.chunkSnapshot.getBlockData(x, y, z);
|
||||
Material m = blockData.getMaterial();
|
||||
boolean belowSeaLevel = seaHeight > 0 && y <= seaHeight;
|
||||
// Slabs can be doubled, so check them twice
|
||||
if (Tag.SLABS.isTagged(m)) {
|
||||
Slab slab = (Slab) blockData;
|
||||
if (slab.getType().equals(Slab.Type.DOUBLE)) {
|
||||
checkBlock(m, belowSeaLevel);
|
||||
}
|
||||
}
|
||||
// Hook for Wild Stackers (Blocks and Spawners Only) - this has to use the real
|
||||
// chunk
|
||||
if (addon.isStackersEnabled() && (m.equals(Material.CAULDRON) || m.equals(Material.SPAWNER))) {
|
||||
stackedBlocks.add(new Location(cp.world, (double) x + cp.chunkSnapshot.getX() * 16, y,
|
||||
(double) z + cp.chunkSnapshot.getZ() * 16));
|
||||
}
|
||||
|
||||
if (addon.isUltimateStackerEnabled() && !m.isAir()) {
|
||||
Location l = new Location(cp.chunk.getWorld(), x, y, z);
|
||||
UltimateStackerCalc.addStackers(m, l, results, belowSeaLevel, limitCount(m));
|
||||
}
|
||||
|
||||
// Scan chests
|
||||
if (addon.getSettings().isIncludeChests() && CHESTS.contains(m)) {
|
||||
chestBlocks.add(cp.chunk);
|
||||
}
|
||||
// Add the value of the block's material
|
||||
checkBlock(m, belowSeaLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the next chunk on the island
|
||||
*
|
||||
* @return completable boolean future that will be true if more chunks are left
|
||||
* to be scanned, and false if not
|
||||
*/
|
||||
public CompletableFuture<Boolean> scanNextChunk() {
|
||||
if (chunksToCheck.isEmpty()) {
|
||||
addon.logError("Unexpected: no chunks to scan!");
|
||||
// This should not be needed, but just in case
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
// Retrieve and remove from the queue
|
||||
Queue<Pair<Integer, Integer>> pairList = new ConcurrentLinkedQueue<>();
|
||||
int i = 0;
|
||||
while (!chunksToCheck.isEmpty() && i++ < CHUNKS_TO_SCAN) {
|
||||
pairList.add(chunksToCheck.poll());
|
||||
}
|
||||
Queue<Pair<Integer, Integer>> endPairList = new ConcurrentLinkedQueue<>(pairList);
|
||||
Queue<Pair<Integer, Integer>> netherPairList = new ConcurrentLinkedQueue<>(pairList);
|
||||
// Set up the result
|
||||
CompletableFuture<Boolean> result = new CompletableFuture<>();
|
||||
// Get chunks and scan
|
||||
// Get chunks and scan
|
||||
getWorldChunk(Environment.THE_END, endPairList).thenAccept(
|
||||
endChunks -> scanChunk(endChunks).thenAccept(b -> getWorldChunk(Environment.NETHER, netherPairList)
|
||||
.thenAccept(netherChunks -> scanChunk(netherChunks)
|
||||
.thenAccept(b2 -> getWorldChunk(Environment.NORMAL, pairList)
|
||||
.thenAccept(normalChunks -> scanChunk(normalChunks).thenAccept(b3 ->
|
||||
// Complete the result now that all chunks have been scanned
|
||||
result.complete(!chunksToCheck.isEmpty())))))));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Collection<String> sortedReport(int total, Multiset<Material> materialCount) {
|
||||
Collection<String> result = new ArrayList<>();
|
||||
Iterable<Multiset.Entry<Material>> entriesSortedByCount = Multisets.copyHighestCountFirst(materialCount)
|
||||
.entrySet();
|
||||
for (Entry<Material> en : entriesSortedByCount) {
|
||||
Material type = en.getElement();
|
||||
|
||||
int value = getValue(type);
|
||||
|
||||
result.add(type.toString() + ":" + String.format("%,d", en.getCount()) + " blocks x " + value + " = "
|
||||
+ (value * en.getCount()));
|
||||
total += (value * en.getCount());
|
||||
|
||||
}
|
||||
result.add("Subtotal = " + total);
|
||||
result.add(LINE_BREAK);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes the calculations and makes the report
|
||||
*/
|
||||
public void tidyUp() {
|
||||
// Finalize calculations
|
||||
results.rawBlockCount
|
||||
.addAndGet((long) (results.underWaterBlockCount.get() * addon.getSettings().getUnderWaterMultiplier()));
|
||||
|
||||
// Set the death penalty
|
||||
if (this.addon.getSettings().isSumTeamDeaths()) {
|
||||
for (UUID uuid : this.island.getMemberSet()) {
|
||||
this.results.deathHandicap.addAndGet(this.addon.getPlayers().getDeaths(island.getWorld(), uuid));
|
||||
}
|
||||
} else {
|
||||
// At this point, it may be that the island has become unowned.
|
||||
this.results.deathHandicap.set(this.island.getOwner() == null ? 0
|
||||
: this.addon.getPlayers().getDeaths(island.getWorld(), this.island.getOwner()));
|
||||
}
|
||||
|
||||
long blockAndDeathPoints = this.results.rawBlockCount.get();
|
||||
this.results.totalPoints.set(blockAndDeathPoints);
|
||||
|
||||
if (this.addon.getSettings().getDeathPenalty() > 0) {
|
||||
// Proper death penalty calculation.
|
||||
blockAndDeathPoints -= this.results.deathHandicap.get() * this.addon.getSettings().getDeathPenalty();
|
||||
}
|
||||
this.results.level.set(calculateLevel(blockAndDeathPoints));
|
||||
|
||||
// Calculate how many points are required to get to the next level
|
||||
long nextLevel = this.results.level.get();
|
||||
long blocks = blockAndDeathPoints;
|
||||
while (nextLevel < this.results.level.get() + 1 && blocks - blockAndDeathPoints < MAX_AMOUNT) {
|
||||
nextLevel = calculateLevel(++blocks);
|
||||
}
|
||||
this.results.pointsToNextLevel.set(blocks - blockAndDeathPoints);
|
||||
|
||||
// Report
|
||||
results.report = getReport();
|
||||
// Set the duration
|
||||
addon.getPipeliner().setTime(System.currentTimeMillis() - duration);
|
||||
// All done.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the zeroIsland
|
||||
*/
|
||||
boolean isNotZeroIsland() {
|
||||
return !zeroIsland;
|
||||
}
|
||||
|
||||
public void scanIsland(Pipeliner pipeliner) {
|
||||
// Scan the next chunk
|
||||
scanNextChunk().thenAccept(result -> {
|
||||
if (!Bukkit.isPrimaryThread()) {
|
||||
addon.getPlugin().logError("scanChunk not on Primary Thread!");
|
||||
}
|
||||
// Timeout check
|
||||
if (System.currentTimeMillis()
|
||||
- pipeliner.getInProcessQueue().get(this) > addon.getSettings().getCalculationTimeout() * 60000) {
|
||||
// Done
|
||||
pipeliner.getInProcessQueue().remove(this);
|
||||
getR().complete(new Results(Result.TIMEOUT));
|
||||
addon.logError("Level calculation timed out after " + addon.getSettings().getCalculationTimeout()
|
||||
+ "m for island: " + getIsland());
|
||||
if (!isNotZeroIsland()) {
|
||||
addon.logError("Island level was being zeroed.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (Boolean.TRUE.equals(result) && !pipeliner.getTask().isCancelled()) {
|
||||
// scanNextChunk returns true if there are more chunks to scan
|
||||
scanIsland(pipeliner);
|
||||
} else {
|
||||
// Done
|
||||
pipeliner.getInProcessQueue().remove(this);
|
||||
// Chunk finished
|
||||
// This was the last chunk. Handle stacked blocks, then chests and exit
|
||||
handleStackedBlocks().thenCompose(v -> handleChests()).thenRun(() -> {
|
||||
this.tidyUp();
|
||||
this.getR().complete(getResults());
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> handleChests() {
|
||||
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||
for (Chunk v : chestBlocks) {
|
||||
CompletableFuture<Void> future = Util.getChunkAtAsync(v.getWorld(), v.getX(), v.getZ()).thenAccept(c -> {
|
||||
scanChests(c);
|
||||
});
|
||||
futures.add(future);
|
||||
}
|
||||
// Return a CompletableFuture that completes when all futures are done
|
||||
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> handleStackedBlocks() {
|
||||
// Deal with any stacked blocks
|
||||
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||
for (Location v : stackedBlocks) {
|
||||
CompletableFuture<Void> future = Util.getChunkAtAsync(v).thenAccept(c -> {
|
||||
Block stackedBlock = v.getBlock();
|
||||
boolean belowSeaLevel = seaHeight > 0 && v.getBlockY() <= seaHeight;
|
||||
if (WildStackerAPI.getWildStacker().getSystemManager().isStackedBarrel(stackedBlock)) {
|
||||
StackedBarrel barrel = WildStackerAPI.getStackedBarrel(stackedBlock);
|
||||
int barrelAmt = WildStackerAPI.getBarrelAmount(stackedBlock);
|
||||
for (int _x = 0; _x < barrelAmt; _x++) {
|
||||
checkBlock(barrel.getType(), belowSeaLevel);
|
||||
}
|
||||
} else if (WildStackerAPI.getWildStacker().getSystemManager().isStackedSpawner(stackedBlock)) {
|
||||
int spawnerAmt = WildStackerAPI.getSpawnersAmount((CreatureSpawner) stackedBlock.getState());
|
||||
for (int _x = 0; _x < spawnerAmt; _x++) {
|
||||
checkBlock(stackedBlock.getType(), belowSeaLevel);
|
||||
}
|
||||
}
|
||||
});
|
||||
futures.add(future);
|
||||
}
|
||||
// Return a CompletableFuture that completes when all futures are done
|
||||
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
package world.bentobox.level.calculators;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.calculators.Results.Result;
|
||||
|
||||
/**
|
||||
* A pipeliner that will process one island at a time
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class Pipeliner {
|
||||
|
||||
private static final int START_DURATION = 10; // 10 seconds
|
||||
private final Queue<IslandLevelCalculator> toProcessQueue;
|
||||
private final Map<IslandLevelCalculator, Long> inProcessQueue;
|
||||
private final BukkitTask task;
|
||||
private final Level addon;
|
||||
private long time;
|
||||
private long count;
|
||||
|
||||
/**
|
||||
* Construct the pipeliner
|
||||
*/
|
||||
public Pipeliner(Level addon) {
|
||||
this.addon = addon;
|
||||
toProcessQueue = new ConcurrentLinkedQueue<>();
|
||||
inProcessQueue = new HashMap<>();
|
||||
// Loop continuously - check every tick if there is an island to scan
|
||||
task = Bukkit.getScheduler().runTaskTimer(BentoBox.getInstance(), () -> {
|
||||
if (!BentoBox.getInstance().isEnabled()) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
// Complete the current to Process queue first
|
||||
if (!inProcessQueue.isEmpty() || toProcessQueue.isEmpty()) return;
|
||||
for (int j = 0; j < addon.getSettings().getConcurrentIslandCalcs() && !toProcessQueue.isEmpty(); j++) {
|
||||
IslandLevelCalculator iD = toProcessQueue.poll();
|
||||
// Ignore deleted or unonwed islands
|
||||
if (!iD.getIsland().isDeleted() && !iD.getIsland().isUnowned()) {
|
||||
inProcessQueue.put(iD, System.currentTimeMillis());
|
||||
// Start the scanning of a island with the first chunk
|
||||
scanIsland(iD);
|
||||
}
|
||||
}
|
||||
}, 1L, 10L);
|
||||
}
|
||||
|
||||
private void cancel() {
|
||||
task.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of islands currently in the queue or in process
|
||||
*/
|
||||
public int getIslandsInQueue() {
|
||||
return inProcessQueue.size() + toProcessQueue.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans one chunk of an island and adds the results to a results object
|
||||
* @param iD
|
||||
*/
|
||||
private void scanIsland(IslandLevelCalculator iD) {
|
||||
if (iD.getIsland().isDeleted() || iD.getIsland().isUnowned() || task.isCancelled()) {
|
||||
// Island is deleted, so finish early with nothing
|
||||
inProcessQueue.remove(iD);
|
||||
iD.getR().complete(null);
|
||||
return;
|
||||
}
|
||||
iD.scanIsland(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds an island to the scanning queue but only if the island is not already in the queue
|
||||
* @param island - the island to scan
|
||||
* @return CompletableFuture of the results. Results will be null if the island is already in the queue
|
||||
*/
|
||||
public CompletableFuture<Results> addIsland(Island island) {
|
||||
// Check if queue already contains island and it's not an island zero calculation
|
||||
if (inProcessQueue.keySet().parallelStream().filter(IslandLevelCalculator::isNotZeroIsland)
|
||||
.map(IslandLevelCalculator::getIsland).anyMatch(island::equals)
|
||||
|| toProcessQueue.parallelStream().filter(IslandLevelCalculator::isNotZeroIsland)
|
||||
.map(IslandLevelCalculator::getIsland).anyMatch(island::equals)) {
|
||||
return CompletableFuture.completedFuture(new Results(Result.IN_PROGRESS));
|
||||
}
|
||||
return addToQueue(island, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an island to the scanning queue
|
||||
* @param island - the island to scan
|
||||
* @return CompletableFuture of the results
|
||||
*/
|
||||
public CompletableFuture<Results> zeroIsland(Island island) {
|
||||
return addToQueue(island, true);
|
||||
}
|
||||
|
||||
private CompletableFuture<Results> addToQueue(Island island, boolean zeroing) {
|
||||
CompletableFuture<Results> r = new CompletableFuture<>();
|
||||
toProcessQueue.add(new IslandLevelCalculator(addon, island, r, zeroing));
|
||||
count++;
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the average time it takes to run a level check
|
||||
* @return the average time in seconds
|
||||
*/
|
||||
public int getTime() {
|
||||
return time == 0 || count == 0 ? START_DURATION : (int)((double)time/count/1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit how long a level check took
|
||||
* @param time the time to set
|
||||
*/
|
||||
public void setTime(long time) {
|
||||
// Running average
|
||||
this.time += time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the current queue.
|
||||
*/
|
||||
public void stop() {
|
||||
addon.log("Stopping Level queue");
|
||||
task.cancel();
|
||||
this.inProcessQueue.clear();
|
||||
this.toProcessQueue.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the inProcessQueue
|
||||
*/
|
||||
protected Map<IslandLevelCalculator, Long> getInProcessQueue() {
|
||||
return inProcessQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the task
|
||||
*/
|
||||
protected BukkitTask getTask() {
|
||||
return task;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
package world.bentobox.level.calculators;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import world.bentobox.bentobox.api.events.addon.AddonEvent;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.calculators.CalcIslandLevel.Results;
|
||||
import world.bentobox.level.event.IslandLevelCalculatedEvent;
|
||||
import world.bentobox.level.event.IslandPreLevelEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Gets the player's island level. For admin or players
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class PlayerLevel {
|
||||
|
||||
private final Level addon;
|
||||
|
||||
private final Island island;
|
||||
private final World world;
|
||||
private final User asker;
|
||||
private final UUID targetPlayer;
|
||||
|
||||
private final long oldLevel;
|
||||
|
||||
private CalcIslandLevel calc;
|
||||
|
||||
|
||||
public PlayerLevel(final Level addon, final Island island, final UUID targetPlayer, final User asker) {
|
||||
this.addon = addon;
|
||||
this.island = island;
|
||||
this.world = island.getCenter().getWorld();
|
||||
this.asker = asker;
|
||||
this.targetPlayer = targetPlayer;
|
||||
this.oldLevel = addon.getIslandLevel(world, targetPlayer);
|
||||
|
||||
// Fire pre-level calc event
|
||||
IslandPreLevelEvent e = new IslandPreLevelEvent(targetPlayer, island);
|
||||
addon.getServer().getPluginManager().callEvent(e);
|
||||
if (!e.isCancelled()) {
|
||||
// Calculate if not cancelled
|
||||
calc = new CalcIslandLevel(addon, island, this::fireIslandLevelCalcEvent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void fireIslandLevelCalcEvent() {
|
||||
// Fire post calculation event
|
||||
IslandLevelCalculatedEvent ilce = new IslandLevelCalculatedEvent(targetPlayer, island, calc.getResult());
|
||||
addon.getServer().getPluginManager().callEvent(ilce);
|
||||
// This exposes these values to plugins via the event
|
||||
Map<String, Object> keyValues = new HashMap<>();
|
||||
keyValues.put("eventName", "IslandLevelCalculatedEvent");
|
||||
keyValues.put("targetPlayer", targetPlayer);
|
||||
keyValues.put("islandUUID", island.getUniqueId());
|
||||
keyValues.put("level", calc.getResult().getLevel());
|
||||
keyValues.put("pointsToNextLevel", calc.getResult().getPointsToNextLevel());
|
||||
keyValues.put("deathHandicap", calc.getResult().getDeathHandicap());
|
||||
keyValues.put("initialLevel", calc.getResult().getInitialLevel());
|
||||
addon.getServer().getPluginManager().callEvent(new AddonEvent().builder().addon(addon).keyValues(keyValues).build());
|
||||
Results results = ilce.getResults();
|
||||
// Save the results
|
||||
island.getMemberSet().forEach(m -> addon.setIslandLevel(world, m, results.getLevel()));
|
||||
// Display result if event is not cancelled
|
||||
if (!ilce.isCancelled()) {
|
||||
informPlayers(results);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void informPlayers(Results results) {
|
||||
// Tell the asker
|
||||
asker.sendMessage("island.level.island-level-is", "[level]", String.valueOf(addon.getIslandLevel(world, targetPlayer)));
|
||||
// Console
|
||||
if (!asker.isPlayer()) {
|
||||
results.getReport().forEach(asker::sendRawMessage);
|
||||
return;
|
||||
}
|
||||
// Player
|
||||
if (addon.getSettings().getDeathPenalty() != 0) {
|
||||
asker.sendMessage("island.level.deaths", "[number]", String.valueOf(results.getDeathHandicap()));
|
||||
}
|
||||
// Send player how many points are required to reach next island level
|
||||
if (results.getPointsToNextLevel() >= 0) {
|
||||
asker.sendMessage("island.level.required-points-to-next-level", "[points]", String.valueOf(results.getPointsToNextLevel()));
|
||||
}
|
||||
// Tell other team members
|
||||
if (addon.getIslandLevel(world, targetPlayer) != oldLevel) {
|
||||
island.getMemberSet().stream()
|
||||
.filter(u -> !u.equals(asker.getUniqueId()))
|
||||
.forEach(m -> User.getInstance(m).sendMessage("island.level.island-level-is", "[level]", String.valueOf(addon.getIslandLevel(world, targetPlayer))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package world.bentobox.level.calculators;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.bukkit.Material;
|
||||
|
||||
import com.google.common.collect.HashMultiset;
|
||||
import com.google.common.collect.Multiset;
|
||||
|
||||
public class Results {
|
||||
public enum Result {
|
||||
/**
|
||||
* A level calc is already in progress
|
||||
*/
|
||||
IN_PROGRESS,
|
||||
/**
|
||||
* Results will be available
|
||||
*/
|
||||
AVAILABLE,
|
||||
/**
|
||||
* Result if calculation timed out
|
||||
*/
|
||||
TIMEOUT
|
||||
}
|
||||
List<String> report;
|
||||
final Multiset<Material> mdCount = HashMultiset.create();
|
||||
final Multiset<Material> uwCount = HashMultiset.create();
|
||||
final Multiset<Material> ncCount = HashMultiset.create();
|
||||
final Multiset<Material> ofCount = HashMultiset.create();
|
||||
// AtomicLong and AtomicInteger must be used because they are changed by multiple concurrent threads
|
||||
AtomicLong rawBlockCount = new AtomicLong(0);
|
||||
AtomicLong underWaterBlockCount = new AtomicLong(0);
|
||||
AtomicLong level = new AtomicLong(0);
|
||||
AtomicInteger deathHandicap = new AtomicInteger(0);
|
||||
AtomicLong pointsToNextLevel = new AtomicLong(0);
|
||||
AtomicLong initialLevel = new AtomicLong(0);
|
||||
AtomicLong totalPoints = new AtomicLong(0);
|
||||
final Result state;
|
||||
|
||||
public Results(Result state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public Results() {
|
||||
this.state = Result.AVAILABLE;
|
||||
}
|
||||
/**
|
||||
* @return the deathHandicap
|
||||
*/
|
||||
public int getDeathHandicap() {
|
||||
return deathHandicap.get();
|
||||
}
|
||||
/**
|
||||
* Set the death handicap
|
||||
* @param handicap
|
||||
*/
|
||||
public void setDeathHandicap(int handicap) {
|
||||
deathHandicap.set(handicap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the report
|
||||
*/
|
||||
public List<String> getReport() {
|
||||
return report;
|
||||
}
|
||||
/**
|
||||
* Set level
|
||||
* @param level - level
|
||||
*/
|
||||
public void setLevel(long level) {
|
||||
this.level.set(level);
|
||||
}
|
||||
/**
|
||||
* @return the level
|
||||
*/
|
||||
public long getLevel() {
|
||||
return level.get();
|
||||
}
|
||||
/**
|
||||
* @return the pointsToNextLevel
|
||||
*/
|
||||
public long getPointsToNextLevel() {
|
||||
return pointsToNextLevel.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the points to next level
|
||||
* @param points
|
||||
*/
|
||||
public void setPointsToNextLevel(long points) {
|
||||
pointsToNextLevel.set(points);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the totalPoints
|
||||
*/
|
||||
public long getTotalPoints() {
|
||||
return totalPoints.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the total points
|
||||
* @param points
|
||||
*/
|
||||
public void setTotalPoints(long points) {
|
||||
totalPoints.set(points);
|
||||
}
|
||||
|
||||
public long getInitialLevel() {
|
||||
return initialLevel.get();
|
||||
}
|
||||
|
||||
public void setInitialLevel(long initialLevel) {
|
||||
this.initialLevel.set(initialLevel);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Results [report=" + report + ", mdCount=" + mdCount + ", uwCount=" + uwCount + ", ncCount="
|
||||
+ ncCount + ", ofCount=" + ofCount + ", rawBlockCount=" + rawBlockCount + ", underWaterBlockCount="
|
||||
+ underWaterBlockCount + ", level=" + level + ", deathHandicap=" + deathHandicap
|
||||
+ ", pointsToNextLevel=" + pointsToNextLevel + ", totalPoints=" + totalPoints + ", initialLevel=" + initialLevel + "]";
|
||||
}
|
||||
/**
|
||||
* @return the mdCount
|
||||
*/
|
||||
public Multiset<Material> getMdCount() {
|
||||
return mdCount;
|
||||
}
|
||||
/**
|
||||
* @return the uwCount
|
||||
*/
|
||||
public Multiset<Material> getUwCount() {
|
||||
return uwCount;
|
||||
}
|
||||
/**
|
||||
* @return the state
|
||||
*/
|
||||
public Result getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package world.bentobox.level.calculators;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
|
||||
import com.craftaro.ultimatestacker.api.UltimateStackerApi;
|
||||
import com.craftaro.ultimatestacker.api.utils.Stackable;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
|
||||
/**
|
||||
* Isolates UltimateStacker imports so that they are only loaded if the plugin exists
|
||||
*/
|
||||
public class UltimateStackerCalc {
|
||||
public static void addStackers(Material material, Location location, Results results, boolean belowSeaLevel,
|
||||
int value) {
|
||||
Stackable stack = UltimateStackerApi.getBlockStackManager().getBlock(location);
|
||||
if (stack != null) {
|
||||
if (belowSeaLevel) {
|
||||
results.underWaterBlockCount.addAndGet((long) stack.getAmount() * value);
|
||||
results.uwCount.add(material);
|
||||
} else {
|
||||
results.rawBlockCount.addAndGet((long) stack.getAmount() * value);
|
||||
results.mdCount.add(material);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +1,18 @@
|
|||
package world.bentobox.level.commands.admin;
|
||||
package world.bentobox.level.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
public class AdminLevelCommand extends CompositeCommand {
|
||||
public class AdminLevelCommand extends IslandLevelCommand {
|
||||
|
||||
private final Level levelPlugin;
|
||||
|
||||
public AdminLevelCommand(Level levelPlugin, CompositeCommand parent) {
|
||||
super(parent, "level");
|
||||
this.levelPlugin = levelPlugin;
|
||||
public AdminLevelCommand(Level addon, CompositeCommand parent) {
|
||||
super(addon, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -27,25 +23,6 @@ public class AdminLevelCommand extends CompositeCommand {
|
|||
this.setDescription("admin.level.description");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> args) {
|
||||
if (args.size() == 1) {
|
||||
// Asking for another player's level?
|
||||
// Convert name to a UUID
|
||||
final UUID playerUUID = getPlugin().getPlayers().getUUID(args.get(0));
|
||||
if (playerUUID == null) {
|
||||
user.sendMessage("general.errors.unknown-player");
|
||||
return true;
|
||||
} else {
|
||||
levelPlugin.calculateIslandLevel(getWorld(), user, playerUUID);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
showHelp(this, user);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
|
||||
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
|
@ -0,0 +1,31 @@
|
|||
package world.bentobox.level.commands;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
public class AdminLevelStatusCommand extends CompositeCommand {
|
||||
|
||||
private final Level addon;
|
||||
|
||||
public AdminLevelStatusCommand(Level addon, CompositeCommand parent) {
|
||||
super(parent, "levelstatus");
|
||||
this.addon = addon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
this.setPermission("admin.levelstatus");
|
||||
this.setOnlyPlayer(false);
|
||||
this.setDescription("admin.levelstatus.description");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> args) {
|
||||
user.sendMessage("admin.levelstatus.islands-in-queue", TextVariables.NUMBER, String.valueOf(addon.getPipeliner().getIslandsInQueue()));
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package world.bentobox.level.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
public class AdminSetInitialLevelCommand extends CompositeCommand {
|
||||
|
||||
private @Nullable UUID targetUUID;
|
||||
private @Nullable Island island;
|
||||
private Level addon;
|
||||
|
||||
public AdminSetInitialLevelCommand(Level addon, CompositeCommand parent) {
|
||||
super(parent, "sethandicap");
|
||||
this.addon = addon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
this.setPermission("admin.level.sethandicap");
|
||||
this.setOnlyPlayer(false);
|
||||
this.setParametersHelp("admin.level.sethandicap.parameters");
|
||||
this.setDescription("admin.level.sethandicap.description");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
|
||||
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
|
||||
if (args.isEmpty()) {
|
||||
// Don't show every player on the server. Require at least the first letter
|
||||
return Optional.empty();
|
||||
}
|
||||
List<String> options = new ArrayList<>(Util.getOnlinePlayerList(user));
|
||||
return Optional.of(Util.tabLimit(options, lastArg));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> args) {
|
||||
String initialLevel = String.valueOf(addon.getManager().getInitialLevel(island));
|
||||
long lv = Long.parseLong(args.get(1));
|
||||
addon.getManager().setInitialIslandLevel(island, lv);
|
||||
user.sendMessage("admin.level.sethandicap.changed", TextVariables.NUMBER, initialLevel, "[new_number]", String.valueOf(lv));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExecute(User user, String label, List<String> args) {
|
||||
if (args.size() != 2) {
|
||||
showHelp(this, user);
|
||||
return false;
|
||||
}
|
||||
targetUUID = getAddon().getPlayers().getUUID(args.get(0));
|
||||
if (targetUUID == null) {
|
||||
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
|
||||
return false;
|
||||
}
|
||||
// Check value
|
||||
if (!Util.isInteger(args.get(1), true)) {
|
||||
user.sendMessage("admin.level.sethandicap.invalid-level");
|
||||
return false;
|
||||
}
|
||||
// Check island
|
||||
island = getAddon().getIslands().getIsland(getWorld(), targetUUID);
|
||||
if (island == null) {
|
||||
user.sendMessage("general.errors.player-has-no-island");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package world.bentobox.level.commands;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.objects.TopTenData;
|
||||
|
||||
public class AdminStatsCommand extends CompositeCommand {
|
||||
|
||||
private final Level level;
|
||||
|
||||
public AdminStatsCommand(Level addon, CompositeCommand parent) {
|
||||
super(parent, "stats");
|
||||
this.level = addon;
|
||||
new AdminTopRemoveCommand(addon, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
this.setPermission("admin.stats");
|
||||
this.setOnlyPlayer(false);
|
||||
this.setDescription("admin.stats.description");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> args) {
|
||||
user.sendMessage("admin.stats.title");
|
||||
Map<World, TopTenData> topTenLists = level.getManager().getTopTenLists();
|
||||
if (topTenLists.isEmpty()) {
|
||||
user.sendMessage("admin.stats.no-data");
|
||||
return false;
|
||||
}
|
||||
for (Entry<World, TopTenData> en : topTenLists.entrySet()) {
|
||||
user.sendMessage("admin.stats.world", TextVariables.NAME,
|
||||
level.getPlugin().getIWM().getWorldName(en.getKey()));
|
||||
Map<String, Long> topTen = en.getValue().getTopTen();
|
||||
if (topTen.isEmpty()) {
|
||||
user.sendMessage("admin.stats.no-data");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculating basic statistics
|
||||
long sum = 0, max = Long.MIN_VALUE, min = Long.MAX_VALUE;
|
||||
Map<Long, Integer> levelFrequency = new HashMap<>();
|
||||
|
||||
for (Long level : topTen.values()) {
|
||||
sum += level;
|
||||
max = Math.max(max, level);
|
||||
min = Math.min(min, level);
|
||||
levelFrequency.merge(level, 1, Integer::sum);
|
||||
}
|
||||
|
||||
double average = sum / (double) topTen.size();
|
||||
List<Long> sortedLevels = topTen.values().stream().sorted().collect(Collectors.toList());
|
||||
long median = sortedLevels.get(sortedLevels.size() / 2);
|
||||
Long mode = Collections.max(levelFrequency.entrySet(), Map.Entry.comparingByValue()).getKey();
|
||||
|
||||
// Logging basic statistics
|
||||
user.sendMessage("admin.stats.average-level", TextVariables.NUMBER, String.valueOf(average));
|
||||
user.sendMessage("admin.stats.median-level", TextVariables.NUMBER, String.valueOf(median));
|
||||
user.sendMessage("admin.stats.mode-level", TextVariables.NUMBER, String.valueOf(mode));
|
||||
user.sendMessage("admin.stats.highest-level", TextVariables.NUMBER, String.valueOf(max));
|
||||
user.sendMessage("admin.stats.lowest-level", TextVariables.NUMBER, String.valueOf(min));
|
||||
|
||||
// Grouping data for distribution analysis
|
||||
Map<String, Integer> rangeMap = new TreeMap<>();
|
||||
for (Long level : topTen.values()) {
|
||||
String range = getRange(level);
|
||||
rangeMap.merge(range, 1, Integer::sum);
|
||||
}
|
||||
|
||||
// Logging distribution
|
||||
user.sendMessage("admin.stats.distribution");
|
||||
for (Map.Entry<String, Integer> entry : rangeMap.entrySet()) {
|
||||
user.sendMessage(
|
||||
entry.getKey() + ": " + entry.getValue() + " " + user.getTranslation("admin.stats.islands"));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String getRange(long level) {
|
||||
long rangeStart = level / 100 * 100;
|
||||
long rangeEnd = rangeStart + 99;
|
||||
return rangeStart + "-" + rangeEnd;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package world.bentobox.level.commands;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
public class AdminTopCommand extends CompositeCommand {
|
||||
|
||||
private final Level levelPlugin;
|
||||
|
||||
public AdminTopCommand(Level addon, CompositeCommand parent) {
|
||||
super(parent, "top", "topten");
|
||||
this.levelPlugin = addon;
|
||||
new AdminTopRemoveCommand(addon, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
this.setPermission("admin.top");
|
||||
this.setOnlyPlayer(false);
|
||||
this.setDescription("admin.top.description");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> args) {
|
||||
user.sendMessage("island.top.gui-title");
|
||||
int rank = 0;
|
||||
for (Map.Entry<String, Long> topTen : levelPlugin.getManager().getTopTen(getWorld(), Level.TEN).entrySet()) {
|
||||
Optional<Island> is = getPlugin().getIslands().getIslandById(topTen.getKey());
|
||||
if (is.isPresent()) {
|
||||
Island island = is.get();
|
||||
rank++;
|
||||
user.sendMessage("admin.top.display", "[rank]", String.valueOf(rank), "[name]",
|
||||
this.getPlugin().getPlayers().getUser(island.getOwner()).getName(), "[level]",
|
||||
String.valueOf(topTen.getValue()));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package world.bentobox.level.commands;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
/**
|
||||
* Removes a player from the top ten
|
||||
*
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class AdminTopRemoveCommand extends CompositeCommand {
|
||||
|
||||
private final Level addon;
|
||||
private User target;
|
||||
|
||||
public AdminTopRemoveCommand(Level addon, CompositeCommand parent) {
|
||||
super(parent, "remove", "delete");
|
||||
this.addon = addon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
this.setPermission("admin.top.remove");
|
||||
this.setOnlyPlayer(false);
|
||||
this.setParametersHelp("admin.top.remove.parameters");
|
||||
this.setDescription("admin.top.remove.description");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see world.bentobox.bentobox.api.commands.BentoBoxCommand#canExecute(world.
|
||||
* bentobox.bentobox.api.user.User, java.lang.String, java.util.List)
|
||||
*/
|
||||
@Override
|
||||
public boolean canExecute(User user, String label, List<String> args) {
|
||||
if (args.size() != 1) {
|
||||
this.showHelp(this, user);
|
||||
return false;
|
||||
}
|
||||
target = getPlayers().getUser(args.get(0));
|
||||
if (target == null) {
|
||||
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> args) {
|
||||
// Removes islands that this target is an owner of
|
||||
getIslands().getIslands(getWorld(), target.getUniqueId()).stream()
|
||||
.filter(is -> target.getUniqueId().equals(is.getOwner()))
|
||||
.forEach(island -> addon.getManager().removeEntry(getWorld(), island.getUniqueId()));
|
||||
user.sendMessage("general.success");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
|
||||
return Optional.of(addon.getManager().getTopTen(getWorld(), Level.TEN).keySet().stream()
|
||||
.map(getIslands()::getIslandById).flatMap(Optional::stream).map(Island::getOwner)
|
||||
.map(addon.getPlayers()::getName).filter(n -> !n.isEmpty()).toList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
package world.bentobox.level.commands;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.calculators.Results;
|
||||
import world.bentobox.level.calculators.Results.Result;
|
||||
|
||||
public class IslandLevelCommand extends CompositeCommand {
|
||||
|
||||
private static final String ISLAND_LEVEL_IS = "island.level.island-level-is";
|
||||
private static final String LEVEL = "[level]";
|
||||
private final Level addon;
|
||||
|
||||
public IslandLevelCommand(Level addon, CompositeCommand parent) {
|
||||
super(parent, "level");
|
||||
this.addon = addon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
this.setPermission("island.level");
|
||||
this.setParametersHelp("island.level.parameters");
|
||||
this.setDescription("island.level.description");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> args) {
|
||||
if (!args.isEmpty()) {
|
||||
// Asking for another player's level?
|
||||
// Convert name to a UUID
|
||||
final UUID playerUUID = getPlugin().getPlayers().getUUID(args.get(0));
|
||||
if (playerUUID == null) {
|
||||
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
|
||||
return false;
|
||||
}
|
||||
// Ops, console and admin perms can request and calculate other player levels
|
||||
if (!user.isPlayer() || user.isOp() || user.hasPermission(this.getPermissionPrefix() + "admin.level")) {
|
||||
return scanIsland(user, playerUUID);
|
||||
}
|
||||
// Request for another player's island level
|
||||
if (!user.getUniqueId().equals(playerUUID) ) {
|
||||
user.sendMessage(ISLAND_LEVEL_IS, LEVEL, addon.getManager().getIslandLevelString(getWorld(), playerUUID));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!user.isPlayer()) {
|
||||
user.sendMessage("general.errors.use-in-game");
|
||||
return false;
|
||||
}
|
||||
// Self request
|
||||
// Check player cooldown
|
||||
int coolDown = this.addon.getSettings().getLevelWait();
|
||||
|
||||
if (coolDown > 0) {
|
||||
// Check cool down
|
||||
if (checkCooldown(user)) return false;
|
||||
// Set cool down
|
||||
setCooldown(user.getUniqueId(), coolDown);
|
||||
}
|
||||
|
||||
// Self level request
|
||||
return scanIsland(user, user.getUniqueId());
|
||||
|
||||
}
|
||||
|
||||
|
||||
private boolean scanIsland(User user, UUID playerUUID) {
|
||||
Island island = getIslands().getIsland(getWorld(), playerUUID);
|
||||
if (island == null) {
|
||||
user.sendMessage("general.errors.player-has-no-island");
|
||||
return false;
|
||||
|
||||
}
|
||||
int inQueue = addon.getPipeliner().getIslandsInQueue();
|
||||
user.sendMessage("island.level.calculating");
|
||||
user.sendMessage("island.level.estimated-wait", TextVariables.NUMBER, String.valueOf(addon.getPipeliner().getTime() * (inQueue + 1)));
|
||||
if (inQueue > 1) {
|
||||
user.sendMessage("island.level.in-queue", TextVariables.NUMBER, String.valueOf(inQueue + 1));
|
||||
}
|
||||
// Get the old level
|
||||
long oldLevel = addon.getManager().getIslandLevel(getWorld(), playerUUID);
|
||||
addon.getManager().calculateLevel(playerUUID, island).thenAccept(results -> {
|
||||
if (results == null) return; // island was deleted or become unowned
|
||||
if (results.getState().equals(Result.IN_PROGRESS)) {
|
||||
user.sendMessage("island.level.in-progress");
|
||||
return;
|
||||
} else if (results.getState().equals(Result.TIMEOUT)) {
|
||||
user.sendMessage("island.level.time-out");
|
||||
return;
|
||||
}
|
||||
showResult(user, playerUUID, island, oldLevel, results);
|
||||
});
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private void showResult(User user, UUID playerUUID, Island island, long oldLevel, Results results) {
|
||||
if (user.isPlayer()) {
|
||||
user.sendMessage(ISLAND_LEVEL_IS, LEVEL, addon.getManager().getIslandLevelString(getWorld(), playerUUID));
|
||||
// Player
|
||||
if (addon.getSettings().getDeathPenalty() != 0) {
|
||||
user.sendMessage("island.level.deaths", "[number]", String.valueOf(results.getDeathHandicap()));
|
||||
}
|
||||
// Send player how many points are required to reach next island level
|
||||
if (results.getPointsToNextLevel() >= 0) {
|
||||
user.sendMessage("island.level.required-points-to-next-level",
|
||||
"[points]", String.valueOf(results.getPointsToNextLevel()),
|
||||
"[progress]", String.valueOf(this.addon.getSettings().getLevelCost()-results.getPointsToNextLevel()),
|
||||
"[levelcost]", String.valueOf(this.addon.getSettings().getLevelCost())
|
||||
);
|
||||
}
|
||||
// Tell other team members
|
||||
if (results.getLevel() != oldLevel) {
|
||||
island.getMemberSet().stream()
|
||||
.filter(u -> !u.equals(user.getUniqueId()))
|
||||
.forEach(m -> User.getInstance(m).sendMessage(ISLAND_LEVEL_IS, LEVEL, addon.getManager().getIslandLevelString(getWorld(), playerUUID)));
|
||||
}
|
||||
} else if (this.addon.getSettings().isLogReportToConsole()) {
|
||||
results.getReport().forEach(BentoBox.getInstance()::log);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,18 +1,20 @@
|
|||
package world.bentobox.level.commands.island;
|
||||
package world.bentobox.level.commands;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.panels.TopLevelPanel;
|
||||
|
||||
|
||||
public class IslandTopCommand extends CompositeCommand {
|
||||
|
||||
private final Level plugin;
|
||||
private final Level addon;
|
||||
|
||||
public IslandTopCommand(Level plugin, CompositeCommand parent) {
|
||||
public IslandTopCommand(Level addon, CompositeCommand parent) {
|
||||
super(parent, "top", "topten");
|
||||
this.plugin = plugin;
|
||||
this.addon = addon;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -24,7 +26,7 @@ public class IslandTopCommand extends CompositeCommand {
|
|||
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> list) {
|
||||
plugin.getTopTen().getGUI(getWorld(), user, getPermissionPrefix());
|
||||
TopLevelPanel.openPanel(this.addon, user, this.getWorld(), this.getPermissionPrefix());
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package world.bentobox.level.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.panels.ValuePanel;
|
||||
import world.bentobox.level.util.Utils;
|
||||
|
||||
|
||||
public class IslandValueCommand extends CompositeCommand
|
||||
{
|
||||
private static final String MATERIAL = "[material]";
|
||||
private final Level addon;
|
||||
|
||||
|
||||
public IslandValueCommand(Level addon, CompositeCommand parent)
|
||||
{
|
||||
super(parent, "value");
|
||||
this.addon = addon;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setup()
|
||||
{
|
||||
this.setPermission("island.value");
|
||||
this.setParametersHelp("level.commands.value.parameters");
|
||||
this.setDescription("level.commands.value.description");
|
||||
this.setOnlyPlayer(true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> args)
|
||||
{
|
||||
if (args.size() > 1)
|
||||
{
|
||||
this.showHelp(this, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.isEmpty())
|
||||
{
|
||||
ValuePanel.openPanel(this.addon, this.getWorld(), user);
|
||||
}
|
||||
else if (args.get(0).equalsIgnoreCase("HAND"))
|
||||
{
|
||||
Player player = user.getPlayer();
|
||||
PlayerInventory inventory = player.getInventory();
|
||||
|
||||
if (!inventory.getItemInMainHand().getType().equals(Material.AIR))
|
||||
{
|
||||
this.printValue(user, inventory.getItemInMainHand().getType());
|
||||
}
|
||||
else
|
||||
{
|
||||
Utils.sendMessage(user, user.getTranslation("level.conversations.empty-hand"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Material material = Material.matchMaterial(args.get(0));
|
||||
|
||||
if (material == null)
|
||||
{
|
||||
Utils.sendMessage(user,
|
||||
user.getTranslation(this.getWorld(), "level.conversations.unknown-item",
|
||||
MATERIAL, args.get(0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.printValue(user, material);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method prints value of the given material in chat.
|
||||
* @param user User who receives the message.
|
||||
* @param material Material value.
|
||||
*/
|
||||
private void printValue(User user, Material material)
|
||||
{
|
||||
Integer value = this.addon.getBlockConfig().getValue(getWorld(), material);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
Utils.sendMessage(user,
|
||||
user.getTranslation(this.getWorld(), "level.conversations.value",
|
||||
"[value]", String.valueOf(value),
|
||||
MATERIAL, Utils.prettifyObject(material, user)));
|
||||
|
||||
double underWater = this.addon.getSettings().getUnderWaterMultiplier();
|
||||
|
||||
if (underWater > 1.0)
|
||||
{
|
||||
Utils.sendMessage(user,
|
||||
user.getTranslation(this.getWorld(),"level.conversations.success-underwater",
|
||||
"[value]", (underWater * value) + ""),
|
||||
MATERIAL, Utils.prettifyObject(material, user));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Utils.sendMessage(user,
|
||||
user.getTranslation(this.getWorld(),"level.conversations.no-value"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Optional<List<String>> tabComplete(User user, String alias, List<String> args)
|
||||
{
|
||||
String lastArg = !args.isEmpty() ? args.get(args.size() - 1) : "";
|
||||
|
||||
if (args.isEmpty())
|
||||
{
|
||||
// Don't show every player on the server. Require at least the first letter
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
List<String> options = new ArrayList<>(Arrays.stream(Material.values()).
|
||||
filter(Material::isBlock).
|
||||
map(Material::name).toList());
|
||||
|
||||
options.add("HAND");
|
||||
|
||||
return Optional.of(Util.tabLimit(options, lastArg));
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package world.bentobox.level.commands.admin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
public class AdminTopCommand extends CompositeCommand {
|
||||
|
||||
private final Level levelPlugin;
|
||||
|
||||
public AdminTopCommand(Level levelPlugin, CompositeCommand parent) {
|
||||
super(parent, "top", "topten");
|
||||
this.levelPlugin = levelPlugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
this.setPermission("admin.top");
|
||||
this.setOnlyPlayer(false);
|
||||
this.setDescription("admin.top.description");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> args) {
|
||||
int rank = 0;
|
||||
for (Map.Entry<UUID, Long> topTen : levelPlugin.getTopTen().getTopTenList(getWorld()).getTopTen().entrySet()) {
|
||||
Island island = getPlugin().getIslands().getIsland(getWorld(), topTen.getKey());
|
||||
if (island != null) {
|
||||
rank++;
|
||||
user.sendMessage("admin.top.display",
|
||||
"[rank]",
|
||||
String.valueOf(rank),
|
||||
"[name]",
|
||||
this.getPlugin().getPlayers().getUser(island.getOwner()).getName(),
|
||||
"[level]",
|
||||
String.valueOf(topTen.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
package world.bentobox.level.commands.island;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
public class IslandLevelCommand extends CompositeCommand {
|
||||
|
||||
private final Level levelPlugin;
|
||||
|
||||
public IslandLevelCommand(Level levelPlugin, CompositeCommand parent) {
|
||||
super(parent, "level");
|
||||
this.levelPlugin = levelPlugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
this.setPermission("island.level");
|
||||
this.setParametersHelp("island.level.parameters");
|
||||
this.setDescription("island.level.description");
|
||||
this.setOnlyPlayer(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> args) {
|
||||
if (!args.isEmpty()) {
|
||||
// Asking for another player's level?
|
||||
// Convert name to a UUID
|
||||
final UUID playerUUID = getPlugin().getPlayers().getUUID(args.get(0));
|
||||
if (playerUUID == null) {
|
||||
user.sendMessage("general.errors.unknown-player");
|
||||
return true;
|
||||
} else if (user.getUniqueId().equals(playerUUID) ) {
|
||||
return this.calculateLevel(user);
|
||||
} else {
|
||||
user.sendMessage("island.level.island-level-is", "[level]", String.valueOf(levelPlugin.getIslandLevel(getWorld(), playerUUID)));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return this.calculateLevel(user);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method calls island level calculation if it is allowed by cooldown.
|
||||
* @param user User which island level must be calculated.
|
||||
* @return True if le
|
||||
*/
|
||||
private boolean calculateLevel(User user)
|
||||
{
|
||||
int coolDown = this.levelPlugin.getSettings().getLevelWait();
|
||||
|
||||
if (coolDown > 0 && this.checkCooldown(user, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Self level request
|
||||
this.levelPlugin.calculateIslandLevel(getWorld(), user, user.getUniqueId());
|
||||
|
||||
if (coolDown > 0)
|
||||
{
|
||||
this.setCooldown(user.getUniqueId(), null, coolDown);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package world.bentobox.level.commands.island;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class IslandValueCommand extends CompositeCommand {
|
||||
private final Level plugin;
|
||||
|
||||
public IslandValueCommand(Level plugin, CompositeCommand parent) {
|
||||
super(parent, "value");
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
this.setPermission("island.value");
|
||||
this.setDescription("island.value.description");
|
||||
this.setOnlyPlayer(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> args) {
|
||||
Player player = user.getPlayer();
|
||||
PlayerInventory inventory = player.getInventory();
|
||||
if (!inventory.getItemInMainHand().getType().equals(Material.AIR)) {
|
||||
Material material = inventory.getItemInMainHand().getType();
|
||||
if (plugin.getConfig().get("blocks." + material.toString()) != null) {
|
||||
int value = plugin.getConfig().getInt("blocks." + material.toString());
|
||||
user.sendMessage("island.value.success", "[value]", value + "");
|
||||
if (plugin.getConfig().get("underwater") != null) {
|
||||
Double underWater = plugin.getConfig().getDouble("underwater");
|
||||
if (underWater > 1.0) {
|
||||
user.sendMessage("island.value.success-underwater", "[value]", (underWater * value) + "");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
user.sendMessage("island.value.no-value");
|
||||
}
|
||||
} else {
|
||||
user.sendMessage("island.value.empty-hand");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
package world.bentobox.level.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
/**
|
||||
* Contains all the block values, limits and world differences
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class BlockConfig {
|
||||
|
||||
private Map<Material, Integer> blockLimits = new EnumMap<>(Material.class);
|
||||
private Map<Material, Integer> blockValues = new EnumMap<>(Material.class);
|
||||
private final Map<World, Map<Material, Integer>> worldBlockValues = new HashMap<>();
|
||||
private Level addon;
|
||||
|
||||
/**
|
||||
* Loads block limits, values and world settings and then saves them again
|
||||
* @param addon - addon
|
||||
* @param blockValues - yaml configuration file containing the block values
|
||||
* @param file - the file representing the yaml config. Will be saved after readong.
|
||||
* @throws IOException - if there is an error
|
||||
*/
|
||||
public BlockConfig(Level addon, YamlConfiguration blockValues, File file) throws IOException {
|
||||
this.addon = addon;
|
||||
if (blockValues.isConfigurationSection("limits")) {
|
||||
setBlockLimits(loadBlockLimits(blockValues));
|
||||
}
|
||||
if (blockValues.isConfigurationSection("blocks")) {
|
||||
setBlockValues(loadBlockValues(blockValues));
|
||||
} else {
|
||||
addon.logWarning("No block values in blockconfig.yml! All island levels will be zero!");
|
||||
}
|
||||
// Worlds
|
||||
if (blockValues.isConfigurationSection("worlds")) {
|
||||
loadWorlds(blockValues);
|
||||
}
|
||||
// All done
|
||||
blockValues.save(file);
|
||||
}
|
||||
|
||||
private void loadWorlds(YamlConfiguration blockValues2) {
|
||||
ConfigurationSection worlds = Objects.requireNonNull(blockValues2.getConfigurationSection("worlds"));
|
||||
for (String world : Objects.requireNonNull(worlds).getKeys(false)) {
|
||||
World bWorld = Bukkit.getWorld(world);
|
||||
if (bWorld != null) {
|
||||
ConfigurationSection worldValues = worlds.getConfigurationSection(world);
|
||||
for (String material : Objects.requireNonNull(worldValues).getKeys(false)) {
|
||||
try {
|
||||
Material mat = Material.valueOf(material);
|
||||
Map<Material, Integer> values = worldBlockValues.getOrDefault(bWorld,
|
||||
new EnumMap<>(Material.class));
|
||||
values.put(mat, worldValues.getInt(material));
|
||||
worldBlockValues.put(bWorld, values);
|
||||
} catch (Exception e) {
|
||||
addon.logError(
|
||||
"Unknown material (" + material + ") in blockconfig.yml worlds section. Skipping...");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addon.logWarning("Level Addon: No such world in blockconfig.yml : " + world);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Map<Material, Integer> loadBlockValues(YamlConfiguration blockValues2) {
|
||||
ConfigurationSection blocks = Objects.requireNonNull(blockValues2.getConfigurationSection("blocks"));
|
||||
Map<Material, Integer> bv = new EnumMap<>(Material.class);
|
||||
// Update blockvalues to latest settings
|
||||
Arrays.stream(Material.values()).filter(Material::isBlock)
|
||||
.filter(m -> !m.name().startsWith("LEGACY_"))
|
||||
.filter(m -> !m.isAir())
|
||||
.filter(m -> !m.equals(Material.WATER))
|
||||
.forEach(m -> {
|
||||
if (!blocks.contains(m.name(), true)) {
|
||||
blocks.set(m.name(), 1);
|
||||
}
|
||||
bv.put(m, blocks.getInt(m.name(), 1));
|
||||
});
|
||||
return bv;
|
||||
}
|
||||
|
||||
private Map<Material, Integer> loadBlockLimits(YamlConfiguration blockValues2) {
|
||||
Map<Material, Integer> bl = new EnumMap<>(Material.class);
|
||||
ConfigurationSection limits = Objects.requireNonNull(blockValues2.getConfigurationSection("limits"));
|
||||
for (String material : limits.getKeys(false)) {
|
||||
try {
|
||||
Material mat = Material.valueOf(material);
|
||||
bl.put(mat, limits.getInt(material, 0));
|
||||
} catch (Exception e) {
|
||||
addon.logError("Unknown material (" + material + ") in blockconfig.yml Limits section. Skipping...");
|
||||
}
|
||||
}
|
||||
return bl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the blockLimits
|
||||
*/
|
||||
public final Map<Material, Integer> getBlockLimits() {
|
||||
return blockLimits;
|
||||
}
|
||||
/**
|
||||
* @param bl the blockLimits to set
|
||||
*/
|
||||
private void setBlockLimits(Map<Material, Integer> bl) {
|
||||
this.blockLimits = bl;
|
||||
}
|
||||
/**
|
||||
* @return the blockValues
|
||||
*/
|
||||
public final Map<Material, Integer> getBlockValues() {
|
||||
return blockValues;
|
||||
}
|
||||
/**
|
||||
* @param blockValues2 the blockValues to set
|
||||
*/
|
||||
private void setBlockValues(Map<Material, Integer> blockValues2) {
|
||||
this.blockValues = blockValues2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the worldBlockValues
|
||||
*/
|
||||
public Map<World, Map<Material, Integer>> getWorldBlockValues() {
|
||||
return worldBlockValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of material in world
|
||||
* @param world - world
|
||||
* @param md - material
|
||||
* @return value or null if not configured with a value
|
||||
*/
|
||||
public Integer getValue(World world, Material md) {
|
||||
// Check world settings
|
||||
if (getWorldBlockValues().containsKey(world) && getWorldBlockValues().get(world).containsKey(md)) {
|
||||
return getWorldBlockValues().get(world).get(md);
|
||||
}
|
||||
// Check baseline
|
||||
if (getBlockValues().containsKey(md)) {
|
||||
return getBlockValues().get(md);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,422 @@
|
|||
package world.bentobox.level.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.configuration.ConfigComment;
|
||||
import world.bentobox.bentobox.api.configuration.ConfigEntry;
|
||||
import world.bentobox.bentobox.api.configuration.ConfigObject;
|
||||
import world.bentobox.bentobox.api.configuration.StoreAt;
|
||||
|
||||
@StoreAt(filename="config.yml", path="addons/Level")
|
||||
@ConfigComment("Level Configuration [version]")
|
||||
@ConfigComment("")
|
||||
public class ConfigSettings implements ConfigObject {
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Disabled Game Mode Addons")
|
||||
@ConfigComment("Level will NOT hook into these game mode addons.")
|
||||
@ConfigEntry(path = "disabled-game-modes")
|
||||
private List<String> gameModes = Collections.emptyList();
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("When executing level command from console, should a report be shown?")
|
||||
@ConfigEntry(path = "log-report-to-console")
|
||||
private boolean logReportToConsole = true;
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Number of concurrent island calculations")
|
||||
@ConfigComment("If your CPU can handle it, you can run parallel island calcs if there are more than one in the queue")
|
||||
@ConfigEntry(path = "concurrent-island-calcs")
|
||||
private int concurrentIslandCalcs = 1;
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Island level calculation timeout in minutes.")
|
||||
@ConfigComment("If an island takes longer that this time to calculate, then the calculation will abort.")
|
||||
@ConfigComment("Generally, calculation should only take a few seconds, so if this ever triggers then something is not right.")
|
||||
@ConfigEntry(path = "calculation-timeout")
|
||||
private int calculationTimeout = 5;
|
||||
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Zero island levels on new island or island reset")
|
||||
@ConfigComment("If true, Level will calculate the starter island's level and remove it from any future level calculations.")
|
||||
@ConfigComment("If false, the player's starter island blocks will count towards their level.")
|
||||
@ConfigComment("This will reduce CPU if false.")
|
||||
@ConfigEntry(path = "zero-new-island-levels")
|
||||
private boolean zeroNewIslandLevels = true;
|
||||
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Calculate island level on login")
|
||||
@ConfigComment("This silently calculates the player's island level when they login")
|
||||
@ConfigComment("This applies to all islands the player has on the server, e.g., BSkyBlock, AcidIsland")
|
||||
@ConfigEntry(path = "login")
|
||||
private boolean calcOnLogin = false;
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Include nether island in level calculations.")
|
||||
@ConfigComment("Warning: Enabling this mid-game will give players with an island a jump in")
|
||||
@ConfigComment("island level. New islands will be correctly zeroed.")
|
||||
@ConfigEntry(path = "nether")
|
||||
private boolean nether = false;
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Include end island in level calculations.")
|
||||
@ConfigComment("Warning: Enabling this mid-game will give players with an island a jump in")
|
||||
@ConfigComment("island level. New islands will be correctly zeroed.")
|
||||
@ConfigEntry(path = "end")
|
||||
private boolean end = false;
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Include chest contents in level calculations.")
|
||||
@ConfigComment("Will count blocks in chests or containers.")
|
||||
@ConfigEntry(path = "include-chests")
|
||||
private boolean includeChests = false;
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Underwater block multiplier")
|
||||
@ConfigComment("If blocks are below sea-level, they can have a higher value. e.g. 2x")
|
||||
@ConfigComment("Promotes under-water development if there is a sea. Value can be fractional.")
|
||||
@ConfigEntry(path = "underwater")
|
||||
private double underWaterMultiplier = 1.0;
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Value of one island level. Default 100. Minimum value is 1.")
|
||||
@ConfigEntry(path = "levelcost")
|
||||
private long levelCost = 100;
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Island level calculation formula")
|
||||
@ConfigComment("blocks - the sum total of all block values, less any death penalty")
|
||||
@ConfigComment("level_cost - in a linear equation, the value of one level")
|
||||
@ConfigComment("This formula can include +,=,*,/,sqrt,^,sin,cos,tan,log (natural log). Result will always be rounded to a long integer")
|
||||
@ConfigComment("for example, an alternative non-linear option could be: 3 * sqrt(blocks / level_cost)")
|
||||
@ConfigEntry(path = "level-calc")
|
||||
private String levelCalc = "blocks / level_cost";
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Cooldown between level requests in seconds")
|
||||
@ConfigEntry(path = "levelwait")
|
||||
private int levelWait = 60;
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Death penalty")
|
||||
@ConfigComment("How many block values a player will lose per death.")
|
||||
@ConfigComment("Default value of 100 means that for every death, the player will lose 1 level (if levelcost is 100)")
|
||||
@ConfigComment("Set to zero to not use this feature")
|
||||
@ConfigEntry(path = "deathpenalty")
|
||||
private int deathPenalty = 100;
|
||||
|
||||
@ConfigComment("Sum team deaths - if true, all the teams deaths are summed")
|
||||
@ConfigComment("If false, only the leader's deaths counts")
|
||||
@ConfigComment("For other death related settings, see the GameModeAddon's config.yml settings.")
|
||||
@ConfigEntry(path = "sumteamdeaths")
|
||||
private boolean sumTeamDeaths = false;
|
||||
|
||||
|
||||
@ConfigComment("Shorthand island level")
|
||||
@ConfigComment("Shows large level values rounded down, e.g., 10,345 -> 10k")
|
||||
@ConfigEntry(path = "shorthand")
|
||||
private boolean shorthand = false;
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Include Shulker Box content in chests in level calculations.")
|
||||
@ConfigComment("Will count blocks in Shulker Boxes inside of chests.")
|
||||
@ConfigComment("NOTE: include-chests needs to be enabled for this to work!.")
|
||||
@ConfigEntry(path = "include-shulkers-in-chest")
|
||||
private boolean includeShulkersInChest = false;
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Disables hooking with other plugins.")
|
||||
@ConfigComment("Example: disabled-plugin-hooks: [UltimateStacker, RoseStacker]")
|
||||
@ConfigEntry(path = "disabled-plugin-hooks")
|
||||
private List<String> disabledPluginHooks = new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* @return the gameModes
|
||||
*/
|
||||
public List<String> getGameModes() {
|
||||
return gameModes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param gameModes the gameModes to set
|
||||
*/
|
||||
public void setGameModes(List<String> gameModes) {
|
||||
this.gameModes = gameModes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the calcOnLogin
|
||||
*/
|
||||
public boolean isCalcOnLogin() {
|
||||
return calcOnLogin;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param calcOnLogin the calcOnLogin to set
|
||||
*/
|
||||
public void setCalcOnLogin(boolean calcOnLogin) {
|
||||
this.calcOnLogin = calcOnLogin;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the nether
|
||||
*/
|
||||
public boolean isNether() {
|
||||
return nether;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param nether the nether to set
|
||||
*/
|
||||
public void setNether(boolean nether) {
|
||||
this.nether = nether;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the end
|
||||
*/
|
||||
public boolean isEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param end the end to set
|
||||
*/
|
||||
public void setEnd(boolean end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the underWaterMultiplier
|
||||
*/
|
||||
public double getUnderWaterMultiplier() {
|
||||
return underWaterMultiplier;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param underWaterMultiplier the underWaterMultiplier to set
|
||||
*/
|
||||
public void setUnderWaterMultiplier(double underWaterMultiplier) {
|
||||
this.underWaterMultiplier = underWaterMultiplier;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the levelCost
|
||||
*/
|
||||
public long getLevelCost() {
|
||||
if (levelCost < 1) {
|
||||
levelCost = 1;
|
||||
BentoBox.getInstance().logError("levelcost in config.yml cannot be less than 1. Setting to 1.");
|
||||
}
|
||||
return levelCost;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param levelCost the levelCost to set
|
||||
*/
|
||||
public void setLevelCost(long levelCost) {
|
||||
this.levelCost = levelCost;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the levelCalc
|
||||
*/
|
||||
public String getLevelCalc() {
|
||||
return levelCalc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param levelCalc the levelCalc to set
|
||||
*/
|
||||
public void setLevelCalc(String levelCalc) {
|
||||
this.levelCalc = levelCalc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the levelWait
|
||||
*/
|
||||
public int getLevelWait() {
|
||||
if (levelWait < 0) {
|
||||
BentoBox.getInstance().logError("levelwait must be at least 0");
|
||||
levelWait = 0;
|
||||
}
|
||||
return levelWait;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param levelWait the levelWait to set
|
||||
*/
|
||||
public void setLevelWait(int levelWait) {
|
||||
this.levelWait = levelWait;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the deathPenalty
|
||||
*/
|
||||
public int getDeathPenalty() {
|
||||
return deathPenalty;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param deathPenalty the deathPenalty to set
|
||||
*/
|
||||
public void setDeathPenalty(int deathPenalty) {
|
||||
this.deathPenalty = deathPenalty;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the sumTeamDeaths
|
||||
*/
|
||||
public boolean isSumTeamDeaths() {
|
||||
return sumTeamDeaths;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param sumTeamDeaths the sumTeamDeaths to set
|
||||
*/
|
||||
public void setSumTeamDeaths(boolean sumTeamDeaths) {
|
||||
this.sumTeamDeaths = sumTeamDeaths;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the shorthand
|
||||
*/
|
||||
public boolean isShorthand() {
|
||||
return shorthand;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param shorthand the shorthand to set
|
||||
*/
|
||||
public void setShorthand(boolean shorthand) {
|
||||
this.shorthand = shorthand;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the includeChests
|
||||
*/
|
||||
public boolean isIncludeChests() {
|
||||
return includeChests;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param includeChests the includeChests to set
|
||||
*/
|
||||
public void setIncludeChests(boolean includeChests) {
|
||||
this.includeChests = includeChests;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the concurrentIslandCalcs
|
||||
*/
|
||||
public int getConcurrentIslandCalcs() {
|
||||
if (concurrentIslandCalcs < 1) concurrentIslandCalcs = 1;
|
||||
return concurrentIslandCalcs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param concurrentIslandCalcs the concurrentIslandCalcs to set
|
||||
*/
|
||||
public void setConcurrentIslandCalcs(int concurrentIslandCalcs) {
|
||||
if (concurrentIslandCalcs < 1) concurrentIslandCalcs = 1;
|
||||
this.concurrentIslandCalcs = concurrentIslandCalcs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the zeroNewIslandLevels
|
||||
*/
|
||||
public boolean isZeroNewIslandLevels() {
|
||||
return zeroNewIslandLevels;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param zeroNewIslandLevels the zeroNewIslandLevels to set
|
||||
*/
|
||||
public void setZeroNewIslandLevels(boolean zeroNewIslandLevels) {
|
||||
this.zeroNewIslandLevels = zeroNewIslandLevels;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the calculationTimeout
|
||||
*/
|
||||
public int getCalculationTimeout() {
|
||||
return calculationTimeout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param calculationTimeout the calculationTimeout to set
|
||||
*/
|
||||
public void setCalculationTimeout(int calculationTimeout) {
|
||||
this.calculationTimeout = calculationTimeout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return logReportToConsole
|
||||
*/
|
||||
public boolean isLogReportToConsole() {
|
||||
return logReportToConsole;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param logReportToConsole if logReportToConsole should be shown on console
|
||||
*/
|
||||
public void setLogReportToConsole(boolean logReportToConsole) {
|
||||
this.logReportToConsole = logReportToConsole;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return includeShulkersInChest
|
||||
*/
|
||||
public boolean isIncludeShulkersInChest() {
|
||||
return includeShulkersInChest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param includeShulkersInChest the includeChests to set
|
||||
*/
|
||||
public void setIncludeShulkersInChest(boolean includeShulkersInChest) {
|
||||
this.includeShulkersInChest = includeShulkersInChest;
|
||||
}
|
||||
|
||||
public List<String> getDisabledPluginHooks() {
|
||||
return disabledPluginHooks;
|
||||
}
|
||||
|
||||
public void setDisabledPluginHooks(List<String> disabledPluginHooks) {
|
||||
this.disabledPluginHooks = disabledPluginHooks;
|
||||
}
|
||||
}
|
|
@ -1,237 +0,0 @@
|
|||
package world.bentobox.level.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
public class Settings {
|
||||
|
||||
private boolean sumTeamDeaths;
|
||||
private Map<Material, Integer> blockLimits = new HashMap<>();
|
||||
private Map<Material, Integer> blockValues = new HashMap<>();
|
||||
private final Map<World, Map<Material, Integer>> worldBlockValues = new HashMap<>();
|
||||
private double underWaterMultiplier;
|
||||
private int deathpenalty;
|
||||
private long levelCost;
|
||||
private int levelWait;
|
||||
private int maxDeaths;
|
||||
private boolean islandResetDeathReset;
|
||||
private boolean teamJoinDeathReset;
|
||||
private List<String> gameModes = new ArrayList<>();
|
||||
|
||||
public Settings(Level level) {
|
||||
|
||||
level.saveDefaultConfig();
|
||||
|
||||
// GameModes
|
||||
gameModes = level.getConfig().getStringList("game-modes");
|
||||
|
||||
setLevelWait(level.getConfig().getInt("levelwait", 60));
|
||||
if (getLevelWait() < 0) {
|
||||
setLevelWait(0);
|
||||
}
|
||||
setDeathpenalty(level.getConfig().getInt("deathpenalty", 0));
|
||||
setSumTeamDeaths(level.getConfig().getBoolean("sumteamdeaths"));
|
||||
setMaxDeaths(level.getConfig().getInt("maxdeaths", 10));
|
||||
setIslandResetDeathReset(level.getConfig().getBoolean("islandresetdeathreset", true));
|
||||
setTeamJoinDeathReset(level.getConfig().getBoolean("teamjoindeathreset", true));
|
||||
setUnderWaterMultiplier(level.getConfig().getDouble("underwater", 1D));
|
||||
setLevelCost(level.getConfig().getInt("levelcost", 100));
|
||||
if (getLevelCost() < 1) {
|
||||
setLevelCost(1);
|
||||
level.getLogger().warning("levelcost in blockvalues.yml cannot be less than 1. Setting to 1.");
|
||||
}
|
||||
|
||||
if (level.getConfig().isSet("limits")) {
|
||||
HashMap<Material, Integer> bl = new HashMap<>();
|
||||
for (String material : level.getConfig().getConfigurationSection("limits").getKeys(false)) {
|
||||
try {
|
||||
Material mat = Material.valueOf(material);
|
||||
bl.put(mat, level.getConfig().getInt("limits." + material, 0));
|
||||
} catch (Exception e) {
|
||||
level.getLogger().warning(() -> "Unknown material (" + material + ") in blockvalues.yml Limits section. Skipping...");
|
||||
}
|
||||
}
|
||||
setBlockLimits(bl);
|
||||
}
|
||||
if (level.getConfig().isSet("blocks")) {
|
||||
Map<Material, Integer> bv = new HashMap<>();
|
||||
for (String material : level.getConfig().getConfigurationSection("blocks").getKeys(false)) {
|
||||
|
||||
try {
|
||||
Material mat = Material.valueOf(material);
|
||||
bv.put(mat, level.getConfig().getInt("blocks." + material, 0));
|
||||
} catch (Exception e) {
|
||||
level.getLogger().warning(()-> "Unknown material (" + material + ") in config.yml blocks section. Skipping...");
|
||||
}
|
||||
}
|
||||
setBlockValues(bv);
|
||||
} else {
|
||||
level.getLogger().severe("No block values in config.yml! All island levels will be zero!");
|
||||
}
|
||||
// Worlds
|
||||
if (level.getConfig().isSet("worlds")) {
|
||||
ConfigurationSection worlds = level.getConfig().getConfigurationSection("worlds");
|
||||
for (String world : worlds.getKeys(false)) {
|
||||
World bWorld = Bukkit.getWorld(world);
|
||||
if (bWorld != null) {
|
||||
ConfigurationSection worldValues = worlds.getConfigurationSection(world);
|
||||
for (String material : worldValues.getKeys(false)) {
|
||||
Material mat = Material.valueOf(material);
|
||||
Map<Material, Integer> values = worldBlockValues.getOrDefault(bWorld, new HashMap<>());
|
||||
values.put(mat, worldValues.getInt("blocks." + material, 0));
|
||||
worldBlockValues.put(bWorld, values);
|
||||
}
|
||||
} else {
|
||||
level.getLogger().severe(() -> "Level Addon: No such world : " + world);
|
||||
}
|
||||
}
|
||||
}
|
||||
// All done
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sumTeamDeaths
|
||||
*/
|
||||
public final boolean isSumTeamDeaths() {
|
||||
return sumTeamDeaths;
|
||||
}
|
||||
/**
|
||||
* @param sumTeamDeaths the sumTeamDeaths to set
|
||||
*/
|
||||
private void setSumTeamDeaths(boolean sumTeamDeaths) {
|
||||
this.sumTeamDeaths = sumTeamDeaths;
|
||||
}
|
||||
/**
|
||||
* @return the blockLimits
|
||||
*/
|
||||
public final Map<Material, Integer> getBlockLimits() {
|
||||
return blockLimits;
|
||||
}
|
||||
/**
|
||||
* @param blockLimits2 the blockLimits to set
|
||||
*/
|
||||
private void setBlockLimits(HashMap<Material, Integer> blockLimits2) {
|
||||
this.blockLimits = blockLimits2;
|
||||
}
|
||||
/**
|
||||
* @return the blockValues
|
||||
*/
|
||||
public final Map<Material, Integer> getBlockValues() {
|
||||
return blockValues;
|
||||
}
|
||||
/**
|
||||
* @param blockValues2 the blockValues to set
|
||||
*/
|
||||
private void setBlockValues(Map<Material, Integer> blockValues2) {
|
||||
this.blockValues = blockValues2;
|
||||
}
|
||||
/**
|
||||
* @return the underWaterMultiplier
|
||||
*/
|
||||
public final double getUnderWaterMultiplier() {
|
||||
return underWaterMultiplier;
|
||||
}
|
||||
/**
|
||||
* @param underWaterMultiplier the underWaterMultiplier to set
|
||||
*/
|
||||
private void setUnderWaterMultiplier(double underWaterMultiplier) {
|
||||
this.underWaterMultiplier = underWaterMultiplier;
|
||||
}
|
||||
/**
|
||||
* @return the deathpenalty
|
||||
*/
|
||||
public final int getDeathPenalty() {
|
||||
return deathpenalty;
|
||||
}
|
||||
/**
|
||||
* @param deathpenalty the deathpenalty to set
|
||||
*/
|
||||
private void setDeathpenalty(int deathpenalty) {
|
||||
this.deathpenalty = deathpenalty;
|
||||
}
|
||||
/**
|
||||
* @return the levelCost
|
||||
*/
|
||||
public final long getLevelCost() {
|
||||
return levelCost;
|
||||
}
|
||||
/**
|
||||
* @param levelCost the levelCost to set
|
||||
*/
|
||||
private void setLevelCost(long levelCost) {
|
||||
this.levelCost = levelCost;
|
||||
}
|
||||
/**
|
||||
* @return the levelWait
|
||||
*/
|
||||
public final int getLevelWait() {
|
||||
return levelWait;
|
||||
}
|
||||
/**
|
||||
* @param levelWait the levelWait to set
|
||||
*/
|
||||
private void setLevelWait(int levelWait) {
|
||||
this.levelWait = levelWait;
|
||||
}
|
||||
/**
|
||||
* TODO: Use max deaths
|
||||
* @return the maxDeaths
|
||||
*/
|
||||
public final int getMaxDeaths() {
|
||||
return maxDeaths;
|
||||
}
|
||||
/**
|
||||
* @param maxDeaths the maxDeaths to set
|
||||
*/
|
||||
private void setMaxDeaths(int maxDeaths) {
|
||||
this.maxDeaths = maxDeaths;
|
||||
}
|
||||
/**
|
||||
* @return the islandResetDeathReset
|
||||
*/
|
||||
public final boolean isIslandResetDeathReset() {
|
||||
return islandResetDeathReset;
|
||||
}
|
||||
/**
|
||||
* @param islandResetDeathReset the islandResetDeathReset to set
|
||||
*/
|
||||
private void setIslandResetDeathReset(boolean islandResetDeathReset) {
|
||||
this.islandResetDeathReset = islandResetDeathReset;
|
||||
}
|
||||
/**
|
||||
* @return the teamJoinDeathReset
|
||||
*/
|
||||
public final boolean isTeamJoinDeathReset() {
|
||||
return teamJoinDeathReset;
|
||||
}
|
||||
/**
|
||||
* @param teamJoinDeathReset the teamJoinDeathReset to set
|
||||
*/
|
||||
private void setTeamJoinDeathReset(boolean teamJoinDeathReset) {
|
||||
this.teamJoinDeathReset = teamJoinDeathReset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the worldBlockValues
|
||||
*/
|
||||
public Map<World, Map<Material, Integer>> getWorldBlockValues() {
|
||||
return worldBlockValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the gameModes
|
||||
*/
|
||||
public List<String> getGameModes() {
|
||||
return gameModes;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package world.bentobox.level.event;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import world.bentobox.bentobox.api.events.IslandBaseEvent;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.level.calculators.CalcIslandLevel.Results;
|
||||
|
||||
/**
|
||||
* This event is fired after the island level is calculated and before the results are saved.
|
||||
* If this event is cancelled, results will saved, but not communicated. i.e., the result will be silent.
|
||||
*
|
||||
* @author tastybento
|
||||
*/
|
||||
public class IslandLevelCalculatedEvent extends IslandBaseEvent {
|
||||
private Results results;
|
||||
|
||||
private UUID targetPlayer;
|
||||
|
||||
/**
|
||||
* @param targetPlayer - target player
|
||||
* @param island - island
|
||||
* @param results - results object to set
|
||||
*/
|
||||
public IslandLevelCalculatedEvent(UUID targetPlayer, Island island, Results results) {
|
||||
super(island);
|
||||
this.targetPlayer = targetPlayer;
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the results
|
||||
*/
|
||||
public Results getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the targetPlayer
|
||||
*/
|
||||
public UUID getTargetPlayer() {
|
||||
return targetPlayer;
|
||||
}
|
||||
/**
|
||||
* @param results the results to set
|
||||
*/
|
||||
public void setResults(Results results) {
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param targetPlayer the targetPlayer to set
|
||||
*/
|
||||
public void setTargetPlayer(UUID targetPlayer) {
|
||||
this.targetPlayer = targetPlayer;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
package world.bentobox.level.event;
|
||||
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
/**
|
||||
* This event is fired when a player clicks on a top ten head.
|
||||
*
|
||||
* @author tastybento
|
||||
*/
|
||||
class TopTenClick extends Event implements Cancellable {
|
||||
|
||||
private boolean cancelled;
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private final String owner;
|
||||
|
||||
|
||||
public TopTenClick(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return name of head owner that was clicked
|
||||
*/
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancelled) {
|
||||
this.cancelled = cancelled;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return getHandlerList();
|
||||
}
|
||||
|
||||
private static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package world.bentobox.level.events;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
|
||||
import world.bentobox.bentobox.api.events.IslandBaseEvent;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.level.calculators.Results;
|
||||
|
||||
/**
|
||||
* This event is fired after the island level is calculated and before the results are saved.
|
||||
* If this event is cancelled, results will saved, but not communicated. i.e., the result will be silent.
|
||||
*
|
||||
* @author tastybento
|
||||
*/
|
||||
public class IslandLevelCalculatedEvent extends IslandBaseEvent {
|
||||
private Results results;
|
||||
|
||||
private UUID targetPlayer;
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
@Override
|
||||
public @NonNull HandlerList getHandlers() {
|
||||
return getHandlerList();
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param targetPlayer - target player
|
||||
* @param island - island
|
||||
* @param results - results object to set
|
||||
*/
|
||||
public IslandLevelCalculatedEvent(UUID targetPlayer, Island island, Results results) {
|
||||
super(island);
|
||||
this.targetPlayer = targetPlayer;
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do NOT get this result if you are not a BentoBox addon!
|
||||
* @return the results
|
||||
*/
|
||||
public Results getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return death handicap value
|
||||
*/
|
||||
public int getDeathHandicap() {
|
||||
return results.getDeathHandicap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the island's initial level. It may be zero if it was never calculated.
|
||||
* @return initial level of island as calculated when the island was created.
|
||||
*/
|
||||
public long getInitialLevel() {
|
||||
return results.getInitialLevel();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the level calculated
|
||||
*/
|
||||
public long getLevel() {
|
||||
return results.getLevel();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overwrite the level. This level will be used instead of the calculated level.
|
||||
* @param level - the level to set
|
||||
*/
|
||||
public void setLevel(long level) {
|
||||
results.setLevel(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of points required to next level
|
||||
*/
|
||||
public long getPointsToNextLevel() {
|
||||
return results.getPointsToNextLevel();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a human readable report explaining how the calculation was made
|
||||
*/
|
||||
public List<String> getReport() {
|
||||
return results.getReport();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the targetPlayer
|
||||
*/
|
||||
public UUID getTargetPlayer() {
|
||||
return targetPlayer;
|
||||
}
|
||||
/**
|
||||
* Do not use this if you are not a BentoBox addon
|
||||
* @param results the results to set
|
||||
*/
|
||||
public void setResults(Results results) {
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param targetPlayer the targetPlayer to set
|
||||
*/
|
||||
public void setTargetPlayer(UUID targetPlayer) {
|
||||
this.targetPlayer = targetPlayer;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
package world.bentobox.level.event;
|
||||
package world.bentobox.level.events;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
|
||||
import world.bentobox.bentobox.api.events.IslandBaseEvent;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
|
||||
|
@ -13,6 +16,16 @@ import world.bentobox.bentobox.database.objects.Island;
|
|||
public class IslandPreLevelEvent extends IslandBaseEvent {
|
||||
|
||||
private final UUID targetPlayer;
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
@Override
|
||||
public @NonNull HandlerList getHandlers() {
|
||||
return getHandlerList();
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
|
@ -0,0 +1,121 @@
|
|||
package world.bentobox.level.listeners;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import world.bentobox.bentobox.api.events.island.IslandCreatedEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandDeleteEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandPreclearEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandRegisteredEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandResettedEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandUnregisteredEvent;
|
||||
import world.bentobox.bentobox.api.events.team.TeamJoinedEvent;
|
||||
import world.bentobox.bentobox.api.events.team.TeamKickEvent;
|
||||
import world.bentobox.bentobox.api.events.team.TeamLeaveEvent;
|
||||
import world.bentobox.bentobox.api.events.team.TeamSetownerEvent;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
/**
|
||||
* Listens for new islands or ownership changes and sets the level to zero
|
||||
* automatically
|
||||
*
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class IslandActivitiesListeners implements Listener {
|
||||
|
||||
private final Level addon;
|
||||
|
||||
/**
|
||||
* @param addon - addon
|
||||
*/
|
||||
public IslandActivitiesListeners(Level addon) {
|
||||
this.addon = addon;
|
||||
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onNewIsland(IslandCreatedEvent e) {
|
||||
if (addon.getSettings().isZeroNewIslandLevels()) {
|
||||
zeroIsland(e.getIsland());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onNewIsland(IslandResettedEvent e) {
|
||||
if (addon.getSettings().isZeroNewIslandLevels()) {
|
||||
zeroIsland(e.getIsland());
|
||||
}
|
||||
}
|
||||
|
||||
private void zeroIsland(final Island island) {
|
||||
// Clear the island setting
|
||||
if (island.getOwner() != null && island.getWorld() != null) {
|
||||
addon.getPipeliner().zeroIsland(island)
|
||||
.thenAccept(results -> addon.getManager().setInitialIslandLevel(island, results.getLevel()));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onIslandDelete(IslandPreclearEvent e) {
|
||||
remove(e.getIsland().getWorld(), e.getIsland().getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onIslandDeleted(IslandDeleteEvent e) {
|
||||
// Remove island
|
||||
addon.getManager().deleteIsland(e.getIsland().getUniqueId());
|
||||
}
|
||||
|
||||
private void remove(World world, String uuid) {
|
||||
if (uuid != null && world != null) {
|
||||
addon.getManager().removeEntry(world, uuid);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onNewIslandOwner(TeamSetownerEvent e) {
|
||||
|
||||
// Remove island from the top ten and level
|
||||
remove(e.getIsland().getWorld(), e.getIsland().getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onIsland(TeamJoinedEvent e) {
|
||||
// TODO: anything to do here?
|
||||
// Remove player from the top ten and level
|
||||
// remove(e.getIsland().getWorld(), e.getPlayerUUID());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onIsland(IslandUnregisteredEvent e) {
|
||||
|
||||
// Remove island from the top ten
|
||||
remove(e.getIsland().getWorld(), e.getIsland().getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onIsland(IslandRegisteredEvent e) {
|
||||
// TODO: anything to do here?
|
||||
// Remove player from the top ten
|
||||
// remove(e.getIsland().getWorld(), e.getPlayerUUID());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onIsland(TeamLeaveEvent e) {
|
||||
// TODO: anything to do here?
|
||||
// Remove player from the top ten and level
|
||||
// remove(e.getIsland().getWorld(), e.getPlayerUUID());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onIsland(TeamKickEvent e) {
|
||||
//// TODO: anything to do here?
|
||||
// Remove player from the top ten and level
|
||||
// remove(e.getIsland().getWorld(), e.getPlayerUUID());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
package world.bentobox.level.listeners;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import world.bentobox.bentobox.api.events.island.IslandEvent.IslandCreatedEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandEvent.IslandRegisteredEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandEvent.IslandResettedEvent;
|
||||
import world.bentobox.bentobox.api.events.island.IslandEvent.IslandUnregisteredEvent;
|
||||
import world.bentobox.bentobox.api.events.team.TeamEvent.TeamJoinedEvent;
|
||||
import world.bentobox.bentobox.api.events.team.TeamEvent.TeamKickEvent;
|
||||
import world.bentobox.bentobox.api.events.team.TeamEvent.TeamLeaveEvent;
|
||||
import world.bentobox.bentobox.api.events.team.TeamEvent.TeamSetownerEvent;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.calculators.CalcIslandLevel;
|
||||
|
||||
/**
|
||||
* Listens for new islands or ownership changes and sets the level to zero automatically
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class IslandTeamListeners implements Listener {
|
||||
|
||||
private final Level addon;
|
||||
private final Map<Island, CalcIslandLevel> cil;
|
||||
|
||||
/**
|
||||
* @param addon - addon
|
||||
*/
|
||||
public IslandTeamListeners(Level addon) {
|
||||
this.addon = addon;
|
||||
cil = new HashMap<>();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onNewIsland(IslandCreatedEvent e) {
|
||||
if (e.getIsland().getOwner() != null && e.getIsland().getWorld() != null) {
|
||||
cil.putIfAbsent(e.getIsland(), new CalcIslandLevel(addon, e.getIsland(), () -> zeroLevel(e.getIsland())));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onNewIsland(IslandResettedEvent e) {
|
||||
if (e.getIsland().getOwner() != null && e.getIsland().getWorld() != null) {
|
||||
cil.putIfAbsent(e.getIsland(), new CalcIslandLevel(addon, e.getIsland(), () -> zeroLevel(e.getIsland())));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onNewIslandOwner(TeamSetownerEvent e) {
|
||||
// Remove player from the top ten and level
|
||||
addon.setIslandLevel(e.getIsland().getWorld(), e.getIsland().getOwner(), 0);
|
||||
addon.getTopTen().removeEntry(e.getIsland().getWorld(), e.getIsland().getOwner());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onIsland(TeamJoinedEvent e) {
|
||||
// Remove player from the top ten and level
|
||||
addon.setIslandLevel(e.getIsland().getWorld(), e.getPlayerUUID(), 0);
|
||||
addon.getTopTen().removeEntry(e.getIsland().getWorld(), e.getPlayerUUID());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onIsland(IslandUnregisteredEvent e) {
|
||||
// Remove player from the top ten and level
|
||||
addon.setIslandLevel(e.getIsland().getWorld(), e.getPlayerUUID(), 0);
|
||||
addon.getTopTen().removeEntry(e.getIsland().getWorld(), e.getPlayerUUID());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onIsland(IslandRegisteredEvent e) {
|
||||
// Remove player from the top ten and level
|
||||
addon.setIslandLevel(e.getIsland().getWorld(), e.getPlayerUUID(), 0);
|
||||
addon.getTopTen().removeEntry(e.getIsland().getWorld(), e.getPlayerUUID());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onIsland(TeamLeaveEvent e) {
|
||||
// Remove player from the top ten and level
|
||||
addon.setIslandLevel(e.getIsland().getWorld(), e.getPlayerUUID(), 0);
|
||||
addon.getTopTen().removeEntry(e.getIsland().getWorld(), e.getPlayerUUID());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onIsland(TeamKickEvent e) {
|
||||
// Remove player from the top ten and level
|
||||
addon.setIslandLevel(e.getIsland().getWorld(), e.getPlayerUUID(), 0);
|
||||
addon.getTopTen().removeEntry(e.getIsland().getWorld(), e.getPlayerUUID());
|
||||
}
|
||||
|
||||
private void zeroLevel(Island island) {
|
||||
if (cil.containsKey(island)) {
|
||||
addon.setInitialIslandLevel(island, cil.get(island).getResult().getLevel());
|
||||
cil.remove(island);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
package world.bentobox.level.listeners;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
/**
|
||||
* Listens for when players join and leave
|
||||
* Listens for when players join
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
|
@ -26,14 +27,15 @@ public class JoinLeaveListener implements Listener {
|
|||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onPlayerJoin(PlayerJoinEvent e) {
|
||||
// Load player into cache
|
||||
addon.getLevelsData(e.getPlayer().getUniqueId());
|
||||
}
|
||||
// If level calc on login is enabled, run through all the worlds and calculate the level
|
||||
if (addon.getSettings().isCalcOnLogin()) {
|
||||
addon.getPlugin().getAddonsManager().getGameModeAddons().stream()
|
||||
.filter(gm -> !addon.getSettings().getGameModes().contains(gm.getDescription().getName()))
|
||||
.map(gm -> gm.getIslands().getIsland(gm.getOverWorld(), e.getPlayer().getUniqueId()))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(island -> addon.getManager().calculateLevel(e.getPlayer().getUniqueId(), island));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onPlayerQuit(PlayerQuitEvent e) {
|
||||
addon.uncachePlayer(e.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// Created by BONNe
|
||||
// Copyright - 2022
|
||||
//
|
||||
|
||||
|
||||
package world.bentobox.level.listeners;
|
||||
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import world.bentobox.bentobox.api.events.BentoBoxReadyEvent;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
|
||||
/**
|
||||
* This listener checks when BentoBox is ready and then tries to migrate Levels addon database, if it is required.
|
||||
*/
|
||||
public class MigrationListener implements Listener
|
||||
{
|
||||
public MigrationListener(Level addon)
|
||||
{
|
||||
this.addon = addon;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBentoBoxReady(BentoBoxReadyEvent e) {
|
||||
// Perform upgrade check
|
||||
this.addon.getManager().migrate();
|
||||
// Load TopTens
|
||||
this.addon.getManager().loadTopTens();
|
||||
/*
|
||||
* DEBUG code to generate fake islands and then try to level them all.
|
||||
Bukkit.getScheduler().runTaskLater(getPlugin(), () -> {
|
||||
getPlugin().getAddonsManager().getGameModeAddons().stream()
|
||||
.filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName()))
|
||||
.forEach(gm -> {
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
try {
|
||||
NewIsland.builder().addon(gm).player(User.getInstance(UUID.randomUUID())).name("default").reason(Reason.CREATE).noPaste().build();
|
||||
} catch (IOException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
// Queue all islands DEBUG
|
||||
|
||||
getIslands().getIslands().stream().filter(Island::isOwned).forEach(is -> {
|
||||
|
||||
this.getManager().calculateLevel(is.getOwner(), is).thenAccept(r ->
|
||||
log("Result for island calc " + r.getLevel() + " at " + is.getCenter()));
|
||||
|
||||
});
|
||||
}, 60L);*/
|
||||
}
|
||||
|
||||
|
||||
private final Level addon;
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
package world.bentobox.level.objects;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Material;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import world.bentobox.bentobox.database.objects.DataObject;
|
||||
import world.bentobox.bentobox.database.objects.Table;
|
||||
|
||||
/**
|
||||
* Stores the levels data of the island.
|
||||
* A note - if this class is extended to support new exposed fields and legacy data doesn't include those fields
|
||||
* they will be set to null by GSON. They will not be initialized and if any attempt is made to use them, then
|
||||
* the JVM will give up WITHOUT AN ERROR!!! That is why there are null checks throughout this class.
|
||||
*
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
@Table(name = "IslandLevels")
|
||||
public class IslandLevels implements DataObject {
|
||||
|
||||
/**
|
||||
* uniqueId is the island's UUID
|
||||
*/
|
||||
@Expose
|
||||
private String uniqueId = "";
|
||||
|
||||
/**
|
||||
* Island level
|
||||
*/
|
||||
@Expose
|
||||
private long level;
|
||||
/**
|
||||
* Initial level
|
||||
*/
|
||||
@Expose
|
||||
private long initialLevel;
|
||||
/**
|
||||
* Points to next level
|
||||
*/
|
||||
@Expose
|
||||
private long pointsToNextLevel;
|
||||
/**
|
||||
* The maximum level this island has ever had
|
||||
*/
|
||||
@Expose
|
||||
private long maxLevel;
|
||||
|
||||
/**
|
||||
* Total points
|
||||
*/
|
||||
@Expose
|
||||
private long totalPoints;
|
||||
|
||||
/**
|
||||
* Underwater count
|
||||
*/
|
||||
@Expose
|
||||
private Map<Material, Integer> uwCount;
|
||||
|
||||
/**
|
||||
* MaterialData count - count of all blocks
|
||||
*/
|
||||
@Expose
|
||||
private Map<Material, Integer> mdCount;
|
||||
|
||||
/**
|
||||
* Constructor for new island
|
||||
* @param islandUUID - island UUID
|
||||
*/
|
||||
public IslandLevels(String islandUUID) {
|
||||
uniqueId = islandUUID;
|
||||
uwCount = new EnumMap<>(Material.class);
|
||||
mdCount = new EnumMap<>(Material.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the uniqueId
|
||||
*/
|
||||
@Override
|
||||
public String getUniqueId() {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uniqueId the uniqueId to set
|
||||
*/
|
||||
@Override
|
||||
public void setUniqueId(String uniqueId) {
|
||||
this.uniqueId = uniqueId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the level
|
||||
*/
|
||||
public long getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param level the level to set
|
||||
*/
|
||||
public void setLevel(long level) {
|
||||
this.level = level;
|
||||
// Track maximum level
|
||||
if (level > this.maxLevel) {
|
||||
maxLevel = level;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the initialLevel
|
||||
*/
|
||||
public long getInitialLevel() {
|
||||
return initialLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param initialLevel the initialLevel to set
|
||||
*/
|
||||
public void setInitialLevel(long initialLevel) {
|
||||
this.initialLevel = initialLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the pointsToNextLevel
|
||||
*/
|
||||
public long getPointsToNextLevel() {
|
||||
return pointsToNextLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pointsToNextLevel the pointsToNextLevel to set
|
||||
*/
|
||||
public void setPointsToNextLevel(long pointsToNextLevel) {
|
||||
this.pointsToNextLevel = pointsToNextLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the totalPoints
|
||||
*/
|
||||
public long getTotalPoints() {
|
||||
return totalPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param totalPoints the totalPoints to set
|
||||
*/
|
||||
public void setTotalPoints(long totalPoints) {
|
||||
this.totalPoints = totalPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum level ever set using {@link #setLevel(long)}
|
||||
* @return the maxLevel
|
||||
*/
|
||||
public long getMaxLevel() {
|
||||
return maxLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the uwCount
|
||||
*/
|
||||
public Map<Material, Integer> getUwCount() {
|
||||
return uwCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uwCount the uwCount to set
|
||||
*/
|
||||
public void setUwCount(Map<Material, Integer> uwCount) {
|
||||
this.uwCount = uwCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the mdCount
|
||||
*/
|
||||
public Map<Material, Integer> getMdCount() {
|
||||
return mdCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mdCount the mdCount to set
|
||||
*/
|
||||
public void setMdCount(Map<Material, Integer> mdCount) {
|
||||
this.mdCount = mdCount;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,15 +1,32 @@
|
|||
package world.bentobox.level.objects;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.google.common.collect.Multiset;
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import world.bentobox.bentobox.database.objects.DataObject;
|
||||
import world.bentobox.bentobox.database.objects.Table;
|
||||
|
||||
/**
|
||||
* Stores the levels data of the user.
|
||||
* A note - if this class is extended to support new exposed fields and legacy data doesn't include those fields
|
||||
* they will be set to null by GSON. They will not be initialized and if any attempt is made to use them, then
|
||||
* the JVM will give up WITHOUT AN ERROR!!! That is why there are null checks throughout this class.
|
||||
*
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
@Table(name = "LevelsData")
|
||||
public class LevelsData implements DataObject {
|
||||
|
||||
// uniqueId is the player's UUID
|
||||
|
@ -20,24 +37,43 @@ public class LevelsData implements DataObject {
|
|||
* Map of world name and island level
|
||||
*/
|
||||
@Expose
|
||||
private Map<String, Long> levels = new HashMap<>();
|
||||
private Map<String, Long> levels;
|
||||
/**
|
||||
* Map of world name to island initial level
|
||||
*/
|
||||
@Expose
|
||||
private Map<String, Long> initialLevel = new HashMap<>();
|
||||
private Map<String, Long> initialLevel;
|
||||
/**
|
||||
* Map of world name to points to next level
|
||||
*/
|
||||
@Expose
|
||||
private Map<String, Long> pointsToNextLevel;
|
||||
|
||||
public LevelsData() {} // For Bean loading
|
||||
@Expose
|
||||
private Map<String, Map<Material, Integer>> uwCount;
|
||||
|
||||
@Expose
|
||||
private Map<String, Map<Material, Integer>> mdCount;
|
||||
|
||||
/**
|
||||
* Create a level entry for target player
|
||||
* @param targetPlayer - target player
|
||||
* @param level - level
|
||||
* @param world - world
|
||||
*/
|
||||
public LevelsData(UUID targetPlayer, long level, World world) {
|
||||
public LevelsData(UUID targetPlayer) {
|
||||
uniqueId = targetPlayer.toString();
|
||||
levels.put(world.getName(), level);
|
||||
levels = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
initialLevel = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
pointsToNextLevel = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
uwCount = new HashMap<>();
|
||||
mdCount = new HashMap<>();
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
if (levels == null) levels = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
if (initialLevel == null) initialLevel = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
if (pointsToNextLevel == null) pointsToNextLevel = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
if (uwCount == null) uwCount = new HashMap<>();
|
||||
if (mdCount == null) mdCount = new HashMap<>();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -62,13 +98,15 @@ public class LevelsData implements DataObject {
|
|||
* @return island level
|
||||
*/
|
||||
public Long getLevel(World world) {
|
||||
return world == null ? 0L : levels.getOrDefault(world.getName(), 0L);
|
||||
initialize();
|
||||
return world == null ? 0L : levels.getOrDefault(world.getName().toLowerCase(Locale.ENGLISH), 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the levels
|
||||
*/
|
||||
public Map<String, Long> getLevels() {
|
||||
initialize();
|
||||
return levels;
|
||||
}
|
||||
|
||||
|
@ -76,11 +114,19 @@ public class LevelsData implements DataObject {
|
|||
* @param levels the levels to set
|
||||
*/
|
||||
public void setLevels(Map<String, Long> levels) {
|
||||
initialize();
|
||||
this.levels = levels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the island level to level - the initial level
|
||||
* @param world - world where island is
|
||||
* @param lv - level
|
||||
*/
|
||||
public void setLevel(World world, Long lv) {
|
||||
levels.put(world.getName(),lv);
|
||||
initialize();
|
||||
String name = world.getName().toLowerCase(Locale.ENGLISH);
|
||||
levels.put(name, lv - this.initialLevel.getOrDefault(name, 0L));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,13 +135,15 @@ public class LevelsData implements DataObject {
|
|||
* @param level - level
|
||||
*/
|
||||
public void setInitialLevel(World world, long level) {
|
||||
this.initialLevel.put(world.getName(), level);
|
||||
initialize();
|
||||
this.initialLevel.put(world.getName().toLowerCase(Locale.ENGLISH), level);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the initialLevel
|
||||
*/
|
||||
public Map<String, Long> getInitialLevel() {
|
||||
initialize();
|
||||
return initialLevel;
|
||||
}
|
||||
|
||||
|
@ -103,6 +151,7 @@ public class LevelsData implements DataObject {
|
|||
* @param initialLevel the initialLevel to set
|
||||
*/
|
||||
public void setInitialLevel(Map<String, Long> initialLevel) {
|
||||
initialize();
|
||||
this.initialLevel = initialLevel;
|
||||
}
|
||||
|
||||
|
@ -112,6 +161,101 @@ public class LevelsData implements DataObject {
|
|||
* @return initial island level or 0 by default
|
||||
*/
|
||||
public long getInitialLevel(World world) {
|
||||
return initialLevel.getOrDefault(world.getName(), 0L);
|
||||
initialize();
|
||||
return initialLevel.getOrDefault(world.getName().toLowerCase(Locale.ENGLISH), 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a world from a player's data
|
||||
* @param world - world to remove
|
||||
*/
|
||||
public void remove(World world) {
|
||||
initialize();
|
||||
this.levels.remove(world.getName().toLowerCase(Locale.ENGLISH));
|
||||
this.initialLevel.remove(world.getName().toLowerCase(Locale.ENGLISH));
|
||||
this.pointsToNextLevel.remove(world.getName().toLowerCase(Locale.ENGLISH));
|
||||
this.mdCount.remove(world.getName().toLowerCase(Locale.ENGLISH));
|
||||
this.uwCount.remove(world.getName().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the pointsToNextLevel
|
||||
*/
|
||||
public Map<String, Long> getPointsToNextLevel() {
|
||||
initialize();
|
||||
return pointsToNextLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pointsToNextLevel the pointsToNextLevel to set
|
||||
*/
|
||||
public void setPointsToNextLevel(Map<String, Long> pointsToNextLevel) {
|
||||
initialize();
|
||||
this.pointsToNextLevel = pointsToNextLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the island points to next level.
|
||||
* This is calculated the last time the level was calculated and will not change dynamically.
|
||||
* @param world - world where island is
|
||||
* @param points - points to next level
|
||||
*/
|
||||
public void setPointsToNextLevel(World world, Long points) {
|
||||
initialize();
|
||||
pointsToNextLevel.put(world.getName().toLowerCase(Locale.ENGLISH), points);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the points required to get to the next island level for this world.
|
||||
* This is calculated when the island level is calculated and will not change dynamically.
|
||||
* @param world - world
|
||||
* @return points to next level or zero if unknown
|
||||
*/
|
||||
public long getPointsToNextLevel(World world) {
|
||||
initialize();
|
||||
return pointsToNextLevel.getOrDefault(world.getName().toLowerCase(Locale.ENGLISH), 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uwCount the uwCount to set
|
||||
*/
|
||||
public void setUwCount(World world, Multiset<Material> uwCount) {
|
||||
initialize();
|
||||
Map<Material, Integer> count = new EnumMap<>(Material.class);
|
||||
uwCount.forEach(m -> count.put(m, uwCount.count(m)));
|
||||
|
||||
this.uwCount.put(world.getName().toLowerCase(Locale.ENGLISH), count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mdCount the mdCount to set
|
||||
*/
|
||||
public void setMdCount(World world, Multiset<Material> mdCount) {
|
||||
initialize();
|
||||
Map<Material, Integer> count = new EnumMap<>(Material.class);
|
||||
mdCount.forEach(m -> count.put(m, mdCount.count(m)));
|
||||
|
||||
this.mdCount.put(world.getName().toLowerCase(Locale.ENGLISH), count);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underwater block count for world
|
||||
* @return the uwCount
|
||||
*/
|
||||
public Map<Material, Integer> getUwCount(World world) {
|
||||
initialize();
|
||||
return uwCount.getOrDefault(world.getName().toLowerCase(Locale.ENGLISH), Collections.emptyMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the over-water block count for world
|
||||
* @return the mdCount
|
||||
*/
|
||||
public Map<Material, Integer> getMdCount(World world) {
|
||||
initialize();
|
||||
return mdCount.getOrDefault(world.getName().toLowerCase(Locale.ENGLISH), Collections.emptyMap());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,75 +1,43 @@
|
|||
package world.bentobox.level.objects;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import world.bentobox.bentobox.database.objects.DataObject;
|
||||
|
||||
/**
|
||||
* This class stores and sorts the top ten.
|
||||
* @author ben
|
||||
* This class stores the top ten.
|
||||
*
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class TopTenData implements DataObject {
|
||||
public class TopTenData {
|
||||
|
||||
// UniqueId is the world name
|
||||
@Expose
|
||||
private String uniqueId = "";
|
||||
@Expose
|
||||
private Map<UUID, Long> topTen = new LinkedHashMap<>();
|
||||
private Map<String, Long> topTen = new LinkedHashMap<>();
|
||||
|
||||
public Map<UUID, Long> getTopTen() {
|
||||
return topTen.entrySet().stream()
|
||||
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).limit(10)
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||
}
|
||||
|
||||
public void setTopTen(Map<UUID, Long> topTen) {
|
||||
this.topTen = topTen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueId() {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUniqueId(String uniqueId) {
|
||||
this.uniqueId = uniqueId;
|
||||
public TopTenData(World k) {
|
||||
uniqueId = k.getName().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add level for this island owner or team leader, sort the top ten and limit to ten entries
|
||||
* @param uuid - UUID of owner or team leader
|
||||
* @param level - island level
|
||||
* @return the topTen
|
||||
*/
|
||||
public void addLevel(UUID uuid, Long level) {
|
||||
this.topTen.put(uuid, level);
|
||||
public Map<String, Long> getTopTen() {
|
||||
return topTen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the level for this UUID, or zero if the UUID is not found
|
||||
* @param uuid - UUID to check
|
||||
* @return island level
|
||||
* @param topTen the topTen to set
|
||||
*/
|
||||
public long getLevel(UUID uuid) {
|
||||
if (topTen.containsKey(uuid))
|
||||
return topTen.get(uuid);
|
||||
return 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes ownerUUID from the top ten
|
||||
* @param ownerUUID - UUID to remove
|
||||
*/
|
||||
public void remove(UUID ownerUUID) {
|
||||
this.topTen.remove(ownerUUID);
|
||||
public void setTopTen(Map<String, Long> topTen) {
|
||||
this.topTen = topTen;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,687 @@
|
|||
package world.bentobox.level.panels;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.google.common.base.Enums;
|
||||
|
||||
import lv.id.bonne.panelutils.PanelUtils;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
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.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.util.Pair;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.objects.IslandLevels;
|
||||
import world.bentobox.level.util.Utils;
|
||||
|
||||
/**
|
||||
* This class opens GUI that shows generator view for user.
|
||||
*/
|
||||
public class DetailsPanel {
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Internal Constructor
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This is internal constructor. It is used internally in current class to avoid
|
||||
* creating objects everywhere.
|
||||
*
|
||||
* @param addon Level object
|
||||
* @param world World where user is operating
|
||||
* @param user User who opens panel
|
||||
*/
|
||||
private DetailsPanel(Level addon, World world, User user) {
|
||||
this.addon = addon;
|
||||
this.world = world;
|
||||
this.user = user;
|
||||
|
||||
this.island = this.addon.getIslands().getIsland(world, user);
|
||||
|
||||
if (this.island != null) {
|
||||
this.levelsData = this.addon.getManager().getLevelsData(this.island);
|
||||
} else {
|
||||
this.levelsData = null;
|
||||
}
|
||||
|
||||
// By default no-filters are active.
|
||||
this.activeTab = Tab.ALL_BLOCKS;
|
||||
this.activeFilter = Filter.NAME;
|
||||
this.materialCountList = new ArrayList<>(Material.values().length);
|
||||
|
||||
this.updateFilters();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds this GUI.
|
||||
*/
|
||||
private void build() {
|
||||
if (this.island == null || this.levelsData == null) {
|
||||
// Nothing to see.
|
||||
Utils.sendMessage(this.user, this.user.getTranslation("general.errors.no-island"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.levelsData.getMdCount().isEmpty() && this.levelsData.getUwCount().isEmpty()) {
|
||||
// Nothing to see.
|
||||
Utils.sendMessage(this.user, this.user.getTranslation("level.conversations.no-data"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Start building panel.
|
||||
TemplatedPanelBuilder panelBuilder = new TemplatedPanelBuilder();
|
||||
panelBuilder.user(this.user);
|
||||
panelBuilder.world(this.user.getWorld());
|
||||
|
||||
panelBuilder.template("detail_panel", new File(this.addon.getDataFolder(), "panels"));
|
||||
|
||||
panelBuilder.parameters("[name]", this.user.getName());
|
||||
|
||||
panelBuilder.registerTypeBuilder("NEXT", this::createNextButton);
|
||||
panelBuilder.registerTypeBuilder("PREVIOUS", this::createPreviousButton);
|
||||
panelBuilder.registerTypeBuilder("BLOCK", this::createMaterialButton);
|
||||
|
||||
panelBuilder.registerTypeBuilder("FILTER", this::createFilterButton);
|
||||
|
||||
// Register tabs
|
||||
panelBuilder.registerTypeBuilder("TAB", this::createTabButton);
|
||||
|
||||
// Register unknown type builder.
|
||||
panelBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method updates filter of elements based on tabs.
|
||||
*/
|
||||
private void updateFilters() {
|
||||
this.materialCountList.clear();
|
||||
|
||||
switch (this.activeTab) {
|
||||
case ALL_BLOCKS -> {
|
||||
Map<Material, Integer> materialCountMap = new EnumMap<>(Material.class);
|
||||
|
||||
materialCountMap.putAll(this.levelsData.getMdCount());
|
||||
|
||||
// Add underwater blocks.
|
||||
this.levelsData.getUwCount().forEach((material, count) -> materialCountMap.put(material,
|
||||
materialCountMap.computeIfAbsent(material, key -> 0) + count));
|
||||
|
||||
materialCountMap.entrySet().stream().sorted((Map.Entry.comparingByKey()))
|
||||
.forEachOrdered(entry -> this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue())));
|
||||
}
|
||||
case ABOVE_SEA_LEVEL -> this.levelsData.getMdCount().entrySet().stream().sorted((Map.Entry.comparingByKey()))
|
||||
.forEachOrdered(entry -> this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue())));
|
||||
|
||||
case UNDERWATER -> this.levelsData.getUwCount().entrySet().stream().sorted((Map.Entry.comparingByKey()))
|
||||
.forEachOrdered(entry -> this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue())));
|
||||
|
||||
case SPAWNER -> {
|
||||
int aboveWater = this.levelsData.getMdCount().getOrDefault(Material.SPAWNER, 0);
|
||||
int underWater = this.levelsData.getUwCount().getOrDefault(Material.SPAWNER, 0);
|
||||
|
||||
// TODO: spawners need some touch...
|
||||
this.materialCountList.add(new Pair<>(Material.SPAWNER, underWater + aboveWater));
|
||||
}
|
||||
}
|
||||
|
||||
Comparator<Pair<Material, Integer>> sorter;
|
||||
|
||||
switch (this.activeFilter) {
|
||||
case COUNT -> {
|
||||
sorter = (o1, o2) -> {
|
||||
if (o1.getValue().equals(o2.getValue())) {
|
||||
String o1Name = Utils.prettifyObject(o1.getKey(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.getKey(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name);
|
||||
} else {
|
||||
return Integer.compare(o2.getValue(), o1.getValue());
|
||||
}
|
||||
};
|
||||
}
|
||||
case VALUE -> {
|
||||
sorter = (o1, o2) -> {
|
||||
int blockLimit = this.addon.getBlockConfig().getBlockLimits().getOrDefault(o1.getKey(), 0);
|
||||
int o1Count = blockLimit > 0 ? Math.min(o1.getValue(), blockLimit) : o1.getValue();
|
||||
|
||||
blockLimit = this.addon.getBlockConfig().getBlockLimits().getOrDefault(o2.getKey(), 0);
|
||||
int o2Count = blockLimit > 0 ? Math.min(o2.getValue(), blockLimit) : o2.getValue();
|
||||
|
||||
long o1Value = (long) o1Count
|
||||
* this.addon.getBlockConfig().getBlockValues().getOrDefault(o1.getKey(), 0);
|
||||
long o2Value = (long) o2Count
|
||||
* this.addon.getBlockConfig().getBlockValues().getOrDefault(o2.getKey(), 0);
|
||||
|
||||
if (o1Value == o2Value) {
|
||||
String o1Name = Utils.prettifyObject(o1.getKey(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.getKey(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name);
|
||||
} else {
|
||||
return Long.compare(o2Value, o1Value);
|
||||
}
|
||||
};
|
||||
}
|
||||
default -> {
|
||||
sorter = (o1, o2) -> {
|
||||
String o1Name = Utils.prettifyObject(o1.getKey(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.getKey(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
this.materialCountList.sort(sorter);
|
||||
|
||||
this.pageIndex = 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Tab Button Type
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create tab button panel item.
|
||||
*
|
||||
* @param template the template
|
||||
* @param slot the slot
|
||||
* @return the panel item
|
||||
*/
|
||||
private PanelItem createTabButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot) {
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null) {
|
||||
// Set icon
|
||||
builder.icon(template.icon().clone());
|
||||
}
|
||||
|
||||
if (template.title() != null) {
|
||||
// Set title
|
||||
builder.name(this.user.getTranslation(this.world, template.title()));
|
||||
}
|
||||
|
||||
if (template.description() != null) {
|
||||
// Set description
|
||||
builder.description(this.user.getTranslation(this.world, template.description()));
|
||||
}
|
||||
|
||||
Tab tab = Enums.getIfPresent(Tab.class, String.valueOf(template.dataMap().get("tab"))).or(Tab.ALL_BLOCKS);
|
||||
|
||||
// Get only possible actions, by removing all inactive ones.
|
||||
List<ItemTemplateRecord.ActionRecords> activeActions = new ArrayList<>(template.actions());
|
||||
|
||||
activeActions.removeIf(action -> "VIEW".equalsIgnoreCase(action.actionType()) && this.activeTab == tab);
|
||||
|
||||
// Add Click handler
|
||||
builder.clickHandler((panel, user, clickType, i) -> {
|
||||
for (ItemTemplateRecord.ActionRecords action : activeActions) {
|
||||
if ((clickType == action.clickType() || ClickType.UNKNOWN.equals(action.clickType()))
|
||||
&& "VIEW".equalsIgnoreCase(action.actionType())) {
|
||||
this.activeTab = tab;
|
||||
|
||||
// Update filters.
|
||||
this.updateFilters();
|
||||
this.build();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = activeActions.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);
|
||||
}
|
||||
|
||||
builder.glow(this.activeTab == tab);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create next button panel item.
|
||||
*
|
||||
* @param template the template
|
||||
* @param slot the slot
|
||||
* @return the panel item
|
||||
*/
|
||||
private PanelItem createFilterButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot) {
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null) {
|
||||
// Set icon
|
||||
builder.icon(template.icon().clone());
|
||||
}
|
||||
|
||||
Filter filter;
|
||||
|
||||
if (slot.amountMap().getOrDefault("FILTER", 0) > 1) {
|
||||
filter = Enums.getIfPresent(Filter.class, String.valueOf(template.dataMap().get("filter"))).or(Filter.NAME);
|
||||
} else {
|
||||
filter = this.activeFilter;
|
||||
}
|
||||
|
||||
final String reference = "level.gui.buttons.filters.";
|
||||
|
||||
if (template.title() != null) {
|
||||
// Set title
|
||||
builder.name(this.user.getTranslation(this.world,
|
||||
template.title().replace("[filter]", filter.name().toLowerCase())));
|
||||
} else {
|
||||
builder.name(this.user.getTranslation(this.world, reference + filter.name().toLowerCase() + ".name"));
|
||||
}
|
||||
|
||||
if (template.description() != null) {
|
||||
// Set description
|
||||
builder.description(this.user.getTranslation(this.world,
|
||||
template.description().replace("[filter]", filter.name().toLowerCase())));
|
||||
} else {
|
||||
builder.name(
|
||||
this.user.getTranslation(this.world, reference + filter.name().toLowerCase() + ".description"));
|
||||
}
|
||||
|
||||
// Get only possible actions, by removing all inactive ones.
|
||||
List<ItemTemplateRecord.ActionRecords> activeActions = new ArrayList<>(template.actions());
|
||||
|
||||
// Add Click handler
|
||||
builder.clickHandler((panel, user, clickType, i) -> {
|
||||
for (ItemTemplateRecord.ActionRecords action : activeActions) {
|
||||
if (clickType == action.clickType() || ClickType.UNKNOWN.equals(action.clickType())) {
|
||||
if ("UP".equalsIgnoreCase(action.actionType())) {
|
||||
this.activeFilter = Utils.getNextValue(Filter.values(), filter);
|
||||
|
||||
// Update filters.
|
||||
this.updateFilters();
|
||||
this.build();
|
||||
} else if ("DOWN".equalsIgnoreCase(action.actionType())) {
|
||||
this.activeFilter = Utils.getPreviousValue(Filter.values(), filter);
|
||||
|
||||
// Update filters.
|
||||
this.updateFilters();
|
||||
this.build();
|
||||
} else if ("SELECT".equalsIgnoreCase(action.actionType())) {
|
||||
this.activeFilter = filter;
|
||||
|
||||
// Update filters.
|
||||
this.updateFilters();
|
||||
this.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = activeActions.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);
|
||||
}
|
||||
|
||||
builder.glow(this.activeFilter == filter);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Create common buttons
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create next button panel item.
|
||||
*
|
||||
* @param template the template
|
||||
* @param slot the slot
|
||||
* @return the panel item
|
||||
*/
|
||||
private PanelItem createNextButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot) {
|
||||
long size = this.materialCountList.size();
|
||||
|
||||
if (size <= slot.amountMap().getOrDefault("BLOCK", 1)
|
||||
|| 1.0 * size / slot.amountMap().getOrDefault("BLOCK", 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.TRUE.equals(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(), TextVariables.NUMBER,
|
||||
String.valueOf(nextPageIndex)));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) -> {
|
||||
for (ItemTemplateRecord.ActionRecords action : template.actions()) {
|
||||
if ((clickType == action.clickType() || ClickType.UNKNOWN.equals(action.clickType()))
|
||||
&& "NEXT".equalsIgnoreCase(action.actionType())) {
|
||||
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
|
||||
*/
|
||||
private PanelItem createPreviousButton(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.TRUE.equals(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(), TextVariables.NUMBER,
|
||||
String.valueOf(previousPageIndex)));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) -> {
|
||||
for (ItemTemplateRecord.ActionRecords action : template.actions()) {
|
||||
if ((clickType == action.clickType() || ClickType.UNKNOWN.equals(action.clickType()))
|
||||
&& "PREVIOUS".equalsIgnoreCase(action.actionType())) {
|
||||
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();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Create Material Button
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create material button panel item.
|
||||
*
|
||||
* @param template the template
|
||||
* @param slot the slot
|
||||
* @return the panel item
|
||||
*/
|
||||
private PanelItem createMaterialButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot) {
|
||||
if (this.materialCountList.isEmpty()) {
|
||||
// Does not contain any generators.
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = this.pageIndex * slot.amountMap().getOrDefault("BLOCK", 1) + slot.slot();
|
||||
|
||||
if (index >= this.materialCountList.size()) {
|
||||
// Out of index.
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.createMaterialButton(template, this.materialCountList.get(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates button for material.
|
||||
*
|
||||
* @param template the template of the button
|
||||
* @param materialCount materialCount which button must be created.
|
||||
* @return PanelItem for generator tier.
|
||||
*/
|
||||
private PanelItem createMaterialButton(ItemTemplateRecord template, Pair<Material, Integer> materialCount) {
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null) {
|
||||
builder.icon(template.icon().clone());
|
||||
} else {
|
||||
builder.icon(PanelUtils.getMaterialItem(materialCount.getKey()));
|
||||
}
|
||||
|
||||
if (materialCount.getValue() < 64) {
|
||||
builder.amount(materialCount.getValue());
|
||||
}
|
||||
|
||||
if (template.title() != null) {
|
||||
builder.name(this.user.getTranslation(this.world, template.title(), TextVariables.NUMBER,
|
||||
String.valueOf(materialCount.getValue()), "[material]",
|
||||
Utils.prettifyObject(materialCount.getKey(), this.user)));
|
||||
}
|
||||
|
||||
String description = Utils.prettifyDescription(materialCount.getKey(), this.user);
|
||||
|
||||
final String reference = "level.gui.buttons.material.";
|
||||
String blockId = this.user.getTranslationOrNothing(reference + "id", "[id]", materialCount.getKey().name());
|
||||
|
||||
int blockValue = this.addon.getBlockConfig().getBlockValues().getOrDefault(materialCount.getKey(), 0);
|
||||
String value = blockValue > 0
|
||||
? this.user.getTranslationOrNothing(reference + "value", TextVariables.NUMBER,
|
||||
String.valueOf(blockValue))
|
||||
: "";
|
||||
|
||||
int blockLimit = this.addon.getBlockConfig().getBlockLimits().getOrDefault(materialCount.getKey(), 0);
|
||||
String limit = blockLimit > 0
|
||||
? this.user.getTranslationOrNothing(reference + "limit", TextVariables.NUMBER,
|
||||
String.valueOf(blockLimit))
|
||||
: "";
|
||||
|
||||
String count = this.user.getTranslationOrNothing(reference + "count", TextVariables.NUMBER,
|
||||
String.valueOf(materialCount.getValue()));
|
||||
|
||||
long calculatedValue = (long) Math.min(blockLimit > 0 ? blockLimit : Integer.MAX_VALUE,
|
||||
materialCount.getValue()) * blockValue;
|
||||
String valueText = calculatedValue > 0 ? this.user.getTranslationOrNothing(reference + "calculated",
|
||||
TextVariables.NUMBER, String.valueOf(calculatedValue)) : "";
|
||||
|
||||
if (template.description() != null) {
|
||||
builder.description(this.user
|
||||
.getTranslation(this.world, template.description(), "[description]", description, "[id]", blockId,
|
||||
"[value]", value, "[calculated]", valueText, "[limit]", limit, "[count]", count)
|
||||
.replaceAll("(?m)^[ \\t]*\\r?\\n", "").replaceAll("(?<!\\\\)\\|", "\n").replace("\\\\\\|", "|"));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Other 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 Level object
|
||||
* @param world World where user is operating
|
||||
* @param user User who opens panel
|
||||
*/
|
||||
public static void openPanel(Level addon, World world, User user) {
|
||||
new DetailsPanel(addon, world, user).build();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Enums
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This enum holds possible tabs for current gui.
|
||||
*/
|
||||
private enum Tab {
|
||||
/**
|
||||
* All block Tab
|
||||
*/
|
||||
ALL_BLOCKS,
|
||||
/**
|
||||
* Above Sea level Tab.
|
||||
*/
|
||||
ABOVE_SEA_LEVEL,
|
||||
/**
|
||||
* Underwater Tab.
|
||||
*/
|
||||
UNDERWATER,
|
||||
/**
|
||||
* Spawner Tab.
|
||||
*/
|
||||
SPAWNER
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorting order of blocks.
|
||||
*/
|
||||
private enum Filter {
|
||||
/**
|
||||
* By name
|
||||
*/
|
||||
NAME,
|
||||
/**
|
||||
* By value
|
||||
*/
|
||||
VALUE,
|
||||
/**
|
||||
* By number
|
||||
*/
|
||||
COUNT
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This variable holds targeted island.
|
||||
*/
|
||||
private final Island island;
|
||||
|
||||
/**
|
||||
* This variable holds targeted island level data.
|
||||
*/
|
||||
private final IslandLevels levelsData;
|
||||
|
||||
/**
|
||||
* This variable allows to access addon object.
|
||||
*/
|
||||
private final Level addon;
|
||||
|
||||
/**
|
||||
* This variable holds user who opens panel. Without it panel cannot be opened.
|
||||
*/
|
||||
private final User user;
|
||||
|
||||
/**
|
||||
* This variable holds a world to which gui referee.
|
||||
*/
|
||||
private final World world;
|
||||
|
||||
/**
|
||||
* This variable stores the list of elements to display.
|
||||
*/
|
||||
private final List<Pair<Material, Integer>> materialCountList;
|
||||
|
||||
/**
|
||||
* This variable holds current pageIndex for multi-page generator choosing.
|
||||
*/
|
||||
private int pageIndex;
|
||||
|
||||
/**
|
||||
* This variable stores which tab currently is active.
|
||||
*/
|
||||
private Tab activeTab;
|
||||
|
||||
/**
|
||||
* This variable stores active filter for items.
|
||||
*/
|
||||
private Filter activeFilter;
|
||||
}
|
|
@ -0,0 +1,467 @@
|
|||
///
|
||||
// Created by BONNe
|
||||
// Copyright - 2021
|
||||
///
|
||||
|
||||
package world.bentobox.level.panels;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
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.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.managers.RanksManager;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.util.Utils;
|
||||
|
||||
/**
|
||||
* This panel opens top likes panel
|
||||
*/
|
||||
public class TopLevelPanel {
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Internal Constructor
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This is internal constructor. It is used internally in current class to avoid
|
||||
* creating objects everywhere.
|
||||
*
|
||||
* @param addon Level object.
|
||||
* @param user User who opens Panel.
|
||||
* @param world World where gui is opened
|
||||
* @param permissionPrefix Permission Prefix
|
||||
*/
|
||||
private TopLevelPanel(Level addon, User user, World world, String permissionPrefix) {
|
||||
this.addon = addon;
|
||||
this.user = user;
|
||||
this.world = world;
|
||||
|
||||
this.iconPermission = permissionPrefix + "level.icon";
|
||||
topIslands = new ArrayList<>();
|
||||
for (Map.Entry<String, Long> en : addon.getManager().getTopTen(this.world, Level.TEN).entrySet()) {
|
||||
Optional<Island> is = addon.getIslands().getIslandById(en.getKey());
|
||||
if (is.isPresent()) {
|
||||
topIslands.add(new IslandTopRecord(is.get(), en.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build method manages current panel opening. It uses BentoBox PanelAPI that is
|
||||
* easy to use and users can get nice panels.
|
||||
*/
|
||||
public void build() {
|
||||
TemplatedPanelBuilder panelBuilder = new TemplatedPanelBuilder();
|
||||
|
||||
panelBuilder.user(this.user);
|
||||
panelBuilder.world(this.world);
|
||||
|
||||
panelBuilder.template("top_panel", new File(this.addon.getDataFolder(), "panels"));
|
||||
|
||||
panelBuilder.registerTypeBuilder("VIEW", this::createViewerButton);
|
||||
panelBuilder.registerTypeBuilder("TOP", this::createPlayerButton);
|
||||
|
||||
// Register unknown type builder.
|
||||
panelBuilder.build();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Methods
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates fallback based on template.
|
||||
*
|
||||
* @param template Template record for fallback button.
|
||||
* @param index Place of the fallback.
|
||||
* @return Fallback panel item.
|
||||
*/
|
||||
private PanelItem createFallback(ItemTemplateRecord template, long index) {
|
||||
if (template == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null) {
|
||||
builder.icon(template.icon().clone());
|
||||
}
|
||||
|
||||
if (template.title() != null) {
|
||||
builder.name(
|
||||
this.user.getTranslation(this.world, template.title(), TextVariables.NAME, String.valueOf(index)));
|
||||
} else {
|
||||
builder.name(this.user.getTranslation(this.world, REFERENCE, TextVariables.NAME, String.valueOf(index)));
|
||||
}
|
||||
|
||||
if (template.description() != null) {
|
||||
builder.description(this.user.getTranslation(this.world, template.description(), TextVariables.NUMBER,
|
||||
String.valueOf(index)));
|
||||
}
|
||||
|
||||
builder.amount(index != 0 ? (int) index : 1);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates player icon with warp functionality.
|
||||
*
|
||||
* @return PanelItem for PanelBuilder.
|
||||
*/
|
||||
private PanelItem createPlayerButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot itemSlot) {
|
||||
int index = (int) template.dataMap().getOrDefault("index", 0);
|
||||
|
||||
if (index < 1) {
|
||||
return this.createFallback(template.fallback(), index);
|
||||
}
|
||||
|
||||
IslandTopRecord islandTopRecord = this.topIslands.size() < index ? null : this.topIslands.get(index - 1);
|
||||
|
||||
if (islandTopRecord == null) {
|
||||
return this.createFallback(template.fallback(), index);
|
||||
}
|
||||
|
||||
return this.createIslandIcon(template, islandTopRecord, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates button from template for given island top record.
|
||||
*
|
||||
* @param template Icon Template.
|
||||
* @param islandTopRecord Island Top Record.
|
||||
* @param index Place Index.
|
||||
* @return PanelItem for PanelBuilder.
|
||||
*/
|
||||
private PanelItem createIslandIcon(ItemTemplateRecord template, IslandTopRecord islandTopRecord, int index) {
|
||||
// Get player island.
|
||||
Island island = islandTopRecord.island();
|
||||
|
||||
if (island == null) {
|
||||
return this.createFallback(template.fallback(), index);
|
||||
}
|
||||
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
this.populateIslandIcon(builder, template, island);
|
||||
this.populateIslandTitle(builder, template, island);
|
||||
this.populateIslandDescription(builder, template, island, islandTopRecord, index);
|
||||
|
||||
builder.amount(index);
|
||||
|
||||
// Get only possible actions, by removing all inactive ones.
|
||||
List<ItemTemplateRecord.ActionRecords> activeActions = new ArrayList<>(template.actions());
|
||||
|
||||
activeActions.removeIf(action -> {
|
||||
switch (action.actionType().toUpperCase()) {
|
||||
case "WARP" -> {
|
||||
return island.getOwner() == null || this.addon.getWarpHook() == null
|
||||
|| !this.addon.getWarpHook().getWarpSignsManager().hasWarp(this.world, island.getOwner());
|
||||
}
|
||||
case "VISIT" -> {
|
||||
return island.getOwner() == null || this.addon.getVisitHook() == null
|
||||
|| !this.addon.getVisitHook().getAddonManager().preprocessTeleportation(this.user, island, true);
|
||||
}
|
||||
case "VIEW" -> {
|
||||
return island.getOwner() == null
|
||||
|| !island.getMemberSet(RanksManager.MEMBER_RANK).contains(this.user.getUniqueId());
|
||||
}
|
||||
default -> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Add Click handler
|
||||
builder.clickHandler((panel, user, clickType, i) -> {
|
||||
for (ItemTemplateRecord.ActionRecords action : activeActions) {
|
||||
if (clickType == action.clickType() || action.clickType() == ClickType.UNKNOWN) {
|
||||
switch (action.actionType().toUpperCase()) {
|
||||
case "WARP" -> {
|
||||
this.user.closeInventory();
|
||||
this.addon.getWarpHook().getWarpSignsManager().warpPlayer(this.world, this.user,
|
||||
island.getOwner());
|
||||
}
|
||||
case "VISIT" ->
|
||||
// The command call implementation solves necessity to check for all visits
|
||||
// options,
|
||||
// like cool down, confirmation and preprocess in single go. Would it be better
|
||||
// to write
|
||||
// all logic here?
|
||||
|
||||
this.addon.getPlugin().getIWM().getAddon(this.world).flatMap(GameModeAddon::getPlayerCommand)
|
||||
.ifPresent(command -> {
|
||||
String mainCommand = this.addon.getVisitHook().getSettings().getPlayerMainCommand();
|
||||
|
||||
if (!mainCommand.isBlank()) {
|
||||
this.user.closeInventory();
|
||||
this.user.performCommand(
|
||||
command.getTopLabel() + " " + mainCommand + " " + island.getOwner());
|
||||
}
|
||||
});
|
||||
|
||||
case "VIEW" -> {
|
||||
this.user.closeInventory();
|
||||
// Open Detailed GUI.
|
||||
DetailsPanel.openPanel(this.addon, this.world, this.user);
|
||||
}
|
||||
// Catch default
|
||||
default -> {
|
||||
this.user.closeInventory();
|
||||
addon.logError("Unknown action type " + action.actionType().toUpperCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = activeActions.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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate given panel item builder name with values from template and island
|
||||
* objects.
|
||||
*
|
||||
* @param builder the builder
|
||||
* @param template the template
|
||||
* @param island the island
|
||||
*/
|
||||
private void populateIslandTitle(PanelItemBuilder builder, ItemTemplateRecord template, Island island) {
|
||||
|
||||
// Get Island Name
|
||||
String nameText;
|
||||
|
||||
if (island.getName() == null || island.getName().isEmpty()) {
|
||||
nameText = this.user.getTranslation(REFERENCE + "owners-island", PLAYER,
|
||||
island.getOwner() == null ? this.user.getTranslation(REFERENCE + "unknown")
|
||||
: this.addon.getPlayers().getName(island.getOwner()));
|
||||
} else {
|
||||
nameText = island.getName();
|
||||
}
|
||||
|
||||
// Template specific title is always more important than custom one.
|
||||
if (template.title() != null && !template.title().isBlank()) {
|
||||
builder.name(this.user.getTranslation(this.world, template.title(), TextVariables.NAME, nameText));
|
||||
} else {
|
||||
builder.name(this.user.getTranslation(REFERENCE + "name", TextVariables.NAME, nameText));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate given panel item builder icon with values from template and island
|
||||
* objects.
|
||||
*
|
||||
* @param builder the builder
|
||||
* @param template the template
|
||||
* @param island the island
|
||||
*/
|
||||
private void populateIslandIcon(PanelItemBuilder builder, ItemTemplateRecord template, Island island) {
|
||||
User owner = island.getOwner() == null ? null : User.getInstance(island.getOwner());
|
||||
|
||||
// Get permission or island icon
|
||||
String permissionIcon = owner == null ? null : Utils.getPermissionValue(owner, this.iconPermission, null);
|
||||
|
||||
Material material;
|
||||
|
||||
if (permissionIcon != null && !permissionIcon.equals("*")) {
|
||||
material = Material.matchMaterial(permissionIcon);
|
||||
} else {
|
||||
material = null;
|
||||
}
|
||||
|
||||
if (material != null) {
|
||||
if (!material.equals(Material.PLAYER_HEAD)) {
|
||||
builder.icon(material);
|
||||
} else {
|
||||
builder.icon(owner.getName());
|
||||
}
|
||||
} else if (template.icon() != null) {
|
||||
builder.icon(template.icon().clone());
|
||||
} else if (owner != null) {
|
||||
builder.icon(owner.getName());
|
||||
} else {
|
||||
builder.icon(Material.PLAYER_HEAD);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate given panel item builder description with values from template and
|
||||
* island objects.
|
||||
*
|
||||
* @param builder the builder
|
||||
* @param template the template
|
||||
* @param island the island
|
||||
* @param islandTopRecord the top record object
|
||||
* @param index place index.
|
||||
*/
|
||||
private void populateIslandDescription(PanelItemBuilder builder, ItemTemplateRecord template, Island island,
|
||||
IslandTopRecord islandTopRecord, int index) {
|
||||
// Get Owner Name
|
||||
String ownerText = this.user.getTranslation(REFERENCE + "owner", PLAYER,
|
||||
island.getOwner() == null ? this.user.getTranslation(REFERENCE + "unknown")
|
||||
: this.addon.getPlayers().getName(island.getOwner()));
|
||||
|
||||
// Get Members Text
|
||||
String memberText;
|
||||
|
||||
if (island.getMemberSet().size() > 1) {
|
||||
StringBuilder memberBuilder = new StringBuilder(
|
||||
this.user.getTranslationOrNothing(REFERENCE + "members-title"));
|
||||
|
||||
for (UUID uuid : island.getMemberSet()) {
|
||||
User member = User.getInstance(uuid);
|
||||
|
||||
if (memberBuilder.length() > 0) {
|
||||
memberBuilder.append("\n");
|
||||
}
|
||||
|
||||
memberBuilder.append(this.user.getTranslationOrNothing(REFERENCE + "member", PLAYER, member.getName()));
|
||||
}
|
||||
|
||||
memberText = memberBuilder.toString();
|
||||
} else {
|
||||
memberText = "";
|
||||
}
|
||||
|
||||
String placeText = this.user.getTranslation(REFERENCE + "place", TextVariables.NUMBER, String.valueOf(index));
|
||||
|
||||
String levelText = this.user.getTranslation(REFERENCE + "level", TextVariables.NUMBER,
|
||||
this.addon.getManager().formatLevel(islandTopRecord.level()));
|
||||
|
||||
// Template specific description is always more important than custom one.
|
||||
if (template.description() != null && !template.description().isBlank()) {
|
||||
builder.description(this.user
|
||||
.getTranslation(this.world, template.description(), "[owner]", ownerText, "[members]", memberText,
|
||||
"[level]", levelText, "[place]", placeText)
|
||||
.replaceAll("(?m)^[ \\t]*\\r?\\n", "").replaceAll("(?<!\\\\)\\|", "\n").replace("\\\\\\|", "|")); // Not
|
||||
// a
|
||||
// regex
|
||||
// -
|
||||
// replace
|
||||
// is
|
||||
// more
|
||||
// efficient
|
||||
} else {
|
||||
// Now combine everything.
|
||||
String descriptionText = this.user.getTranslation(REFERENCE + "description", "[owner]", ownerText,
|
||||
"[members]", memberText, "[level]", levelText, "[place]", placeText);
|
||||
|
||||
builder.description(descriptionText.replaceAll("(?m)^[ \\t]*\\r?\\n", "").replaceAll("(?<!\\\\)\\|", "\n")
|
||||
.replace("\\\\\\|", "|")); // Not a regex - replace is more efficient
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create viewer button panel item.
|
||||
*
|
||||
* @return PanelItem for PanelBuilder.
|
||||
*/
|
||||
private PanelItem createViewerButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot itemSlot) {
|
||||
Island island = this.addon.getIslands().getIsland(this.world, this.user);
|
||||
|
||||
if (island == null || island.getOwner() == null) {
|
||||
// Player do not have an island.
|
||||
return null;
|
||||
}
|
||||
|
||||
int place = this.addon.getManager().getRank(this.world, this.user.getUniqueId());
|
||||
long level = this.addon.getIslandLevel(this.world, island.getOwner());
|
||||
|
||||
IslandTopRecord topRecord = new IslandTopRecord(island, level);
|
||||
|
||||
return this.createIslandIcon(template, topRecord, place);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Level Addon object
|
||||
* @param user User who opens panel
|
||||
* @param world World where gui is opened
|
||||
* @param permissionPrefix Permission Prefix
|
||||
*/
|
||||
public static void openPanel(Level addon, User user, World world, String permissionPrefix) {
|
||||
new TopLevelPanel(addon, user, world, permissionPrefix).build();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Constants
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private static final String REFERENCE = "level.gui.buttons.island.";
|
||||
private static final String PLAYER = "[player]";
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Record
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This record is used internally. It converts user -> level to island -> level.
|
||||
*
|
||||
* @param island island
|
||||
* @param level level
|
||||
*/
|
||||
private record IslandTopRecord(Island island, Long level) {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This variable allows to access addon object.
|
||||
*/
|
||||
private final Level addon;
|
||||
|
||||
/**
|
||||
* This variable holds user who opens panel. Without it panel cannot be opened.
|
||||
*/
|
||||
private final User user;
|
||||
|
||||
/**
|
||||
* This variable holds a world to which gui referee.
|
||||
*/
|
||||
private final World world;
|
||||
|
||||
/**
|
||||
* Location to icon permission.
|
||||
*/
|
||||
private final String iconPermission;
|
||||
|
||||
/**
|
||||
* List of top 10 island records.
|
||||
*/
|
||||
private final List<IslandTopRecord> topIslands;
|
||||
}
|
|
@ -0,0 +1,779 @@
|
|||
package world.bentobox.level.panels;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.google.common.base.Enums;
|
||||
|
||||
import lv.id.bonne.panelutils.PanelUtils;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
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.level.Level;
|
||||
import world.bentobox.level.util.ConversationUtils;
|
||||
import world.bentobox.level.util.Utils;
|
||||
|
||||
|
||||
/**
|
||||
* This class opens GUI that shows generator view for user.
|
||||
*/
|
||||
public class ValuePanel
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Internal Constructor
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* This is internal constructor. It is used internally in current class to avoid creating objects everywhere.
|
||||
*
|
||||
* @param addon Level object
|
||||
* @param world World where user is operating
|
||||
* @param user User who opens panel
|
||||
*/
|
||||
private ValuePanel(Level addon,
|
||||
World world,
|
||||
User user)
|
||||
{
|
||||
this.addon = addon;
|
||||
this.world = world;
|
||||
this.user = user;
|
||||
|
||||
this.activeFilter = Filter.NAME_ASC;
|
||||
this.materialRecordList = Arrays.stream(Material.values()).
|
||||
filter(Material::isBlock).
|
||||
filter(m -> !m.name().startsWith("LEGACY_")).
|
||||
map(material ->
|
||||
{
|
||||
Integer value = this.addon.getBlockConfig().getValue(this.world, material);
|
||||
Integer limit = this.addon.getBlockConfig().getBlockLimits().get(material);
|
||||
|
||||
return new MaterialRecord(material,
|
||||
value != null ? value : 0,
|
||||
limit != null ? limit : 0);
|
||||
}).
|
||||
collect(Collectors.toList());
|
||||
|
||||
this.elementList = new ArrayList<>(Material.values().length);
|
||||
this.searchText = "";
|
||||
|
||||
this.updateFilters();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method builds this GUI.
|
||||
*/
|
||||
private void build()
|
||||
{
|
||||
// Start building panel.
|
||||
TemplatedPanelBuilder panelBuilder = new TemplatedPanelBuilder();
|
||||
panelBuilder.user(this.user);
|
||||
panelBuilder.world(this.user.getWorld());
|
||||
|
||||
panelBuilder.template("value_panel", new File(this.addon.getDataFolder(), "panels"));
|
||||
|
||||
panelBuilder.registerTypeBuilder("NEXT", this::createNextButton);
|
||||
panelBuilder.registerTypeBuilder("PREVIOUS", this::createPreviousButton);
|
||||
panelBuilder.registerTypeBuilder(BLOCK, this::createMaterialButton);
|
||||
|
||||
panelBuilder.registerTypeBuilder("FILTER", this::createFilterButton);
|
||||
panelBuilder.registerTypeBuilder("SEARCH", this::createSearchButton);
|
||||
|
||||
// Register unknown type builder.
|
||||
panelBuilder.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method updates filter of elements based on tabs.
|
||||
*/
|
||||
private void updateFilters()
|
||||
{
|
||||
Comparator<MaterialRecord> sorter;
|
||||
|
||||
switch (this.activeFilter)
|
||||
{
|
||||
case VALUE_ASC ->
|
||||
|
||||
sorter = (o1, o2) ->
|
||||
{
|
||||
if (o1.value().equals(o2.value()))
|
||||
{
|
||||
String o1Name = Utils.prettifyObject(o1.material(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.material(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Integer.compare(o1.value(), o2.value());
|
||||
}
|
||||
};
|
||||
|
||||
case VALUE_DESC ->
|
||||
|
||||
sorter = (o1, o2) ->
|
||||
{
|
||||
if (o1.value().equals(o2.value()))
|
||||
{
|
||||
String o1Name = Utils.prettifyObject(o1.material(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.material(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Integer.compare(o2.value(), o1.value());
|
||||
}
|
||||
};
|
||||
|
||||
case NAME_DESC ->
|
||||
|
||||
sorter = (o1, o2) ->
|
||||
{
|
||||
String o1Name = Utils.prettifyObject(o1.material(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.material(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o2Name, o1Name);
|
||||
};
|
||||
|
||||
default ->
|
||||
|
||||
sorter = (o1, o2) ->
|
||||
{
|
||||
String o1Name = Utils.prettifyObject(o1.material(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.material(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
this.materialRecordList.sort(sorter);
|
||||
|
||||
if (!this.searchText.isBlank())
|
||||
{
|
||||
this.elementList = new ArrayList<>(this.materialRecordList.size());
|
||||
final String text = this.searchText.toLowerCase();
|
||||
|
||||
this.materialRecordList.forEach(rec ->
|
||||
{
|
||||
if (rec.material.name().toLowerCase().contains(text) ||
|
||||
Utils.prettifyObject(rec.material(), this.user).toLowerCase().contains(text))
|
||||
{
|
||||
this.elementList.add(rec);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.elementList = this.materialRecordList;
|
||||
}
|
||||
|
||||
this.pageIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Tab Button Type
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Create tab button panel item.
|
||||
*
|
||||
* @param template the template
|
||||
* @param slot the slot
|
||||
* @return the panel item
|
||||
*/
|
||||
private PanelItem createSearchButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
// Set icon
|
||||
builder.icon(template.icon().clone());
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
// Set title
|
||||
builder.name(this.user.getTranslation(this.world, template.title(), "[text]", this.searchText));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
// Set description
|
||||
builder.description(this.user.getTranslation(this.world, template.description(), "[text]", this.searchText));
|
||||
}
|
||||
|
||||
// Get only possible actions, by removing all inactive ones.
|
||||
List<ItemTemplateRecord.ActionRecords> activeActions = new ArrayList<>(template.actions());
|
||||
|
||||
activeActions.removeIf(action ->
|
||||
"CLEAR".equalsIgnoreCase(action.actionType()) && this.searchText.isBlank());
|
||||
|
||||
// Add Click handler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
for (ItemTemplateRecord.ActionRecords action : activeActions)
|
||||
{
|
||||
if (clickType == action.clickType() || ClickType.UNKNOWN.equals(action.clickType()))
|
||||
{
|
||||
if ("CLEAR".equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
this.searchText = "";
|
||||
|
||||
// Update filters.
|
||||
this.updateFilters();
|
||||
this.build();
|
||||
}
|
||||
else if ("INPUT".equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
// Create consumer that process description change
|
||||
Consumer<String> consumer = value ->
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
this.searchText = value;
|
||||
this.updateFilters();
|
||||
}
|
||||
|
||||
this.build();
|
||||
};
|
||||
|
||||
// start conversation
|
||||
ConversationUtils.createStringInput(consumer,
|
||||
user,
|
||||
user.getTranslation("level.conversations.write-search"),
|
||||
user.getTranslation("level.conversations.search-updated"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = activeActions.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);
|
||||
}
|
||||
|
||||
builder.glow(!this.searchText.isBlank());
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create next button panel item.
|
||||
*
|
||||
* @param template the template
|
||||
* @param slot the slot
|
||||
* @return the panel item
|
||||
*/
|
||||
private PanelItem createFilterButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
// Set icon
|
||||
builder.icon(template.icon().clone());
|
||||
}
|
||||
|
||||
String filterName = String.valueOf(template.dataMap().get("filter"));
|
||||
|
||||
final String reference = "level.gui.buttons.filters.";
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
// Set title
|
||||
builder.name(this.user.getTranslation(this.world, template.title()));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.world, reference + filterName.toLowerCase() + ".name"));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
// Set description
|
||||
builder.description(this.user.getTranslation(this.world, template.description()));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.world, reference + filterName.toLowerCase() + ".description"));
|
||||
}
|
||||
|
||||
// Get only possible actions, by removing all inactive ones.
|
||||
List<ItemTemplateRecord.ActionRecords> activeActions = new ArrayList<>(template.actions());
|
||||
|
||||
activeActions.removeIf(action -> {
|
||||
if (this.activeFilter.name().startsWith(filterName))
|
||||
{
|
||||
return this.activeFilter.name().endsWith("ASC") && "ASC".equalsIgnoreCase(action.actionType()) ||
|
||||
this.activeFilter.name().endsWith("DESC") && "DESC".equalsIgnoreCase(action.actionType());
|
||||
}
|
||||
else
|
||||
{
|
||||
return "DESC".equalsIgnoreCase(action.actionType());
|
||||
}
|
||||
});
|
||||
|
||||
// Add Click handler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
for (ItemTemplateRecord.ActionRecords action : activeActions)
|
||||
{
|
||||
if (clickType == action.clickType() || ClickType.UNKNOWN.equals(action.clickType()))
|
||||
{
|
||||
if ("ASC".equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
this.activeFilter = Enums.getIfPresent(Filter.class, filterName + "_ASC").or(Filter.NAME_ASC);
|
||||
|
||||
// Update filters.
|
||||
this.updateFilters();
|
||||
this.build();
|
||||
}
|
||||
else if ("DESC".equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
this.activeFilter = Enums.getIfPresent(Filter.class, filterName + "_DESC").or(Filter.NAME_DESC);
|
||||
|
||||
// Update filters.
|
||||
this.updateFilters();
|
||||
this.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = activeActions.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);
|
||||
}
|
||||
|
||||
builder.glow(this.activeFilter.name().startsWith(filterName.toUpperCase()));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Create common buttons
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Create next button panel item.
|
||||
*
|
||||
* @param template the template
|
||||
* @param slot the slot
|
||||
* @return the panel item
|
||||
*/
|
||||
private PanelItem createNextButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
long size = this.elementList.size();
|
||||
|
||||
if (size <= slot.amountMap().getOrDefault(BLOCK, 1) ||
|
||||
1.0 * size / slot.amountMap().getOrDefault(BLOCK, 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.TRUE.equals(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(),
|
||||
TextVariables.NUMBER, String.valueOf(nextPageIndex)));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
for (ItemTemplateRecord.ActionRecords action : template.actions())
|
||||
{
|
||||
if ((clickType == action.clickType() || ClickType.UNKNOWN.equals(action.clickType()))
|
||||
&& "NEXT".equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
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
|
||||
*/
|
||||
private PanelItem createPreviousButton(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.TRUE.equals(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(),
|
||||
TextVariables.NUMBER, String.valueOf(previousPageIndex)));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
for (ItemTemplateRecord.ActionRecords action : template.actions())
|
||||
{
|
||||
if ((clickType == action.clickType() || ClickType.UNKNOWN.equals(action.clickType()))
|
||||
&& "PREVIOUS".equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Create Material Button
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Create material button panel item.
|
||||
*
|
||||
* @param template the template
|
||||
* @param slot the slot
|
||||
* @return the panel item
|
||||
*/
|
||||
private PanelItem createMaterialButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
if (this.elementList.isEmpty())
|
||||
{
|
||||
// Does not contain any generators.
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = this.pageIndex * slot.amountMap().getOrDefault(BLOCK, 1) + slot.slot();
|
||||
|
||||
if (index >= this.elementList.size())
|
||||
{
|
||||
// Out of index.
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.createMaterialButton(template, this.elementList.get(index));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method creates button for material.
|
||||
*
|
||||
* @param template the template of the button
|
||||
* @param materialRecord materialRecord which button must be created.
|
||||
* @return PanelItem for generator tier.
|
||||
*/
|
||||
private PanelItem createMaterialButton(ItemTemplateRecord template,
|
||||
MaterialRecord materialRecord)
|
||||
{
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
builder.icon(template.icon().clone());
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.icon(PanelUtils.getMaterialItem(materialRecord.material()));
|
||||
}
|
||||
|
||||
if (materialRecord.value() <= 64 && materialRecord.value() > 0)
|
||||
{
|
||||
builder.amount(materialRecord.value());
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.world, template.title(),
|
||||
"[material]", Utils.prettifyObject(materialRecord.material(), this.user)));
|
||||
}
|
||||
|
||||
String description = Utils.prettifyDescription(materialRecord.material(), this.user);
|
||||
|
||||
final String reference = "level.gui.buttons.material.";
|
||||
String blockId = this.user.getTranslationOrNothing(reference + "id",
|
||||
"[id]", materialRecord.material().name());
|
||||
|
||||
String value = this.user.getTranslationOrNothing(reference + "value",
|
||||
TextVariables.NUMBER, String.valueOf(materialRecord.value()));
|
||||
|
||||
String underWater;
|
||||
|
||||
if (this.addon.getSettings().getUnderWaterMultiplier() > 1.0)
|
||||
{
|
||||
underWater = this.user.getTranslationOrNothing(reference + "underwater",
|
||||
TextVariables.NUMBER, String.valueOf(materialRecord.value() * this.addon.getSettings().getUnderWaterMultiplier()));
|
||||
}
|
||||
else
|
||||
{
|
||||
underWater = "";
|
||||
}
|
||||
|
||||
String limit = materialRecord.limit() > 0 ? this.user.getTranslationOrNothing(reference + "limit",
|
||||
TextVariables.NUMBER, String.valueOf(materialRecord.limit())) : "";
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(this.world, template.description(),
|
||||
"[description]", description,
|
||||
"[id]", blockId,
|
||||
"[value]", value,
|
||||
"[underwater]", underWater,
|
||||
"[limit]", limit).
|
||||
replaceAll("(?m)^[ \\t]*\\r?\\n", "").
|
||||
replaceAll("(?<!\\\\)\\|", "\n").
|
||||
replace("\\\\\\|", "|")); // Non regex
|
||||
}
|
||||
|
||||
builder.clickHandler((panel, user1, clickType, i) -> {
|
||||
addon.log("Material: " + materialRecord.material());
|
||||
return true;
|
||||
});
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Other 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 Level object
|
||||
* @param world World where user is operating
|
||||
* @param user User who opens panel
|
||||
*/
|
||||
public static void openPanel(Level addon,
|
||||
World world,
|
||||
User user)
|
||||
{
|
||||
new ValuePanel(addon, world, user).build();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Enums
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Sorting order of blocks.
|
||||
*/
|
||||
private enum Filter
|
||||
{
|
||||
/**
|
||||
* By name asc
|
||||
*/
|
||||
NAME_ASC,
|
||||
/**
|
||||
* By name desc
|
||||
*/
|
||||
NAME_DESC,
|
||||
/**
|
||||
* By value asc
|
||||
*/
|
||||
VALUE_ASC,
|
||||
/**
|
||||
* By value desc
|
||||
*/
|
||||
VALUE_DESC,
|
||||
}
|
||||
|
||||
|
||||
private record MaterialRecord(Material material, Integer value, Integer limit)
|
||||
{
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Constants
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private static final String BLOCK = "BLOCK";
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This variable allows to access addon object.
|
||||
*/
|
||||
private final Level addon;
|
||||
|
||||
/**
|
||||
* This variable holds user who opens panel. Without it panel cannot be opened.
|
||||
*/
|
||||
private final User user;
|
||||
|
||||
/**
|
||||
* This variable holds a world to which gui referee.
|
||||
*/
|
||||
private final World world;
|
||||
|
||||
/**
|
||||
* This variable stores the list of elements to display.
|
||||
*/
|
||||
private final List<MaterialRecord> materialRecordList;
|
||||
|
||||
/**
|
||||
* This variable stores the list of elements to display.
|
||||
*/
|
||||
private List<MaterialRecord> elementList;
|
||||
|
||||
/**
|
||||
* This variable holds current pageIndex for multi-page generator choosing.
|
||||
*/
|
||||
private int pageIndex;
|
||||
|
||||
/**
|
||||
* This variable stores which tab currently is active.
|
||||
*/
|
||||
private String searchText;
|
||||
|
||||
/**
|
||||
* This variable stores active filter for items.
|
||||
*/
|
||||
private Filter activeFilter;
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package world.bentobox.level.placeholders;
|
||||
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class LevelPlaceholder implements PlaceholderReplacer {
|
||||
|
||||
private Level addon;
|
||||
private GameModeAddon gm;
|
||||
|
||||
/**
|
||||
* Provides placeholder support
|
||||
* @param addon - Level addon
|
||||
* @param gm - Game mode
|
||||
*/
|
||||
public LevelPlaceholder(Level addon, GameModeAddon gm) {
|
||||
this.addon = addon;
|
||||
this.gm = gm;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see world.bentobox.bentobox.api.placeholders.PlaceholderReplacer#onReplace(world.bentobox.bentobox.api.user.User)
|
||||
*/
|
||||
@Override
|
||||
public String onReplace(User user) {
|
||||
return String.valueOf(addon.getIslandLevel(gm.getOverWorld(), user.getUniqueId()));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package world.bentobox.level.placeholders;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class TopTenNamePlaceholder implements PlaceholderReplacer {
|
||||
|
||||
private final Level level;
|
||||
private final GameModeAddon gm;
|
||||
private final int i;
|
||||
|
||||
public TopTenNamePlaceholder(Level level, GameModeAddon gm, int i) {
|
||||
this.level = level;
|
||||
this.gm = gm;
|
||||
this.i = i - 1;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see world.bentobox.bentobox.api.placeholders.PlaceholderReplacer#onReplace(world.bentobox.bentobox.api.user.User)
|
||||
*/
|
||||
@Override
|
||||
public String onReplace(User user) {
|
||||
Collection<UUID> values = level.getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().keySet();
|
||||
return values.size() < i ? "" : level.getPlayers().getName(values.stream().skip(i).findFirst().orElse(null));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package world.bentobox.level.placeholders;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
/**
|
||||
* Provides the level values to placeholders
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class TopTenPlaceholder implements PlaceholderReplacer {
|
||||
|
||||
private final Level level;
|
||||
private final GameModeAddon gm;
|
||||
private final int i;
|
||||
|
||||
public TopTenPlaceholder(Level level, GameModeAddon gm, int i) {
|
||||
this.level = level;
|
||||
this.gm = gm;
|
||||
this.i = i - 1;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see world.bentobox.bentobox.api.placeholders.PlaceholderReplacer#onReplace(world.bentobox.bentobox.api.user.User)
|
||||
*/
|
||||
@Override
|
||||
public String onReplace(User user) {
|
||||
Collection<Long> values = level.getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().values();
|
||||
return values.size() < i ? "" : values.stream().skip(i).findFirst().map(String::valueOf).orElse("");
|
||||
}
|
||||
|
||||
}
|
|
@ -10,7 +10,9 @@ import world.bentobox.level.Level;
|
|||
|
||||
public class LevelRequestHandler extends AddonRequestHandler {
|
||||
|
||||
private Level addon;
|
||||
private static final Object WORLD_NAME = "world-name";
|
||||
private static final Object PLAYER = "player";
|
||||
private final Level addon;
|
||||
|
||||
public LevelRequestHandler(Level addon) {
|
||||
super("island-level");
|
||||
|
@ -32,12 +34,12 @@ public class LevelRequestHandler extends AddonRequestHandler {
|
|||
*/
|
||||
|
||||
if (map == null || map.isEmpty()
|
||||
|| map.get("world-name") == null || !(map.get("world-name") instanceof String)
|
||||
|| map.get("player") == null || !(map.get("player") instanceof UUID)
|
||||
|| Bukkit.getWorld((String) map.get("world-name")) == null) {
|
||||
|| map.get(WORLD_NAME) == null || !(map.get(WORLD_NAME) instanceof String)
|
||||
|| map.get(PLAYER) == null || !(map.get(PLAYER) instanceof UUID)
|
||||
|| Bukkit.getWorld((String) map.get(WORLD_NAME)) == null) {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
return addon.getIslandLevel(Bukkit.getWorld((String) map.get("world-name")), (UUID) map.get("player"));
|
||||
return addon.getManager().getIslandLevel(Bukkit.getWorld((String) map.get(WORLD_NAME)), (UUID) map.get(PLAYER));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import org.bukkit.Bukkit;
|
|||
|
||||
import world.bentobox.bentobox.api.addons.request.AddonRequestHandler;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.objects.TopTenData;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -16,26 +15,27 @@ import world.bentobox.level.objects.TopTenData;
|
|||
*/
|
||||
public class TopTenRequestHandler extends AddonRequestHandler {
|
||||
|
||||
/**
|
||||
* The level addon field.
|
||||
*/
|
||||
private Level addon;
|
||||
private static final String WORLD_NAME = "world-name";
|
||||
/**
|
||||
* The level addon field.
|
||||
*/
|
||||
private final Level addon;
|
||||
|
||||
/**
|
||||
* This constructor creates a new TopTenRequestHandler instance.
|
||||
*
|
||||
* @param addon of type Level
|
||||
*/
|
||||
public TopTenRequestHandler(Level addon) {
|
||||
super("top-ten-level");
|
||||
this.addon = addon;
|
||||
}
|
||||
/**
|
||||
* This constructor creates a new TopTenRequestHandler instance.
|
||||
*
|
||||
* @param addon of type Level
|
||||
*/
|
||||
public TopTenRequestHandler(Level addon) {
|
||||
super("top-ten-level");
|
||||
this.addon = addon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AddonRequestHandler#handle(Map<String, Object>)
|
||||
*/
|
||||
@Override
|
||||
public Object handle(Map<String, Object> map) {
|
||||
/**
|
||||
* See {@link AddonRequestHandler#handle(Map)}
|
||||
*/
|
||||
@Override
|
||||
public Object handle(Map<String, Object> map) {
|
||||
/*
|
||||
What we need in the map:
|
||||
|
||||
|
@ -47,14 +47,13 @@ public class TopTenRequestHandler extends AddonRequestHandler {
|
|||
- the map of top ten player UUIDs and their island levels. Can be less then 10.
|
||||
*/
|
||||
|
||||
if (map == null || map.isEmpty()
|
||||
|| map.get("world-name") == null || !(map.get("world-name") instanceof String)
|
||||
|| Bukkit.getWorld((String) map.get("world-name")) == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
if (map == null || map.isEmpty()
|
||||
|| map.get(WORLD_NAME) == null || !(map.get(WORLD_NAME) instanceof String)
|
||||
|| Bukkit.getWorld((String) map.get(WORLD_NAME)) == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// Null-point check.
|
||||
TopTenData data = addon.getTopTen().getTopTenList(Bukkit.getWorld((String) map.get("world-name")));
|
||||
return data != null ? data.getTopTen() : Collections.emptyMap();
|
||||
}
|
||||
// No null check required
|
||||
return addon.getManager().getTopTen(Bukkit.getWorld((String) map.get(WORLD_NAME)), Level.TEN);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package world.bentobox.level.util;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Cache for top tens
|
||||
*/
|
||||
public class CachedData {
|
||||
private Map<String, Long> cachedMap;
|
||||
private Instant lastUpdated;
|
||||
|
||||
public CachedData(Map<String, Long> cachedMap, Instant lastUpdated) {
|
||||
this.cachedMap = cachedMap;
|
||||
this.lastUpdated = lastUpdated;
|
||||
}
|
||||
|
||||
public Map<String, Long> getCachedMap() {
|
||||
return cachedMap;
|
||||
}
|
||||
|
||||
public Instant getLastUpdated() {
|
||||
return lastUpdated;
|
||||
}
|
||||
|
||||
public void updateCache(Map<String, Long> newMap, Instant newUpdateTime) {
|
||||
this.cachedMap = newMap;
|
||||
this.lastUpdated = newUpdateTime;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
//
|
||||
// Created by BONNe
|
||||
// Copyright - 2021
|
||||
//
|
||||
|
||||
|
||||
package world.bentobox.level.util;
|
||||
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.bukkit.conversations.ConversationAbandonedListener;
|
||||
import org.bukkit.conversations.ConversationContext;
|
||||
import org.bukkit.conversations.ConversationFactory;
|
||||
import org.bukkit.conversations.MessagePrompt;
|
||||
import org.bukkit.conversations.Prompt;
|
||||
import org.bukkit.conversations.StringPrompt;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
|
||||
|
||||
public class ConversationUtils
|
||||
{
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Conversation API implementation
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private ConversationUtils() {} // Private constructor as this is a utility class only with static methods
|
||||
|
||||
/**
|
||||
* This method will close opened gui and writes question in chat. After players answers on question in chat, message
|
||||
* will trigger consumer and gui will reopen.
|
||||
*
|
||||
* @param consumer Consumer that accepts player output text.
|
||||
* @param question Message that will be displayed in chat when player triggers conversion.
|
||||
* @param user User who is targeted with current confirmation.
|
||||
*/
|
||||
public static void createStringInput(Consumer<String> consumer,
|
||||
User user,
|
||||
@NonNull String question,
|
||||
@Nullable String successMessage)
|
||||
{
|
||||
// Text input message.
|
||||
StringPrompt stringPrompt = new StringPrompt()
|
||||
{
|
||||
@Override
|
||||
public @NonNull String getPromptText(@NonNull ConversationContext context)
|
||||
{
|
||||
user.closeInventory();
|
||||
return question;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NonNull Prompt acceptInput(@NonNull ConversationContext context, @Nullable String input)
|
||||
{
|
||||
consumer.accept(input);
|
||||
return ConversationUtils.endMessagePrompt(successMessage);
|
||||
}
|
||||
};
|
||||
|
||||
new ConversationFactory(BentoBox.getInstance()).
|
||||
withPrefix(context -> user.getTranslation("level.conversations.prefix")).
|
||||
withFirstPrompt(stringPrompt).
|
||||
// On cancel conversation will be closed.
|
||||
withLocalEcho(false).
|
||||
withTimeout(90).
|
||||
withEscapeSequence(user.getTranslation("level.conversations.cancel-string")).
|
||||
// Use null value in consumer to detect if user has abandoned conversation.
|
||||
addConversationAbandonedListener(ConversationUtils.getAbandonListener(consumer, user)).
|
||||
buildConversation(user.getPlayer()).
|
||||
begin();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is just a simple end message prompt that displays requested message.
|
||||
*
|
||||
* @param message Message that will be displayed.
|
||||
* @return MessagePrompt that displays given message and exists from conversation.
|
||||
*/
|
||||
private static MessagePrompt endMessagePrompt(@Nullable String message)
|
||||
{
|
||||
return new MessagePrompt()
|
||||
{
|
||||
@Override
|
||||
public @NonNull String getPromptText(@NonNull ConversationContext context)
|
||||
{
|
||||
return message == null ? "" : message;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected @Nullable Prompt getNextPrompt(@NonNull ConversationContext context)
|
||||
{
|
||||
return Prompt.END_OF_CONVERSATION;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method creates and returns abandon listener for every conversation.
|
||||
*
|
||||
* @param consumer Consumer which must return null value.
|
||||
* @param user User who was using conversation.
|
||||
* @return ConversationAbandonedListener instance.
|
||||
*/
|
||||
private static ConversationAbandonedListener getAbandonListener(Consumer<?> consumer, User user)
|
||||
{
|
||||
return abandonedEvent ->
|
||||
{
|
||||
if (!abandonedEvent.gracefulExit())
|
||||
{
|
||||
consumer.accept(null);
|
||||
// send cancell message
|
||||
abandonedEvent.getContext().getForWhom().sendRawMessage(
|
||||
user.getTranslation("level.conversations.prefix") +
|
||||
user.getTranslation("level.conversations.cancelled"));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
//
|
||||
// Created by BONNe
|
||||
// Copyright - 2021
|
||||
//
|
||||
|
||||
|
||||
package world.bentobox.level.util;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.hooks.LangUtilsHook;
|
||||
|
||||
|
||||
public class Utils
|
||||
{
|
||||
private static final String LEVEL_MATERIALS = "level.materials.";
|
||||
|
||||
private Utils() {} // Private constructor as this is a utility class only with static methods
|
||||
|
||||
/**
|
||||
* 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( "level.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)).
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method allows to get next value from array list after given value.
|
||||
*
|
||||
* @param values Array that should be searched for given value.
|
||||
* @param currentValue Value which next element should be found.
|
||||
* @param <T> Instance of given object.
|
||||
* @return Next value after currentValue in values array.
|
||||
*/
|
||||
public static <T> T getNextValue(T[] values, T currentValue)
|
||||
{
|
||||
for (int i = 0; i < values.length; i++)
|
||||
{
|
||||
if (values[i].equals(currentValue))
|
||||
{
|
||||
if (i + 1 == values.length)
|
||||
{
|
||||
return values[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return values[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method allows to get previous value from array list after given value.
|
||||
*
|
||||
* @param values Array that should be searched for given value.
|
||||
* @param currentValue Value which previous element should be found.
|
||||
* @param <T> Instance of given object.
|
||||
* @return Previous value before currentValue in values array.
|
||||
*/
|
||||
public static <T> T getPreviousValue(T[] values, T currentValue)
|
||||
{
|
||||
for (int i = 0; i < values.length; i++)
|
||||
{
|
||||
if (values[i].equals(currentValue))
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
return values[i - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
return values[values.length - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prettify Material object for user.
|
||||
* @param object Object that must be pretty.
|
||||
* @param user User who will see the object.
|
||||
* @return Prettified string for Material.
|
||||
*/
|
||||
public static String prettifyObject(Material object, User user)
|
||||
{
|
||||
// Nothing to translate
|
||||
if (object == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
// Find addon structure with:
|
||||
// [addon]:
|
||||
// materials:
|
||||
// [material]:
|
||||
// name: [name]
|
||||
String translation = user.getTranslationOrNothing(LEVEL_MATERIALS + object.name().toLowerCase() + ".name");
|
||||
|
||||
if (!translation.isEmpty())
|
||||
{
|
||||
// We found our translation.
|
||||
return translation;
|
||||
}
|
||||
|
||||
// Find addon structure with:
|
||||
// [addon]:
|
||||
// materials:
|
||||
// [material]: [name]
|
||||
|
||||
translation = user.getTranslationOrNothing(LEVEL_MATERIALS + object.name().toLowerCase());
|
||||
|
||||
if (!translation.isEmpty())
|
||||
{
|
||||
// We found our translation.
|
||||
return translation;
|
||||
}
|
||||
|
||||
// Find general structure with:
|
||||
// materials:
|
||||
// [material]: [name]
|
||||
|
||||
translation = user.getTranslationOrNothing("materials." + object.name().toLowerCase());
|
||||
|
||||
if (!translation.isEmpty())
|
||||
{
|
||||
// We found our translation.
|
||||
return translation;
|
||||
}
|
||||
|
||||
// Use Lang Utils Hook to translate material
|
||||
return LangUtilsHook.getMaterialName(object, user);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prettify Material object description for user.
|
||||
* @param object Object that must be pretty.
|
||||
* @param user User who will see the object.
|
||||
* @return Prettified description string for Material.
|
||||
*/
|
||||
public static String prettifyDescription(Material object, User user)
|
||||
{
|
||||
// Nothing to translate
|
||||
if (object == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
// Find addon structure with:
|
||||
// [addon]:
|
||||
// materials:
|
||||
// [material]:
|
||||
// description: [text]
|
||||
String translation = user.getTranslationOrNothing(LEVEL_MATERIALS + object.name().toLowerCase() + ".description");
|
||||
|
||||
if (!translation.isEmpty())
|
||||
{
|
||||
// We found our translation.
|
||||
return translation;
|
||||
}
|
||||
|
||||
// No text to return.
|
||||
return "";
|
||||
}
|
||||
}
|
|
@ -1,84 +1,39 @@
|
|||
name: Level
|
||||
main: world.bentobox.level.Level
|
||||
version: ${version}
|
||||
|
||||
softdepend: AcidIsland, BSkyBlock
|
||||
version: ${version}${build.number}
|
||||
icon: DIAMOND
|
||||
api-version: 2.4.0
|
||||
|
||||
authors: tastybento
|
||||
|
||||
permissions:
|
||||
bskyblock.intopten:
|
||||
'[gamemode].intopten':
|
||||
description: Player is in the top ten.
|
||||
default: true
|
||||
bskyblock.island.level:
|
||||
'[gamemode].island.level':
|
||||
description: Player can use level command
|
||||
default: true
|
||||
bskyblock.island.top:
|
||||
'[gamemode].island.top':
|
||||
description: Player can use top ten command
|
||||
default: true
|
||||
bskyblock.island.value:
|
||||
'[gamemode].island.value':
|
||||
description: Player can use value command
|
||||
default: true
|
||||
bskyblock.admin.level:
|
||||
'[gamemode].island.level.details.blocks':
|
||||
description: Player see the level details
|
||||
default: true
|
||||
'[gamemode].island.level.details.spawners':
|
||||
description: Player can see the spawners tab in the level details
|
||||
default: false
|
||||
'[gamemode].island.level.details.underwater':
|
||||
description: Player can see the underwater tab in the level details
|
||||
default: false
|
||||
'[gamemode].island.level.details.above-sea-level':
|
||||
description: Player can see the above sea level tab in the level details
|
||||
default: false
|
||||
'[gamemode].admin.level':
|
||||
description: Player can use admin level command
|
||||
default: true
|
||||
bskyblock.admin.topten:
|
||||
default: op
|
||||
'[gamemode].admin.topten':
|
||||
description: Player can use admin top ten command
|
||||
default: true
|
||||
|
||||
acidisland.intopten:
|
||||
description: Player is in the top ten.
|
||||
default: true
|
||||
acidisland.island.level:
|
||||
description: Player can use level command
|
||||
default: true
|
||||
acidisland.island.top:
|
||||
description: Player can use top ten command
|
||||
default: true
|
||||
acidisland.island.value:
|
||||
description: Player can use value command
|
||||
default: true
|
||||
acidisland.admin.level:
|
||||
description: Player can use admin level command
|
||||
default: true
|
||||
acidisland.admin.topten:
|
||||
description: Player can use admin top ten command
|
||||
default: true
|
||||
|
||||
caveblock.intopten:
|
||||
description: Player is in the top ten.
|
||||
default: true
|
||||
caveblock.island.level:
|
||||
description: Player can use level command
|
||||
default: true
|
||||
caveblock.island.top:
|
||||
description: Player can use top ten command
|
||||
default: true
|
||||
caveblock.island.value:
|
||||
description: Player can use value command
|
||||
default: true
|
||||
caveblock.admin.level:
|
||||
description: Player can use admin level command
|
||||
default: true
|
||||
caveblock.admin.topten:
|
||||
description: Player can use admin top ten command
|
||||
default: true
|
||||
|
||||
skygird.intopten:
|
||||
description: Player is in the top ten.
|
||||
default: true
|
||||
skygird.island.level:
|
||||
description: Player can use level command
|
||||
default: true
|
||||
skygird.island.top:
|
||||
description: Player can use top ten command
|
||||
default: true
|
||||
skygird.island.value:
|
||||
description: Player can use value command
|
||||
default: true
|
||||
skygird.admin.level:
|
||||
description: Player can use admin level command
|
||||
default: true
|
||||
skygird.admin.topten:
|
||||
description: Player can use admin top ten command
|
||||
default: true
|
||||
default: op
|
||||
|
|
|
@ -0,0 +1,835 @@
|
|||
# Block Config file for Level add-on Version ${version}
|
||||
#
|
||||
# This file lists the values for various blocks that are used to calculate the
|
||||
# island level.
|
||||
#
|
||||
# This section lists the limits for any particular block. Blocks over this amount
|
||||
# are not counted.
|
||||
# Format:
|
||||
# MATERIAL: limit
|
||||
limits:
|
||||
COBBLESTONE: 10000
|
||||
NETHERRACK: 1000
|
||||
blocks:
|
||||
ACACIA_BUTTON: 1
|
||||
ACACIA_DOOR: 2
|
||||
ACACIA_FENCE: 2
|
||||
ACACIA_FENCE_GATE: 4
|
||||
ACACIA_LEAVES: 0
|
||||
ACACIA_LOG: 0
|
||||
ACACIA_PLANKS: 1
|
||||
ACACIA_PRESSURE_PLATE: 2
|
||||
ACACIA_SAPLING: 1
|
||||
ACACIA_SIGN: 6
|
||||
ACACIA_SLAB: 1
|
||||
ACACIA_STAIRS: 2
|
||||
ACACIA_TRAPDOOR: 3
|
||||
ACACIA_WALL_SIGN: 6
|
||||
ACACIA_WOOD: 1
|
||||
ACTIVATOR_RAIL: 1
|
||||
AIR: 0
|
||||
ALLIUM: 1
|
||||
ANCIENT_DEBRIS: 10
|
||||
ANDESITE: 1
|
||||
ANDESITE_SLAB: 1
|
||||
ANDESITE_STAIRS: 1
|
||||
ANDESITE_WALL: 1
|
||||
ANVIL: 10
|
||||
ATTACHED_MELON_STEM: 1
|
||||
ATTACHED_PUMPKIN_STEM: 1
|
||||
AZURE_BLUET: 1
|
||||
BAMBOO: 1
|
||||
BAMBOO_SAPLING: 1
|
||||
BARREL: 2
|
||||
BARRIER: 0
|
||||
BASALT: 1
|
||||
BEDROCK: 0
|
||||
BEETROOTS: 1
|
||||
BELL: 100
|
||||
BIRCH_BUTTON: 1
|
||||
BIRCH_DOOR: 2
|
||||
BIRCH_FENCE: 2
|
||||
BIRCH_FENCE_GATE: 4
|
||||
BIRCH_LEAVES: 0
|
||||
BIRCH_LOG: 0
|
||||
BIRCH_PLANKS: 1
|
||||
BIRCH_PRESSURE_PLATE: 2
|
||||
BIRCH_SAPLING: 1
|
||||
BIRCH_SIGN: 6
|
||||
BIRCH_SLAB: 1
|
||||
BIRCH_STAIRS: 2
|
||||
BIRCH_TRAPDOOR: 3
|
||||
BIRCH_WALL_SIGN: 6
|
||||
BIRCH_WOOD: 1
|
||||
BLACK_BANNER: 2
|
||||
BLACK_BED: 6
|
||||
BLACK_CARPET: 1
|
||||
BLACK_CONCRETE: 3
|
||||
BLACK_CONCRETE_POWDER: 2
|
||||
BLACK_GLAZED_TERRACOTTA: 5
|
||||
BLACK_SHULKER_BOX: 11
|
||||
BLACK_STAINED_GLASS: 2
|
||||
BLACK_STAINED_GLASS_PANE: 1
|
||||
BLACK_TERRACOTTA: 2
|
||||
BLACK_WALL_BANNER: 2
|
||||
BLACK_WOOL: 2
|
||||
BLACKSTONE: 1
|
||||
BLACKSTONE_SLAB: 1
|
||||
BLACKSTONE_STAIRS: 2
|
||||
BLACKSTONE_WALL: 1
|
||||
BLAST_FURNACE: 150
|
||||
BLUE_BANNER: 2
|
||||
BLUE_BED: 6
|
||||
BLUE_CARPET: 1
|
||||
BLUE_CONCRETE: 3
|
||||
BLUE_CONCRETE_POWDER: 2
|
||||
BLUE_GLAZED_TERRACOTTA: 5
|
||||
BLUE_ICE: 1
|
||||
BLUE_ORCHID: 1
|
||||
BLUE_SHULKER_BOX: 11
|
||||
BLUE_STAINED_GLASS: 2
|
||||
BLUE_STAINED_GLASS_PANE: 1
|
||||
BLUE_TERRACOTTA: 2
|
||||
BLUE_WALL_BANNER: 2
|
||||
BLUE_WOOL: 2
|
||||
BONE_BLOCK: 1
|
||||
BOOKSHELF: 5
|
||||
BRAIN_CORAL: 1
|
||||
BRAIN_CORAL_BLOCK: 1
|
||||
BRAIN_CORAL_FAN: 1
|
||||
BRAIN_CORAL_WALL_FAN: 1
|
||||
BREWING_STAND: 20
|
||||
BRICK_SLAB: 3
|
||||
BRICK_STAIRS: 5
|
||||
BRICK_WALL: 5
|
||||
BRICKS: 5
|
||||
BROWN_BANNER: 2
|
||||
BROWN_BED: 6
|
||||
BROWN_CARPET: 1
|
||||
BROWN_CONCRETE: 3
|
||||
BROWN_CONCRETE_POWDER: 2
|
||||
BROWN_GLAZED_TERRACOTTA: 5
|
||||
BROWN_MUSHROOM: 1
|
||||
BROWN_MUSHROOM_BLOCK: 1
|
||||
BROWN_SHULKER_BOX: 11
|
||||
BROWN_STAINED_GLASS: 2
|
||||
BROWN_STAINED_GLASS_PANE: 1
|
||||
BROWN_TERRACOTTA: 2
|
||||
BROWN_WALL_BANNER: 2
|
||||
BROWN_WOOL: 2
|
||||
BUBBLE_COLUMN: 1
|
||||
BUBBLE_CORAL: 1
|
||||
BUBBLE_CORAL_BLOCK: 1
|
||||
BUBBLE_CORAL_FAN: 1
|
||||
BUBBLE_CORAL_WALL_FAN: 1
|
||||
CACTUS: 1
|
||||
CAKE: 9
|
||||
CAMPFIRE: 5
|
||||
CARROTS: 1
|
||||
CARTOGRAPHY_TABLE: 6
|
||||
CARVED_PUMPKIN: 2
|
||||
CAULDRON: 10
|
||||
CAVE_AIR: 0
|
||||
CHAIN: 2
|
||||
CHAIN_COMMAND_BLOCK: 0
|
||||
CHEST: 8
|
||||
CHIPPED_ANVIL: 9
|
||||
CHISELED_NETHER_BRICKS: 2
|
||||
CHISELED_POLISHED_BLACKSTONE: 2
|
||||
CHISELED_QUARTZ_BLOCK: 2
|
||||
CHISELED_RED_SANDSTONE: 2
|
||||
CHISELED_SANDSTONE: 2
|
||||
CHISELED_STONE_BRICKS: 2
|
||||
CHORUS_FLOWER: 1
|
||||
CHORUS_PLANT: 1
|
||||
CLAY: 2
|
||||
COAL_BLOCK: 9
|
||||
COAL_ORE: 1
|
||||
COARSE_DIRT: 2
|
||||
COBBLESTONE: 1
|
||||
COBBLESTONE_SLAB: 1
|
||||
COBBLESTONE_STAIRS: 2
|
||||
COBBLESTONE_WALL: 1
|
||||
COBWEB: 10
|
||||
COCOA: 1
|
||||
COMMAND_BLOCK: 0
|
||||
COMPARATOR: 10
|
||||
COMPOSTER: 9
|
||||
CONDUIT: 1
|
||||
CORNFLOWER: 1
|
||||
CRACKED_NETHER_BRICKS: 1
|
||||
CRACKED_POLISHED_BLACKSTONE_BRICKS: 1
|
||||
CRACKED_STONE_BRICKS: 2
|
||||
CRAFTING_TABLE: 1
|
||||
CREEPER_HEAD: 1
|
||||
CREEPER_WALL_HEAD: 1
|
||||
CRIMSON_BUTTON: 1
|
||||
CRIMSON_DOOR: 2
|
||||
CRIMSON_FENCE: 2
|
||||
CRIMSON_FENCE_GATE: 4
|
||||
CRIMSON_FUNGUS: 1
|
||||
CRIMSON_HYPHAE: 1
|
||||
CRIMSON_NYLIUM: 1
|
||||
CRIMSON_PLANKS: 1
|
||||
CRIMSON_PRESSURE_PLATE: 2
|
||||
CRIMSON_ROOTS: 1
|
||||
CRIMSON_SIGN: 6
|
||||
CRIMSON_SLAB: 1
|
||||
CRIMSON_STAIRS: 2
|
||||
CRIMSON_STEM: 1
|
||||
CRIMSON_TRAPDOOR: 3
|
||||
CRIMSON_WALL_SIGN: 6
|
||||
CRYING_OBSIDIAN: 15
|
||||
CUT_RED_SANDSTONE: 1
|
||||
CUT_RED_SANDSTONE_SLAB: 1
|
||||
CUT_SANDSTONE: 1
|
||||
CUT_SANDSTONE_SLAB: 1
|
||||
CYAN_BANNER: 2
|
||||
CYAN_BED: 6
|
||||
CYAN_CARPET: 1
|
||||
CYAN_CONCRETE: 3
|
||||
CYAN_CONCRETE_POWDER: 2
|
||||
CYAN_GLAZED_TERRACOTTA: 5
|
||||
CYAN_SHULKER_BOX: 11
|
||||
CYAN_STAINED_GLASS: 2
|
||||
CYAN_STAINED_GLASS_PANE: 1
|
||||
CYAN_TERRACOTTA: 2
|
||||
CYAN_WALL_BANNER: 2
|
||||
CYAN_WOOL: 2
|
||||
DAMAGED_ANVIL: 5
|
||||
DANDELION: 1
|
||||
DARK_OAK_BUTTON: 1
|
||||
DARK_OAK_DOOR: 2
|
||||
DARK_OAK_FENCE: 2
|
||||
DARK_OAK_FENCE_GATE: 4
|
||||
DARK_OAK_LEAVES: 0
|
||||
DARK_OAK_LOG: 0
|
||||
DARK_OAK_PLANKS: 1
|
||||
DARK_OAK_PRESSURE_PLATE: 2
|
||||
DARK_OAK_SAPLING: 1
|
||||
DARK_OAK_SIGN: 6
|
||||
DARK_OAK_SLAB: 1
|
||||
DARK_OAK_STAIRS: 2
|
||||
DARK_OAK_TRAPDOOR: 3
|
||||
DARK_OAK_WALL_SIGN: 6
|
||||
DARK_OAK_WOOD: 1
|
||||
DARK_PRISMARINE: 1
|
||||
DARK_PRISMARINE_SLAB: 1
|
||||
DARK_PRISMARINE_STAIRS: 2
|
||||
DAYLIGHT_DETECTOR: 10
|
||||
DEAD_BRAIN_CORAL: 1
|
||||
DEAD_BRAIN_CORAL_BLOCK: 1
|
||||
DEAD_BRAIN_CORAL_FAN: 1
|
||||
DEAD_BRAIN_CORAL_WALL_FAN: 1
|
||||
DEAD_BUBBLE_CORAL: 1
|
||||
DEAD_BUBBLE_CORAL_BLOCK: 1
|
||||
DEAD_BUBBLE_CORAL_FAN: 1
|
||||
DEAD_BUBBLE_CORAL_WALL_FAN: 1
|
||||
DEAD_BUSH: 1
|
||||
DEAD_FIRE_CORAL: 1
|
||||
DEAD_FIRE_CORAL_BLOCK: 1
|
||||
DEAD_FIRE_CORAL_FAN: 1
|
||||
DEAD_FIRE_CORAL_WALL_FAN: 1
|
||||
DEAD_HORN_CORAL: 1
|
||||
DEAD_HORN_CORAL_BLOCK: 1
|
||||
DEAD_HORN_CORAL_FAN: 1
|
||||
DEAD_HORN_CORAL_WALL_FAN: 1
|
||||
DEAD_TUBE_CORAL: 1
|
||||
DEAD_TUBE_CORAL_BLOCK: 1
|
||||
DEAD_TUBE_CORAL_FAN: 1
|
||||
DEAD_TUBE_CORAL_WALL_FAN: 1
|
||||
DETECTOR_RAIL: 10
|
||||
DIAMOND_BLOCK: 300
|
||||
DIAMOND_ORE: 1
|
||||
DIORITE: 1
|
||||
DIORITE_SLAB: 1
|
||||
DIORITE_STAIRS: 1
|
||||
DIORITE_WALL: 1
|
||||
DIRT: 3
|
||||
DIRT_PATH: 4
|
||||
DISPENSER: 5
|
||||
DRAGON_EGG: 150
|
||||
DRAGON_HEAD: 1
|
||||
DRAGON_WALL_HEAD: 1
|
||||
DRIED_KELP_BLOCK: 1
|
||||
DROPPER: 5
|
||||
EMERALD_BLOCK: 150
|
||||
EMERALD_ORE: 1
|
||||
ENCHANTING_TABLE: 150
|
||||
END_GATEWAY: 0
|
||||
END_PORTAL: 0
|
||||
END_PORTAL_FRAME: 0
|
||||
END_ROD: 1
|
||||
END_STONE: 1
|
||||
END_STONE_BRICK_SLAB: 2
|
||||
END_STONE_BRICK_STAIRS: 2
|
||||
END_STONE_BRICK_WALL: 2
|
||||
END_STONE_BRICKS: 2
|
||||
ENDER_CHEST: 150
|
||||
FARMLAND: 1
|
||||
FERN: 1
|
||||
FIRE: 0
|
||||
FIRE_CORAL: 1
|
||||
FIRE_CORAL_BLOCK: 1
|
||||
FIRE_CORAL_FAN: 1
|
||||
FIRE_CORAL_WALL_FAN: 1
|
||||
FLETCHING_TABLE: 8
|
||||
FLOWER_POT: 1
|
||||
FROSTED_ICE: 1
|
||||
FURNACE: 8
|
||||
GILDED_BLACKSTONE: 1
|
||||
GLASS: 2
|
||||
GLASS_PANE: 1
|
||||
GLOWSTONE: 1
|
||||
GOLD_BLOCK: 150
|
||||
GOLD_ORE: 1
|
||||
GRANITE: 1
|
||||
GRANITE_SLAB: 1
|
||||
GRANITE_STAIRS: 1
|
||||
GRANITE_WALL: 1
|
||||
SHORT_GRASS: 4
|
||||
GRASS_BLOCK: 4
|
||||
GRAVEL: 1
|
||||
GRAY_BANNER: 2
|
||||
GRAY_BED: 6
|
||||
GRAY_CARPET: 1
|
||||
GRAY_CONCRETE: 3
|
||||
GRAY_CONCRETE_POWDER: 2
|
||||
GRAY_GLAZED_TERRACOTTA: 5
|
||||
GRAY_SHULKER_BOX: 11
|
||||
GRAY_STAINED_GLASS: 2
|
||||
GRAY_STAINED_GLASS_PANE: 1
|
||||
GRAY_TERRACOTTA: 2
|
||||
GRAY_WALL_BANNER: 2
|
||||
GRAY_WOOL: 2
|
||||
GREEN_BANNER: 2
|
||||
GREEN_BED: 6
|
||||
GREEN_CARPET: 1
|
||||
GREEN_CONCRETE: 3
|
||||
GREEN_CONCRETE_POWDER: 2
|
||||
GREEN_GLAZED_TERRACOTTA: 5
|
||||
GREEN_SHULKER_BOX: 11
|
||||
GREEN_STAINED_GLASS: 2
|
||||
GREEN_STAINED_GLASS_PANE: 1
|
||||
GREEN_TERRACOTTA: 2
|
||||
GREEN_WALL_BANNER: 2
|
||||
GREEN_WOOL: 2
|
||||
GRINDSTONE: 8
|
||||
HAY_BLOCK: 2
|
||||
HEAVY_WEIGHTED_PRESSURE_PLATE: 2
|
||||
HONEY_BLOCK: 1
|
||||
HONEYCOMB_BLOCK: 1
|
||||
HOPPER: -10
|
||||
HORN_CORAL: 1
|
||||
HORN_CORAL_BLOCK: 1
|
||||
HORN_CORAL_FAN: 1
|
||||
HORN_CORAL_WALL_FAN: 1
|
||||
ICE: 5
|
||||
INFESTED_CHISELED_STONE_BRICKS: 2
|
||||
INFESTED_COBBLESTONE: 1
|
||||
INFESTED_CRACKED_STONE_BRICKS: 2
|
||||
INFESTED_MOSSY_STONE_BRICKS: 2
|
||||
INFESTED_STONE: 1
|
||||
INFESTED_STONE_BRICKS: 2
|
||||
IRON_BARS: 2
|
||||
IRON_BLOCK: 10
|
||||
IRON_DOOR: 5
|
||||
IRON_ORE: 1
|
||||
IRON_TRAPDOOR: 4
|
||||
JACK_O_LANTERN: 2
|
||||
JIGSAW: 1
|
||||
JUKEBOX: 10
|
||||
JUNGLE_BUTTON: 1
|
||||
JUNGLE_DOOR: 2
|
||||
JUNGLE_FENCE: 2
|
||||
JUNGLE_FENCE_GATE: 4
|
||||
JUNGLE_LEAVES: 0
|
||||
JUNGLE_LOG: 0
|
||||
JUNGLE_PLANKS: 1
|
||||
JUNGLE_PRESSURE_PLATE: 2
|
||||
JUNGLE_SAPLING: 1
|
||||
JUNGLE_SIGN: 6
|
||||
JUNGLE_SLAB: 1
|
||||
JUNGLE_STAIRS: 2
|
||||
JUNGLE_TRAPDOOR: 3
|
||||
JUNGLE_WALL_SIGN: 6
|
||||
JUNGLE_WOOD: 1
|
||||
KELP: 1
|
||||
KELP_PLANT: 1
|
||||
LADDER: 2
|
||||
LANTERN: 3
|
||||
LAPIS_BLOCK: 10
|
||||
LAPIS_ORE: 1
|
||||
LARGE_FERN: 1
|
||||
LAVA: 0
|
||||
LECTERN: 8
|
||||
LEVER: 1
|
||||
LIGHT_BLUE_BANNER: 2
|
||||
LIGHT_BLUE_BED: 6
|
||||
LIGHT_BLUE_CARPET: 1
|
||||
LIGHT_BLUE_CONCRETE: 3
|
||||
LIGHT_BLUE_CONCRETE_POWDER: 2
|
||||
LIGHT_BLUE_GLAZED_TERRACOTTA: 5
|
||||
LIGHT_BLUE_SHULKER_BOX: 11
|
||||
LIGHT_BLUE_STAINED_GLASS: 2
|
||||
LIGHT_BLUE_STAINED_GLASS_PANE: 1
|
||||
LIGHT_BLUE_TERRACOTTA: 2
|
||||
LIGHT_BLUE_WALL_BANNER: 2
|
||||
LIGHT_BLUE_WOOL: 2
|
||||
LIGHT_GRAY_BANNER: 2
|
||||
LIGHT_GRAY_BED: 6
|
||||
LIGHT_GRAY_CARPET: 1
|
||||
LIGHT_GRAY_CONCRETE: 3
|
||||
LIGHT_GRAY_CONCRETE_POWDER: 2
|
||||
LIGHT_GRAY_GLAZED_TERRACOTTA: 5
|
||||
LIGHT_GRAY_SHULKER_BOX: 11
|
||||
LIGHT_GRAY_STAINED_GLASS: 2
|
||||
LIGHT_GRAY_STAINED_GLASS_PANE: 1
|
||||
LIGHT_GRAY_TERRACOTTA: 2
|
||||
LIGHT_GRAY_WALL_BANNER: 2
|
||||
LIGHT_GRAY_WOOL: 2
|
||||
LIGHT_WEIGHTED_PRESSURE_PLATE: 3
|
||||
LILAC: 1
|
||||
LILY_OF_THE_VALLEY: 1
|
||||
LILY_PAD: 5
|
||||
LIME_BANNER: 2
|
||||
LIME_BED: 6
|
||||
LIME_CARPET: 1
|
||||
LIME_CONCRETE: 3
|
||||
LIME_CONCRETE_POWDER: 2
|
||||
LIME_GLAZED_TERRACOTTA: 5
|
||||
LIME_SHULKER_BOX: 11
|
||||
LIME_STAINED_GLASS: 2
|
||||
LIME_STAINED_GLASS_PANE: 1
|
||||
LIME_TERRACOTTA: 2
|
||||
LIME_WALL_BANNER: 2
|
||||
LIME_WOOL: 2
|
||||
LODESTONE: 10
|
||||
LOOM: 5
|
||||
MAGENTA_BANNER: 2
|
||||
MAGENTA_BED: 6
|
||||
MAGENTA_CARPET: 1
|
||||
MAGENTA_CONCRETE: 3
|
||||
MAGENTA_CONCRETE_POWDER: 2
|
||||
MAGENTA_GLAZED_TERRACOTTA: 5
|
||||
MAGENTA_SHULKER_BOX: 11
|
||||
MAGENTA_STAINED_GLASS: 2
|
||||
MAGENTA_STAINED_GLASS_PANE: 1
|
||||
MAGENTA_TERRACOTTA: 2
|
||||
MAGENTA_WALL_BANNER: 2
|
||||
MAGENTA_WOOL: 2
|
||||
MAGMA_BLOCK: 1
|
||||
MELON: 1
|
||||
MELON_STEM: 1
|
||||
MOSSY_COBBLESTONE: 1
|
||||
MOSSY_COBBLESTONE_SLAB: 1
|
||||
MOSSY_COBBLESTONE_STAIRS: 1
|
||||
MOSSY_COBBLESTONE_WALL: 1
|
||||
MOSSY_STONE_BRICK_SLAB: 2
|
||||
MOSSY_STONE_BRICK_STAIRS: 2
|
||||
MOSSY_STONE_BRICK_WALL: 2
|
||||
MOSSY_STONE_BRICKS: 2
|
||||
MOVING_PISTON: 1
|
||||
MUSHROOM_STEM: 1
|
||||
MYCELIUM: 5
|
||||
NETHER_BRICK_FENCE: 2
|
||||
NETHER_BRICK_SLAB: 1
|
||||
NETHER_BRICK_STAIRS: 2
|
||||
NETHER_BRICK_WALL: 2
|
||||
NETHER_BRICKS: 2
|
||||
NETHER_GOLD_ORE: 1
|
||||
NETHER_PORTAL: 1
|
||||
NETHER_QUARTZ_ORE: 1
|
||||
NETHER_SPROUTS: 1
|
||||
NETHER_WART: 1
|
||||
NETHER_WART_BLOCK: 2
|
||||
NETHERITE_BLOCK: 1
|
||||
NETHERRACK: 1
|
||||
NOTE_BLOCK: 10
|
||||
OAK_BUTTON: 1
|
||||
OAK_DOOR: 2
|
||||
OAK_FENCE: 2
|
||||
OAK_FENCE_GATE: 4
|
||||
OAK_LEAVES: 0
|
||||
OAK_LOG: 0
|
||||
OAK_PLANKS: 1
|
||||
OAK_PRESSURE_PLATE: 2
|
||||
OAK_SAPLING: 1
|
||||
OAK_SIGN: 6
|
||||
OAK_SLAB: 1
|
||||
OAK_STAIRS: 2
|
||||
OAK_TRAPDOOR: 3
|
||||
OAK_WALL_SIGN: 6
|
||||
OAK_WOOD: 1
|
||||
OBSERVER: 1
|
||||
OBSIDIAN: 10
|
||||
ORANGE_BANNER: 2
|
||||
ORANGE_BED: 6
|
||||
ORANGE_CARPET: 1
|
||||
ORANGE_CONCRETE: 3
|
||||
ORANGE_CONCRETE_POWDER: 2
|
||||
ORANGE_GLAZED_TERRACOTTA: 5
|
||||
ORANGE_SHULKER_BOX: 11
|
||||
ORANGE_STAINED_GLASS: 2
|
||||
ORANGE_STAINED_GLASS_PANE: 1
|
||||
ORANGE_TERRACOTTA: 2
|
||||
ORANGE_TULIP: 1
|
||||
ORANGE_WALL_BANNER: 2
|
||||
ORANGE_WOOL: 2
|
||||
OXEYE_DAISY: 1
|
||||
PACKED_ICE: 5
|
||||
PEONY: 1
|
||||
PETRIFIED_OAK_SLAB: 1
|
||||
PINK_BANNER: 2
|
||||
PINK_BED: 6
|
||||
PINK_CARPET: 1
|
||||
PINK_CONCRETE: 3
|
||||
PINK_CONCRETE_POWDER: 2
|
||||
PINK_GLAZED_TERRACOTTA: 5
|
||||
PINK_SHULKER_BOX: 11
|
||||
PINK_STAINED_GLASS: 2
|
||||
PINK_STAINED_GLASS_PANE: 1
|
||||
PINK_TERRACOTTA: 2
|
||||
PINK_TULIP: 1
|
||||
PINK_WALL_BANNER: 2
|
||||
PINK_WOOL: 2
|
||||
PISTON: 2
|
||||
PISTON_HEAD: 1
|
||||
PLAYER_HEAD: 1
|
||||
PLAYER_WALL_HEAD: 1
|
||||
PODZOL: 2
|
||||
POLISHED_ANDESITE: 1
|
||||
POLISHED_ANDESITE_SLAB: 1
|
||||
POLISHED_ANDESITE_STAIRS: 1
|
||||
POLISHED_BASALT: 1
|
||||
POLISHED_BLACKSTONE: 1
|
||||
POLISHED_BLACKSTONE_BRICK_SLAB: 2
|
||||
POLISHED_BLACKSTONE_BRICK_STAIRS: 2
|
||||
POLISHED_BLACKSTONE_BRICK_WALL: 2
|
||||
POLISHED_BLACKSTONE_BRICKS: 2
|
||||
POLISHED_BLACKSTONE_BUTTON: 1
|
||||
POLISHED_BLACKSTONE_PRESSURE_PLATE: 2
|
||||
POLISHED_BLACKSTONE_SLAB: 1
|
||||
POLISHED_BLACKSTONE_STAIRS: 2
|
||||
POLISHED_BLACKSTONE_WALL: 1
|
||||
POLISHED_DIORITE: 1
|
||||
POLISHED_DIORITE_SLAB: 1
|
||||
POLISHED_DIORITE_STAIRS: 1
|
||||
POLISHED_GRANITE: 1
|
||||
POLISHED_GRANITE_SLAB: 1
|
||||
POLISHED_GRANITE_STAIRS: 1
|
||||
POPPY: 1
|
||||
POTATOES: 1
|
||||
POTTED_ACACIA_SAPLING: 1
|
||||
POTTED_ALLIUM: 1
|
||||
POTTED_AZURE_BLUET: 1
|
||||
POTTED_BAMBOO: 1
|
||||
POTTED_BIRCH_SAPLING: 1
|
||||
POTTED_BLUE_ORCHID: 1
|
||||
POTTED_BROWN_MUSHROOM: 1
|
||||
POTTED_CACTUS: 1
|
||||
POTTED_CORNFLOWER: 1
|
||||
POTTED_CRIMSON_FUNGUS: 1
|
||||
POTTED_CRIMSON_ROOTS: 1
|
||||
POTTED_DANDELION: 1
|
||||
POTTED_DARK_OAK_SAPLING: 1
|
||||
POTTED_DEAD_BUSH: 1
|
||||
POTTED_FERN: 1
|
||||
POTTED_JUNGLE_SAPLING: 1
|
||||
POTTED_LILY_OF_THE_VALLEY: 1
|
||||
POTTED_OAK_SAPLING: 1
|
||||
POTTED_ORANGE_TULIP: 1
|
||||
POTTED_OXEYE_DAISY: 1
|
||||
POTTED_PINK_TULIP: 1
|
||||
POTTED_POPPY: 1
|
||||
POTTED_RED_MUSHROOM: 1
|
||||
POTTED_RED_TULIP: 1
|
||||
POTTED_SPRUCE_SAPLING: 1
|
||||
POTTED_WARPED_FUNGUS: 1
|
||||
POTTED_WARPED_ROOTS: 1
|
||||
POTTED_WHITE_TULIP: 1
|
||||
POTTED_WITHER_ROSE: 1
|
||||
POWERED_RAIL: 2
|
||||
PRISMARINE: 1
|
||||
PRISMARINE_BRICK_SLAB: 1
|
||||
PRISMARINE_BRICK_STAIRS: 2
|
||||
PRISMARINE_BRICKS: 2
|
||||
PRISMARINE_SLAB: 1
|
||||
PRISMARINE_STAIRS: 2
|
||||
PRISMARINE_WALL: 2
|
||||
PUMPKIN: 1
|
||||
PUMPKIN_STEM: 1
|
||||
PURPLE_BANNER: 2
|
||||
PURPLE_BED: 6
|
||||
PURPLE_CARPET: 1
|
||||
PURPLE_CONCRETE: 3
|
||||
PURPLE_CONCRETE_POWDER: 2
|
||||
PURPLE_GLAZED_TERRACOTTA: 5
|
||||
PURPLE_SHULKER_BOX: 11
|
||||
PURPLE_STAINED_GLASS: 2
|
||||
PURPLE_STAINED_GLASS_PANE: 1
|
||||
PURPLE_TERRACOTTA: 2
|
||||
PURPLE_WALL_BANNER: 2
|
||||
PURPLE_WOOL: 2
|
||||
PURPUR_BLOCK: 1
|
||||
PURPUR_PILLAR: 1
|
||||
PURPUR_SLAB: 1
|
||||
PURPUR_STAIRS: 2
|
||||
QUARTZ_BLOCK: 1
|
||||
QUARTZ_BRICKS: 2
|
||||
QUARTZ_PILLAR: 1
|
||||
QUARTZ_SLAB: 1
|
||||
QUARTZ_STAIRS: 2
|
||||
RAIL: 1
|
||||
RED_BANNER: 2
|
||||
RED_BED: 6
|
||||
RED_CARPET: 1
|
||||
RED_CONCRETE: 3
|
||||
RED_CONCRETE_POWDER: 2
|
||||
RED_GLAZED_TERRACOTTA: 5
|
||||
RED_MUSHROOM: 1
|
||||
RED_MUSHROOM_BLOCK: 1
|
||||
RED_NETHER_BRICK_SLAB: 2
|
||||
RED_NETHER_BRICK_STAIRS: 2
|
||||
RED_NETHER_BRICK_WALL: 2
|
||||
RED_NETHER_BRICKS: 2
|
||||
RED_SAND: 1
|
||||
RED_SANDSTONE: 1
|
||||
RED_SANDSTONE_SLAB: 1
|
||||
RED_SANDSTONE_STAIRS: 2
|
||||
RED_SANDSTONE_WALL: 2
|
||||
RED_SHULKER_BOX: 11
|
||||
RED_STAINED_GLASS: 2
|
||||
RED_STAINED_GLASS_PANE: 1
|
||||
RED_TERRACOTTA: 2
|
||||
RED_TULIP: 1
|
||||
RED_WALL_BANNER: 2
|
||||
RED_WOOL: 2
|
||||
REDSTONE_BLOCK: 10
|
||||
REDSTONE_LAMP: 10
|
||||
REDSTONE_ORE: 1
|
||||
REDSTONE_TORCH: 5
|
||||
REDSTONE_WALL_TORCH: 5
|
||||
REDSTONE_WIRE: 1
|
||||
REPEATER: 6
|
||||
REPEATING_COMMAND_BLOCK: 0
|
||||
RESPAWN_ANCHOR: 100
|
||||
ROSE_BUSH: 1
|
||||
SAND: 1
|
||||
SANDSTONE: 1
|
||||
SANDSTONE_SLAB: 1
|
||||
SANDSTONE_STAIRS: 2
|
||||
SANDSTONE_WALL: 2
|
||||
SCAFFOLDING: 1
|
||||
SEA_LANTERN: 9
|
||||
SEA_PICKLE: 1
|
||||
SEAGRASS: 1
|
||||
SHROOMLIGHT: 1
|
||||
SHULKER_BOX: 10
|
||||
SKELETON_SKULL: 10
|
||||
SKELETON_WALL_SKULL: 100
|
||||
SLIME_BLOCK: 10
|
||||
SMITHING_TABLE: 6
|
||||
SMOKER: 10
|
||||
SMOOTH_QUARTZ: 1
|
||||
SMOOTH_QUARTZ_SLAB: 1
|
||||
SMOOTH_QUARTZ_STAIRS: 1
|
||||
SMOOTH_RED_SANDSTONE: 1
|
||||
SMOOTH_RED_SANDSTONE_SLAB: 1
|
||||
SMOOTH_RED_SANDSTONE_STAIRS: 1
|
||||
SMOOTH_SANDSTONE: 1
|
||||
SMOOTH_SANDSTONE_SLAB: 1
|
||||
SMOOTH_SANDSTONE_STAIRS: 1
|
||||
SMOOTH_STONE: 1
|
||||
SMOOTH_STONE_SLAB: 1
|
||||
SNOW: 1
|
||||
SNOW_BLOCK: 1
|
||||
SOUL_CAMPFIRE: 1
|
||||
SOUL_FIRE: 1
|
||||
SOUL_LANTERN: 1
|
||||
SOUL_SAND: 2
|
||||
SOUL_SOIL: 1
|
||||
SOUL_TORCH: 1
|
||||
SOUL_WALL_TORCH: 1
|
||||
SPAWNER: 1
|
||||
SPONGE: 10
|
||||
SPRUCE_BUTTON: 1
|
||||
SPRUCE_DOOR: 2
|
||||
SPRUCE_FENCE: 2
|
||||
SPRUCE_FENCE_GATE: 4
|
||||
SPRUCE_LEAVES: 0
|
||||
SPRUCE_LOG: 0
|
||||
SPRUCE_PLANKS: 1
|
||||
SPRUCE_PRESSURE_PLATE: 2
|
||||
SPRUCE_SAPLING: 1
|
||||
SPRUCE_SIGN: 6
|
||||
SPRUCE_SLAB: 1
|
||||
SPRUCE_STAIRS: 2
|
||||
SPRUCE_TRAPDOOR: 3
|
||||
SPRUCE_WALL_SIGN: 6
|
||||
SPRUCE_WOOD: 1
|
||||
STICKY_PISTON: 1
|
||||
STONE: 1
|
||||
STONE_BRICK_SLAB: 1
|
||||
STONE_BRICK_STAIRS: 2
|
||||
STONE_BRICK_WALL: 2
|
||||
STONE_BRICKS: 2
|
||||
STONE_BUTTON: 1
|
||||
STONE_PRESSURE_PLATE: 2
|
||||
STONE_SLAB: 1
|
||||
STONE_STAIRS: 1
|
||||
STONECUTTER: 4
|
||||
STRIPPED_ACACIA_LOG: 0
|
||||
STRIPPED_ACACIA_WOOD: 1
|
||||
STRIPPED_BIRCH_LOG: 0
|
||||
STRIPPED_BIRCH_WOOD: 1
|
||||
STRIPPED_CRIMSON_HYPHAE: 1
|
||||
STRIPPED_CRIMSON_STEM: 1
|
||||
STRIPPED_DARK_OAK_LOG: 0
|
||||
STRIPPED_DARK_OAK_WOOD: 1
|
||||
STRIPPED_JUNGLE_LOG: 0
|
||||
STRIPPED_JUNGLE_WOOD: 1
|
||||
STRIPPED_OAK_LOG: 0
|
||||
STRIPPED_OAK_WOOD: 1
|
||||
STRIPPED_SPRUCE_LOG: 0
|
||||
STRIPPED_SPRUCE_WOOD: 1
|
||||
STRIPPED_WARPED_HYPHAE: 1
|
||||
STRIPPED_WARPED_STEM: 1
|
||||
STRUCTURE_BLOCK: 0
|
||||
STRUCTURE_VOID: 0
|
||||
SUGAR_CANE: 1
|
||||
SUNFLOWER: 1
|
||||
SWEET_BERRY_BUSH: 1
|
||||
TALL_GRASS: 1
|
||||
TALL_SEAGRASS: 1
|
||||
TARGET: 5
|
||||
TERRACOTTA: 2
|
||||
TNT: 5
|
||||
TORCH: 1
|
||||
TRAPPED_CHEST: 10
|
||||
TRIPWIRE: 2
|
||||
TRIPWIRE_HOOK: 2
|
||||
TUBE_CORAL: 1
|
||||
TUBE_CORAL_BLOCK: 1
|
||||
TUBE_CORAL_FAN: 1
|
||||
TUBE_CORAL_WALL_FAN: 1
|
||||
TURTLE_EGG: 1
|
||||
TWISTING_VINES: 1
|
||||
TWISTING_VINES_PLANT: 1
|
||||
VINE: 1
|
||||
VOID_AIR: 0
|
||||
WALL_TORCH: 1
|
||||
WARPED_BUTTON: 1
|
||||
WARPED_DOOR: 3
|
||||
WARPED_FENCE: 2
|
||||
WARPED_FENCE_GATE: 4
|
||||
WARPED_FUNGUS: 1
|
||||
WARPED_HYPHAE: 1
|
||||
WARPED_NYLIUM: 1
|
||||
WARPED_PLANKS: 1
|
||||
WARPED_PRESSURE_PLATE: 2
|
||||
WARPED_ROOTS: 1
|
||||
WARPED_SIGN: 6
|
||||
WARPED_SLAB: 1
|
||||
WARPED_STAIRS: 2
|
||||
WARPED_STEM: 1
|
||||
WARPED_TRAPDOOR: 3
|
||||
WARPED_WALL_SIGN: 6
|
||||
WARPED_WART_BLOCK: 1
|
||||
WATER: 0
|
||||
WEEPING_VINES: 1
|
||||
WEEPING_VINES_PLANT: 1
|
||||
WET_SPONGE: 10
|
||||
WHEAT: 1
|
||||
WHITE_BANNER: 2
|
||||
WHITE_BED: 6
|
||||
WHITE_CARPET: 1
|
||||
WHITE_CONCRETE: 3
|
||||
WHITE_CONCRETE_POWDER: 2
|
||||
WHITE_GLAZED_TERRACOTTA: 5
|
||||
WHITE_SHULKER_BOX: 11
|
||||
WHITE_STAINED_GLASS: 2
|
||||
WHITE_STAINED_GLASS_PANE: 1
|
||||
WHITE_TERRACOTTA: 2
|
||||
WHITE_TULIP: 1
|
||||
WHITE_WALL_BANNER: 2
|
||||
WHITE_WOOL: 2
|
||||
WITHER_ROSE: 1
|
||||
WITHER_SKELETON_SKULL: 10
|
||||
WITHER_SKELETON_WALL_SKULL: 10
|
||||
YELLOW_BANNER: 2
|
||||
YELLOW_BED: 6
|
||||
YELLOW_CARPET: 1
|
||||
YELLOW_CONCRETE: 3
|
||||
YELLOW_CONCRETE_POWDER: 2
|
||||
YELLOW_GLAZED_TERRACOTTA: 5
|
||||
YELLOW_SHULKER_BOX: 11
|
||||
YELLOW_STAINED_GLASS: 2
|
||||
YELLOW_STAINED_GLASS_PANE: 1
|
||||
YELLOW_TERRACOTTA: 2
|
||||
YELLOW_WALL_BANNER: 2
|
||||
YELLOW_WOOL: 2
|
||||
ZOMBIE_HEAD: 1
|
||||
ZOMBIE_WALL_HEAD: 1
|
||||
worlds:
|
||||
caveblock-world:
|
||||
STONE: 0
|
||||
GRANITE: 0
|
||||
ANDESITE: 0
|
||||
DIORITE: 0
|
||||
acidisland_world:
|
||||
BRAIN_CORAL: 0
|
||||
BRAIN_CORAL_BLOCK: 0
|
||||
BRAIN_CORAL_FAN: 0
|
||||
BRAIN_CORAL_WALL_FAN: 0
|
||||
BUBBLE_CORAL: 0
|
||||
BUBBLE_CORAL_BLOCK: 0
|
||||
BUBBLE_CORAL_FAN: 0
|
||||
BUBBLE_CORAL_WALL_FAN: 0
|
||||
DEAD_BRAIN_CORAL: 0
|
||||
DEAD_BRAIN_CORAL_BLOCK: 0
|
||||
DEAD_BRAIN_CORAL_FAN: 0
|
||||
DEAD_BRAIN_CORAL_WALL_FAN: 0
|
||||
DEAD_BUBBLE_CORAL: 0
|
||||
DEAD_BUBBLE_CORAL_BLOCK: 0
|
||||
DEAD_BUBBLE_CORAL_FAN: 0
|
||||
DEAD_BUBBLE_CORAL_WALL_FAN: 0
|
||||
FIRE_CORAL: 0
|
||||
FIRE_CORAL_BLOCK: 0
|
||||
FIRE_CORAL_FAN: 0
|
||||
FIRE_CORAL_WALL_FAN: 0
|
||||
DEAD_FIRE_CORAL: 0
|
||||
DEAD_FIRE_CORAL_BLOCK: 0
|
||||
DEAD_FIRE_CORAL_FAN: 0
|
||||
DEAD_FIRE_CORAL_WALL_FAN: 0
|
||||
HORN_CORAL: 0
|
||||
HORN_CORAL_BLOCK: 0
|
||||
HORN_CORAL_FAN: 0
|
||||
HORN_CORAL_WALL_FAN: 0
|
||||
DEAD_HORN_CORAL: 0
|
||||
DEAD_HORN_CORAL_BLOCK: 0
|
||||
DEAD_HORN_CORAL_FAN: 0
|
||||
DEAD_HORN_CORAL_WALL_FAN: 0
|
||||
TUBE_CORAL: 0
|
||||
TUBE_CORAL_BLOCK: 0
|
||||
TUBE_CORAL_FAN: 0
|
||||
TUBE_CORAL_WALL_FAN: 0
|
||||
DEAD_TUBE_CORAL: 0
|
||||
DEAD_TUBE_CORAL_BLOCK: 0
|
||||
DEAD_TUBE_CORAL_FAN: 0
|
||||
DEAD_TUBE_CORAL_WALL_FAN: 0
|
||||
SAND: 0
|
||||
SANDSTONE: 0
|
||||
RED_SAND: 0
|
||||
ICE: 0
|
||||
AMETHYST_CLUSTER: 0
|
||||
AMETHYST_BLOCK: 0
|
||||
LARGE_AMETHYST_BUD: 0
|
||||
MEDIUM_AMETHYST_BUD: 0
|
||||
SMALL_AMETHYST_BUD: 0
|
||||
BUDDING_AMETHYST: 0
|
||||
SEA_PICKLE: 0
|
||||
CALCITE: 0
|
||||
TALL_SEAGRASS: 0
|
||||
SEAGRASS: 0
|
||||
SMOOTH_BASALT: 0
|
|
@ -1,30 +1,65 @@
|
|||
# Config file for Level add-on Version ${version}
|
||||
|
||||
# Game Mode Addons
|
||||
# Level will hook into these game mode addons. Don't forget to set any world-specific
|
||||
# block values below!
|
||||
game-modes:
|
||||
- AcidIsland
|
||||
- BSkyBlock
|
||||
- CaveBlock
|
||||
#- SkyGrid
|
||||
|
||||
# This file lists the values for various blocks that are used to calculate the
|
||||
# island level. Level = total of all blocks in island boundary / 100.
|
||||
# Players with the permission askyblock.island.multiplier.# will have their blocks
|
||||
# multiplied in value by that amount.
|
||||
|
||||
# Level Configuration ${version}
|
||||
#
|
||||
#
|
||||
# Disabled Game Mode Addons
|
||||
# Level will NOT hook into these game mode addons.
|
||||
disabled-game-modes: []
|
||||
#
|
||||
# When executing level command from console, should a report be shown?
|
||||
log-report-to-console: true
|
||||
#
|
||||
# Number of concurrent island calculations
|
||||
# If your CPU can handle it, you can run parallel island calcs if there are more than one in the queue
|
||||
concurrent-island-calcs: 1
|
||||
#
|
||||
# Island level calculation timeout in minutes.
|
||||
# If an island takes longer that this time to calculate, then the calculation will abort.
|
||||
# Generally, calculation should only take a few seconds, so if this ever triggers then something is not right.
|
||||
calculation-timeout: 5
|
||||
#
|
||||
# Zero island levels on new island or island reset
|
||||
# If true, Level will calculate the starter island's level and remove it from any future level calculations.
|
||||
# If this is false, the player's starter island blocks will count towards their level.
|
||||
# This will reduce CPU if false.
|
||||
zero-new-island-levels: true
|
||||
#
|
||||
# Calculate island level on login
|
||||
# This silently calculates the player's island level when they login
|
||||
# This applies to all islands the player has on the server, e.g., BSkyBlock, AcidIsland
|
||||
login: false
|
||||
#
|
||||
# Include nether island in level calculations.
|
||||
# Warning: Enabling this mid-game will give players with an island a jump in
|
||||
# island level. New islands will be correctly zeroed.
|
||||
nether: false
|
||||
#
|
||||
# Include end island in level calculations.
|
||||
# Warning: Enabling this mid-game will give players with an island a jump in
|
||||
# island level. New islands will be correctly zeroed.
|
||||
end: false
|
||||
#
|
||||
# Include chest contents in level calculations.
|
||||
# Will count blocks in chests or containers.
|
||||
include-chests: false
|
||||
#
|
||||
# Underwater block multiplier
|
||||
# If blocks are below sea-level, they can have a higher value. e.g. 2x
|
||||
# Promotes under-water development if there is a sea. Value can be fractional.
|
||||
underwater: 1.0
|
||||
|
||||
#
|
||||
# Value of one island level. Default 100. Minimum value is 1.
|
||||
levelcost: 100
|
||||
|
||||
#
|
||||
# Island level calculation formula
|
||||
# blocks - the sum total of all block values, less any death penalty
|
||||
# level_cost - in a linear equation, the value of one level
|
||||
# This formula can include +,=,*,/,sqrt,^,sin,cos,tan,log (natural log). Result will always be rounded to a long integer
|
||||
# for example, an alternative non-linear option could be: 3 * sqrt(blocks / level_cost)
|
||||
level-calc: blocks / level_cost
|
||||
#
|
||||
# Cooldown between level requests in seconds
|
||||
levelwait: 60
|
||||
|
||||
#
|
||||
# Death penalty
|
||||
# How many block values a player will lose per death.
|
||||
# Default value of 100 means that for every death, the player will lose 1 level (if levelcost is 100)
|
||||
|
@ -32,627 +67,8 @@ levelwait: 60
|
|||
deathpenalty: 100
|
||||
# Sum team deaths - if true, all the teams deaths are summed
|
||||
# If false, only the leader's deaths counts
|
||||
# For other death related settings, see the GameModeAddon's config.yml settings.
|
||||
sumteamdeaths: false
|
||||
# Max deaths
|
||||
# If player dies more than this, it doesn't count anymore
|
||||
# Stops players from getting into an impossible situation
|
||||
maxdeaths: 10
|
||||
# Reset deaths on island reset
|
||||
islandresetdeathreset: true
|
||||
# Reset deaths on team join
|
||||
teamjoindeathreset: true
|
||||
|
||||
|
||||
# This section lists the limits for any particular block. Blocks over this amount
|
||||
# are not counted.
|
||||
# Format:
|
||||
# MATERIAL: limit
|
||||
limits:
|
||||
COBBLESTONE: 10000
|
||||
NETHERRACK: 1000
|
||||
|
||||
# This section lists the value of a block. Value must be an integer.
|
||||
# Any blocks not listed will have a value of 0. AIR is always zero.
|
||||
# Format is MATERIAL: value
|
||||
|
||||
blocks:
|
||||
ACACIA_BUTTON: 1
|
||||
ACACIA_DOOR: 2
|
||||
ACACIA_FENCE: 2
|
||||
ACACIA_FENCE_GATE: 4
|
||||
ACACIA_LEAVES: 0
|
||||
ACACIA_LOG: 0
|
||||
ACACIA_PLANKS: 1
|
||||
ACACIA_PRESSURE_PLATE: 2
|
||||
ACACIA_SAPLING: 1
|
||||
ACACIA_SLAB: 1
|
||||
ACACIA_STAIRS: 2
|
||||
ACACIA_TRAPDOOR: 3
|
||||
ACACIA_WOOD: 1
|
||||
ACTIVATOR_RAIL: 1
|
||||
ALLIUM: 1
|
||||
ANDESITE: 1
|
||||
ANVIL: 10
|
||||
ATTACHED_MELON_STEM: 1
|
||||
ATTACHED_PUMPKIN_STEM: 1
|
||||
AZURE_BLUET: 1
|
||||
BARRIER: 0
|
||||
BEACON: 500
|
||||
BEDROCK: 0
|
||||
BEETROOTS: 1
|
||||
BIRCH_BUTTON: 1
|
||||
BIRCH_DOOR: 2
|
||||
BIRCH_FENCE: 2
|
||||
BIRCH_FENCE_GATE: 4
|
||||
BIRCH_LEAVES: 0
|
||||
BIRCH_LOG: 0
|
||||
BIRCH_PLANKS: 1
|
||||
BIRCH_PRESSURE_PLATE: 2
|
||||
BIRCH_SAPLING: 1
|
||||
BIRCH_SLAB: 1
|
||||
BIRCH_STAIRS: 2
|
||||
BIRCH_TRAPDOOR: 3
|
||||
BIRCH_WOOD: 1
|
||||
BLACK_BANNER: 2
|
||||
BLACK_BED: 6
|
||||
BLACK_CARPET: 1
|
||||
BLACK_CONCRETE: 3
|
||||
BLACK_CONCRETE_POWDER: 2
|
||||
BLACK_GLAZED_TERRACOTTA: 5
|
||||
BLACK_SHULKER_BOX: 11
|
||||
BLACK_STAINED_GLASS: 2
|
||||
BLACK_STAINED_GLASS_PANE: 1
|
||||
BLACK_TERRACOTTA: 2
|
||||
BLACK_WALL_BANNER: 2
|
||||
BLACK_WOOL: 2
|
||||
BLUE_BANNER: 2
|
||||
BLUE_BED: 6
|
||||
BLUE_CARPET: 1
|
||||
BLUE_CONCRETE: 3
|
||||
BLUE_CONCRETE_POWDER: 2
|
||||
BLUE_GLAZED_TERRACOTTA: 5
|
||||
BLUE_ICE: 1
|
||||
BLUE_ORCHID: 1
|
||||
BLUE_SHULKER_BOX: 11
|
||||
BLUE_STAINED_GLASS: 2
|
||||
BLUE_STAINED_GLASS_PANE: 1
|
||||
BLUE_TERRACOTTA: 2
|
||||
BLUE_WALL_BANNER: 2
|
||||
BLUE_WOOL: 2
|
||||
BONE_BLOCK: 1
|
||||
BOOKSHELF: 5
|
||||
BRAIN_CORAL: 1
|
||||
BRAIN_CORAL_BLOCK: 1
|
||||
BRAIN_CORAL_FAN: 1
|
||||
BRAIN_CORAL_WALL_FAN: 1
|
||||
BREWING_STAND: 20
|
||||
BRICKS: 5
|
||||
BRICK_SLAB: 3
|
||||
BRICK_STAIRS: 5
|
||||
BROWN_BANNER: 2
|
||||
BROWN_BED: 6
|
||||
BROWN_CARPET: 1
|
||||
BROWN_CONCRETE: 3
|
||||
BROWN_CONCRETE_POWDER: 2
|
||||
BROWN_GLAZED_TERRACOTTA: 5
|
||||
BROWN_MUSHROOM: 1
|
||||
BROWN_MUSHROOM_BLOCK: 1
|
||||
BROWN_SHULKER_BOX: 11
|
||||
BROWN_STAINED_GLASS: 2
|
||||
BROWN_STAINED_GLASS_PANE: 1
|
||||
BROWN_TERRACOTTA: 2
|
||||
BROWN_WALL_BANNER: 2
|
||||
BROWN_WOOL: 2
|
||||
BUBBLE_COLUMN: 1
|
||||
BUBBLE_CORAL: 1
|
||||
BUBBLE_CORAL_BLOCK: 1
|
||||
BUBBLE_CORAL_FAN: 1
|
||||
BUBBLE_CORAL_WALL_FAN: 1
|
||||
CACTUS: 1
|
||||
CAKE: 9
|
||||
CARROTS: 1
|
||||
CARVED_PUMPKIN: 2
|
||||
CAULDRON: 10
|
||||
CAVE_AIR: 0
|
||||
CHAIN_COMMAND_BLOCK: 0
|
||||
CHEST: 8
|
||||
CHIPPED_ANVIL: 9
|
||||
CHISELED_QUARTZ_BLOCK: 2
|
||||
CHISELED_RED_SANDSTONE: 2
|
||||
CHISELED_SANDSTONE: 2
|
||||
CHISELED_STONE_BRICKS: 2
|
||||
CHORUS_FLOWER: 1
|
||||
CHORUS_PLANT: 1
|
||||
CLAY: 2
|
||||
COAL_BLOCK: 9
|
||||
COAL_ORE: 1
|
||||
COARSE_DIRT: 2
|
||||
COBBLESTONE: 1
|
||||
COBBLESTONE_SLAB: 1
|
||||
COBBLESTONE_STAIRS: 2
|
||||
COBBLESTONE_WALL: 1
|
||||
COBWEB: 10
|
||||
COCOA: 1
|
||||
COMMAND_BLOCK: 0
|
||||
COMPARATOR: 10
|
||||
CONDUIT: 1
|
||||
CRACKED_STONE_BRICKS: 2
|
||||
CRAFTING_TABLE: 1
|
||||
CREEPER_HEAD: 1
|
||||
CREEPER_WALL_HEAD: 1
|
||||
CUT_RED_SANDSTONE: 1
|
||||
CUT_SANDSTONE: 1
|
||||
CYAN_BANNER: 2
|
||||
CYAN_BED: 6
|
||||
CYAN_CARPET: 1
|
||||
CYAN_CONCRETE: 3
|
||||
CYAN_CONCRETE_POWDER: 2
|
||||
CYAN_GLAZED_TERRACOTTA: 5
|
||||
CYAN_SHULKER_BOX: 11
|
||||
CYAN_STAINED_GLASS: 2
|
||||
CYAN_STAINED_GLASS_PANE: 1
|
||||
CYAN_TERRACOTTA: 2
|
||||
CYAN_WALL_BANNER: 2
|
||||
CYAN_WOOL: 2
|
||||
DAMAGED_ANVIL: 5
|
||||
DANDELION: 1
|
||||
DARK_OAK_BUTTON: 1
|
||||
DARK_OAK_DOOR: 2
|
||||
DARK_OAK_FENCE: 2
|
||||
DARK_OAK_FENCE_GATE: 4
|
||||
DARK_OAK_LEAVES: 0
|
||||
DARK_OAK_LOG: 0
|
||||
DARK_OAK_PLANKS: 1
|
||||
DARK_OAK_PRESSURE_PLATE: 2
|
||||
DARK_OAK_SAPLING: 1
|
||||
DARK_OAK_SLAB: 1
|
||||
DARK_OAK_STAIRS: 2
|
||||
DARK_OAK_TRAPDOOR: 3
|
||||
DARK_OAK_WOOD: 1
|
||||
DARK_PRISMARINE: 1
|
||||
DARK_PRISMARINE_SLAB: 1
|
||||
DARK_PRISMARINE_STAIRS: 2
|
||||
DAYLIGHT_DETECTOR: 10
|
||||
DEAD_BRAIN_CORAL_BLOCK: 1
|
||||
DEAD_BRAIN_CORAL_FAN: 1
|
||||
DEAD_BRAIN_CORAL_WALL_FAN: 1
|
||||
DEAD_BUBBLE_CORAL_BLOCK: 1
|
||||
DEAD_BUBBLE_CORAL_FAN: 1
|
||||
DEAD_BUBBLE_CORAL_WALL_FAN: 1
|
||||
DEAD_BUSH: 1
|
||||
DEAD_FIRE_CORAL_BLOCK: 1
|
||||
DEAD_FIRE_CORAL_FAN: 1
|
||||
DEAD_FIRE_CORAL_WALL_FAN: 1
|
||||
DEAD_HORN_CORAL_BLOCK: 1
|
||||
DEAD_HORN_CORAL_FAN: 1
|
||||
DEAD_HORN_CORAL_WALL_FAN: 1
|
||||
DEAD_TUBE_CORAL_BLOCK: 1
|
||||
DEAD_TUBE_CORAL_FAN: 1
|
||||
DEAD_TUBE_CORAL_WALL_FAN: 1
|
||||
DETECTOR_RAIL: 10
|
||||
DIAMOND_BLOCK: 300
|
||||
DIAMOND_ORE: 1
|
||||
DIORITE: 1
|
||||
DIRT: 3
|
||||
DISPENSER: 5
|
||||
DRAGON_EGG: 150
|
||||
DRAGON_HEAD: 1
|
||||
DRAGON_WALL_HEAD: 1
|
||||
DRIED_KELP_BLOCK: 1
|
||||
DROPPER: 5
|
||||
EMERALD_BLOCK: 150
|
||||
EMERALD_ORE: 1
|
||||
ENCHANTING_TABLE: 150
|
||||
ENDER_CHEST: 150
|
||||
END_GATEWAY: 0
|
||||
END_PORTAL: 0
|
||||
END_PORTAL_FRAME: 0
|
||||
END_ROD: 1
|
||||
END_STONE: 1
|
||||
END_STONE_BRICKS: 2
|
||||
FARMLAND: 1
|
||||
FERN: 1
|
||||
FIRE: 0
|
||||
FIRE_CORAL: 1
|
||||
FIRE_CORAL_BLOCK: 1
|
||||
FIRE_CORAL_FAN: 1
|
||||
FIRE_CORAL_WALL_FAN: 1
|
||||
FLOWER_POT: 1
|
||||
FROSTED_ICE: 1
|
||||
FURNACE: 8
|
||||
GLASS: 2
|
||||
GLASS_PANE: 1
|
||||
GLOWSTONE: 1
|
||||
GOLD_BLOCK: 150
|
||||
GOLD_ORE: 1
|
||||
GRANITE: 1
|
||||
GRASS: 4
|
||||
GRASS_BLOCK: 4
|
||||
GRASS_PATH: 4
|
||||
GRAVEL: 1
|
||||
GRAY_BANNER: 2
|
||||
GRAY_BED: 6
|
||||
GRAY_CARPET: 1
|
||||
GRAY_CONCRETE: 3
|
||||
GRAY_CONCRETE_POWDER: 2
|
||||
GRAY_GLAZED_TERRACOTTA: 5
|
||||
GRAY_SHULKER_BOX: 11
|
||||
GRAY_STAINED_GLASS: 2
|
||||
GRAY_STAINED_GLASS_PANE: 1
|
||||
GRAY_TERRACOTTA: 2
|
||||
GRAY_WALL_BANNER: 2
|
||||
GRAY_WOOL: 2
|
||||
GREEN_BANNER: 2
|
||||
GREEN_BED: 6
|
||||
GREEN_CARPET: 1
|
||||
GREEN_CONCRETE: 3
|
||||
GREEN_CONCRETE_POWDER: 2
|
||||
GREEN_GLAZED_TERRACOTTA: 5
|
||||
GREEN_SHULKER_BOX: 11
|
||||
GREEN_STAINED_GLASS: 2
|
||||
GREEN_STAINED_GLASS_PANE: 1
|
||||
GREEN_TERRACOTTA: 2
|
||||
GREEN_WALL_BANNER: 2
|
||||
GREEN_WOOL: 2
|
||||
HAY_BLOCK: 2
|
||||
HEAVY_WEIGHTED_PRESSURE_PLATE: 3
|
||||
HOPPER: -10
|
||||
HORN_CORAL: 1
|
||||
HORN_CORAL_BLOCK: 1
|
||||
HORN_CORAL_FAN: 1
|
||||
HORN_CORAL_WALL_FAN: 1
|
||||
ICE: 5
|
||||
INFESTED_CHISELED_STONE_BRICKS: 2
|
||||
INFESTED_COBBLESTONE: 1
|
||||
INFESTED_CRACKED_STONE_BRICKS: 2
|
||||
INFESTED_MOSSY_STONE_BRICKS: 2
|
||||
INFESTED_STONE: 1
|
||||
INFESTED_STONE_BRICKS: 2
|
||||
IRON_BARS: 2
|
||||
IRON_BLOCK: 10
|
||||
IRON_DOOR: 5
|
||||
IRON_ORE: 1
|
||||
IRON_TRAPDOOR: 4
|
||||
JACK_O_LANTERN: 2
|
||||
JUKEBOX: 10
|
||||
JUNGLE_BUTTON: 1
|
||||
JUNGLE_DOOR: 2
|
||||
JUNGLE_FENCE: 2
|
||||
JUNGLE_FENCE_GATE: 4
|
||||
JUNGLE_LEAVES: 0
|
||||
JUNGLE_LOG: 0
|
||||
JUNGLE_PLANKS: 1
|
||||
JUNGLE_PRESSURE_PLATE: 2
|
||||
JUNGLE_SAPLING: 1
|
||||
JUNGLE_SLAB: 1
|
||||
JUNGLE_STAIRS: 2
|
||||
JUNGLE_TRAPDOOR: 3
|
||||
JUNGLE_WOOD: 1
|
||||
KELP: 1
|
||||
KELP_PLANT: 1
|
||||
LADDER: 2
|
||||
LAPIS_BLOCK: 10
|
||||
LAPIS_ORE: 1
|
||||
LARGE_FERN: 1
|
||||
LAVA: 0
|
||||
LEVER: 1
|
||||
LIGHT_BLUE_BANNER: 2
|
||||
LIGHT_BLUE_BED: 6
|
||||
LIGHT_BLUE_CARPET: 1
|
||||
LIGHT_BLUE_CONCRETE: 3
|
||||
LIGHT_BLUE_CONCRETE_POWDER: 2
|
||||
LIGHT_BLUE_GLAZED_TERRACOTTA: 5
|
||||
LIGHT_BLUE_SHULKER_BOX: 11
|
||||
LIGHT_BLUE_STAINED_GLASS: 2
|
||||
LIGHT_BLUE_STAINED_GLASS_PANE: 1
|
||||
LIGHT_BLUE_TERRACOTTA: 2
|
||||
LIGHT_BLUE_WALL_BANNER: 2
|
||||
LIGHT_BLUE_WOOL: 2
|
||||
LIGHT_GRAY_BANNER: 2
|
||||
LIGHT_GRAY_BED: 6
|
||||
LIGHT_GRAY_CARPET: 1
|
||||
LIGHT_GRAY_CONCRETE: 3
|
||||
LIGHT_GRAY_CONCRETE_POWDER: 2
|
||||
LIGHT_GRAY_GLAZED_TERRACOTTA: 5
|
||||
LIGHT_GRAY_SHULKER_BOX: 11
|
||||
LIGHT_GRAY_STAINED_GLASS: 2
|
||||
LIGHT_GRAY_STAINED_GLASS_PANE: 1
|
||||
LIGHT_GRAY_TERRACOTTA: 2
|
||||
LIGHT_GRAY_WALL_BANNER: 2
|
||||
LIGHT_GRAY_WOOL: 2
|
||||
LIGHT_WEIGHTED_PRESSURE_PLATE: 3
|
||||
LILAC: 1
|
||||
LILY_PAD: 5
|
||||
LIME_BANNER: 2
|
||||
LIME_BED: 6
|
||||
LIME_CARPET: 1
|
||||
LIME_CONCRETE: 3
|
||||
LIME_CONCRETE_POWDER: 2
|
||||
LIME_GLAZED_TERRACOTTA: 5
|
||||
LIME_SHULKER_BOX: 11
|
||||
LIME_STAINED_GLASS: 2
|
||||
LIME_STAINED_GLASS_PANE: 1
|
||||
LIME_TERRACOTTA: 2
|
||||
LIME_WALL_BANNER: 2
|
||||
LIME_WOOL: 2
|
||||
MAGENTA_BANNER: 2
|
||||
MAGENTA_BED: 6
|
||||
MAGENTA_CARPET: 1
|
||||
MAGENTA_CONCRETE: 3
|
||||
MAGENTA_CONCRETE_POWDER: 2
|
||||
MAGENTA_GLAZED_TERRACOTTA: 5
|
||||
MAGENTA_SHULKER_BOX: 11
|
||||
MAGENTA_STAINED_GLASS: 2
|
||||
MAGENTA_STAINED_GLASS_PANE: 1
|
||||
MAGENTA_TERRACOTTA: 2
|
||||
MAGENTA_WALL_BANNER: 2
|
||||
MAGENTA_WOOL: 2
|
||||
MAGMA_BLOCK: 1
|
||||
MELON: 1
|
||||
MELON_STEM: 1
|
||||
MOSSY_COBBLESTONE: 1
|
||||
MOSSY_COBBLESTONE_WALL: 1
|
||||
MOSSY_STONE_BRICKS: 2
|
||||
MOVING_PISTON: 1
|
||||
MUSHROOM_STEM: 1
|
||||
MYCELIUM: 5
|
||||
NETHERRACK: 1
|
||||
NETHER_BRICKS: 2
|
||||
NETHER_BRICK_FENCE: 2
|
||||
NETHER_BRICK_SLAB: 1
|
||||
NETHER_BRICK_STAIRS: 2
|
||||
NETHER_PORTAL: 1
|
||||
NETHER_QUARTZ_ORE: 1
|
||||
NETHER_WART: 1
|
||||
NETHER_WART_BLOCK: 2
|
||||
NOTE_BLOCK: 10
|
||||
OAK_BUTTON: 1
|
||||
OAK_DOOR: 2
|
||||
OAK_FENCE: 2
|
||||
OAK_FENCE_GATE: 4
|
||||
OAK_LEAVES: 0
|
||||
OAK_LOG: 0
|
||||
OAK_PLANKS: 1
|
||||
OAK_PRESSURE_PLATE: 2
|
||||
OAK_SAPLING: 1
|
||||
OAK_SLAB: 1
|
||||
OAK_STAIRS: 2
|
||||
OAK_TRAPDOOR: 3
|
||||
OAK_WOOD: 1
|
||||
OBSERVER: 1
|
||||
OBSIDIAN: 10
|
||||
ORANGE_BANNER: 2
|
||||
ORANGE_BED: 6
|
||||
ORANGE_CARPET: 1
|
||||
ORANGE_CONCRETE: 3
|
||||
ORANGE_CONCRETE_POWDER: 2
|
||||
ORANGE_GLAZED_TERRACOTTA: 5
|
||||
ORANGE_SHULKER_BOX: 11
|
||||
ORANGE_STAINED_GLASS: 2
|
||||
ORANGE_STAINED_GLASS_PANE: 1
|
||||
ORANGE_TERRACOTTA: 2
|
||||
ORANGE_TULIP: 1
|
||||
ORANGE_WALL_BANNER: 2
|
||||
ORANGE_WOOL: 2
|
||||
OXEYE_DAISY: 1
|
||||
PACKED_ICE: 5
|
||||
PEONY: 1
|
||||
PETRIFIED_OAK_SLAB: 1
|
||||
PINK_BANNER: 2
|
||||
PINK_BED: 6
|
||||
PINK_CARPET: 1
|
||||
PINK_CONCRETE: 3
|
||||
PINK_CONCRETE_POWDER: 2
|
||||
PINK_GLAZED_TERRACOTTA: 5
|
||||
PINK_SHULKER_BOX: 11
|
||||
PINK_STAINED_GLASS: 2
|
||||
PINK_STAINED_GLASS_PANE: 1
|
||||
PINK_TERRACOTTA: 2
|
||||
PINK_TULIP: 1
|
||||
PINK_WALL_BANNER: 2
|
||||
PINK_WOOL: 2
|
||||
PISTON: 2
|
||||
PISTON_HEAD: 1
|
||||
PLAYER_HEAD: 1
|
||||
PLAYER_WALL_HEAD: 1
|
||||
PODZOL: 2
|
||||
POLISHED_ANDESITE: 1
|
||||
POLISHED_DIORITE: 1
|
||||
POLISHED_GRANITE: 1
|
||||
POPPY: 1
|
||||
POTATOES: 1
|
||||
POTTED_ACACIA_SAPLING: 1
|
||||
POTTED_ALLIUM: 1
|
||||
POTTED_AZURE_BLUET: 1
|
||||
POTTED_BIRCH_SAPLING: 1
|
||||
POTTED_BLUE_ORCHID: 1
|
||||
POTTED_BROWN_MUSHROOM: 1
|
||||
POTTED_CACTUS: 1
|
||||
POTTED_DANDELION: 1
|
||||
POTTED_DARK_OAK_SAPLING: 1
|
||||
POTTED_DEAD_BUSH: 1
|
||||
POTTED_FERN: 1
|
||||
POTTED_JUNGLE_SAPLING: 1
|
||||
POTTED_OAK_SAPLING: 1
|
||||
POTTED_ORANGE_TULIP: 1
|
||||
POTTED_OXEYE_DAISY: 1
|
||||
POTTED_PINK_TULIP: 1
|
||||
POTTED_POPPY: 1
|
||||
POTTED_RED_MUSHROOM: 1
|
||||
POTTED_RED_TULIP: 1
|
||||
POTTED_SPRUCE_SAPLING: 1
|
||||
POTTED_WHITE_TULIP: 1
|
||||
POWERED_RAIL: 2
|
||||
PRISMARINE: 1
|
||||
PRISMARINE_BRICKS: 2
|
||||
PRISMARINE_BRICK_SLAB: 1
|
||||
PRISMARINE_BRICK_STAIRS: 2
|
||||
PRISMARINE_SLAB: 1
|
||||
PRISMARINE_STAIRS: 2
|
||||
PUMPKIN: 1
|
||||
PUMPKIN_STEM: 1
|
||||
PURPLE_BANNER: 2
|
||||
PURPLE_BED: 6
|
||||
PURPLE_CARPET: 1
|
||||
PURPLE_CONCRETE: 3
|
||||
PURPLE_CONCRETE_POWDER: 2
|
||||
PURPLE_GLAZED_TERRACOTTA: 5
|
||||
PURPLE_SHULKER_BOX: 11
|
||||
PURPLE_STAINED_GLASS: 2
|
||||
PURPLE_STAINED_GLASS_PANE: 1
|
||||
PURPLE_TERRACOTTA: 2
|
||||
PURPLE_WALL_BANNER: 2
|
||||
PURPLE_WOOL: 2
|
||||
PURPUR_BLOCK: 1
|
||||
PURPUR_PILLAR: 1
|
||||
PURPUR_SLAB: 1
|
||||
PURPUR_STAIRS: 2
|
||||
QUARTZ_BLOCK: 1
|
||||
QUARTZ_PILLAR: 1
|
||||
QUARTZ_SLAB: 1
|
||||
QUARTZ_STAIRS: 2
|
||||
RAIL: 1
|
||||
REDSTONE_BLOCK: 10
|
||||
REDSTONE_LAMP: 10
|
||||
REDSTONE_ORE: 1
|
||||
REDSTONE_TORCH: 5
|
||||
REDSTONE_WALL_TORCH: 5
|
||||
REDSTONE_WIRE: 1
|
||||
RED_BED: 6
|
||||
RED_CARPET: 1
|
||||
RED_CONCRETE: 3
|
||||
RED_CONCRETE_POWDER: 2
|
||||
RED_GLAZED_TERRACOTTA: 5
|
||||
RED_MUSHROOM: 1
|
||||
RED_MUSHROOM_BLOCK: 1
|
||||
RED_NETHER_BRICKS: 2
|
||||
RED_SAND: 1
|
||||
RED_SANDSTONE: 1
|
||||
RED_SANDSTONE_SLAB: 1
|
||||
RED_SANDSTONE_STAIRS: 2
|
||||
RED_SHULKER_BOX: 11
|
||||
RED_STAINED_GLASS: 2
|
||||
RED_STAINED_GLASS_PANE: 1
|
||||
RED_TERRACOTTA: 2
|
||||
RED_TULIP: 1
|
||||
RED_WALL_BANNER: 2
|
||||
RED_WOOL: 2
|
||||
REPEATER: 6
|
||||
REPEATING_COMMAND_BLOCK: 0
|
||||
ROSE_BUSH: 1
|
||||
SAND: 1
|
||||
SANDSTONE: 1
|
||||
SANDSTONE_SLAB: 1
|
||||
SANDSTONE_STAIRS: 2
|
||||
SEAGRASS: 1
|
||||
SEA_LANTERN: 9
|
||||
SEA_PICKLE: 1
|
||||
SHULKER_BOX: 10
|
||||
SIGN: 6
|
||||
SKELETON_SKULL: 10
|
||||
SKELETON_WALL_SKULL: 100
|
||||
SLIME_BLOCK: 10
|
||||
SMOOTH_QUARTZ: 1
|
||||
SMOOTH_RED_SANDSTONE: 1
|
||||
SMOOTH_SANDSTONE: 1
|
||||
SMOOTH_STONE: 1
|
||||
SNOW: 1
|
||||
SNOW_BLOCK: 1
|
||||
SOUL_SAND: 2
|
||||
SPAWNER: 1
|
||||
SPONGE: 10
|
||||
SPRUCE_BUTTON: 1
|
||||
SPRUCE_DOOR: 2
|
||||
SPRUCE_FENCE: 2
|
||||
SPRUCE_FENCE_GATE: 4
|
||||
SPRUCE_LEAVES: 0
|
||||
SPRUCE_LOG: 0
|
||||
SPRUCE_PLANKS: 1
|
||||
SPRUCE_PRESSURE_PLATE: 2
|
||||
SPRUCE_SAPLING: 1
|
||||
SPRUCE_SLAB: 1
|
||||
SPRUCE_STAIRS: 2
|
||||
SPRUCE_TRAPDOOR: 3
|
||||
SPRUCE_WOOD: 1
|
||||
STICKY_PISTON: 1
|
||||
STONE: 1
|
||||
STONE_BRICKS: 2
|
||||
STONE_BRICK_SLAB: 1
|
||||
STONE_BRICK_STAIRS: 2
|
||||
STONE_BUTTON: 1
|
||||
STONE_PRESSURE_PLATE: 2
|
||||
STONE_SLAB: 1
|
||||
STRIPPED_ACACIA_LOG: 0
|
||||
STRIPPED_ACACIA_WOOD: 1
|
||||
STRIPPED_BIRCH_LOG: 0
|
||||
STRIPPED_BIRCH_WOOD: 1
|
||||
STRIPPED_DARK_OAK_LOG: 0
|
||||
STRIPPED_DARK_OAK_WOOD: 1
|
||||
STRIPPED_JUNGLE_LOG: 0
|
||||
STRIPPED_JUNGLE_WOOD: 1
|
||||
STRIPPED_OAK_LOG: 0
|
||||
STRIPPED_OAK_WOOD: 1
|
||||
STRIPPED_SPRUCE_LOG: 0
|
||||
STRIPPED_SPRUCE_WOOD: 1
|
||||
SUGAR_CANE: 1
|
||||
SUNFLOWER: 1
|
||||
TALL_GRASS: 1
|
||||
TALL_SEAGRASS: 1
|
||||
TERRACOTTA: 2
|
||||
TNT: 5
|
||||
TORCH: 1
|
||||
TRAPPED_CHEST: 10
|
||||
TRIPWIRE: 2
|
||||
TRIPWIRE_HOOK: 2
|
||||
TUBE_CORAL: 1
|
||||
TUBE_CORAL_BLOCK: 1
|
||||
TUBE_CORAL_FAN: 1
|
||||
TUBE_CORAL_WALL_FAN: 1
|
||||
TURTLE_EGG: 1
|
||||
VINE: 1
|
||||
VOID_AIR: 0
|
||||
WALL_SIGN: 6
|
||||
WALL_TORCH: 1
|
||||
WATER: 0
|
||||
WET_SPONGE: 10
|
||||
WHEAT: 1
|
||||
WHITE_BANNER: 2
|
||||
WHITE_BED: 6
|
||||
WHITE_CARPET: 1
|
||||
WHITE_CONCRETE: 3
|
||||
WHITE_CONCRETE_POWDER: 2
|
||||
WHITE_GLAZED_TERRACOTTA: 5
|
||||
WHITE_SHULKER_BOX: 11
|
||||
WHITE_STAINED_GLASS: 2
|
||||
WHITE_STAINED_GLASS_PANE: 1
|
||||
WHITE_TERRACOTTA: 2
|
||||
WHITE_TULIP: 1
|
||||
WHITE_WALL_BANNER: 2
|
||||
WHITE_WOOL: 2
|
||||
WITHER_SKELETON_SKULL: 10
|
||||
WITHER_SKELETON_WALL_SKULL: 10
|
||||
YELLOW_BANNER: 2
|
||||
YELLOW_BED: 6
|
||||
YELLOW_CARPET: 1
|
||||
YELLOW_CONCRETE: 3
|
||||
YELLOW_CONCRETE_POWDER: 2
|
||||
YELLOW_GLAZED_TERRACOTTA: 5
|
||||
YELLOW_SHULKER_BOX: 11
|
||||
YELLOW_STAINED_GLASS: 2
|
||||
YELLOW_STAINED_GLASS_PANE: 1
|
||||
YELLOW_TERRACOTTA: 2
|
||||
YELLOW_WALL_BANNER: 2
|
||||
YELLOW_WOOL: 2
|
||||
ZOMBIE_HEAD: 1
|
||||
ZOMBIE_WALL_HEAD: 1
|
||||
|
||||
# World differences
|
||||
# List any blocks that have a different value in a specific world
|
||||
# If a block is not listed, the default value will be used
|
||||
# Prefix with world name
|
||||
worlds:
|
||||
AcidIsland_world:
|
||||
SAND: 0
|
||||
SANDSTONE: 0
|
||||
ICE: 0
|
||||
|
||||
# Shorthand island level
|
||||
# Shows large level values rounded down, e.g., 10,345 -> 10k
|
||||
shorthand: false
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
###########################################################################################
|
||||
# This is a YML file. Be careful when editing. Check your edits in a YAML checker like #
|
||||
# the one at http://yaml-online-parser.appspot.com #
|
||||
# #
|
||||
# Translation by: CZghost #
|
||||
###########################################################################################
|
||||
|
||||
admin:
|
||||
level:
|
||||
parameters: "<player>"
|
||||
description: "vypočítat úroveň ostrova hráče"
|
||||
top:
|
||||
description: "ukázat seznam TOP 10"
|
||||
unknown-world: "&cNeznámý svět!"
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
remove:
|
||||
description: "odstranit hráče z TOP 10"
|
||||
parameters: "<player>"
|
||||
|
||||
island:
|
||||
level:
|
||||
parameters: "[player]"
|
||||
description: "spočítat úroveň tvého ostrova nebo ostrova hráče [player]"
|
||||
calculating: "&aPočítám úroveň..."
|
||||
island-level-is: "&aÚroveň ostrova je &b[level]"
|
||||
required-points-to-next-level: "&a[points] vyžadováno do další úrovně"
|
||||
deaths: "&c([number] smrtí)"
|
||||
cooldown: "&cMusíš čekat &b[time] &csekund, než můžeš příkaz znovu použít"
|
||||
|
||||
top:
|
||||
description: "ukázat TOP 10"
|
||||
gui-title: "&aTOP 10"
|
||||
gui-heading: "&6[name]: &B[rank]"
|
||||
island-level: "&BÚroveň [level]"
|
||||
warp-to: "&AWarp na ostrov [name]"
|
||||
|
||||
value:
|
||||
description: "ukáže hodnotu jakéhokoliv bloku"
|
||||
success: "&7Hodnota tohoto bloku je: &e[value]"
|
||||
success-underwater: "&7Hodnota tohoto bloku pod úrovní moře: &e[value]"
|
||||
empty-hand: "&cNemáš v ruce žádný blok"
|
||||
no-value: "&cTento předmět nemá žádnou hodnotu."
|
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
admin:
|
||||
level:
|
||||
parameters: "<Spieler>"
|
||||
description: Berechne das Insel Level für den Spieler
|
||||
levelstatus:
|
||||
islands-in-queue: "& a Inseln in der Warteschlange: [number]"
|
||||
top:
|
||||
description: Zeige die Top-10 Liste
|
||||
unknown-world: "&cUnbekannte Welt!"
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
remove:
|
||||
description: entferne Spieler von Top-10
|
||||
parameters: "<Spieler>"
|
||||
island:
|
||||
level:
|
||||
parameters: "[Spieler]"
|
||||
description: Berechne dein Insel Level oder zeige das Level von [Spieler]
|
||||
calculating: "&aBerechne Level..."
|
||||
estimated-wait: "& a Geschätzte Wartezeit: [number] Sekunden"
|
||||
in-queue: "& a Sie sind Nummer [number] in der Warteschlange"
|
||||
island-level-is: "&aInsel Level: &b[level]"
|
||||
required-points-to-next-level: "&a[points] Punkte werden für das nächste Level
|
||||
benötigt"
|
||||
deaths: "&c([number] Tode)"
|
||||
cooldown: "&cDu musst &b[time] &csekunden warten bevor du das erneut machen kannst."
|
||||
top:
|
||||
description: Zeige die Top-10
|
||||
gui-title: "&aTop Zehn"
|
||||
gui-heading: "&6[name]: &B[rank]"
|
||||
island-level: "&BLevel [level]"
|
||||
warp-to: "&ATeleportiere zu [name]'s Insel"
|
||||
level-details:
|
||||
above-sea-level-blocks: Blöcke über dem Meeresspiegel
|
||||
spawners: Spawner
|
||||
underwater-blocks: Unterwasserblöcke
|
||||
all-blocks: Alle Blöcke
|
||||
no-island: "&c Keine Insel!"
|
||||
value:
|
||||
description: Zeige den Wert jedes Blockes
|
||||
success: "&7Wert: &e[value]"
|
||||
success-underwater: "&7Wert des Blockes Unterwasser: &e[value]"
|
||||
empty-hand: "&cDu hast keinen Block in der Hand"
|
||||
no-value: "&cDas Item hat kein wert!"
|
|
@ -7,31 +7,207 @@ admin:
|
|||
level:
|
||||
parameters: "<player>"
|
||||
description: "calculate the island level for player"
|
||||
sethandicap:
|
||||
parameters: <player> <handicap>
|
||||
description: "set the island handicap, usually the level of the starter island"
|
||||
changed: "&a Initial island handicap changed from [number] to [new_number]."
|
||||
invalid-level: "&c Invalid handicap. Use an integer."
|
||||
levelstatus:
|
||||
description: "show how many islands are in the queue for scanning"
|
||||
islands-in-queue: "&a Islands in queue: [number]"
|
||||
top:
|
||||
description: "show the top ten list"
|
||||
unknown-world: "&cUnknown world!"
|
||||
unknown-world: "&c Unknown world!"
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
|
||||
remove:
|
||||
description: "remove player from Top Ten"
|
||||
parameters: "<player>"
|
||||
stats:
|
||||
description: "show stats on islands on this server"
|
||||
title: "Server Island Stats"
|
||||
world: "&a [name]"
|
||||
no-data: "&c No data to process."
|
||||
average-level: "Average Island Level: [number]"
|
||||
median-level: "Median Island Level: [number]"
|
||||
mode-level: "Mode Island Level: [number]"
|
||||
highest-level: "Highest Island Level: [number]"
|
||||
lowest-level: "Lowest Island Level: [number]"
|
||||
distribution: "Island Level Distribution:"
|
||||
islands: "islands"
|
||||
island:
|
||||
level:
|
||||
parameters: "[player]"
|
||||
description: "calculate your island level or show the level of [player]"
|
||||
calculating: "&aCalculating level..."
|
||||
island-level-is: "&aIsland level is &b[level]"
|
||||
required-points-to-next-level: "&a[points] points required until the next level"
|
||||
deaths: "&c([number] deaths)"
|
||||
cooldown: "&cYou must wait &b[time] &cseconds until you can do that again"
|
||||
calculating: "&a Calculating level..."
|
||||
estimated-wait: "&a Estimated wait: [number] seconds"
|
||||
in-queue: "&a You are number [number] in the queue"
|
||||
island-level-is: "&a Island level is &b[level]"
|
||||
required-points-to-next-level: "&a Level progress: &6 [progress]&b /&e [levelcost] &a points"
|
||||
deaths: "&c ([number] deaths)"
|
||||
cooldown: "&c You must wait &b[time] &c seconds until you can do that again"
|
||||
in-progress: "&6 Island level calculation is in progress..."
|
||||
time-out: "&c The level calculation took too long. Please try again later."
|
||||
|
||||
top:
|
||||
description: "show the Top Ten"
|
||||
gui-title: "&aTop Ten"
|
||||
gui-title: "&a Top Ten"
|
||||
gui-heading: "&6[name]: &B[rank]"
|
||||
island-level: "&BLevel [level]"
|
||||
warp-to: "&AWarping to [name]'s island"
|
||||
island-level: "&b Level [level]"
|
||||
warp-to: "&A Warping to [name]'s island"
|
||||
|
||||
level-details:
|
||||
above-sea-level-blocks: "Above Sea Level Blocks"
|
||||
spawners: "Spawners"
|
||||
underwater-blocks: "Underwater Blocks"
|
||||
all-blocks: "All Blocks"
|
||||
no-island: "&c No island!"
|
||||
names-island: "[name]'s island"
|
||||
syntax: "[name] x [number]"
|
||||
hint: "&c Run level to see the block report"
|
||||
|
||||
value:
|
||||
description: "shows the value of any block"
|
||||
success: "&7The value of this block is: &e[value]"
|
||||
success-underwater: "&7The value of this block below sea-level: &e[value]"
|
||||
empty-hand: "&cThere are no blocks in your hand"
|
||||
no-value: "&cThat item has no value."
|
||||
level:
|
||||
commands:
|
||||
value:
|
||||
parameters: "[hand|<material>]"
|
||||
description: "shows the value of blocks. Add 'hand' at the end to display value for item in hand."
|
||||
gui:
|
||||
titles:
|
||||
top: "&0&l Top Islands"
|
||||
detail-panel: "&0&l [name]'s island"
|
||||
value-panel: "&0&l Block Values"
|
||||
buttons:
|
||||
island:
|
||||
empty: '&f&l [name]. place'
|
||||
name: '&f&l [name]'
|
||||
description: |-
|
||||
[owner]
|
||||
[members]
|
||||
[place]
|
||||
[level]
|
||||
# Text that is replacing [name] if island do not have a name
|
||||
owners-island: "[player]'s Island"
|
||||
# Text for [owner] in description.
|
||||
owner: "&7&l Owner: &r&b [player]"
|
||||
# Title before listing members for [members] in description
|
||||
members-title: "&7&l Members:"
|
||||
# List each member under the title for [members] in description
|
||||
member: "&b - [player]"
|
||||
# Name of unknown player.
|
||||
unknown: "unknown"
|
||||
# Section for parsing [place]
|
||||
place: "&7&o [number]. &r&7 place"
|
||||
# Section for parsing [level]
|
||||
level: "&7 Level: &o [number]"
|
||||
material:
|
||||
name: "&f&l [number] x [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[count]
|
||||
[value]
|
||||
[calculated]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 Block id: &e [id]"
|
||||
value: "&7 Block value: &e [number]"
|
||||
limit: "&7 Block limit: &e [number]"
|
||||
count: "&7 Number of blocks: &e [number]"
|
||||
calculated: "&7 Calculated value: &e [number]"
|
||||
all_blocks:
|
||||
name: "&f&l All Blocks"
|
||||
description: |-
|
||||
&7 Display all blocks
|
||||
&7 on island.
|
||||
above_sea_level:
|
||||
name: "&f&l Blocks Above Sea Level"
|
||||
description: |-
|
||||
&7 Display only blocks
|
||||
&7 that are above sea
|
||||
&7 level.
|
||||
underwater:
|
||||
name: "&f&l Blocks Under Sea level"
|
||||
description: |-
|
||||
&7 Display only blocks
|
||||
&7 that are bellow sea
|
||||
&7 level.
|
||||
spawner:
|
||||
name: "&f&l Spawners"
|
||||
description: |-
|
||||
&7 Display only spawners.
|
||||
filters:
|
||||
name:
|
||||
name: "&f&l Sort by Name"
|
||||
description: |-
|
||||
&7 Sort all blocks by name.
|
||||
value:
|
||||
name: "&f&l Sort by Value"
|
||||
description: |-
|
||||
&7 Sort all blocks by their value.
|
||||
count:
|
||||
name: "&f&l Sort by Count"
|
||||
description: |-
|
||||
&7 Sort all blocks by their amount.
|
||||
value:
|
||||
name: "&f&l [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[value]
|
||||
[underwater]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 Block id: &e [id]"
|
||||
value: "&7 Block value: &e [number]"
|
||||
underwater: "&7 Bellow sea level: &e [number]"
|
||||
limit: "&7 Block limit: &e [number]"
|
||||
# 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
|
||||
search:
|
||||
name: "&f&l Search"
|
||||
description: |-
|
||||
&7 Search for a specific
|
||||
&7 value.
|
||||
search: "&b Value: [value]"
|
||||
tips:
|
||||
click-to-view: "&e Click &7 to view."
|
||||
click-to-previous: "&e Click &7 to view previous page."
|
||||
click-to-next: "&e Click &7 to view next page."
|
||||
click-to-select: "&e Click &7 to select."
|
||||
left-click-to-cycle-up: "&e Left Click &7 to cycle up."
|
||||
right-click-to-cycle-down: "&e Right Click &7 to cycle down."
|
||||
left-click-to-change: "&e Left Click &7 to edit."
|
||||
right-click-to-clear: "&e Right Click &7 to clear."
|
||||
click-to-asc: "&e Click &7 to sort in increasing order."
|
||||
click-to-desc: "&e Click &7 to sort in decreasing order."
|
||||
click-to-warp: "&e Click &7 to warp."
|
||||
click-to-visit: "&e Click &7 to visit."
|
||||
right-click-to-visit: "&e Right Click &7 to visit."
|
||||
conversations:
|
||||
# Prefix for messages that are send from server.
|
||||
prefix: "&l&6 [BentoBox]: &r"
|
||||
no-data: "&c Run level to see the block report."
|
||||
# String that allows to cancel conversation. (can be only one)
|
||||
cancel-string: "cancel"
|
||||
# List of strings that allows to exit conversation. (separated with ,)
|
||||
exit-string: "cancel, exit, quit"
|
||||
# Message that asks for search value input.
|
||||
write-search: "&e Please enter a search value. (Write 'cancel' to exit)"
|
||||
# Message that appears after updating search value.
|
||||
search-updated: "&a Search value updated."
|
||||
# Message that is sent to user when conversation is cancelled.
|
||||
cancelled: "&c Conversation cancelled!"
|
||||
# Message that is sent to user when given material does not have any value.
|
||||
no-value: "&c That item has no value."
|
||||
# Message that is sent to user when requested material does not exist.
|
||||
unknown-item: "&c The '[material]' does not exist in game."
|
||||
# Messages that is sent to user when requesting value for a specific material.
|
||||
value: "&7 The value of '[material]' is: &e[value]"
|
||||
value-underwater: "&7 The value of '[material]' below sea-level: &e[value]"
|
||||
# Message that is sent to user when he does not hold any items in hand.
|
||||
empty-hand: "&c There are no blocks in your hand"
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
###########################################################################################################
|
||||
# Este es un archivo YML. Tenga cuidado al editar. Revisa tus ediciones en un verificador de YAML como #
|
||||
# el de http://yaml-online-parser.appspot.com #
|
||||
###########################################################################################################
|
||||
|
||||
admin:
|
||||
level:
|
||||
parameters: "<player>"
|
||||
description: "calcula el nivel de la isla para el jugador"
|
||||
top:
|
||||
description: "mostrar la lista de los diez primeros"
|
||||
unknown-world: "&cMundo Desconocido!"
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
|
||||
island:
|
||||
level:
|
||||
parameters: "[player]"
|
||||
description: "calcula tu nivel de isla o muestra el nivel de [player]"
|
||||
calculating: "&aCalculando nivel..."
|
||||
island-level-is: "&aNivel de isla es de &b[level]"
|
||||
required-points-to-next-level: "&a[points] Puntos requeridos hasta el siguiente nivel."
|
||||
deaths: "&c([number] Muertes)"
|
||||
cooldown: "&cDebes esperar &b[time] &csegundos para poder volver a hacer eso"
|
||||
|
||||
top:
|
||||
description: "mostrar los diez primeros"
|
||||
gui-title: "&aDiez primeros"
|
||||
gui-heading: "&6[name]: &B[rank]"
|
||||
island-level: "&BNivel [level]"
|
||||
warp-to: "&ATeletransportandote a la isla de [name]"
|
||||
|
||||
value:
|
||||
description: "muestra el valor de cualquier bloque"
|
||||
success: "&7El valor de este bloque es: &e[value]"
|
||||
success-underwater: "&7El valor de este bloque bajo el nivel del mar: &e[value]"
|
||||
empty-hand: "&cNo hay bloques en tu mano"
|
||||
no-value: "&cEse item no tiene valor"
|
|
@ -0,0 +1,172 @@
|
|||
---
|
||||
admin:
|
||||
level:
|
||||
parameters: "<player>"
|
||||
description: Calcula el nivel de la isla del jugador
|
||||
sethandicap:
|
||||
parameters: "<player> <handicap>"
|
||||
description: Define la desventaja de la isla, usualmente el nivel inicial para
|
||||
nuevas islas
|
||||
changed: "&aDesventaja inicial de la isla cambiado de [number] a [new_number]."
|
||||
invalid-level: "&cNúmero no válido. Usa un número entero."
|
||||
levelstatus:
|
||||
description: Muestra cuantas islas hay en la cola para escanear
|
||||
islands-in-queue: "&aIslas en cola: [number]"
|
||||
top:
|
||||
description: Muestra la lista de las diez primeras islas
|
||||
unknown-world: "&c¡Mundo desconocido!"
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
remove:
|
||||
description: Elimina a un jugador de los diez primeros
|
||||
parameters: "<jugador>"
|
||||
island:
|
||||
level:
|
||||
parameters: "[player]"
|
||||
description: Calcula tu nivel de isla o muestra el nivel de [player]
|
||||
calculating: "&aCalculando nivel..."
|
||||
estimated-wait: "&aEspera estimada: [number] segundos"
|
||||
in-queue: "&aEstás en el puesto [number] de la cola"
|
||||
island-level-is: "&aNivel de isla es de &b[level]"
|
||||
required-points-to-next-level: "&a[points] Puntos requeridos hasta el siguiente
|
||||
nivel."
|
||||
deaths: "&c([number] Muertes)"
|
||||
cooldown: "&cDebes esperar &b[time] &csegundos para poder volver a hacer esto."
|
||||
in-progress: "&6El Calculo del nivel de la islas está en progreso..."
|
||||
time-out: "&cEl calculo del nivel de la isla está tardando. Intente más tarde."
|
||||
top:
|
||||
description: Muestra el top de islas
|
||||
gui-title: "&aTop diez"
|
||||
gui-heading: "&6[name]: &b[rank]"
|
||||
island-level: "&bNivel [level]"
|
||||
warp-to: "&aLlevándote a la isla de [name]"
|
||||
level-details:
|
||||
above-sea-level-blocks: Bloques sobre el nivel del mar
|
||||
spawners: Spawners
|
||||
underwater-blocks: Bloques debajo del nivel del mar
|
||||
all-blocks: Todos los bloques
|
||||
no-island: "&c¡Sin isla!"
|
||||
names-island: Isla de [name]
|
||||
syntax: "[name] x [number]"
|
||||
hint: "&cEscriba /level para ver el recuento de bloques"
|
||||
level:
|
||||
commands:
|
||||
value:
|
||||
parameters: "[hand|<material>]"
|
||||
description: muestra el valor de los bloques. Añade 'hand' al final para mostrar
|
||||
el valor del bloque de la mano.
|
||||
gui:
|
||||
titles:
|
||||
top: "&0&lTop de islas"
|
||||
detail-panel: "&0&lIsla de [name]"
|
||||
value-panel: "&0&l Valores de los Bloques"
|
||||
buttons:
|
||||
island:
|
||||
empty: "&f&l[name]. lugar"
|
||||
name: "&f&l[name]"
|
||||
description: |-
|
||||
[owner]
|
||||
[members]
|
||||
[place]
|
||||
[level]
|
||||
owners-island: Isla de [player]
|
||||
owner: "&7&l Dueño: &r&b[player]"
|
||||
members-title: "&7&l Miembros:"
|
||||
member: "&b - [player]"
|
||||
unknown: " desconocido"
|
||||
place: "&7&o [number]. &r&7lugar"
|
||||
level: "&7 Nivel: &o[number]"
|
||||
material:
|
||||
name: "&f&l[number] x [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[count]
|
||||
[value]
|
||||
[calculated]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 ID del bloque: &e[id]"
|
||||
value: "&7 Valor del bloque: &e[number]"
|
||||
limit: "&7 Limite de bloques: &e[number]"
|
||||
count: "&7 Número de bloques: &e[number]"
|
||||
calculated: "&7 Valor calculado: &e[number]"
|
||||
all_blocks:
|
||||
name: "&f&lTodos los bloques"
|
||||
description: |-
|
||||
&7 Muestra todos los
|
||||
&7 bloques en la isla.
|
||||
above_sea_level:
|
||||
name: "&f&lBloques sobre el nivel del mar"
|
||||
description: |-
|
||||
&7 Muestra solo bloques
|
||||
&7 que estén sobre el
|
||||
&7 nivel del mar.
|
||||
underwater:
|
||||
name: "&f&lBloques debajo del nivel del mar"
|
||||
description: |-
|
||||
&7 Muestra solo bloques
|
||||
&7 que estén debajo del
|
||||
&7 nivel del mar.
|
||||
spawner:
|
||||
name: "&f&lSpawners"
|
||||
description: "&7Mostrar solo spawners."
|
||||
filters:
|
||||
name:
|
||||
name: "&f&lOrdenar por nombre"
|
||||
description: "&7Ordenar todos los bloques por nombre."
|
||||
value:
|
||||
name: "&f&lOrdenar por valor"
|
||||
description: "&7Ordenar todos los bloques por valor."
|
||||
count:
|
||||
name: "&f&lOrdenar por cantidad"
|
||||
description: "&7Ordenar todos los bloques por cantidad."
|
||||
value:
|
||||
name: "&f&l [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[value]
|
||||
[underwater]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 ID de Bloque: &e [id]"
|
||||
value: "&7 Valor del Bloque: &e [number]"
|
||||
underwater: "&7 Por debajo del nivel del mar: &e [number]"
|
||||
limit: "&7 Límite de bloque: &e [number]"
|
||||
previous:
|
||||
name: "&f&lPágina anterior"
|
||||
description: "&7Cambiar a la página [number]"
|
||||
next:
|
||||
name: "&f&lSiguiente página"
|
||||
description: "&7Cambiar a la página [number]"
|
||||
search:
|
||||
name: "&f&l Buscar"
|
||||
description: |-
|
||||
&7 Buscar un determinado
|
||||
&7 valor.
|
||||
search: "&b Valor: [value]"
|
||||
tips:
|
||||
click-to-view: "&eClic &7para ver."
|
||||
click-to-previous: "&eClic &7 para ir a la página anterior."
|
||||
click-to-next: "&eClic &7 para ir a la siguiente página."
|
||||
click-to-select: "&eClic &7 para seleccionar."
|
||||
left-click-to-cycle-up: "&eClic izquierdo &7para ir hacia arriba."
|
||||
right-click-to-cycle-down: "&eClic derecho &7para ir hacia abajo."
|
||||
left-click-to-change: "&e Clic Izquierdo &7 para editar."
|
||||
right-click-to-clear: "&e Clic Derecho &7 para borrar."
|
||||
click-to-asc: "&e Clic &7 para ordenar de forma creciente."
|
||||
click-to-desc: "&e Clic &7 para ordenar de forma decreciente."
|
||||
click-to-warp: "&e Clic &7 para teletransportarse."
|
||||
click-to-visit: "&e Clic &7 para visitar."
|
||||
right-click-to-visit: "&e Clic Derecho &7 para visitar."
|
||||
conversations:
|
||||
prefix: "&l&6[BentoBox]: &r"
|
||||
no-data: "&cEscriba /level para ver el recuento de bloques."
|
||||
cancel-string: cancelar
|
||||
exit-string: cancelar, salir, abandonar
|
||||
write-search: "&e Introduce un valor de búsqueda. (Escribe 'cancel' para salir)"
|
||||
search-updated: "&a Valor de búsqueda actualizado."
|
||||
cancelled: "&c ¡Conversación cancelada!"
|
||||
no-value: "&c Ese ítem no tiene valor."
|
||||
unknown-item: "&c El '[material]' no existe en el juego."
|
||||
value: "&7 El valor de '[material]' es: &e[value]"
|
||||
value-underwater: "&7 El valor de '[material]' por debajo del nivel del mar: &e[value]"
|
||||
empty-hand: "&c No hay bloques en tu mano"
|
|
@ -0,0 +1,175 @@
|
|||
---
|
||||
admin:
|
||||
level:
|
||||
parameters: "<player>"
|
||||
description: calcule le niveau d'île d'un joueur
|
||||
sethandicap:
|
||||
parameters: "<player> <handicap>"
|
||||
description: définir le handicap de l'île, généralement le niveau de l'île de
|
||||
départ
|
||||
changed: "&a le handicap initial de l'île est passé de [number] à [new_number]."
|
||||
invalid-level: "&c Handicap non valide. Utilisez un nombre entier."
|
||||
levelstatus:
|
||||
description: affiche le nombre d'îles dans la file d'attente pour l'analyse
|
||||
islands-in-queue: "&a Nombre d'Îles dans la file d'attente: [number]"
|
||||
top:
|
||||
description: affiche le top 10 des îles
|
||||
unknown-world: "&cMonde inconnu."
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
remove:
|
||||
description: retire le joueur du top 10
|
||||
parameters: "<player>"
|
||||
island:
|
||||
level:
|
||||
parameters: "[joueur]"
|
||||
description: calcule le niveau de votre île ou affiche le niveau d'un [joueur]
|
||||
calculating: "&aCalcul du niveau en cours..."
|
||||
estimated-wait: "&a Attente estimée: [number] seconds"
|
||||
in-queue: "&a Vous êtes le numéro [number ] dans la file d'attente"
|
||||
island-level-is: "&aLe niveau d'île est &b[level]"
|
||||
required-points-to-next-level: "&a[points] points avant le prochain niveau"
|
||||
deaths: "&c([number] morts)"
|
||||
cooldown: "&cVous devez attendre &b[time] &csecondes avant de pouvoir refaire
|
||||
cette action"
|
||||
in-progress: "&6 Le calcul du niveau de l'île est en cours ..."
|
||||
time-out: "&c Le calcul du niveau a pris trop de temps. Veuillez réessayer plus
|
||||
tard."
|
||||
top:
|
||||
description: affiche le top 10
|
||||
gui-title: "&aTop 10"
|
||||
gui-heading: "&6[name]: &B[rank]"
|
||||
island-level: "&BNiveau [level]"
|
||||
warp-to: "&ATéléportation vers l'île de [name]"
|
||||
level-details:
|
||||
above-sea-level-blocks: Blocs au-dessus du niveau de la mer
|
||||
spawners: Spawners
|
||||
underwater-blocks: Blocs en-dessous du niveau de la mer
|
||||
all-blocks: Total des blocs
|
||||
no-island: "&c Pas d'île!"
|
||||
names-island: île de [name]
|
||||
syntax: "[name] x [number]"
|
||||
hint: "&c Exécuter level pour voir le rapport des blocs"
|
||||
level:
|
||||
commands:
|
||||
value:
|
||||
parameters: "[hand|<material>]"
|
||||
description: affiche la valeur des blocs. Ajoutez 'hand' à la fin pour afficher
|
||||
la valeur de l'objet en main.
|
||||
gui:
|
||||
titles:
|
||||
top: "&0&l Top Islands"
|
||||
detail-panel: "&0&l [name]'s island"
|
||||
value-panel: "&0&l Block Values"
|
||||
buttons:
|
||||
island:
|
||||
empty: "&f&l [name]. place"
|
||||
name: "&f&l [name]"
|
||||
description: |-
|
||||
[owner]
|
||||
[members]
|
||||
[place]
|
||||
[level]
|
||||
owners-island: "[player]'s Island"
|
||||
owner: "&7&l Propriétaire: &r&b [player]"
|
||||
members-title: "&7&l Membres:"
|
||||
member: "&b - [player]"
|
||||
unknown: inconnue
|
||||
place: "&7&o [number]. &r&7 place"
|
||||
level: "&7 Level: &o [number]"
|
||||
material:
|
||||
name: "&f&l [number] x [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[count]
|
||||
[value]
|
||||
[calculated]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 Block id: &e [id]"
|
||||
value: "&7 Block value: &e [number]"
|
||||
limit: "&7 Block limit: &e [number]"
|
||||
count: "&7 Nombre de blocs: &e [number]"
|
||||
calculated: "&7 Valeur calculée: &e [number]"
|
||||
all_blocks:
|
||||
name: "&f&l Tous les blocs"
|
||||
description: |-
|
||||
&7 Afficher tous les blocs
|
||||
&7 sur l'île.
|
||||
above_sea_level:
|
||||
name: "&f&l Blocs au-dessus du niveau de la mer"
|
||||
description: |-
|
||||
&7 Afficher uniquement les blocs
|
||||
&7 qui sont au-dessus du niveau
|
||||
&7 de la mer.
|
||||
underwater:
|
||||
name: "&f&l Blocs sous le niveau de la mer"
|
||||
description: |-
|
||||
&7 Afficher uniquement les blocs
|
||||
&7 situés sous le niveau
|
||||
&7 de la mer.
|
||||
spawner:
|
||||
name: "&f&l Spawners"
|
||||
description: "&7 Afficher uniquement les spawners."
|
||||
filters:
|
||||
name:
|
||||
name: "&f&l STrier par nom"
|
||||
description: "&7 Trier tous les blocs par nom."
|
||||
value:
|
||||
name: "&f&l Trier par valeur"
|
||||
description: "&7 Triez tous les blocs par leur valeur."
|
||||
count:
|
||||
name: "&f&l Trier par nombre"
|
||||
description: "&7 Trier tous les blocs par leur montant."
|
||||
value:
|
||||
name: "&f&l [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[value]
|
||||
[underwater]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 Block id: &e [id]"
|
||||
value: "&7 Block value: &e [number]"
|
||||
underwater: "&7 Sous le niveau de la mer : &e [number]"
|
||||
limit: "&7 Block limit: &e [number]"
|
||||
previous:
|
||||
name: "&f&l Page précédente"
|
||||
description: "&7 Passer à la page [number]"
|
||||
next:
|
||||
name: "&f&l Page suivante"
|
||||
description: "&7 Passer à la page [number]"
|
||||
search:
|
||||
name: "&f&l Rechercher"
|
||||
description: "&7 Recherche une valeur \n&7 spécifique."
|
||||
search: "&b Valeur : [value]"
|
||||
tips:
|
||||
click-to-view: "&e Cliquez &7 pour afficher."
|
||||
click-to-previous: "&e Cliquez &7 pour afficher la page précédente."
|
||||
click-to-next: "&e Cliquez &7 pour afficher la page suivante."
|
||||
click-to-select: "&e Cliquez &7 pour sélectionner."
|
||||
left-click-to-cycle-up: "&e Clic gauche &7 pour monter."
|
||||
right-click-to-cycle-down: "&e Clic droit &7 pour descendre."
|
||||
left-click-to-change: "&e Clic gauche &7 pour éditer."
|
||||
right-click-to-clear: "&e Clic droit &7 pour effacer."
|
||||
click-to-asc: "&e Cliquez &7 pour trier par ordre croissant."
|
||||
click-to-desc: "&e Cliquez &7 pour trier par ordre décroissant."
|
||||
click-to-warp: "&e Cliquer &7 to warp."
|
||||
click-to-visit: "&e Cliquer &7 pour visiter."
|
||||
right-click-to-visit: "&e Clic droit&7 pour visiter."
|
||||
conversations:
|
||||
prefix: "&l&6 [BentoBox]: &r"
|
||||
no-data: "&c Niveau d'exécution pour voir le rapport de blocage."
|
||||
cancel-string: annuler
|
||||
exit-string: annuler, sortir, quitter
|
||||
write-search: "&e Veuillez entrer une valeur de recherche. (Ecrivez 'cancel' pour
|
||||
quitter)"
|
||||
search-updated: "&a Valeur de recherche mise à jour."
|
||||
cancelled: "&c Conversation annulée !"
|
||||
no-value: "&c Cet item n'a aucune valeur."
|
||||
unknown-item: "&c Le '[material]' n'existe pas dans le jeu."
|
||||
value: "&7 La valeur de '[material]' est : &e[value]"
|
||||
value-underwater: "&7 La valeur de '[material]' sous le niveau de la mer : &e[value]"
|
||||
empty-hand: "&c Il n'y a pas de blocs dans votre main"
|
||||
meta:
|
||||
authors:
|
||||
'0': plagoutte
|
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
admin:
|
||||
level:
|
||||
parameters: "<player>"
|
||||
description: Egy játékos sziget szintjének kiszámítása
|
||||
sethandicap:
|
||||
parameters: "<játékos> <hátrány>"
|
||||
description: állítsa be a sziget hátrányát, általában a kezdő sziget szintjét
|
||||
changed: "&a A kezdeti sziget hátrány változott erről [number] erre [new_number]."
|
||||
invalid-level: "&c Érvénytelen hátrány. Használj egész számot."
|
||||
levelstatus:
|
||||
description: megmutatja, hogy hány sziget van a szkennelési sorban
|
||||
islands-in-queue: "&a Szigetek a sorban: [number]"
|
||||
top:
|
||||
description: Top Tíz lista megtekintése
|
||||
unknown-world: "&cIsmeretlen világ!"
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
remove:
|
||||
description: játékos törlése a Top Tízből
|
||||
parameters: "<játékos>"
|
||||
island:
|
||||
level:
|
||||
parameters: "[player]"
|
||||
description: A saját vagy más játékos sziget szintjének kiszámítása
|
||||
calculating: "&aSziget szint kiszámítása..."
|
||||
estimated-wait: "&a Becsült várakozás: [number] másodperc"
|
||||
in-queue: "&a Te vagy a(z) [number] a sorban"
|
||||
island-level-is: "&aA sziget szint: &b[level]"
|
||||
required-points-to-next-level: "&a[points] pont szükséges a következő szinthez."
|
||||
deaths: "&c([number] halál)"
|
||||
cooldown: "&cVárnod kell &b[time] &cmásodpercet, hogy újra használhasd."
|
||||
top:
|
||||
description: Top Tíz lista megtekintése
|
||||
gui-title: "&aTop Tíz"
|
||||
gui-heading: "&6[name]: &B[rank]"
|
||||
island-level: "&BLevel [level]"
|
||||
warp-to: "&ATeleportálás [name] szigetére."
|
||||
remove:
|
||||
description: játékos törlése a Top Tízből
|
||||
parameters: "<player>"
|
||||
level-details:
|
||||
above-sea-level-blocks: Tengerszint Feletti Blokkok
|
||||
spawners: Spawner-ek
|
||||
underwater-blocks: Víz Alatti Blokkok
|
||||
all-blocks: Minden Blokk
|
||||
no-island: "&c Nincs sziget!"
|
||||
names-island: "[name] szigete"
|
||||
syntax: "[name] x [number]"
|
||||
hint: "&c Futtassa a szintet a blokk jelentés megjelenítéséhez"
|
||||
value:
|
||||
description: Bármely blokk értékét mutatja
|
||||
success: "&7Ennek a blokknak az értéke: &e[value]"
|
||||
success-underwater: "&7Ennek a blokknak a tengerszint alatti értéke: &e[value]"
|
||||
empty-hand: "&cNincsenek blokkok a kezedben"
|
||||
no-value: "&cEnnek nincs értéke."
|
|
@ -0,0 +1,171 @@
|
|||
---
|
||||
admin:
|
||||
level:
|
||||
parameters: "<player>"
|
||||
description: hitung level pulau untuk pemain
|
||||
sethandicap:
|
||||
parameters: "<player> <handicap>"
|
||||
description: mengatur handicap pulau, biasanya level pulau pemula
|
||||
changed: "&a Handicap pulau awal diubah dari [number] menjadi [new_number]."
|
||||
invalid-level: "&c Handicap tidak valid. Gunakan angka bulat."
|
||||
levelstatus:
|
||||
description: menunjukkan berapa banyak pulau dalam antrian untuk pemindaian
|
||||
islands-in-queue: "&a Pulau di dalam antrian: [number]"
|
||||
top:
|
||||
description: menunjukkan daftar sepuluh besar
|
||||
unknown-world: "&c Dunia tidak ditemukan!"
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
remove:
|
||||
description: menghapus pemain dari sepuluh besar
|
||||
parameters: "<player>"
|
||||
island:
|
||||
level:
|
||||
parameters: "[player]"
|
||||
description: hitung level pulau kamu atau melihat level [player]
|
||||
calculating: "&a Menghitung level..."
|
||||
estimated-wait: "&a Perkiraan menunggu: [number] detik"
|
||||
in-queue: "&a Kamu berada pada antrian nomor [number]"
|
||||
island-level-is: "&a Level pulau adalah &b[level]"
|
||||
required-points-to-next-level: "&a [points] poin dibutuhkan hingga level selanjutnya"
|
||||
deaths: "&c([number] kematian)"
|
||||
cooldown: "&c Kamu harus menunggu &b[time] &c detik sebelum kamu dapat melakukannya
|
||||
lagi"
|
||||
in-progress: "&6 Perhitungan level pulau sedang dijalankan..."
|
||||
time-out: "&c Perhitungan level pulau terlalu lama. Coba lagi nanti."
|
||||
top:
|
||||
description: menunjukkan Sepuluh Besar
|
||||
gui-title: "&a Sepuluh Besar"
|
||||
gui-heading: "&6[name]: &B[rank]"
|
||||
island-level: "&b Level [level]"
|
||||
warp-to: "&A Warp ke pulau [name]"
|
||||
level-details:
|
||||
above-sea-level-blocks: Blok di atas permukaan laut
|
||||
spawners: Spawner
|
||||
underwater-blocks: Blok di bawah permukaan laut
|
||||
all-blocks: Semua blok
|
||||
no-island: "&c Tidak ada pulau!"
|
||||
names-island: Pulau [name]
|
||||
syntax: "[name] x [number]"
|
||||
hint: "&c Jalankan perintah level untuk melihat laporan blok"
|
||||
level:
|
||||
commands:
|
||||
value:
|
||||
parameters: "[hand|<material>]"
|
||||
description: menunjukkan nilai blok. Tambah 'hand' di akhir untuk menjukkan
|
||||
nilai item di tangan.
|
||||
gui:
|
||||
titles:
|
||||
top: "&0&l Pulau Terbaik"
|
||||
detail-panel: "&0&l Pulau [name]"
|
||||
value-panel: "&0&l Nilai Blok"
|
||||
buttons:
|
||||
island:
|
||||
empty: "&f&l [name]. place"
|
||||
name: "&f&l [name]"
|
||||
description: |-
|
||||
[owner]
|
||||
[members]
|
||||
[place]
|
||||
[level]
|
||||
owners-island: Pulau [player]
|
||||
owner: "&7&l Pemilik: &r&b [player]"
|
||||
members-title: "&7&l Anggota:"
|
||||
member: "&b - [player]"
|
||||
unknown: tidak diketahui
|
||||
place: "&r&7Peringkat &7&o [number]."
|
||||
level: "&7 Level: &o [number]"
|
||||
material:
|
||||
name: "&f&l [number] x [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[count]
|
||||
[value]
|
||||
[calculated]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 Id blok: &e [id]"
|
||||
value: "&7 Nilai blok: &e [number]"
|
||||
limit: "&7 Batas blok: &e [number]"
|
||||
count: "&7 Jumlah blok: &e [number]"
|
||||
calculated: "&7 Nilai yang dihitung: &e [number]"
|
||||
all_blocks:
|
||||
name: "&f&l Semua blok"
|
||||
description: |-
|
||||
&7 Tampilkan semua blok
|
||||
&7 di pulau.
|
||||
above_sea_level:
|
||||
name: "&f&l Blok Diatas Permukaan Laut"
|
||||
description: |-
|
||||
&7 Hanya mengampilkan blok
|
||||
&7 yang berada di atas
|
||||
&7 permukaan laut.
|
||||
underwater:
|
||||
name: "&f&l Blok Di bawah Permukaan Laut"
|
||||
description: |-
|
||||
&7 Hanya menampilkan blok
|
||||
&7 yang berada di bawah
|
||||
&7 permukaan laut.
|
||||
spawner:
|
||||
name: "&f&l Spawner"
|
||||
description: "&7 Hanya tampilkan spawner."
|
||||
filters:
|
||||
name:
|
||||
name: "&f&l Urut berdasarkan Nama"
|
||||
description: "&7 Mengurutkan semua blok berdasarkan nama."
|
||||
value:
|
||||
name: "&f&l Urut berdasarkan Nilai"
|
||||
description: "&7 Mengurutkan semua blok berdasarkan nilainya."
|
||||
count:
|
||||
name: "&f&l Urut berdasarkan Jumlah"
|
||||
description: "&7 Mengurutkan semua blok berdasarkan jumlahnya."
|
||||
value:
|
||||
name: "&f&l [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[value]
|
||||
[underwater]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 Id blok: &e [id]"
|
||||
value: "&7 Nilai blok: &e [number]"
|
||||
underwater: "&7 Dibawah permukaan laut: &e [number]"
|
||||
limit: "&7 Batas block: &e [number]"
|
||||
previous:
|
||||
name: "&f&l Halaman sebelumnya"
|
||||
description: "&7 Beralih ke halaman [number]"
|
||||
next:
|
||||
name: "&f&l Halaman selanjutnya"
|
||||
description: "&7 Beralih ke halaman [number]"
|
||||
search:
|
||||
name: "&f&l Cari"
|
||||
description: |-
|
||||
&7 Mencari nilai yang
|
||||
&7 spesifik.
|
||||
search: "&b Nilai: [value]"
|
||||
tips:
|
||||
click-to-view: "&e Klik &7 untuk melihat."
|
||||
click-to-previous: "&e Klik &7 untuk melihat halaman sebelumnya."
|
||||
click-to-next: "&e Klik &7 untuk melihat halaman selanjutnya."
|
||||
click-to-select: "&e Klik &7 untuk memilih."
|
||||
left-click-to-cycle-up: "&e Klik Kiri &7 untuk memutar ke atas."
|
||||
right-click-to-cycle-down: "&e Klik Kanan &7 memutar ke bawah."
|
||||
left-click-to-change: "&e Klik Kiri &7 untuk mengubah."
|
||||
right-click-to-clear: "&e Klik Kanan &7 untuk membersihkan."
|
||||
click-to-asc: "&e Klik &7 untuk mengurutkan dalam urutan menaik."
|
||||
click-to-desc: "&e Klik &7 untuk mengurutkan dalam urutan menurun."
|
||||
click-to-warp: "&e Klik &7 untuk warp."
|
||||
click-to-visit: "&e Klik &7 untuk mengunjungi."
|
||||
right-click-to-visit: "&e Klik Kanan &7 untuk mengunjungi."
|
||||
conversations:
|
||||
prefix: "&l&6 [BentoBox]: &r"
|
||||
no-data: "&c Jalankan perintah level untuk melihat laporan blok"
|
||||
cancel-string: batal
|
||||
exit-string: batal, keluar, berhenti
|
||||
write-search: "&e Tolong masukkan pencarian nilai. (Ketik 'batal' untuk keluar)"
|
||||
search-updated: "&a Nilai pencarian diperbarui."
|
||||
cancelled: "&c Percakapan dibatalkan!"
|
||||
no-value: "&c Item itu tidak ada nilai."
|
||||
unknown-item: "&c '[material]' tidak ada di dalam permainan."
|
||||
value: "&7 Nilai dari '[material]' adalah: &e[value]"
|
||||
value-underwater: "&7Nilai dari '[material]' di bawah permukaan laut: &e[value]"
|
||||
empty-hand: "&c Tidak ada blok di tangan mu"
|
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
admin:
|
||||
level:
|
||||
parameters: "<player>"
|
||||
description: 플레이어의 섬레벨을 계산합니다
|
||||
sethandicap:
|
||||
parameters: "<플레이어> <핸디캡>"
|
||||
description: 섬 핸디캡을 설정하십시오. 일반적으로 시작 섬의 레벨
|
||||
changed: "& a 초기 아일랜드 핸디캡이 [번호]에서 [new_number] (으)로 변경되었습니다."
|
||||
invalid-level: "& c 잘못된 핸디캡. 정수를 사용하십시오."
|
||||
levelstatus:
|
||||
description: 스캔 대기열에 몇 개의 섬이 있는지 표시
|
||||
islands-in-queue: "& a 대기열에있는 섬 : [번호]"
|
||||
top:
|
||||
unknown-world: "& c 알수없는 월드 입니다"
|
||||
display: "&f[rank]. &a[name] &7-&b[level]"
|
||||
remove:
|
||||
description: 탑 10에서 플레이어를 제거합니다
|
||||
parameters: "<플레이어>"
|
||||
island:
|
||||
level:
|
||||
parameters: "[플레이어]"
|
||||
description: 섬 레벨을 계산하거나 [플레이어]의 섬레벨을 보여줍니다
|
||||
calculating: "&a 계산중....\n"
|
||||
estimated-wait: "&a예상 대기 시간 : [번호] 초"
|
||||
in-queue: "& a 당신은 대기열에있는 숫자 [번호]입니다"
|
||||
island-level-is: "& a 섬 레벨은 & b [level]"
|
||||
required-points-to-next-level: "&a [point] 다음 레벨까지 요구되는 경험치"
|
||||
deaths: "&c ([number] 사망)"
|
||||
cooldown: "&c그것을 다시하려면 &b[time]초&c를 기다려야합니다."
|
||||
top:
|
||||
description: 탑 10을 보여줍니다
|
||||
gui-title: "&a 탑 10"
|
||||
gui-heading: "&6 [name] : &B[rank]"
|
||||
island-level: "&b 레벨 [level]"
|
||||
warp-to: "&a[name]님의 섬으로 이동중입니다.."
|
||||
level-details:
|
||||
above-sea-level-blocks: 해발 블록
|
||||
spawners: 스포너
|
||||
underwater-blocks: 수중 블록
|
||||
all-blocks: 모든 블록
|
||||
no-island: "&c 섬이 없습니다."
|
||||
names-island: "[name]의 섬"
|
||||
syntax: "[name] x [number]"
|
||||
hint: "&c 블록 리포트를 보려면 레벨을 해야합니다."
|
||||
value:
|
||||
description: 모든 블록의 값을 보여줍니다
|
||||
success: "&7이 블록의 값은 &e [value]입니다."
|
||||
success-underwater: "&7 해수면 아래의 블록 값 : &e [value]"
|
||||
empty-hand: "& c 손에 블록이 없습니다"
|
||||
no-value: "&c 해당 항목에는 가치가 없습니다."
|
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
admin:
|
||||
level:
|
||||
description: aprēķina spēlētāja salas līmeni
|
||||
parameters: "<spēlētājs>"
|
||||
top:
|
||||
description: rādīt labākās 10 salas
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
unknown-world: "&cNezināma pasaule!"
|
||||
remove:
|
||||
description: noņemt spēlētāju no labāko desmit saraksta
|
||||
parameters: "<spēlētājs>"
|
||||
island:
|
||||
level:
|
||||
calculating: "&aAprēķina līmeni..."
|
||||
cooldown: "&cTev ir jāuzgaida &b[time]&c sekundes, lai vēlreiz aprēķinātu salas
|
||||
līmeni!"
|
||||
deaths: "&c([number] nāves)"
|
||||
description: aprēķina tavas salas līmeni, vai parāda spēlētāja [player] līmeni
|
||||
island-level-is: "&aSalas līmenis ir &b[level]"
|
||||
parameters: "[player]"
|
||||
required-points-to-next-level: "&aNepieciešami [points] punkti, lai sasniegtu
|
||||
nākošo līmeni"
|
||||
top:
|
||||
description: rādīt labākos 10
|
||||
gui-heading: "&6[name]: &B[rank]"
|
||||
gui-title: "&aLabākie 10"
|
||||
island-level: "&BLīmenis [level]"
|
||||
warp-to: "&APārvietoties uz [name] salu."
|
||||
value:
|
||||
description: rādīt vērtību jebkuram blokam
|
||||
empty-hand: "&cTev nav bloks rokās."
|
||||
no-value: "&cŠim blokam/priekšmetam nav vērtības."
|
||||
success: "&7Vērtība šim blokam ir: &e[value]"
|
||||
success-underwater: "&7Vērtība šim blokam zem jūras līmeņa: &e[value]"
|
|
@ -0,0 +1,165 @@
|
|||
---
|
||||
admin:
|
||||
level:
|
||||
parameters: "<speler>"
|
||||
description: bereken het eiland level voor een speler
|
||||
sethandicap:
|
||||
parameters: "<speler> <handicap>"
|
||||
description: stel handicap in voor het eiland, normaal gesproken het level van
|
||||
het starter eiland.
|
||||
changed: "&a Initiële handicap is veranderd van [number] naar [new_number]."
|
||||
invalid-level: "&c Ongeldige handicap. Gebruik een getal."
|
||||
levelstatus:
|
||||
description: laat zien hoeveel eilanden er in de wachtrij staan voor het scannen
|
||||
islands-in-queue: "&a Aantal eilanden in de wachtrij: [number]"
|
||||
top:
|
||||
description: Laat de top tien zien
|
||||
unknown-world: "&c Ongeldige wereld!"
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
remove:
|
||||
description: verwijder speler van de top tien
|
||||
parameters: "<speler>"
|
||||
island:
|
||||
level:
|
||||
parameters: "[speler]"
|
||||
description: bereken het eiland level voor [player]
|
||||
calculating: "&a Level aan het berekenen..."
|
||||
estimated-wait: "&a Verwachtte wachttijd: [number] seconde"
|
||||
in-queue: "&a Jij staat op plek [number] in de wachtrij"
|
||||
island-level-is: "&a Eiland level is &b[level]"
|
||||
required-points-to-next-level: "&a [points] punten nodig voor het volgende level"
|
||||
deaths: "&c([number] doodgegaan)"
|
||||
cooldown: "&c Je moet nog &b[time] &c seconden wachten tot je dit weer kan doen."
|
||||
in-progress: "&6 Eiland level wordt berekend..."
|
||||
time-out: "&c De level berekening duurde te lang. Probeer het later opnieuw."
|
||||
top:
|
||||
description: Toon de Top tien
|
||||
gui-title: "&a Top tien"
|
||||
gui-heading: "&6[name]: &B[rank]"
|
||||
island-level: "&b Level [level]"
|
||||
warp-to: "&A Teleporteren naar [name]'s eiland"
|
||||
level-details:
|
||||
above-sea-level-blocks: 'Blokken boven zeeniveau '
|
||||
spawners: Monsterkooien
|
||||
underwater-blocks: Blokken onder zeeniveau
|
||||
all-blocks: Alle blokken
|
||||
no-island: "&c Geen eiland!"
|
||||
names-island: "[name]'s eiland"
|
||||
syntax: "[name] x [number]"
|
||||
hint: "&c Gebruik level om het blokkenrapport te zien"
|
||||
level:
|
||||
commands:
|
||||
value:
|
||||
parameters: "[hand|<type>]"
|
||||
description: toont de waarde van blokken. Voeg 'hand' toe aan het einde om de
|
||||
waarde te laten zien van het item in je hand.
|
||||
gui:
|
||||
titles:
|
||||
top: "&0&l Top eilanden"
|
||||
detail-panel: "&0&l [name]'s eiland"
|
||||
value-panel: "&0&l Blok waardes"
|
||||
buttons:
|
||||
island:
|
||||
empty: "&f&l [name]. plaats"
|
||||
name: "&f&l [name]"
|
||||
description: |-
|
||||
[owner]
|
||||
[members]
|
||||
[place]
|
||||
[level]
|
||||
owners-island: "[player]'s Eiland"
|
||||
owner: "&7&l Eigenaar: &r&b [player]"
|
||||
members-title: "&7&l Leden:"
|
||||
member: "&b - [player]"
|
||||
unknown: onbekend
|
||||
place: "&7&o [number]. &r&7 plaats"
|
||||
level: "&7 Level: &o [number]"
|
||||
material:
|
||||
name: "&f&l [number] x [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[count]
|
||||
[value]
|
||||
[calculated]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 Blok id: &e [id]"
|
||||
value: "&7 Block waarde: &e [number]"
|
||||
limit: "&7 Block limiet: &e [number]"
|
||||
count: "&7 Aantal blokken: &e [number]"
|
||||
calculated: "&7 Berekende waarde: &e [number]"
|
||||
all_blocks:
|
||||
name: "&f&l Alle Blokken"
|
||||
description: "&7 Toon alle blokken \n&7 op het eiland."
|
||||
above_sea_level:
|
||||
name: "&f&l Blokken boven zeeniveau"
|
||||
description: |-
|
||||
&7 Toon alleen blokken
|
||||
&7 die boven zeeniveau zijn
|
||||
underwater:
|
||||
name: "&f&l Blokken onder zeeniveau"
|
||||
description: |-
|
||||
&7 Toon alleen blokken
|
||||
&7 die onder zeeniveau zijn
|
||||
spawner:
|
||||
name: "&f&l Monsterkooien"
|
||||
description: "&7 Toon alleen monsterkooien."
|
||||
filters:
|
||||
name:
|
||||
name: "&f&l Sorteer aan de hand van naam"
|
||||
description: "&7 Sorteer alle blokken aan de hand van naam."
|
||||
value:
|
||||
name: "&f&l Sorteer aan de hand van waarde"
|
||||
description: "&7 Sorteer alle blokken aan de hand van waarde."
|
||||
count:
|
||||
name: "&f&l Sorteer aan de hand van aantal"
|
||||
description: "&7 Sorteer alle blokken aan de hand van aantal."
|
||||
value:
|
||||
name: "&f&l [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[value]
|
||||
[underwater]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 Blok id: &e [id]"
|
||||
value: "&7 Block waarrde: &e [number]"
|
||||
underwater: "&7 Onder zeeniveau: &e [number]"
|
||||
limit: "&7 Blok limiet: &e [number]"
|
||||
previous:
|
||||
name: "&f&l Vorige pagina"
|
||||
description: "&7 Ga naar pagina [number]"
|
||||
next:
|
||||
name: "&f&l Volgende pagina"
|
||||
description: "&7 Ga naar pagina [number]"
|
||||
search:
|
||||
name: "&f&l Zoek"
|
||||
description: "&7 Zoek voor een \n&7 specifieke waarde."
|
||||
search: "&b Waarde: [value]"
|
||||
tips:
|
||||
click-to-view: "&e Klik &7 om te zien."
|
||||
click-to-previous: "&e Klik &7 om de vorige pagina te zien."
|
||||
click-to-next: "&e Klik &7 om de volgende pagina te zien."
|
||||
click-to-select: "&e Klik &7 om te selecteren."
|
||||
left-click-to-cycle-up: "&e Linker Klik &7 om door te lopen."
|
||||
right-click-to-cycle-down: "&e Rechter Klik &7 om terug door te lopen."
|
||||
left-click-to-change: "&e Linker Klik &7 om bij te werken."
|
||||
right-click-to-clear: "&e Linker Klik &7 om te verwijderen."
|
||||
click-to-asc: "&e Klik &7 om te toenemend te sorteren."
|
||||
click-to-desc: "&e Klik &7 om te afnemenend te sorteren."
|
||||
click-to-warp: "&e Klik &7 om te teleporteren."
|
||||
click-to-visit: "&e Klik &7 om te bezoeken."
|
||||
right-click-to-visit: "&e Rechter Klik &7 om te bezoeken."
|
||||
conversations:
|
||||
prefix: "&l&6 [BentoBox]: &r"
|
||||
no-data: "&c Gebruik level om het blokkenrapport te zien."
|
||||
cancel-string: stop
|
||||
exit-string: stop
|
||||
write-search: "&e Schrijf een zoekopdracht. (Schrijf 'stop' om te zoeken)"
|
||||
search-updated: "&a Zoekopdracht bijgewerkt."
|
||||
cancelled: "&c Conversatie gestopt!"
|
||||
no-value: "&c Dit item heeft geen waarde."
|
||||
unknown-item: "&c '[material]' bestaat niet in het spel."
|
||||
value: "&7 De waarde van '[material]' is: &e[value]"
|
||||
value-underwater: "&7 The waarde van '[material]' onder zeeniveau: &e[value]"
|
||||
empty-hand: "&c Je hebt geen blok vast"
|
|
@ -0,0 +1,171 @@
|
|||
---
|
||||
admin:
|
||||
level:
|
||||
parameters: "<player>"
|
||||
description: oblicza poziom wyspy
|
||||
sethandicap:
|
||||
parameters: "<gracz> <uposledzenie>"
|
||||
description: ustawić 0 poziom wyspy, zwykle poziom wyspy startowej
|
||||
changed: "&a Początkowy poziom wysp został zmieniony z [number] na [new_number]."
|
||||
invalid-level: "&c Nieprawidłowy poziom. Użyj liczby całkowitej."
|
||||
levelstatus:
|
||||
description: pokazuje ile wysp znajduje się w kolejce do skanowania
|
||||
islands-in-queue: "&a Wyspy w kolejce: [number]"
|
||||
top:
|
||||
description: pokazuje Top 10 wysp
|
||||
unknown-world: "&cNieznany świat!"
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
remove:
|
||||
description: usuwa gracza z Top 10
|
||||
parameters: "<gracz>"
|
||||
island:
|
||||
level:
|
||||
parameters: "[player]"
|
||||
description: oblicza poziom wyspy lub pokazać poziom [player]
|
||||
calculating: "&aObliczanie poziomu wyspy..."
|
||||
estimated-wait: "&a Szacowany czas: [number] sekund"
|
||||
in-queue: "&a Jestes numerem [number] w kolejce"
|
||||
island-level-is: "&aPoziom wyspy wynosi &b[level]"
|
||||
required-points-to-next-level: "&aPozostało [points] punktów do następnego poziomu"
|
||||
deaths: "&c([number] śmierci)"
|
||||
cooldown: "&cMusisz zaczekać &b[time] &csekund przed następnym obliczeniem poziomu"
|
||||
in-progress: "&6 Trwa obliczanie poziomu twojej wyspy..."
|
||||
time-out: "&c Sprawdzanie poziomu twojej wyspy trwalo zbyt dlugo. Sprobuj ponownie
|
||||
pozniej!"
|
||||
top:
|
||||
description: pokauje Top 10 wysp
|
||||
gui-title: "&aTop 10"
|
||||
gui-heading: "&6[name]: &B[rank]"
|
||||
island-level: "&BPoziom [level]"
|
||||
warp-to: "&ATeleportowanie do wyspy [name]"
|
||||
level-details:
|
||||
above-sea-level-blocks: Bloki nad poziomem morza
|
||||
spawners: Spawnery
|
||||
underwater-blocks: Podwodne bloki
|
||||
all-blocks: Wszystkie bloki
|
||||
no-island: "&c Brak wyspy!"
|
||||
names-island: Wyspa gracza [name]
|
||||
syntax: "[name] x [number]"
|
||||
hint: "&c Uruchom poziom, aby wyświetlić raport o blokach"
|
||||
level:
|
||||
commands:
|
||||
value:
|
||||
parameters: "[hand|<materiał>]"
|
||||
description: pokazuje wartość bloków. Dodaj „hand” na końcu, aby wyświetlić
|
||||
wartość pozycji w ręku.
|
||||
gui:
|
||||
titles:
|
||||
top: "&0&l Najlepsze wyspy"
|
||||
detail-panel: "&0&l Wyspa gracza [name] "
|
||||
value-panel: "&0&l Wartości bloków"
|
||||
buttons:
|
||||
island:
|
||||
empty: "&f&l [name]. miejsce"
|
||||
name: "&f&l [name]"
|
||||
description: |-
|
||||
[owner]
|
||||
[members]
|
||||
[place]
|
||||
[level]
|
||||
owners-island: wyspa gracza [player]
|
||||
owner: "&7&l Lider: &r&b [player]"
|
||||
members-title: "&7&l Członkowie:"
|
||||
member: "&b - [player]"
|
||||
unknown: nieznany
|
||||
place: "&7&o [number]. &r&7 miejsce"
|
||||
level: "&7 Poziom: &o [number]"
|
||||
material:
|
||||
name: "&f&l [number] x [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[count]
|
||||
[value]
|
||||
[calculated]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 Identyfikator bloku: &e [id]"
|
||||
value: "&7 Wartość bloku: &e [number]"
|
||||
limit: "&7 Limit bloków: &e [number]"
|
||||
count: "&7 Numer bloku: &e [number]"
|
||||
calculated: "&7 Obliczona wartość: &e [number]"
|
||||
all_blocks:
|
||||
name: "&f&l Wszystkie bloki"
|
||||
description: |-
|
||||
&7 Wyświetl wszystkie bloki
|
||||
&7 na wyspie.
|
||||
above_sea_level:
|
||||
name: "&f&l Bloki nad poziomem morza"
|
||||
description: |-
|
||||
&7 Wyświetlaj tylko bloki
|
||||
&7 które są nad poziomem
|
||||
&7 morza
|
||||
underwater:
|
||||
name: "&f&l Bloki pod poziomem morza"
|
||||
description: |-
|
||||
&7 Wyświetlaj tylko bloki
|
||||
&7 ponad poziomem morza
|
||||
spawner:
|
||||
name: "&f&l Spawnery"
|
||||
description: "&7 Wyświetlaj tylko spawnery."
|
||||
filters:
|
||||
name:
|
||||
name: "&f&l Sortuj według nazwy"
|
||||
description: "&7 Sortuj wszystkie bloki według nazwy."
|
||||
value:
|
||||
name: "&f&l Sortuj według wartości"
|
||||
description: "&7 Sortuj wszystkie bloki według ich wartości."
|
||||
count:
|
||||
name: "&f&l Sortuj według liczby"
|
||||
description: "&7 Sortuj wszystkie bloki według ich ilości."
|
||||
value:
|
||||
name: "&f&l [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[value]
|
||||
[underwater]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 Identyfikator bloku: &e [id]"
|
||||
value: "&7 Wartość bloku: &e [number]"
|
||||
underwater: "&7 Poniżej poziomu morza: &e [number]"
|
||||
limit: "&7 Limit bloku: &e [number]"
|
||||
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]"
|
||||
search:
|
||||
name: "&f&l Szukaj"
|
||||
description: |-
|
||||
&7 Wyszukaj konkretną
|
||||
&7 wartość.
|
||||
search: "&b Wartość: [value]"
|
||||
tips:
|
||||
click-to-view: "&e Kliknij &7, aby wyświetlić."
|
||||
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-select: "&e Kliknij &7, aby wybrać."
|
||||
left-click-to-cycle-up: "&e Kliknij lewym przyciskiem &7, aby przejść w górę."
|
||||
right-click-to-cycle-down: "&e Kliknij prawym przyciskiem &7, aby przejść w
|
||||
dół."
|
||||
left-click-to-change: "&e Kliknij lewym przyciskiem &7, aby edytować."
|
||||
right-click-to-clear: "&e Kliknij prawym przyciskiem &7, aby wyczyścić."
|
||||
click-to-asc: "&e Kliknij &7, aby posortować w porządku rosnącym."
|
||||
click-to-desc: "&e Kliknij &7, aby posortować w porządku malejącym."
|
||||
click-to-warp: "&e Kliknij&7, aby przenieść"
|
||||
click-to-visit: "&e Kliknij&7, aby odwiedzić"
|
||||
right-click-to-visit: "&e Kliknij prawym przyciskiem &7, aby odwiedzić."
|
||||
conversations:
|
||||
prefix: "&l&6 [BentoBox]: &r"
|
||||
no-data: "&c Wykonaj sprawdzenie poziomu, przed raportem bloków"
|
||||
cancel-string: anuluj
|
||||
exit-string: cancel, exit, quit, anuluj
|
||||
write-search: "&e Wprowadź wartość wyszukiwania. (Napisz „anuluj”, aby wyjść)"
|
||||
search-updated: "&a Zaktualizowano wartość wyszukiwania."
|
||||
cancelled: "&c Rozmowa została anulowana!"
|
||||
no-value: "&c Ten element nie ma wartości."
|
||||
unknown-item: "&c „[material]” nie istnieje w grze."
|
||||
value: "&7 Wartość '[material]' to: &e[value]"
|
||||
value-underwater: "&7 Wartość „[material]” poniżej poziomu morza: &e[value]"
|
||||
empty-hand: "&c W twojej ręce nie ma bloków"
|
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
admin:
|
||||
level:
|
||||
parameters: "<player>"
|
||||
description: calcula o nível da ilha para o jogador
|
||||
sethandicap:
|
||||
parameters: "<player> <handicap>"
|
||||
description: Define o handicap da ilha. É geralmente o nível da ilha inicial.
|
||||
changed: "&a O handicap inicial da ilha foi alterado de [number] para [new_number]."
|
||||
invalid-level: "&c Handicap inválido. Use um número inteiro."
|
||||
levelstatus:
|
||||
description: mostrar quantas ilhas estão na fila para escaneamento.
|
||||
islands-in-queue: "&a Ilhas na fila: [number]"
|
||||
top:
|
||||
description: Mostra a lista dos dez primeiros
|
||||
unknown-world: "&c Mundo desconhecido!"
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
remove:
|
||||
description: Remover jogador do Top 10
|
||||
parameters: "<player>"
|
||||
island:
|
||||
level:
|
||||
parameters: "[player]"
|
||||
description: Calcula o nível da sua ilha ou mostra o nível de [player]
|
||||
calculating: "&a Calculando level..."
|
||||
estimated-wait: "&a Espera estimada: [number] segundos."
|
||||
in-queue: "&a Você é o número [number] na fila."
|
||||
island-level-is: "& O nível da ilha é&b [level]"
|
||||
required-points-to-next-level: "&a [pontos] pontos são necessários para chegar
|
||||
o próximo nível"
|
||||
deaths: "&c([number] mortes)"
|
||||
cooldown: "&c Você deve esperar &b [time] &c segundos até que possa fazer isso
|
||||
novamente."
|
||||
in-progress: "&6 Calculando o nível da ilha..."
|
||||
time-out: "&c O cálculo do nível demorou muito. Por favor, tente novamente mais
|
||||
tarde."
|
||||
top:
|
||||
description: Mostra os dez melhores
|
||||
gui-title: "&a Top 10"
|
||||
gui-heading: "&6[name]: &B[rank]"
|
||||
island-level: "&b Level [level]"
|
||||
warp-to: "&a Teletransportando para a ilha de [name]"
|
||||
level-details:
|
||||
above-sea-level-blocks: Blocos acima do nível do mar
|
||||
spawners: Spawners
|
||||
underwater-blocks: Blocos Subaquáticos
|
||||
all-blocks: Todos os blocos
|
||||
no-island: "&c Sem ilha!"
|
||||
names-island: Ilha de [name]
|
||||
syntax: "[name] x [number]"
|
||||
hint: "&c Executa o nível para ver o relatório de blocos."
|
||||
value:
|
||||
description: Mostra o valor de qualquer bloco
|
||||
success: "&7 O valor deste bloco é: &e [value]"
|
||||
success-underwater: "& 7O valor deste bloco abaixo do nível do mar: &e [value]"
|
||||
empty-hand: "&c Não há blocos em sua mão."
|
||||
no-value: "&c Item sem valor."
|
|
@ -0,0 +1,37 @@
|
|||
###########################################################################################
|
||||
# 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 #
|
||||
###########################################################################################
|
||||
|
||||
admin:
|
||||
level:
|
||||
parameters: "<player>"
|
||||
description: "Bir oyuncunun ada seviyesini hesapla"
|
||||
top:
|
||||
description: "Ilk 10 adayı sırala"
|
||||
unknown-world: "&cBilinmeyen kelime"
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
|
||||
island:
|
||||
level:
|
||||
parameters: "[player]"
|
||||
description: "&7Kendi ada seviyeni hesapla veya başka oyuncunun ada seviyesini öğren"
|
||||
calculating: "&aLevel hesaplanıyor..."
|
||||
island-level-is: "&7Ada seviyesi &b[level]"
|
||||
required-points-to-next-level: "&7Adayı yükseltmek için &a[points] &7Puan gerekiyor"
|
||||
deaths: "&c(Ölümler: [number])"
|
||||
cooldown: "&7Bunu tekrar yapmak için &b[time] &7beklemelisin"
|
||||
|
||||
top:
|
||||
description: "Ilk 10 adayı sırala"
|
||||
gui-title: "&aIlk 10 Ada"
|
||||
gui-heading: "&6Sıralama: &3[rank]"
|
||||
island-level: "&7Seviye: &a[level]"
|
||||
warp-to: "&a[name] &7oyuncusunun adasına ışınlanıyor"
|
||||
|
||||
value:
|
||||
description: "Herhangi bir bloğun değerini gösterir"
|
||||
success: "&7Bu bloğun değeri: &e[value]"
|
||||
success-underwater: "&7Deniz seviyesinin altındaki bu bloğun değeri: &e[value]"
|
||||
empty-hand: "&cElinde hiç blok yok"
|
||||
no-value: "&cBu eşyanın bir değeri yok."
|
|
@ -0,0 +1,184 @@
|
|||
---
|
||||
admin:
|
||||
level:
|
||||
parameters: "<player>"
|
||||
description: розрахувати рівень острова для гравця
|
||||
sethandicap:
|
||||
parameters: "<player> <handicap>"
|
||||
description: встановити гандикап острова, як правило, рівень острова стартера
|
||||
changed: "&a Початковий гандикап острова змінено з [number] на [new_number]."
|
||||
invalid-level: "&c Недійсний гандикап. Використовуйте ціле число."
|
||||
levelstatus:
|
||||
description: показати, скільки островів у черзі на сканування
|
||||
islands-in-queue: "&a Острови в черзі: [number]"
|
||||
top:
|
||||
description: показати першу десятку списку
|
||||
unknown-world: "&c Невідомий світ!"
|
||||
display: "&f[rank]. &a[name] &7- &b[level]"
|
||||
remove:
|
||||
description: видалити гравця з першої десятки
|
||||
parameters: "<player>"
|
||||
stats:
|
||||
description: показати статистику островів на цьому сервері
|
||||
title: Статистика острова сервера
|
||||
world: "&a [name]"
|
||||
no-data: "&c Немає даних для обробки."
|
||||
average-level: 'Середній рівень острова: [number]'
|
||||
median-level: 'Середній рівень острова: [number]'
|
||||
mode-level: 'Рівень острова режиму: [number]'
|
||||
highest-level: 'Найвищий рівень острова: [number]'
|
||||
lowest-level: 'Найнижчий рівень острова: [number]'
|
||||
distribution: 'Розподіл на рівні острова:'
|
||||
islands: острови
|
||||
island:
|
||||
level:
|
||||
parameters: "[player]"
|
||||
description: обчисліть свій рівень острова або покажіть рівень [player]
|
||||
calculating: "&a Розрахунок рівня..."
|
||||
estimated-wait: "&a Приблизне очікування: [number] секунд"
|
||||
in-queue: "&a Ви номер [number] у черзі"
|
||||
island-level-is: "&a Рівень острова &b[level]"
|
||||
required-points-to-next-level: "&a [points] потрібні бали до наступного рівня"
|
||||
deaths: "&c([number] смерті)"
|
||||
cooldown: "&c Ви повинні зачекати &b[time] &c секунд, поки ви зможете зробити
|
||||
це знову"
|
||||
in-progress: "&6 Розрахунок рівня острова триває..."
|
||||
time-out: "&c Розрахунок рівня тривав занадто довго. Будь-ласка спробуйте пізніше."
|
||||
top:
|
||||
description: показати першу десятку
|
||||
gui-title: "& Десятка Кращих"
|
||||
gui-heading: "&6[name]: &B[rank]"
|
||||
island-level: "&b Рівень [level]"
|
||||
warp-to: "&A Варп на острів [name]."
|
||||
level-details:
|
||||
above-sea-level-blocks: Блоки над рівнем моря
|
||||
spawners: Спавера
|
||||
underwater-blocks: Підводні блоки
|
||||
all-blocks: Всі блоки
|
||||
no-island: "&c Немає острова!"
|
||||
names-island: острів [name].
|
||||
syntax: "[name] x [number]"
|
||||
hint: "&c Запустіть рівень, щоб переглянути звіт про блокування"
|
||||
level:
|
||||
commands:
|
||||
value:
|
||||
parameters: "[hand|<material>]"
|
||||
description: показує значення блоків. Додайте 'hand' в кінці, щоб відобразити
|
||||
значення предмета в руках.
|
||||
gui:
|
||||
titles:
|
||||
top: "&0&l Топ островів"
|
||||
detail-panel: "&0&l острів [name]."
|
||||
value-panel: "&0&l Значення блоку"
|
||||
buttons:
|
||||
island:
|
||||
empty: "&f&l [name]. місце"
|
||||
name: "&f&l [name]"
|
||||
description: |-
|
||||
[owner]
|
||||
[members]
|
||||
[place]
|
||||
[level]
|
||||
owners-island: Острів [player].
|
||||
owner: "&7&l Власник: &r&b [player]"
|
||||
members-title: "&7&l Члени:"
|
||||
member: "&b - [player]"
|
||||
unknown: невідомий
|
||||
place: "&7&o [number]. &r&7 місце"
|
||||
level: "&7 Рівень: &o [number]"
|
||||
material:
|
||||
name: "&f&l [number] x [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[count]
|
||||
[value]
|
||||
[calculated]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 Ідентифікатор блоку: &e [id]"
|
||||
value: "&7 Значення блоку: &e [number]"
|
||||
limit: "&7 Обмеження блоку: &e [number]"
|
||||
count: "&7 Кількість блоків: &e [number]"
|
||||
calculated: "&7 Розраховане значення: &e [number]"
|
||||
all_blocks:
|
||||
name: "&f&l Усі блоки"
|
||||
description: |-
|
||||
&7 Показати всі блоки
|
||||
&7 на острові.
|
||||
above_sea_level:
|
||||
name: "&f&l Блоки над рівнем моря"
|
||||
description: |-
|
||||
&7 Показувати лише блоки
|
||||
&7, які знаходяться над морем
|
||||
&7 рівень.
|
||||
underwater:
|
||||
name: "&f&l Блоки під рівнем моря"
|
||||
description: |-
|
||||
&7 Показувати лише блоки
|
||||
&7, які знаходяться нижче моря
|
||||
&7 рівень.
|
||||
spawner:
|
||||
name: "&f&l Спанера"
|
||||
description: "&7 Відображати лише спавнери."
|
||||
filters:
|
||||
name:
|
||||
name: "&f&l Сортувати за назвою"
|
||||
description: "&7 Сортувати всі блоки за назвою."
|
||||
value:
|
||||
name: "&f&l Сортувати за значенням"
|
||||
description: "&7 Сортувати всі блоки за їх значенням."
|
||||
count:
|
||||
name: "&f&l Сортувати за кількістю"
|
||||
description: "&7 Відсортуйте всі блоки за їх кількістю."
|
||||
value:
|
||||
name: "&f&l [material]"
|
||||
description: |-
|
||||
[description]
|
||||
[value]
|
||||
[underwater]
|
||||
[limit]
|
||||
[id]
|
||||
id: "&7 Ідентифікатор блоку: &e [id]"
|
||||
value: "&7 Значення блоку: &e [number]"
|
||||
underwater: "&7 Нижче рівня моря: &e [number]"
|
||||
limit: "&7 Обмеження блоку: &e [number]"
|
||||
previous:
|
||||
name: "&f&l Попередня сторінка"
|
||||
description: "&7 Перейти на сторінку [number]."
|
||||
next:
|
||||
name: "&f&l Наступна сторінка"
|
||||
description: "&7 Перейти на сторінку [number]."
|
||||
search:
|
||||
name: "&f&l Пошук"
|
||||
description: |-
|
||||
&7 Пошук конкретного
|
||||
&7 значення.
|
||||
search: "&b Значення: [value]"
|
||||
tips:
|
||||
click-to-view: "&e Натисніть &7, щоб переглянути."
|
||||
click-to-previous: "&e Натисніть &7, щоб переглянути попередню сторінку."
|
||||
click-to-next: "&e Натисніть &7, щоб переглянути наступну сторінку."
|
||||
click-to-select: "&e Натисніть &7, щоб вибрати."
|
||||
left-click-to-cycle-up: "&e Клацніть лівою кнопкою миші &7, щоб перейти вгору."
|
||||
right-click-to-cycle-down: "&e Клацніть правою кнопкою миші &7, щоб перейти
|
||||
вниз."
|
||||
left-click-to-change: "&e Клацніть лівою кнопкою миші &7 для редагування."
|
||||
right-click-to-clear: "&e Клацніть правою кнопкою миші &7, щоб очистити."
|
||||
click-to-asc: "&e Клацніть &7, щоб відсортувати в порядку збільшення."
|
||||
click-to-desc: "&e Клацніть &7, щоб відсортувати в порядку зменшення."
|
||||
click-to-warp: "&e Натисніть &7, щоб деформувати."
|
||||
click-to-visit: "&e Натисніть &7, щоб відвідати."
|
||||
right-click-to-visit: "&e Клацніть правою кнопкою миші &7, щоб відвідати."
|
||||
conversations:
|
||||
prefix: "&l&6 [BentoBox]: &r"
|
||||
no-data: "&c Запустіть рівень, щоб переглянути звіт про блокування."
|
||||
cancel-string: cancel
|
||||
exit-string: cancel, exit, quit
|
||||
write-search: "&e Введіть пошукове значення. (Напишіть 'cancel', щоб вийти)"
|
||||
search-updated: "&a Значення пошуку оновлено."
|
||||
cancelled: "&c Розмова скасована!"
|
||||
no-value: "&c Цей предмет не має цінності."
|
||||
unknown-item: "&c '[material]' не існує в грі."
|
||||
value: "&7 Значення '[material]' таке: &e[value]"
|
||||
value-underwater: "&7 Значення '[material]' нижче рівня моря: &e[value]"
|
||||
empty-hand: "&c У вашій руці немає блоків"
|
|
@ -0,0 +1,56 @@
|
|||
#
|
||||
# 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 #
|
||||
admin:
|
||||
level:
|
||||
parameters: <người chơi>
|
||||
description: tính toán cấp độ đảo của người chơi
|
||||
sethandicap:
|
||||
parameters: <người chơi> <cấp>
|
||||
description: chỉnh cấp của các đảo bắt đầu
|
||||
changed: '&a Cấp đảo bắt đầu đã chỉnh từ [number] thành [new_number].'
|
||||
invalid-level: '&c Cấp không xác định. Hãy dùng số nguyên.'
|
||||
levelstatus:
|
||||
description: xem bao nhiêu đảo đang trong hàng chờ được quét
|
||||
islands-in-queue: '&a Đảo đang chờ: [number]'
|
||||
top:
|
||||
description: xem bảng xếp hạng TOP 10
|
||||
unknown-world: '&c Thế giới không xác định!'
|
||||
display: '&f[rank]. &a[name] &7- &b[level]'
|
||||
remove:
|
||||
description: xoá người khỏi TOP 10
|
||||
parameters: <người chơi>
|
||||
island:
|
||||
level:
|
||||
parameters: '[người chơi]'
|
||||
description: tính toán cấp đảo của bạn hoặc xem cấp đảo của [người chơi]
|
||||
calculating: '&a Đang tính toán cấp đảo...'
|
||||
estimated-wait: '&a Thời gian còn lại: [number] giây'
|
||||
in-queue: '&a Bạn đang ở vị trí [number] trong hàng chờ'
|
||||
island-level-is: '&a Cấp đảo là &b[level]'
|
||||
required-points-to-next-level: '&a Cần [points] điểm để qua cấp tiếp theo'
|
||||
deaths: '&c([number] lần chết)'
|
||||
cooldown: '&c Bạn phải chờ &b[time] &c giây trước khi có thể làm điều đó'
|
||||
in-progress: '&6 Quá trình tính toán cấp đảo đang thực hiện...'
|
||||
time-out: '&c Tính toán cấp đảo quá lâu. Vui lòng thử lại sau.'
|
||||
top:
|
||||
description: xem TOP 10
|
||||
gui-title: '&a TOP 10'
|
||||
gui-heading: '&6[name]: &B[rank]'
|
||||
island-level: '&b Cấp [level]'
|
||||
warp-to: '&A Đang dịch chuyển đến đảo của [name]'
|
||||
level-details:
|
||||
above-sea-level-blocks: Khối Trên Mực Nước Biển
|
||||
spawners: Lồng Sinh Quái
|
||||
underwater-blocks: Khối Dưới Nước
|
||||
all-blocks: Toàn Bộ Khối
|
||||
no-island: '&c Không có đảo!'
|
||||
names-island: 'đảo của [name]'
|
||||
syntax: '[name] x [number]'
|
||||
hint: '&c Chạy lệnh cấp để xem báo cáo khối'
|
||||
value:
|
||||
description: xem giá trị của bất kì khối
|
||||
success: '&7 Giá trị của khối này là: &e[value]'
|
||||
success-underwater: '&7 Giá trị của khối này dưới mực nước biển: &e[value]'
|
||||
empty-hand: '&c Không có khối nào trên tay bạn'
|
||||
no-value: '&c Vật phẩm này vô giá trị.'
|
|
@ -1,30 +1,173 @@
|
|||
###########################################################################################
|
||||
# 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 #
|
||||
###########################################################################################
|
||||
|
||||
admin:
|
||||
level:
|
||||
parameters: "<player>"
|
||||
description: "计算玩家的岛屿等级"
|
||||
parameters: <player>
|
||||
description: 计算指定玩家的岛屿等级
|
||||
sethandicap:
|
||||
parameters: <player> <handicap>
|
||||
description: 设置偏差值, 通常用于抵消初始岛屿等级, 来保证岛屿等级从零开始. 实际岛屿等级 - <handicap> = 最终的岛屿等级
|
||||
changed: '&a岛屿的偏差值从[number]更改为[new_number]'
|
||||
invalid-level: '&c偏差值无效, 请使用整数'
|
||||
levelstatus:
|
||||
description: 显示等级计算队列中的岛屿
|
||||
islands-in-queue: '&a列队中的岛屿: [number]'
|
||||
top:
|
||||
description: "显示排名前十榜单"
|
||||
unknown-world: "&c未知世界!"
|
||||
|
||||
description: 显示前十名
|
||||
unknown-world: '&c未知的世界!'
|
||||
display: '&f[rank]. &a[name] &7- &b[level]'
|
||||
remove:
|
||||
description: 将玩家移出前十名
|
||||
parameters: <player>
|
||||
stats:
|
||||
description: 显示该服务器上岛屿的统计数据
|
||||
title: 服务器岛屿数据
|
||||
world: '&a[name]'
|
||||
no-data: '&c没有数据.'
|
||||
average-level: '平均岛屿等级: [number]'
|
||||
median-level: '中位数岛屿等级: [number]'
|
||||
mode-level: '众数岛屿等级: [number]'
|
||||
highest-level: '最高岛屿等级: [number]'
|
||||
lowest-level: '最低岛屿等级: [number]'
|
||||
distribution: '岛屿等级分布:'
|
||||
islands: 个岛屿
|
||||
island:
|
||||
level:
|
||||
parameters: "[player]"
|
||||
description: "计算您的岛屿等级或显示 [player] 的岛屿等级"
|
||||
calculating: "&a正在计算等级……"
|
||||
island-level-is: "&a岛屿等级是 &b[level]"
|
||||
required-points-to-next-level: "&a距离下一级还需要 [points] 点"
|
||||
deaths: "&c([number] 次死亡)"
|
||||
cooldown: "&c在您可以再次做这件事之前必须等待 &b[time] &c秒"
|
||||
|
||||
level:
|
||||
parameters: '[player]'
|
||||
description: 计算你或指定玩家[player]的岛屿等级
|
||||
calculating: '&a等级计算中...'
|
||||
estimated-wait: '&a预计等待时间: [number]秒'
|
||||
in-queue: '&a你处于队列中第[number]个'
|
||||
island-level-is: '&a岛屿等级为: &b[level]'
|
||||
required-points-to-next-level: '&a还需[points]点数才能到达下一级'
|
||||
deaths: '&c([number]次死亡)'
|
||||
cooldown: '&c还需等待&b[time]&c秒才能再次使用该指令'
|
||||
in-progress: '&6岛屿等级正在计算中...'
|
||||
time-out: '&c等级计算超时, 请稍后再试'
|
||||
|
||||
top:
|
||||
description: "显示排名前十榜单"
|
||||
gui-title: "&a前十榜"
|
||||
gui-heading: "&6[name]: &B[rank]"
|
||||
island-level: "&B等级 [level]"
|
||||
warp-to: "&A正在传送到 [name] 的岛屿"
|
||||
|
||||
description: 显示前十名
|
||||
gui-title: '&a前十'
|
||||
gui-heading: '&6[name]: &B[rank]'
|
||||
island-level: '&b等级: [level]'
|
||||
warp-to: '&a正在传送到[name]的岛屿'
|
||||
|
||||
level-details:
|
||||
above-sea-level-blocks: 海平面以上的方块
|
||||
spawners: 刷怪笼
|
||||
underwater-blocks: 水下的方块
|
||||
all-blocks: 所有方块
|
||||
no-island: '&c没有岛屿!'
|
||||
names-island: '[name]的岛屿'
|
||||
syntax: '[name] x [number]'
|
||||
hint: '&c运行level指令查看方块报告'
|
||||
|
||||
level:
|
||||
commands:
|
||||
value:
|
||||
parameters: '[hand|<material>]'
|
||||
description: 显示方块的价值. 在末尾添加'hand'可显示手中方块的价值
|
||||
gui:
|
||||
titles:
|
||||
top: '&0&l岛屿排行榜'
|
||||
detail-panel: '&0&l[name]的岛屿'
|
||||
value-panel: '&0&l方块价值'
|
||||
buttons:
|
||||
island:
|
||||
empty: '&f&l第[name]名'
|
||||
name: '&f&l[name]'
|
||||
description: |-
|
||||
[owner]
|
||||
[members]
|
||||
[place]
|
||||
[level]
|
||||
owners-island: '[player]的岛屿'
|
||||
owner: '&7&l岛主: &r&b[player]'
|
||||
members-title: '&7&l成员: '
|
||||
member: '&b- [player]'
|
||||
unknown: 未知
|
||||
place: '&7第&7&o[number]&r&7名'
|
||||
level: '&7等级: &o[number]'
|
||||
material:
|
||||
name: '&f&l [number] x [material]'
|
||||
description: |-
|
||||
[description]
|
||||
[count]
|
||||
[value]
|
||||
[calculated]
|
||||
[limit]
|
||||
[id]
|
||||
id: '&7方块ID: &e[id]'
|
||||
value: '&7方块价值: &e[number]'
|
||||
limit: '&7方块限制: &e[number]'
|
||||
count: '&7方块数量: &e[number]'
|
||||
calculated: '&7计算值: &e[number]'
|
||||
all_blocks:
|
||||
name: '&f&l所有方块'
|
||||
description: '&7显示岛屿上所有的方块'
|
||||
above_sea_level:
|
||||
name: '&f&l海平面以上的方块'
|
||||
description: '&7只显示所有海平面以上的方块'
|
||||
underwater:
|
||||
name: '&f&l海平面以下的方块'
|
||||
description: 只显示所有海平面以下的方块
|
||||
spawner:
|
||||
name: '&f&l刷怪笼'
|
||||
description: '&7只显示刷怪笼'
|
||||
filters:
|
||||
name:
|
||||
name: '&f&l按名称排序'
|
||||
description: '&7通过名称排序所有的方块'
|
||||
value:
|
||||
name: '&f&l按价值排序'
|
||||
description: '&7通过价值排序所有的方块'
|
||||
count:
|
||||
name: '&f&l按数量排序'
|
||||
description: '&7通过数量排序所有方块'
|
||||
value:
|
||||
name: '&f&l[material]'
|
||||
description: |-
|
||||
[description]
|
||||
[value]
|
||||
[underwater]
|
||||
[limit]
|
||||
[id]
|
||||
id: '&7方块ID: &e[id]'
|
||||
value: '&7方块价值: &e[number]'
|
||||
underwater: '&7海平面以下方块的价值: &e[number]'
|
||||
limit: '&7方块限制: &e[number]'
|
||||
previous:
|
||||
name: '&f&l上一页'
|
||||
description: '&7切换到第[number]页'
|
||||
next:
|
||||
name: '&f&l下一页'
|
||||
description: '&7切换到第[number]页'
|
||||
search:
|
||||
name: '&f&l搜索'
|
||||
description: '&7搜索特定的内容'
|
||||
search: '&b搜索值: [value]'
|
||||
tips:
|
||||
click-to-view: '&e点击 &7查看'
|
||||
click-to-previous: '&e点击 &7查看上一页'
|
||||
click-to-next: '&e点击 &7查看下一页'
|
||||
click-to-select: '&e点击 &7选择'
|
||||
left-click-to-cycle-up: '&e左键 &7向上循环'
|
||||
right-click-to-cycle-down: '&e右键 &7向下循环'
|
||||
left-click-to-change: '&e左键 &7编辑'
|
||||
right-click-to-clear: '&e右键 &7清除'
|
||||
click-to-asc: '&e点击 &7以升序排序'
|
||||
click-to-desc: '&e点击 &7以降序排序'
|
||||
click-to-warp: '&e点击 &7去岛屿传送点'
|
||||
click-to-visit: '&e点击 &7参观'
|
||||
right-click-to-visit: '&e右键 &7查看'
|
||||
conversations:
|
||||
prefix: '&l&6[BentoBox]: &r'
|
||||
no-data: '&c运行level指令查看方块报告'
|
||||
cancel-string: cancel
|
||||
exit-string: cancel, exit, quit
|
||||
write-search: '&e请输入要搜索的值. (输入''cancel''退出)'
|
||||
search-updated: '&a搜索值已更新'
|
||||
cancelled: '&c对话已取消'
|
||||
no-value: '&c这件物品一文不值'
|
||||
unknown-item: '&c物品''[material]''在游戏中不存在'
|
||||
value: '&7物品''[material]''的价值: &e[value]'
|
||||
value-underwater: '&7物品''[material]''在海平面以下的价值: &e[value]'
|
||||
empty-hand: '&c你的手中没有拿着方块'
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
# Name of panel used for indentification in the code
|
||||
detail_panel:
|
||||
# Title of the panel shown to the user. This is a reference and the reference will be translatable in the locale file
|
||||
title: level.gui.titles.detail-panel
|
||||
# The type of panel to show. Options are INVENTORY, HOPPER, DROPPER. INVENTORY is that standard chest inventory and
|
||||
# the others refer to the inventories shown for those items.
|
||||
type: INVENTORY
|
||||
# The background of the panel. These items will be shown if other items are not there. STAINED_GLASS_PANEs give a good effect.
|
||||
background:
|
||||
icon: BLACK_STAINED_GLASS_PANE
|
||||
# Each item may have text applied to it, but usually for background items, nothing is shown.
|
||||
title: "&b&r" # Empty text. This is using the Bukkit chat color coding with &'s.
|
||||
border:
|
||||
# The border of each panel may be shown as a different item.
|
||||
# It can be used to provide a contrast to items in the panel.
|
||||
icon: BLACK_STAINED_GLASS_PANE
|
||||
title: "&b&r" # Empty text
|
||||
# This tag indicates which rows in the panel must be shown. The panel will be sized vertically accordingly. This does not include the borders.
|
||||
# This can be a list and rows must be between 1 and 6, if used.
|
||||
force-shown: []
|
||||
# The content section contains details of each item/button in the panel. The numbers indicate the rows and then then columns of each item.
|
||||
content:
|
||||
# Row number
|
||||
1:
|
||||
# Column number
|
||||
2:
|
||||
# Icon is a Bukkit Material.
|
||||
icon: STONE
|
||||
# Title of the button shown to the user. This is a reference and the reference will be translatable in the locale file
|
||||
title: level.gui.buttons.all_blocks.name
|
||||
# Description of the button shown to the user in the lore. This is a reference and the reference will be translatable in the locale file
|
||||
description: level.gui.buttons.all_blocks.description
|
||||
# The data section is a key-value list of data relavent for this button. It is interpreted by the code implemented the panel.
|
||||
# The convention is to specify the type and the panel tab that will open if pressed. These are Enums in the code.
|
||||
data:
|
||||
# Type button will go to the ALL_BLOCKS tab when clicked.
|
||||
type: TAB
|
||||
tab: ALL_BLOCKS
|
||||
# Actions cover what happens if the button is clicked or the mouse is moved over it. There can be multiple actions possible for different
|
||||
# click-types.
|
||||
actions:
|
||||
# Each action has an arbitrary descriptive name to define it.
|
||||
view:
|
||||
# The click-type is the same as the bukkit {@link org.bukkit.event.inventory.ClickType}. UNKNOWN is the default.
|
||||
click-type: unknown
|
||||
# tooltip is a locale reference that will be translated for the user and shown when they hover over the button.
|
||||
tooltip: level.gui.tips.click-to-view
|
||||
3:
|
||||
icon: GRASS_BLOCK
|
||||
title: level.gui.buttons.above_sea_level.name
|
||||
description: level.gui.buttons.above_sea_level.description
|
||||
data:
|
||||
type: TAB
|
||||
tab: ABOVE_SEA_LEVEL
|
||||
actions:
|
||||
view:
|
||||
click-type: unknown
|
||||
tooltip: level.gui.tips.click-to-view
|
||||
4:
|
||||
icon: WATER_BUCKET
|
||||
title: level.gui.buttons.underwater.name
|
||||
description: level.gui.buttons.underwater.description
|
||||
data:
|
||||
type: TAB
|
||||
tab: UNDERWATER
|
||||
actions:
|
||||
view:
|
||||
click-type: unknown
|
||||
tooltip: level.gui.tips.click-to-view
|
||||
5:
|
||||
icon: SPAWNER
|
||||
title: level.gui.buttons.spawner.name
|
||||
description: level.gui.buttons.spawner.description
|
||||
data:
|
||||
type: TAB
|
||||
tab: SPAWNER
|
||||
actions:
|
||||
view:
|
||||
click-type: unknown
|
||||
tooltip: level.gui.tips.click-to-view
|
||||
9:
|
||||
# You can create multiple buttons. By default it is one.
|
||||
icon: IRON_TRAPDOOR
|
||||
# [filter] is a placeholder for different filter types. It will be replaced with name, value, count.
|
||||
title: level.gui.buttons.filters.[filter].name
|
||||
description: level.gui.buttons.filters.[filter].description
|
||||
data:
|
||||
type: FILTER
|
||||
# the value of filter button. Suggestion is to leave first value to name if you use single button.
|
||||
filter: NAME
|
||||
actions:
|
||||
up:
|
||||
click-type: left
|
||||
tooltip: level.gui.tips.left-click-to-cycle-up
|
||||
down:
|
||||
click-type: right
|
||||
tooltip: level.gui.tips.right-click-to-cycle-down
|
||||
# There is also select action. With it you can create multiple filter buttons.
|
||||
# select:
|
||||
# click-type: unknown
|
||||
# tooltip: level.gui.tips.click-to-select
|
||||
2:
|
||||
# If a button is used repeatedly then it can be mentioned by name and then defined in the 'reusable' section
|
||||
2: material_button
|
||||
3: material_button
|
||||
4: material_button
|
||||
5: material_button
|
||||
6: material_button
|
||||
7: material_button
|
||||
8: material_button
|
||||
3:
|
||||
1:
|
||||
# In this case, the icon is defined as a TIPPED_ARROW with and enchantment applied. The format for the enchantment is
|
||||
# define in {@link world.bentobox.bentobox.util.ItemParser} and available for POTIONS or TIPPED_ARROWs.
|
||||
# Format TIPPED_ARROW:NAME:<LEVEL>:<EXTENDED>:<SPLASH/LINGER>:QTY
|
||||
# LEVEL, EXTENDED, SPLASH, LINGER are optional.
|
||||
# LEVEL is a number, 1 or 2
|
||||
# LINGER is for V1.9 servers and later
|
||||
# Examples:
|
||||
# TIPPED_ARROW:STRENGTH:1:EXTENDED:SPLASH:1
|
||||
# TIPPED_ARROW:INSTANT_DAMAGE:2::LINGER:2
|
||||
# TIPPED_ARROW:JUMP:2:NOTEXTENDED:NOSPLASH:1
|
||||
# TIPPED_ARROW:WEAKNESS::::1 - any weakness enchantment
|
||||
icon: tipped_arrow{CustomPotionColor:11546150}
|
||||
title: level.gui.buttons.previous.name
|
||||
description: level.gui.buttons.previous.description
|
||||
data:
|
||||
type: PREVIOUS
|
||||
indexing: true
|
||||
actions:
|
||||
previous:
|
||||
click-type: unknown
|
||||
tooltip: level.gui.tips.click-to-previous
|
||||
2: material_button
|
||||
3: material_button
|
||||
4: material_button
|
||||
5: material_button
|
||||
6: material_button
|
||||
7: material_button
|
||||
8: material_button
|
||||
9:
|
||||
icon: tipped_arrow{CustomPotionColor:8439583}
|
||||
title: level.gui.buttons.next.name
|
||||
description: level.gui.buttons.next.description
|
||||
data:
|
||||
type: NEXT
|
||||
indexing: true
|
||||
actions:
|
||||
next:
|
||||
click-type: unknown
|
||||
tooltip: level.gui.tips.click-to-next
|
||||
4:
|
||||
2: material_button
|
||||
3: material_button
|
||||
4: material_button
|
||||
5: material_button
|
||||
6: material_button
|
||||
7: material_button
|
||||
8: material_button
|
||||
# This is where reuable buttons are defined.
|
||||
reusable:
|
||||
# This is the name of the button that is referenced
|
||||
material_button:
|
||||
# If the icon for a button is not defined, it defaults to AIR and so effectively will not be shown.
|
||||
# icons are usually not defined if the icon is going to be dynamically set in the panel, e.g. in this case the material will vary
|
||||
#icon: STONE
|
||||
title: level.gui.buttons.material.name
|
||||
description: level.gui.buttons.material.description
|
||||
data:
|
||||
type: BLOCK
|
|
@ -0,0 +1,208 @@
|
|||
# Name of panel used for indentification in the code
|
||||
top_panel:
|
||||
# Title of the panel shown to the user. This is a reference and the reference will be translatable in the locale file
|
||||
title: level.gui.titles.top
|
||||
# The type of panel to show. Options are INVENTORY, HOPPER, DROPPER. INVENTORY is that standard chest inventory and
|
||||
# the others refer to the inventories shown for those items.
|
||||
type: INVENTORY
|
||||
# The background of the panel. These items will be shown if other items are not there. STAINED_GLASS_PANEs give a good effect.
|
||||
background:
|
||||
icon: BLACK_STAINED_GLASS_PANE
|
||||
# Each item may have text applied to it, but usually for background items, nothing is shown.
|
||||
title: "&b&r" # Empty text
|
||||
border:
|
||||
# The border of each panel may be shown as a different item.
|
||||
# It can be used to provide a contrast to items in the panel.
|
||||
icon: BLACK_STAINED_GLASS_PANE
|
||||
title: "&b&r" # Empty text
|
||||
# This tag indicates which rows in the panel must be shown. The panel will be sized vertically accordingly. This does not include the borders.
|
||||
# This can be a list and rows must be between 1 and 6, if used.
|
||||
force-shown: [2,3,4,5]
|
||||
# The content section contains details of each item/button in the panel. The numbers indicate the rows and then then columns of each item.
|
||||
content:
|
||||
# Row number
|
||||
2:
|
||||
# Column number
|
||||
5:
|
||||
#icon: PLAYER_HEAD
|
||||
title: level.gui.buttons.island.name
|
||||
description: level.gui.buttons.island.description
|
||||
data:
|
||||
type: TOP
|
||||
index: 1
|
||||
actions:
|
||||
warp:
|
||||
click-type: LEFT
|
||||
tooltip: level.gui.tips.click-to-warp
|
||||
visit:
|
||||
click-type: RIGHT
|
||||
tooltip: level.gui.tips.right-click-to-visit
|
||||
fallback:
|
||||
icon: LIME_STAINED_GLASS_PANE
|
||||
title: level.gui.buttons.island.empty
|
||||
3:
|
||||
4:
|
||||
#icon: PLAYER_HEAD
|
||||
title: level.gui.buttons.island.name
|
||||
description: level.gui.buttons.island.description
|
||||
data:
|
||||
type: TOP
|
||||
index: 2
|
||||
actions:
|
||||
warp:
|
||||
click-type: LEFT
|
||||
tooltip: level.gui.tips.click-to-warp
|
||||
visit:
|
||||
click-type: RIGHT
|
||||
tooltip: level.gui.tips.right-click-to-visit
|
||||
fallback:
|
||||
icon: LIME_STAINED_GLASS_PANE
|
||||
title: level.gui.buttons.island.empty
|
||||
6:
|
||||
#icon: PLAYER_HEAD
|
||||
title: level.gui.buttons.island.name
|
||||
description: level.gui.buttons.island.description
|
||||
data:
|
||||
type: TOP
|
||||
index: 3
|
||||
actions:
|
||||
warp:
|
||||
click-type: LEFT
|
||||
tooltip: level.gui.tips.click-to-warp
|
||||
visit:
|
||||
click-type: RIGHT
|
||||
tooltip: level.gui.tips.right-click-to-visit
|
||||
fallback:
|
||||
icon: LIME_STAINED_GLASS_PANE
|
||||
title: level.gui.buttons.island.empty
|
||||
4:
|
||||
2:
|
||||
#icon: PLAYER_HEAD
|
||||
title: level.gui.buttons.island.name
|
||||
description: level.gui.buttons.island.description
|
||||
data:
|
||||
type: TOP
|
||||
index: 4
|
||||
actions:
|
||||
warp:
|
||||
click-type: LEFT
|
||||
tooltip: level.gui.tips.click-to-warp
|
||||
visit:
|
||||
click-type: RIGHT
|
||||
tooltip: level.gui.tips.right-click-to-visit
|
||||
fallback:
|
||||
icon: LIME_STAINED_GLASS_PANE
|
||||
title: level.gui.buttons.island.empty
|
||||
3:
|
||||
#icon: PLAYER_HEAD
|
||||
title: level.gui.buttons.island.name
|
||||
description: level.gui.buttons.island.description
|
||||
data:
|
||||
type: TOP
|
||||
index: 5
|
||||
actions:
|
||||
warp:
|
||||
click-type: LEFT
|
||||
tooltip: level.gui.tips.click-to-warp
|
||||
visit:
|
||||
click-type: RIGHT
|
||||
tooltip: level.gui.tips.right-click-to-visit
|
||||
fallback:
|
||||
icon: LIME_STAINED_GLASS_PANE
|
||||
title: level.gui.buttons.island.empty
|
||||
4:
|
||||
#icon: PLAYER_HEAD
|
||||
title: level.gui.buttons.island.name
|
||||
description: level.gui.buttons.island.description
|
||||
data:
|
||||
type: TOP
|
||||
index: 6
|
||||
actions:
|
||||
warp:
|
||||
click-type: LEFT
|
||||
tooltip: level.gui.tips.click-to-warp
|
||||
visit:
|
||||
click-type: RIGHT
|
||||
tooltip: level.gui.tips.right-click-to-visit
|
||||
fallback:
|
||||
icon: LIME_STAINED_GLASS_PANE
|
||||
title: level.gui.buttons.island.empty
|
||||
5:
|
||||
#icon: PLAYER_HEAD
|
||||
title: level.gui.buttons.island.name
|
||||
description: level.gui.buttons.island.description
|
||||
data:
|
||||
type: TOP
|
||||
index: 7
|
||||
actions:
|
||||
warp:
|
||||
click-type: LEFT
|
||||
tooltip: level.gui.tips.click-to-warp
|
||||
visit:
|
||||
click-type: RIGHT
|
||||
tooltip: level.gui.tips.right-click-to-visit
|
||||
fallback:
|
||||
icon: LIME_STAINED_GLASS_PANE
|
||||
title: level.gui.buttons.island.empty
|
||||
6:
|
||||
#icon: PLAYER_HEAD
|
||||
title: level.gui.buttons.island.name
|
||||
description: level.gui.buttons.island.description
|
||||
data:
|
||||
type: TOP
|
||||
index: 8
|
||||
actions:
|
||||
warp:
|
||||
click-type: LEFT
|
||||
tooltip: level.gui.tips.click-to-warp
|
||||
visit:
|
||||
click-type: RIGHT
|
||||
tooltip: level.gui.tips.right-click-to-visit
|
||||
fallback:
|
||||
icon: LIME_STAINED_GLASS_PANE
|
||||
title: level.gui.buttons.island.empty
|
||||
7:
|
||||
#icon: PLAYER_HEAD
|
||||
title: level.gui.buttons.island.name
|
||||
description: level.gui.buttons.island.description
|
||||
data:
|
||||
type: TOP
|
||||
index: 9
|
||||
actions:
|
||||
warp:
|
||||
click-type: LEFT
|
||||
tooltip: level.gui.tips.click-to-warp
|
||||
visit:
|
||||
click-type: RIGHT
|
||||
tooltip: level.gui.tips.right-click-to-visit
|
||||
fallback:
|
||||
icon: LIME_STAINED_GLASS_PANE
|
||||
title: level.gui.buttons.island.empty
|
||||
8:
|
||||
#icon: PLAYER_HEAD
|
||||
title: level.gui.buttons.island.name
|
||||
description: level.gui.buttons.island.description
|
||||
data:
|
||||
type: TOP
|
||||
index: 10
|
||||
actions:
|
||||
warp:
|
||||
click-type: LEFT
|
||||
tooltip: level.gui.tips.click-to-warp
|
||||
visit:
|
||||
click-type: RIGHT
|
||||
tooltip: level.gui.tips.right-click-to-visit
|
||||
fallback:
|
||||
icon: LIME_STAINED_GLASS_PANE
|
||||
title: level.gui.buttons.island.empty
|
||||
6:
|
||||
5:
|
||||
#icon: PLAYER_HEAD
|
||||
title: level.gui.buttons.island.name
|
||||
description: level.gui.buttons.island.description
|
||||
data:
|
||||
type: VIEW
|
||||
actions:
|
||||
view:
|
||||
click-type: unknown
|
||||
tooltip: level.gui.tips.click-to-view
|
|
@ -0,0 +1,109 @@
|
|||
value_panel:
|
||||
title: level.gui.titles.value-panel
|
||||
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:
|
||||
1:
|
||||
4:
|
||||
icon: PAPER
|
||||
title: level.gui.buttons.filters.name.name
|
||||
description: level.gui.buttons.filters.name.description
|
||||
data:
|
||||
type: FILTER
|
||||
# the value of filter button. Suggestion is to leave fist value to name if you use single button.
|
||||
filter: NAME
|
||||
actions:
|
||||
asc:
|
||||
click-type: unknown
|
||||
tooltip: level.gui.tips.click-to-asc
|
||||
desc:
|
||||
click-type: unknown
|
||||
tooltip: level.gui.tips.click-to-desc
|
||||
5:
|
||||
# You can create multiple buttons. By default it is one.
|
||||
icon: MAP
|
||||
title: level.gui.buttons.search.name
|
||||
description: level.gui.buttons.search.description
|
||||
data:
|
||||
type: SEARCH
|
||||
actions:
|
||||
input:
|
||||
click-type: left
|
||||
tooltip: level.gui.tips.left-click-to-change
|
||||
clear:
|
||||
click-type: right
|
||||
tooltip: level.gui.tips.right-click-to-clear
|
||||
6:
|
||||
icon: DIAMOND
|
||||
title: level.gui.buttons.filters.value.name
|
||||
description: level.gui.buttons.filters.value.description
|
||||
data:
|
||||
type: FILTER
|
||||
# the value of filter button. Suggestion is to leave fist value to name if you use single button.
|
||||
filter: VALUE
|
||||
actions:
|
||||
asc:
|
||||
click-type: unknown
|
||||
tooltip: level.gui.tips.click-to-asc
|
||||
desc:
|
||||
click-type: unknown
|
||||
tooltip: level.gui.tips.click-to-desc
|
||||
2:
|
||||
2: material_button
|
||||
3: material_button
|
||||
4: material_button
|
||||
5: material_button
|
||||
6: material_button
|
||||
7: material_button
|
||||
8: material_button
|
||||
3:
|
||||
1:
|
||||
icon: tipped_arrow{CustomPotionColor:11546150}
|
||||
title: level.gui.buttons.previous.name
|
||||
description: level.gui.buttons.previous.description
|
||||
data:
|
||||
type: PREVIOUS
|
||||
indexing: true
|
||||
actions:
|
||||
previous:
|
||||
click-type: unknown
|
||||
tooltip: level.gui.tips.click-to-previous
|
||||
2: material_button
|
||||
3: material_button
|
||||
4: material_button
|
||||
5: material_button
|
||||
6: material_button
|
||||
7: material_button
|
||||
8: material_button
|
||||
9:
|
||||
icon: tipped_arrow{CustomPotionColor:8439583}
|
||||
title: level.gui.buttons.next.name
|
||||
description: level.gui.buttons.next.description
|
||||
data:
|
||||
type: NEXT
|
||||
indexing: true
|
||||
actions:
|
||||
next:
|
||||
click-type: unknown
|
||||
tooltip: level.gui.tips.click-to-next
|
||||
4:
|
||||
2: material_button
|
||||
3: material_button
|
||||
4: material_button
|
||||
5: material_button
|
||||
6: material_button
|
||||
7: material_button
|
||||
8: material_button
|
||||
reusable:
|
||||
material_button:
|
||||
#icon: STONE
|
||||
title: level.gui.buttons.value.name
|
||||
description: level.gui.buttons.value.description
|
||||
data:
|
||||
type: BLOCK
|
|
@ -0,0 +1,9 @@
|
|||
name: BentoBox-Level
|
||||
main: world.bentobox.level.LevelPladdon
|
||||
version: ${project.version}${build.number}
|
||||
api-version: "1.19"
|
||||
|
||||
authors: [tastybento]
|
||||
contributors: ["The BentoBoxWorld Community"]
|
||||
website: https://bentobox.world
|
||||
description: ${project.description}
|
|
@ -1,81 +0,0 @@
|
|||
package world.bentobox.level;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mockito;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
import world.bentobox.level.calculators.PlayerLevel;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({Bukkit.class, LevelPresenter.class})
|
||||
public class LevelPresenterTest {
|
||||
|
||||
private BentoBox plugin;
|
||||
private Level addon;
|
||||
private PlayerLevel pl;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
plugin = mock(BentoBox.class);
|
||||
addon = mock(Level.class);
|
||||
IslandWorldManager iwm = mock(IslandWorldManager.class);
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
when(iwm.getPermissionPrefix(Mockito.any())).thenReturn("world");
|
||||
IslandsManager im = mock(IslandsManager.class);
|
||||
when(plugin.getIslands()).thenReturn(im);
|
||||
// Has island
|
||||
when(im.hasIsland(Mockito.any(), Mockito.any(User.class))).thenReturn(true);
|
||||
// In team
|
||||
when(im.inTeam(Mockito.any(), Mockito.any())).thenReturn(true);
|
||||
// team leader
|
||||
when(im.getOwner(Mockito.any(), Mockito.any())).thenReturn(UUID.randomUUID());
|
||||
|
||||
pl = mock(PlayerLevel.class);
|
||||
PowerMockito.whenNew(PlayerLevel.class).withAnyArguments().thenReturn(pl);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link LevelPresenter#LevelPresenter(Level, world.bentobox.bentobox.BentoBox)}.
|
||||
*/
|
||||
@Test
|
||||
public void testLevelPresenter() {
|
||||
new LevelPresenter(addon, plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link LevelPresenter#calculateIslandLevel(org.bukkit.World, world.bentobox.bentobox.api.user.User, java.util.UUID)}.
|
||||
*/
|
||||
@Test
|
||||
public void testCalculateIslandLevel() {
|
||||
LevelPresenter lp = new LevelPresenter(addon, plugin);
|
||||
World world = mock(World.class);
|
||||
User sender = mock(User.class);
|
||||
UUID targetPlayer = UUID.randomUUID();
|
||||
lp.calculateIslandLevel(world, sender, targetPlayer);
|
||||
|
||||
Mockito.verify(sender).sendMessage("island.level.calculating");
|
||||
// Verify PlayerLevel was called
|
||||
Mockito.verify(pl);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,300 @@
|
|||
package world.bentobox.level;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.UnsafeValues;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemFactory;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.powermock.reflect.Whitebox;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.Settings;
|
||||
import world.bentobox.bentobox.api.addons.AddonDescription;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.managers.AddonsManager;
|
||||
import world.bentobox.bentobox.managers.CommandsManager;
|
||||
import world.bentobox.bentobox.managers.FlagsManager;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
import world.bentobox.bentobox.managers.PlaceholdersManager;
|
||||
import world.bentobox.level.config.BlockConfig;
|
||||
import world.bentobox.level.config.ConfigSettings;
|
||||
import world.bentobox.level.listeners.IslandActivitiesListeners;
|
||||
import world.bentobox.level.listeners.JoinLeaveListener;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({ Bukkit.class, BentoBox.class, User.class })
|
||||
public class LevelTest {
|
||||
|
||||
private static File jFile;
|
||||
@Mock
|
||||
private User user;
|
||||
@Mock
|
||||
private IslandsManager im;
|
||||
@Mock
|
||||
private Island island;
|
||||
@Mock
|
||||
private BentoBox plugin;
|
||||
@Mock
|
||||
private FlagsManager fm;
|
||||
@Mock
|
||||
private GameModeAddon gameMode;
|
||||
@Mock
|
||||
private AddonsManager am;
|
||||
@Mock
|
||||
private BukkitScheduler scheduler;
|
||||
|
||||
@Mock
|
||||
private Settings pluginSettings;
|
||||
|
||||
private Level addon;
|
||||
|
||||
@Mock
|
||||
private Logger logger;
|
||||
@Mock
|
||||
private PlaceholdersManager phm;
|
||||
@Mock
|
||||
private CompositeCommand cmd;
|
||||
@Mock
|
||||
private CompositeCommand adminCmd;
|
||||
@Mock
|
||||
private World world;
|
||||
private UUID uuid;
|
||||
|
||||
@Mock
|
||||
private PluginManager pim;
|
||||
@Mock
|
||||
private BlockConfig blockConfig;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws IOException {
|
||||
// Make the addon jar
|
||||
jFile = new File("addon.jar");
|
||||
// Copy over config file from src folder
|
||||
Path fromPath = Paths.get("src/main/resources/config.yml");
|
||||
Path path = Paths.get("config.yml");
|
||||
Files.copy(fromPath, path);
|
||||
// Copy over block config file from src folder
|
||||
fromPath = Paths.get("src/main/resources/blockconfig.yml");
|
||||
path = Paths.get("blockconfig.yml");
|
||||
Files.copy(fromPath, path);
|
||||
try (JarOutputStream tempJarOutputStream = new JarOutputStream(new FileOutputStream(jFile))) {
|
||||
// Added the new files to the jar.
|
||||
try (FileInputStream fis = new FileInputStream(path.toFile())) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead = 0;
|
||||
JarEntry entry = new JarEntry(path.toString());
|
||||
tempJarOutputStream.putNextEntry(entry);
|
||||
while ((bytesRead = fis.read(buffer)) != -1) {
|
||||
tempJarOutputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
// Set up plugin
|
||||
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
|
||||
when(plugin.getLogger()).thenReturn(Logger.getAnonymousLogger());
|
||||
|
||||
// The database type has to be created one line before the thenReturn() to work!
|
||||
DatabaseType value = DatabaseType.JSON;
|
||||
when(plugin.getSettings()).thenReturn(pluginSettings);
|
||||
when(pluginSettings.getDatabaseType()).thenReturn(value);
|
||||
|
||||
// when(plugin.isEnabled()).thenReturn(true);
|
||||
// Command manager
|
||||
CommandsManager cm = mock(CommandsManager.class);
|
||||
when(plugin.getCommandsManager()).thenReturn(cm);
|
||||
|
||||
// Player
|
||||
Player p = mock(Player.class);
|
||||
// Sometimes use Mockito.withSettings().verboseLogging()
|
||||
when(user.isOp()).thenReturn(false);
|
||||
uuid = UUID.randomUUID();
|
||||
when(user.getUniqueId()).thenReturn(uuid);
|
||||
when(user.getPlayer()).thenReturn(p);
|
||||
when(user.getName()).thenReturn("tastybento");
|
||||
User.setPlugin(plugin);
|
||||
|
||||
// Island World Manager
|
||||
IslandWorldManager iwm = mock(IslandWorldManager.class);
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
|
||||
// Player has island to begin with
|
||||
when(im.getIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(island);
|
||||
when(plugin.getIslands()).thenReturn(im);
|
||||
|
||||
// Locales
|
||||
// Return the reference (USE THIS IN THE FUTURE)
|
||||
when(user.getTranslation(Mockito.anyString()))
|
||||
.thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
|
||||
|
||||
// Server
|
||||
PowerMockito.mockStatic(Bukkit.class);
|
||||
Server server = mock(Server.class);
|
||||
when(Bukkit.getServer()).thenReturn(server);
|
||||
when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
|
||||
when(Bukkit.getPluginManager()).thenReturn(mock(PluginManager.class));
|
||||
|
||||
// Addon
|
||||
addon = new Level();
|
||||
File dataFolder = new File("addons/Level");
|
||||
addon.setDataFolder(dataFolder);
|
||||
addon.setFile(jFile);
|
||||
AddonDescription desc = new AddonDescription.Builder("bentobox", "Level", "1.3").description("test")
|
||||
.authors("tastybento").build();
|
||||
addon.setDescription(desc);
|
||||
addon.setSettings(new ConfigSettings());
|
||||
// Addons manager
|
||||
when(plugin.getAddonsManager()).thenReturn(am);
|
||||
// One game mode
|
||||
when(am.getGameModeAddons()).thenReturn(Collections.singletonList(gameMode));
|
||||
AddonDescription desc2 = new AddonDescription.Builder("bentobox", "BSkyBlock", "1.3").description("test")
|
||||
.authors("tasty").build();
|
||||
when(gameMode.getDescription()).thenReturn(desc2);
|
||||
when(gameMode.getOverWorld()).thenReturn(world);
|
||||
|
||||
// Player command
|
||||
@NonNull
|
||||
Optional<CompositeCommand> opCmd = Optional.of(cmd);
|
||||
when(gameMode.getPlayerCommand()).thenReturn(opCmd);
|
||||
// Admin command
|
||||
Optional<CompositeCommand> opAdminCmd = Optional.of(adminCmd);
|
||||
when(gameMode.getAdminCommand()).thenReturn(opAdminCmd);
|
||||
|
||||
// Flags manager
|
||||
when(plugin.getFlagsManager()).thenReturn(fm);
|
||||
when(fm.getFlags()).thenReturn(Collections.emptyList());
|
||||
|
||||
// Bukkit
|
||||
PowerMockito.mockStatic(Bukkit.class);
|
||||
when(Bukkit.getScheduler()).thenReturn(scheduler);
|
||||
ItemMeta meta = mock(ItemMeta.class);
|
||||
ItemFactory itemFactory = mock(ItemFactory.class);
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(meta);
|
||||
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
|
||||
UnsafeValues unsafe = mock(UnsafeValues.class);
|
||||
when(unsafe.getDataVersion()).thenReturn(777);
|
||||
when(Bukkit.getUnsafe()).thenReturn(unsafe);
|
||||
when(Bukkit.getPluginManager()).thenReturn(pim);
|
||||
|
||||
// placeholders
|
||||
when(plugin.getPlaceholdersManager()).thenReturn(phm);
|
||||
|
||||
// World
|
||||
when(world.getName()).thenReturn("bskyblock-world");
|
||||
// Island
|
||||
when(island.getWorld()).thenReturn(world);
|
||||
when(island.getOwner()).thenReturn(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
deleteAll(new File("database"));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void cleanUp() throws Exception {
|
||||
new File("addon.jar").delete();
|
||||
new File("config.yml").delete();
|
||||
new File("blockconfig.yml").delete();
|
||||
deleteAll(new File("addons"));
|
||||
}
|
||||
|
||||
private static void deleteAll(File file) throws IOException {
|
||||
if (file.exists()) {
|
||||
Files.walk(file.toPath()).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.level.Level#onEnable()}.
|
||||
*/
|
||||
@Test
|
||||
public void testOnEnable() {
|
||||
addon.onEnable();
|
||||
verify(plugin).logWarning("[Level] Level Addon: No such world in blockconfig.yml : acidisland_world");
|
||||
verify(plugin).log("[Level] Level hooking into BSkyBlock");
|
||||
verify(cmd, times(3)).getAddon(); // 3 commands
|
||||
verify(adminCmd, times(5)).getAddon(); // Five commands
|
||||
// Placeholders
|
||||
verify(phm).registerPlaceholder(eq(addon), eq("bskyblock_island_level"), any());
|
||||
verify(phm).registerPlaceholder(eq(addon), eq("bskyblock_visited_island_level"), any());
|
||||
verify(phm).registerPlaceholder(eq(addon), eq("bskyblock_points_to_next_level"), any());
|
||||
for (int i = 1; i < 11; i++) {
|
||||
verify(phm).registerPlaceholder(eq(addon), eq("bskyblock_top_name_" + i), any());
|
||||
verify(phm).registerPlaceholder(eq(addon), eq("bskyblock_top_value_" + i), any());
|
||||
}
|
||||
// Commands
|
||||
verify(am).registerListener(eq(addon), any(IslandActivitiesListeners.class));
|
||||
verify(am).registerListener(eq(addon), any(JoinLeaveListener.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.level.Level#getSettings()}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetSettings() {
|
||||
addon.onEnable();
|
||||
ConfigSettings s = addon.getSettings();
|
||||
assertEquals(100, s.getLevelCost());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,464 @@
|
|||
package world.bentobox.level;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemFactory;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.junit.After;
|
||||
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.stubbing.Answer;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.powermock.reflect.Whitebox;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.Settings;
|
||||
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.AbstractDatabaseHandler;
|
||||
import world.bentobox.bentobox.database.DatabaseSetup;
|
||||
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
import world.bentobox.bentobox.managers.PlayersManager;
|
||||
import world.bentobox.level.calculators.Pipeliner;
|
||||
import world.bentobox.level.calculators.Results;
|
||||
import world.bentobox.level.config.ConfigSettings;
|
||||
import world.bentobox.level.objects.IslandLevels;
|
||||
import world.bentobox.level.objects.TopTenData;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({ Bukkit.class, BentoBox.class, DatabaseSetup.class, PanelBuilder.class })
|
||||
public class LevelsManagerTest {
|
||||
|
||||
@Mock
|
||||
private static AbstractDatabaseHandler<Object> handler;
|
||||
@Mock
|
||||
Level addon;
|
||||
@Mock
|
||||
private BentoBox plugin;
|
||||
@Mock
|
||||
private Settings pluginSettings;
|
||||
|
||||
// Class under test
|
||||
private LevelsManager lm;
|
||||
@Mock
|
||||
private Island island;
|
||||
@Mock
|
||||
private Pipeliner pipeliner;
|
||||
private CompletableFuture<Results> cf;
|
||||
private UUID uuid;
|
||||
@Mock
|
||||
private World world;
|
||||
@Mock
|
||||
private Player player;
|
||||
@Mock
|
||||
private ConfigSettings settings;
|
||||
@Mock
|
||||
private User user;
|
||||
@Mock
|
||||
private PlayersManager pm;
|
||||
@Mock
|
||||
private Inventory inv;
|
||||
@Mock
|
||||
private IslandWorldManager iwm;
|
||||
@Mock
|
||||
private PluginManager pim;
|
||||
@Mock
|
||||
private IslandLevels levelsData;
|
||||
@Mock
|
||||
private IslandsManager im;
|
||||
@Mock
|
||||
private BukkitScheduler scheduler;
|
||||
|
||||
@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
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
when(addon.getPlugin()).thenReturn(plugin);
|
||||
// Set up plugin
|
||||
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
|
||||
|
||||
// Bukkit
|
||||
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
|
||||
when(Bukkit.getWorld(anyString())).thenReturn(world);
|
||||
when(Bukkit.getPluginManager()).thenReturn(pim);
|
||||
when(Bukkit.getPlayer(any(UUID.class))).thenReturn(player);
|
||||
when(Bukkit.getScheduler()).thenReturn(scheduler);
|
||||
|
||||
// The database type has to be created one line before the thenReturn() to work!
|
||||
DatabaseType value = DatabaseType.JSON;
|
||||
when(plugin.getSettings()).thenReturn(pluginSettings);
|
||||
when(pluginSettings.getDatabaseType()).thenReturn(value);
|
||||
|
||||
// Pipeliner
|
||||
when(addon.getPipeliner()).thenReturn(pipeliner);
|
||||
cf = new CompletableFuture<>();
|
||||
when(pipeliner.addIsland(any())).thenReturn(cf);
|
||||
|
||||
// Island
|
||||
when(addon.getIslands()).thenReturn(im);
|
||||
uuid = UUID.randomUUID();
|
||||
ImmutableSet<UUID> iset = ImmutableSet.of(uuid);
|
||||
when(island.getMemberSet()).thenReturn(iset);
|
||||
when(island.getOwner()).thenReturn(uuid);
|
||||
when(island.getWorld()).thenReturn(world);
|
||||
when(island.getUniqueId()).thenReturn(uuid.toString());
|
||||
// Default to uuid's being island owners
|
||||
when(im.hasIsland(eq(world), any(UUID.class))).thenReturn(true);
|
||||
when(im.getIsland(world, uuid)).thenReturn(island);
|
||||
when(im.getIslandById(anyString())).thenReturn(Optional.of(island));
|
||||
when(im.getIslandById(anyString(), eq(false))).thenReturn(Optional.of(island));
|
||||
|
||||
// Player
|
||||
when(player.getUniqueId()).thenReturn(uuid);
|
||||
when(player.hasPermission(anyString())).thenReturn(true);
|
||||
|
||||
// World
|
||||
when(world.getName()).thenReturn("bskyblock-world");
|
||||
|
||||
// Settings
|
||||
when(addon.getSettings()).thenReturn(settings);
|
||||
|
||||
// User
|
||||
when(user.getTranslation(anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
|
||||
when(user.getTranslation(eq("island.top.gui-heading"), eq("[name]"), anyString(), eq("[rank]"), anyString())).thenReturn("gui-heading");
|
||||
when(user.getTranslation(eq("island.top.island-level"),eq("[level]"), anyString())).thenReturn("island-level");
|
||||
when(user.getPlayer()).thenReturn(player);
|
||||
|
||||
// Player Manager
|
||||
when(addon.getPlayers()).thenReturn(pm);
|
||||
when(pm.getName(any())).thenReturn("player1",
|
||||
"player2",
|
||||
"player3",
|
||||
"player4",
|
||||
"player5",
|
||||
"player6",
|
||||
"player7",
|
||||
"player8",
|
||||
"player9",
|
||||
"player10"
|
||||
);
|
||||
// Mock item factory (for itemstacks)
|
||||
ItemFactory itemFactory = mock(ItemFactory.class);
|
||||
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
|
||||
ItemMeta itemMeta = mock(ItemMeta.class);
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(itemMeta);
|
||||
|
||||
// Has perms
|
||||
when(player.hasPermission(anyString())).thenReturn(true);
|
||||
// Make island levels
|
||||
|
||||
List<Object> islands = new ArrayList<>();
|
||||
for (long i = -5; i < 5; i ++) {
|
||||
IslandLevels il = new IslandLevels(UUID.randomUUID().toString());
|
||||
il.setInitialLevel(3);
|
||||
il.setLevel(i);
|
||||
il.setPointsToNextLevel(3);
|
||||
islands.add(il);
|
||||
}
|
||||
// Supply no island levels first (for migrate), then islands
|
||||
when(handler.loadObjects()).thenReturn(Collections.emptyList(), islands);
|
||||
when(handler.objectExists(anyString())).thenReturn(true);
|
||||
when(levelsData.getLevel()).thenReturn(-5L, -4L, -3L, -2L, -1L, 0L, 1L, 2L, 3L, 4L, 5L, 45678L);
|
||||
when(levelsData.getUniqueId()).thenReturn(uuid.toString());
|
||||
when(handler.loadObject(anyString())).thenReturn(levelsData );
|
||||
|
||||
|
||||
// Inventory GUI
|
||||
when(Bukkit.createInventory(any(), anyInt(), anyString())).thenReturn(inv);
|
||||
|
||||
// IWM
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
when(iwm.getPermissionPrefix(any())).thenReturn("bskyblock.");
|
||||
|
||||
lm = new LevelsManager(addon);
|
||||
lm.migrate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
deleteAll(new File("database"));
|
||||
User.clearUsers();
|
||||
Mockito.framework().clearInlineMocks();
|
||||
}
|
||||
|
||||
private static void deleteAll(File file) throws IOException {
|
||||
if (file.exists()) {
|
||||
Files.walk(file.toPath()).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#calculateLevel(UUID, world.bentobox.bentobox.database.objects.Island)}.
|
||||
*/
|
||||
@Test
|
||||
public void testCalculateLevel() {
|
||||
Results results = new Results();
|
||||
results.setLevel(10000);
|
||||
results.setInitialLevel(3);
|
||||
lm.calculateLevel(uuid, island);
|
||||
// Complete the pipelined completable future
|
||||
cf.complete(results);
|
||||
|
||||
assertEquals(10000L, lm.getLevelsData(island).getLevel());
|
||||
// Map<UUID, Long> tt = lm.getTopTen(world, 10);
|
||||
// assertEquals(1, tt.size());
|
||||
// assertTrue(tt.get(uuid) == 10000);
|
||||
assertEquals(10000L, lm.getIslandMaxLevel(world, uuid));
|
||||
|
||||
results.setLevel(5000);
|
||||
lm.calculateLevel(uuid, island);
|
||||
// Complete the pipelined completable future
|
||||
cf.complete(results);
|
||||
assertEquals(5000L, lm.getLevelsData(island).getLevel());
|
||||
// Still should be 10000
|
||||
assertEquals(10000L, lm.getIslandMaxLevel(world, uuid));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#getInitialLevel(world.bentobox.bentobox.database.objects.Island)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetInitialLevel() {
|
||||
assertEquals(0, lm.getInitialLevel(island));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#getIslandLevel(org.bukkit.World, java.util.UUID)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetIslandLevel() {
|
||||
assertEquals(-5, lm.getIslandLevel(world, uuid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#getPointsToNextString(org.bukkit.World, java.util.UUID)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetPointsToNextString() {
|
||||
// No island player
|
||||
assertEquals("", lm.getPointsToNextString(world, UUID.randomUUID()));
|
||||
// Player has island
|
||||
assertEquals("0", lm.getPointsToNextString(world, uuid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#getIslandLevelString(org.bukkit.World, java.util.UUID)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetIslandLevelString() {
|
||||
assertEquals("-5", lm.getIslandLevelString(world, uuid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#getLevelsData(java.util.UUID)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetLevelsData() {
|
||||
assertEquals(levelsData, lm.getLevelsData(island));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.level.LevelsManager#formatLevel(long)}.
|
||||
*/
|
||||
@Test
|
||||
public void testFormatLevel() {
|
||||
assertEquals("123456789", lm.formatLevel(123456789L));
|
||||
when(settings.isShorthand()).thenReturn(true);
|
||||
assertEquals("123.5M", lm.formatLevel(123456789L));
|
||||
assertEquals("1.2k", lm.formatLevel(1234L));
|
||||
assertEquals("123.5G", lm.formatLevel(123456789352L));
|
||||
assertEquals("1.2T", lm.formatLevel(1234567893524L));
|
||||
assertEquals("12345.7T", lm.formatLevel(12345678345345349L));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#getTopTen(org.bukkit.World, int)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetTopTenEmpty() {
|
||||
Map<String, Long> tt = lm.getTopTen(world, Level.TEN);
|
||||
assertTrue(tt.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#getTopTen(org.bukkit.World, int)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetTopTen() {
|
||||
testLoadTopTens();
|
||||
Map<String, Long> tt = lm.getTopTen(world, Level.TEN);
|
||||
assertFalse(tt.isEmpty());
|
||||
assertEquals(1, tt.size());
|
||||
assertEquals(1, lm.getTopTen(world, 1).size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#getWeightedTopTen(org.bukkit.World, int)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetWeightedTopTen() {
|
||||
testLoadTopTens();
|
||||
Map<Island, Long> tt = lm.getWeightedTopTen(world, Level.TEN);
|
||||
assertFalse(tt.isEmpty());
|
||||
assertEquals(1, tt.size());
|
||||
assertEquals(1, lm.getTopTen(world, 1).size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#hasTopTenPerm(org.bukkit.World, java.util.UUID)}.
|
||||
*/
|
||||
@Test
|
||||
public void testHasTopTenPerm() {
|
||||
assertTrue(lm.hasTopTenPerm(world, uuid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.level.LevelsManager#loadTopTens()}.
|
||||
*/
|
||||
@Test
|
||||
public void testLoadTopTens() {
|
||||
ArgumentCaptor<Runnable> task = ArgumentCaptor.forClass(Runnable.class);
|
||||
lm.loadTopTens();
|
||||
PowerMockito.verifyStatic(Bukkit.class); // 1
|
||||
Bukkit.getScheduler();
|
||||
verify(scheduler).runTaskAsynchronously(eq(plugin), task.capture()); // Capture the task in the scheduler
|
||||
task.getValue().run(); // run it
|
||||
verify(addon).log("Generating rankings");
|
||||
verify(addon).log("Generated rankings for bskyblock-world");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#removeEntry(org.bukkit.World, java.util.UUID)}.
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveEntry() {
|
||||
testLoadTopTens();
|
||||
Map<String, Long> tt = lm.getTopTen(world, Level.TEN);
|
||||
assertTrue(tt.containsKey(uuid.toString()));
|
||||
lm.removeEntry(world, uuid.toString());
|
||||
tt = lm.getTopTen(world, Level.TEN);
|
||||
assertFalse(tt.containsKey(uuid.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#setInitialIslandLevel(world.bentobox.bentobox.database.objects.Island, long)}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetInitialIslandLevel() {
|
||||
lm.setInitialIslandLevel(island, Level.TEN);
|
||||
assertEquals(Level.TEN, lm.getInitialLevel(island));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#setIslandLevel(org.bukkit.World, java.util.UUID, long)}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetIslandLevel() {
|
||||
lm.setIslandLevel(world, uuid, 1234);
|
||||
assertEquals(1234, lm.getIslandLevel(world, uuid));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.LevelsManager#getRank(World, UUID)}
|
||||
*/
|
||||
@Test
|
||||
public void testGetRank() {
|
||||
lm.createAndCleanRankings(world);
|
||||
Map<World, TopTenData> ttl = lm.getTopTenLists();
|
||||
Map<String, Long> tt = ttl.get(world).getTopTen();
|
||||
for (long i = 100; i < 150; i++) {
|
||||
tt.put(UUID.randomUUID().toString(), i);
|
||||
}
|
||||
// Put island as lowest rank
|
||||
tt.put(uuid.toString(), 10L);
|
||||
assertEquals(51, lm.getRank(world, uuid));
|
||||
// Put island as highest rank
|
||||
tt.put(uuid.toString(), 1000L);
|
||||
assertEquals(1, lm.getRank(world, uuid));
|
||||
// Unknown UUID - lowest rank + 1
|
||||
assertEquals(52, lm.getRank(world, UUID.randomUUID()));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,333 @@
|
|||
package world.bentobox.level;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
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.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.AddonDescription;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
import world.bentobox.bentobox.managers.PlaceholdersManager;
|
||||
import world.bentobox.bentobox.managers.PlayersManager;
|
||||
import world.bentobox.bentobox.managers.RanksManager;
|
||||
import world.bentobox.level.objects.IslandLevels;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({ BentoBox.class })
|
||||
public class PlaceholderManagerTest {
|
||||
|
||||
@Mock
|
||||
private Level addon;
|
||||
@Mock
|
||||
private GameModeAddon gm;
|
||||
@Mock
|
||||
private BentoBox plugin;
|
||||
|
||||
private PlaceholderManager phm;
|
||||
@Mock
|
||||
private PlaceholdersManager bpm;
|
||||
@Mock
|
||||
private LevelsManager lm;
|
||||
@Mock
|
||||
private World world;
|
||||
@Mock
|
||||
private IslandsManager im;
|
||||
@Mock
|
||||
private Island island;
|
||||
@Mock
|
||||
private User user;
|
||||
private static final Map<UUID, String> names = new LinkedHashMap<>();
|
||||
static {
|
||||
names.put(UUID.randomUUID(), "tasty");
|
||||
names.put(UUID.randomUUID(), "bento");
|
||||
names.put(UUID.randomUUID(), "fred");
|
||||
names.put(UUID.randomUUID(), "bonne");
|
||||
names.put(UUID.randomUUID(), "cyprien");
|
||||
names.put(UUID.randomUUID(), "mael");
|
||||
names.put(UUID.randomUUID(), "joe");
|
||||
names.put(UUID.randomUUID(), "horacio");
|
||||
names.put(UUID.randomUUID(), "steph");
|
||||
names.put(UUID.randomUUID(), "vicky");
|
||||
}
|
||||
private Map<String, Island> islands = new HashMap<>();
|
||||
private Map<String, Long> map = new LinkedHashMap<>();
|
||||
private Map<Island, Long> map2 = new LinkedHashMap<>();
|
||||
private @NonNull IslandLevels data;
|
||||
@Mock
|
||||
private PlayersManager pm;
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
when(addon.getPlugin()).thenReturn(plugin);
|
||||
|
||||
// Users
|
||||
when(addon.getPlayers()).thenReturn(pm);
|
||||
|
||||
// Users
|
||||
when(user.getWorld()).thenReturn(world);
|
||||
when(user.getLocation()).thenReturn(mock(Location.class));
|
||||
|
||||
int i = 0;
|
||||
for (Entry<UUID, String> n : names.entrySet()) {
|
||||
UUID uuid = UUID.randomUUID(); // Random island ID
|
||||
Long value = (long)(100 - i++);
|
||||
map.put(uuid.toString(), value); // level
|
||||
Island is = new Island();
|
||||
is.setUniqueId(uuid.toString());
|
||||
is.setOwner(n.getKey());
|
||||
is.setName(n.getValue() + "'s island");
|
||||
islands.put(uuid.toString(), is);
|
||||
map2.put(is, value);
|
||||
}
|
||||
// Sort
|
||||
map = map.entrySet().stream()
|
||||
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
|
||||
.collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||
when(pm.getName(any())).thenAnswer((Answer<String>) invocation -> names.getOrDefault(invocation.getArgument(0, UUID.class), "unknown"));
|
||||
Map<UUID, Integer> members = new HashMap<>();
|
||||
names.forEach((uuid, l) -> members.put(uuid, RanksManager.MEMBER_RANK));
|
||||
islands.values().forEach(is -> is.setMembers(members));
|
||||
|
||||
|
||||
// Placeholders manager for plugin
|
||||
when(plugin.getPlaceholdersManager()).thenReturn(bpm);
|
||||
|
||||
// Game mode
|
||||
AddonDescription desc = new AddonDescription.Builder("bentobox", "AOneBlock", "1.3").description("test").authors("tasty").build();
|
||||
when(gm.getDescription()).thenReturn(desc);
|
||||
when(gm.getOverWorld()).thenReturn(world);
|
||||
when(gm.inWorld(world)).thenReturn(true);
|
||||
|
||||
// Islands
|
||||
when(im.getIsland(any(World.class), any(User.class))).thenReturn(island);
|
||||
when(im.getIslandAt(any(Location.class))).thenReturn(Optional.of(island));
|
||||
when(im.getIslandById(anyString())).thenAnswer((Answer<Optional<Island>>) invocation -> Optional.of(islands.get(invocation.getArgument(0, String.class))));
|
||||
when(im.getIslands(any(), any(UUID.class))).thenReturn(new ArrayList<>(islands.values()));
|
||||
when(addon.getIslands()).thenReturn(im);
|
||||
|
||||
// Levels Manager
|
||||
when(lm.getIslandLevel(any(), any())).thenReturn(1234567L);
|
||||
when(lm.getIslandLevelString(any(), any())).thenReturn("1234567");
|
||||
when(lm.getPointsToNextString(any(), any())).thenReturn("1234567");
|
||||
when(lm.getIslandMaxLevel(any(), any())).thenReturn(987654L);
|
||||
when(lm.getTopTen(world, Level.TEN)).thenReturn(map);
|
||||
when(lm.getWeightedTopTen(world, Level.TEN)).thenReturn(map2);
|
||||
when(lm.formatLevel(any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, Long.class).toString());
|
||||
|
||||
data = new IslandLevels("uniqueId");
|
||||
data.setTotalPoints(12345678);
|
||||
when(lm.getLevelsData(island)).thenReturn(data);
|
||||
when(addon.getManager()).thenReturn(lm);
|
||||
|
||||
phm = new PlaceholderManager(addon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.PlaceholderManager#PlaceholderManager(world.bentobox.level.Level)}.
|
||||
*/
|
||||
@Test
|
||||
public void testPlaceholderManager() {
|
||||
verify(addon).getPlugin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.PlaceholderManager#registerPlaceholders(world.bentobox.bentobox.api.addons.GameModeAddon)}.
|
||||
*/
|
||||
@Test
|
||||
public void testRegisterPlaceholders() {
|
||||
phm.registerPlaceholders(gm);
|
||||
// Island Level
|
||||
verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_island_level"), any());
|
||||
verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_island_level_raw"), any());
|
||||
verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_island_total_points"), any());
|
||||
|
||||
verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_points_to_next_level"), any());
|
||||
verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_island_level_max"), any());
|
||||
|
||||
// Visited Island Level
|
||||
verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_visited_island_level"), any());
|
||||
|
||||
// Register Top Ten Placeholders
|
||||
for (int i = 1; i < 11; i++) {
|
||||
// Name
|
||||
verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_top_name_" + i), any());
|
||||
// Island Name
|
||||
verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_top_island_name_" + i), any());
|
||||
// Members
|
||||
verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_top_members_" + i), any());
|
||||
// Level
|
||||
verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_top_value_" + i), any());
|
||||
}
|
||||
|
||||
// Personal rank
|
||||
verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_rank_value"), any());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.PlaceholderManager#getRankName(org.bukkit.World, int)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetRankName() {
|
||||
// Test extremes
|
||||
assertEquals("tasty", phm.getRankName(world, 0, false));
|
||||
assertEquals("vicky", phm.getRankName(world, 100, false));
|
||||
// Test the ranks
|
||||
int rank = 1;
|
||||
for (String name : names.values()) {
|
||||
assertEquals(name, phm.getRankName(world, rank++, false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.PlaceholderManager#getRankIslandName(org.bukkit.World, int)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetRankIslandName() {
|
||||
// Test extremes
|
||||
assertEquals("tasty's island", phm.getRankIslandName(world, 0, false));
|
||||
assertEquals("vicky's island", phm.getRankIslandName(world, 100, false));
|
||||
// Test the ranks
|
||||
int rank = 1;
|
||||
for (String name : names.values()) {
|
||||
assertEquals(name + "'s island", phm.getRankIslandName(world, rank++, false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.PlaceholderManager#getRankMembers(org.bukkit.World, int)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetRankMembers() {
|
||||
// Test extremes
|
||||
check(1, phm.getRankMembers(world, 0, false));
|
||||
check(2, phm.getRankMembers(world, 100, false));
|
||||
// Test the ranks
|
||||
for (int rank = 1; rank < 11; rank++) {
|
||||
check(3, phm.getRankMembers(world, rank, false));
|
||||
}
|
||||
}
|
||||
|
||||
void check(int indicator, String list) {
|
||||
for (String n : names.values()) {
|
||||
assertTrue(n + " is missing for test " + indicator, list.contains(n));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.PlaceholderManager#getRankLevel(org.bukkit.World, int)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetRankLevel() {
|
||||
// Test extremes
|
||||
assertEquals("100", phm.getRankLevel(world, 0, false));
|
||||
assertEquals("91", phm.getRankLevel(world, 100, false));
|
||||
// Test the ranks
|
||||
for (int rank = 1; rank < 11; rank++) {
|
||||
assertEquals(String.valueOf(101 - rank), phm.getRankLevel(world, rank, false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.PlaceholderManager#getRankLevel(org.bukkit.World, int)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetWeightedRankLevel() {
|
||||
// Test extremes
|
||||
assertEquals("100", phm.getRankLevel(world, 0, true));
|
||||
assertEquals("91", phm.getRankLevel(world, 100, true));
|
||||
// Test the ranks
|
||||
for (int rank = 1; rank < 11; rank++) {
|
||||
assertEquals(String.valueOf(101 - rank), phm.getRankLevel(world, rank, true));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.PlaceholderManager#getVisitedIslandLevel(world.bentobox.bentobox.api.addons.GameModeAddon, world.bentobox.bentobox.api.user.User)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetVisitedIslandLevelNullUser() {
|
||||
assertEquals("", phm.getVisitedIslandLevel(gm, null));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.level.PlaceholderManager#getVisitedIslandLevel(world.bentobox.bentobox.api.addons.GameModeAddon, world.bentobox.bentobox.api.user.User)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetVisitedIslandLevelUserNotInWorld() {
|
||||
// Another world
|
||||
when(user.getWorld()).thenReturn(mock(World.class));
|
||||
assertEquals("", phm.getVisitedIslandLevel(gm, user));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.PlaceholderManager#getVisitedIslandLevel(world.bentobox.bentobox.api.addons.GameModeAddon, world.bentobox.bentobox.api.user.User)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetVisitedIslandLevel() {
|
||||
assertEquals("1234567", phm.getVisitedIslandLevel(gm, user));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.level.PlaceholderManager#getVisitedIslandLevel(world.bentobox.bentobox.api.addons.GameModeAddon, world.bentobox.bentobox.api.user.User)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetVisitedIslandLevelNoIsland() {
|
||||
when(im.getIslandAt(any(Location.class))).thenReturn(Optional.empty());
|
||||
assertEquals("0", phm.getVisitedIslandLevel(gm, user));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package world.bentobox.level.calculators;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test the equation evaluation
|
||||
*/
|
||||
public class EquationEvaluatorTest {
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.level.calculators.EquationEvaluator#eval(java.lang.String)}.
|
||||
* @throws ParseException
|
||||
*/
|
||||
@Test
|
||||
public void testEval() throws ParseException {
|
||||
assertEquals(4D, EquationEvaluator.eval("2+2"), 0D);
|
||||
assertEquals(0D, EquationEvaluator.eval("2-2"), 0D);
|
||||
assertEquals(1D, EquationEvaluator.eval("2/2"), 0D);
|
||||
assertEquals(4D, EquationEvaluator.eval("2*2"), 0D);
|
||||
assertEquals(8D, EquationEvaluator.eval("2+2+2+2"), 0D);
|
||||
assertEquals(5D, EquationEvaluator.eval("2.5+2.5"), 0D);
|
||||
assertEquals(1.414, EquationEvaluator.eval("sqrt(2)"), 0.001D);
|
||||
assertEquals(3.414, EquationEvaluator.eval("2 + sqrt(2)"), 0.001D);
|
||||
assertEquals(0D, EquationEvaluator.eval("sin(0)"), 0.1D);
|
||||
assertEquals(1D, EquationEvaluator.eval("cos(0)"), 0.1D);
|
||||
assertEquals(0D, EquationEvaluator.eval("tan(0)"), 0.1D);
|
||||
assertEquals(0D, EquationEvaluator.eval("log(1)"), 0.1D);
|
||||
assertEquals(27D, EquationEvaluator.eval("3^3"), 0.D);
|
||||
assertEquals(84.70332D, EquationEvaluator.eval("3^3 + 2 + 2.65 * (3 / 4) - sin(45) * log(10) + 55.344"),
|
||||
0.0001D);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
package world.bentobox.level.commands;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemFactory;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.powermock.reflect.Whitebox;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
import world.bentobox.bentobox.managers.LocalesManager;
|
||||
import world.bentobox.bentobox.managers.PlayersManager;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.LevelsManager;
|
||||
import world.bentobox.level.objects.TopTenData;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({ Bukkit.class, BentoBox.class })
|
||||
public class AdminStatsCommandTest {
|
||||
|
||||
@Mock
|
||||
private CompositeCommand ic;
|
||||
private UUID uuid;
|
||||
@Mock
|
||||
private User user;
|
||||
@Mock
|
||||
private IslandsManager im;
|
||||
@Mock
|
||||
private Island island;
|
||||
@Mock
|
||||
private Level addon;
|
||||
@Mock
|
||||
private World world;
|
||||
@Mock
|
||||
private IslandWorldManager iwm;
|
||||
@Mock
|
||||
private GameModeAddon gameModeAddon;
|
||||
@Mock
|
||||
private Player p;
|
||||
@Mock
|
||||
private LocalesManager lm;
|
||||
@Mock
|
||||
private PlayersManager pm;
|
||||
|
||||
private AdminStatsCommand asc;
|
||||
private TopTenData ttd;
|
||||
@Mock
|
||||
private LevelsManager manager;
|
||||
@Mock
|
||||
private Server server;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// Set up plugin
|
||||
BentoBox plugin = mock(BentoBox.class);
|
||||
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
|
||||
User.setPlugin(plugin);
|
||||
when(addon.getPlugin()).thenReturn(plugin);
|
||||
|
||||
// Addon
|
||||
when(ic.getAddon()).thenReturn(addon);
|
||||
when(ic.getPermissionPrefix()).thenReturn("bskyblock.");
|
||||
when(ic.getLabel()).thenReturn("island");
|
||||
when(ic.getTopLabel()).thenReturn("island");
|
||||
when(ic.getWorld()).thenReturn(world);
|
||||
when(ic.getTopLabel()).thenReturn("bsb");
|
||||
|
||||
// IWM friendly name
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
|
||||
|
||||
// World
|
||||
when(world.toString()).thenReturn("world");
|
||||
when(world.getName()).thenReturn("BSkyBlock_world");
|
||||
|
||||
// Player manager
|
||||
when(plugin.getPlayers()).thenReturn(pm);
|
||||
when(pm.getUser(anyString())).thenReturn(user);
|
||||
// topTen
|
||||
when(addon.getManager()).thenReturn(manager);
|
||||
// User
|
||||
uuid = UUID.randomUUID();
|
||||
when(user.getUniqueId()).thenReturn(uuid);
|
||||
when(user.getTranslation(any())).thenAnswer(invocation -> invocation.getArgument(0, String.class));
|
||||
|
||||
// Bukkit
|
||||
PowerMockito.mockStatic(Bukkit.class);
|
||||
when(Bukkit.getServer()).thenReturn(server);
|
||||
// Mock item factory (for itemstacks)
|
||||
ItemFactory itemFactory = mock(ItemFactory.class);
|
||||
ItemMeta itemMeta = mock(ItemMeta.class);
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(itemMeta);
|
||||
when(server.getItemFactory()).thenReturn(itemFactory);
|
||||
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
|
||||
|
||||
// Top ten
|
||||
ttd = new TopTenData(world);
|
||||
Map<String, Long> topten = new HashMap<>();
|
||||
Random r = new Random();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
topten.put(UUID.randomUUID().toString(), r.nextLong(20000));
|
||||
}
|
||||
ttd.setTopTen(topten);
|
||||
asc = new AdminStatsCommand(addon, ic);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
User.clearUsers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.commands.AdminStatsCommand#setup()}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetup() {
|
||||
assertEquals("bskyblock.admin.stats", asc.getPermission());
|
||||
assertFalse(asc.isOnlyPlayer());
|
||||
assertEquals("admin.stats.description", asc.getDescription());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.commands.AdminStatsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteUserStringListOfString() {
|
||||
assertFalse(asc.execute(user, "", List.of()));
|
||||
verify(user).sendMessage("admin.stats.title");
|
||||
verify(user).sendMessage("admin.stats.no-data");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.commands.AdminStatsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteUserStringListOfStringLevels() {
|
||||
Map<World, TopTenData> map = new HashMap<>();
|
||||
map.put(world, ttd);
|
||||
when(manager.getTopTenLists()).thenReturn(map);
|
||||
assertTrue(asc.execute(user, "", List.of()));
|
||||
verify(user).sendMessage("admin.stats.title");
|
||||
verify(user, never()).sendMessage("admin.stats.no-data");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
package world.bentobox.level.commands;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemFactory;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.powermock.reflect.Whitebox;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
import world.bentobox.bentobox.managers.LocalesManager;
|
||||
import world.bentobox.bentobox.managers.PlayersManager;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.LevelsManager;
|
||||
import world.bentobox.level.objects.TopTenData;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({ Bukkit.class, BentoBox.class })
|
||||
public class AdminTopRemoveCommandTest {
|
||||
|
||||
@Mock
|
||||
private CompositeCommand ic;
|
||||
private UUID uuid;
|
||||
@Mock
|
||||
private User user;
|
||||
@Mock
|
||||
private IslandsManager im;
|
||||
@Mock
|
||||
private Island island;
|
||||
@Mock
|
||||
private Level addon;
|
||||
@Mock
|
||||
private World world;
|
||||
@Mock
|
||||
private IslandWorldManager iwm;
|
||||
@Mock
|
||||
private GameModeAddon gameModeAddon;
|
||||
@Mock
|
||||
private Player p;
|
||||
@Mock
|
||||
private LocalesManager lm;
|
||||
@Mock
|
||||
private PlayersManager pm;
|
||||
|
||||
private AdminTopRemoveCommand atrc;
|
||||
@Mock
|
||||
private TopTenData ttd;
|
||||
@Mock
|
||||
private LevelsManager manager;
|
||||
@Mock
|
||||
private Server server;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// Set up plugin
|
||||
BentoBox plugin = mock(BentoBox.class);
|
||||
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
|
||||
User.setPlugin(plugin);
|
||||
|
||||
// Addon
|
||||
when(ic.getAddon()).thenReturn(addon);
|
||||
when(ic.getPermissionPrefix()).thenReturn("bskyblock.");
|
||||
when(ic.getLabel()).thenReturn("island");
|
||||
when(ic.getTopLabel()).thenReturn("island");
|
||||
when(ic.getWorld()).thenReturn(world);
|
||||
when(ic.getTopLabel()).thenReturn("bsb");
|
||||
|
||||
// IWM friendly name
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
|
||||
|
||||
// World
|
||||
when(world.toString()).thenReturn("world");
|
||||
when(world.getName()).thenReturn("BSkyBlock_world");
|
||||
|
||||
// Player manager
|
||||
when(plugin.getPlayers()).thenReturn(pm);
|
||||
when(pm.getUser(anyString())).thenReturn(user);
|
||||
// topTen
|
||||
when(addon.getManager()).thenReturn(manager);
|
||||
// User
|
||||
uuid = UUID.randomUUID();
|
||||
when(user.getUniqueId()).thenReturn(uuid);
|
||||
when(user.getTranslation(any())).thenAnswer(invocation -> invocation.getArgument(0, String.class));
|
||||
// Island
|
||||
when(island.getUniqueId()).thenReturn(uuid.toString());
|
||||
when(island.getOwner()).thenReturn(uuid);
|
||||
// Island Manager
|
||||
when(plugin.getIslands()).thenReturn(im);
|
||||
when(im.getIslands(any(), any(User.class))).thenReturn(List.of(island));
|
||||
when(im.getIslands(any(), any(UUID.class))).thenReturn(List.of(island));
|
||||
|
||||
// Bukkit
|
||||
PowerMockito.mockStatic(Bukkit.class);
|
||||
when(Bukkit.getServer()).thenReturn(server);
|
||||
// Mock item factory (for itemstacks)
|
||||
ItemFactory itemFactory = mock(ItemFactory.class);
|
||||
ItemMeta itemMeta = mock(ItemMeta.class);
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(itemMeta);
|
||||
when(server.getItemFactory()).thenReturn(itemFactory);
|
||||
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
|
||||
|
||||
atrc = new AdminTopRemoveCommand(addon, ic);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
User.clearUsers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#AdminTopRemoveCommand(world.bentobox.level.Level, world.bentobox.bentobox.api.commands.CompositeCommand)}.
|
||||
*/
|
||||
@Test
|
||||
public void testAdminTopRemoveCommand() {
|
||||
assertEquals("remove", atrc.getLabel());
|
||||
assertEquals("delete", atrc.getAliases().get(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#setup()}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetup() {
|
||||
assertEquals("bskyblock.admin.top.remove", atrc.getPermission());
|
||||
assertEquals("admin.top.remove.parameters", atrc.getParameters());
|
||||
assertEquals("admin.top.remove.description", atrc.getDescription());
|
||||
assertFalse(atrc.isOnlyPlayer());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
|
||||
*/
|
||||
@Test
|
||||
public void testCanExecuteWrongArgs() {
|
||||
assertFalse(atrc.canExecute(user, "delete", Collections.emptyList()));
|
||||
verify(user).sendMessage("commands.help.header", TextVariables.LABEL, "BSkyBlock");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
|
||||
*/
|
||||
@Test
|
||||
public void testCanExecuteUnknown() {
|
||||
when(pm.getUser(anyString())).thenReturn(null);
|
||||
assertFalse(atrc.canExecute(user, "delete", Collections.singletonList("tastybento")));
|
||||
verify(user).sendMessage("general.errors.unknown-player", TextVariables.NAME, "tastybento");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
|
||||
*/
|
||||
@Test
|
||||
public void testCanExecuteKnown() {
|
||||
assertTrue(atrc.canExecute(user, "delete", Collections.singletonList("tastybento")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteUserStringListOfString() {
|
||||
testCanExecuteKnown();
|
||||
assertTrue(atrc.execute(user, "delete", Collections.singletonList("tastybento")));
|
||||
verify(manager).removeEntry(world, uuid.toString());
|
||||
verify(user).sendMessage("general.success");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue