diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..cb7fd21 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,31 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + + - name: Build and test + run: mvn -B clean verify --file pom.xml + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results + path: target/surefire-reports/ diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml deleted file mode 100644 index 620e851..0000000 --- a/.github/workflows/maven.yml +++ /dev/null @@ -1,35 +0,0 @@ -# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven - -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -name: Java CI with Maven - -on: - push: - branches: [ "master" ] - pull_request: - branches: [ "master" ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Set up JDK 18 - uses: actions/setup-java@v3 - with: - java-version: '18' - distribution: 'temurin' - cache: maven - - name: Build with Maven - run: mvn -B package --file pom.xml - - # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive - - name: Update dependency graph - uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..5fd0a29 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,105 @@ +# Architecture — MiningLevels + +## High-Level Overview + +``` +┌─────────────────────────────────────────────────┐ +│ MiningLevels │ +│ (JavaPlugin entry) │ +├──────────┬──────────┬───────────┬───────────────┤ +│ API │ Listeners│ GUI │ Utils │ +│ │ │ │ │ +│ MiningLvl│ Commands │ LevelList │ ConfigStrings │ +│ MiningBlk│ Events │ LevelEdit │ MathUtils │ +│ MiningPly│ │ BlockList │ SenderUtils │ +│ Reward │ │ BlockEdit │ Crucial │ +│ │ │ Leaderboard│ CustomMessages│ +├──────────┴──────────┴───────────┴───────────────┤ +│ I/O │ +│ FileManager · MessagesYaml │ +├─────────────────────────────────────────────────┤ +│ CrucialLib 3.0.0 │ +│ (JSON, localization, effects) │ +└─────────────────────────────────────────────────┘ +``` + +## Package Structure + +### `api` — Core Data Model + +- **MiningLevel**: Defines a level with name, ordinal, XP threshold, and skills (haste, instant break, extra ore, rewards, commands). Stored as ordered list. +- **MiningBlock**: Maps one or more `Material` names to an XP value and minimum level requirement. +- **MiningPlayer**: Tracks a player's UUID, current level ordinal, XP, and unclaimed rewards. Provides `alterXp()` for XP changes with automatic level-up detection. +- **Reward**: Wraps an `ItemStack` for JSON serialization (material + amount). + +All model classes use **static ArrayLists** as in-memory registries (`miningLevels`, `miningBlocks`, `miningPlayers`) loaded from JSON at startup. + +### `listeners` — Commands & Events + +- **MiningLevelsCommandListener**: Handles `/mininglevels` (aliases: `/ml`). Subcommands: level, setlevel, setxp, reload, editor, leaderboard. +- **RewardCommandListener**: Handles `/miningrewards` for claiming level-up rewards. +- **MiningEvents**: Core gameplay — block break XP, haste effect, instant break, extra ore drops. +- **NoXpBlockEvents**: Tracks player-placed blocks to prevent XP farming. +- **ServerEvents**: Player join/quit handling (creates new MiningPlayers, saves data). + +### `gui` — Inventory Editor + +In-game GUIs built with CrucialLib's `Interface` system for editing levels and blocks. Admin-only (`mininglevels.editor`). + +### `io` — Persistence + +- **FileManager**: Manages JSON data files (`miningLevels.json`, `miningBlocks.json`, `players.json`). Uses CrucialLib's `Json` class. +- **MessagesYaml**: Loads `messages.yml` for CrucialLib's `Localizer`. + +### `utils` — Helpers + +- **ConfigStrings**: All config keys, permissions, message keys, and constants. +- **Crucial**: CrucialLib dependency checker — downloads if missing, validates version. +- **MathUtils**: `randomDouble(min, max)` for probability calculations. +- **SenderUtils**: Chat message formatting with prefix support. +- **CustomMessages**: Loads custom message configuration. + +### `placeholders` — PlaceholderAPI + +- **LevelPlaceholders**: Registers `%mininglevels_level%`, `%mininglevels_xp%`, etc. +- **PlaceholderCommand**: Executes commands with placeholder replacement on level-up. + +## Data Flow + +### Startup Sequence + +``` +onLoad() → Crucial.init() (ensure CrucialLib is available) +onEnable() → Crucial.connect() (enable CrucialLib) + → loadConfig() (config.yml defaults) + → FileManager() (ensure data directory) + → MiningLevel.init() (load miningLevels.json) + → MiningPlayer.init()(load players.json) + → MiningBlock.init() (load miningBlocks.json) + → register listeners, commands, placeholders +``` + +### Mining Event Flow + +``` +BlockBreakEvent + → Check mining item in hand (config: mining_items) + → Check player-placed block tracking + → MiningBlock.getMiningBlock(material) + → Check minLevel requirement + → Apply haste effect (PotionEffectType.HASTE) + → Apply instant break probability + → Apply extra ore probability + → MiningPlayer.alterXp(block.getXp()) + → xpChange() + → If xp >= threshold: levelUp() + → If xp < 0: level drop + → Otherwise: show progress +``` + +### Persistence + +All data is JSON-based via CrucialLib. Saved on: +- Plugin disable (`onDisable()`) +- Editor changes (immediate save) +- Config reload command diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c65a622 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,63 @@ +# CLAUDE.md — MiningLevels + +## Project Overview + +MiningLevels is a Spigot/Paper plugin that adds a configurable mining leveling system to Minecraft servers. Players earn XP by mining blocks, level up, and unlock skills (haste, instant break, extra ore drops) and rewards. + +## Build & Test + +```bash +mvn clean verify # compile + test + package +mvn test # run tests only +mvn package -DskipTests # package without tests +``` + +- **Java**: 21 +- **Server API**: Paper 1.21 +- **Build tool**: Maven 3.x +- **Test framework**: JUnit 5 + MockBukkit 4.x + +The shaded JAR is produced at `target/MiningLevels-.jar`. + +## Key Packages + +| Package | Purpose | +|---|---| +| `api` | Core data model: `MiningLevel`, `MiningBlock`, `MiningPlayer`, `Reward` | +| `listeners` | Command handlers and event listeners | +| `listeners/events` | Bukkit event listeners (mining, block placement, server events) | +| `gui` | Inventory-based editor GUIs (levels, blocks, leaderboard) | +| `io` | File I/O (`FileManager`, `MessagesYaml`) | +| `utils` | Config constants, math utilities, messaging helpers | +| `placeholders` | PlaceholderAPI integration | + +## Level System + +- Levels are defined in `miningLevels.json` (loaded via `MiningLevel.init()`) +- Blocks and their XP values are in `miningBlocks.json` (loaded via `MiningBlock.init()`) +- Player progress is in `players.json` (loaded via `MiningPlayer.init()`) +- All persistence uses CrucialLib's `Json.fromJson()` / `FileManager.saveFile()` + +## Event Flow + +1. Player breaks a block → `MiningEvents.onBlockBreak()` +2. Block matched against `MiningBlock.getMiningBlock(material)` +3. XP awarded via `MiningPlayer.alterXp(xp)` +4. `xpChange()` checks threshold → calls `MiningLevel.levelUp()` if needed +5. Level-up triggers: sound, message, skill display, rewards, commands + +## External Dependencies + +- **CrucialLib 3.0.0** — JSON persistence, localization, boss bars, player effects +- **PlaceholderAPI** (optional) — exposes level/XP placeholders and command rewards + +## Testing Notes + +- Tests use `MockBukkit.mock()` (server only, no plugin load) for domain model tests +- Plugin load is avoided in tests because `Crucial.init()` requires CrucialLib at runtime +- Lazy initialization (`getPlugin()`) ensures classes can be loaded without the plugin being active +- The `MiningLevels` class must NOT be `final` (MockBukkit requirement) + +## Config Keys + +See `ConfigStrings.java` for all config paths and permission strings. Main config is in `config.yml`, messages in `messages.yml`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..9d23431 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,70 @@ +# Contributing to MiningLevels + +## Development Environment + +### Prerequisites + +- Java 21 (JDK) +- Maven 3.x +- Git + +### Setup + +```bash +git clone https://github.com/ChafficPlugins/MiningLevels.git +cd MiningLevels +mvn clean verify +``` + +## Branch Naming + +- `feature/` — new features +- `fix/` — bug fixes +- `chore/` — maintenance, dependency updates + +## Testing + +All changes must pass `mvn clean verify` with 0 test failures before merging. + +### Writing Tests + +- Test files go in `src/test/java/` mirroring the main source structure +- Use JUnit 5 (`@Test`, `@BeforeAll`, `@BeforeEach`, `@AfterAll`) +- Use `MockBukkit.mock()` for tests needing Bukkit API (Materials, ItemStacks, etc.) +- Do **not** use `MockBukkit.load(MiningLevels.class)` — the plugin depends on CrucialLib at runtime +- Always call `MockBukkit.unmock()` in `@AfterAll` +- Clear static registries in `@BeforeEach` (e.g., `MiningLevel.miningLevels.clear()`) + +### Test Structure + +```java +class MyTest { + @BeforeAll + static void setUpServer() { + MockBukkit.mock(); + } + + @AfterAll + static void tearDown() { + MockBukkit.unmock(); + } + + @BeforeEach + void setUp() { + // Clear and set up test data + } + + @Test + void methodName_condition_expectedBehavior() { + // Arrange, Act, Assert + } +} +``` + +## PR Checklist + +- [ ] `mvn clean verify` passes with 0 failures +- [ ] New code has unit tests where applicable +- [ ] No secrets or credentials committed +- [ ] Commit messages are clear and descriptive +- [ ] `plugin.yml` version updated if releasing diff --git a/DECISIONS/001-spigot-1.21-update.md b/DECISIONS/001-spigot-1.21-update.md new file mode 100644 index 0000000..c2ff626 --- /dev/null +++ b/DECISIONS/001-spigot-1.21-update.md @@ -0,0 +1,25 @@ +# ADR-001: Update to Paper 1.21 and Java 21 + +## Status +Accepted + +## Context +MiningLevels was targeting Spigot 1.15 API with Java 8/14. The Minecraft server ecosystem has moved to 1.21.x, and MockBukkit 4.x (needed for testing) requires Paper API. + +## Decision +- Update to **Paper API 1.21** (superset of Spigot API) +- Update to **Java 21** (current LTS) +- Migrate from **CrucialAPI 2.1.7** to **CrucialLib 3.0.0** (package rename: `CrucialAPI` → `CrucialLib`) +- Update `plugin.yml` api-version from `1.15` to `1.21` + +## Key Changes +- `PotionEffectType.FAST_DIGGING` → `PotionEffectType.HASTE` (renamed in 1.20+) +- `new URL()` → `URI.create().toURL()` (URL constructor deprecated) +- `Server.checkCompatibility()` updated for 1.21 +- All CrucialAPI imports changed to CrucialLib package paths + +## Consequences +- Plugin requires Java 21+ to run +- Compatible with Paper/Spigot 1.21.x servers +- Enables use of MockBukkit 4.x for testing +- Some deprecation warnings remain (Sound.valueOf, getPluginLoader) but are functional diff --git a/DECISIONS/002-add-unit-tests.md b/DECISIONS/002-add-unit-tests.md new file mode 100644 index 0000000..6caffbc --- /dev/null +++ b/DECISIONS/002-add-unit-tests.md @@ -0,0 +1,31 @@ +# ADR-002: Add Unit Tests with MockBukkit + +## Status +Accepted + +## Context +The project had no automated tests. MockBukkit provides a mock Bukkit server for testing Spigot/Paper plugins without a real Minecraft server. + +## Decision +- Use **JUnit 5** as the test framework +- Use **MockBukkit 4.101.0** (for Paper 1.21) as the Bukkit mock +- Test domain model classes (`MiningLevel`, `MiningBlock`, `MiningPlayer`, `Reward`) and utilities (`MathUtils`, `ConfigStrings`) +- Use `MockBukkit.mock()` only (no `MockBukkit.load()`) for domain model tests + +## Why Not MockBukkit.load()? +The plugin's `onLoad()` calls `Crucial.init()` which attempts to find/download CrucialLib — a runtime dependency not available in the test environment. Since domain model tests only need Bukkit Material/ItemStack classes (not the full plugin lifecycle), `MockBukkit.mock()` provides sufficient infrastructure. + +## Design Decisions +- **Lazy plugin initialization**: Static `getPlugin()` methods in `MiningLevel`, `MiningPlayer`, and `Crucial` use lazy init to avoid `JavaPlugin.getPlugin()` calls at class load time (which fails under MockBukkit) +- **MiningLevels class is non-final**: MockBukkit requires subclassing the plugin class +- **Paper API as compile dependency**: MockBukkit 4.x is built against Paper, not Spigot + +## Test Coverage +- `MathUtilsTest` — 121 tests (randomDouble range behavior) +- `ConfigStringsTest` — 7 tests (constant validation) +- `MiningLevelTest` — 24 tests (level data model, navigation, skills) +- `MiningBlockTest` — 10 tests (block creation, lookup, validation) +- `MiningPlayerTest` — 19 tests (player lifecycle, XP, levels) +- `RewardTest` — 3 tests (reward creation, item stacks) + +**Total: 184 tests** diff --git a/RUNBOOK.md b/RUNBOOK.md new file mode 100644 index 0000000..90ef5ae --- /dev/null +++ b/RUNBOOK.md @@ -0,0 +1,78 @@ +# Runbook — MiningLevels + +## Release Process + +1. Update version in `pom.xml` +2. Update version in `plugin.yml` +3. Run `mvn clean verify` — ensure all tests pass +4. Build the shaded JAR: `mvn package` +5. Upload `target/MiningLevels-.jar` to GitHub Releases / SpigotMC + +## Adding a New Mining Block + +1. In-game: Use `/mininglevels editor` → Blocks → Add Block +2. Or edit `plugins/MiningLevels/miningBlocks.json` directly: + ```json + { + "materials": ["COPPER_ORE", "DEEPSLATE_COPPER_ORE"], + "xp": 2, + "minLevel": 0 + } + ``` +3. Reload with `/mininglevels reload` + +## Adding a New Mining Level + +1. In-game: Use `/mininglevels editor` → Levels → Add Level +2. Or edit `plugins/MiningLevels/miningLevels.json`: + ```json + { + "name": "Grandmaster", + "nextLevelXP": 2000, + "ordinal": 4, + "hasteLevel": 3, + "instantBreakProbability": 15.0, + "extraOreProbability": 20.0, + "maxExtraOre": 3, + "rewards": [], + "commands": [] + } + ``` +3. Levels must have sequential ordinals starting from 0 +4. Reload with `/mininglevels reload` + +## Common Issues + +### "Error 24: Failed to download CrucialLib" +- The server couldn't download CrucialLib automatically +- Download manually from: https://github.com/ChafficPlugins/CrucialLib/releases +- Place the JAR in the `plugins/` folder and restart + +### "Error 26: Wrong version of CrucialLib" +- Incompatible CrucialLib version installed +- Required version: 3.0.x (see `ConfigStrings.CRUCIAL_LIB_VERSION`) +- Download the correct version and replace the existing JAR + +### Players not earning XP +- Check that the block is in `miningBlocks.json` +- Check that the player's pickaxe is in the `mining_items` config list +- Check `level_with.player_placed_blocks` if mining player-placed blocks +- Check that the player meets the block's `minLevel` requirement + +### PlaceholderAPI placeholders not working +- Ensure PlaceholderAPI is installed and enabled +- Placeholders: `%mininglevels_level%`, `%mininglevels_xp%`, `%mininglevels_next_level_xp%` + +## Configuration Reference + +Key config values in `config.yml`: + +| Key | Default | Description | +|-----|---------|-------------| +| `levelup_sound` | `ENTITY_PLAYER_LEVELUP` | Sound played on level-up | +| `max_level_xp_drops` | `false` | Allow XP at max level | +| `level_with.player_placed_blocks` | `false` | Earn XP from placed blocks | +| `level_with.generated_blocks` | `false` | Earn XP from generated blocks | +| `level_progression_messages` | `actionBar` | Message type: chat/title/actionBar/bossBar | +| `destroy_mining_blocks_on_explode` | `true` | Track exploded blocks | +| `mining_items` | All pickaxes | Tools that grant mining XP | diff --git a/claude.md b/claude.md index e0203b4..667e370 100644 --- a/claude.md +++ b/claude.md @@ -2,31 +2,34 @@ An easily configurable advanced mining level system for Spigot/Minecraft servers. Players gain XP by mining configured blocks, level up through a progression system, unlock skills (haste, instant break, extra ore drops), and claim item rewards. -**Version:** 1.2.10 +**Version:** 1.3.0 **Author:** ChafficPlugins -**Spigot API:** 1.15+ (tested on 1.15–1.19) -**Java:** Compiled to Java 14 bytecode; requires Java 16+ at runtime +**Server API:** Paper 1.21 +**Java:** 21 ## Build System Maven project. Build with: ``` -mvn -B package --file pom.xml +mvn clean verify # compile + test + package +mvn test # run tests only +mvn package -DskipTests # package without tests ``` -The Maven Shade Plugin bundles dependencies into the final JAR. CI uses GitHub Actions (`.github/workflows/maven.yml`) with JDK 18 on `ubuntu-latest`, triggered on push/PR to `master`. +The Maven Shade Plugin bundles dependencies into the final JAR. CI uses GitHub Actions (`.github/workflows/ci.yml`) with JDK 21 on `ubuntu-latest`, triggered on push/PR to `master`. ### Dependencies | Dependency | Version | Scope | Purpose | |---|---|---|---| -| Spigot API | 1.18-R0.1-SNAPSHOT | provided | Server framework | -| CrucialAPI | 2.1.7 | provided | GUI framework, localization, JSON I/O, utilities | +| Paper API | 1.21.11-R0.1-SNAPSHOT | provided | Server framework | +| CrucialLib | 3.0.0 | compile | GUI framework, localization, JSON I/O, utilities | | PlaceholderAPI | 2.11.5 | provided | Placeholder expansion (optional) | -| JUnit Jupiter | 5.9.0 | test | Unit testing | +| JUnit Jupiter | 5.11.0 | test | Unit testing | +| MockBukkit | 4.101.0 | test | Bukkit mock for unit tests | -Both CrucialAPI and PlaceholderAPI are soft dependencies. CrucialAPI is auto-downloaded from GitHub releases if missing. PlaceholderAPI features gracefully degrade when absent. +Both CrucialLib and PlaceholderAPI are soft dependencies. CrucialLib is auto-downloaded from GitHub releases if missing. PlaceholderAPI features gracefully degrade when absent. ## Project Structure @@ -65,10 +68,10 @@ src/main/java/de/chafficplugins/mininglevels/ │ └── PlaceholderCommand.java # Execute commands with placeholder replacement └── utils/ ├── ConfigStrings.java # All constants: permissions, config keys, message keys, IDs - ├── CustomMessages.java # Localization wrapper (extends CrucialAPI LocalizedFromYaml) + ├── CustomMessages.java # Localization wrapper (extends CrucialLib LocalizedFromYaml) ├── SenderUtils.java # Permission checks, message sending, debug logging ├── MathUtils.java # randomDouble(min, max) utility - └── Crucial.java # CrucialAPI auto-download and version checking + └── Crucial.java # CrucialLib auto-download and version checking src/main/resources/ ├── plugin.yml # Plugin manifest (uses Maven resource filtering) @@ -77,7 +80,7 @@ src/main/resources/ ## Data Storage -All data is stored as JSON files using CrucialAPI's `Json` utility (GSON-based). +All data is stored as JSON files using CrucialLib's `Json` utility (GSON-based). | File | Path | Contents | |---|---|---| @@ -231,9 +234,9 @@ Key messages: `no_permission`, `new_level`, `player_not_exist`, `xp_received`, ` - **Main class:** `MiningLevels.java` — handles lifecycle (`onLoad`/`onEnable`/`onDisable`), config defaults, and event/command registration - **Static collections:** `MiningPlayer.miningPlayers`, `MiningLevel.miningLevels`, and `MiningBlock.miningBlocks` are in-memory `ArrayList`s that serve as the data store -- **GUI framework:** All GUIs extend `Page` from CrucialAPI, providing inventory-based UIs -- **Localization:** Uses CrucialAPI's `Localizer` with the identifier `mininglevels` -- **Serialization:** GSON via CrucialAPI's `Json` utility; `Reward` wraps `ItemStack` for JSON compatibility +- **GUI framework:** All GUIs extend `Page` from CrucialLib, providing inventory-based UIs +- **Localization:** Uses CrucialLib's `Localizer` with the identifier `mininglevels` +- **Serialization:** GSON via CrucialLib's `Json` utility; `Reward` wraps `ItemStack` for JSON compatibility - **Permission bypass:** `SenderUtils.hasOnePermissions()` grants access to ops and players with `mininglevels.*` - **bStats ID:** 14709 (anonymous usage statistics) - **Spigot Resource ID:** 100886 diff --git a/pom.xml b/pom.xml index b170653..72c6bbb 100644 --- a/pom.xml +++ b/pom.xml @@ -6,14 +6,14 @@ de.chafficplugins MiningLevels - 1.2.10 + 1.3.0 jar MiningLevels A easily configurable advanced mining leveling system. - 1.8 + 21 UTF-8 @@ -22,10 +22,10 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.11.0 - 14 - 14 + 21 + 21 @@ -40,10 +40,22 @@ false + + + com.github.ChafficPlugins:CrucialLib + io.papermc.paper:* + org.spigotmc:* + me.clip:* + + + + maven-surefire-plugin + 3.2.5 + @@ -55,8 +67,12 @@ - spigotmc-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + spigot-repo + https://hub.spigotmc.org/nexus/content/groups/public/ + + + papermc + https://repo.papermc.io/repository/maven-public/ sonatype @@ -74,22 +90,15 @@ - org.spigotmc - spigot-api - 1.18-R0.1-SNAPSHOT + io.papermc.paper + paper-api + 1.21.11-R0.1-SNAPSHOT provided - org.junit.jupiter - junit-jupiter - 5.9.0 - test - - - com.github.Chafficui - CrucialAPI - 2.1.7 - provided + com.github.ChafficPlugins + CrucialLib + v3.0.0 me.clip @@ -97,5 +106,17 @@ 2.11.5 provided + + org.junit.jupiter + junit-jupiter + 5.11.0 + test + + + org.mockbukkit.mockbukkit + mockbukkit-v1.21 + 4.101.0 + test + diff --git a/src/main/java/de/chafficplugins/mininglevels/MiningLevels.java b/src/main/java/de/chafficplugins/mininglevels/MiningLevels.java index 6462f2e..e65b8d4 100644 --- a/src/main/java/de/chafficplugins/mininglevels/MiningLevels.java +++ b/src/main/java/de/chafficplugins/mininglevels/MiningLevels.java @@ -13,8 +13,8 @@ import de.chafficplugins.mininglevels.placeholders.LevelPlaceholders; import de.chafficplugins.mininglevels.utils.Crucial; import de.chafficplugins.mininglevels.utils.CustomMessages; -import io.github.chafficui.CrucialAPI.Utils.Server; -import io.github.chafficui.CrucialAPI.Utils.Stats; +import io.github.chafficui.CrucialLib.Utils.Server; +import io.github.chafficui.CrucialLib.Utils.Stats; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -30,7 +30,7 @@ import static de.chafficplugins.mininglevels.utils.ConfigStrings.*; -public final class MiningLevels extends JavaPlugin { +public class MiningLevels extends JavaPlugin { private final Logger logger = Logger.getLogger("MiningLevels"); public FileManager fileManager; public CustomMessages customMessages; @@ -45,7 +45,7 @@ public void onLoad() { public void onEnable() { // Plugin startup logic try { - if (!Server.checkCompatibility("1.19", "1.18", "1.17", "1.16", "1.15")) { + if (!Server.checkCompatibility("1.21")) { warn("Unsupported server version, there may be some issues with this version. Please use a supported version."); warn("This is NOT a bug. Do NOT report this!"); } diff --git a/src/main/java/de/chafficplugins/mininglevels/api/MiningBlock.java b/src/main/java/de/chafficplugins/mininglevels/api/MiningBlock.java index 408eb06..6bcee28 100644 --- a/src/main/java/de/chafficplugins/mininglevels/api/MiningBlock.java +++ b/src/main/java/de/chafficplugins/mininglevels/api/MiningBlock.java @@ -2,7 +2,7 @@ import com.google.gson.reflect.TypeToken; import de.chafficplugins.mininglevels.io.FileManager; -import io.github.chafficui.CrucialAPI.io.Json; +import io.github.chafficui.CrucialLib.io.Json; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; diff --git a/src/main/java/de/chafficplugins/mininglevels/api/MiningLevel.java b/src/main/java/de/chafficplugins/mininglevels/api/MiningLevel.java index 1100315..a5b0e01 100644 --- a/src/main/java/de/chafficplugins/mininglevels/api/MiningLevel.java +++ b/src/main/java/de/chafficplugins/mininglevels/api/MiningLevel.java @@ -4,7 +4,7 @@ import de.chafficplugins.mininglevels.MiningLevels; import de.chafficplugins.mininglevels.io.FileManager; import de.chafficplugins.mininglevels.placeholders.PlaceholderCommand; -import io.github.chafficui.CrucialAPI.io.Json; +import io.github.chafficui.CrucialLib.io.Json; import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -23,7 +23,11 @@ * This class defines a mining level and all its rewards, skills and commands. */ public class MiningLevel { - private static final MiningLevels plugin = MiningLevels.getPlugin(MiningLevels.class); + private static MiningLevels plugin; + private static MiningLevels getPlugin() { + if (plugin == null) plugin = MiningLevels.getPlugin(MiningLevels.class); + return plugin; + } /** * The displayName of the mining level. @@ -264,7 +268,7 @@ public void levelUp(MiningPlayer miningPlayer) { } //perform all commands - if(nextLevel.commands != null && nextLevel.commands.length > 0 && plugin.placeholderAPI) { + if(nextLevel.commands != null && nextLevel.commands.length > 0 && getPlugin().placeholderAPI) { for (String command : nextLevel.commands) { PlaceholderCommand.perform(player, command); } diff --git a/src/main/java/de/chafficplugins/mininglevels/api/MiningPlayer.java b/src/main/java/de/chafficplugins/mininglevels/api/MiningPlayer.java index 0399cde..8c65888 100644 --- a/src/main/java/de/chafficplugins/mininglevels/api/MiningPlayer.java +++ b/src/main/java/de/chafficplugins/mininglevels/api/MiningPlayer.java @@ -3,9 +3,9 @@ import com.google.gson.reflect.TypeToken; import de.chafficplugins.mininglevels.MiningLevels; import de.chafficplugins.mininglevels.io.FileManager; -import io.github.chafficui.CrucialAPI.Utils.localization.Localizer; -import io.github.chafficui.CrucialAPI.Utils.player.effects.Interface; -import io.github.chafficui.CrucialAPI.io.Json; +import io.github.chafficui.CrucialLib.Utils.localization.Localizer; +import io.github.chafficui.CrucialLib.Utils.player.effects.Interface; +import io.github.chafficui.CrucialLib.io.Json; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; @@ -21,7 +21,7 @@ import static de.chafficplugins.mininglevels.utils.ConfigStrings.*; import static de.chafficplugins.mininglevels.utils.SenderUtils.sendActionBar; -import static io.github.chafficui.CrucialAPI.Utils.api.Bossbar.sendBossbar; +import static io.github.chafficui.CrucialLib.Utils.api.Bossbar.sendBossbar; /** * @author Chaffic @@ -31,7 +31,11 @@ * Contains a player's mining level, its xp and unclaimed rewards. */ public class MiningPlayer { - private static final MiningLevels plugin = MiningLevels.getPlugin(MiningLevels.class); + private static MiningLevels plugin; + private static MiningLevels getPlugin() { + if (plugin == null) plugin = MiningLevels.getPlugin(MiningLevels.class); + return plugin; + } /** * The bukkit player's uuid. @@ -110,7 +114,7 @@ public int getXp() { * @param xp The amount of xp to alter the players xp by. */ public void alterXp(int xp) { - if(level == MiningLevel.getMaxLevel().getOrdinal() && !plugin.getConfigBoolean(MAX_LEVEL_XP_DROPS)) return; + if(level == MiningLevel.getMaxLevel().getOrdinal() && !getPlugin().getConfigBoolean(MAX_LEVEL_XP_DROPS)) return; this.xp += xp; xpChange(); } @@ -254,23 +258,23 @@ public static boolean notExists(UUID uuid) { public void showMessage(String key, ChatColor color, String... values) { String msg = ChatColor.GREEN + Localizer.getLocalizedString(LOCALIZED_IDENTIFIER + "_" + key, values); - switch (plugin.getConfigString(LEVEL_PROGRESSION_MESSAGES)) { + switch (getPlugin().getConfigString(LEVEL_PROGRESSION_MESSAGES)) { case "chat" -> getPlayer().sendMessage(msg); case "title" -> Interface.showText(getPlayer(), msg, ""); case "actionBar" -> sendActionBar(getPlayer(), key, color, values); case "bossBar" -> sendBossbar(getPlayer(), msg, BarColor.GREEN, 100, 5 * 20); - default -> plugin.error("Invalid level progression message type: " + plugin.getConfigString(LEVEL_PROGRESSION_MESSAGES)); + default -> getPlugin().error("Invalid level progression message type: " + getPlugin().getConfigString(LEVEL_PROGRESSION_MESSAGES)); } } public void showLevelProgress() { String msg = ChatColor.GREEN + Localizer.getLocalizedString(LOCALIZED_IDENTIFIER + "_" + XP_GAINED, getLevel().getName(), String.valueOf(xp), String.valueOf(getLevel().getNextLevelXP())); - switch (plugin.getConfigString(LEVEL_PROGRESSION_MESSAGES)) { + switch (getPlugin().getConfigString(LEVEL_PROGRESSION_MESSAGES)) { case "chat" -> getPlayer().sendMessage(msg); case "title" -> Interface.showText(getPlayer(), msg, ""); case "actionBar" -> sendActionBar(getPlayer(), XP_GAINED, ChatColor.GREEN, getLevel().getName(), String.valueOf(xp), String.valueOf(getLevel().getNextLevelXP())); case "bossBar" -> sendBossbar(getPlayer(), msg, BarColor.GREEN, (int) (((float) xp / (float) getLevel().getNextLevelXP()) * 100), 5 * 20); - default -> plugin.error("Invalid level progression message type: " + plugin.getConfigString(LEVEL_PROGRESSION_MESSAGES)); + default -> getPlugin().error("Invalid level progression message type: " + getPlugin().getConfigString(LEVEL_PROGRESSION_MESSAGES)); } } diff --git a/src/main/java/de/chafficplugins/mininglevels/gui/blocks/BlockEdit.java b/src/main/java/de/chafficplugins/mininglevels/gui/blocks/BlockEdit.java index a717a1b..689a1a8 100644 --- a/src/main/java/de/chafficplugins/mininglevels/gui/blocks/BlockEdit.java +++ b/src/main/java/de/chafficplugins/mininglevels/gui/blocks/BlockEdit.java @@ -1,8 +1,8 @@ package de.chafficplugins.mininglevels.gui.blocks; import de.chafficplugins.mininglevels.api.MiningBlock; -import io.github.chafficui.CrucialAPI.Utils.player.inventory.InventoryItem; -import io.github.chafficui.CrucialAPI.Utils.player.inventory.Page; +import io.github.chafficui.CrucialLib.Utils.player.inventory.InventoryItem; +import io.github.chafficui.CrucialLib.Utils.player.inventory.Page; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.Sound; diff --git a/src/main/java/de/chafficplugins/mininglevels/gui/blocks/BlockList.java b/src/main/java/de/chafficplugins/mininglevels/gui/blocks/BlockList.java index 14aee32..ea3e279 100644 --- a/src/main/java/de/chafficplugins/mininglevels/gui/blocks/BlockList.java +++ b/src/main/java/de/chafficplugins/mininglevels/gui/blocks/BlockList.java @@ -2,8 +2,8 @@ import de.chafficplugins.mininglevels.api.MiningBlock; import de.chafficplugins.mininglevels.api.MiningLevel; -import io.github.chafficui.CrucialAPI.Utils.player.inventory.InventoryItem; -import io.github.chafficui.CrucialAPI.Utils.player.inventory.Page; +import io.github.chafficui.CrucialLib.Utils.player.inventory.InventoryItem; +import io.github.chafficui.CrucialLib.Utils.player.inventory.Page; import org.bukkit.Material; import org.bukkit.Sound; diff --git a/src/main/java/de/chafficplugins/mininglevels/gui/leaderboard/LeaderboardList.java b/src/main/java/de/chafficplugins/mininglevels/gui/leaderboard/LeaderboardList.java index a9bdb00..8a64c1f 100644 --- a/src/main/java/de/chafficplugins/mininglevels/gui/leaderboard/LeaderboardList.java +++ b/src/main/java/de/chafficplugins/mininglevels/gui/leaderboard/LeaderboardList.java @@ -1,10 +1,10 @@ package de.chafficplugins.mininglevels.gui.leaderboard; import de.chafficplugins.mininglevels.api.MiningPlayer; -import io.github.chafficui.CrucialAPI.Utils.customItems.Stack; -import io.github.chafficui.CrucialAPI.Utils.localization.Localizer; -import io.github.chafficui.CrucialAPI.Utils.player.inventory.InventoryItem; -import io.github.chafficui.CrucialAPI.Utils.player.inventory.Page; +import io.github.chafficui.CrucialLib.Utils.customItems.Stack; +import io.github.chafficui.CrucialLib.Utils.localization.Localizer; +import io.github.chafficui.CrucialLib.Utils.player.inventory.InventoryItem; +import io.github.chafficui.CrucialLib.Utils.player.inventory.Page; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; diff --git a/src/main/java/de/chafficplugins/mininglevels/gui/leaderboard/MiningLevelProfile.java b/src/main/java/de/chafficplugins/mininglevels/gui/leaderboard/MiningLevelProfile.java index 8e2f0f8..7a56ba0 100644 --- a/src/main/java/de/chafficplugins/mininglevels/gui/leaderboard/MiningLevelProfile.java +++ b/src/main/java/de/chafficplugins/mininglevels/gui/leaderboard/MiningLevelProfile.java @@ -1,10 +1,10 @@ package de.chafficplugins.mininglevels.gui.leaderboard; import de.chafficplugins.mininglevels.api.MiningPlayer; -import io.github.chafficui.CrucialAPI.Utils.customItems.Stack; -import io.github.chafficui.CrucialAPI.Utils.localization.Localizer; -import io.github.chafficui.CrucialAPI.Utils.player.inventory.InventoryItem; -import io.github.chafficui.CrucialAPI.Utils.player.inventory.Page; +import io.github.chafficui.CrucialLib.Utils.customItems.Stack; +import io.github.chafficui.CrucialLib.Utils.localization.Localizer; +import io.github.chafficui.CrucialLib.Utils.player.inventory.InventoryItem; +import io.github.chafficui.CrucialLib.Utils.player.inventory.Page; import org.bukkit.Material; import org.bukkit.OfflinePlayer; import org.bukkit.inventory.ItemStack; diff --git a/src/main/java/de/chafficplugins/mininglevels/gui/levels/LevelEdit.java b/src/main/java/de/chafficplugins/mininglevels/gui/levels/LevelEdit.java index 75326bc..e06df65 100644 --- a/src/main/java/de/chafficplugins/mininglevels/gui/levels/LevelEdit.java +++ b/src/main/java/de/chafficplugins/mininglevels/gui/levels/LevelEdit.java @@ -1,8 +1,8 @@ package de.chafficplugins.mininglevels.gui.levels; import de.chafficplugins.mininglevels.api.MiningLevel; -import io.github.chafficui.CrucialAPI.Utils.player.inventory.InventoryItem; -import io.github.chafficui.CrucialAPI.Utils.player.inventory.Page; +import io.github.chafficui.CrucialLib.Utils.player.inventory.InventoryItem; +import io.github.chafficui.CrucialLib.Utils.player.inventory.Page; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.Sound; diff --git a/src/main/java/de/chafficplugins/mininglevels/gui/levels/LevelList.java b/src/main/java/de/chafficplugins/mininglevels/gui/levels/LevelList.java index be1986f..05c4c54 100644 --- a/src/main/java/de/chafficplugins/mininglevels/gui/levels/LevelList.java +++ b/src/main/java/de/chafficplugins/mininglevels/gui/levels/LevelList.java @@ -1,8 +1,8 @@ package de.chafficplugins.mininglevels.gui.levels; import de.chafficplugins.mininglevels.api.MiningLevel; -import io.github.chafficui.CrucialAPI.Utils.player.inventory.InventoryItem; -import io.github.chafficui.CrucialAPI.Utils.player.inventory.Page; +import io.github.chafficui.CrucialLib.Utils.player.inventory.InventoryItem; +import io.github.chafficui.CrucialLib.Utils.player.inventory.Page; import org.bukkit.Material; import org.bukkit.Sound; diff --git a/src/main/java/de/chafficplugins/mininglevels/io/FileManager.java b/src/main/java/de/chafficplugins/mininglevels/io/FileManager.java index 4cc661a..eccf692 100644 --- a/src/main/java/de/chafficplugins/mininglevels/io/FileManager.java +++ b/src/main/java/de/chafficplugins/mininglevels/io/FileManager.java @@ -1,7 +1,7 @@ package de.chafficplugins.mininglevels.io; import de.chafficplugins.mininglevels.MiningLevels; -import io.github.chafficui.CrucialAPI.io.Json; +import io.github.chafficui.CrucialLib.io.Json; import java.io.File; import java.io.FileOutputStream; diff --git a/src/main/java/de/chafficplugins/mininglevels/listeners/events/MiningEvents.java b/src/main/java/de/chafficplugins/mininglevels/listeners/events/MiningEvents.java index c47f663..dece8b9 100644 --- a/src/main/java/de/chafficplugins/mininglevels/listeners/events/MiningEvents.java +++ b/src/main/java/de/chafficplugins/mininglevels/listeners/events/MiningEvents.java @@ -43,7 +43,7 @@ public void onBlockDamage(final BlockDamageEvent event) { if (isMiningItem(itemInUse.getType())) { if (miningPlayer.getLevel().getHasteLevel() > 0) { sendDebug(event.getPlayer(), "BlockDamageEvent: " + "Haste level: " + miningPlayer.getLevel().getHasteLevel()); - event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.FAST_DIGGING, 5 * 20, miningPlayer.getLevel().getHasteLevel())); + event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.HASTE, 5 * 20, miningPlayer.getLevel().getHasteLevel())); } if (MathUtils.randomDouble(0, 100) < miningPlayer.getLevel().getInstantBreakProbability()) { sendDebug(event.getPlayer(), "BlockDamageEvent: " + "Instant break."); diff --git a/src/main/java/de/chafficplugins/mininglevels/utils/ConfigStrings.java b/src/main/java/de/chafficplugins/mininglevels/utils/ConfigStrings.java index 098aa21..85623ba 100644 --- a/src/main/java/de/chafficplugins/mininglevels/utils/ConfigStrings.java +++ b/src/main/java/de/chafficplugins/mininglevels/utils/ConfigStrings.java @@ -3,7 +3,7 @@ public class ConfigStrings { public final static int SPIGOT_ID = 100886; public final static int BSTATS_ID = 14709; - public final static String CRUCIAL_API_VERSION = "2.1.7"; + public final static String CRUCIAL_LIB_VERSION = "3.0.0"; public final static String LOCALIZED_IDENTIFIER = "mininglevels"; public static final String PERMISSION_DEBUG = "mininglevels.debug"; diff --git a/src/main/java/de/chafficplugins/mininglevels/utils/Crucial.java b/src/main/java/de/chafficplugins/mininglevels/utils/Crucial.java index a1cd11a..797e98f 100644 --- a/src/main/java/de/chafficplugins/mininglevels/utils/Crucial.java +++ b/src/main/java/de/chafficplugins/mininglevels/utils/Crucial.java @@ -1,7 +1,7 @@ package de.chafficplugins.mininglevels.utils; import de.chafficplugins.mininglevels.MiningLevels; -import io.github.chafficui.CrucialAPI.Utils.Server; +import io.github.chafficui.CrucialLib.Utils.Server; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.plugin.InvalidDescriptionException; @@ -11,60 +11,64 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.net.URL; +import java.net.URI; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; -import static de.chafficplugins.mininglevels.utils.ConfigStrings.CRUCIAL_API_VERSION; +import static de.chafficplugins.mininglevels.utils.ConfigStrings.CRUCIAL_LIB_VERSION; public class Crucial { - private static final MiningLevels plugin = MiningLevels.getPlugin(MiningLevels.class); + private static MiningLevels pluginInstance; + private static MiningLevels plugin() { + if (pluginInstance == null) pluginInstance = MiningLevels.getPlugin(MiningLevels.class); + return pluginInstance; + } private static boolean isConnected = false; public static void init() { - Plugin crucialAPI = plugin.getServer().getPluginManager().getPlugin("CrucialAPI"); - if (crucialAPI == null) { + Plugin crucialLib = plugin().getServer().getPluginManager().getPlugin("CrucialLib"); + if (crucialLib == null) { try { download(); } catch (IOException e) { - plugin.error("Error 24: Failed to download CrucialAPI"); - plugin.log("Please download it from: https://www.spigotmc.org/resources/crucialapi.86380/"); - Bukkit.getPluginManager().disablePlugin(plugin); - } catch (InvalidDescriptionException | org.bukkit.plugin.InvalidPluginException e) { - plugin.error("Error 25: Failed to load CrucialAPI."); - Bukkit.getPluginManager().disablePlugin(plugin); + plugin().error("Error 24: Failed to download CrucialLib"); + plugin().log("Please download it from: https://github.com/ChafficPlugins/CrucialLib/releases"); + Bukkit.getPluginManager().disablePlugin(plugin()); + } catch (InvalidDescriptionException | InvalidPluginException e) { + plugin().error("Error 25: Failed to load CrucialLib."); + Bukkit.getPluginManager().disablePlugin(plugin()); } - } else if (!checkVersion(crucialAPI)) { - plugin.error("Error 26: Wrong version of CrucialAPI."); - plugin.getServer().getPluginManager().disablePlugin(crucialAPI); + } else if (!checkVersion(crucialLib)) { + plugin().error("Error 26: Wrong version of CrucialLib."); + plugin().getServer().getPluginManager().disablePlugin(crucialLib); try { download(); } catch (IOException e) { - plugin.error("Error 24: Failed to download CrucialAPI"); - plugin.log("Please download it from: https://www.spigotmc.org/resources/crucialapi.86380/"); - Bukkit.getPluginManager().disablePlugin(plugin); + plugin().error("Error 24: Failed to download CrucialLib"); + plugin().log("Please download it from: https://github.com/ChafficPlugins/CrucialLib/releases"); + Bukkit.getPluginManager().disablePlugin(plugin()); } catch (InvalidPluginException | InvalidDescriptionException e) { - plugin.error("Error 25: Failed to load CrucialAPI."); - Bukkit.getPluginManager().disablePlugin(plugin); + plugin().error("Error 25: Failed to load CrucialLib."); + Bukkit.getPluginManager().disablePlugin(plugin()); } } } private static void download() throws IOException, InvalidPluginException, InvalidDescriptionException { - plugin.log("Downloading CrucialAPI"); - URL website = new URL("https://github.com/Chafficui/CrucialAPI/releases/download/v" + CRUCIAL_API_VERSION + "/CrucialAPI-v" + CRUCIAL_API_VERSION + ".jar"); + plugin().log("Downloading CrucialLib"); + java.net.URL website = URI.create("https://github.com/ChafficPlugins/CrucialLib/releases/download/v" + CRUCIAL_LIB_VERSION + "/CrucialLib-v" + CRUCIAL_LIB_VERSION + ".jar").toURL(); ReadableByteChannel rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream("plugins/CrucialAPI.jar"); + FileOutputStream fos = new FileOutputStream("plugins/CrucialLib.jar"); fos.getChannel().transferFrom(rbc, 0L, Long.MAX_VALUE); - plugin.log(ChatColor.GREEN + "Downloaded successfully."); - Bukkit.getPluginManager().loadPlugin(new File("plugins/CrucialAPI.jar")); + plugin().log(ChatColor.GREEN + "Downloaded successfully."); + Bukkit.getPluginManager().loadPlugin(new File("plugins/CrucialLib.jar")); } - private static boolean checkVersion(Plugin crucialAPI) { - String version = crucialAPI.getDescription().getVersion(); - if(version.equals(CRUCIAL_API_VERSION)) return true; + private static boolean checkVersion(Plugin crucialLib) { + String version = crucialLib.getDescription().getVersion(); + if(version.equals(CRUCIAL_LIB_VERSION)) return true; String[] subVersions = version.split("\\."); - String[] subVersions2 = CRUCIAL_API_VERSION.split("\\."); + String[] subVersions2 = CRUCIAL_LIB_VERSION.split("\\."); if(subVersions[0].equals(subVersions2[0]) && subVersions[1].equals(subVersions2[1])) { return Integer.parseInt(subVersions[2]) >= Integer.parseInt(subVersions2[2]); } @@ -72,25 +76,25 @@ private static boolean checkVersion(Plugin crucialAPI) { } public static boolean connect() throws IOException { - org.bukkit.plugin.Plugin crucialAPI = plugin.getServer().getPluginManager().getPlugin("CrucialAPI"); - if (crucialAPI != null) { - if (!crucialAPI.isEnabled()) { - Bukkit.getPluginManager().enablePlugin(crucialAPI); + Plugin crucialLib = plugin().getServer().getPluginManager().getPlugin("CrucialLib"); + if (crucialLib != null) { + if (!crucialLib.isEnabled()) { + Bukkit.getPluginManager().enablePlugin(crucialLib); } - plugin.log(ChatColor.GREEN + "Successfully connected to CrucialAPI."); + plugin().log(ChatColor.GREEN + "Successfully connected to CrucialLib."); isConnected = true; - if (!crucialAPI.getDescription().getVersion().startsWith(CRUCIAL_API_VERSION.substring(0,3))) { - plugin.error("Error 24: Please update to CrucialAPI " + CRUCIAL_API_VERSION); - plugin.log("Please download it from: https://www.spigotmc.org/resources/crucialapi.86380/"); + if (!crucialLib.getDescription().getVersion().startsWith(CRUCIAL_LIB_VERSION.substring(0,3))) { + plugin().error("Error 24: Please update to CrucialLib " + CRUCIAL_LIB_VERSION); + plugin().log("Please download it from: https://github.com/ChafficPlugins/CrucialLib/releases"); return false; } return true; } - plugin.error("Error 26: Failed to connect to CrucialAPI."); + plugin().error("Error 26: Failed to connect to CrucialLib."); return false; } public static boolean isIsConnected() { return isConnected; } -} \ No newline at end of file +} diff --git a/src/main/java/de/chafficplugins/mininglevels/utils/CustomMessages.java b/src/main/java/de/chafficplugins/mininglevels/utils/CustomMessages.java index fada0dd..51fe029 100644 --- a/src/main/java/de/chafficplugins/mininglevels/utils/CustomMessages.java +++ b/src/main/java/de/chafficplugins/mininglevels/utils/CustomMessages.java @@ -1,7 +1,7 @@ package de.chafficplugins.mininglevels.utils; import de.chafficplugins.mininglevels.MiningLevels; -import io.github.chafficui.CrucialAPI.Utils.localization.LocalizedFromYaml; +import io.github.chafficui.CrucialLib.Utils.localization.LocalizedFromYaml; import java.io.IOException; diff --git a/src/main/java/de/chafficplugins/mininglevels/utils/SenderUtils.java b/src/main/java/de/chafficplugins/mininglevels/utils/SenderUtils.java index 872c8dd..42c8b83 100644 --- a/src/main/java/de/chafficplugins/mininglevels/utils/SenderUtils.java +++ b/src/main/java/de/chafficplugins/mininglevels/utils/SenderUtils.java @@ -1,7 +1,7 @@ package de.chafficplugins.mininglevels.utils; import de.chafficplugins.mininglevels.MiningLevels; -import io.github.chafficui.CrucialAPI.Utils.localization.Localizer; +import io.github.chafficui.CrucialLib.Utils.localization.Localizer; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.ChatColor; diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index fea51f8..dc9392b 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,9 +1,9 @@ name: ${project.name} version: '${project.version}' main: de.chafficplugins.mininglevels.MiningLevels -api-version: 1.15 +api-version: '1.21' prefix: MiningLevels -softdepend: [ CrucialAPI, PlaceholderAPI ] +softdepend: [ CrucialLib, PlaceholderAPI ] authors: [ ChafficPlugins ] description: An easily configurable advanced mining level system. commands: diff --git a/src/test/java/de/chafficplugins/mininglevels/api/MiningBlockTest.java b/src/test/java/de/chafficplugins/mininglevels/api/MiningBlockTest.java new file mode 100644 index 0000000..0fbec93 --- /dev/null +++ b/src/test/java/de/chafficplugins/mininglevels/api/MiningBlockTest.java @@ -0,0 +1,130 @@ +package de.chafficplugins.mininglevels.api; + +import org.bukkit.Material; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockbukkit.mockbukkit.MockBukkit; + +import static org.junit.jupiter.api.Assertions.*; + +class MiningBlockTest { + + @BeforeAll + static void setUpServer() { + MockBukkit.mock(); + } + + @AfterAll + static void tearDown() { + MockBukkit.unmock(); + } + + @BeforeEach + void setUp() { + MiningBlock.miningBlocks.clear(); + MiningLevel.miningLevels.clear(); + MiningLevel.miningLevels.add(new MiningLevel("Beginner", 100, 0)); + MiningLevel.miningLevels.add(new MiningLevel("Apprentice", 300, 1)); + MiningLevel.miningLevels.add(new MiningLevel("Expert", 500, 2)); + } + + @Test + void constructor_singleMaterial_shouldCreateBlock() { + MiningBlock block = new MiningBlock(Material.COAL_ORE, 1, 0); + assertNotNull(block); + assertEquals(1, block.getXp()); + assertEquals(0, block.getMinLevel()); + assertTrue(block.getMaterials().contains(Material.COAL_ORE)); + } + + @Test + void constructor_multipleMaterials_shouldCreateBlock() { + MiningBlock block = new MiningBlock( + new Material[]{Material.REDSTONE_ORE, Material.DEEPSLATE_REDSTONE_ORE}, + 2, 0 + ); + assertEquals(2, block.getMaterials().size()); + assertTrue(block.getMaterials().contains(Material.REDSTONE_ORE)); + assertTrue(block.getMaterials().contains(Material.DEEPSLATE_REDSTONE_ORE)); + } + + @Test + void constructor_nonBlockMaterial_shouldThrow() { + assertThrows(IllegalArgumentException.class, () -> + new MiningBlock(Material.DIAMOND, 1, 0)); + } + + @Test + void getMiningBlock_existingMaterial_shouldReturnBlock() { + MiningBlock block = new MiningBlock(Material.DIAMOND_ORE, 5, 2); + MiningBlock.miningBlocks.add(block); + + MiningBlock found = MiningBlock.getMiningBlock(Material.DIAMOND_ORE); + assertNotNull(found); + assertEquals(5, found.getXp()); + assertEquals(2, found.getMinLevel()); + } + + @Test + void getMiningBlock_nonExistingMaterial_shouldReturnNull() { + MiningBlock.miningBlocks.add(new MiningBlock(Material.COAL_ORE, 1, 0)); + + assertNull(MiningBlock.getMiningBlock(Material.DIAMOND_ORE)); + } + + @Test + void getMiningBlock_fromMultiMaterialBlock_shouldReturnBlock() { + MiningBlock block = new MiningBlock( + new Material[]{Material.IRON_ORE, Material.DEEPSLATE_IRON_ORE}, + 3, 1 + ); + MiningBlock.miningBlocks.add(block); + + assertNotNull(MiningBlock.getMiningBlock(Material.IRON_ORE)); + assertNotNull(MiningBlock.getMiningBlock(Material.DEEPSLATE_IRON_ORE)); + assertEquals(block, MiningBlock.getMiningBlock(Material.IRON_ORE)); + } + + @Test + void setXp_shouldUpdateValue() { + MiningBlock block = new MiningBlock(Material.COAL_ORE, 1, 0); + block.setXp(10); + assertEquals(10, block.getXp()); + } + + @Test + void setMinLevel_validRange_shouldUpdateValue() { + MiningBlock block = new MiningBlock(Material.COAL_ORE, 1, 0); + block.setMinLevel(1); + assertEquals(1, block.getMinLevel()); + } + + @Test + void setMinLevel_outOfRange_shouldNotChange() { + MiningBlock block = new MiningBlock(Material.COAL_ORE, 1, 1); + // 0 is not > 0, so setMinLevel(0) won't change + block.setMinLevel(0); + assertEquals(1, block.getMinLevel()); + // 10 >= miningLevels.size() (3), so won't change + block.setMinLevel(10); + assertEquals(1, block.getMinLevel()); + } + + @Test + void multipleMiningBlocks_shouldTrackSeparately() { + MiningBlock coal = new MiningBlock(Material.COAL_ORE, 1, 0); + MiningBlock iron = new MiningBlock(Material.IRON_ORE, 3, 1); + MiningBlock diamond = new MiningBlock(Material.DIAMOND_ORE, 5, 2); + + MiningBlock.miningBlocks.add(coal); + MiningBlock.miningBlocks.add(iron); + MiningBlock.miningBlocks.add(diamond); + + assertEquals(3, MiningBlock.miningBlocks.size()); + assertEquals(coal, MiningBlock.getMiningBlock(Material.COAL_ORE)); + assertEquals(iron, MiningBlock.getMiningBlock(Material.IRON_ORE)); + assertEquals(diamond, MiningBlock.getMiningBlock(Material.DIAMOND_ORE)); + } +} diff --git a/src/test/java/de/chafficplugins/mininglevels/api/MiningLevelTest.java b/src/test/java/de/chafficplugins/mininglevels/api/MiningLevelTest.java new file mode 100644 index 0000000..6112687 --- /dev/null +++ b/src/test/java/de/chafficplugins/mininglevels/api/MiningLevelTest.java @@ -0,0 +1,227 @@ +package de.chafficplugins.mininglevels.api; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockbukkit.mockbukkit.MockBukkit; + +import static org.junit.jupiter.api.Assertions.*; + +class MiningLevelTest { + + @BeforeAll + static void setUpServer() { + MockBukkit.mock(); + } + + @AfterAll + static void tearDown() { + MockBukkit.unmock(); + } + + @BeforeEach + void setUp() { + MiningLevel.miningLevels.clear(); + MiningLevel level0 = new MiningLevel("Beginner", 100, 0); + MiningLevel level1 = new MiningLevel("Apprentice", 300, 1); + MiningLevel level2 = new MiningLevel("Expert", 500, 2); + MiningLevel level3 = new MiningLevel("Master", 1000, 3); + MiningLevel.miningLevels.add(level0); + MiningLevel.miningLevels.add(level1); + MiningLevel.miningLevels.add(level2); + MiningLevel.miningLevels.add(level3); + } + + @Test + void get_shouldReturnCorrectLevel() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + assertEquals("Beginner", level.getName()); + assertEquals(0, level.getOrdinal()); + } + + @Test + void get_shouldReturnNullForInvalidOrdinal() { + assertNull(MiningLevel.get(99)); + assertNull(MiningLevel.get(-1)); + } + + @Test + void getNext_shouldReturnNextLevel() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + MiningLevel next = level.getNext(); + assertNotNull(next); + assertEquals("Apprentice", next.getName()); + assertEquals(1, next.getOrdinal()); + } + + @Test + void getNext_atMaxLevel_shouldReturnSelf() { + MiningLevel maxLevel = MiningLevel.get(3); + assertNotNull(maxLevel); + MiningLevel next = maxLevel.getNext(); + assertEquals(maxLevel, next); + } + + @Test + void getBefore_shouldReturnPreviousLevel() { + MiningLevel level = MiningLevel.get(2); + assertNotNull(level); + MiningLevel before = level.getBefore(); + assertNotNull(before); + assertEquals("Apprentice", before.getName()); + assertEquals(1, before.getOrdinal()); + } + + @Test + void getBefore_atMinLevel_shouldReturnSelf() { + MiningLevel minLevel = MiningLevel.get(0); + assertNotNull(minLevel); + MiningLevel before = minLevel.getBefore(); + assertEquals(minLevel, before); + } + + @Test + void getNextLevelXP_shouldReturnCorrectValue() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + assertEquals(100, level.getNextLevelXP()); + } + + @Test + void setNextLevelXP_shouldUpdateValue() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + level.setNextLevelXP(200); + assertEquals(200, level.getNextLevelXP()); + } + + @Test + void getMaxLevel_shouldReturnLastLevel() { + MiningLevel maxLevel = MiningLevel.getMaxLevel(); + assertNotNull(maxLevel); + assertEquals("Master", maxLevel.getName()); + assertEquals(3, maxLevel.getOrdinal()); + } + + @Test + void equals_sameLevels_shouldBeEqual() { + MiningLevel level1 = MiningLevel.get(0); + MiningLevel level2 = MiningLevel.get(0); + assertEquals(level1, level2); + } + + @Test + void equals_differentLevels_shouldNotBeEqual() { + MiningLevel level1 = MiningLevel.get(0); + MiningLevel level2 = MiningLevel.get(1); + assertNotEquals(level1, level2); + } + + @Test + void instantBreakProbability_defaultIsZero() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + assertEquals(0, level.getInstantBreakProbability()); + } + + @Test + void setInstantBreakProbability_validRange() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + level.setInstantBreakProbability(50); + assertEquals(50, level.getInstantBreakProbability()); + } + + @Test + void setInstantBreakProbability_outOfRange_shouldNotChange() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + level.setInstantBreakProbability(50); + level.setInstantBreakProbability(101); + assertEquals(50, level.getInstantBreakProbability()); + level.setInstantBreakProbability(-1); + assertEquals(50, level.getInstantBreakProbability()); + } + + @Test + void extraOreProbability_defaultIsZero() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + assertEquals(0, level.getExtraOreProbability()); + } + + @Test + void setExtraOreProbability_validRange() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + level.setExtraOreProbability(25); + assertEquals(25, level.getExtraOreProbability()); + } + + @Test + void setExtraOreProbability_outOfRange_shouldNotChange() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + level.setExtraOreProbability(25); + level.setExtraOreProbability(101); + assertEquals(25, level.getExtraOreProbability()); + level.setExtraOreProbability(-1); + assertEquals(25, level.getExtraOreProbability()); + } + + @Test + void maxExtraOre_defaultIsZero() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + assertEquals(0, level.getMaxExtraOre()); + } + + @Test + void setMaxExtraOre_validValue() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + level.setMaxExtraOre(5); + assertEquals(5, level.getMaxExtraOre()); + } + + @Test + void setMaxExtraOre_negative_shouldNotChange() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + level.setMaxExtraOre(5); + level.setMaxExtraOre(-1); + assertEquals(5, level.getMaxExtraOre()); + } + + @Test + void hasteLevel_defaultIsZero() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + assertEquals(0, level.getHasteLevel()); + } + + @Test + void setHasteLevel_validValue() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + level.setHasteLevel(3); + assertEquals(3, level.getHasteLevel()); + } + + @Test + void setHasteLevel_negative_shouldNotChange() { + MiningLevel level = MiningLevel.get(0); + assertNotNull(level); + level.setHasteLevel(3); + level.setHasteLevel(-1); + assertEquals(3, level.getHasteLevel()); + } + + @Test + void levelListSize_shouldBeFour() { + assertEquals(4, MiningLevel.miningLevels.size()); + } +} diff --git a/src/test/java/de/chafficplugins/mininglevels/api/MiningPlayerTest.java b/src/test/java/de/chafficplugins/mininglevels/api/MiningPlayerTest.java new file mode 100644 index 0000000..ed3044d --- /dev/null +++ b/src/test/java/de/chafficplugins/mininglevels/api/MiningPlayerTest.java @@ -0,0 +1,178 @@ +package de.chafficplugins.mininglevels.api; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockbukkit.mockbukkit.MockBukkit; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +class MiningPlayerTest { + + private UUID playerUUID; + + @BeforeAll + static void setUpServer() { + MockBukkit.mock(); + } + + @AfterAll + static void tearDown() { + MockBukkit.unmock(); + } + + @BeforeEach + void setUp() { + MiningPlayer.miningPlayers.clear(); + MiningLevel.miningLevels.clear(); + MiningLevel.miningLevels.add(new MiningLevel("Beginner", 100, 0)); + MiningLevel.miningLevels.add(new MiningLevel("Apprentice", 300, 1)); + MiningLevel.miningLevels.add(new MiningLevel("Expert", 500, 2)); + playerUUID = UUID.randomUUID(); + } + + @Test + void constructor_shouldCreatePlayer() { + MiningPlayer player = new MiningPlayer(playerUUID, 0, 0); + assertNotNull(player); + assertEquals(playerUUID, player.getUUID()); + assertEquals(0, player.getXp()); + assertNotNull(player.getLevel()); + assertEquals("Beginner", player.getLevel().getName()); + } + + @Test + void constructor_shouldAddToStaticList() { + new MiningPlayer(playerUUID, 0, 0); + assertEquals(1, MiningPlayer.miningPlayers.size()); + } + + @Test + void constructor_duplicatePlayer_shouldThrow() { + new MiningPlayer(playerUUID, 0, 0); + assertThrows(IllegalArgumentException.class, () -> + new MiningPlayer(playerUUID, 0, 0)); + } + + @Test + void getMiningPlayer_existingPlayer_shouldReturn() { + new MiningPlayer(playerUUID, 0, 0); + MiningPlayer found = MiningPlayer.getMiningPlayer(playerUUID); + assertNotNull(found); + assertEquals(playerUUID, found.getUUID()); + } + + @Test + void getMiningPlayer_nonExistingPlayer_shouldReturnNull() { + assertNull(MiningPlayer.getMiningPlayer(UUID.randomUUID())); + } + + @Test + void notExists_newPlayer_shouldReturnTrue() { + assertTrue(MiningPlayer.notExists(UUID.randomUUID())); + } + + @Test + void notExists_existingPlayer_shouldReturnFalse() { + new MiningPlayer(playerUUID, 0, 0); + assertFalse(MiningPlayer.notExists(playerUUID)); + } + + @Test + void setXp_shouldSetWithoutLevelCheck() { + MiningPlayer player = new MiningPlayer(playerUUID, 0, 0); + player.setXp(50); + assertEquals(50, player.getXp()); + } + + @Test + void setXp_canSetAboveThreshold() { + MiningPlayer player = new MiningPlayer(playerUUID, 0, 0); + player.setXp(999); + assertEquals(999, player.getXp()); + } + + @Test + void setLevel_byOrdinal_shouldUpdateLevel() { + MiningPlayer player = new MiningPlayer(playerUUID, 0, 0); + player.setLevel(1); + assertEquals("Apprentice", player.getLevel().getName()); + } + + @Test + void setLevel_byMiningLevel_shouldUpdateLevel() { + MiningPlayer player = new MiningPlayer(playerUUID, 0, 0); + MiningLevel expert = MiningLevel.get(2); + assertNotNull(expert); + player.setLevel(expert); + assertEquals("Expert", player.getLevel().getName()); + } + + @Test + void getLevel_shouldReturnCorrectMiningLevel() { + MiningPlayer player = new MiningPlayer(playerUUID, 1, 50); + MiningLevel level = player.getLevel(); + assertNotNull(level); + assertEquals("Apprentice", level.getName()); + assertEquals(1, level.getOrdinal()); + } + + @Test + void equals_sameUUID_shouldBeEqual() { + MiningPlayer player1 = new MiningPlayer(playerUUID, 0, 0); + // Can't create another with same UUID (throws), so test self-equality + assertEquals(player1, player1); + } + + @Test + void equals_differentUUID_shouldNotBeEqual() { + MiningPlayer player1 = new MiningPlayer(playerUUID, 0, 0); + MiningPlayer player2 = new MiningPlayer(UUID.randomUUID(), 0, 0); + assertNotEquals(player1, player2); + } + + @Test + void equals_nonMiningPlayerObject_shouldReturnFalse() { + MiningPlayer player = new MiningPlayer(playerUUID, 0, 0); + assertNotEquals(player, "not a player"); + } + + @Test + void multiplePlayers_shouldAllBeTracked() { + UUID uuid1 = UUID.randomUUID(); + UUID uuid2 = UUID.randomUUID(); + UUID uuid3 = UUID.randomUUID(); + + new MiningPlayer(uuid1, 0, 0); + new MiningPlayer(uuid2, 1, 50); + new MiningPlayer(uuid3, 2, 200); + + assertEquals(3, MiningPlayer.miningPlayers.size()); + assertNotNull(MiningPlayer.getMiningPlayer(uuid1)); + assertNotNull(MiningPlayer.getMiningPlayer(uuid2)); + assertNotNull(MiningPlayer.getMiningPlayer(uuid3)); + } + + @Test + void playerWithLevel0_shouldHaveBeginnerLevel() { + MiningPlayer player = new MiningPlayer(playerUUID, 0, 0); + assertEquals("Beginner", player.getLevel().getName()); + assertEquals(0, player.getLevel().getOrdinal()); + } + + @Test + void playerWithMaxLevel_shouldHaveMaxLevel() { + MiningPlayer player = new MiningPlayer(playerUUID, 2, 0); + assertEquals("Expert", player.getLevel().getName()); + } + + @Test + void setXp_zeroXp_shouldWork() { + MiningPlayer player = new MiningPlayer(playerUUID, 0, 50); + player.setXp(0); + assertEquals(0, player.getXp()); + } +} diff --git a/src/test/java/de/chafficplugins/mininglevels/api/RewardTest.java b/src/test/java/de/chafficplugins/mininglevels/api/RewardTest.java new file mode 100644 index 0000000..3fc2e18 --- /dev/null +++ b/src/test/java/de/chafficplugins/mininglevels/api/RewardTest.java @@ -0,0 +1,50 @@ +package de.chafficplugins.mininglevels.api; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockbukkit.mockbukkit.MockBukkit; +import org.mockbukkit.mockbukkit.ServerMock; + +import static org.junit.jupiter.api.Assertions.*; + +class RewardTest { + + private static ServerMock server; + + @BeforeAll + static void setUpServer() { + server = MockBukkit.mock(); + } + + @AfterAll + static void tearDown() { + MockBukkit.unmock(); + } + + @Test + void constructor_shouldStoreTypeAndAmount() { + ItemStack item = new ItemStack(Material.DIAMOND, 10); + Reward reward = new Reward(item); + assertEquals(10, reward.getAmount()); + } + + @Test + void getItemStack_shouldReturnCorrectMaterialAndAmount() { + ItemStack item = new ItemStack(Material.IRON_INGOT, 5); + Reward reward = new Reward(item); + ItemStack result = reward.getItemStack(); + assertEquals(Material.IRON_INGOT, result.getType()); + assertEquals(5, result.getAmount()); + } + + @Test + void getItemStack_singleItem_shouldHaveAmountOne() { + ItemStack item = new ItemStack(Material.EMERALD, 1); + Reward reward = new Reward(item); + assertEquals(1, reward.getAmount()); + assertEquals(Material.EMERALD, reward.getItemStack().getType()); + } +} diff --git a/src/test/java/de/chafficplugins/mininglevels/utils/ConfigStringsTest.java b/src/test/java/de/chafficplugins/mininglevels/utils/ConfigStringsTest.java new file mode 100644 index 0000000..05c72a0 --- /dev/null +++ b/src/test/java/de/chafficplugins/mininglevels/utils/ConfigStringsTest.java @@ -0,0 +1,68 @@ +package de.chafficplugins.mininglevels.utils; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ConfigStringsTest { + + @Test + void crucialLibVersion_shouldBe300() { + assertEquals("3.0.0", ConfigStrings.CRUCIAL_LIB_VERSION); + } + + @Test + void permissions_shouldNotBeNull() { + assertNotNull(ConfigStrings.PERMISSION_ADMIN); + assertNotNull(ConfigStrings.PERMISSION_SET_LEVEL); + assertNotNull(ConfigStrings.PERMISSION_SET_XP); + assertNotNull(ConfigStrings.PERMISSION_LEVEL); + assertNotNull(ConfigStrings.PERMISSION_RELOAD); + assertNotNull(ConfigStrings.PERMISSION_EDITOR); + assertNotNull(ConfigStrings.PERMISSIONS_LEADERBOARD); + assertNotNull(ConfigStrings.PERMISSION_DEBUG); + } + + @Test + void configKeys_shouldNotBeNull() { + assertNotNull(ConfigStrings.LVL_UP_SOUND); + assertNotNull(ConfigStrings.MAX_LEVEL_XP_DROPS); + assertNotNull(ConfigStrings.LEVEL_WITH_PLAYER_PLACED_BLOCKS); + assertNotNull(ConfigStrings.LEVEL_WITH_GENERATED_BLOCKS); + assertNotNull(ConfigStrings.LEVEL_PROGRESSION_MESSAGES); + assertNotNull(ConfigStrings.DESTROY_MINING_BLOCKS_ON_EXPLODE); + assertNotNull(ConfigStrings.MINING_ITEMS); + assertNotNull(ConfigStrings.ADMIN_DEBUG); + } + + @Test + void messageKeys_shouldNotBeNull() { + assertNotNull(ConfigStrings.NO_PERMISSION); + assertNotNull(ConfigStrings.NEW_LEVEL); + assertNotNull(ConfigStrings.PLAYER_NOT_EXIST); + assertNotNull(ConfigStrings.XP_RECEIVED); + assertNotNull(ConfigStrings.LEVEL_OF); + assertNotNull(ConfigStrings.LEVEL_UNLOCKED); + assertNotNull(ConfigStrings.LEVEL_NEEDED); + assertNotNull(ConfigStrings.LEVEL_DROPPED); + assertNotNull(ConfigStrings.XP_GAINED); + assertNotNull(ConfigStrings.RELOAD_SUCCESSFUL); + assertNotNull(ConfigStrings.ERROR_OCCURRED); + } + + @Test + void prefix_shouldHaveDefaultValue() { + assertNotNull(ConfigStrings.PREFIX); + assertTrue(ConfigStrings.PREFIX.contains("ML")); + } + + @Test + void localizedIdentifier_shouldBeMininglevels() { + assertEquals("mininglevels", ConfigStrings.LOCALIZED_IDENTIFIER); + } + + @Test + void permissionAdmin_shouldBeWildcard() { + assertEquals("mininglevels.*", ConfigStrings.PERMISSION_ADMIN); + } +} diff --git a/src/test/java/de/chafficplugins/mininglevels/utils/MathUtilsTest.java b/src/test/java/de/chafficplugins/mininglevels/utils/MathUtilsTest.java new file mode 100644 index 0000000..2c2f610 --- /dev/null +++ b/src/test/java/de/chafficplugins/mininglevels/utils/MathUtilsTest.java @@ -0,0 +1,36 @@ +package de.chafficplugins.mininglevels.utils; + +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class MathUtilsTest { + + @RepeatedTest(50) + void randomDouble_shouldReturnValueInRange() { + double result = MathUtils.randomDouble(0, 100); + assertTrue(result >= 0 && result < 100, + "Expected value in [0, 100), got: " + result); + } + + @RepeatedTest(50) + void randomDouble_shouldReturnValueInNegativeRange() { + double result = MathUtils.randomDouble(-50, 50); + assertTrue(result >= -50 && result < 50, + "Expected value in [-50, 50), got: " + result); + } + + @Test + void randomDouble_sameMinMax_shouldReturnMin() { + double result = MathUtils.randomDouble(5, 5); + assertEquals(5.0, result, 0.001); + } + + @RepeatedTest(20) + void randomDouble_smallRange_shouldReturnValueInRange() { + double result = MathUtils.randomDouble(1, 3); + assertTrue(result >= 1 && result < 3, + "Expected value in [1, 3), got: " + result); + } +}