Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
# BlockParty
|
||||
|
||||
BlockParty is a colored-floor elimination minigame for PaperMC servers. Players stand on a
|
||||
floor of colored blocks; each round a target color is announced and players must move onto
|
||||
it before time runs out. All other blocks vanish, anyone not standing on the target color
|
||||
(or standing on nothing) falls and is eliminated, and the floor is restored for the next,
|
||||
slightly faster round. Last player standing wins.
|
||||
|
||||
## Requirements
|
||||
|
||||
- PaperMC 1.21.x (API version `1.21`)
|
||||
- Java 21
|
||||
- No other plugins required. Optional soft-dependencies: PlaceholderAPI, Vault.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Download `BlockParty-<version>.jar` (see [Building from source](#building-from-source))
|
||||
or grab it from the CI build artifacts.
|
||||
2. Drop it into your server's `plugins/` folder.
|
||||
3. Start/restart the server. `config.yml`, `messages.yml` and the `arenas/` folder are
|
||||
created automatically under `plugins/BlockParty/`.
|
||||
|
||||
## Commands
|
||||
|
||||
All admin/config commands live under `/blockparty` (alias `/bp`) and work from console
|
||||
where it makes sense (`create`, `delete`, `enable`, `disable`, `info`, `list`, `reload`).
|
||||
Commands that require a physical location (`setlobby`, `setspawn`, `setspectator`,
|
||||
`pos1`, `pos2`) require a player sender.
|
||||
|
||||
### Admin
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `/blockparty help` | Show command help |
|
||||
| `/blockparty create <arena>` | Create a new, disabled arena |
|
||||
| `/blockparty delete <arena>` | Delete an arena and its config file |
|
||||
| `/blockparty enable <arena>` | Validate and enable an arena |
|
||||
| `/blockparty disable <arena>` | Disable an arena, kicking anyone inside |
|
||||
| `/blockparty setlobby <arena>` | Set the waiting-room location |
|
||||
| `/blockparty setspawn <arena>` | Set the in-game spawn location |
|
||||
| `/blockparty setspectator <arena>` | Set the spectator/eliminated location |
|
||||
| `/blockparty pos1 <arena>` | Set floor region corner 1 |
|
||||
| `/blockparty pos2 <arena>` | Set floor region corner 2 |
|
||||
| `/blockparty setfloor <arena> <mat1,mat2,...>` | Set the allowed floor materials |
|
||||
| `/blockparty generate <arena>` | Randomly generate and persist the floor layout |
|
||||
| `/blockparty info <arena>` | Show arena configuration/status and validation errors |
|
||||
| `/blockparty list` | List all arenas |
|
||||
| `/blockparty reload` | Reload config.yml, messages.yml and arena definitions |
|
||||
|
||||
### Player
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `/blockparty join <arena>` | Join an arena's waiting lobby |
|
||||
| `/blockparty leave` | Leave your current arena |
|
||||
| `/blockparty arenas` | List arenas (alias of `list`) |
|
||||
| `/blockparty stats [player]` | View your or another player's stats |
|
||||
|
||||
## Permissions
|
||||
|
||||
| Permission | Default | Description |
|
||||
|---|---|---|
|
||||
| `blockparty.play` | true | Baseline permission to use player commands |
|
||||
| `blockparty.join` | true | Allows joining arenas |
|
||||
| `blockparty.spectate` | true | Allows spectating |
|
||||
| `blockparty.admin` | op | Parent permission, grants all `blockparty.admin.*` |
|
||||
| `blockparty.admin.create` | op | Create arenas |
|
||||
| `blockparty.admin.delete` | op | Delete arenas |
|
||||
| `blockparty.admin.setup` | op | Configure lobby/spawn/floor/etc, enable/disable |
|
||||
| `blockparty.admin.reload` | op | Reload the plugin |
|
||||
|
||||
## Creating an arena — full walkthrough
|
||||
|
||||
1. `/bp create lobby1` — creates `plugins/BlockParty/arenas/lobby1.yml`.
|
||||
2. Stand where players should wait and run `/bp setlobby lobby1`.
|
||||
3. Stand where players should spawn on the floor and run `/bp setspawn lobby1`.
|
||||
4. Stand where eliminated players/spectators should go and run `/bp setspectator lobby1`.
|
||||
5. Stand at one corner of the floor area and run `/bp pos1 lobby1`.
|
||||
6. Stand at the opposite corner and run `/bp pos2 lobby1`.
|
||||
7. Either:
|
||||
- Run `/bp setfloor lobby1 RED_CONCRETE,BLUE_CONCRETE,GREEN_CONCRETE,YELLOW_CONCRETE` to
|
||||
choose the color palette (defaults to the full concrete rainbow if you skip this and
|
||||
just generate), then `/bp generate lobby1` to lay out and persist a random floor, **or**
|
||||
- Build the floor by hand out of allowed materials, then run `/bp generate lobby1` is
|
||||
still required once so BlockParty captures/serializes the exact layout it should restore
|
||||
each round (BlockParty does not scan the world every round — it restores from the saved
|
||||
layout for performance and determinism).
|
||||
8. `/bp info lobby1` to confirm there are no validation errors.
|
||||
9. `/bp enable lobby1`.
|
||||
10. Players run `/bp join lobby1`. Once `min-players` is reached the countdown starts
|
||||
automatically; joining an arena mid-countdown is allowed by default
|
||||
(`allow-join-while-waiting: true`).
|
||||
|
||||
### Floor selection details
|
||||
|
||||
- `pos1` / `pos2` define the two opposite corners of the rectangular floor region (any Y).
|
||||
- `setfloor` only changes which materials are *allowed* to be used/regenerated — it does not
|
||||
touch blocks in the world.
|
||||
- `generate` is the step that actually writes a random layout (biased evenly across the
|
||||
configured palette) across the whole region and serializes it into the arena's yml file
|
||||
(`generated-layout`) so it can be restored exactly, every round, without re-scanning or
|
||||
re-randomizing the world.
|
||||
|
||||
## Player usage
|
||||
|
||||
- `/bp join <arena>` to enter the waiting lobby. Your inventory, armor, offhand, health,
|
||||
food, XP, game mode, flight state, location and potion effects are all captured and will
|
||||
be restored exactly when you leave, get eliminated-and-the-match-ends, or the match ends.
|
||||
- `/bp leave` at any time to exit and be restored.
|
||||
- During a round, a title/subtitle/action bar/sound announce the target color, and the
|
||||
target block is placed in your hotbar (slot 9) as a visual reminder. A boss bar (if
|
||||
enabled) shows the remaining time as a shrinking progress bar.
|
||||
- Get eliminated by not standing on the target color when the floor clears, or by falling
|
||||
off entirely. Eliminated players become spectators at the configured spectator location.
|
||||
- Last player standing wins; rewards, stats and celebration effects (fireworks, titles,
|
||||
sounds) fire automatically.
|
||||
|
||||
## Configuration overview
|
||||
|
||||
- **`config.yml`** — global settings: `ui.*` toggles for scoreboard/bossbar/titles/actionbar,
|
||||
`sounds.*` (Bukkit `Sound` enum names; invalid names are logged and skipped, never crash
|
||||
the plugin), `performance.floor-blocks-per-tick` (batch size for floor mutations),
|
||||
`defaults.*` (used only when `/bp create` seeds a new arena), `default-floor-materials`
|
||||
(the full 16-color concrete palette by default), `rewards.winner.commands`, and
|
||||
`integrations.placeholderapi`.
|
||||
- **`messages.yml`** — every user-facing string, in [MiniMessage](https://docs.advntr.dev/minimessage/format.html)
|
||||
format (Adventure, bundled with Paper). Placeholders like `%player%`, `%arena%`, `%round%`,
|
||||
`%time%`, `%color%` are substituted per-message.
|
||||
- **`arenas/<name>.yml`** — one file per arena; a broken file only disables that one arena
|
||||
(the rest still load) and the error is logged.
|
||||
|
||||
### Reload behavior
|
||||
|
||||
`/blockparty reload` re-reads `config.yml`, `messages.yml`, and every arena file. Arenas
|
||||
currently in the `RUNNING` or `ENDING` state are **skipped** during arena reload (their
|
||||
config keeps running unmodified) to avoid corrupting an active match; a warning is logged
|
||||
per skipped arena. Arenas that are `WAITING`, `STARTING` or `DISABLED` are reloaded fully
|
||||
from disk. This is a deliberate design choice: rather than queuing a reload for when the
|
||||
arena goes idle, in-progress matches simply finish on their old configuration and pick up
|
||||
the new configuration the next time they return to `WAITING`.
|
||||
|
||||
## Rewards
|
||||
|
||||
```yaml
|
||||
rewards:
|
||||
winner:
|
||||
commands:
|
||||
- "eco give %player% 100"
|
||||
- "say %player% won BlockParty in %arena% after %round% rounds!"
|
||||
```
|
||||
|
||||
Commands run as the console, so no Vault/economy plugin is required by BlockParty itself —
|
||||
if you reference an economy command (like `eco give`) you need that plugin installed
|
||||
separately. `%player%`, `%arena%` and `%round%` are replaced before dispatch.
|
||||
|
||||
## PlaceholderAPI support
|
||||
|
||||
If PlaceholderAPI is installed, BlockParty registers a `%blockparty_...%` expansion
|
||||
automatically (soft-dependency — startup never fails if PAPI is absent):
|
||||
|
||||
- `%blockparty_wins%`
|
||||
- `%blockparty_games_played%`
|
||||
- `%blockparty_best_round%`
|
||||
- `%blockparty_arena%`
|
||||
- `%blockparty_players_<arena>%`
|
||||
- `%blockparty_state_<arena>%`
|
||||
|
||||
## Building from source
|
||||
|
||||
```bash
|
||||
./gradlew clean build
|
||||
```
|
||||
|
||||
The shaded plugin jar (with `sqlite-jdbc` bundled and relocated) is produced at
|
||||
`build/libs/BlockParty-<version>.jar`.
|
||||
|
||||
Run unit tests only:
|
||||
|
||||
```bash
|
||||
./gradlew test
|
||||
```
|
||||
|
||||
Unit tests cover the pure-logic package (`us.tss3.blockparty.logic`) with no Bukkit
|
||||
dependency: arena state transitions, countdown start/cancel logic, round-time
|
||||
progression/clamping math, target-color selection (deterministic via an injectable RNG),
|
||||
elimination/winner determination, arena config validation, and player-count/join logic.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **"Arena failed validation" on enable** — run `/bp info <arena>` to see exactly which
|
||||
fields are missing (lobby/spawn/spectator/region/materials/etc).
|
||||
- **World unloaded warning** — if an arena's world is unloaded while the plugin is running,
|
||||
BlockParty detects it, safely disables that arena and restores any players inside it.
|
||||
- **Invalid sound/material in config** — logged as a warning at startup/use and skipped;
|
||||
it will not crash the plugin.
|
||||
- **Nothing happens on `/bp join`** — check the arena is enabled (`/bp info <arena>`), not
|
||||
full, and that you are not already in another arena (`/bp leave` first).
|
||||
- **Floor doesn't look right** — remember `setfloor` only changes the allowed palette; you
|
||||
must run `/bp generate <arena>` to actually (re)generate and persist a layout.
|
||||
|
||||
## Architecture
|
||||
|
||||
- `logic/` — pure, Bukkit-free game logic (unit tested).
|
||||
- `arena/` — `Arena` (per-arena runtime state machine + round loop) and `ArenaManager`.
|
||||
- `config/` — `ArenaConfig`, `ArenaConfigLoader`, `ConfigManager`, `MessagesManager`.
|
||||
- `floor/` — `FloorManager`, tick-batched floor generation/removal/restoration.
|
||||
- `session/` — `PlayerSession`, `SessionManager` (single-arena-membership enforcement).
|
||||
- `model/` — `PlayerState` snapshot/restore.
|
||||
- `command/` — `BlockPartyCommand` (single entry point, dispatches to handlers).
|
||||
- `listener/` — connection/quit handling and gameplay restrictions.
|
||||
- `scoreboard/` — interval-based sidebar scoreboard.
|
||||
- `reward/` — console-command reward dispatch.
|
||||
- `persistence/` — async SQLite-backed stats (`StatsDatabase`, `StatsManager`).
|
||||
- `placeholder/` — optional PlaceholderAPI expansion, loaded only when PAPI is present.
|
||||
- `util/` — sound/location helpers.
|
||||
Reference in New Issue
Block a user