Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -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/
35 changes: 0 additions & 35 deletions .github/workflows/maven.yml

This file was deleted.

105 changes: 105 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -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
63 changes: 63 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -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-<version>.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`.
70 changes: 70 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -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/<description>` — new features
- `fix/<description>` — bug fixes
- `chore/<description>` — 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
25 changes: 25 additions & 0 deletions DECISIONS/001-spigot-1.21-update.md
Original file line number Diff line number Diff line change
@@ -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
31 changes: 31 additions & 0 deletions DECISIONS/002-add-unit-tests.md
Original file line number Diff line number Diff line change
@@ -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**
Loading