├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── docs └── MAIN-CLASSES.md ├── pom.xml └── src ├── main ├── java │ └── world │ │ └── bentobox │ │ └── level │ │ ├── Level.java │ │ ├── LevelPladdon.java │ │ ├── LevelsManager.java │ │ ├── PlaceholderManager.java │ │ ├── calculators │ │ ├── EquationEvaluator.java │ │ ├── IslandLevelCalculator.java │ │ ├── Pipeliner.java │ │ ├── Results.java │ │ └── UltimateStackerCalc.java │ │ ├── commands │ │ ├── AdminLevelCommand.java │ │ ├── AdminLevelStatusCommand.java │ │ ├── AdminSetInitialLevelCommand.java │ │ ├── AdminStatsCommand.java │ │ ├── AdminTopCommand.java │ │ ├── AdminTopRemoveCommand.java │ │ ├── IslandDetailCommand.java │ │ ├── IslandLevelCommand.java │ │ ├── IslandTopCommand.java │ │ └── IslandValueCommand.java │ │ ├── config │ │ ├── BlockConfig.java │ │ └── ConfigSettings.java │ │ ├── events │ │ ├── IslandLevelCalculatedEvent.java │ │ └── IslandPreLevelEvent.java │ │ ├── listeners │ │ ├── IslandActivitiesListeners.java │ │ ├── JoinLeaveListener.java │ │ └── MigrationListener.java │ │ ├── objects │ │ ├── IslandLevels.java │ │ ├── LevelsData.java │ │ └── TopTenData.java │ │ ├── panels │ │ ├── DetailsPanel.java │ │ ├── TopLevelPanel.java │ │ └── ValuePanel.java │ │ ├── requests │ │ ├── LevelRequestHandler.java │ │ └── TopTenRequestHandler.java │ │ └── util │ │ ├── CachedData.java │ │ ├── ConversationUtils.java │ │ └── Utils.java └── resources │ ├── addon.yml │ ├── blockconfig.yml │ ├── config.yml │ ├── locales │ ├── cs.yml │ ├── de.yml │ ├── en-US.yml │ ├── es.yml │ ├── fr.yml │ ├── hu.yml │ ├── id.yml │ ├── ko.yml │ ├── lv.yml │ ├── nl.yml │ ├── pl.yml │ ├── pt.yml │ ├── tr.yml │ ├── uk.yml │ ├── vi.yml │ └── zh-CN.yml │ ├── panels │ ├── detail_panel.yml │ ├── top_panel.yml │ └── value_panel.yml │ └── plugin.yml └── test └── java └── world └── bentobox └── level ├── LevelTest.java ├── LevelsManagerTest.java ├── PlaceholderManagerTest.java ├── calculators └── EquationEvaluatorTest.java ├── commands ├── AdminStatsCommandTest.java └── AdminTopRemoveCommandTest.java └── mocks └── ServerMocks.java /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - develop 6 | - master 7 | pull_request: 8 | types: [opened, synchronize, reopened] 9 | jobs: 10 | build: 11 | name: Build 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | with: 16 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 17 | - name: Set up JDK 21 18 | uses: actions/setup-java@v4 19 | with: 20 | distribution: 'adopt' 21 | java-version: '21' 22 | - name: Cache SonarCloud packages 23 | uses: actions/cache@v4 24 | with: 25 | path: ~/.sonar/cache 26 | key: ${{ runner.os }}-sonar 27 | restore-keys: ${{ runner.os }}-sonar 28 | - name: Cache Maven packages 29 | uses: actions/cache@v4 30 | with: 31 | path: ~/.m2 32 | key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} 33 | restore-keys: ${{ runner.os }}-m2 34 | - name: Build and analyze 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any 37 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 38 | run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Git 2 | *.orig 3 | !.gitignore 4 | /.settings/ 5 | 6 | # Windows 7 | Thumbs.db 8 | ehthumbs.db 9 | ehthumbs_vista.db 10 | *.stackdump 11 | [Dd]esktop.ini 12 | $RECYCLE.BIN/ 13 | *.lnk 14 | 15 | # Linux 16 | *~ 17 | .fuse_hidden* 18 | .directory 19 | .Trash-* 20 | .nfs* 21 | 22 | # MacOS 23 | .DS_Store 24 | .AppleDouble 25 | .LSOverride 26 | ._* 27 | 28 | # Java 29 | *.class 30 | *.log 31 | *.ctxt 32 | .mtj.tmp/ 33 | *.jar 34 | *.war 35 | *.nar 36 | *.ear 37 | hs_err_pid* 38 | 39 | # Maven 40 | target/ 41 | pom.xml.tag 42 | pom.xml.releaseBackup 43 | pom.xml.versionsBackup 44 | pom.xml.next 45 | release.properties 46 | dependency-reduced-pom.xml 47 | buildNumber.properties 48 | 49 | # Intellij 50 | *.iml 51 | *.java___jb_tmp___ 52 | .idea/* 53 | *.ipr 54 | *.iws 55 | /out/ 56 | .idea_modules/ 57 | 58 | # Eclipse 59 | *.pydevproject 60 | .metadata 61 | .gradle 62 | bin/ 63 | tmp/ 64 | *.tmp 65 | *.bak 66 | *.swp 67 | *~.nib 68 | local.properties 69 | .settings/ 70 | .loadpath 71 | .project 72 | .externalToolBuilders/ 73 | *.launch 74 | .cproject 75 | .classpath 76 | .buildpath 77 | .target 78 | 79 | # NetBeans 80 | nbproject/private/ 81 | build/ 82 | nbbuild/ 83 | dist/ 84 | nbdist/ 85 | nbactions.xml 86 | nb-configuration.xml 87 | .nb-gradle/ 88 | /.idea/ 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🌟 Level Add-on for BentoBox 2 | [![Build Status](https://ci.codemc.org/buildStatus/icon?job=BentoBoxWorld/Level)](https://ci.codemc.org/job/BentoBoxWorld/job/Level/)[ 3 | ![Bugs](https://sonarcloud.io/api/project_badges/measure?project=BentoBoxWorld_Level&metric=bugs)](https://sonarcloud.io/dashboard?id=BentoBoxWorld_Level) 4 | [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=BentoBoxWorld_Level&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=BentoBoxWorld_Level) 5 | [![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=BentoBoxWorld_Level&metric=ncloc)](https://sonarcloud.io/dashboard?id=BentoBoxWorld_Level) 6 | 7 | ## 🔍 What is Level? 8 | 9 | **Level** is the ultimate competition booster for your BentoBox server! Designed for game modes like **BSkyBlock**, **AcidIsland**, and more, this powerful add-on turns your island into a battleground of **block-by-block domination**. 10 | 11 | Every block you place counts toward your **island level**—and every block you lose could cost you your spot in the rankings. Whether you're aiming for the top ten or just flexing your creative builds, **Level** adds stakes, strategy, and excitement to your sky-high journey. 12 | 13 | 📘 [Full Documentation](https://docs.bentobox.world/en/latest/addons/Level/) 14 | 📦 [Official Downloads](https://download.bentobox.world) 15 | 16 | --- 17 | 18 | ## 🚀 Getting Started 19 | 20 | Ready to level up? Here's how to launch **Level** on your server: 21 | 22 | 1. Drop the **Level** add-on `.jar` into your BentoBox `addons` folder. 23 | 2. Restart your server and let the magic happen. 24 | 3. A new `Level` data folder and `config.yml` will be created. 25 | 4. Open `config.yml` and customize block values, settings, and behavior to suit your game mode. 26 | 5. Restart your server again to apply changes. 27 | 28 | Now you’re all set—go build something worth leveling for! 🏗️ 29 | 30 | --- 31 | 32 | ## 🔄 Upgrading 33 | 34 | When updating, always read the **release notes**! 35 | Some updates might require a fresh `config.yml`, so make backups and review changes carefully. 36 | 37 | --- 38 | 39 | ## 🛡️ Permissions 40 | 41 | **Level** integrates directly with your permissions plugin, giving players the tools to compete while letting admins keep control. 42 | 43 | Default permissions for **BSkyBlock**, **AcidIsland**, and **CaveBlock**: 44 | 45 | ``` 46 | permissions: 47 | bskyblock.intopten: # Show up in top 10 48 | default: true 49 | bskyblock.island.level: # Use /is level 50 | default: true 51 | bskyblock.island.top: # Use /is top 52 | default: true 53 | bskyblock.island.value: # Use /is value 54 | default: true 55 | bskyblock.admin.level: # Admin access to /is level 56 | default: true 57 | bskyblock.admin.topten: # Admin access to /is topten 58 | default: true 59 | ``` 60 | 61 | ⚠️ Players need `intopten` to appear in the leaderboard! 62 | 63 | --- 64 | 65 | ## ⚙️ Configuration: Make It Yours 66 | 67 | The `config.yml` file gives you total control over how leveling works. Here's a breakdown of what you can tweak: 68 | 69 | ### 🎮 Game Mode Hook 70 | Tell Level which BentoBox game modes it should connect to. 71 | 72 | ### ⚙️ General Settings 73 | - **Underwater Block Multiplier** – Give bonus points for blocks below sea level. 74 | - **Level Cost** – Set how many points are needed to gain 1 island level. 75 | - **Level Wait** – Add a cooldown between level scans. 76 | - **Death Penalty** – Punish deaths with level loss. 77 | - **Sum Team Deaths** – Choose whether to track team deaths or just the leader's. 78 | - **Reset on Island Reset / Team Join** – Wipe the death count when teams change or islands are reset. 79 | 80 | ### 🚫 Block Limits 81 | Cap the number of specific blocks that count toward level (e.g., only 200 DIAMOND_BLOCKs count). 82 | 83 | Format: 84 | ``` 85 | DIAMOND_BLOCK: 200 86 | ``` 87 | 88 | ### 💎 Block Values 89 | Assign point values to blocks to reward rare or hard-to-get materials. 90 | 91 | Format: 92 | ``` 93 | STONE: 1 94 | DIAMOND_BLOCK: 100 95 | ``` 96 | 97 | Blocks not listed are worth **0**. `AIR` is always ignored. 98 | 99 | ### 🌍 World-Specific Values 100 | Customize block values for individual worlds or game modes. 101 | 102 | Example: 103 | ```yaml 104 | worlds: 105 | AcidIsland_world: 106 | SAND: 0 107 | SANDSTONE: 0 108 | ICE: 0 109 | ``` 110 | 111 | In this setup, **AcidIsland** disables points for sand-based blocks while using default values for everything else. 112 | 113 | --- 114 | 115 | ## 🏁 Final Words 116 | 117 | **Level** isn’t just a numbers game—it’s a **challenge**, a **competition**, and a **celebration** of creativity. 118 | Whether you're climbing the ranks or just making your mark, Level brings out the best in your builds. 119 | 120 | 💡 Need help or want to contribute? Join the community at [bentobox.world](https://bentobox.world) and show us what your island is made of! 121 | 122 | Now go get that top spot. 🌌 123 | — The BentoBox Team 124 | -------------------------------------------------------------------------------- /docs/MAIN-CLASSES.md: -------------------------------------------------------------------------------- 1 | # **Level Plugin Documentation** 2 | 3 | 📌 **Repository:** [BentoBoxWorld/Level](https://github.com/BentoBoxWorld/Level) 4 | 📌 **Purpose:** This document provides documentation for all major classes in the Level plugin. 5 | 📌 **Target Audience:** Programmers or maintainers of this code. 6 | 7 | ## **Table of Contents** 8 | - [Core Classes](#core-classes) 9 | - [Managers](#managers) 10 | - [Calculators](#calculators) 11 | - [Commands](#commands) 12 | - [Events](#events) 13 | - [Panels (GUI)](#panels-gui) 14 | - [Utilities](#utilities) 15 | 16 | --- 17 | 18 | ## **1️⃣ Core Classes** 19 | ### **Level** 20 | 📍 [`Level.java`](https://github.com/BentoBoxWorld/Level/blob/develop/src/main/java/world/bentobox/level/Level.java) 21 | Handles configuration, plugin hooks, and initialization. Level uses the BentoBox Addon API, which follows the Plugin style. 22 | **Main Methods:** 23 | - `onLoad()`, `onEnable()`, `allLoaded()`, `getIslandLevel()`, `setIslandLevel()` 24 | 25 | `allLoaded()` is a method that BentoBox calls when all the Addons have been loaded, which usually means that all the BentoBox worlds have been loaded. This is important because Level will be referencing worlds. 26 | `getIslandLevel()` is used by the Level addon, but is also used by external Plugins to obtain island levels for players. 27 | 28 | ### **LevelPladdon** 29 | 📍 [`LevelPladdon.java`](https://github.com/BentoBoxWorld/Level/blob/develop/src/main/java/world/bentobox/level/LevelPladdon.java) 30 | A wrapper for registering the Level addon. Pladdons are wrappers that make Addons Plugins. This is required because servers like Paper 31 | do byte-code-level conversions when the code is loaded and so the Addons have to be Plugins to benefit from this. 32 | **Main Method:** 33 | - `getAddon()` 34 | 35 | --- 36 | 37 | ## **2️⃣ Managers** 38 | ### **LevelsManager** 39 | 📍 [`LevelsManager.java`](https://github.com/BentoBoxWorld/Level/blob/develop/src/main/java/world/bentobox/level/LevelsManager.java) 40 | Manages island level calculations, leaderboards, and formatting. 41 | **Main Methods:** 42 | - `calculateLevel()`, `getIslandLevel()`, `getTopTen()` 43 | 44 | ### **PlaceholderManager** 45 | 📍 [`PlaceholderManager.java`](https://github.com/BentoBoxWorld/Level/blob/develop/src/main/java/world/bentobox/level/PlaceholderManager.java) 46 | Handles dynamic placeholders. 47 | **Main Methods:** 48 | - `registerPlaceholders()`, `getRankName()`, `getVisitedIslandLevel()` 49 | 50 | --- 51 | 52 | ## **3️⃣ Calculators** 53 | ### **EquationEvaluator** 54 | 📍 [`EquationEvaluator.java`](https://github.com/BentoBoxWorld/Level/blob/develop/src/main/java/world/bentobox/level/calculators/EquationEvaluator.java) 55 | Evaluates mathematical expressions dynamically. 56 | **Main Method:** 57 | - `eval(String)` 58 | 59 | ### **IslandLevelCalculator** 60 | 📍 [`IslandLevelCalculator.java`](https://github.com/BentoBoxWorld/Level/blob/develop/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java) 61 | Computes island levels by scanning blocks and entities. 62 | **Main Methods:** 63 | - `scanIsland()`, `calculateLevel()` 64 | 65 | ### **UltimateStackerCalc** 66 | 📍 [`UltimateStackerCalc.java`](https://github.com/BentoBoxWorld/Level/blob/develop/src/main/java/world/bentobox/level/calculators/UltimateStackerCalc.java) 67 | Handles calculations for stacked blocks from the plugin UltimateStacker. 68 | **Main Method:** 69 | - `addStackers()` 70 | 71 | --- 72 | 73 | ## **4️⃣ Commands** 74 | 📌 [Command Handlers Directory](https://github.com/BentoBoxWorld/Level/tree/develop/src/main/java/world/bentobox/level/commands) 75 | 76 | - **Admin Commands** 77 | - [`AdminLevelStatusCommand.java`](#) → Displays islands in calculation queue. 78 | - [`AdminSetInitialLevelCommand.java`](#) → Sets initial island level. 79 | 80 | - **Player Commands** 81 | - [`IslandLevelCommand.java`](#) → Triggers level calculation. 82 | - [`IslandTopCommand.java`](#) → Shows top island levels. 83 | 84 | --- 85 | 86 | ## **5️⃣ Events** 87 | ### **IslandActivitiesListeners** 88 | 📍 [`IslandActivitiesListeners.java`](https://github.com/BentoBoxWorld/Level/blob/develop/src/main/java/world/bentobox/level/listeners/IslandActivitiesListeners.java) 89 | Handles **island creation, deletion, and ownership changes**. 90 | **Main Events:** 91 | - `onNewIsland()`, `onIslandDelete()`, `onNewIslandOwner()` 92 | 93 | --- 94 | 95 | ## **6️⃣ Panels (GUI)** 96 | ### **TopLevelPanel** 97 | 📍 [`TopLevelPanel.java`](https://github.com/BentoBoxWorld/Level/blob/develop/src/main/java/world/bentobox/level/panels/TopLevelPanel.java) 98 | Displays the **top 10 ranked islands** in a GUI. 99 | **Main Methods:** 100 | - `build()`, `createPlayerButton()`, `openPanel()` 101 | 102 | ### **ValuePanel** 103 | 📍 [`ValuePanel.java`](https://github.com/BentoBoxWorld/Level/blob/develop/src/main/java/world/bentobox/level/panels/ValuePanel.java) 104 | Displays **block values** for island levels. 105 | **Main Methods:** 106 | - `build()`, `createMaterialButton()`, `openPanel()` 107 | 108 | --- 109 | 110 | ## **7️⃣ Utilities** 111 | 📌 [Utility Classes Directory](https://github.com/BentoBoxWorld/Level/tree/develop/src/main/java/world/bentobox/level/util) 112 | 113 | - **Utils.java** → General helper methods. 114 | - **ConversationUtils.java** → Handles player text input in conversations. 115 | 116 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/LevelPladdon.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level; 2 | 3 | import world.bentobox.bentobox.api.addons.Addon; 4 | import world.bentobox.bentobox.api.addons.Pladdon; 5 | 6 | 7 | /** 8 | * @author tastybento 9 | * 10 | */ 11 | public class LevelPladdon extends Pladdon { 12 | 13 | private Addon addon; 14 | 15 | @Override 16 | public Addon getAddon() { 17 | if (addon == null) { 18 | addon = new Level(); 19 | } 20 | return addon; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/calculators/EquationEvaluator.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.calculators; 2 | 3 | import java.text.ParseException; 4 | 5 | /** 6 | * Utility class to evaluate equations 7 | */ 8 | public class EquationEvaluator { 9 | 10 | private static class Parser { 11 | private final String input; 12 | private int pos = -1; 13 | private int currentChar; 14 | 15 | @SuppressWarnings("unused") 16 | private Parser() { 17 | throw new IllegalStateException("Utility class"); 18 | } 19 | 20 | public Parser(String input) { 21 | this.input = input; 22 | moveToNextChar(); 23 | } 24 | 25 | private void moveToNextChar() { 26 | currentChar = (++pos < input.length()) ? input.charAt(pos) : -1; 27 | } 28 | 29 | private boolean tryToEat(int charToEat) { 30 | while (currentChar == ' ') { 31 | moveToNextChar(); 32 | } 33 | if (currentChar == charToEat) { 34 | moveToNextChar(); 35 | return true; 36 | } 37 | return false; 38 | } 39 | 40 | public double evaluate() throws ParseException { 41 | double result = parseExpression(); 42 | if (pos < input.length()) { 43 | throw new ParseException("Unexpected character: " + (char) currentChar, pos); 44 | } 45 | return result; 46 | } 47 | 48 | private double parseExpression() throws ParseException { 49 | double result = parseTerm(); 50 | while (true) { 51 | if (tryToEat('+')) { 52 | result += parseTerm(); 53 | } else if (tryToEat('-')) { 54 | result -= parseTerm(); 55 | } else { 56 | return result; 57 | } 58 | } 59 | } 60 | 61 | private double parseFactor() throws ParseException { 62 | if (tryToEat('+')) { 63 | return parseFactor(); // unary plus 64 | } 65 | if (tryToEat('-')) { 66 | return -parseFactor(); // unary minus 67 | } 68 | double x; 69 | int startPos = this.pos; 70 | if (tryToEat('(')) { // parentheses 71 | x = parseExpression(); 72 | tryToEat(')'); 73 | } else if ((currentChar >= '0' && currentChar <= '9') || currentChar == '.') { // numbers 74 | while ((currentChar >= '0' && currentChar <= '9') || currentChar == '.') { 75 | moveToNextChar(); 76 | } 77 | x = Double.parseDouble(input.substring(startPos, this.pos)); 78 | } else if (currentChar >= 'a' && currentChar <= 'z') { // functions 79 | while (currentChar >= 'a' && currentChar <= 'z') { 80 | moveToNextChar(); 81 | } 82 | String func = input.substring(startPos, this.pos); 83 | x = parseFactor(); 84 | x = switch (func) { 85 | case "sqrt" -> Math.sqrt(x); 86 | case "sin" -> Math.sin(Math.toRadians(x)); 87 | case "cos" -> Math.cos(Math.toRadians(x)); 88 | case "tan" -> Math.tan(Math.toRadians(x)); 89 | case "log" -> Math.log(x); 90 | default -> throw new ParseException("Unknown function: " + func, startPos); 91 | }; 92 | } else { 93 | throw new ParseException("Unexpected: " + (char) currentChar, startPos); 94 | } 95 | 96 | if (tryToEat('^')) { 97 | x = Math.pow(x, parseFactor()); // exponentiation 98 | } 99 | 100 | return x; 101 | } 102 | 103 | private double parseTerm() throws ParseException { 104 | double x = parseFactor(); 105 | for (;;) { 106 | if (tryToEat('*')) 107 | x *= parseFactor(); // multiplication 108 | else if (tryToEat('/')) 109 | x /= parseFactor(); // division 110 | else 111 | return x; 112 | } 113 | } 114 | 115 | } 116 | 117 | public static double eval(final String equation) throws ParseException { 118 | return new Parser(equation).evaluate(); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/calculators/Pipeliner.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.calculators; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Queue; 6 | import java.util.concurrent.CompletableFuture; 7 | import java.util.concurrent.ConcurrentLinkedQueue; 8 | 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.scheduler.BukkitTask; 11 | 12 | import world.bentobox.bentobox.BentoBox; 13 | import world.bentobox.bentobox.database.objects.Island; 14 | import world.bentobox.level.Level; 15 | import world.bentobox.level.calculators.Results.Result; 16 | 17 | /** 18 | * A pipeliner that will process one island at a time 19 | * @author tastybento 20 | * 21 | */ 22 | public class Pipeliner { 23 | 24 | private static final int START_DURATION = 10; // 10 seconds 25 | private final Queue toProcessQueue; 26 | private final Map inProcessQueue; 27 | private final BukkitTask task; 28 | private final Level addon; 29 | private long time; 30 | private long count; 31 | 32 | /** 33 | * Construct the pipeliner 34 | */ 35 | public Pipeliner(Level addon) { 36 | this.addon = addon; 37 | toProcessQueue = new ConcurrentLinkedQueue<>(); 38 | inProcessQueue = new HashMap<>(); 39 | // Loop continuously - check every tick if there is an island to scan 40 | task = Bukkit.getScheduler().runTaskTimer(BentoBox.getInstance(), () -> { 41 | if (!BentoBox.getInstance().isEnabled()) { 42 | cancel(); 43 | return; 44 | } 45 | // Complete the current to Process queue first 46 | if (!inProcessQueue.isEmpty() || toProcessQueue.isEmpty()) return; 47 | for (int j = 0; j < addon.getSettings().getConcurrentIslandCalcs() && !toProcessQueue.isEmpty(); j++) { 48 | IslandLevelCalculator iD = toProcessQueue.poll(); 49 | // Ignore deleted or unowned islands 50 | if (!iD.getIsland().isDeleted() && !iD.getIsland().isUnowned()) { 51 | inProcessQueue.put(iD, System.currentTimeMillis()); 52 | BentoBox.getInstance().log("Starting to scan island level at " + iD.getIsland().getCenter()); 53 | // Start the scanning of a island with the first chunk 54 | scanIsland(iD); 55 | } 56 | } 57 | }, 1L, 10L); 58 | } 59 | 60 | private void cancel() { 61 | task.cancel(); 62 | } 63 | 64 | /** 65 | * @return number of islands currently in the queue or in process 66 | */ 67 | public int getIslandsInQueue() { 68 | return inProcessQueue.size() + toProcessQueue.size(); 69 | } 70 | 71 | /** 72 | * Scans one chunk of an island and adds the results to a results object 73 | * @param iD 74 | */ 75 | private void scanIsland(IslandLevelCalculator iD) { 76 | if (iD.getIsland().isDeleted() || iD.getIsland().isUnowned() || task.isCancelled()) { 77 | // Island is deleted, so finish early with nothing 78 | inProcessQueue.remove(iD); 79 | iD.getR().complete(null); 80 | return; 81 | } 82 | iD.scanIsland(this); 83 | } 84 | 85 | 86 | /** 87 | * Adds an island to the scanning queue but only if the island is not already in the queue 88 | * @param island - the island to scan 89 | * @return CompletableFuture of the results. Results will be null if the island is already in the queue 90 | */ 91 | public CompletableFuture addIsland(Island island) { 92 | // Check if queue already contains island and it's not an island zero calculation 93 | if (inProcessQueue.keySet().parallelStream().filter(IslandLevelCalculator::isNotZeroIsland) 94 | .map(IslandLevelCalculator::getIsland).anyMatch(island::equals) 95 | || toProcessQueue.parallelStream().filter(IslandLevelCalculator::isNotZeroIsland) 96 | .map(IslandLevelCalculator::getIsland).anyMatch(island::equals)) { 97 | return CompletableFuture.completedFuture(new Results(Result.IN_PROGRESS)); 98 | } 99 | BentoBox.getInstance().log("Added island to Level queue: " + island.getCenter()); 100 | return addToQueue(island, false); 101 | } 102 | 103 | /** 104 | * Adds an island to the scanning queue 105 | * @param island - the island to scan 106 | * @return CompletableFuture of the results 107 | */ 108 | public CompletableFuture zeroIsland(Island island) { 109 | BentoBox.getInstance().log("Zeroing island level for island at " + island.getCenter()); 110 | return addToQueue(island, true); 111 | } 112 | 113 | private CompletableFuture addToQueue(Island island, boolean zeroing) { 114 | CompletableFuture r = new CompletableFuture<>(); 115 | toProcessQueue.add(new IslandLevelCalculator(addon, island, r, zeroing)); 116 | count++; 117 | return r; 118 | } 119 | 120 | /** 121 | * Get the average time it takes to run a level check 122 | * @return the average time in seconds 123 | */ 124 | public int getTime() { 125 | return time == 0 || count == 0 ? START_DURATION : (int)((double)time/count/1000); 126 | } 127 | 128 | /** 129 | * Submit how long a level check took 130 | * @param time the time to set 131 | */ 132 | public void setTime(long time) { 133 | // Running average 134 | this.time += time; 135 | } 136 | 137 | /** 138 | * Stop the current queue. 139 | */ 140 | public void stop() { 141 | addon.log("Stopping Level queue"); 142 | task.cancel(); 143 | this.inProcessQueue.clear(); 144 | this.toProcessQueue.clear(); 145 | } 146 | 147 | /** 148 | * @return the inProcessQueue 149 | */ 150 | protected Map getInProcessQueue() { 151 | return inProcessQueue; 152 | } 153 | 154 | /** 155 | * @return the task 156 | */ 157 | protected BukkitTask getTask() { 158 | return task; 159 | } 160 | 161 | 162 | 163 | 164 | } 165 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/calculators/Results.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.calculators; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | import java.util.concurrent.atomic.AtomicLong; 6 | 7 | import com.google.common.collect.HashMultiset; 8 | import com.google.common.collect.Multiset; 9 | 10 | /** 11 | * Where results are stored 12 | */ 13 | public class Results { 14 | public enum Result { 15 | /** 16 | * A level calc is already in progress 17 | */ 18 | IN_PROGRESS, 19 | /** 20 | * Results will be available 21 | */ 22 | AVAILABLE, 23 | /** 24 | * Result if calculation timed out 25 | */ 26 | TIMEOUT 27 | } 28 | List report; 29 | /** 30 | * MaterialData count anything above sea level 31 | */ 32 | final Multiset mdCount = HashMultiset.create(); 33 | /** 34 | * Underwater count 35 | */ 36 | final Multiset uwCount = HashMultiset.create(); 37 | /** 38 | * Not-in-config count - blocks not listed in the scoring config file 39 | */ 40 | final Multiset ncCount = HashMultiset.create(); 41 | /** 42 | * Blocks not counted because they exceeded limits 43 | */ 44 | final Multiset ofCount = HashMultiset.create(); 45 | // AtomicLong and AtomicInteger must be used because they are changed by multiple concurrent threads 46 | AtomicLong rawBlockCount = new AtomicLong(0); 47 | AtomicLong underWaterBlockCount = new AtomicLong(0); 48 | AtomicLong level = new AtomicLong(0); 49 | AtomicInteger deathHandicap = new AtomicInteger(0); 50 | AtomicLong pointsToNextLevel = new AtomicLong(0); 51 | //AtomicLong initialLevel = new AtomicLong(0); 52 | AtomicLong initialCount = new AtomicLong(0); 53 | /** 54 | * Total points before any death penalties 55 | */ 56 | AtomicLong totalPoints = new AtomicLong(0); 57 | final Result state; 58 | 59 | public Results(Result state) { 60 | this.state = state; 61 | } 62 | 63 | public Results() { 64 | this.state = Result.AVAILABLE; 65 | } 66 | /** 67 | * @return the deathHandicap 68 | */ 69 | public int getDeathHandicap() { 70 | return deathHandicap.get(); 71 | } 72 | /** 73 | * Set the death handicap 74 | * @param handicap 75 | */ 76 | public void setDeathHandicap(int handicap) { 77 | deathHandicap.set(handicap); 78 | } 79 | 80 | /** 81 | * @return the report 82 | */ 83 | public List getReport() { 84 | return report; 85 | } 86 | /** 87 | * Set level 88 | * @param level - level 89 | */ 90 | public void setLevel(long level) { 91 | this.level.set(level); 92 | } 93 | /** 94 | * @return the level 95 | */ 96 | public long getLevel() { 97 | return level.get(); 98 | } 99 | /** 100 | * @return the pointsToNextLevel 101 | */ 102 | public long getPointsToNextLevel() { 103 | return pointsToNextLevel.get(); 104 | } 105 | 106 | /** 107 | * Set the points to next level 108 | * @param points 109 | */ 110 | public void setPointsToNextLevel(long points) { 111 | pointsToNextLevel.set(points); 112 | } 113 | 114 | /** 115 | * @return the totalPoints 116 | */ 117 | public long getTotalPoints() { 118 | return totalPoints.get(); 119 | } 120 | 121 | /** 122 | * Set the total points 123 | * @param points 124 | */ 125 | public void setTotalPoints(long points) { 126 | totalPoints.set(points); 127 | } 128 | 129 | /* 130 | public long getInitialLevel() { 131 | return initialLevel.get(); 132 | } 133 | 134 | public void setInitialLevel(long initialLevel) { 135 | this.initialLevel.set(initialLevel); 136 | } 137 | */ 138 | /* (non-Javadoc) 139 | * @see java.lang.Object#toString() 140 | */ 141 | /* 142 | @Override 143 | public String toString() { 144 | return "Results [report=" + report + ", mdCount=" + mdCount + ", uwCount=" + uwCount + ", ncCount=" 145 | + ncCount + ", ofCount=" + ofCount + ", rawBlockCount=" + rawBlockCount + ", underWaterBlockCount=" 146 | + underWaterBlockCount + ", level=" + level + ", deathHandicap=" + deathHandicap 147 | + ", pointsToNextLevel=" + pointsToNextLevel + ", totalPoints=" + totalPoints + ", initialLevel=" + initialLevel + "]"; 148 | }*/ 149 | /** 150 | * @return the mdCount 151 | */ 152 | public Multiset getMdCount() { 153 | return mdCount; 154 | } 155 | /** 156 | * @return the uwCount 157 | */ 158 | public Multiset getUwCount() { 159 | return uwCount; 160 | } 161 | /** 162 | * @return the state 163 | */ 164 | public Result getState() { 165 | return state; 166 | } 167 | 168 | /** 169 | * @return the initialCount 170 | */ 171 | public long getInitialCount() { 172 | return initialCount.get(); 173 | } 174 | 175 | /** 176 | * @param long1 the initialCount to set 177 | */ 178 | public void setInitialCount(Long count) { 179 | this.initialCount.set(count); 180 | } 181 | 182 | } 183 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/calculators/UltimateStackerCalc.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.calculators; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.Material; 5 | 6 | import com.craftaro.ultimatestacker.api.UltimateStackerApi; 7 | import com.craftaro.ultimatestacker.api.utils.Stackable; 8 | 9 | /** 10 | * Isolates UltimateStacker imports so that they are only loaded if the plugin exists 11 | */ 12 | public class UltimateStackerCalc { 13 | public static void addStackers(Material material, Location location, Results results, boolean belowSeaLevel, 14 | int value) { 15 | Stackable stack = UltimateStackerApi.getBlockStackManager().getBlock(location); 16 | if (stack != null) { 17 | if (belowSeaLevel) { 18 | results.underWaterBlockCount.addAndGet((long) stack.getAmount() * value); 19 | results.uwCount.add(material); 20 | } else { 21 | results.rawBlockCount.addAndGet((long) stack.getAmount() * value); 22 | results.mdCount.add(material); 23 | } 24 | } 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/commands/AdminLevelCommand.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.commands; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Optional; 6 | 7 | import world.bentobox.bentobox.api.commands.CompositeCommand; 8 | import world.bentobox.bentobox.api.user.User; 9 | import world.bentobox.bentobox.util.Util; 10 | import world.bentobox.level.Level; 11 | 12 | public class AdminLevelCommand extends IslandLevelCommand { 13 | 14 | public AdminLevelCommand(Level addon, CompositeCommand parent) { 15 | super(addon, parent); 16 | } 17 | 18 | @Override 19 | public void setup() { 20 | this.setPermission("admin.level"); 21 | this.setOnlyPlayer(false); 22 | this.setParametersHelp("admin.level.parameters"); 23 | this.setDescription("admin.level.description"); 24 | } 25 | 26 | @Override 27 | public Optional> tabComplete(User user, String alias, List args) { 28 | String lastArg = !args.isEmpty() ? args.get(args.size()-1) : ""; 29 | if (args.isEmpty()) { 30 | // Don't show every player on the server. Require at least the first letter 31 | return Optional.empty(); 32 | } 33 | List options = new ArrayList<>(Util.getOnlinePlayerList(user)); 34 | return Optional.of(Util.tabLimit(options, lastArg)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/commands/AdminLevelStatusCommand.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.commands; 2 | 3 | import java.util.List; 4 | 5 | import world.bentobox.bentobox.api.commands.CompositeCommand; 6 | import world.bentobox.bentobox.api.localization.TextVariables; 7 | import world.bentobox.bentobox.api.user.User; 8 | import world.bentobox.level.Level; 9 | 10 | public class AdminLevelStatusCommand extends CompositeCommand { 11 | 12 | private final Level addon; 13 | 14 | public AdminLevelStatusCommand(Level addon, CompositeCommand parent) { 15 | super(parent, "levelstatus"); 16 | this.addon = addon; 17 | } 18 | 19 | @Override 20 | public void setup() { 21 | this.setPermission("admin.levelstatus"); 22 | this.setOnlyPlayer(false); 23 | this.setDescription("admin.levelstatus.description"); 24 | } 25 | 26 | @Override 27 | public boolean execute(User user, String label, List args) { 28 | user.sendMessage("admin.levelstatus.islands-in-queue", TextVariables.NUMBER, String.valueOf(addon.getPipeliner().getIslandsInQueue())); 29 | return true; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/commands/AdminSetInitialLevelCommand.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.commands; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Optional; 6 | import java.util.UUID; 7 | 8 | import org.eclipse.jdt.annotation.Nullable; 9 | 10 | import world.bentobox.bentobox.api.commands.CompositeCommand; 11 | import world.bentobox.bentobox.api.localization.TextVariables; 12 | import world.bentobox.bentobox.api.user.User; 13 | import world.bentobox.bentobox.database.objects.Island; 14 | import world.bentobox.bentobox.util.Util; 15 | import world.bentobox.level.Level; 16 | 17 | public class AdminSetInitialLevelCommand extends CompositeCommand { 18 | 19 | private @Nullable UUID targetUUID; 20 | private @Nullable Island island; 21 | private Level addon; 22 | 23 | public AdminSetInitialLevelCommand(Level addon, CompositeCommand parent) { 24 | super(parent, "sethandicap"); 25 | this.addon = addon; 26 | } 27 | 28 | @Override 29 | public void setup() { 30 | this.setPermission("admin.level.sethandicap"); 31 | this.setOnlyPlayer(false); 32 | this.setParametersHelp("admin.level.sethandicap.parameters"); 33 | this.setDescription("admin.level.sethandicap.description"); 34 | } 35 | 36 | @Override 37 | public Optional> tabComplete(User user, String alias, List args) { 38 | String lastArg = !args.isEmpty() ? args.get(args.size()-1) : ""; 39 | if (args.isEmpty()) { 40 | // Don't show every player on the server. Require at least the first letter 41 | return Optional.empty(); 42 | } 43 | List options = new ArrayList<>(Util.getOnlinePlayerList(user)); 44 | return Optional.of(Util.tabLimit(options, lastArg)); 45 | } 46 | 47 | @Override 48 | public boolean execute(User user, String label, List args) { 49 | long initialLevel = addon.getManager().getInitialCount(island); 50 | long lv = 0; 51 | if (args.get(1).startsWith("+")) { 52 | String change = args.get(1).substring(1); 53 | lv = initialLevel + Long.parseLong(change); 54 | } else if (args.get(1).startsWith("-")) { 55 | String change = args.get(1).substring(1); 56 | lv = initialLevel - Long.parseLong(change); 57 | } else { 58 | lv = Long.parseLong(args.get(1)); 59 | } 60 | addon.getManager().setInitialIslandCount(island, lv); // TODO Enable level setting 61 | user.sendMessage("admin.level.sethandicap.changed", TextVariables.NUMBER, String.valueOf(initialLevel), 62 | "[new_number]", String.valueOf(lv)); 63 | return true; 64 | } 65 | 66 | @Override 67 | public boolean canExecute(User user, String label, List args) { 68 | if (args.size() != 2) { 69 | showHelp(this, user); 70 | return false; 71 | } 72 | targetUUID = getAddon().getPlayers().getUUID(args.get(0)); 73 | if (targetUUID == null) { 74 | user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); 75 | return false; 76 | } 77 | // Check if this is a add or remove 78 | if (args.get(1).startsWith("+") || args.get(1).startsWith("-")) { 79 | String change = args.get(1).substring(1); 80 | if (!Util.isInteger(change, true)) { 81 | user.sendMessage("admin.level.sethandicap.invalid-level"); 82 | return false; 83 | } 84 | // Value is okay 85 | } else { 86 | // Check value 87 | if (!Util.isInteger(args.get(1), true)) { 88 | user.sendMessage("admin.level.sethandicap.invalid-level"); 89 | return false; 90 | } 91 | } 92 | // Check island 93 | island = getAddon().getIslands().getIsland(getWorld(), targetUUID); 94 | if (island == null) { 95 | user.sendMessage("general.errors.player-has-no-island"); 96 | return false; 97 | } 98 | return true; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/commands/AdminStatsCommand.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.commands; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Map.Entry; 8 | import java.util.TreeMap; 9 | import java.util.stream.Collectors; 10 | 11 | import org.bukkit.World; 12 | 13 | import world.bentobox.bentobox.api.commands.CompositeCommand; 14 | import world.bentobox.bentobox.api.localization.TextVariables; 15 | import world.bentobox.bentobox.api.user.User; 16 | import world.bentobox.level.Level; 17 | import world.bentobox.level.objects.TopTenData; 18 | 19 | public class AdminStatsCommand extends CompositeCommand { 20 | 21 | private final Level level; 22 | 23 | public AdminStatsCommand(Level addon, CompositeCommand parent) { 24 | super(parent, "stats"); 25 | this.level = addon; 26 | new AdminTopRemoveCommand(addon, this); 27 | } 28 | 29 | @Override 30 | public void setup() { 31 | this.setPermission("admin.stats"); 32 | this.setOnlyPlayer(false); 33 | this.setDescription("admin.stats.description"); 34 | } 35 | 36 | @Override 37 | public boolean execute(User user, String label, List args) { 38 | user.sendMessage("admin.stats.title"); 39 | Map topTenLists = level.getManager().getTopTenLists(); 40 | if (topTenLists.isEmpty()) { 41 | user.sendMessage("admin.stats.no-data"); 42 | return false; 43 | } 44 | for (Entry en : topTenLists.entrySet()) { 45 | user.sendMessage("admin.stats.world", TextVariables.NAME, 46 | level.getPlugin().getIWM().getWorldName(en.getKey())); 47 | Map topTen = en.getValue().getTopTen(); 48 | if (topTen.isEmpty()) { 49 | user.sendMessage("admin.stats.no-data"); 50 | return false; 51 | } 52 | 53 | // Calculating basic statistics 54 | long sum = 0, max = Long.MIN_VALUE, min = Long.MAX_VALUE; 55 | Map levelFrequency = new HashMap<>(); 56 | 57 | for (Long level : topTen.values()) { 58 | sum += level; 59 | max = Math.max(max, level); 60 | min = Math.min(min, level); 61 | levelFrequency.merge(level, 1, Integer::sum); 62 | } 63 | 64 | double average = sum / (double) topTen.size(); 65 | List sortedLevels = topTen.values().stream().sorted().collect(Collectors.toList()); 66 | long median = sortedLevels.get(sortedLevels.size() / 2); 67 | Long mode = Collections.max(levelFrequency.entrySet(), Map.Entry.comparingByValue()).getKey(); 68 | 69 | // Logging basic statistics 70 | user.sendMessage("admin.stats.average-level", TextVariables.NUMBER, String.valueOf(average)); 71 | user.sendMessage("admin.stats.median-level", TextVariables.NUMBER, String.valueOf(median)); 72 | user.sendMessage("admin.stats.mode-level", TextVariables.NUMBER, String.valueOf(mode)); 73 | user.sendMessage("admin.stats.highest-level", TextVariables.NUMBER, String.valueOf(max)); 74 | user.sendMessage("admin.stats.lowest-level", TextVariables.NUMBER, String.valueOf(min)); 75 | 76 | // Grouping data for distribution analysis 77 | Map rangeMap = new TreeMap<>(); 78 | for (Long level : topTen.values()) { 79 | String range = getRange(level); 80 | rangeMap.merge(range, 1, Integer::sum); 81 | } 82 | 83 | // Logging distribution 84 | user.sendMessage("admin.stats.distribution"); 85 | for (Map.Entry entry : rangeMap.entrySet()) { 86 | user.sendMessage( 87 | entry.getKey() + ": " + entry.getValue() + " " + user.getTranslation("admin.stats.islands")); 88 | } 89 | } 90 | return true; 91 | } 92 | 93 | private static String getRange(long level) { 94 | long rangeStart = level / 100 * 100; 95 | long rangeEnd = rangeStart + 99; 96 | return rangeStart + "-" + rangeEnd; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/commands/AdminTopCommand.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.commands; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.Optional; 6 | 7 | import world.bentobox.bentobox.api.commands.CompositeCommand; 8 | import world.bentobox.bentobox.api.user.User; 9 | import world.bentobox.bentobox.database.objects.Island; 10 | import world.bentobox.level.Level; 11 | 12 | public class AdminTopCommand extends CompositeCommand { 13 | 14 | private final Level levelPlugin; 15 | 16 | public AdminTopCommand(Level addon, CompositeCommand parent) { 17 | super(parent, "top", "topten"); 18 | this.levelPlugin = addon; 19 | new AdminTopRemoveCommand(addon, this); 20 | } 21 | 22 | @Override 23 | public void setup() { 24 | this.setPermission("admin.top"); 25 | this.setOnlyPlayer(false); 26 | this.setDescription("admin.top.description"); 27 | } 28 | 29 | @Override 30 | public boolean execute(User user, String label, List args) { 31 | user.sendMessage("island.top.gui-title"); 32 | int rank = 0; 33 | for (Map.Entry topTen : levelPlugin.getManager().getTopTen(getWorld(), Level.TEN).entrySet()) { 34 | Optional is = getPlugin().getIslands().getIslandById(topTen.getKey()); 35 | if (is.isPresent()) { 36 | Island island = is.get(); 37 | rank++; 38 | user.sendMessage("admin.top.display", "[rank]", String.valueOf(rank), "[name]", 39 | this.getPlugin().getPlayers().getUser(island.getOwner()).getName(), "[level]", 40 | String.valueOf(topTen.getValue())); 41 | } 42 | } 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/commands/AdminTopRemoveCommand.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.commands; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | import world.bentobox.bentobox.api.commands.CompositeCommand; 7 | import world.bentobox.bentobox.api.localization.TextVariables; 8 | import world.bentobox.bentobox.api.user.User; 9 | import world.bentobox.bentobox.database.objects.Island; 10 | import world.bentobox.level.Level; 11 | 12 | /** 13 | * Removes a player from the top ten 14 | * 15 | * @author tastybento 16 | * 17 | */ 18 | public class AdminTopRemoveCommand extends CompositeCommand { 19 | 20 | private final Level addon; 21 | private User target; 22 | 23 | public AdminTopRemoveCommand(Level addon, CompositeCommand parent) { 24 | super(parent, "remove", "delete"); 25 | this.addon = addon; 26 | } 27 | 28 | @Override 29 | public void setup() { 30 | this.setPermission("admin.top.remove"); 31 | this.setOnlyPlayer(false); 32 | this.setParametersHelp("admin.top.remove.parameters"); 33 | this.setDescription("admin.top.remove.description"); 34 | } 35 | 36 | /* 37 | * (non-Javadoc) 38 | * 39 | * @see world.bentobox.bentobox.api.commands.BentoBoxCommand#canExecute(world. 40 | * bentobox.bentobox.api.user.User, java.lang.String, java.util.List) 41 | */ 42 | @Override 43 | public boolean canExecute(User user, String label, List args) { 44 | if (args.size() != 1) { 45 | this.showHelp(this, user); 46 | return false; 47 | } 48 | target = getPlayers().getUser(args.get(0)); 49 | if (target == null) { 50 | user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); 51 | return false; 52 | } 53 | 54 | return true; 55 | } 56 | 57 | @Override 58 | public boolean execute(User user, String label, List args) { 59 | // Removes islands that this target is an owner of 60 | getIslands().getIslands(getWorld(), target.getUniqueId()).stream() 61 | .filter(is -> target.getUniqueId().equals(is.getOwner())) 62 | .forEach(island -> addon.getManager().removeEntry(getWorld(), island.getUniqueId())); 63 | user.sendMessage("general.success"); 64 | return true; 65 | } 66 | 67 | @Override 68 | public Optional> tabComplete(User user, String alias, List args) { 69 | return Optional.of(addon.getManager().getTopTen(getWorld(), Level.TEN).keySet().stream() 70 | .map(getIslands()::getIslandById).flatMap(Optional::stream).map(Island::getOwner) 71 | .map(addon.getPlayers()::getName).filter(n -> !n.isEmpty()).toList()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/commands/IslandDetailCommand.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.commands; 2 | 3 | import java.util.List; 4 | 5 | import world.bentobox.bentobox.api.commands.CompositeCommand; 6 | import world.bentobox.bentobox.api.user.User; 7 | import world.bentobox.bentobox.database.objects.Island; 8 | import world.bentobox.level.Level; 9 | import world.bentobox.level.panels.DetailsPanel; 10 | 11 | 12 | public class IslandDetailCommand extends CompositeCommand { 13 | 14 | private final Level addon; 15 | 16 | public IslandDetailCommand(Level addon, CompositeCommand parent) { 17 | super(parent, "detail"); 18 | this.addon = addon; 19 | } 20 | 21 | @Override 22 | public void setup() { 23 | setPermission("island.detail"); 24 | setDescription("island.detail.description"); 25 | setOnlyPlayer(true); 26 | } 27 | 28 | @Override 29 | public boolean execute(User user, String label, List list) { 30 | Island island = getIslands().getIsland(getWorld(), user); 31 | if (island == null) { 32 | user.sendMessage("general.errors.player-has-no-island"); 33 | return false; 34 | 35 | } 36 | DetailsPanel.openPanel(this.addon, getWorld(), user); 37 | return true; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/commands/IslandLevelCommand.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.commands; 2 | 3 | import java.util.List; 4 | import java.util.UUID; 5 | 6 | import world.bentobox.bentobox.BentoBox; 7 | import world.bentobox.bentobox.api.commands.CompositeCommand; 8 | import world.bentobox.bentobox.api.localization.TextVariables; 9 | import world.bentobox.bentobox.api.user.User; 10 | import world.bentobox.bentobox.database.objects.Island; 11 | import world.bentobox.level.Level; 12 | import world.bentobox.level.calculators.Results; 13 | import world.bentobox.level.calculators.Results.Result; 14 | 15 | public class IslandLevelCommand extends CompositeCommand { 16 | 17 | private static final String ISLAND_LEVEL_IS = "island.level.island-level-is"; 18 | private static final String LEVEL = "[level]"; 19 | private final Level addon; 20 | 21 | public IslandLevelCommand(Level addon, CompositeCommand parent) { 22 | super(parent, "level"); 23 | this.addon = addon; 24 | } 25 | 26 | @Override 27 | public void setup() { 28 | this.setPermission("island.level"); 29 | this.setParametersHelp("island.level.parameters"); 30 | this.setDescription("island.level.description"); 31 | } 32 | 33 | 34 | @Override 35 | public boolean execute(User user, String label, List args) { 36 | if (!args.isEmpty()) { 37 | // Asking for another player's level? 38 | // Convert name to a UUID 39 | final UUID playerUUID = getPlugin().getPlayers().getUUID(args.get(0)); 40 | if (playerUUID == null) { 41 | user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); 42 | return false; 43 | } 44 | // Ops, console and admin perms can request and calculate other player levels 45 | if (!user.isPlayer() || user.isOp() || user.hasPermission(this.getPermissionPrefix() + "admin.level")) { 46 | return scanIsland(user, playerUUID); 47 | } 48 | // Request for another player's island level 49 | if (!user.getUniqueId().equals(playerUUID) ) { 50 | user.sendMessage(ISLAND_LEVEL_IS, LEVEL, addon.getManager().getIslandLevelString(getWorld(), playerUUID)); 51 | return true; 52 | } 53 | } 54 | if (!user.isPlayer()) { 55 | user.sendMessage("general.errors.use-in-game"); 56 | return false; 57 | } 58 | // Self request 59 | // Check player cooldown 60 | int coolDown = this.addon.getSettings().getLevelWait(); 61 | 62 | if (coolDown > 0) { 63 | // Check cool down 64 | if (checkCooldown(user)) return false; 65 | // Set cool down 66 | setCooldown(user.getUniqueId(), coolDown); 67 | } 68 | 69 | // Self level request 70 | return scanIsland(user, user.getUniqueId()); 71 | 72 | } 73 | 74 | 75 | private boolean scanIsland(User user, UUID playerUUID) { 76 | Island island = getIslands().getIsland(getWorld(), playerUUID); 77 | if (island == null) { 78 | user.sendMessage("general.errors.player-has-no-island"); 79 | return false; 80 | 81 | } 82 | int inQueue = addon.getPipeliner().getIslandsInQueue(); 83 | user.sendMessage("island.level.calculating"); 84 | user.sendMessage("island.level.estimated-wait", TextVariables.NUMBER, String.valueOf(addon.getPipeliner().getTime() * (inQueue + 1))); 85 | if (inQueue > 1) { 86 | user.sendMessage("island.level.in-queue", TextVariables.NUMBER, String.valueOf(inQueue + 1)); 87 | } 88 | // Get the old level 89 | long oldLevel = addon.getManager().getIslandLevel(getWorld(), playerUUID); 90 | addon.getManager().calculateLevel(playerUUID, island).thenAccept(results -> { 91 | if (results == null) return; // island was deleted or become unowned 92 | if (results.getState().equals(Result.IN_PROGRESS)) { 93 | user.sendMessage("island.level.in-progress"); 94 | return; 95 | } else if (results.getState().equals(Result.TIMEOUT)) { 96 | user.sendMessage("island.level.time-out"); 97 | return; 98 | } 99 | showResult(user, playerUUID, island, oldLevel, results); 100 | }); 101 | return true; 102 | 103 | } 104 | 105 | private void showResult(User user, UUID playerUUID, Island island, long oldLevel, Results results) { 106 | if (user.isPlayer()) { 107 | user.sendMessage(ISLAND_LEVEL_IS, LEVEL, addon.getManager().getIslandLevelString(getWorld(), playerUUID)); 108 | // Player 109 | if (addon.getSettings().getDeathPenalty() != 0) { 110 | user.sendMessage("island.level.deaths", "[number]", String.valueOf(results.getDeathHandicap())); 111 | } 112 | // Send player how many points are required to reach next island level 113 | if (results.getPointsToNextLevel() >= 0) { 114 | user.sendMessage("island.level.required-points-to-next-level", 115 | "[points]", String.valueOf(results.getPointsToNextLevel()), 116 | "[progress]", String.valueOf(this.addon.getSettings().getLevelCost()-results.getPointsToNextLevel()), 117 | "[levelcost]", String.valueOf(this.addon.getSettings().getLevelCost()) 118 | ); 119 | } 120 | // Tell other team members 121 | if (results.getLevel() != oldLevel) { 122 | island.getMemberSet().stream() 123 | .filter(u -> !u.equals(user.getUniqueId())) 124 | .forEach(m -> User.getInstance(m).sendMessage(ISLAND_LEVEL_IS, LEVEL, addon.getManager().getIslandLevelString(getWorld(), playerUUID))); 125 | } 126 | } else if (this.addon.getSettings().isLogReportToConsole()) { 127 | results.getReport().forEach(BentoBox.getInstance()::log); 128 | } 129 | 130 | } 131 | 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/commands/IslandTopCommand.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.commands; 2 | 3 | import java.util.List; 4 | 5 | import world.bentobox.bentobox.api.commands.CompositeCommand; 6 | import world.bentobox.bentobox.api.user.User; 7 | import world.bentobox.level.Level; 8 | import world.bentobox.level.panels.TopLevelPanel; 9 | 10 | 11 | public class IslandTopCommand extends CompositeCommand { 12 | 13 | private final Level addon; 14 | 15 | public IslandTopCommand(Level addon, CompositeCommand parent) { 16 | super(parent, "top", "topten"); 17 | this.addon = addon; 18 | } 19 | 20 | @Override 21 | public void setup() { 22 | setPermission("island.top"); 23 | setDescription("island.top.description"); 24 | setOnlyPlayer(true); 25 | } 26 | 27 | @Override 28 | public boolean execute(User user, String label, List list) { 29 | TopLevelPanel.openPanel(this.addon, user, this.getWorld(), this.getPermissionPrefix()); 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/commands/IslandValueCommand.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.commands; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.Optional; 7 | 8 | import org.bukkit.Material; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.inventory.ItemStack; 11 | import org.bukkit.inventory.PlayerInventory; 12 | import org.eclipse.jdt.annotation.NonNull; 13 | 14 | import world.bentobox.bentobox.api.commands.CompositeCommand; 15 | import world.bentobox.bentobox.api.localization.TextVariables; 16 | import world.bentobox.bentobox.api.user.User; 17 | import world.bentobox.bentobox.hooks.ItemsAdderHook; 18 | import world.bentobox.bentobox.util.Util; 19 | import world.bentobox.level.Level; 20 | import world.bentobox.level.objects.IslandLevels; 21 | import world.bentobox.level.panels.ValuePanel; 22 | import world.bentobox.level.util.Utils; 23 | 24 | 25 | public class IslandValueCommand extends CompositeCommand 26 | { 27 | private static final String MATERIAL = "[material]"; 28 | private final Level addon; 29 | 30 | 31 | public IslandValueCommand(Level addon, CompositeCommand parent) 32 | { 33 | super(parent, "value"); 34 | this.addon = addon; 35 | } 36 | 37 | 38 | @Override 39 | public void setup() 40 | { 41 | this.setPermission("island.value"); 42 | this.setParametersHelp("level.commands.value.parameters"); 43 | this.setDescription("level.commands.value.description"); 44 | this.setOnlyPlayer(true); 45 | } 46 | 47 | 48 | @Override 49 | public boolean execute(User user, String label, List args) { 50 | if (args.size() > 1) { 51 | showHelp(this, user); 52 | return false; 53 | } 54 | 55 | if (args.isEmpty()) { 56 | ValuePanel.openPanel(addon, getWorld(), user); 57 | return true; 58 | } 59 | 60 | String arg = args.get(0); 61 | if ("HAND".equalsIgnoreCase(arg)) { 62 | executeHandCommand(user); 63 | return true; 64 | } 65 | 66 | executeMaterialCommand(user, arg); 67 | return true; 68 | } 69 | 70 | private void executeHandCommand(User user) { 71 | Player player = user.getPlayer(); 72 | PlayerInventory inventory = player.getInventory(); 73 | ItemStack mainHandItem = inventory.getItemInMainHand(); 74 | 75 | if (mainHandItem.getType() == Material.AIR) { 76 | Utils.sendMessage(user, user.getTranslation("level.conversations.empty-hand")); 77 | return; 78 | } 79 | 80 | if (addon.isItemsAdder()) { 81 | Optional id = ItemsAdderHook.getNamespacedId(mainHandItem); 82 | if (id.isPresent()) { 83 | printValue(user, id.get()); 84 | return; 85 | } 86 | } 87 | 88 | printValue(user, mainHandItem.getType()); 89 | } 90 | 91 | private void executeMaterialCommand(User user, String arg) { 92 | Material material = Material.matchMaterial(arg); 93 | if (material == null) { 94 | Utils.sendMessage(user, user.getTranslation(getWorld(), "level.conversations.unknown-item", MATERIAL, arg)); 95 | } else { 96 | printValue(user, material); 97 | } 98 | } 99 | 100 | /** 101 | * This method prints value of the given material in chat. 102 | * @param user User who receives the message. 103 | * @param material Material value. 104 | */ 105 | private void printValue(User user, Object material) 106 | { 107 | Integer value = this.addon.getBlockConfig().getValue(getWorld(), material); 108 | 109 | if (value != null) 110 | { 111 | Utils.sendMessage(user, user.getTranslation(this.getWorld(), "level.conversations.value", "[value]", 112 | String.valueOf(value), MATERIAL, Utils.prettifyObject(material, user))); 113 | 114 | double underWater = this.addon.getSettings().getUnderWaterMultiplier(); 115 | 116 | if (underWater > 1.0) { 117 | Utils.sendMessage(user, user.getTranslation(this.getWorld(), "level.conversations.success-underwater", 118 | "[value]", (underWater * value) + ""), MATERIAL, Utils.prettifyObject(material, user)); 119 | } 120 | 121 | // Show how many have been placed and how many are allowed 122 | @NonNull 123 | IslandLevels lvData = this.addon.getManager() 124 | .getLevelsData(getIslands().getPrimaryIsland(getWorld(), user.getUniqueId())); 125 | int count = lvData.getMdCount().getOrDefault(material, 0) + lvData.getUwCount().getOrDefault(material, 0); 126 | user.sendMessage("level.conversations.you-have", TextVariables.NUMBER, String.valueOf(count)); 127 | Integer limit = this.addon.getBlockConfig().getLimit(material); 128 | if (limit != null) { 129 | user.sendMessage("level.conversations.you-can-place", TextVariables.NUMBER, String.valueOf(limit)); 130 | } 131 | } 132 | else { 133 | Utils.sendMessage(user, user.getTranslation(this.getWorld(), "level.conversations.no-value")); 134 | } 135 | } 136 | 137 | @Override 138 | public Optional> tabComplete(User user, String alias, List args) { 139 | String lastArg = !args.isEmpty() ? args.get(args.size() - 1) : ""; 140 | 141 | if (args.isEmpty()) 142 | { 143 | // Don't show every player on the server. Require at least the first letter 144 | return Optional.empty(); 145 | } 146 | 147 | List options = new ArrayList<>( 148 | Arrays.stream(Material.values()).filter(Material::isBlock).map(Material::name).toList()); 149 | 150 | options.add("HAND"); 151 | 152 | return Optional.of(Util.tabLimit(options, lastArg)); 153 | } 154 | } -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/events/IslandLevelCalculatedEvent.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.events; 2 | 3 | import java.util.List; 4 | import java.util.UUID; 5 | 6 | import org.bukkit.event.HandlerList; 7 | import org.eclipse.jdt.annotation.NonNull; 8 | 9 | import world.bentobox.bentobox.api.events.IslandBaseEvent; 10 | import world.bentobox.bentobox.database.objects.Island; 11 | import world.bentobox.level.calculators.Results; 12 | 13 | /** 14 | * This event is fired after the island level is calculated and before the results are saved. 15 | * If this event is cancelled, results will saved, but not communicated. i.e., the result will be silent. 16 | * 17 | * @author tastybento 18 | */ 19 | public class IslandLevelCalculatedEvent extends IslandBaseEvent { 20 | private Results results; 21 | 22 | private UUID targetPlayer; 23 | 24 | private static final HandlerList handlers = new HandlerList(); 25 | 26 | @Override 27 | public @NonNull HandlerList getHandlers() { 28 | return getHandlerList(); 29 | } 30 | 31 | public static HandlerList getHandlerList() { 32 | return handlers; 33 | } 34 | 35 | /** 36 | * @param targetPlayer - target player 37 | * @param island - island 38 | * @param results - results object to set 39 | */ 40 | public IslandLevelCalculatedEvent(UUID targetPlayer, Island island, Results results) { 41 | super(island); 42 | this.targetPlayer = targetPlayer; 43 | this.results = results; 44 | } 45 | 46 | /** 47 | * Do NOT get this result if you are not a BentoBox addon! 48 | * @return the results 49 | */ 50 | public Results getResults() { 51 | return results; 52 | } 53 | 54 | /** 55 | * @return death handicap value 56 | */ 57 | public int getDeathHandicap() { 58 | return results.getDeathHandicap(); 59 | } 60 | 61 | /** 62 | * Get the island's initial count. It may be zero if it was never calculated. 63 | * @return initial count of island as calculated when the island was created. 64 | */ 65 | public long getInitiaCount() { 66 | return results.getInitialCount(); 67 | } 68 | 69 | /** 70 | * @return the level calculated 71 | */ 72 | public long getLevel() { 73 | return results.getLevel(); 74 | } 75 | 76 | 77 | /** 78 | * Overwrite the level. This level will be used instead of the calculated level. 79 | * @param level - the level to set 80 | */ 81 | public void setLevel(long level) { 82 | results.setLevel(level); 83 | } 84 | 85 | /** 86 | * @return number of points required to next level 87 | */ 88 | public long getPointsToNextLevel() { 89 | return results.getPointsToNextLevel(); 90 | } 91 | 92 | /** 93 | * @return a human readable report explaining how the calculation was made 94 | */ 95 | public List getReport() { 96 | return results.getReport(); 97 | } 98 | 99 | /** 100 | * @return the targetPlayer 101 | */ 102 | public UUID getTargetPlayer() { 103 | return targetPlayer; 104 | } 105 | /** 106 | * Do not use this if you are not a BentoBox addon 107 | * @param results the results to set 108 | */ 109 | public void setResults(Results results) { 110 | this.results = results; 111 | } 112 | 113 | /** 114 | * @param targetPlayer the targetPlayer to set 115 | */ 116 | public void setTargetPlayer(UUID targetPlayer) { 117 | this.targetPlayer = targetPlayer; 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/events/IslandPreLevelEvent.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.events; 2 | 3 | import java.util.UUID; 4 | 5 | import org.bukkit.event.HandlerList; 6 | import org.eclipse.jdt.annotation.NonNull; 7 | 8 | import world.bentobox.bentobox.api.events.IslandBaseEvent; 9 | import world.bentobox.bentobox.database.objects.Island; 10 | 11 | /** 12 | * Called when an island level is going to be calculated 13 | * @author tastybento 14 | * 15 | */ 16 | public class IslandPreLevelEvent extends IslandBaseEvent { 17 | 18 | private final UUID targetPlayer; 19 | private static final HandlerList handlers = new HandlerList(); 20 | 21 | @Override 22 | public @NonNull HandlerList getHandlers() { 23 | return getHandlerList(); 24 | } 25 | 26 | public static HandlerList getHandlerList() { 27 | return handlers; 28 | } 29 | 30 | 31 | /** 32 | * Called when an island level is going to be calculated 33 | * @param targetPlayer - the player who is being tagetted (owner or team member) 34 | * @param island - the island 35 | */ 36 | public IslandPreLevelEvent(UUID targetPlayer, Island island) { 37 | super(island); 38 | this.targetPlayer = targetPlayer; 39 | } 40 | 41 | public UUID getTargetPlayer() { 42 | return targetPlayer; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/listeners/IslandActivitiesListeners.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.listeners; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.World; 5 | import org.bukkit.event.EventHandler; 6 | import org.bukkit.event.EventPriority; 7 | import org.bukkit.event.Listener; 8 | 9 | import world.bentobox.bentobox.api.events.island.IslandCreatedEvent; 10 | import world.bentobox.bentobox.api.events.island.IslandDeleteEvent; 11 | import world.bentobox.bentobox.api.events.island.IslandPreclearEvent; 12 | import world.bentobox.bentobox.api.events.island.IslandRegisteredEvent; 13 | import world.bentobox.bentobox.api.events.island.IslandResettedEvent; 14 | import world.bentobox.bentobox.api.events.island.IslandUnregisteredEvent; 15 | import world.bentobox.bentobox.api.events.team.TeamJoinedEvent; 16 | import world.bentobox.bentobox.api.events.team.TeamKickEvent; 17 | import world.bentobox.bentobox.api.events.team.TeamLeaveEvent; 18 | import world.bentobox.bentobox.api.events.team.TeamSetownerEvent; 19 | import world.bentobox.bentobox.database.objects.Island; 20 | import world.bentobox.level.Level; 21 | 22 | /** 23 | * Listens for new islands or ownership changes and sets the level to zero 24 | * automatically 25 | * 26 | * @author tastybento 27 | * 28 | */ 29 | public class IslandActivitiesListeners implements Listener { 30 | 31 | private final Level addon; 32 | 33 | /** 34 | * @param addon - addon 35 | */ 36 | public IslandActivitiesListeners(Level addon) { 37 | this.addon = addon; 38 | 39 | } 40 | 41 | @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) 42 | public void onNewIsland(IslandCreatedEvent e) { 43 | if (addon.getSettings().isZeroNewIslandLevels()) { 44 | // Wait a few seconds before performing the zero 45 | Bukkit.getScheduler().runTaskLater(addon.getPlugin(), () -> zeroIsland(e.getIsland()), 150L); 46 | } 47 | } 48 | 49 | @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) 50 | public void onNewIsland(IslandResettedEvent e) { 51 | if (addon.getSettings().isZeroNewIslandLevels()) { 52 | zeroIsland(e.getIsland()); 53 | } 54 | } 55 | 56 | private void zeroIsland(final Island island) { 57 | // Clear the island setting 58 | if (island.getOwner() != null && island.getWorld() != null) { 59 | addon.getPipeliner().zeroIsland(island) 60 | .thenAccept(results -> addon.getManager().setInitialIslandCount(island, results.getTotalPoints())); 61 | } 62 | } 63 | 64 | @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) 65 | public void onIslandDelete(IslandPreclearEvent e) { 66 | remove(e.getIsland().getWorld(), e.getIsland().getUniqueId()); 67 | } 68 | 69 | @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) 70 | public void onIslandDeleted(IslandDeleteEvent e) { 71 | // Remove island 72 | addon.getManager().deleteIsland(e.getIsland().getUniqueId()); 73 | } 74 | 75 | private void remove(World world, String uuid) { 76 | if (uuid != null && world != null) { 77 | addon.getManager().removeEntry(world, uuid); 78 | } 79 | } 80 | 81 | @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) 82 | public void onNewIslandOwner(TeamSetownerEvent e) { 83 | 84 | // Remove island from the top ten and level 85 | remove(e.getIsland().getWorld(), e.getIsland().getUniqueId()); 86 | } 87 | 88 | @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) 89 | public void onIsland(TeamJoinedEvent e) { 90 | // TODO: anything to do here? 91 | // Remove player from the top ten and level 92 | // remove(e.getIsland().getWorld(), e.getPlayerUUID()); 93 | } 94 | 95 | @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) 96 | public void onIsland(IslandUnregisteredEvent e) { 97 | 98 | // Remove island from the top ten 99 | remove(e.getIsland().getWorld(), e.getIsland().getUniqueId()); 100 | } 101 | 102 | @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) 103 | public void onIsland(IslandRegisteredEvent e) { 104 | // TODO: anything to do here? 105 | // Remove player from the top ten 106 | // remove(e.getIsland().getWorld(), e.getPlayerUUID()); 107 | } 108 | 109 | @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) 110 | public void onIsland(TeamLeaveEvent e) { 111 | // TODO: anything to do here? 112 | // Remove player from the top ten and level 113 | // remove(e.getIsland().getWorld(), e.getPlayerUUID()); 114 | } 115 | 116 | @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) 117 | public void onIsland(TeamKickEvent e) { 118 | //// TODO: anything to do here? 119 | // Remove player from the top ten and level 120 | // remove(e.getIsland().getWorld(), e.getPlayerUUID()); 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/listeners/JoinLeaveListener.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.listeners; 2 | 3 | import java.util.Objects; 4 | 5 | import org.bukkit.event.EventHandler; 6 | import org.bukkit.event.EventPriority; 7 | import org.bukkit.event.Listener; 8 | import org.bukkit.event.player.PlayerJoinEvent; 9 | 10 | import world.bentobox.level.Level; 11 | 12 | /** 13 | * Listens for when players join 14 | * @author tastybento 15 | * 16 | */ 17 | public class JoinLeaveListener implements Listener { 18 | 19 | private final Level addon; 20 | 21 | /** 22 | * @param addon - addon 23 | */ 24 | public JoinLeaveListener(Level addon) { 25 | this.addon = addon; 26 | } 27 | 28 | @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) 29 | public void onPlayerJoin(PlayerJoinEvent e) { 30 | // If level calc on login is enabled, run through all the worlds and calculate the level 31 | if (addon.getSettings().isCalcOnLogin()) { 32 | addon.getPlugin().getAddonsManager().getGameModeAddons().stream() 33 | .filter(gm -> !addon.getSettings().getGameModes().contains(gm.getDescription().getName())) 34 | .map(gm -> gm.getIslands().getIsland(gm.getOverWorld(), e.getPlayer().getUniqueId())) 35 | .filter(Objects::nonNull) 36 | .forEach(island -> addon.getManager().calculateLevel(e.getPlayer().getUniqueId(), island)); 37 | } 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/listeners/MigrationListener.java: -------------------------------------------------------------------------------- 1 | // 2 | // Created by BONNe 3 | // Copyright - 2022 4 | // 5 | 6 | 7 | package world.bentobox.level.listeners; 8 | 9 | 10 | import org.bukkit.event.EventHandler; 11 | import org.bukkit.event.Listener; 12 | 13 | import world.bentobox.bentobox.api.events.BentoBoxReadyEvent; 14 | import world.bentobox.level.Level; 15 | 16 | 17 | /** 18 | * This listener checks when BentoBox is ready and then tries to migrate Levels addon database, if it is required. 19 | */ 20 | public class MigrationListener implements Listener 21 | { 22 | public MigrationListener(Level addon) 23 | { 24 | this.addon = addon; 25 | } 26 | 27 | @EventHandler 28 | public void onBentoBoxReady(BentoBoxReadyEvent e) { 29 | // Load TopTens 30 | this.addon.getManager().loadTopTens(); 31 | /* 32 | * DEBUG code to generate fake islands and then try to level them all. 33 | Bukkit.getScheduler().runTaskLater(getPlugin(), () -> { 34 | getPlugin().getAddonsManager().getGameModeAddons().stream() 35 | .filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName())) 36 | .forEach(gm -> { 37 | for (int i = 0; i < 1000; i++) { 38 | try { 39 | NewIsland.builder().addon(gm).player(User.getInstance(UUID.randomUUID())).name("default").reason(Reason.CREATE).noPaste().build(); 40 | } catch (IOException e1) { 41 | // TODO Auto-generated catch block 42 | e1.printStackTrace(); 43 | } 44 | } 45 | }); 46 | // Queue all islands DEBUG 47 | 48 | getIslands().getIslands().stream().filter(Island::isOwned).forEach(is -> { 49 | 50 | this.getManager().calculateLevel(is.getOwner(), is).thenAccept(r -> 51 | log("Result for island calc " + r.getLevel() + " at " + is.getCenter())); 52 | 53 | }); 54 | }, 60L);*/ 55 | } 56 | 57 | 58 | private final Level addon; 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/objects/IslandLevels.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.objects; 2 | 3 | import java.util.HashMap; 4 | import java.util.Locale; 5 | import java.util.Map; 6 | 7 | import org.bukkit.Material; 8 | import org.bukkit.entity.EntityType; 9 | 10 | import com.google.gson.annotations.Expose; 11 | 12 | import world.bentobox.bentobox.database.objects.DataObject; 13 | import world.bentobox.bentobox.database.objects.Table; 14 | 15 | /** 16 | * Stores the levels data of the island. 17 | * A note - if this class is extended to support new exposed fields and legacy data doesn't include those fields 18 | * they will be set to null by GSON. They will not be initialized and if any attempt is made to use them, then 19 | * the JVM will give up WITHOUT AN ERROR!!! That is why there are null checks throughout this class. 20 | * 21 | * @author tastybento 22 | * 23 | */ 24 | @Table(name = "IslandLevels") 25 | public class IslandLevels implements DataObject { 26 | 27 | /** 28 | * uniqueId is the island's UUID 29 | */ 30 | @Expose 31 | private String uniqueId = ""; 32 | 33 | /** 34 | * Island level 35 | */ 36 | @Expose 37 | private long level; 38 | /** 39 | * Initial level 40 | */ 41 | @Expose 42 | private Long initialLevel; 43 | /** 44 | * Initial count 45 | */ 46 | @Expose 47 | private Long initialCount; 48 | /** 49 | * Points to next level 50 | */ 51 | @Expose 52 | private long pointsToNextLevel; 53 | /** 54 | * The maximum level this island has ever had 55 | */ 56 | @Expose 57 | private long maxLevel; 58 | 59 | /** 60 | * Total points 61 | */ 62 | @Expose 63 | private long totalPoints; 64 | 65 | /** 66 | * Underwater count 67 | */ 68 | @Expose 69 | private Map uwCount; 70 | 71 | /** 72 | * MaterialData count - count of all blocks excluding under water 73 | */ 74 | @Expose 75 | private Map mdCount; 76 | 77 | /** 78 | * Constructor for new island 79 | * @param islandUUID - island UUID 80 | */ 81 | public IslandLevels(String islandUUID) { 82 | uniqueId = islandUUID; 83 | uwCount = new HashMap<>(); 84 | mdCount = new HashMap<>(); 85 | } 86 | 87 | /** 88 | * @return the uniqueId 89 | */ 90 | @Override 91 | public String getUniqueId() { 92 | return uniqueId; 93 | } 94 | 95 | /** 96 | * @param uniqueId the uniqueId to set 97 | */ 98 | @Override 99 | public void setUniqueId(String uniqueId) { 100 | this.uniqueId = uniqueId; 101 | } 102 | 103 | /** 104 | * @return the level 105 | */ 106 | public long getLevel() { 107 | return level; 108 | } 109 | 110 | /** 111 | * @param level the level to set 112 | */ 113 | public void setLevel(long level) { 114 | this.level = level; 115 | // Track maximum level 116 | if (level > this.maxLevel) { 117 | maxLevel = level; 118 | } 119 | } 120 | 121 | /** 122 | * @return the initialLevel 123 | */ 124 | /* 125 | public long getInitialLevel() { 126 | // TODO: Add Backwards compatibility 127 | return initialLevel; 128 | } 129 | 130 | /** 131 | * @param initialLevel the initialLevel to set 132 | */ 133 | /* 134 | public void setInitialLevel(long initialLevel) { 135 | this.initialLevel = initialLevel; 136 | } 137 | */ 138 | /** 139 | * @return the pointsToNextLevel 140 | */ 141 | public long getPointsToNextLevel() { 142 | return pointsToNextLevel; 143 | } 144 | 145 | /** 146 | * @param pointsToNextLevel the pointsToNextLevel to set 147 | */ 148 | public void setPointsToNextLevel(long pointsToNextLevel) { 149 | this.pointsToNextLevel = pointsToNextLevel; 150 | } 151 | 152 | /** 153 | * @return the totalPoints 154 | */ 155 | public long getTotalPoints() { 156 | return totalPoints; 157 | } 158 | 159 | /** 160 | * @param totalPoints the totalPoints to set 161 | */ 162 | public void setTotalPoints(long totalPoints) { 163 | this.totalPoints = totalPoints; 164 | } 165 | 166 | /** 167 | * Get the maximum level ever set using {@link #setLevel(long)} 168 | * @return the maxLevel 169 | */ 170 | public long getMaxLevel() { 171 | return maxLevel; 172 | } 173 | 174 | /** 175 | * The count of underwater blocks 176 | * @return the uwCount 177 | */ 178 | public Map getUwCount() { 179 | // Loaded objects come in as strings, so need to be converted to Material Or EntityTypes 180 | uwCount = convertMap(uwCount); 181 | return uwCount; 182 | } 183 | 184 | /** 185 | * Underwater blocks 186 | * @param map the uwCount to set 187 | */ 188 | public void setUwCount(Map map) { 189 | this.uwCount = map; 190 | } 191 | 192 | /** 193 | * All blocks count except for underwater blocks 194 | * @return the mdCount 195 | */ 196 | public Map getMdCount() { 197 | // Loaded objects come in as strings, so need to be converted to Material Or EntityTypes 198 | mdCount = convertMap(mdCount); 199 | return mdCount; 200 | } 201 | 202 | private Map convertMap(Map blockCountMap) { 203 | Map convertedMap = new HashMap<>(); 204 | 205 | for (Map.Entry entry : blockCountMap.entrySet()) { 206 | Object key = entry.getKey(); 207 | Integer value = entry.getValue(); 208 | 209 | if (key instanceof String keyStr) { 210 | // First, try converting to Material 211 | Material material = Material.matchMaterial(keyStr); 212 | if (material != null) { 213 | convertedMap.put(material, value); 214 | } else { 215 | // Fallback to converting to EntityType (using uppercase as enum constants are uppercase) 216 | try { 217 | EntityType entityType = EntityType.valueOf(keyStr.toUpperCase(Locale.ENGLISH)); 218 | convertedMap.put(entityType, value); 219 | } catch (IllegalArgumentException ex) { 220 | // No valid Material or EntityType found. 221 | convertedMap.put(key, value); // Leave the key unchanged. 222 | } 223 | } 224 | } else { 225 | // If the key is not a String, add it directly. 226 | convertedMap.put(key, value); 227 | } 228 | } 229 | return convertedMap; 230 | } 231 | 232 | /** 233 | * All blocks except for underwater blocks 234 | * @param mdCount the mdCount to set 235 | */ 236 | public void setMdCount(Map mdCount) { 237 | this.mdCount = mdCount; 238 | } 239 | 240 | /** 241 | * @return the initialCount 242 | */ 243 | public Long getInitialCount() { 244 | return initialCount; 245 | } 246 | 247 | /** 248 | * @param initialCount the initialCount to set 249 | */ 250 | public void setInitialCount(Long initialCount) { 251 | this.initialCount = initialCount; 252 | } 253 | 254 | /** 255 | * @return the initialLevel 256 | * @deprecated only used for backwards compatibility. Use {@link #getInitialCount()} instead 257 | */ 258 | public Long getInitialLevel() { 259 | return initialLevel; 260 | } 261 | 262 | /** 263 | * @param initialLevel the initialLevel to set 264 | * @deprecated only used for backwards compatil 265 | */ 266 | public void setInitialLevel(Long initialLevel) { 267 | this.initialLevel = initialLevel; 268 | } 269 | 270 | } 271 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/objects/LevelsData.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.objects; 2 | 3 | import java.util.Collections; 4 | import java.util.EnumMap; 5 | import java.util.HashMap; 6 | import java.util.Locale; 7 | import java.util.Map; 8 | import java.util.TreeMap; 9 | import java.util.UUID; 10 | 11 | import org.bukkit.Material; 12 | import org.bukkit.World; 13 | 14 | import com.google.common.collect.Multiset; 15 | import com.google.gson.annotations.Expose; 16 | 17 | import world.bentobox.bentobox.database.objects.DataObject; 18 | import world.bentobox.bentobox.database.objects.Table; 19 | 20 | /** 21 | * Stores the levels data of the user. 22 | * A note - if this class is extended to support new exposed fields and legacy data doesn't include those fields 23 | * they will be set to null by GSON. They will not be initialized and if any attempt is made to use them, then 24 | * the JVM will give up WITHOUT AN ERROR!!! That is why there are null checks throughout this class. 25 | * 26 | * @author tastybento 27 | * 28 | */ 29 | @Table(name = "LevelsData") 30 | public class LevelsData implements DataObject { 31 | 32 | // uniqueId is the player's UUID 33 | @Expose 34 | private String uniqueId = ""; 35 | 36 | /** 37 | * Map of world name and island level 38 | */ 39 | @Expose 40 | private Map levels; 41 | /** 42 | * Map of world name to island initial level 43 | */ 44 | @Expose 45 | private Map initialLevel; 46 | /** 47 | * Map of world name to points to next level 48 | */ 49 | @Expose 50 | private Map pointsToNextLevel; 51 | 52 | @Expose 53 | private Map> uwCount; 54 | 55 | @Expose 56 | private Map> mdCount; 57 | 58 | /** 59 | * Create a level entry for target player 60 | * @param targetPlayer - target player 61 | */ 62 | public LevelsData(UUID targetPlayer) { 63 | uniqueId = targetPlayer.toString(); 64 | levels = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 65 | initialLevel = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 66 | pointsToNextLevel = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 67 | uwCount = new HashMap<>(); 68 | mdCount = new HashMap<>(); 69 | } 70 | 71 | private void initialize() { 72 | if (levels == null) levels = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 73 | if (initialLevel == null) initialLevel = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 74 | if (pointsToNextLevel == null) pointsToNextLevel = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 75 | if (uwCount == null) uwCount = new HashMap<>(); 76 | if (mdCount == null) mdCount = new HashMap<>(); 77 | } 78 | 79 | /* (non-Javadoc) 80 | * @see world.bentobox.bbox.database.objects.DataObject#getUniqueId() 81 | */ 82 | @Override 83 | public String getUniqueId() { 84 | return uniqueId; 85 | } 86 | 87 | /* (non-Javadoc) 88 | * @see world.bentobox.bbox.database.objects.DataObject#setUniqueId(java.lang.String) 89 | */ 90 | @Override 91 | public void setUniqueId(String uniqueId) { 92 | this.uniqueId = uniqueId; 93 | } 94 | 95 | /** 96 | * Get the island level for this world 97 | * @param world - world 98 | * @return island level 99 | */ 100 | public Long getLevel(World world) { 101 | initialize(); 102 | return world == null ? 0L : levels.getOrDefault(world.getName().toLowerCase(Locale.ENGLISH), 0L); 103 | } 104 | 105 | /** 106 | * @return the levels 107 | */ 108 | public Map getLevels() { 109 | initialize(); 110 | return levels; 111 | } 112 | 113 | /** 114 | * @param levels the levels to set 115 | */ 116 | public void setLevels(Map levels) { 117 | initialize(); 118 | this.levels = levels; 119 | } 120 | 121 | /** 122 | * Sets the island level to level - the initial level 123 | * @param world - world where island is 124 | * @param lv - level 125 | */ 126 | public void setLevel(World world, Long lv) { 127 | initialize(); 128 | String name = world.getName().toLowerCase(Locale.ENGLISH); 129 | levels.put(name, lv - this.initialLevel.getOrDefault(name, 0L)); 130 | } 131 | 132 | /** 133 | * Set the initial level of the island for this world 134 | * @param world - world 135 | * @param level - level 136 | */ 137 | public void setInitialLevel(World world, long level) { 138 | initialize(); 139 | this.initialLevel.put(world.getName().toLowerCase(Locale.ENGLISH), level); 140 | } 141 | 142 | /** 143 | * @return the initialLevel 144 | */ 145 | public Map getInitialLevel() { 146 | initialize(); 147 | return initialLevel; 148 | } 149 | 150 | /** 151 | * @param initialLevel the initialLevel to set 152 | */ 153 | public void setInitialLevel(Map initialLevel) { 154 | initialize(); 155 | this.initialLevel = initialLevel; 156 | } 157 | 158 | /** 159 | * Get the initial island level for this world 160 | * @param world - world 161 | * @return initial island level or 0 by default 162 | */ 163 | public long getInitialLevel(World world) { 164 | initialize(); 165 | return initialLevel.getOrDefault(world.getName().toLowerCase(Locale.ENGLISH), 0L); 166 | } 167 | 168 | /** 169 | * Remove a world from a player's data 170 | * @param world - world to remove 171 | */ 172 | public void remove(World world) { 173 | initialize(); 174 | this.levels.remove(world.getName().toLowerCase(Locale.ENGLISH)); 175 | this.initialLevel.remove(world.getName().toLowerCase(Locale.ENGLISH)); 176 | this.pointsToNextLevel.remove(world.getName().toLowerCase(Locale.ENGLISH)); 177 | this.mdCount.remove(world.getName().toLowerCase(Locale.ENGLISH)); 178 | this.uwCount.remove(world.getName().toLowerCase(Locale.ENGLISH)); 179 | } 180 | 181 | /** 182 | * @return the pointsToNextLevel 183 | */ 184 | public Map getPointsToNextLevel() { 185 | initialize(); 186 | return pointsToNextLevel; 187 | } 188 | 189 | /** 190 | * @param pointsToNextLevel the pointsToNextLevel to set 191 | */ 192 | public void setPointsToNextLevel(Map pointsToNextLevel) { 193 | initialize(); 194 | this.pointsToNextLevel = pointsToNextLevel; 195 | } 196 | 197 | /** 198 | * Sets the island points to next level. 199 | * This is calculated the last time the level was calculated and will not change dynamically. 200 | * @param world - world where island is 201 | * @param points - points to next level 202 | */ 203 | public void setPointsToNextLevel(World world, Long points) { 204 | initialize(); 205 | pointsToNextLevel.put(world.getName().toLowerCase(Locale.ENGLISH), points); 206 | } 207 | 208 | /** 209 | * Get the points required to get to the next island level for this world. 210 | * This is calculated when the island level is calculated and will not change dynamically. 211 | * @param world - world 212 | * @return points to next level or zero if unknown 213 | */ 214 | public long getPointsToNextLevel(World world) { 215 | initialize(); 216 | return pointsToNextLevel.getOrDefault(world.getName().toLowerCase(Locale.ENGLISH), 0L); 217 | } 218 | 219 | /** 220 | * @param uwCount the uwCount to set 221 | */ 222 | public void setUwCount(World world, Multiset uwCount) { 223 | initialize(); 224 | Map count = new EnumMap<>(Material.class); 225 | uwCount.forEach(m -> count.put(m, uwCount.count(m))); 226 | 227 | this.uwCount.put(world.getName().toLowerCase(Locale.ENGLISH), count); 228 | } 229 | 230 | /** 231 | * @param mdCount the mdCount to set 232 | */ 233 | public void setMdCount(World world, Multiset mdCount) { 234 | initialize(); 235 | Map count = new EnumMap<>(Material.class); 236 | mdCount.forEach(m -> count.put(m, mdCount.count(m))); 237 | 238 | this.mdCount.put(world.getName().toLowerCase(Locale.ENGLISH), count); 239 | 240 | } 241 | 242 | /** 243 | * Get the underwater block count for world 244 | * @return the uwCount 245 | */ 246 | public Map getUwCount(World world) { 247 | initialize(); 248 | return uwCount.getOrDefault(world.getName().toLowerCase(Locale.ENGLISH), Collections.emptyMap()); 249 | } 250 | 251 | /** 252 | * Get the over-water block count for world 253 | * @return the mdCount 254 | */ 255 | public Map getMdCount(World world) { 256 | initialize(); 257 | return mdCount.getOrDefault(world.getName().toLowerCase(Locale.ENGLISH), Collections.emptyMap()); 258 | } 259 | 260 | 261 | } 262 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/objects/TopTenData.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.objects; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Locale; 5 | import java.util.Map; 6 | 7 | import org.bukkit.World; 8 | 9 | import com.google.gson.annotations.Expose; 10 | 11 | /** 12 | * This class stores the top ten. 13 | * 14 | * @author tastybento 15 | * 16 | */ 17 | public class TopTenData { 18 | 19 | // UniqueId is the world name 20 | @Expose 21 | private String uniqueId = ""; 22 | @Expose 23 | private Map topTen = new LinkedHashMap<>(); 24 | 25 | public TopTenData(World k) { 26 | uniqueId = k.getName().toLowerCase(Locale.ENGLISH); 27 | } 28 | 29 | /** 30 | * @return the topTen 31 | */ 32 | public Map getTopTen() { 33 | return topTen; 34 | } 35 | 36 | /** 37 | * @param topTen the topTen to set 38 | */ 39 | public void setTopTen(Map topTen) { 40 | this.topTen = topTen; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/requests/LevelRequestHandler.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.requests; 2 | 3 | import java.util.Map; 4 | import java.util.UUID; 5 | 6 | import org.bukkit.Bukkit; 7 | 8 | import world.bentobox.bentobox.api.addons.request.AddonRequestHandler; 9 | import world.bentobox.level.Level; 10 | 11 | public class LevelRequestHandler extends AddonRequestHandler { 12 | 13 | private static final Object WORLD_NAME = "world-name"; 14 | private static final Object PLAYER = "player"; 15 | private final Level addon; 16 | 17 | public LevelRequestHandler(Level addon) { 18 | super("island-level"); 19 | this.addon = addon; 20 | } 21 | 22 | @Override 23 | public Object handle(Map map) { 24 | /* 25 | What we need in the map: 26 | 27 | 0. "world-name" -> String 28 | 1. "player" -> UUID 29 | 30 | What we will return: 31 | 32 | - 0L if invalid input/player has no island 33 | - the island level otherwise (which may be 0) 34 | */ 35 | 36 | if (map == null || map.isEmpty() 37 | || map.get(WORLD_NAME) == null || !(map.get(WORLD_NAME) instanceof String) 38 | || map.get(PLAYER) == null || !(map.get(PLAYER) instanceof UUID) 39 | || Bukkit.getWorld((String) map.get(WORLD_NAME)) == null) { 40 | return 0L; 41 | } 42 | 43 | return addon.getManager().getIslandLevel(Bukkit.getWorld((String) map.get(WORLD_NAME)), (UUID) map.get(PLAYER)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/requests/TopTenRequestHandler.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.requests; 2 | 3 | import java.util.Collections; 4 | import java.util.Map; 5 | 6 | import org.bukkit.Bukkit; 7 | 8 | import world.bentobox.bentobox.api.addons.request.AddonRequestHandler; 9 | import world.bentobox.level.Level; 10 | 11 | 12 | /** 13 | * This Request Handler allows other plugins to get access to top 10 player list per particular world. 14 | * Handler returns linked hashmap from TopTenData for particular world. 15 | */ 16 | public class TopTenRequestHandler extends AddonRequestHandler { 17 | 18 | private static final String WORLD_NAME = "world-name"; 19 | /** 20 | * The level addon field. 21 | */ 22 | private final Level addon; 23 | 24 | /** 25 | * This constructor creates a new TopTenRequestHandler instance. 26 | * 27 | * @param addon of type Level 28 | */ 29 | public TopTenRequestHandler(Level addon) { 30 | super("top-ten-level"); 31 | this.addon = addon; 32 | } 33 | 34 | /** 35 | * See {@link AddonRequestHandler#handle(Map)} 36 | */ 37 | @Override 38 | public Object handle(Map map) { 39 | /* 40 | What we need in the map: 41 | 42 | "world-name" -> String 43 | 44 | What we will return: 45 | 46 | - Empty map if invalid input 47 | - the map of top ten player UUIDs and their island levels. Can be less then 10. 48 | */ 49 | 50 | if (map == null || map.isEmpty() 51 | || map.get(WORLD_NAME) == null || !(map.get(WORLD_NAME) instanceof String) 52 | || Bukkit.getWorld((String) map.get(WORLD_NAME)) == null) { 53 | return Collections.emptyMap(); 54 | } 55 | 56 | // No null check required 57 | return addon.getManager().getTopTen(Bukkit.getWorld((String) map.get(WORLD_NAME)), Level.TEN); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/util/CachedData.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.util; 2 | 3 | import java.time.Instant; 4 | import java.util.Map; 5 | 6 | /** 7 | * Cache for top tens 8 | */ 9 | public class CachedData { 10 | private Map cachedMap; 11 | private Instant lastUpdated; 12 | 13 | public CachedData(Map cachedMap, Instant lastUpdated) { 14 | this.cachedMap = cachedMap; 15 | this.lastUpdated = lastUpdated; 16 | } 17 | 18 | public Map getCachedMap() { 19 | return cachedMap; 20 | } 21 | 22 | public Instant getLastUpdated() { 23 | return lastUpdated; 24 | } 25 | 26 | public void updateCache(Map newMap, Instant newUpdateTime) { 27 | this.cachedMap = newMap; 28 | this.lastUpdated = newUpdateTime; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/util/ConversationUtils.java: -------------------------------------------------------------------------------- 1 | // 2 | // Created by BONNe 3 | // Copyright - 2021 4 | // 5 | 6 | 7 | package world.bentobox.level.util; 8 | 9 | 10 | import java.util.function.Consumer; 11 | 12 | import org.bukkit.conversations.ConversationAbandonedListener; 13 | import org.bukkit.conversations.ConversationContext; 14 | import org.bukkit.conversations.ConversationFactory; 15 | import org.bukkit.conversations.MessagePrompt; 16 | import org.bukkit.conversations.Prompt; 17 | import org.bukkit.conversations.StringPrompt; 18 | import org.eclipse.jdt.annotation.NonNull; 19 | import org.eclipse.jdt.annotation.Nullable; 20 | 21 | import world.bentobox.bentobox.BentoBox; 22 | import world.bentobox.bentobox.api.user.User; 23 | 24 | 25 | public class ConversationUtils 26 | { 27 | // --------------------------------------------------------------------- 28 | // Section: Conversation API implementation 29 | // --------------------------------------------------------------------- 30 | 31 | private ConversationUtils() {} // Private constructor as this is a utility class only with static methods 32 | 33 | /** 34 | * This method will close opened gui and writes question in chat. After players answers on question in chat, message 35 | * will trigger consumer and gui will reopen. 36 | * 37 | * @param consumer Consumer that accepts player output text. 38 | * @param question Message that will be displayed in chat when player triggers conversion. 39 | * @param user User who is targeted with current confirmation. 40 | */ 41 | public static void createStringInput(Consumer consumer, 42 | User user, 43 | @NonNull String question, 44 | @Nullable String successMessage) 45 | { 46 | // Text input message. 47 | StringPrompt stringPrompt = new StringPrompt() 48 | { 49 | @Override 50 | public @NonNull String getPromptText(@NonNull ConversationContext context) 51 | { 52 | user.closeInventory(); 53 | return question; 54 | } 55 | 56 | 57 | @Override 58 | public @NonNull Prompt acceptInput(@NonNull ConversationContext context, @Nullable String input) 59 | { 60 | consumer.accept(input); 61 | return ConversationUtils.endMessagePrompt(successMessage); 62 | } 63 | }; 64 | 65 | new ConversationFactory(BentoBox.getInstance()). 66 | withPrefix(context -> user.getTranslation("level.conversations.prefix")). 67 | withFirstPrompt(stringPrompt). 68 | // On cancel conversation will be closed. 69 | withLocalEcho(false). 70 | withTimeout(90). 71 | withEscapeSequence(user.getTranslation("level.conversations.cancel-string")). 72 | // Use null value in consumer to detect if user has abandoned conversation. 73 | addConversationAbandonedListener(ConversationUtils.getAbandonListener(consumer, user)). 74 | buildConversation(user.getPlayer()). 75 | begin(); 76 | } 77 | 78 | 79 | /** 80 | * This is just a simple end message prompt that displays requested message. 81 | * 82 | * @param message Message that will be displayed. 83 | * @return MessagePrompt that displays given message and exists from conversation. 84 | */ 85 | private static MessagePrompt endMessagePrompt(@Nullable String message) 86 | { 87 | return new MessagePrompt() 88 | { 89 | @Override 90 | public @NonNull String getPromptText(@NonNull ConversationContext context) 91 | { 92 | return message == null ? "" : message; 93 | } 94 | 95 | 96 | @Override 97 | protected @Nullable Prompt getNextPrompt(@NonNull ConversationContext context) 98 | { 99 | return Prompt.END_OF_CONVERSATION; 100 | } 101 | }; 102 | } 103 | 104 | 105 | /** 106 | * This method creates and returns abandon listener for every conversation. 107 | * 108 | * @param consumer Consumer which must return null value. 109 | * @param user User who was using conversation. 110 | * @return ConversationAbandonedListener instance. 111 | */ 112 | private static ConversationAbandonedListener getAbandonListener(Consumer consumer, User user) 113 | { 114 | return abandonedEvent -> 115 | { 116 | if (!abandonedEvent.gracefulExit()) 117 | { 118 | consumer.accept(null); 119 | // send cancell message 120 | abandonedEvent.getContext().getForWhom().sendRawMessage( 121 | user.getTranslation("level.conversations.prefix") + 122 | user.getTranslation("level.conversations.cancelled")); 123 | } 124 | }; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/world/bentobox/level/util/Utils.java: -------------------------------------------------------------------------------- 1 | // 2 | // Created by BONNe 3 | // Copyright - 2021 4 | // 5 | 6 | 7 | package world.bentobox.level.util; 8 | 9 | 10 | import java.util.List; 11 | 12 | import org.bukkit.Material; 13 | import org.bukkit.entity.EntityType; 14 | import org.bukkit.permissions.PermissionAttachmentInfo; 15 | 16 | import world.bentobox.bentobox.api.user.User; 17 | import world.bentobox.bentobox.hooks.LangUtilsHook; 18 | 19 | 20 | public class Utils 21 | { 22 | 23 | private Utils() {} // Private constructor as this is a utility class only with static methods 24 | 25 | /** 26 | * This method sends a message to the user with appended "prefix" text before message. 27 | * @param user User who receives message. 28 | * @param translationText Translation text of the message. 29 | * @param parameters Parameters for the translation text. 30 | */ 31 | public static void sendMessage(User user, String translationText, String... parameters) 32 | { 33 | user.sendMessage(user.getTranslation( "level.conversations.prefix") + 34 | user.getTranslation( translationText, parameters)); 35 | } 36 | 37 | 38 | /** 39 | * This method gets string value of given permission prefix. If user does not have given permission or it have all 40 | * (*), then return default value. 41 | * 42 | * @param user User who's permission should be checked. 43 | * @param permissionPrefix Prefix that need to be found. 44 | * @param defaultValue Default value that will be returned if permission not found. 45 | * @return String value that follows permissionPrefix. 46 | */ 47 | public static String getPermissionValue(User user, String permissionPrefix, String defaultValue) 48 | { 49 | if (user.isPlayer()) 50 | { 51 | if (permissionPrefix.endsWith(".")) 52 | { 53 | permissionPrefix = permissionPrefix.substring(0, permissionPrefix.length() - 1); 54 | } 55 | 56 | String permPrefix = permissionPrefix + "."; 57 | 58 | List permissions = user.getEffectivePermissions().stream(). 59 | map(PermissionAttachmentInfo::getPermission). 60 | filter(permission -> permission.startsWith(permPrefix)). 61 | toList(); 62 | 63 | for (String permission : permissions) 64 | { 65 | if (permission.contains(permPrefix + "*")) 66 | { 67 | // * means all. So continue to search more specific. 68 | continue; 69 | } 70 | 71 | String[] parts = permission.split(permPrefix); 72 | 73 | if (parts.length > 1) 74 | { 75 | return parts[1]; 76 | } 77 | } 78 | } 79 | 80 | return defaultValue; 81 | } 82 | 83 | 84 | /** 85 | * This method allows to get next value from array list after given value. 86 | * 87 | * @param values Array that should be searched for given value. 88 | * @param currentValue Value which next element should be found. 89 | * @param Instance of given object. 90 | * @return Next value after currentValue in values array. 91 | */ 92 | public static T getNextValue(T[] values, T currentValue) 93 | { 94 | for (int i = 0; i < values.length; i++) 95 | { 96 | if (values[i].equals(currentValue)) 97 | { 98 | if (i + 1 == values.length) 99 | { 100 | return values[0]; 101 | } 102 | else 103 | { 104 | return values[i + 1]; 105 | } 106 | } 107 | } 108 | 109 | return currentValue; 110 | } 111 | 112 | 113 | /** 114 | * This method allows to get previous value from array list after given value. 115 | * 116 | * @param values Array that should be searched for given value. 117 | * @param currentValue Value which previous element should be found. 118 | * @param Instance of given object. 119 | * @return Previous value before currentValue in values array. 120 | */ 121 | public static T getPreviousValue(T[] values, T currentValue) 122 | { 123 | for (int i = 0; i < values.length; i++) 124 | { 125 | if (values[i].equals(currentValue)) 126 | { 127 | if (i > 0) 128 | { 129 | return values[i - 1]; 130 | } 131 | else 132 | { 133 | return values[values.length - 1]; 134 | } 135 | } 136 | } 137 | 138 | return currentValue; 139 | } 140 | 141 | /** 142 | * Reference string in translations. 143 | */ 144 | public static final String ENTITIES = "level.entities."; 145 | private static final String LEVEL_MATERIALS = "level.materials."; 146 | private static final String DESCRIPTION = ".description"; 147 | 148 | public static String prettifyObject(Object object, User user) { 149 | if (object == null) { 150 | return ""; 151 | } 152 | // All supported objects are enums so we can use name() safely. 153 | String translation = ""; 154 | 155 | if (object instanceof Material || object instanceof String) { 156 | String key = ""; 157 | if (object instanceof Material) { 158 | key = ((Enum) object).name().toLowerCase(); 159 | } else { 160 | key = (String) object; 161 | } 162 | 163 | // Try our translations for Material. 164 | translation = user.getTranslationOrNothing(LEVEL_MATERIALS + key + ".name"); 165 | if (!translation.isEmpty()) 166 | return translation; 167 | 168 | translation = user.getTranslationOrNothing(LEVEL_MATERIALS + key); 169 | if (!translation.isEmpty()) 170 | return translation; 171 | 172 | translation = user.getTranslationOrNothing("materials." + key); 173 | if (!translation.isEmpty()) 174 | return translation; 175 | 176 | if (object instanceof Material) { 177 | // Fallback to our hook for Material. 178 | return LangUtilsHook.getMaterialName((Material) object, user); 179 | } else { 180 | return key; 181 | } 182 | } else if (object instanceof EntityType) { 183 | String key = ((Enum) object).name().toLowerCase(); 184 | // Try our translations for EntityType. 185 | translation = user.getTranslationOrNothing(ENTITIES + key + ".name"); 186 | if (!translation.isEmpty()) 187 | return translation; 188 | 189 | translation = user.getTranslationOrNothing(ENTITIES + key); 190 | if (!translation.isEmpty()) 191 | return translation; 192 | 193 | translation = user.getTranslationOrNothing("entities." + key); 194 | if (!translation.isEmpty()) 195 | return translation; 196 | 197 | // Fallback to our hook for EntityType. 198 | return LangUtilsHook.getEntityName((EntityType) object, user); 199 | } 200 | 201 | // In case of an unexpected type, return an empty string. 202 | return ""; 203 | } 204 | 205 | public static String prettifyDescription(Object object, User user) { 206 | if (object instanceof String key) { 207 | String translation = user.getTranslationOrNothing(LEVEL_MATERIALS + key + DESCRIPTION); 208 | return translation != null ? translation : ""; 209 | } 210 | if (object == null || !(object instanceof Enum)) { 211 | return ""; 212 | } 213 | String key = ((Enum) object).name().toLowerCase(); 214 | 215 | if (object instanceof Material) { 216 | String translation = user.getTranslationOrNothing(LEVEL_MATERIALS + key + DESCRIPTION); 217 | return translation != null ? translation : ""; 218 | } else if (object instanceof EntityType) { 219 | String translation = user.getTranslationOrNothing(ENTITIES + key + DESCRIPTION); 220 | return translation != null ? translation : ""; 221 | } 222 | 223 | return ""; 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /src/main/resources/addon.yml: -------------------------------------------------------------------------------- 1 | name: Level 2 | main: world.bentobox.level.Level 3 | version: ${version}${build.number} 4 | icon: DIAMOND 5 | api-version: 2.4.0 6 | 7 | authors: tastybento 8 | 9 | permissions: 10 | '[gamemode].intopten': 11 | description: Player is in the top ten. 12 | default: true 13 | '[gamemode].island.level': 14 | description: Player can use level command 15 | default: true 16 | '[gamemode].island.detail': 17 | description: Player can use island detail command 18 | default: true 19 | '[gamemode].island.top': 20 | description: Player can use top ten command 21 | default: true 22 | '[gamemode].island.value': 23 | description: Player can use value command 24 | default: true 25 | '[gamemode].island.level.details.blocks': 26 | description: Player see the level details 27 | default: true 28 | '[gamemode].island.level.details.spawners': 29 | description: Player can see the spawners tab in the level details 30 | default: false 31 | '[gamemode].island.level.details.underwater': 32 | description: Player can see the underwater tab in the level details 33 | default: false 34 | '[gamemode].island.level.details.above-sea-level': 35 | description: Player can see the above sea level tab in the level details 36 | default: false 37 | '[gamemode].admin.level': 38 | description: Player can use admin level command 39 | default: op 40 | '[gamemode].admin.topten': 41 | description: Player can use admin top ten command 42 | default: op 43 | -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | # Level Configuration ${version} 2 | # 3 | # 4 | # Disabled Game Mode Addons 5 | # Level will NOT hook into these game mode addons. 6 | disabled-game-modes: [] 7 | # 8 | # Disable ItemsAdder support 9 | # This will ignore ItemsAdder even if it is installed and not use it. Do not set this to true unless you know what you are doing. 10 | disabled-itemsadder: false 11 | # 12 | # When executing level command from console, should a report be shown? 13 | log-report-to-console: true 14 | # 15 | # Number of concurrent island calculations 16 | # If your CPU can handle it, you can run parallel island calcs if there are more than one in the queue 17 | concurrent-island-calcs: 1 18 | # 19 | # Island level calculation timeout in minutes. 20 | # If an island takes longer that this time to calculate, then the calculation will abort. 21 | # Generally, calculation should only take a few seconds, so if this ever triggers then something is not right. 22 | calculation-timeout: 5 23 | # 24 | # Zero island levels on new island or island reset 25 | # If true, Level will calculate the starter island's level and remove it from any future level calculations. 26 | # If false, the player's starter island blocks will count towards their level. 27 | # This will reduce CPU if false. 28 | zero-new-island-levels: true 29 | # 30 | # Calculate island level on login 31 | # This silently calculates the player's island level when they login 32 | # This applies to all islands the player has on the server, e.g., BSkyBlock, AcidIsland 33 | login: false 34 | # 35 | # Include nether island in level calculations. 36 | # Warning: Enabling this mid-game will give players with an island a jump in 37 | # island level. New islands will be correctly zeroed. 38 | nether: false 39 | # 40 | # Include end island in level calculations. 41 | # Warning: Enabling this mid-game will give players with an island a jump in 42 | # island level. New islands will be correctly zeroed. 43 | end: false 44 | # 45 | # Include chest contents in level calculations. 46 | # Will count blocks in chests or containers. 47 | include-chests: false 48 | # 49 | # Underwater block multiplier 50 | # If blocks are below sea-level, they can have a higher value. e.g. 2x 51 | # Promotes under-water development if there is a sea. Value can be fractional. 52 | underwater: 1.0 53 | # 54 | # Value of one island level. Default 100. Minimum value is 1. 55 | levelcost: 100 56 | # 57 | # Island level calculation formula 58 | # blocks - the sum total of all block values, less any death penalty 59 | # level_cost - in a linear equation, the value of one level 60 | # This formula can include +,=,*,/,sqrt,^,sin,cos,tan,log (natural log). Result will always be rounded to a long integer 61 | # for example, an alternative non-linear option could be: 3 * sqrt(blocks / level_cost) 62 | level-calc: blocks / level_cost 63 | # 64 | # Cooldown between level requests in seconds 65 | levelwait: 60 66 | # 67 | # Death penalty 68 | # How many block values a player will lose per death. 69 | # Default value of 100 means that for every death, the player will lose 1 level (if levelcost is 100) 70 | # Set to zero to not use this feature 71 | deathpenalty: 100 72 | # Sum team deaths - if true, all the teams deaths are summed 73 | # If false, only the leader's deaths counts 74 | # For other death related settings, see the GameModeAddon's config.yml settings. 75 | sumteamdeaths: false 76 | # Shorthand island level 77 | # Shows large level values rounded down, e.g., 10,345 -> 10k 78 | shorthand: false 79 | units: 80 | # Shorthand units 81 | kilo: k 82 | mega: M 83 | giga: G 84 | tera: T 85 | # 86 | # Include Shulker Box content in chests in level calculations. 87 | # Will count blocks in Shulker Boxes inside of chests. 88 | # NOTE: include-chests needs to be enabled for this to work!. 89 | include-shulkers-in-chest: false 90 | # 91 | # Disables hooking with other plugins. 92 | # Example: disabled-plugin-hooks: [UltimateStacker, RoseStacker] 93 | disabled-plugin-hooks: [] 94 | -------------------------------------------------------------------------------- /src/main/resources/locales/cs.yml: -------------------------------------------------------------------------------- 1 | admin: 2 | level: 3 | parameters: 4 | description: vypočítat úroveň ostrova hráče 5 | sethandicap: 6 | parameters: [+/-] 7 | description: | 8 | Nastavte nebo změňte ostrov *handicap* 9 | např. +10 odstraní 10 úrovní, 10 | 30 nastaví handicap na 30, 11 | -20 přidá 20 úrovní 12 | changed: '&a Počáteční ostrovní handicap se změnil z [number] na [new_number].' 13 | invalid-level: '&c Neplatný handicap. Použijte celé číslo.' 14 | levelstatus: 15 | description: Ukažte, kolik ostrovů je ve frontě pro skenování 16 | islands-in-queue: '&a Ostrovy ve frontě: [number]' 17 | top: 18 | description: ukázat seznam TOP 10 19 | unknown-world: '&cNeznámý svět!' 20 | display: '&f[rank]. &a[name] &7- &b[level]' 21 | remove: 22 | description: odstranit hráče z TOP 10 23 | parameters: 24 | stats: 25 | description: Zobrazit statistiky na ostrovech na tomto serveru 26 | title: Statistiky serveru 27 | world: '&a [name]' 28 | no-data: '&c Žádná data pro zpracování.' 29 | average-level: 'Průměrná úroveň ostrova: [number]' 30 | median-level: 'Střední úroveň ostrova: [number]' 31 | mode-level: 'Úroveň ostrova režimu: [number]' 32 | highest-level: 'Nejvyšší úroveň ostrova: [number]' 33 | lowest-level: 'Nejnižší úroveň ostrova: [number]' 34 | distribution: 'Distribuce úrovně ostrova:' 35 | islands: ostrovy 36 | island: 37 | level: 38 | parameters: '[player]' 39 | description: spočítat úroveň tvého ostrova nebo ostrova hráče [player] 40 | calculating: '&aPočítám úroveň...' 41 | estimated-wait: '&a Odhadované čekání: [number] sekundy' 42 | in-queue: '&a Jste číslo [number] ve frontě' 43 | island-level-is: '&aÚroveň ostrova je &b[level]' 44 | required-points-to-next-level: '&a[points] vyžadováno do další úrovně' 45 | deaths: '&c([number] smrtí)' 46 | cooldown: '&cMusíš čekat &b[time] &csekund, než můžeš příkaz znovu použít' 47 | in-progress: '&6 Probíhá výpočet úrovně ostrova ...' 48 | time-out: '&c Výpočet úrovně trval příliš dlouho. Zkuste to prosím znovu později.' 49 | top: 50 | description: ukázat TOP 10 51 | gui-title: '&aTOP 10' 52 | gui-heading: '&6[name]: &B[rank]' 53 | island-level: '&BÚroveň [level]' 54 | warp-to: '&AWarp na ostrov [name]' 55 | level-details: 56 | above-sea-level-blocks: Nad bloky hladiny moře 57 | spawners: Spawners 58 | underwater-blocks: Podvodové bloky 59 | all-blocks: Všechny bloky 60 | no-island: '&c Žádný ostrov!' 61 | names-island: '[name]''s Island' 62 | syntax: '[name] x [number]' 63 | hint: '&c Spustit úroveň a zobrazit zprávu bloku' 64 | level: 65 | commands: 66 | value: 67 | parameters: '[hand |]' 68 | description: >- 69 | ukazuje hodnotu bloků. Na konci přidejte „ruku“ a zobrazíte hodnotu pro 70 | položku v ruce. 71 | gui: 72 | titles: 73 | top: '&0&l Nejlepší ostrovy' 74 | detail-panel: '&0&l [name]''s Island' 75 | value-panel: '&0&l Blokové hodnoty' 76 | buttons: 77 | island: 78 | empty: '&f&l [name]. místo' 79 | name: '&f&l [name]' 80 | description: |- 81 | [owner] 82 | [members] 83 | [place] 84 | [level] 85 | owners-island: '[player]''s Island' 86 | owner: '&7&l Majitel: &r&b [player]' 87 | members-title: '&7&l Členové:' 88 | member: '&b - [player]' 89 | unknown: neznámý 90 | place: '&7&o [number]. &r&7 místo' 91 | level: '&7 Úroveň:&o [number]' 92 | material: 93 | name: '&f&l [number] x [material]' 94 | description: |- 95 | [description] 96 | [count] 97 | [value] 98 | [calculated] 99 | [limit] 100 | [id] 101 | id: '&7 Blok ID: &e [id]' 102 | value: '&7 Hodnota bloku:&e [number]' 103 | limit: '&7 Limit bloku:&e [number]' 104 | count: '&7 Počet bloků:&e [number]' 105 | calculated: '&7 Vypočítaná hodnota:&e [number]' 106 | value_blocks: 107 | name: '&f&l Všechny bloky s hodnotou' 108 | description: |- 109 | &7 Zobrazit všechny bloky 110 | &7 s hodnotou na ostrově. 111 | all_blocks: 112 | name: '&f&l Všechny bloky' 113 | description: |- 114 | &7 Zobrazit všechny bloky 115 | &7 na ostrově. 116 | above_sea_level: 117 | name: '&f&l Bloky nad hladinou moře' 118 | description: |- 119 | &7 Zobrazit pouze bloky 120 | &7 které jsou nad mořem 121 | &7 úroveň. 122 | underwater: 123 | name: '&f&l Blocks Under Sea level' 124 | description: |- 125 | &7 Zobrazit pouze bloky 126 | &7 to je níže moře 127 | &7 úroveň. 128 | spawner: 129 | name: '&f&l Spawners' 130 | description: '&7 Displej pouze tření.' 131 | block-name: '&b Spawner' 132 | filters: 133 | name: 134 | name: '&f&l Sort by Name' 135 | description: '&7 Sort all blocks by name.' 136 | value: 137 | name: '&f&l Sort by Value' 138 | description: '&7 Sort all blocks by their value.' 139 | count: 140 | name: '&f&l Sort by Count' 141 | description: '&7 Sort all blocks by their amount.' 142 | value: 143 | name: '&f&l [material]' 144 | description: |- 145 | [description] 146 | [value] 147 | [underwater] 148 | [limit] 149 | [id] 150 | id: '&7 Block id: &e [id]' 151 | value: '&7 Hodnota bloku: &e [number]' 152 | underwater: '&7 Hladina moře Bellow: &e [number]' 153 | limit: '&7 Limit bloku: &e [number]' 154 | previous: 155 | name: Předchozí stránka 156 | description: '&7 Přepněte na stránku [number]' 157 | next: 158 | name: Další stránka 159 | description: '&7 Přepněte na stránku [number]' 160 | search: 161 | name: Vyhledávání 162 | description: |- 163 | &7 Hledejte konkrétní 164 | &7 hodnota. 165 | search: '&b Hodnota: [value]' 166 | tips: 167 | click-to-view: '&e Kliknutím zobrazíte.' 168 | click-to-previous: '&e Kliknutím zobrazíte předchozí stránku.' 169 | click-to-next: '&e Kliknutím zobrazíte další stránku.' 170 | click-to-select: '&e Kliknutím vyberte.' 171 | left-click-to-cycle-up: '&e Levé kliknutí na cyklus nahoru.' 172 | right-click-to-cycle-down: '&e Kliknutím pravým tlačítkem je cyklujte dolů.' 173 | left-click-to-change: '&e Levý kliknutí upravte.' 174 | right-click-to-clear: '&e Kliknutím pravým tlačítkem vymažte.' 175 | click-to-asc: '&e Kliknutím třídíte v zvyšování pořadí.' 176 | click-to-desc: '&e Kliknutím třídíte v klesajícím pořadí.' 177 | click-to-warp: '&e Klikněte na warp.' 178 | click-to-visit: '&e Kliknutím navštívíte.' 179 | right-click-to-visit: '&e Kliknutím na návštěvu.' 180 | conversations: 181 | prefix: '&l&6 [BentoBox]: &r' 182 | no-data: '&c Spusťte úroveň a zobrazí se zpráva o bloku.' 183 | cancel-string: zrušit 184 | exit-string: zrušit, ukončit, přestat 185 | write-search: '&e Zadejte hodnotu vyhledávání. (Napište „zrušit“ do ukončení)' 186 | search-updated: Aktualizována hodnota vyhledávání. 187 | cancelled: '&c Konverzace zrušena!' 188 | no-value: '&c Tato položka nemá žádnou hodnotu.' 189 | unknown-item: '&c „[material]“ ve hře neexistuje.' 190 | value: '&7 Hodnota „[material]“ je: &e [value]' 191 | value-underwater: '&7 Hodnota [material] ''pod hladinou moře: &e [value]' 192 | empty-hand: '&c V ruce nejsou žádné bloky' 193 | you-have: '&7 Máte [number] na posledním počtu.' 194 | you-can-place: '&7 Můžete umístit až [number] a nechat je počítat' 195 | -------------------------------------------------------------------------------- /src/main/resources/locales/de.yml: -------------------------------------------------------------------------------- 1 | --- 2 | admin: 3 | level: 4 | parameters: "" 5 | description: Berechne das Insel Level für den Spieler 6 | levelstatus: 7 | islands-in-queue: "&aInseln in der Warteschlange: [number]" 8 | top: 9 | description: Zeige die Top-10 Liste 10 | unknown-world: "&cUnbekannte Welt!" 11 | display: "&f[rank]. &a[name] &7- &b[level]" 12 | remove: 13 | description: entferne Spieler von Top-10 14 | parameters: "" 15 | island: 16 | level: 17 | parameters: "[Spieler]" 18 | description: Berechne dein Insel Level oder zeige das Level von [Spieler] 19 | calculating: "&aBerechne Level..." 20 | estimated-wait: "&aGeschätzte Wartezeit: [number] Sekunden" 21 | in-queue: "&aSie sind Nummer [number] in der Warteschlange" 22 | island-level-is: "&aInsel Level: &b[level]" 23 | required-points-to-next-level: "&a[points] Punkte werden für das nächste Level 24 | benötigt" 25 | deaths: "&c([number] Tode)" 26 | cooldown: "&cDu musst &b[time] &csekunden warten bevor du das erneut machen kannst." 27 | top: 28 | description: Zeige die Top-10 29 | gui-title: "&aTop Zehn" 30 | gui-heading: "&6[name]: &B[rank]" 31 | island-level: "&BLevel [level]" 32 | warp-to: "&aTeleportiere zu [name]'s Insel" 33 | level-details: 34 | above-sea-level-blocks: Blöcke über dem Meeresspiegel 35 | spawners: Spawner 36 | underwater-blocks: Unterwasserblöcke 37 | all-blocks: Alle Blöcke 38 | no-island: "&cKeine Insel!" 39 | value: 40 | description: Zeige den Wert jedes Blockes 41 | success: "&7Wert: &e[value]" 42 | success-underwater: "&7Wert des Blockes Unterwasser: &e[value]" 43 | empty-hand: "&cDu hast keinen Block in der Hand" 44 | no-value: "&cDas Item hat kein wert!" 45 | -------------------------------------------------------------------------------- /src/main/resources/locales/es.yml: -------------------------------------------------------------------------------- 1 | --- 2 | admin: 3 | level: 4 | parameters: "" 5 | description: Calcula el nivel de la isla del jugador 6 | sethandicap: 7 | parameters: " " 8 | description: Define la desventaja de la isla, usualmente el nivel inicial para 9 | nuevas islas 10 | changed: "&aDesventaja inicial de la isla cambiado de [number] a [new_number]." 11 | invalid-level: "&cNúmero no válido. Usa un número entero." 12 | levelstatus: 13 | description: Muestra cuantas islas hay en la cola para escanear 14 | islands-in-queue: "&aIslas en cola: [number]" 15 | top: 16 | description: Muestra la lista de las diez primeras islas 17 | unknown-world: "&c¡Mundo desconocido!" 18 | display: "&f[rank]. &a[name] &7- &b[level]" 19 | remove: 20 | description: Elimina a un jugador de los diez primeros 21 | parameters: "" 22 | island: 23 | level: 24 | parameters: "[player]" 25 | description: Calcula tu nivel de isla o muestra el nivel de [player] 26 | calculating: "&aCalculando nivel..." 27 | estimated-wait: "&aEspera estimada: [number] segundos" 28 | in-queue: "&aEstás en el puesto [number] de la cola" 29 | island-level-is: "&aNivel de isla es de &b[level]" 30 | required-points-to-next-level: "&a[points] Puntos requeridos hasta el siguiente 31 | nivel." 32 | deaths: "&c([number] Muertes)" 33 | cooldown: "&cDebes esperar &b[time] &csegundos para poder volver a hacer esto." 34 | in-progress: "&6El Calculo del nivel de la islas está en progreso..." 35 | time-out: "&cEl calculo del nivel de la isla está tardando. Intente más tarde." 36 | top: 37 | description: Muestra el top de islas 38 | gui-title: "&aTop diez" 39 | gui-heading: "&6[name]: &b[rank]" 40 | island-level: "&bNivel [level]" 41 | warp-to: "&aLlevándote a la isla de [name]" 42 | level-details: 43 | above-sea-level-blocks: Bloques sobre el nivel del mar 44 | spawners: Spawners 45 | underwater-blocks: Bloques debajo del nivel del mar 46 | all-blocks: Todos los bloques 47 | no-island: "&c¡Sin isla!" 48 | names-island: Isla de [name] 49 | syntax: "[name] x [number]" 50 | hint: "&cEscriba /level para ver el recuento de bloques" 51 | level: 52 | commands: 53 | value: 54 | parameters: "[hand|]" 55 | description: muestra el valor de los bloques. Añade 'hand' al final para mostrar 56 | el valor del bloque de la mano. 57 | gui: 58 | titles: 59 | top: "&0&lTop de islas" 60 | detail-panel: "&0&lIsla de [name]" 61 | value-panel: "&0&l Valores de los Bloques" 62 | buttons: 63 | island: 64 | empty: "&f&l[name]. lugar" 65 | name: "&f&l[name]" 66 | description: |- 67 | [owner] 68 | [members] 69 | [place] 70 | [level] 71 | owners-island: Isla de [player] 72 | owner: "&7&l Dueño: &r&b[player]" 73 | members-title: "&7&l Miembros:" 74 | member: "&b - [player]" 75 | unknown: " desconocido" 76 | place: "&7&o [number]. &r&7lugar" 77 | level: "&7 Nivel: &o[number]" 78 | material: 79 | name: "&f&l[number] x [material]" 80 | description: |- 81 | [description] 82 | [count] 83 | [value] 84 | [calculated] 85 | [limit] 86 | [id] 87 | id: "&7 ID del bloque: &e[id]" 88 | value: "&7 Valor del bloque: &e[number]" 89 | limit: "&7 Limite de bloques: &e[number]" 90 | count: "&7 Número de bloques: &e[number]" 91 | calculated: "&7 Valor calculado: &e[number]" 92 | all_blocks: 93 | name: "&f&lTodos los bloques" 94 | description: |- 95 | &7 Muestra todos los 96 | &7 bloques en la isla. 97 | above_sea_level: 98 | name: "&f&lBloques sobre el nivel del mar" 99 | description: |- 100 | &7 Muestra solo bloques 101 | &7 que estén sobre el 102 | &7 nivel del mar. 103 | underwater: 104 | name: "&f&lBloques debajo del nivel del mar" 105 | description: |- 106 | &7 Muestra solo bloques 107 | &7 que estén debajo del 108 | &7 nivel del mar. 109 | spawner: 110 | name: "&f&lSpawners" 111 | description: "&7Mostrar solo spawners." 112 | filters: 113 | name: 114 | name: "&f&lOrdenar por nombre" 115 | description: "&7Ordenar todos los bloques por nombre." 116 | value: 117 | name: "&f&lOrdenar por valor" 118 | description: "&7Ordenar todos los bloques por valor." 119 | count: 120 | name: "&f&lOrdenar por cantidad" 121 | description: "&7Ordenar todos los bloques por cantidad." 122 | value: 123 | name: "&f&l [material]" 124 | description: |- 125 | [description] 126 | [value] 127 | [underwater] 128 | [limit] 129 | [id] 130 | id: "&7 ID de Bloque: &e [id]" 131 | value: "&7 Valor del Bloque: &e [number]" 132 | underwater: "&7 Por debajo del nivel del mar: &e [number]" 133 | limit: "&7 Límite de bloque: &e [number]" 134 | previous: 135 | name: "&f&lPágina anterior" 136 | description: "&7Cambiar a la página [number]" 137 | next: 138 | name: "&f&lSiguiente página" 139 | description: "&7Cambiar a la página [number]" 140 | search: 141 | name: "&f&l Buscar" 142 | description: |- 143 | &7 Buscar un determinado 144 | &7 valor. 145 | search: "&b Valor: [value]" 146 | tips: 147 | click-to-view: "&eClic &7para ver." 148 | click-to-previous: "&eClic &7 para ir a la página anterior." 149 | click-to-next: "&eClic &7 para ir a la siguiente página." 150 | click-to-select: "&eClic &7 para seleccionar." 151 | left-click-to-cycle-up: "&eClic izquierdo &7para ir hacia arriba." 152 | right-click-to-cycle-down: "&eClic derecho &7para ir hacia abajo." 153 | left-click-to-change: "&e Clic Izquierdo &7 para editar." 154 | right-click-to-clear: "&e Clic Derecho &7 para borrar." 155 | click-to-asc: "&e Clic &7 para ordenar de forma creciente." 156 | click-to-desc: "&e Clic &7 para ordenar de forma decreciente." 157 | click-to-warp: "&e Clic &7 para teletransportarse." 158 | click-to-visit: "&e Clic &7 para visitar." 159 | right-click-to-visit: "&e Clic Derecho &7 para visitar." 160 | conversations: 161 | prefix: "&l&6[BentoBox]: &r" 162 | no-data: "&cEscriba /level para ver el recuento de bloques." 163 | cancel-string: cancelar 164 | exit-string: cancelar, salir, abandonar 165 | write-search: "&e Introduce un valor de búsqueda. (Escribe 'cancel' para salir)" 166 | search-updated: "&a Valor de búsqueda actualizado." 167 | cancelled: "&c ¡Conversación cancelada!" 168 | no-value: "&c Ese ítem no tiene valor." 169 | unknown-item: "&c El '[material]' no existe en el juego." 170 | value: "&7 El valor de '[material]' es: &e[value]" 171 | value-underwater: "&7 El valor de '[material]' por debajo del nivel del mar: &e[value]" 172 | empty-hand: "&c No hay bloques en tu mano" 173 | -------------------------------------------------------------------------------- /src/main/resources/locales/fr.yml: -------------------------------------------------------------------------------- 1 | --- 2 | admin: 3 | level: 4 | parameters: "" 5 | description: calcule le niveau d'île d'un joueur 6 | sethandicap: 7 | parameters: " " 8 | description: définir le handicap de l'île, généralement le niveau de l'île de 9 | départ 10 | changed: "&a le handicap initial de l'île est passé de [number] à [new_number]." 11 | invalid-level: "&c Handicap non valide. Utilisez un nombre entier." 12 | levelstatus: 13 | description: affiche le nombre d'îles dans la file d'attente pour l'analyse 14 | islands-in-queue: "&a Nombre d'Îles dans la file d'attente: [number]" 15 | top: 16 | description: affiche le top 10 des îles 17 | unknown-world: "&cMonde inconnu." 18 | display: "&f[rank]. &a[name] &7- &b[level]" 19 | remove: 20 | description: retire le joueur du top 10 21 | parameters: "" 22 | island: 23 | level: 24 | parameters: "[joueur]" 25 | description: calcule le niveau de votre île ou affiche le niveau d'un [joueur] 26 | calculating: "&aCalcul du niveau en cours..." 27 | estimated-wait: "&a Attente estimée: [number] seconds" 28 | in-queue: "&a Vous êtes le numéro [number ] dans la file d'attente" 29 | island-level-is: "&aLe niveau d'île est &b[level]" 30 | required-points-to-next-level: "&a[points] points avant le prochain niveau" 31 | deaths: "&c([number] morts)" 32 | cooldown: "&cVous devez attendre &b[time] &csecondes avant de pouvoir refaire 33 | cette action" 34 | in-progress: "&6 Le calcul du niveau de l'île est en cours ..." 35 | time-out: "&c Le calcul du niveau a pris trop de temps. Veuillez réessayer plus 36 | tard." 37 | top: 38 | description: affiche le top 10 39 | gui-title: "&aTop 10" 40 | gui-heading: "&6[name]: &B[rank]" 41 | island-level: "&BNiveau [level]" 42 | warp-to: "&ATéléportation vers l'île de [name]" 43 | level-details: 44 | above-sea-level-blocks: Blocs au-dessus du niveau de la mer 45 | spawners: Spawners 46 | underwater-blocks: Blocs en-dessous du niveau de la mer 47 | all-blocks: Total des blocs 48 | no-island: "&c Pas d'île!" 49 | names-island: île de [name] 50 | syntax: "[name] x [number]" 51 | hint: "&c Exécuter level pour voir le rapport des blocs" 52 | level: 53 | commands: 54 | value: 55 | parameters: "[hand|]" 56 | description: affiche la valeur des blocs. Ajoutez 'hand' à la fin pour afficher 57 | la valeur de l'objet en main. 58 | gui: 59 | titles: 60 | top: "&0&l Top Islands" 61 | detail-panel: "&0&l [name]'s island" 62 | value-panel: "&0&l Block Values" 63 | buttons: 64 | island: 65 | empty: "&f&l [name]. place" 66 | name: "&f&l [name]" 67 | description: |- 68 | [owner] 69 | [members] 70 | [place] 71 | [level] 72 | owners-island: "[player]'s Island" 73 | owner: "&7&l Propriétaire: &r&b [player]" 74 | members-title: "&7&l Membres:" 75 | member: "&b - [player]" 76 | unknown: inconnue 77 | place: "&7&o [number]. &r&7 place" 78 | level: "&7 Level: &o [number]" 79 | material: 80 | name: "&f&l [number] x [material]" 81 | description: |- 82 | [description] 83 | [count] 84 | [value] 85 | [calculated] 86 | [limit] 87 | [id] 88 | id: "&7 Block id: &e [id]" 89 | value: "&7 Block value: &e [number]" 90 | limit: "&7 Block limit: &e [number]" 91 | count: "&7 Nombre de blocs: &e [number]" 92 | calculated: "&7 Valeur calculée: &e [number]" 93 | all_blocks: 94 | name: "&f&l Tous les blocs" 95 | description: |- 96 | &7 Afficher tous les blocs 97 | &7 sur l'île. 98 | above_sea_level: 99 | name: "&f&l Blocs au-dessus du niveau de la mer" 100 | description: |- 101 | &7 Afficher uniquement les blocs 102 | &7 qui sont au-dessus du niveau 103 | &7 de la mer. 104 | underwater: 105 | name: "&f&l Blocs sous le niveau de la mer" 106 | description: |- 107 | &7 Afficher uniquement les blocs 108 | &7 situés sous le niveau 109 | &7 de la mer. 110 | spawner: 111 | name: "&f&l Spawners" 112 | description: "&7 Afficher uniquement les spawners." 113 | filters: 114 | name: 115 | name: "&f&l STrier par nom" 116 | description: "&7 Trier tous les blocs par nom." 117 | value: 118 | name: "&f&l Trier par valeur" 119 | description: "&7 Triez tous les blocs par leur valeur." 120 | count: 121 | name: "&f&l Trier par nombre" 122 | description: "&7 Trier tous les blocs par leur montant." 123 | value: 124 | name: "&f&l [material]" 125 | description: |- 126 | [description] 127 | [value] 128 | [underwater] 129 | [limit] 130 | [id] 131 | id: "&7 Block id: &e [id]" 132 | value: "&7 Block value: &e [number]" 133 | underwater: "&7 Sous le niveau de la mer : &e [number]" 134 | limit: "&7 Block limit: &e [number]" 135 | previous: 136 | name: "&f&l Page précédente" 137 | description: "&7 Passer à la page [number]" 138 | next: 139 | name: "&f&l Page suivante" 140 | description: "&7 Passer à la page [number]" 141 | search: 142 | name: "&f&l Rechercher" 143 | description: "&7 Recherche une valeur \n&7 spécifique." 144 | search: "&b Valeur : [value]" 145 | tips: 146 | click-to-view: "&e Cliquez &7 pour afficher." 147 | click-to-previous: "&e Cliquez &7 pour afficher la page précédente." 148 | click-to-next: "&e Cliquez &7 pour afficher la page suivante." 149 | click-to-select: "&e Cliquez &7 pour sélectionner." 150 | left-click-to-cycle-up: "&e Clic gauche &7 pour monter." 151 | right-click-to-cycle-down: "&e Clic droit &7 pour descendre." 152 | left-click-to-change: "&e Clic gauche &7 pour éditer." 153 | right-click-to-clear: "&e Clic droit &7 pour effacer." 154 | click-to-asc: "&e Cliquez &7 pour trier par ordre croissant." 155 | click-to-desc: "&e Cliquez &7 pour trier par ordre décroissant." 156 | click-to-warp: "&e Cliquer &7 to warp." 157 | click-to-visit: "&e Cliquer &7 pour visiter." 158 | right-click-to-visit: "&e Clic droit&7 pour visiter." 159 | conversations: 160 | prefix: "&l&6 [BentoBox]: &r" 161 | no-data: "&c Niveau d'exécution pour voir le rapport de blocage." 162 | cancel-string: annuler 163 | exit-string: annuler, sortir, quitter 164 | write-search: "&e Veuillez entrer une valeur de recherche. (Ecrivez 'cancel' pour 165 | quitter)" 166 | search-updated: "&a Valeur de recherche mise à jour." 167 | cancelled: "&c Conversation annulée !" 168 | no-value: "&c Cet item n'a aucune valeur." 169 | unknown-item: "&c Le '[material]' n'existe pas dans le jeu." 170 | value: "&7 La valeur de '[material]' est : &e[value]" 171 | value-underwater: "&7 La valeur de '[material]' sous le niveau de la mer : &e[value]" 172 | empty-hand: "&c Il n'y a pas de blocs dans votre main" 173 | meta: 174 | authors: 175 | '0': plagoutte 176 | -------------------------------------------------------------------------------- /src/main/resources/locales/hu.yml: -------------------------------------------------------------------------------- 1 | --- 2 | admin: 3 | level: 4 | parameters: "" 5 | description: Egy játékos sziget szintjének kiszámítása 6 | sethandicap: 7 | parameters: " " 8 | description: állítsa be a sziget hátrányát, általában a kezdő sziget szintjét 9 | changed: "&a A kezdeti sziget hátrány változott erről [number] erre [new_number]." 10 | invalid-level: "&c Érvénytelen hátrány. Használj egész számot." 11 | levelstatus: 12 | description: megmutatja, hogy hány sziget van a szkennelési sorban 13 | islands-in-queue: "&a Szigetek a sorban: [number]" 14 | top: 15 | description: Top Tíz lista megtekintése 16 | unknown-world: "&cIsmeretlen világ!" 17 | display: "&f[rank]. &a[name] &7- &b[level]" 18 | remove: 19 | description: játékos törlése a Top Tízből 20 | parameters: "" 21 | island: 22 | level: 23 | parameters: "[player]" 24 | description: A saját vagy más játékos sziget szintjének kiszámítása 25 | calculating: "&aSziget szint kiszámítása..." 26 | estimated-wait: "&a Becsült várakozás: [number] másodperc" 27 | in-queue: "&a Te vagy a(z) [number] a sorban" 28 | island-level-is: "&aA sziget szint: &b[level]" 29 | required-points-to-next-level: "&a[points] pont szükséges a következő szinthez." 30 | deaths: "&c([number] halál)" 31 | cooldown: "&cVárnod kell &b[time] &cmásodpercet, hogy újra használhasd." 32 | top: 33 | description: Top Tíz lista megtekintése 34 | gui-title: "&aTop Tíz" 35 | gui-heading: "&6[name]: &B[rank]" 36 | island-level: "&BLevel [level]" 37 | warp-to: "&ATeleportálás [name] szigetére." 38 | remove: 39 | description: játékos törlése a Top Tízből 40 | parameters: "" 41 | level-details: 42 | above-sea-level-blocks: Tengerszint Feletti Blokkok 43 | spawners: Spawner-ek 44 | underwater-blocks: Víz Alatti Blokkok 45 | all-blocks: Minden Blokk 46 | no-island: "&c Nincs sziget!" 47 | names-island: "[name] szigete" 48 | syntax: "[name] x [number]" 49 | hint: "&c Futtassa a szintet a blokk jelentés megjelenítéséhez" 50 | value: 51 | description: Bármely blokk értékét mutatja 52 | success: "&7Ennek a blokknak az értéke: &e[value]" 53 | success-underwater: "&7Ennek a blokknak a tengerszint alatti értéke: &e[value]" 54 | empty-hand: "&cNincsenek blokkok a kezedben" 55 | no-value: "&cEnnek nincs értéke." 56 | -------------------------------------------------------------------------------- /src/main/resources/locales/id.yml: -------------------------------------------------------------------------------- 1 | --- 2 | admin: 3 | level: 4 | parameters: "" 5 | description: hitung level pulau untuk pemain 6 | sethandicap: 7 | parameters: " " 8 | description: mengatur handicap pulau, biasanya level pulau pemula 9 | changed: "&a Handicap pulau awal diubah dari [number] menjadi [new_number]." 10 | invalid-level: "&c Handicap tidak valid. Gunakan angka bulat." 11 | levelstatus: 12 | description: menunjukkan berapa banyak pulau dalam antrian untuk pemindaian 13 | islands-in-queue: "&a Pulau di dalam antrian: [number]" 14 | top: 15 | description: menunjukkan daftar sepuluh besar 16 | unknown-world: "&c Dunia tidak ditemukan!" 17 | display: "&f[rank]. &a[name] &7- &b[level]" 18 | remove: 19 | description: menghapus pemain dari sepuluh besar 20 | parameters: "" 21 | island: 22 | level: 23 | parameters: "[player]" 24 | description: hitung level pulau kamu atau melihat level [player] 25 | calculating: "&a Menghitung level..." 26 | estimated-wait: "&a Perkiraan menunggu: [number] detik" 27 | in-queue: "&a Kamu berada pada antrian nomor [number]" 28 | island-level-is: "&a Level pulau adalah &b[level]" 29 | required-points-to-next-level: "&a [points] poin dibutuhkan hingga level selanjutnya" 30 | deaths: "&c([number] kematian)" 31 | cooldown: "&c Kamu harus menunggu &b[time] &c detik sebelum kamu dapat melakukannya 32 | lagi" 33 | in-progress: "&6 Perhitungan level pulau sedang dijalankan..." 34 | time-out: "&c Perhitungan level pulau terlalu lama. Coba lagi nanti." 35 | top: 36 | description: menunjukkan Sepuluh Besar 37 | gui-title: "&a Sepuluh Besar" 38 | gui-heading: "&6[name]: &B[rank]" 39 | island-level: "&b Level [level]" 40 | warp-to: "&A Warp ke pulau [name]" 41 | level-details: 42 | above-sea-level-blocks: Blok di atas permukaan laut 43 | spawners: Spawner 44 | underwater-blocks: Blok di bawah permukaan laut 45 | all-blocks: Semua blok 46 | no-island: "&c Tidak ada pulau!" 47 | names-island: Pulau [name] 48 | syntax: "[name] x [number]" 49 | hint: "&c Jalankan perintah level untuk melihat laporan blok" 50 | level: 51 | commands: 52 | value: 53 | parameters: "[hand|]" 54 | description: menunjukkan nilai blok. Tambah 'hand' di akhir untuk menjukkan 55 | nilai item di tangan. 56 | gui: 57 | titles: 58 | top: "&0&l Pulau Terbaik" 59 | detail-panel: "&0&l Pulau [name]" 60 | value-panel: "&0&l Nilai Blok" 61 | buttons: 62 | island: 63 | empty: "&f&l [name]. place" 64 | name: "&f&l [name]" 65 | description: |- 66 | [owner] 67 | [members] 68 | [place] 69 | [level] 70 | owners-island: Pulau [player] 71 | owner: "&7&l Pemilik: &r&b [player]" 72 | members-title: "&7&l Anggota:" 73 | member: "&b - [player]" 74 | unknown: tidak diketahui 75 | place: "&r&7Peringkat &7&o [number]." 76 | level: "&7 Level: &o [number]" 77 | material: 78 | name: "&f&l [number] x [material]" 79 | description: |- 80 | [description] 81 | [count] 82 | [value] 83 | [calculated] 84 | [limit] 85 | [id] 86 | id: "&7 Id blok: &e [id]" 87 | value: "&7 Nilai blok: &e [number]" 88 | limit: "&7 Batas blok: &e [number]" 89 | count: "&7 Jumlah blok: &e [number]" 90 | calculated: "&7 Nilai yang dihitung: &e [number]" 91 | all_blocks: 92 | name: "&f&l Semua blok" 93 | description: |- 94 | &7 Tampilkan semua blok 95 | &7 di pulau. 96 | above_sea_level: 97 | name: "&f&l Blok Diatas Permukaan Laut" 98 | description: |- 99 | &7 Hanya mengampilkan blok 100 | &7 yang berada di atas 101 | &7 permukaan laut. 102 | underwater: 103 | name: "&f&l Blok Di bawah Permukaan Laut" 104 | description: |- 105 | &7 Hanya menampilkan blok 106 | &7 yang berada di bawah 107 | &7 permukaan laut. 108 | spawner: 109 | name: "&f&l Spawner" 110 | description: "&7 Hanya tampilkan spawner." 111 | filters: 112 | name: 113 | name: "&f&l Urut berdasarkan Nama" 114 | description: "&7 Mengurutkan semua blok berdasarkan nama." 115 | value: 116 | name: "&f&l Urut berdasarkan Nilai" 117 | description: "&7 Mengurutkan semua blok berdasarkan nilainya." 118 | count: 119 | name: "&f&l Urut berdasarkan Jumlah" 120 | description: "&7 Mengurutkan semua blok berdasarkan jumlahnya." 121 | value: 122 | name: "&f&l [material]" 123 | description: |- 124 | [description] 125 | [value] 126 | [underwater] 127 | [limit] 128 | [id] 129 | id: "&7 Id blok: &e [id]" 130 | value: "&7 Nilai blok: &e [number]" 131 | underwater: "&7 Dibawah permukaan laut: &e [number]" 132 | limit: "&7 Batas block: &e [number]" 133 | previous: 134 | name: "&f&l Halaman sebelumnya" 135 | description: "&7 Beralih ke halaman [number]" 136 | next: 137 | name: "&f&l Halaman selanjutnya" 138 | description: "&7 Beralih ke halaman [number]" 139 | search: 140 | name: "&f&l Cari" 141 | description: |- 142 | &7 Mencari nilai yang 143 | &7 spesifik. 144 | search: "&b Nilai: [value]" 145 | tips: 146 | click-to-view: "&e Klik &7 untuk melihat." 147 | click-to-previous: "&e Klik &7 untuk melihat halaman sebelumnya." 148 | click-to-next: "&e Klik &7 untuk melihat halaman selanjutnya." 149 | click-to-select: "&e Klik &7 untuk memilih." 150 | left-click-to-cycle-up: "&e Klik Kiri &7 untuk memutar ke atas." 151 | right-click-to-cycle-down: "&e Klik Kanan &7 memutar ke bawah." 152 | left-click-to-change: "&e Klik Kiri &7 untuk mengubah." 153 | right-click-to-clear: "&e Klik Kanan &7 untuk membersihkan." 154 | click-to-asc: "&e Klik &7 untuk mengurutkan dalam urutan menaik." 155 | click-to-desc: "&e Klik &7 untuk mengurutkan dalam urutan menurun." 156 | click-to-warp: "&e Klik &7 untuk warp." 157 | click-to-visit: "&e Klik &7 untuk mengunjungi." 158 | right-click-to-visit: "&e Klik Kanan &7 untuk mengunjungi." 159 | conversations: 160 | prefix: "&l&6 [BentoBox]: &r" 161 | no-data: "&c Jalankan perintah level untuk melihat laporan blok" 162 | cancel-string: batal 163 | exit-string: batal, keluar, berhenti 164 | write-search: "&e Tolong masukkan pencarian nilai. (Ketik 'batal' untuk keluar)" 165 | search-updated: "&a Nilai pencarian diperbarui." 166 | cancelled: "&c Percakapan dibatalkan!" 167 | no-value: "&c Item itu tidak ada nilai." 168 | unknown-item: "&c '[material]' tidak ada di dalam permainan." 169 | value: "&7 Nilai dari '[material]' adalah: &e[value]" 170 | value-underwater: "&7Nilai dari '[material]' di bawah permukaan laut: &e[value]" 171 | empty-hand: "&c Tidak ada blok di tangan mu" 172 | -------------------------------------------------------------------------------- /src/main/resources/locales/ko.yml: -------------------------------------------------------------------------------- 1 | --- 2 | admin: 3 | level: 4 | parameters: "" 5 | description: 플레이어의 섬레벨을 계산합니다 6 | sethandicap: 7 | parameters: "<플레이어> <핸디캡>" 8 | description: 섬 핸디캡을 설정하십시오. 일반적으로 시작 섬의 레벨 9 | changed: "& a 초기 아일랜드 핸디캡이 [번호]에서 [new_number] (으)로 변경되었습니다." 10 | invalid-level: "& c 잘못된 핸디캡. 정수를 사용하십시오." 11 | levelstatus: 12 | description: 스캔 대기열에 몇 개의 섬이 있는지 표시 13 | islands-in-queue: "& a 대기열에있는 섬 : [번호]" 14 | top: 15 | unknown-world: "& c 알수없는 월드 입니다" 16 | display: "&f[rank]. &a[name] &7-&b[level]" 17 | remove: 18 | description: 탑 10에서 플레이어를 제거합니다 19 | parameters: "<플레이어>" 20 | island: 21 | level: 22 | parameters: "[플레이어]" 23 | description: 섬 레벨을 계산하거나 [플레이어]의 섬레벨을 보여줍니다 24 | calculating: "&a 계산중....\n" 25 | estimated-wait: "&a예상 대기 시간 : [번호] 초" 26 | in-queue: "& a 당신은 대기열에있는 숫자 [번호]입니다" 27 | island-level-is: "& a 섬 레벨은 & b [level]" 28 | required-points-to-next-level: "&a [point] 다음 레벨까지 요구되는 경험치" 29 | deaths: "&c ([number] 사망)" 30 | cooldown: "&c그것을 다시하려면 &b[time]초&c를 기다려야합니다." 31 | top: 32 | description: 탑 10을 보여줍니다 33 | gui-title: "&a 탑 10" 34 | gui-heading: "&6 [name] : &B[rank]" 35 | island-level: "&b 레벨 [level]" 36 | warp-to: "&a[name]님의 섬으로 이동중입니다.." 37 | level-details: 38 | above-sea-level-blocks: 해발 블록 39 | spawners: 스포너 40 | underwater-blocks: 수중 블록 41 | all-blocks: 모든 블록 42 | no-island: "&c 섬이 없습니다." 43 | names-island: "[name]의 섬" 44 | syntax: "[name] x [number]" 45 | hint: "&c 블록 리포트를 보려면 레벨을 해야합니다." 46 | value: 47 | description: 모든 블록의 값을 보여줍니다 48 | success: "&7이 블록의 값은 &e [value]입니다." 49 | success-underwater: "&7 해수면 아래의 블록 값 : &e [value]" 50 | empty-hand: "& c 손에 블록이 없습니다" 51 | no-value: "&c 해당 항목에는 가치가 없습니다." 52 | -------------------------------------------------------------------------------- /src/main/resources/locales/lv.yml: -------------------------------------------------------------------------------- 1 | --- 2 | admin: 3 | level: 4 | description: aprēķina spēlētāja salas līmeni 5 | parameters: "" 6 | top: 7 | description: rādīt labākās 10 salas 8 | display: "&f[rank]. &a[name] &7- &b[level]" 9 | unknown-world: "&cNezināma pasaule!" 10 | remove: 11 | description: noņemt spēlētāju no labāko desmit saraksta 12 | parameters: "" 13 | island: 14 | level: 15 | calculating: "&aAprēķina līmeni..." 16 | cooldown: "&cTev ir jāuzgaida &b[time]&c sekundes, lai vēlreiz aprēķinātu salas 17 | līmeni!" 18 | deaths: "&c([number] nāves)" 19 | description: aprēķina tavas salas līmeni, vai parāda spēlētāja [player] līmeni 20 | island-level-is: "&aSalas līmenis ir &b[level]" 21 | parameters: "[player]" 22 | required-points-to-next-level: "&aNepieciešami [points] punkti, lai sasniegtu 23 | nākošo līmeni" 24 | top: 25 | description: rādīt labākos 10 26 | gui-heading: "&6[name]: &B[rank]" 27 | gui-title: "&aLabākie 10" 28 | island-level: "&BLīmenis [level]" 29 | warp-to: "&APārvietoties uz [name] salu." 30 | value: 31 | description: rādīt vērtību jebkuram blokam 32 | empty-hand: "&cTev nav bloks rokās." 33 | no-value: "&cŠim blokam/priekšmetam nav vērtības." 34 | success: "&7Vērtība šim blokam ir: &e[value]" 35 | success-underwater: "&7Vērtība šim blokam zem jūras līmeņa: &e[value]" 36 | -------------------------------------------------------------------------------- /src/main/resources/locales/nl.yml: -------------------------------------------------------------------------------- 1 | --- 2 | admin: 3 | level: 4 | parameters: "" 5 | description: bereken het eiland level voor een speler 6 | sethandicap: 7 | parameters: " " 8 | description: stel handicap in voor het eiland, normaal gesproken het level van 9 | het starter eiland. 10 | changed: "&a Initiële handicap is veranderd van [number] naar [new_number]." 11 | invalid-level: "&c Ongeldige handicap. Gebruik een getal." 12 | levelstatus: 13 | description: laat zien hoeveel eilanden er in de wachtrij staan voor het scannen 14 | islands-in-queue: "&a Aantal eilanden in de wachtrij: [number]" 15 | top: 16 | description: Laat de top tien zien 17 | unknown-world: "&c Ongeldige wereld!" 18 | display: "&f[rank]. &a[name] &7- &b[level]" 19 | remove: 20 | description: verwijder speler van de top tien 21 | parameters: "" 22 | island: 23 | level: 24 | parameters: "[speler]" 25 | description: bereken het eiland level voor [player] 26 | calculating: "&a Level aan het berekenen..." 27 | estimated-wait: "&a Verwachtte wachttijd: [number] seconde" 28 | in-queue: "&a Jij staat op plek [number] in de wachtrij" 29 | island-level-is: "&a Eiland level is &b[level]" 30 | required-points-to-next-level: "&a [points] punten nodig voor het volgende level" 31 | deaths: "&c([number] doodgegaan)" 32 | cooldown: "&c Je moet nog &b[time] &c seconden wachten tot je dit weer kan doen." 33 | in-progress: "&6 Eiland level wordt berekend..." 34 | time-out: "&c De level berekening duurde te lang. Probeer het later opnieuw." 35 | top: 36 | description: Toon de Top tien 37 | gui-title: "&a Top tien" 38 | gui-heading: "&6[name]: &B[rank]" 39 | island-level: "&b Level [level]" 40 | warp-to: "&A Teleporteren naar [name]'s eiland" 41 | level-details: 42 | above-sea-level-blocks: 'Blokken boven zeeniveau ' 43 | spawners: Monsterkooien 44 | underwater-blocks: Blokken onder zeeniveau 45 | all-blocks: Alle blokken 46 | no-island: "&c Geen eiland!" 47 | names-island: "[name]'s eiland" 48 | syntax: "[name] x [number]" 49 | hint: "&c Gebruik level om het blokkenrapport te zien" 50 | level: 51 | commands: 52 | value: 53 | parameters: "[hand|]" 54 | description: toont de waarde van blokken. Voeg 'hand' toe aan het einde om de 55 | waarde te laten zien van het item in je hand. 56 | gui: 57 | titles: 58 | top: "&0&l Top eilanden" 59 | detail-panel: "&0&l [name]'s eiland" 60 | value-panel: "&0&l Blok waardes" 61 | buttons: 62 | island: 63 | empty: "&f&l [name]. plaats" 64 | name: "&f&l [name]" 65 | description: |- 66 | [owner] 67 | [members] 68 | [place] 69 | [level] 70 | owners-island: "[player]'s Eiland" 71 | owner: "&7&l Eigenaar: &r&b [player]" 72 | members-title: "&7&l Leden:" 73 | member: "&b - [player]" 74 | unknown: onbekend 75 | place: "&7&o [number]. &r&7 plaats" 76 | level: "&7 Level: &o [number]" 77 | material: 78 | name: "&f&l [number] x [material]" 79 | description: |- 80 | [description] 81 | [count] 82 | [value] 83 | [calculated] 84 | [limit] 85 | [id] 86 | id: "&7 Blok id: &e [id]" 87 | value: "&7 Block waarde: &e [number]" 88 | limit: "&7 Block limiet: &e [number]" 89 | count: "&7 Aantal blokken: &e [number]" 90 | calculated: "&7 Berekende waarde: &e [number]" 91 | all_blocks: 92 | name: "&f&l Alle Blokken" 93 | description: "&7 Toon alle blokken \n&7 op het eiland." 94 | above_sea_level: 95 | name: "&f&l Blokken boven zeeniveau" 96 | description: |- 97 | &7 Toon alleen blokken 98 | &7 die boven zeeniveau zijn 99 | underwater: 100 | name: "&f&l Blokken onder zeeniveau" 101 | description: |- 102 | &7 Toon alleen blokken 103 | &7 die onder zeeniveau zijn 104 | spawner: 105 | name: "&f&l Monsterkooien" 106 | description: "&7 Toon alleen monsterkooien." 107 | filters: 108 | name: 109 | name: "&f&l Sorteer aan de hand van naam" 110 | description: "&7 Sorteer alle blokken aan de hand van naam." 111 | value: 112 | name: "&f&l Sorteer aan de hand van waarde" 113 | description: "&7 Sorteer alle blokken aan de hand van waarde." 114 | count: 115 | name: "&f&l Sorteer aan de hand van aantal" 116 | description: "&7 Sorteer alle blokken aan de hand van aantal." 117 | value: 118 | name: "&f&l [material]" 119 | description: |- 120 | [description] 121 | [value] 122 | [underwater] 123 | [limit] 124 | [id] 125 | id: "&7 Blok id: &e [id]" 126 | value: "&7 Block waarrde: &e [number]" 127 | underwater: "&7 Onder zeeniveau: &e [number]" 128 | limit: "&7 Blok limiet: &e [number]" 129 | previous: 130 | name: "&f&l Vorige pagina" 131 | description: "&7 Ga naar pagina [number]" 132 | next: 133 | name: "&f&l Volgende pagina" 134 | description: "&7 Ga naar pagina [number]" 135 | search: 136 | name: "&f&l Zoek" 137 | description: "&7 Zoek voor een \n&7 specifieke waarde." 138 | search: "&b Waarde: [value]" 139 | tips: 140 | click-to-view: "&e Klik &7 om te zien." 141 | click-to-previous: "&e Klik &7 om de vorige pagina te zien." 142 | click-to-next: "&e Klik &7 om de volgende pagina te zien." 143 | click-to-select: "&e Klik &7 om te selecteren." 144 | left-click-to-cycle-up: "&e Linker Klik &7 om door te lopen." 145 | right-click-to-cycle-down: "&e Rechter Klik &7 om terug door te lopen." 146 | left-click-to-change: "&e Linker Klik &7 om bij te werken." 147 | right-click-to-clear: "&e Linker Klik &7 om te verwijderen." 148 | click-to-asc: "&e Klik &7 om te toenemend te sorteren." 149 | click-to-desc: "&e Klik &7 om te afnemenend te sorteren." 150 | click-to-warp: "&e Klik &7 om te teleporteren." 151 | click-to-visit: "&e Klik &7 om te bezoeken." 152 | right-click-to-visit: "&e Rechter Klik &7 om te bezoeken." 153 | conversations: 154 | prefix: "&l&6 [BentoBox]: &r" 155 | no-data: "&c Gebruik level om het blokkenrapport te zien." 156 | cancel-string: stop 157 | exit-string: stop 158 | write-search: "&e Schrijf een zoekopdracht. (Schrijf 'stop' om te zoeken)" 159 | search-updated: "&a Zoekopdracht bijgewerkt." 160 | cancelled: "&c Conversatie gestopt!" 161 | no-value: "&c Dit item heeft geen waarde." 162 | unknown-item: "&c '[material]' bestaat niet in het spel." 163 | value: "&7 De waarde van '[material]' is: &e[value]" 164 | value-underwater: "&7 The waarde van '[material]' onder zeeniveau: &e[value]" 165 | empty-hand: "&c Je hebt geen blok vast" 166 | -------------------------------------------------------------------------------- /src/main/resources/locales/pl.yml: -------------------------------------------------------------------------------- 1 | --- 2 | admin: 3 | level: 4 | parameters: "" 5 | description: oblicza poziom wyspy 6 | sethandicap: 7 | parameters: " " 8 | description: ustawić 0 poziom wyspy, zwykle poziom wyspy startowej 9 | changed: "&a Początkowy poziom wysp został zmieniony z [number] na [new_number]." 10 | invalid-level: "&c Nieprawidłowy poziom. Użyj liczby całkowitej." 11 | levelstatus: 12 | description: pokazuje ile wysp znajduje się w kolejce do skanowania 13 | islands-in-queue: "&a Wyspy w kolejce: [number]" 14 | top: 15 | description: pokazuje Top 10 wysp 16 | unknown-world: "&cNieznany świat!" 17 | display: "&f[rank]. &a[name] &7- &b[level]" 18 | remove: 19 | description: usuwa gracza z Top 10 20 | parameters: "" 21 | island: 22 | level: 23 | parameters: "[player]" 24 | description: oblicza poziom wyspy lub pokazać poziom [player] 25 | calculating: "&aObliczanie poziomu wyspy..." 26 | estimated-wait: "&a Szacowany czas: [number] sekund" 27 | in-queue: "&a Jestes numerem [number] w kolejce" 28 | island-level-is: "&aPoziom wyspy wynosi &b[level]" 29 | required-points-to-next-level: "&aPozostało [points] punktów do następnego poziomu" 30 | deaths: "&c([number] śmierci)" 31 | cooldown: "&cMusisz zaczekać &b[time] &csekund przed następnym obliczeniem poziomu" 32 | in-progress: "&6 Trwa obliczanie poziomu twojej wyspy..." 33 | time-out: "&c Sprawdzanie poziomu twojej wyspy trwalo zbyt dlugo. Sprobuj ponownie 34 | pozniej!" 35 | top: 36 | description: pokauje Top 10 wysp 37 | gui-title: "&aTop 10" 38 | gui-heading: "&6[name]: &B[rank]" 39 | island-level: "&BPoziom [level]" 40 | warp-to: "&ATeleportowanie do wyspy [name]" 41 | level-details: 42 | above-sea-level-blocks: Bloki nad poziomem morza 43 | spawners: Spawnery 44 | underwater-blocks: Podwodne bloki 45 | all-blocks: Wszystkie bloki 46 | no-island: "&c Brak wyspy!" 47 | names-island: Wyspa gracza [name] 48 | syntax: "[name] x [number]" 49 | hint: "&c Uruchom poziom, aby wyświetlić raport o blokach" 50 | level: 51 | commands: 52 | value: 53 | parameters: "[hand|]" 54 | description: pokazuje wartość bloków. Dodaj „hand” na końcu, aby wyświetlić 55 | wartość pozycji w ręku. 56 | gui: 57 | titles: 58 | top: "&0&l Najlepsze wyspy" 59 | detail-panel: "&0&l Wyspa gracza [name] " 60 | value-panel: "&0&l Wartości bloków" 61 | buttons: 62 | island: 63 | empty: "&f&l [name]. miejsce" 64 | name: "&f&l [name]" 65 | description: |- 66 | [owner] 67 | [members] 68 | [place] 69 | [level] 70 | owners-island: wyspa gracza [player] 71 | owner: "&7&l Lider: &r&b [player]" 72 | members-title: "&7&l Członkowie:" 73 | member: "&b - [player]" 74 | unknown: nieznany 75 | place: "&7&o [number]. &r&7 miejsce" 76 | level: "&7 Poziom: &o [number]" 77 | material: 78 | name: "&f&l [number] x [material]" 79 | description: |- 80 | [description] 81 | [count] 82 | [value] 83 | [calculated] 84 | [limit] 85 | [id] 86 | id: "&7 Identyfikator bloku: &e [id]" 87 | value: "&7 Wartość bloku: &e [number]" 88 | limit: "&7 Limit bloków: &e [number]" 89 | count: "&7 Numer bloku: &e [number]" 90 | calculated: "&7 Obliczona wartość: &e [number]" 91 | all_blocks: 92 | name: "&f&l Wszystkie bloki" 93 | description: |- 94 | &7 Wyświetl wszystkie bloki 95 | &7 na wyspie. 96 | above_sea_level: 97 | name: "&f&l Bloki nad poziomem morza" 98 | description: |- 99 | &7 Wyświetlaj tylko bloki 100 | &7 które są nad poziomem 101 | &7 morza 102 | underwater: 103 | name: "&f&l Bloki pod poziomem morza" 104 | description: |- 105 | &7 Wyświetlaj tylko bloki 106 | &7 ponad poziomem morza 107 | spawner: 108 | name: "&f&l Spawnery" 109 | description: "&7 Wyświetlaj tylko spawnery." 110 | filters: 111 | name: 112 | name: "&f&l Sortuj według nazwy" 113 | description: "&7 Sortuj wszystkie bloki według nazwy." 114 | value: 115 | name: "&f&l Sortuj według wartości" 116 | description: "&7 Sortuj wszystkie bloki według ich wartości." 117 | count: 118 | name: "&f&l Sortuj według liczby" 119 | description: "&7 Sortuj wszystkie bloki według ich ilości." 120 | value: 121 | name: "&f&l [material]" 122 | description: |- 123 | [description] 124 | [value] 125 | [underwater] 126 | [limit] 127 | [id] 128 | id: "&7 Identyfikator bloku: &e [id]" 129 | value: "&7 Wartość bloku: &e [number]" 130 | underwater: "&7 Poniżej poziomu morza: &e [number]" 131 | limit: "&7 Limit bloku: &e [number]" 132 | previous: 133 | name: "&f&l Poprzednia strona" 134 | description: "&7 Przełącz na stronę [number]" 135 | next: 136 | name: "&f&l Następna strona" 137 | description: "&7 Przełącz na stronę [number]" 138 | search: 139 | name: "&f&l Szukaj" 140 | description: |- 141 | &7 Wyszukaj konkretną 142 | &7 wartość. 143 | search: "&b Wartość: [value]" 144 | tips: 145 | click-to-view: "&e Kliknij &7, aby wyświetlić." 146 | click-to-previous: "&e Kliknij &7, aby wyświetlić poprzednią stronę." 147 | click-to-next: "&e Kliknij &7, aby wyświetlić następną stronę." 148 | click-to-select: "&e Kliknij &7, aby wybrać." 149 | left-click-to-cycle-up: "&e Kliknij lewym przyciskiem &7, aby przejść w górę." 150 | right-click-to-cycle-down: "&e Kliknij prawym przyciskiem &7, aby przejść w 151 | dół." 152 | left-click-to-change: "&e Kliknij lewym przyciskiem &7, aby edytować." 153 | right-click-to-clear: "&e Kliknij prawym przyciskiem &7, aby wyczyścić." 154 | click-to-asc: "&e Kliknij &7, aby posortować w porządku rosnącym." 155 | click-to-desc: "&e Kliknij &7, aby posortować w porządku malejącym." 156 | click-to-warp: "&e Kliknij&7, aby przenieść" 157 | click-to-visit: "&e Kliknij&7, aby odwiedzić" 158 | right-click-to-visit: "&e Kliknij prawym przyciskiem &7, aby odwiedzić." 159 | conversations: 160 | prefix: "&l&6 [BentoBox]: &r" 161 | no-data: "&c Wykonaj sprawdzenie poziomu, przed raportem bloków" 162 | cancel-string: anuluj 163 | exit-string: cancel, exit, quit, anuluj 164 | write-search: "&e Wprowadź wartość wyszukiwania. (Napisz „anuluj”, aby wyjść)" 165 | search-updated: "&a Zaktualizowano wartość wyszukiwania." 166 | cancelled: "&c Rozmowa została anulowana!" 167 | no-value: "&c Ten element nie ma wartości." 168 | unknown-item: "&c „[material]” nie istnieje w grze." 169 | value: "&7 Wartość '[material]' to: &e[value]" 170 | value-underwater: "&7 Wartość „[material]” poniżej poziomu morza: &e[value]" 171 | empty-hand: "&c W twojej ręce nie ma bloków" 172 | -------------------------------------------------------------------------------- /src/main/resources/locales/pt.yml: -------------------------------------------------------------------------------- 1 | --- 2 | admin: 3 | level: 4 | parameters: "" 5 | description: calcula o nível da ilha para o jogador 6 | sethandicap: 7 | parameters: " " 8 | description: Define o handicap da ilha. É geralmente o nível da ilha inicial. 9 | changed: "&a O handicap inicial da ilha foi alterado de [number] para [new_number]." 10 | invalid-level: "&c Handicap inválido. Use um número inteiro." 11 | levelstatus: 12 | description: mostrar quantas ilhas estão na fila para escaneamento. 13 | islands-in-queue: "&a Ilhas na fila: [number]" 14 | top: 15 | description: Mostra a lista dos dez primeiros 16 | unknown-world: "&c Mundo desconhecido!" 17 | display: "&f[rank]. &a[name] &7- &b[level]" 18 | remove: 19 | description: Remover jogador do Top 10 20 | parameters: "" 21 | island: 22 | level: 23 | parameters: "[player]" 24 | description: Calcula o nível da sua ilha ou mostra o nível de [player] 25 | calculating: "&a Calculando level..." 26 | estimated-wait: "&a Espera estimada: [number] segundos." 27 | in-queue: "&a Você é o número [number] na fila." 28 | island-level-is: "& O nível da ilha é&b [level]" 29 | required-points-to-next-level: "&a [pontos] pontos são necessários para chegar 30 | o próximo nível" 31 | deaths: "&c([number] mortes)" 32 | cooldown: "&c Você deve esperar &b [time] &c segundos até que possa fazer isso 33 | novamente." 34 | in-progress: "&6 Calculando o nível da ilha..." 35 | time-out: "&c O cálculo do nível demorou muito. Por favor, tente novamente mais 36 | tarde." 37 | top: 38 | description: Mostra os dez melhores 39 | gui-title: "&a Top 10" 40 | gui-heading: "&6[name]: &B[rank]" 41 | island-level: "&b Level [level]" 42 | warp-to: "&a Teletransportando para a ilha de [name]" 43 | level-details: 44 | above-sea-level-blocks: Blocos acima do nível do mar 45 | spawners: Spawners 46 | underwater-blocks: Blocos Subaquáticos 47 | all-blocks: Todos os blocos 48 | no-island: "&c Sem ilha!" 49 | names-island: Ilha de [name] 50 | syntax: "[name] x [number]" 51 | hint: "&c Executa o nível para ver o relatório de blocos." 52 | value: 53 | description: Mostra o valor de qualquer bloco 54 | success: "&7 O valor deste bloco é: &e [value]" 55 | success-underwater: "& 7O valor deste bloco abaixo do nível do mar: &e [value]" 56 | empty-hand: "&c Não há blocos em sua mão." 57 | no-value: "&c Item sem valor." 58 | -------------------------------------------------------------------------------- /src/main/resources/locales/tr.yml: -------------------------------------------------------------------------------- 1 | ########################################################################################### 2 | # This is a YML file. Be careful when editing. Check your edits in a YAML checker like # 3 | # the one at http://yaml-online-parser.appspot.com # 4 | ########################################################################################### 5 | 6 | admin: 7 | level: 8 | parameters: "" 9 | description: "Bir oyuncunun ada seviyesini hesapla" 10 | top: 11 | description: "Ilk 10 adayı sırala" 12 | unknown-world: "&cBilinmeyen kelime" 13 | display: "&f[rank]. &a[name] &7- &b[level]" 14 | 15 | island: 16 | level: 17 | parameters: "[player]" 18 | description: "&7Kendi ada seviyeni hesapla veya başka oyuncunun ada seviyesini öğren" 19 | calculating: "&aLevel hesaplanıyor..." 20 | island-level-is: "&7Ada seviyesi &b[level]" 21 | required-points-to-next-level: "&7Adayı yükseltmek için &a[points] &7Puan gerekiyor" 22 | deaths: "&c(Ölümler: [number])" 23 | cooldown: "&7Bunu tekrar yapmak için &b[time] &7beklemelisin" 24 | 25 | top: 26 | description: "Ilk 10 adayı sırala" 27 | gui-title: "&aIlk 10 Ada" 28 | gui-heading: "&6Sıralama: &3[rank]" 29 | island-level: "&7Seviye: &a[level]" 30 | warp-to: "&a[name] &7oyuncusunun adasına ışınlanıyor" 31 | 32 | value: 33 | description: "Herhangi bir bloğun değerini gösterir" 34 | success: "&7Bu bloğun değeri: &e[value]" 35 | success-underwater: "&7Deniz seviyesinin altındaki bu bloğun değeri: &e[value]" 36 | empty-hand: "&cElinde hiç blok yok" 37 | no-value: "&cBu eşyanın bir değeri yok." 38 | -------------------------------------------------------------------------------- /src/main/resources/locales/uk.yml: -------------------------------------------------------------------------------- 1 | --- 2 | admin: 3 | level: 4 | parameters: "" 5 | description: розрахувати рівень острова для гравця 6 | sethandicap: 7 | parameters: " " 8 | description: встановити гандикап острова, як правило, рівень острова стартера 9 | changed: "&a Початковий гандикап острова змінено з [number] на [new_number]." 10 | invalid-level: "&c Недійсний гандикап. Використовуйте ціле число." 11 | levelstatus: 12 | description: показати, скільки островів у черзі на сканування 13 | islands-in-queue: "&a Острови в черзі: [number]" 14 | top: 15 | description: показати першу десятку списку 16 | unknown-world: "&c Невідомий світ!" 17 | display: "&f[rank]. &a[name] &7- &b[level]" 18 | remove: 19 | description: видалити гравця з першої десятки 20 | parameters: "" 21 | stats: 22 | description: показати статистику островів на цьому сервері 23 | title: Статистика острова сервера 24 | world: "&a [name]" 25 | no-data: "&c Немає даних для обробки." 26 | average-level: 'Середній рівень острова: [number]' 27 | median-level: 'Середній рівень острова: [number]' 28 | mode-level: 'Рівень острова режиму: [number]' 29 | highest-level: 'Найвищий рівень острова: [number]' 30 | lowest-level: 'Найнижчий рівень острова: [number]' 31 | distribution: 'Розподіл на рівні острова:' 32 | islands: острови 33 | island: 34 | level: 35 | parameters: "[player]" 36 | description: обчисліть свій рівень острова або покажіть рівень [player] 37 | calculating: "&a Розрахунок рівня..." 38 | estimated-wait: "&a Приблизне очікування: [number] секунд" 39 | in-queue: "&a Ви номер [number] у черзі" 40 | island-level-is: "&a Рівень острова &b[level]" 41 | required-points-to-next-level: "&a [points] потрібні бали до наступного рівня" 42 | deaths: "&c([number] смерті)" 43 | cooldown: "&c Ви повинні зачекати &b[time] &c секунд, поки ви зможете зробити 44 | це знову" 45 | in-progress: "&6 Розрахунок рівня острова триває..." 46 | time-out: "&c Розрахунок рівня тривав занадто довго. Будь-ласка спробуйте пізніше." 47 | top: 48 | description: показати першу десятку 49 | gui-title: "& Десятка Кращих" 50 | gui-heading: "&6[name]: &B[rank]" 51 | island-level: "&b Рівень [level]" 52 | warp-to: "&A Варп на острів [name]." 53 | level-details: 54 | above-sea-level-blocks: Блоки над рівнем моря 55 | spawners: Спавера 56 | underwater-blocks: Підводні блоки 57 | all-blocks: Всі блоки 58 | no-island: "&c Немає острова!" 59 | names-island: острів [name]. 60 | syntax: "[name] x [number]" 61 | hint: "&c Запустіть рівень, щоб переглянути звіт про блокування" 62 | level: 63 | commands: 64 | value: 65 | parameters: "[hand|]" 66 | description: показує значення блоків. Додайте 'hand' в кінці, щоб відобразити 67 | значення предмета в руках. 68 | gui: 69 | titles: 70 | top: "&0&l Топ островів" 71 | detail-panel: "&0&l острів [name]." 72 | value-panel: "&0&l Значення блоку" 73 | buttons: 74 | island: 75 | empty: "&f&l [name]. місце" 76 | name: "&f&l [name]" 77 | description: |- 78 | [owner] 79 | [members] 80 | [place] 81 | [level] 82 | owners-island: Острів [player]. 83 | owner: "&7&l Власник: &r&b [player]" 84 | members-title: "&7&l Члени:" 85 | member: "&b - [player]" 86 | unknown: невідомий 87 | place: "&7&o [number]. &r&7 місце" 88 | level: "&7 Рівень: &o [number]" 89 | material: 90 | name: "&f&l [number] x [material]" 91 | description: |- 92 | [description] 93 | [count] 94 | [value] 95 | [calculated] 96 | [limit] 97 | [id] 98 | id: "&7 Ідентифікатор блоку: &e [id]" 99 | value: "&7 Значення блоку: &e [number]" 100 | limit: "&7 Обмеження блоку: &e [number]" 101 | count: "&7 Кількість блоків: &e [number]" 102 | calculated: "&7 Розраховане значення: &e [number]" 103 | all_blocks: 104 | name: "&f&l Усі блоки" 105 | description: |- 106 | &7 Показати всі блоки 107 | &7 на острові. 108 | above_sea_level: 109 | name: "&f&l Блоки над рівнем моря" 110 | description: |- 111 | &7 Показувати лише блоки 112 | &7, які знаходяться над морем 113 | &7 рівень. 114 | underwater: 115 | name: "&f&l Блоки під рівнем моря" 116 | description: |- 117 | &7 Показувати лише блоки 118 | &7, які знаходяться нижче моря 119 | &7 рівень. 120 | spawner: 121 | name: "&f&l Спанера" 122 | description: "&7 Відображати лише спавнери." 123 | filters: 124 | name: 125 | name: "&f&l Сортувати за назвою" 126 | description: "&7 Сортувати всі блоки за назвою." 127 | value: 128 | name: "&f&l Сортувати за значенням" 129 | description: "&7 Сортувати всі блоки за їх значенням." 130 | count: 131 | name: "&f&l Сортувати за кількістю" 132 | description: "&7 Відсортуйте всі блоки за їх кількістю." 133 | value: 134 | name: "&f&l [material]" 135 | description: |- 136 | [description] 137 | [value] 138 | [underwater] 139 | [limit] 140 | [id] 141 | id: "&7 Ідентифікатор блоку: &e [id]" 142 | value: "&7 Значення блоку: &e [number]" 143 | underwater: "&7 Нижче рівня моря: &e [number]" 144 | limit: "&7 Обмеження блоку: &e [number]" 145 | previous: 146 | name: "&f&l Попередня сторінка" 147 | description: "&7 Перейти на сторінку [number]." 148 | next: 149 | name: "&f&l Наступна сторінка" 150 | description: "&7 Перейти на сторінку [number]." 151 | search: 152 | name: "&f&l Пошук" 153 | description: |- 154 | &7 Пошук конкретного 155 | &7 значення. 156 | search: "&b Значення: [value]" 157 | tips: 158 | click-to-view: "&e Натисніть &7, щоб переглянути." 159 | click-to-previous: "&e Натисніть &7, щоб переглянути попередню сторінку." 160 | click-to-next: "&e Натисніть &7, щоб переглянути наступну сторінку." 161 | click-to-select: "&e Натисніть &7, щоб вибрати." 162 | left-click-to-cycle-up: "&e Клацніть лівою кнопкою миші &7, щоб перейти вгору." 163 | right-click-to-cycle-down: "&e Клацніть правою кнопкою миші &7, щоб перейти 164 | вниз." 165 | left-click-to-change: "&e Клацніть лівою кнопкою миші &7 для редагування." 166 | right-click-to-clear: "&e Клацніть правою кнопкою миші &7, щоб очистити." 167 | click-to-asc: "&e Клацніть &7, щоб відсортувати в порядку збільшення." 168 | click-to-desc: "&e Клацніть &7, щоб відсортувати в порядку зменшення." 169 | click-to-warp: "&e Натисніть &7, щоб деформувати." 170 | click-to-visit: "&e Натисніть &7, щоб відвідати." 171 | right-click-to-visit: "&e Клацніть правою кнопкою миші &7, щоб відвідати." 172 | conversations: 173 | prefix: "&l&6 [BentoBox]: &r" 174 | no-data: "&c Запустіть рівень, щоб переглянути звіт про блокування." 175 | cancel-string: cancel 176 | exit-string: cancel, exit, quit 177 | write-search: "&e Введіть пошукове значення. (Напишіть 'cancel', щоб вийти)" 178 | search-updated: "&a Значення пошуку оновлено." 179 | cancelled: "&c Розмова скасована!" 180 | no-value: "&c Цей предмет не має цінності." 181 | unknown-item: "&c '[material]' не існує в грі." 182 | value: "&7 Значення '[material]' таке: &e[value]" 183 | value-underwater: "&7 Значення '[material]' нижче рівня моря: &e[value]" 184 | empty-hand: "&c У вашій руці немає блоків" 185 | -------------------------------------------------------------------------------- /src/main/resources/locales/vi.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This is a YML file. Be careful when editing. Check your edits in a YAML checker like # 3 | # the one at http://yaml-online-parser.appspot.com # 4 | admin: 5 | level: 6 | parameters: 7 | description: tính toán cấp độ đảo của người chơi 8 | sethandicap: 9 | parameters: 10 | description: chỉnh cấp của các đảo bắt đầu 11 | changed: '&a Cấp đảo bắt đầu đã chỉnh từ [number] thành [new_number].' 12 | invalid-level: '&c Cấp không xác định. Hãy dùng số nguyên.' 13 | levelstatus: 14 | description: xem bao nhiêu đảo đang trong hàng chờ được quét 15 | islands-in-queue: '&a Đảo đang chờ: [number]' 16 | top: 17 | description: xem bảng xếp hạng TOP 10 18 | unknown-world: '&c Thế giới không xác định!' 19 | display: '&f[rank]. &a[name] &7- &b[level]' 20 | remove: 21 | description: xoá người khỏi TOP 10 22 | parameters: 23 | island: 24 | level: 25 | parameters: '[người chơi]' 26 | description: tính toán cấp đảo của bạn hoặc xem cấp đảo của [người chơi] 27 | calculating: '&a Đang tính toán cấp đảo...' 28 | estimated-wait: '&a Thời gian còn lại: [number] giây' 29 | in-queue: '&a Bạn đang ở vị trí [number] trong hàng chờ' 30 | island-level-is: '&a Cấp đảo là &b[level]' 31 | required-points-to-next-level: '&a Cần [points] điểm để qua cấp tiếp theo' 32 | deaths: '&c([number] lần chết)' 33 | cooldown: '&c Bạn phải chờ &b[time] &c giây trước khi có thể làm điều đó' 34 | in-progress: '&6 Quá trình tính toán cấp đảo đang thực hiện...' 35 | time-out: '&c Tính toán cấp đảo quá lâu. Vui lòng thử lại sau.' 36 | top: 37 | description: xem TOP 10 38 | gui-title: '&a TOP 10' 39 | gui-heading: '&6[name]: &B[rank]' 40 | island-level: '&b Cấp [level]' 41 | warp-to: '&A Đang dịch chuyển đến đảo của [name]' 42 | level-details: 43 | above-sea-level-blocks: Khối Trên Mực Nước Biển 44 | spawners: Lồng Sinh Quái 45 | underwater-blocks: Khối Dưới Nước 46 | all-blocks: Toàn Bộ Khối 47 | no-island: '&c Không có đảo!' 48 | names-island: 'đảo của [name]' 49 | syntax: '[name] x [number]' 50 | hint: '&c Chạy lệnh cấp để xem báo cáo khối' 51 | value: 52 | description: xem giá trị của bất kì khối 53 | success: '&7 Giá trị của khối này là: &e[value]' 54 | success-underwater: '&7 Giá trị của khối này dưới mực nước biển: &e[value]' 55 | empty-hand: '&c Không có khối nào trên tay bạn' 56 | no-value: '&c Vật phẩm này vô giá trị.' 57 | -------------------------------------------------------------------------------- /src/main/resources/locales/zh-CN.yml: -------------------------------------------------------------------------------- 1 | admin: 2 | level: 3 | parameters: 4 | description: 计算指定玩家的岛屿等级 5 | sethandicap: 6 | parameters: 7 | description: 设置偏差值, 通常用于抵消初始岛屿等级, 来保证岛屿等级从零开始. 实际岛屿等级 - = 最终的岛屿等级 8 | changed: '&a岛屿的偏差值从[number]更改为[new_number]' 9 | invalid-level: '&c偏差值无效, 请使用整数' 10 | levelstatus: 11 | description: 显示等级计算队列中的岛屿 12 | islands-in-queue: '&a列队中的岛屿: [number]' 13 | top: 14 | description: 显示前十名 15 | unknown-world: '&c未知的世界!' 16 | display: '&f[rank]. &a[name] &7- &b[level]' 17 | remove: 18 | description: 将玩家移出前十名 19 | parameters: 20 | stats: 21 | description: 显示该服务器上岛屿的统计数据 22 | title: 服务器岛屿数据 23 | world: '&a[name]' 24 | no-data: '&c没有数据.' 25 | average-level: '平均岛屿等级: [number]' 26 | median-level: '中位数岛屿等级: [number]' 27 | mode-level: '众数岛屿等级: [number]' 28 | highest-level: '最高岛屿等级: [number]' 29 | lowest-level: '最低岛屿等级: [number]' 30 | distribution: '岛屿等级分布:' 31 | islands: 个岛屿 32 | island: 33 | level: 34 | parameters: '[player]' 35 | description: 计算你或指定玩家[player]的岛屿等级 36 | calculating: '&a等级计算中...' 37 | estimated-wait: '&a预计等待时间: [number]秒' 38 | in-queue: '&a你处于队列中第[number]个' 39 | island-level-is: '&a岛屿等级为: &b[level]' 40 | required-points-to-next-level: '&a还需[points]点数才能到达下一级' 41 | deaths: '&c([number]次死亡)' 42 | cooldown: '&c还需等待&b[time]&c秒才能再次使用该指令' 43 | in-progress: '&6岛屿等级正在计算中...' 44 | time-out: '&c等级计算超时, 请稍后再试' 45 | 46 | top: 47 | description: 显示前十名 48 | gui-title: '&a前十' 49 | gui-heading: '&6[name]: &B[rank]' 50 | island-level: '&b等级: [level]' 51 | warp-to: '&a正在传送到[name]的岛屿' 52 | 53 | level-details: 54 | above-sea-level-blocks: 海平面以上的方块 55 | spawners: 刷怪笼 56 | underwater-blocks: 水下的方块 57 | all-blocks: 所有方块 58 | no-island: '&c没有岛屿!' 59 | names-island: '[name]的岛屿' 60 | syntax: '[name] x [number]' 61 | hint: '&c运行level指令查看方块报告' 62 | 63 | level: 64 | commands: 65 | value: 66 | parameters: '[hand|]' 67 | description: 显示方块的价值. 在末尾添加'hand'可显示手中方块的价值 68 | gui: 69 | titles: 70 | top: '&0&l岛屿排行榜' 71 | detail-panel: '&0&l[name]的岛屿' 72 | value-panel: '&0&l方块价值' 73 | buttons: 74 | island: 75 | empty: '&f&l第[name]名' 76 | name: '&f&l[name]' 77 | description: |- 78 | [owner] 79 | [members] 80 | [place] 81 | [level] 82 | owners-island: '[player]的岛屿' 83 | owner: '&7&l岛主: &r&b[player]' 84 | members-title: '&7&l成员: ' 85 | member: '&b- [player]' 86 | unknown: 未知 87 | place: '&7第&7&o[number]&r&7名' 88 | level: '&7等级: &o[number]' 89 | material: 90 | name: '&f&l [number] x [material]' 91 | description: |- 92 | [description] 93 | [count] 94 | [value] 95 | [calculated] 96 | [limit] 97 | [id] 98 | id: '&7方块ID: &e[id]' 99 | value: '&7方块价值: &e[number]' 100 | limit: '&7方块限制: &e[number]' 101 | count: '&7方块数量: &e[number]' 102 | calculated: '&7计算值: &e[number]' 103 | all_blocks: 104 | name: '&f&l所有方块' 105 | description: '&7显示岛屿上所有的方块' 106 | above_sea_level: 107 | name: '&f&l海平面以上的方块' 108 | description: '&7只显示所有海平面以上的方块' 109 | underwater: 110 | name: '&f&l海平面以下的方块' 111 | description: 只显示所有海平面以下的方块 112 | spawner: 113 | name: '&f&l刷怪笼' 114 | description: '&7只显示刷怪笼' 115 | filters: 116 | name: 117 | name: '&f&l按名称排序' 118 | description: '&7通过名称排序所有的方块' 119 | value: 120 | name: '&f&l按价值排序' 121 | description: '&7通过价值排序所有的方块' 122 | count: 123 | name: '&f&l按数量排序' 124 | description: '&7通过数量排序所有方块' 125 | value: 126 | name: '&f&l[material]' 127 | description: |- 128 | [description] 129 | [value] 130 | [underwater] 131 | [limit] 132 | [id] 133 | id: '&7方块ID: &e[id]' 134 | value: '&7方块价值: &e[number]' 135 | underwater: '&7海平面以下方块的价值: &e[number]' 136 | limit: '&7方块限制: &e[number]' 137 | previous: 138 | name: '&f&l上一页' 139 | description: '&7切换到第[number]页' 140 | next: 141 | name: '&f&l下一页' 142 | description: '&7切换到第[number]页' 143 | search: 144 | name: '&f&l搜索' 145 | description: '&7搜索特定的内容' 146 | search: '&b搜索值: [value]' 147 | tips: 148 | click-to-view: '&e点击 &7查看' 149 | click-to-previous: '&e点击 &7查看上一页' 150 | click-to-next: '&e点击 &7查看下一页' 151 | click-to-select: '&e点击 &7选择' 152 | left-click-to-cycle-up: '&e左键 &7向上循环' 153 | right-click-to-cycle-down: '&e右键 &7向下循环' 154 | left-click-to-change: '&e左键 &7编辑' 155 | right-click-to-clear: '&e右键 &7清除' 156 | click-to-asc: '&e点击 &7以升序排序' 157 | click-to-desc: '&e点击 &7以降序排序' 158 | click-to-warp: '&e点击 &7去岛屿传送点' 159 | click-to-visit: '&e点击 &7参观' 160 | right-click-to-visit: '&e右键 &7查看' 161 | conversations: 162 | prefix: '&l&6[BentoBox]: &r' 163 | no-data: '&c运行level指令查看方块报告' 164 | cancel-string: cancel 165 | exit-string: cancel, exit, quit 166 | write-search: '&e请输入要搜索的值. (输入''cancel''退出)' 167 | search-updated: '&a搜索值已更新' 168 | cancelled: '&c对话已取消' 169 | no-value: '&c这件物品一文不值' 170 | unknown-item: '&c物品''[material]''在游戏中不存在' 171 | value: '&7物品''[material]''的价值: &e[value]' 172 | value-underwater: '&7物品''[material]''在海平面以下的价值: &e[value]' 173 | empty-hand: '&c你的手中没有拿着方块' 174 | -------------------------------------------------------------------------------- /src/main/resources/panels/detail_panel.yml: -------------------------------------------------------------------------------- 1 | # Name of panel used for indentification in the code 2 | detail_panel: 3 | # Title of the panel shown to the user. This is a reference and the reference will be translatable in the locale file 4 | title: level.gui.titles.detail-panel 5 | # The type of panel to show. Options are INVENTORY, HOPPER, DROPPER. INVENTORY is that standard chest inventory and 6 | # the others refer to the inventories shown for those items. 7 | type: INVENTORY 8 | # The background of the panel. These items will be shown if other items are not there. STAINED_GLASS_PANEs give a good effect. 9 | background: 10 | icon: BLACK_STAINED_GLASS_PANE 11 | # Each item may have text applied to it, but usually for background items, nothing is shown. 12 | title: "&b&r" # Empty text. This is using the Bukkit chat color coding with &'s. 13 | border: 14 | # The border of each panel may be shown as a different item. 15 | # It can be used to provide a contrast to items in the panel. 16 | icon: BLACK_STAINED_GLASS_PANE 17 | title: "&b&r" # Empty text 18 | # This tag indicates which rows in the panel must be shown. The panel will be sized vertically accordingly. This does not include the borders. 19 | # This can be a list and rows must be between 1 and 6, if used. 20 | force-shown: [] 21 | # The content section contains details of each item/button in the panel. The numbers indicate the rows and then then columns of each item. 22 | content: 23 | # Row number 24 | 1: 25 | # Column number 26 | 2: 27 | # Icon is a Bukkit Material. 28 | icon: ICE 29 | # Title of the button shown to the user. This is a reference and the reference will be translatable in the locale file 30 | title: level.gui.buttons.value_blocks.name 31 | # 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 32 | description: level.gui.buttons.value_blocks.description 33 | # The data section is a key-value list of data relavent for this button. It is interpreted by the code implemented the panel. 34 | # The convention is to specify the type and the panel tab that will open if pressed. These are Enums in the code. 35 | data: 36 | # Type button will go to the ALL_BLOCKS tab when clicked. 37 | type: TAB 38 | tab: VALUE_BLOCKS 39 | # Actions cover what happens if the button is clicked or the mouse is moved over it. There can be multiple actions possible for different 40 | # click-types. 41 | actions: 42 | # Each action has an arbitrary descriptive name to define it. 43 | view: 44 | # The click-type is the same as the bukkit {@link org.bukkit.event.inventory.ClickType}. UNKNOWN is the default. 45 | click-type: unknown 46 | # tooltip is a locale reference that will be translated for the user and shown when they hover over the button. 47 | tooltip: level.gui.tips.click-to-view 48 | 3: 49 | # Icon is a Bukkit Material. 50 | icon: STONE 51 | # Title of the button shown to the user. This is a reference and the reference will be translatable in the locale file 52 | title: level.gui.buttons.all_blocks.name 53 | # 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 54 | description: level.gui.buttons.all_blocks.description 55 | # The data section is a key-value list of data relavent for this button. It is interpreted by the code implemented the panel. 56 | # The convention is to specify the type and the panel tab that will open if pressed. These are Enums in the code. 57 | data: 58 | # Type button will go to the ALL_BLOCKS tab when clicked. 59 | type: TAB 60 | tab: ALL_BLOCKS 61 | # Actions cover what happens if the button is clicked or the mouse is moved over it. There can be multiple actions possible for different 62 | # click-types. 63 | actions: 64 | # Each action has an arbitrary descriptive name to define it. 65 | view: 66 | # The click-type is the same as the bukkit {@link org.bukkit.event.inventory.ClickType}. UNKNOWN is the default. 67 | click-type: unknown 68 | # tooltip is a locale reference that will be translated for the user and shown when they hover over the button. 69 | tooltip: level.gui.tips.click-to-view 70 | 4: 71 | icon: GRASS_BLOCK 72 | title: level.gui.buttons.above_sea_level.name 73 | description: level.gui.buttons.above_sea_level.description 74 | data: 75 | type: TAB 76 | tab: ABOVE_SEA_LEVEL 77 | actions: 78 | view: 79 | click-type: unknown 80 | tooltip: level.gui.tips.click-to-view 81 | 5: 82 | icon: WATER_BUCKET 83 | title: level.gui.buttons.underwater.name 84 | description: level.gui.buttons.underwater.description 85 | data: 86 | type: TAB 87 | tab: UNDERWATER 88 | actions: 89 | view: 90 | click-type: unknown 91 | tooltip: level.gui.tips.click-to-view 92 | 6: 93 | icon: SPAWNER 94 | title: level.gui.buttons.spawner.name 95 | description: level.gui.buttons.spawner.description 96 | data: 97 | type: TAB 98 | tab: SPAWNER 99 | actions: 100 | view: 101 | click-type: unknown 102 | tooltip: level.gui.tips.click-to-view 103 | 9: 104 | # You can create multiple buttons. By default it is one. 105 | icon: IRON_TRAPDOOR 106 | # [filter] is a placeholder for different filter types. It will be replaced with name, value, count. 107 | title: level.gui.buttons.filters.[filter].name 108 | description: level.gui.buttons.filters.[filter].description 109 | data: 110 | type: FILTER 111 | # the value of filter button. Suggestion is to leave first value to name if you use single button. 112 | filter: NAME 113 | actions: 114 | up: 115 | click-type: left 116 | tooltip: level.gui.tips.left-click-to-cycle-up 117 | down: 118 | click-type: right 119 | tooltip: level.gui.tips.right-click-to-cycle-down 120 | # There is also select action. With it you can create multiple filter buttons. 121 | # select: 122 | # click-type: unknown 123 | # tooltip: level.gui.tips.click-to-select 124 | 2: 125 | # If a button is used repeatedly then it can be mentioned by name and then defined in the 'reusable' section 126 | 2: material_button 127 | 3: material_button 128 | 4: material_button 129 | 5: material_button 130 | 6: material_button 131 | 7: material_button 132 | 8: material_button 133 | 3: 134 | 1: 135 | # In this case, the icon is defined as a TIPPED_ARROW with a color. 136 | # CustomPotionColor uses the Decimal description of a Color, just as leather armor does. 137 | # All you need to do is take a hex code of a color (like #ff00aa) which represents red, 138 | # green, blue as 2 hex digits each and convert that number into a decimal, using a hex to decimal calculator. 139 | icon: tipped_arrow[potion_contents={custom_color:11546150}] 140 | title: level.gui.buttons.previous.name 141 | description: level.gui.buttons.previous.description 142 | data: 143 | type: PREVIOUS 144 | indexing: true 145 | actions: 146 | previous: 147 | click-type: unknown 148 | tooltip: level.gui.tips.click-to-previous 149 | 2: material_button 150 | 3: material_button 151 | 4: material_button 152 | 5: material_button 153 | 6: material_button 154 | 7: material_button 155 | 8: material_button 156 | 9: 157 | icon: tipped_arrow[potion_contents={custom_color:8439583}] 158 | title: level.gui.buttons.next.name 159 | description: level.gui.buttons.next.description 160 | data: 161 | type: NEXT 162 | indexing: true 163 | actions: 164 | next: 165 | click-type: unknown 166 | tooltip: level.gui.tips.click-to-next 167 | 4: 168 | 2: material_button 169 | 3: material_button 170 | 4: material_button 171 | 5: material_button 172 | 6: material_button 173 | 7: material_button 174 | 8: material_button 175 | # This is where reuable buttons are defined. 176 | reusable: 177 | # This is the name of the button that is referenced 178 | material_button: 179 | # If the icon for a button is not defined, it defaults to AIR and so effectively will not be shown. 180 | # 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 181 | #icon: STONE 182 | title: level.gui.buttons.material.name 183 | description: level.gui.buttons.material.description 184 | data: 185 | type: BLOCK -------------------------------------------------------------------------------- /src/main/resources/panels/top_panel.yml: -------------------------------------------------------------------------------- 1 | # Name of panel used for indentification in the code 2 | top_panel: 3 | # Title of the panel shown to the user. This is a reference and the reference will be translatable in the locale file 4 | title: level.gui.titles.top 5 | # The type of panel to show. Options are INVENTORY, HOPPER, DROPPER. INVENTORY is that standard chest inventory and 6 | # the others refer to the inventories shown for those items. 7 | type: INVENTORY 8 | # The background of the panel. These items will be shown if other items are not there. STAINED_GLASS_PANEs give a good effect. 9 | background: 10 | icon: BLACK_STAINED_GLASS_PANE 11 | # Each item may have text applied to it, but usually for background items, nothing is shown. 12 | title: "&b&r" # Empty text 13 | border: 14 | # The border of each panel may be shown as a different item. 15 | # It can be used to provide a contrast to items in the panel. 16 | icon: BLACK_STAINED_GLASS_PANE 17 | title: "&b&r" # Empty text 18 | # This tag indicates which rows in the panel must be shown. The panel will be sized vertically accordingly. This does not include the borders. 19 | # This can be a list and rows must be between 1 and 6, if used. 20 | force-shown: [2,3,4,5] 21 | # The content section contains details of each item/button in the panel. The numbers indicate the rows and then then columns of each item. 22 | content: 23 | # Row number 24 | 2: 25 | # Column number 26 | 5: 27 | #icon: PLAYER_HEAD 28 | title: level.gui.buttons.island.name 29 | description: level.gui.buttons.island.description 30 | data: 31 | type: TOP 32 | index: 1 33 | actions: 34 | warp: 35 | click-type: LEFT 36 | tooltip: level.gui.tips.click-to-warp 37 | visit: 38 | click-type: RIGHT 39 | tooltip: level.gui.tips.right-click-to-visit 40 | fallback: 41 | icon: LIME_STAINED_GLASS_PANE 42 | title: level.gui.buttons.island.empty 43 | 3: 44 | 4: 45 | #icon: PLAYER_HEAD 46 | title: level.gui.buttons.island.name 47 | description: level.gui.buttons.island.description 48 | data: 49 | type: TOP 50 | index: 2 51 | actions: 52 | warp: 53 | click-type: LEFT 54 | tooltip: level.gui.tips.click-to-warp 55 | visit: 56 | click-type: RIGHT 57 | tooltip: level.gui.tips.right-click-to-visit 58 | fallback: 59 | icon: LIME_STAINED_GLASS_PANE 60 | title: level.gui.buttons.island.empty 61 | 6: 62 | #icon: PLAYER_HEAD 63 | title: level.gui.buttons.island.name 64 | description: level.gui.buttons.island.description 65 | data: 66 | type: TOP 67 | index: 3 68 | actions: 69 | warp: 70 | click-type: LEFT 71 | tooltip: level.gui.tips.click-to-warp 72 | visit: 73 | click-type: RIGHT 74 | tooltip: level.gui.tips.right-click-to-visit 75 | fallback: 76 | icon: LIME_STAINED_GLASS_PANE 77 | title: level.gui.buttons.island.empty 78 | 4: 79 | 2: 80 | #icon: PLAYER_HEAD 81 | title: level.gui.buttons.island.name 82 | description: level.gui.buttons.island.description 83 | data: 84 | type: TOP 85 | index: 4 86 | actions: 87 | warp: 88 | click-type: LEFT 89 | tooltip: level.gui.tips.click-to-warp 90 | visit: 91 | click-type: RIGHT 92 | tooltip: level.gui.tips.right-click-to-visit 93 | fallback: 94 | icon: LIME_STAINED_GLASS_PANE 95 | title: level.gui.buttons.island.empty 96 | 3: 97 | #icon: PLAYER_HEAD 98 | title: level.gui.buttons.island.name 99 | description: level.gui.buttons.island.description 100 | data: 101 | type: TOP 102 | index: 5 103 | actions: 104 | warp: 105 | click-type: LEFT 106 | tooltip: level.gui.tips.click-to-warp 107 | visit: 108 | click-type: RIGHT 109 | tooltip: level.gui.tips.right-click-to-visit 110 | fallback: 111 | icon: LIME_STAINED_GLASS_PANE 112 | title: level.gui.buttons.island.empty 113 | 4: 114 | #icon: PLAYER_HEAD 115 | title: level.gui.buttons.island.name 116 | description: level.gui.buttons.island.description 117 | data: 118 | type: TOP 119 | index: 6 120 | actions: 121 | warp: 122 | click-type: LEFT 123 | tooltip: level.gui.tips.click-to-warp 124 | visit: 125 | click-type: RIGHT 126 | tooltip: level.gui.tips.right-click-to-visit 127 | fallback: 128 | icon: LIME_STAINED_GLASS_PANE 129 | title: level.gui.buttons.island.empty 130 | 5: 131 | #icon: PLAYER_HEAD 132 | title: level.gui.buttons.island.name 133 | description: level.gui.buttons.island.description 134 | data: 135 | type: TOP 136 | index: 7 137 | actions: 138 | warp: 139 | click-type: LEFT 140 | tooltip: level.gui.tips.click-to-warp 141 | visit: 142 | click-type: RIGHT 143 | tooltip: level.gui.tips.right-click-to-visit 144 | fallback: 145 | icon: LIME_STAINED_GLASS_PANE 146 | title: level.gui.buttons.island.empty 147 | 6: 148 | #icon: PLAYER_HEAD 149 | title: level.gui.buttons.island.name 150 | description: level.gui.buttons.island.description 151 | data: 152 | type: TOP 153 | index: 8 154 | actions: 155 | warp: 156 | click-type: LEFT 157 | tooltip: level.gui.tips.click-to-warp 158 | visit: 159 | click-type: RIGHT 160 | tooltip: level.gui.tips.right-click-to-visit 161 | fallback: 162 | icon: LIME_STAINED_GLASS_PANE 163 | title: level.gui.buttons.island.empty 164 | 7: 165 | #icon: PLAYER_HEAD 166 | title: level.gui.buttons.island.name 167 | description: level.gui.buttons.island.description 168 | data: 169 | type: TOP 170 | index: 9 171 | actions: 172 | warp: 173 | click-type: LEFT 174 | tooltip: level.gui.tips.click-to-warp 175 | visit: 176 | click-type: RIGHT 177 | tooltip: level.gui.tips.right-click-to-visit 178 | fallback: 179 | icon: LIME_STAINED_GLASS_PANE 180 | title: level.gui.buttons.island.empty 181 | 8: 182 | #icon: PLAYER_HEAD 183 | title: level.gui.buttons.island.name 184 | description: level.gui.buttons.island.description 185 | data: 186 | type: TOP 187 | index: 10 188 | actions: 189 | warp: 190 | click-type: LEFT 191 | tooltip: level.gui.tips.click-to-warp 192 | visit: 193 | click-type: RIGHT 194 | tooltip: level.gui.tips.right-click-to-visit 195 | fallback: 196 | icon: LIME_STAINED_GLASS_PANE 197 | title: level.gui.buttons.island.empty 198 | 6: 199 | 5: 200 | #icon: PLAYER_HEAD 201 | title: level.gui.buttons.island.name 202 | description: level.gui.buttons.island.description 203 | data: 204 | type: VIEW 205 | actions: 206 | view: 207 | click-type: unknown 208 | tooltip: level.gui.tips.click-to-view -------------------------------------------------------------------------------- /src/main/resources/panels/value_panel.yml: -------------------------------------------------------------------------------- 1 | value_panel: 2 | title: level.gui.titles.value-panel 3 | type: INVENTORY 4 | background: 5 | icon: BLACK_STAINED_GLASS_PANE 6 | title: "&b&r" # Empty text 7 | border: 8 | icon: BLACK_STAINED_GLASS_PANE 9 | title: "&b&r" # Empty text 10 | force-shown: [] 11 | content: 12 | 1: 13 | 4: 14 | icon: PAPER 15 | title: level.gui.buttons.filters.name.name 16 | description: level.gui.buttons.filters.name.description 17 | data: 18 | type: FILTER 19 | # the value of filter button. Suggestion is to leave fist value to name if you use single button. 20 | filter: NAME 21 | actions: 22 | asc: 23 | click-type: unknown 24 | tooltip: level.gui.tips.click-to-asc 25 | desc: 26 | click-type: unknown 27 | tooltip: level.gui.tips.click-to-desc 28 | 5: 29 | # You can create multiple buttons. By default it is one. 30 | icon: MAP 31 | title: level.gui.buttons.search.name 32 | description: level.gui.buttons.search.description 33 | data: 34 | type: SEARCH 35 | actions: 36 | input: 37 | click-type: left 38 | tooltip: level.gui.tips.left-click-to-change 39 | clear: 40 | click-type: right 41 | tooltip: level.gui.tips.right-click-to-clear 42 | 6: 43 | icon: DIAMOND 44 | title: level.gui.buttons.filters.value.name 45 | description: level.gui.buttons.filters.value.description 46 | data: 47 | type: FILTER 48 | # the value of filter button. Suggestion is to leave fist value to name if you use single button. 49 | filter: VALUE 50 | actions: 51 | asc: 52 | click-type: unknown 53 | tooltip: level.gui.tips.click-to-asc 54 | desc: 55 | click-type: unknown 56 | tooltip: level.gui.tips.click-to-desc 57 | 2: 58 | 2: material_button 59 | 3: material_button 60 | 4: material_button 61 | 5: material_button 62 | 6: material_button 63 | 7: material_button 64 | 8: material_button 65 | 3: 66 | 1: 67 | icon: tipped_arrow[potion_contents={custom_color:11546150}] 68 | title: level.gui.buttons.previous.name 69 | description: level.gui.buttons.previous.description 70 | data: 71 | type: PREVIOUS 72 | indexing: true 73 | actions: 74 | previous: 75 | click-type: unknown 76 | tooltip: level.gui.tips.click-to-previous 77 | 2: material_button 78 | 3: material_button 79 | 4: material_button 80 | 5: material_button 81 | 6: material_button 82 | 7: material_button 83 | 8: material_button 84 | 9: 85 | icon: tipped_arrow[potion_contents={custom_color:8439583}] 86 | title: level.gui.buttons.next.name 87 | description: level.gui.buttons.next.description 88 | data: 89 | type: NEXT 90 | indexing: true 91 | actions: 92 | next: 93 | click-type: unknown 94 | tooltip: level.gui.tips.click-to-next 95 | 4: 96 | 2: material_button 97 | 3: material_button 98 | 4: material_button 99 | 5: material_button 100 | 6: material_button 101 | 7: material_button 102 | 8: material_button 103 | reusable: 104 | material_button: 105 | #icon: STONE 106 | title: level.gui.buttons.value.name 107 | description: level.gui.buttons.value.description 108 | data: 109 | type: BLOCK -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: BentoBox-Level 2 | main: world.bentobox.level.LevelPladdon 3 | version: ${project.version}${build.number} 4 | api-version: "1.20" 5 | 6 | authors: [tastybento] 7 | contributors: ["The BentoBoxWorld Community"] 8 | website: https://bentobox.world 9 | description: ${project.description} 10 | -------------------------------------------------------------------------------- /src/test/java/world/bentobox/level/calculators/EquationEvaluatorTest.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.calculators; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.text.ParseException; 6 | 7 | import org.junit.Test; 8 | 9 | /** 10 | * Test the equation evaluation 11 | */ 12 | public class EquationEvaluatorTest { 13 | 14 | /** 15 | * Test method for {@link world.bentobox.level.calculators.EquationEvaluator#eval(java.lang.String)}. 16 | * @throws ParseException 17 | */ 18 | @Test 19 | public void testEval() throws ParseException { 20 | assertEquals(4D, EquationEvaluator.eval("2+2"), 0D); 21 | assertEquals(0D, EquationEvaluator.eval("2-2"), 0D); 22 | assertEquals(1D, EquationEvaluator.eval("2/2"), 0D); 23 | assertEquals(4D, EquationEvaluator.eval("2*2"), 0D); 24 | assertEquals(8D, EquationEvaluator.eval("2+2+2+2"), 0D); 25 | assertEquals(5D, EquationEvaluator.eval("2.5+2.5"), 0D); 26 | assertEquals(1.414, EquationEvaluator.eval("sqrt(2)"), 0.001D); 27 | assertEquals(3.414, EquationEvaluator.eval("2 + sqrt(2)"), 0.001D); 28 | assertEquals(0D, EquationEvaluator.eval("sin(0)"), 0.1D); 29 | assertEquals(1D, EquationEvaluator.eval("cos(0)"), 0.1D); 30 | assertEquals(0D, EquationEvaluator.eval("tan(0)"), 0.1D); 31 | assertEquals(0D, EquationEvaluator.eval("log(1)"), 0.1D); 32 | assertEquals(27D, EquationEvaluator.eval("3^3"), 0.D); 33 | assertEquals(84.70332D, EquationEvaluator.eval("3^3 + 2 + 2.65 * (3 / 4) - sin(45) * log(10) + 55.344"), 34 | 0.0001D); 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/world/bentobox/level/commands/AdminStatsCommandTest.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.commands; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertFalse; 5 | import static org.junit.Assert.assertTrue; 6 | import static org.mockito.ArgumentMatchers.any; 7 | import static org.mockito.ArgumentMatchers.anyString; 8 | import static org.mockito.Mockito.mock; 9 | import static org.mockito.Mockito.never; 10 | import static org.mockito.Mockito.verify; 11 | import static org.mockito.Mockito.when; 12 | 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.Random; 17 | import java.util.UUID; 18 | 19 | import org.bukkit.Bukkit; 20 | import org.bukkit.Server; 21 | import org.bukkit.World; 22 | import org.bukkit.entity.Player; 23 | import org.bukkit.inventory.ItemFactory; 24 | import org.bukkit.inventory.meta.ItemMeta; 25 | import org.junit.After; 26 | import org.junit.Before; 27 | import org.junit.Test; 28 | import org.junit.runner.RunWith; 29 | import org.mockito.Mock; 30 | import org.powermock.api.mockito.PowerMockito; 31 | import org.powermock.core.classloader.annotations.PrepareForTest; 32 | import org.powermock.modules.junit4.PowerMockRunner; 33 | import org.powermock.reflect.Whitebox; 34 | 35 | import world.bentobox.bentobox.BentoBox; 36 | import world.bentobox.bentobox.api.addons.GameModeAddon; 37 | import world.bentobox.bentobox.api.commands.CompositeCommand; 38 | import world.bentobox.bentobox.api.user.User; 39 | import world.bentobox.bentobox.database.objects.Island; 40 | import world.bentobox.bentobox.managers.IslandWorldManager; 41 | import world.bentobox.bentobox.managers.IslandsManager; 42 | import world.bentobox.bentobox.managers.LocalesManager; 43 | import world.bentobox.bentobox.managers.PlayersManager; 44 | import world.bentobox.level.Level; 45 | import world.bentobox.level.LevelsManager; 46 | import world.bentobox.level.objects.TopTenData; 47 | 48 | /** 49 | * @author tastybento 50 | */ 51 | @RunWith(PowerMockRunner.class) 52 | @PrepareForTest({ Bukkit.class, BentoBox.class }) 53 | public class AdminStatsCommandTest { 54 | 55 | @Mock 56 | private CompositeCommand ic; 57 | private UUID uuid; 58 | @Mock 59 | private User user; 60 | @Mock 61 | private IslandsManager im; 62 | @Mock 63 | private Island island; 64 | @Mock 65 | private Level addon; 66 | @Mock 67 | private World world; 68 | @Mock 69 | private IslandWorldManager iwm; 70 | @Mock 71 | private GameModeAddon gameModeAddon; 72 | @Mock 73 | private Player p; 74 | @Mock 75 | private LocalesManager lm; 76 | @Mock 77 | private PlayersManager pm; 78 | 79 | private AdminStatsCommand asc; 80 | private TopTenData ttd; 81 | @Mock 82 | private LevelsManager manager; 83 | @Mock 84 | private Server server; 85 | 86 | @Before 87 | public void setUp() { 88 | // Set up plugin 89 | BentoBox plugin = mock(BentoBox.class); 90 | Whitebox.setInternalState(BentoBox.class, "instance", plugin); 91 | User.setPlugin(plugin); 92 | when(addon.getPlugin()).thenReturn(plugin); 93 | 94 | // Addon 95 | when(ic.getAddon()).thenReturn(addon); 96 | when(ic.getPermissionPrefix()).thenReturn("bskyblock."); 97 | when(ic.getLabel()).thenReturn("island"); 98 | when(ic.getTopLabel()).thenReturn("island"); 99 | when(ic.getWorld()).thenReturn(world); 100 | when(ic.getTopLabel()).thenReturn("bsb"); 101 | 102 | // IWM friendly name 103 | when(plugin.getIWM()).thenReturn(iwm); 104 | when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock"); 105 | 106 | // World 107 | when(world.toString()).thenReturn("world"); 108 | when(world.getName()).thenReturn("BSkyBlock_world"); 109 | 110 | // Player manager 111 | when(plugin.getPlayers()).thenReturn(pm); 112 | when(pm.getUser(anyString())).thenReturn(user); 113 | // topTen 114 | when(addon.getManager()).thenReturn(manager); 115 | // User 116 | uuid = UUID.randomUUID(); 117 | when(user.getUniqueId()).thenReturn(uuid); 118 | when(user.getTranslation(any())).thenAnswer(invocation -> invocation.getArgument(0, String.class)); 119 | 120 | // Bukkit 121 | PowerMockito.mockStatic(Bukkit.class); 122 | when(Bukkit.getServer()).thenReturn(server); 123 | // Mock item factory (for itemstacks) 124 | ItemFactory itemFactory = mock(ItemFactory.class); 125 | ItemMeta itemMeta = mock(ItemMeta.class); 126 | when(itemFactory.getItemMeta(any())).thenReturn(itemMeta); 127 | when(server.getItemFactory()).thenReturn(itemFactory); 128 | when(Bukkit.getItemFactory()).thenReturn(itemFactory); 129 | 130 | // Top ten 131 | ttd = new TopTenData(world); 132 | Map topten = new HashMap<>(); 133 | Random r = new Random(); 134 | for (int i = 0; i < 1000; i++) { 135 | topten.put(UUID.randomUUID().toString(), r.nextLong(20000)); 136 | } 137 | ttd.setTopTen(topten); 138 | asc = new AdminStatsCommand(addon, ic); 139 | } 140 | 141 | @After 142 | public void tearDown() { 143 | User.clearUsers(); 144 | } 145 | 146 | /** 147 | * Test method for 148 | * {@link world.bentobox.level.commands.AdminStatsCommand#setup()}. 149 | */ 150 | @Test 151 | public void testSetup() { 152 | assertEquals("bskyblock.admin.stats", asc.getPermission()); 153 | assertFalse(asc.isOnlyPlayer()); 154 | assertEquals("admin.stats.description", asc.getDescription()); 155 | 156 | } 157 | 158 | /** 159 | * Test method for 160 | * {@link world.bentobox.level.commands.AdminStatsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. 161 | */ 162 | @Test 163 | public void testExecuteUserStringListOfString() { 164 | assertFalse(asc.execute(user, "", List.of())); 165 | verify(user).sendMessage("admin.stats.title"); 166 | verify(user).sendMessage("admin.stats.no-data"); 167 | } 168 | 169 | /** 170 | * Test method for 171 | * {@link world.bentobox.level.commands.AdminStatsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. 172 | */ 173 | @Test 174 | public void testExecuteUserStringListOfStringLevels() { 175 | Map map = new HashMap<>(); 176 | map.put(world, ttd); 177 | when(manager.getTopTenLists()).thenReturn(map); 178 | assertTrue(asc.execute(user, "", List.of())); 179 | verify(user).sendMessage("admin.stats.title"); 180 | verify(user, never()).sendMessage("admin.stats.no-data"); 181 | } 182 | 183 | } 184 | -------------------------------------------------------------------------------- /src/test/java/world/bentobox/level/commands/AdminTopRemoveCommandTest.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.commands; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertFalse; 5 | import static org.junit.Assert.assertTrue; 6 | import static org.mockito.ArgumentMatchers.any; 7 | import static org.mockito.ArgumentMatchers.anyString; 8 | import static org.mockito.Mockito.mock; 9 | import static org.mockito.Mockito.verify; 10 | import static org.mockito.Mockito.when; 11 | 12 | import java.util.Collections; 13 | import java.util.List; 14 | import java.util.UUID; 15 | 16 | import org.bukkit.Bukkit; 17 | import org.bukkit.Server; 18 | import org.bukkit.World; 19 | import org.bukkit.entity.Player; 20 | import org.bukkit.inventory.ItemFactory; 21 | import org.bukkit.inventory.meta.ItemMeta; 22 | import org.junit.After; 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | import org.mockito.Mock; 27 | import org.powermock.api.mockito.PowerMockito; 28 | import org.powermock.core.classloader.annotations.PrepareForTest; 29 | import org.powermock.modules.junit4.PowerMockRunner; 30 | import org.powermock.reflect.Whitebox; 31 | 32 | import world.bentobox.bentobox.BentoBox; 33 | import world.bentobox.bentobox.api.addons.GameModeAddon; 34 | import world.bentobox.bentobox.api.commands.CompositeCommand; 35 | import world.bentobox.bentobox.api.localization.TextVariables; 36 | import world.bentobox.bentobox.api.user.User; 37 | import world.bentobox.bentobox.database.objects.Island; 38 | import world.bentobox.bentobox.managers.IslandWorldManager; 39 | import world.bentobox.bentobox.managers.IslandsManager; 40 | import world.bentobox.bentobox.managers.LocalesManager; 41 | import world.bentobox.bentobox.managers.PlayersManager; 42 | import world.bentobox.level.Level; 43 | import world.bentobox.level.LevelsManager; 44 | import world.bentobox.level.objects.TopTenData; 45 | 46 | /** 47 | * @author tastybento 48 | * 49 | */ 50 | @RunWith(PowerMockRunner.class) 51 | @PrepareForTest({ Bukkit.class, BentoBox.class }) 52 | public class AdminTopRemoveCommandTest { 53 | 54 | @Mock 55 | private CompositeCommand ic; 56 | private UUID uuid; 57 | @Mock 58 | private User user; 59 | @Mock 60 | private IslandsManager im; 61 | @Mock 62 | private Island island; 63 | @Mock 64 | private Level addon; 65 | @Mock 66 | private World world; 67 | @Mock 68 | private IslandWorldManager iwm; 69 | @Mock 70 | private GameModeAddon gameModeAddon; 71 | @Mock 72 | private Player p; 73 | @Mock 74 | private LocalesManager lm; 75 | @Mock 76 | private PlayersManager pm; 77 | 78 | private AdminTopRemoveCommand atrc; 79 | @Mock 80 | private TopTenData ttd; 81 | @Mock 82 | private LevelsManager manager; 83 | @Mock 84 | private Server server; 85 | 86 | @Before 87 | public void setUp() { 88 | // Set up plugin 89 | BentoBox plugin = mock(BentoBox.class); 90 | Whitebox.setInternalState(BentoBox.class, "instance", plugin); 91 | User.setPlugin(plugin); 92 | 93 | // Addon 94 | when(ic.getAddon()).thenReturn(addon); 95 | when(ic.getPermissionPrefix()).thenReturn("bskyblock."); 96 | when(ic.getLabel()).thenReturn("island"); 97 | when(ic.getTopLabel()).thenReturn("island"); 98 | when(ic.getWorld()).thenReturn(world); 99 | when(ic.getTopLabel()).thenReturn("bsb"); 100 | 101 | // IWM friendly name 102 | when(plugin.getIWM()).thenReturn(iwm); 103 | when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock"); 104 | 105 | // World 106 | when(world.toString()).thenReturn("world"); 107 | when(world.getName()).thenReturn("BSkyBlock_world"); 108 | 109 | // Player manager 110 | when(plugin.getPlayers()).thenReturn(pm); 111 | when(pm.getUser(anyString())).thenReturn(user); 112 | // topTen 113 | when(addon.getManager()).thenReturn(manager); 114 | // User 115 | uuid = UUID.randomUUID(); 116 | when(user.getUniqueId()).thenReturn(uuid); 117 | when(user.getTranslation(any())).thenAnswer(invocation -> invocation.getArgument(0, String.class)); 118 | // Island 119 | when(island.getUniqueId()).thenReturn(uuid.toString()); 120 | when(island.getOwner()).thenReturn(uuid); 121 | // Island Manager 122 | when(plugin.getIslands()).thenReturn(im); 123 | when(im.getIslands(any(), any(User.class))).thenReturn(List.of(island)); 124 | when(im.getIslands(any(), any(UUID.class))).thenReturn(List.of(island)); 125 | 126 | // Bukkit 127 | PowerMockito.mockStatic(Bukkit.class); 128 | when(Bukkit.getServer()).thenReturn(server); 129 | // Mock item factory (for itemstacks) 130 | ItemFactory itemFactory = mock(ItemFactory.class); 131 | ItemMeta itemMeta = mock(ItemMeta.class); 132 | when(itemFactory.getItemMeta(any())).thenReturn(itemMeta); 133 | when(server.getItemFactory()).thenReturn(itemFactory); 134 | when(Bukkit.getItemFactory()).thenReturn(itemFactory); 135 | 136 | atrc = new AdminTopRemoveCommand(addon, ic); 137 | } 138 | 139 | @After 140 | public void tearDown() { 141 | User.clearUsers(); 142 | } 143 | 144 | /** 145 | * Test method for 146 | * {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#AdminTopRemoveCommand(world.bentobox.level.Level, world.bentobox.bentobox.api.commands.CompositeCommand)}. 147 | */ 148 | @Test 149 | public void testAdminTopRemoveCommand() { 150 | assertEquals("remove", atrc.getLabel()); 151 | assertEquals("delete", atrc.getAliases().get(0)); 152 | } 153 | 154 | /** 155 | * Test method for 156 | * {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#setup()}. 157 | */ 158 | @Test 159 | public void testSetup() { 160 | assertEquals("bskyblock.admin.top.remove", atrc.getPermission()); 161 | assertEquals("admin.top.remove.parameters", atrc.getParameters()); 162 | assertEquals("admin.top.remove.description", atrc.getDescription()); 163 | assertFalse(atrc.isOnlyPlayer()); 164 | 165 | } 166 | 167 | /** 168 | * Test method for 169 | * {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. 170 | */ 171 | @Test 172 | public void testCanExecuteWrongArgs() { 173 | assertFalse(atrc.canExecute(user, "delete", Collections.emptyList())); 174 | verify(user).sendMessage("commands.help.header", TextVariables.LABEL, "BSkyBlock"); 175 | } 176 | 177 | /** 178 | * Test method for {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. 179 | */ 180 | @Test 181 | public void testCanExecuteUnknown() { 182 | when(pm.getUser(anyString())).thenReturn(null); 183 | assertFalse(atrc.canExecute(user, "delete", Collections.singletonList("tastybento"))); 184 | verify(user).sendMessage("general.errors.unknown-player", TextVariables.NAME, "tastybento"); 185 | } 186 | 187 | /** 188 | * Test method for 189 | * {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. 190 | */ 191 | @Test 192 | public void testCanExecuteKnown() { 193 | assertTrue(atrc.canExecute(user, "delete", Collections.singletonList("tastybento"))); 194 | } 195 | 196 | /** 197 | * Test method for 198 | * {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. 199 | */ 200 | @Test 201 | public void testExecuteUserStringListOfString() { 202 | testCanExecuteKnown(); 203 | assertTrue(atrc.execute(user, "delete", Collections.singletonList("tastybento"))); 204 | verify(manager).removeEntry(world, uuid.toString()); 205 | verify(user).sendMessage("general.success"); 206 | } 207 | 208 | } 209 | -------------------------------------------------------------------------------- /src/test/java/world/bentobox/level/mocks/ServerMocks.java: -------------------------------------------------------------------------------- 1 | package world.bentobox.level.mocks; 2 | 3 | import static org.mockito.ArgumentMatchers.notNull; 4 | import static org.mockito.Mockito.doAnswer; 5 | import static org.mockito.Mockito.doReturn; 6 | import static org.mockito.Mockito.mock; 7 | import static org.mockito.Mockito.when; 8 | 9 | import java.lang.reflect.Field; 10 | import java.util.HashMap; 11 | import java.util.Locale; 12 | import java.util.Map; 13 | import java.util.Set; 14 | import java.util.logging.Logger; 15 | 16 | import org.bukkit.Bukkit; 17 | import org.bukkit.Keyed; 18 | import org.bukkit.NamespacedKey; 19 | import org.bukkit.Registry; 20 | import org.bukkit.Server; 21 | import org.bukkit.Tag; 22 | import org.bukkit.UnsafeValues; 23 | import org.eclipse.jdt.annotation.NonNull; 24 | 25 | public final class ServerMocks { 26 | 27 | public static @NonNull Server newServer() { 28 | Server mock = mock(Server.class); 29 | 30 | Logger noOp = mock(Logger.class); 31 | when(mock.getLogger()).thenReturn(noOp); 32 | when(mock.isPrimaryThread()).thenReturn(true); 33 | 34 | // Unsafe 35 | UnsafeValues unsafe = mock(UnsafeValues.class); 36 | when(mock.getUnsafe()).thenReturn(unsafe); 37 | 38 | // Server must be available before tags can be mocked. 39 | Bukkit.setServer(mock); 40 | 41 | // Bukkit has a lot of static constants referencing registry values. To initialize those, the 42 | // registries must be able to be fetched before the classes are touched. 43 | Map, Object> registers = new HashMap<>(); 44 | 45 | doAnswer(invocationGetRegistry -> registers.computeIfAbsent(invocationGetRegistry.getArgument(0), clazz -> { 46 | Registry registry = mock(Registry.class); 47 | Map cache = new HashMap<>(); 48 | doAnswer(invocationGetEntry -> { 49 | NamespacedKey key = invocationGetEntry.getArgument(0); 50 | // Some classes (like BlockType and ItemType) have extra generics that will be 51 | // erased during runtime calls. To ensure accurate typing, grab the constant's field. 52 | // This approach also allows us to return null for unsupported keys. 53 | Class constantClazz; 54 | try { 55 | //noinspection unchecked 56 | constantClazz = (Class) clazz 57 | .getField(key.getKey().toUpperCase(Locale.ROOT).replace('.', '_')).getType(); 58 | } catch (ClassCastException e) { 59 | throw new RuntimeException(e); 60 | } catch (NoSuchFieldException e) { 61 | return null; 62 | } 63 | 64 | return cache.computeIfAbsent(key, key1 -> { 65 | Keyed keyed = mock(constantClazz); 66 | doReturn(key).when(keyed).getKey(); 67 | return keyed; 68 | }); 69 | }).when(registry).get(notNull()); 70 | return registry; 71 | })).when(mock).getRegistry(notNull()); 72 | 73 | // Tags are dependent on registries, but use a different method. 74 | // This will set up blank tags for each constant; all that needs to be done to render them 75 | // functional is to re-mock Tag#getValues. 76 | doAnswer(invocationGetTag -> { 77 | Tag tag = mock(Tag.class); 78 | doReturn(invocationGetTag.getArgument(1)).when(tag).getKey(); 79 | doReturn(Set.of()).when(tag).getValues(); 80 | doAnswer(invocationIsTagged -> { 81 | Keyed keyed = invocationIsTagged.getArgument(0); 82 | Class type = invocationGetTag.getArgument(2); 83 | if (!type.isAssignableFrom(keyed.getClass())) { 84 | return null; 85 | } 86 | // Since these are mocks, the exact instance might not be equal. Consider equal keys equal. 87 | return tag.getValues().contains(keyed) 88 | || tag.getValues().stream().anyMatch(value -> value.getKey().equals(keyed.getKey())); 89 | }).when(tag).isTagged(notNull()); 90 | return tag; 91 | }).when(mock).getTag(notNull(), notNull(), notNull()); 92 | 93 | // Once the server is all set up, touch BlockType and ItemType to initialize. 94 | // This prevents issues when trying to access dependent methods from a Material constant. 95 | try { 96 | Class.forName("org.bukkit.inventory.ItemType"); 97 | Class.forName("org.bukkit.block.BlockType"); 98 | } catch (ClassNotFoundException e) { 99 | throw new RuntimeException(e); 100 | } 101 | 102 | return mock; 103 | } 104 | 105 | public static void unsetBukkitServer() { 106 | try { 107 | Field server = Bukkit.class.getDeclaredField("server"); 108 | server.setAccessible(true); 109 | server.set(null, null); 110 | } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { 111 | throw new RuntimeException(e); 112 | } 113 | } 114 | 115 | private ServerMocks() { 116 | } 117 | 118 | } --------------------------------------------------------------------------------