Skip to main content

Nexal Boat Racing

A competitive boat racing minigame for Minecraft servers. Build tracks with a hotbar editor, run several races at once, and let players race laps through checkpoints with live positions, a per-player scoreboard, spectating, stats, leaderboards and reward commands for the podium.

Features​

  1. Multiple Concurrent Arenas - Run different races simultaneously across multiple arenas
  2. Checkpoint Anti-Cheat - Players must pass checkpoints in order; crossing a later one first sends them back to the last one they passed
  3. Real-Time Position Tracking - Positions from laps, checkpoints and the distance to the next checkpoint, on a flicker-free per-player sidebar that only racers and spectators see
  4. Finish Line Detection - Line-segment intersection catches fast boats crossing between ticks
  5. Boat Freezing Warmup - Boats frozen on armor stands during the final countdown for fair starts
  6. Configurable Races - Laps, player counts, lobby countdown, warmup and finish timeout per arena, with server-wide defaults for new arenas
  7. Reward Commands - Console commands per finish position (economy rewards, items)
  8. Spectator Mode - Finished racers watch the rest of the race; anyone can watch with /br spectate
  9. Player Statistics GUI - Totals plus per-arena best times, best laps, races, wins and win rate
  10. Leaderboard GUI - Global wins and per-arena best times with tab switching and pagination
  11. Admin Menu - /br admin opens a hub with the plugin configuration, the arenas, and export/import
  12. Arena Settings GUI - Every race setting, the schedule, rewards, enabling and race control from one screen
  13. Arena Editor Mode - Hotbar tools for lobby, start positions, finish line and checkpoints, with a live action bar
  14. Crash-Safe Inventories - Racers', spectators' and editors' items are backed up on disk and given back after a crash
  15. Cron Scheduling - Open race lobbies automatically on a schedule
  16. Checkpoint Holograms - Numbered holograms above checkpoints, no hologram plugin needed
  17. PlaceholderAPI Integration - 37 placeholders for scoreboards, tab and chat
  18. Dual Storage - JSON file or MySQL/MariaDB, with export and import to move between them

Technologies​

  • Paper/Spigot API 1.20.1+ - Minecraft server API
  • Utilizer - Configuration, messages, menus, tasks, holograms
  • ACF - Command framework
  • nexal-core - JSON and SQL persistence (MariaDB/MySQL)
  • cron4j - Race schedules
  • PlaceholderAPI - Placeholder integration (optional)

Commands​

/boatracing also answers to /br and /racing.

Player Commands​

CommandDescriptionPermission
/br or /br help [page]Show helpnexalboatracing.use
/br join [arena]Join a race. Without an arena: joins the only open lobby, or opens the arena browsernexalboatracing.join
/br leave (or /br quit)Leave your race or stop spectating; your items come backnexalboatracing.join
/br gui (or /br menu)Open the arena browsernexalboatracing.join
/br spectate \<arena>Watch a running racenexalboatracing.spectate
/br stats [player]View player stats (GUI)nexalboatracing.stats
/br leaderboard [arena] (or lb, top)Global wins, or the arena's best times (GUI)nexalboatracing.stats

Admin Commands​

Admin commands are hidden from players without the nexalboatracing.admin permission.

CommandDescriptionPermission
/br adminOpen the admin menu (console: the admin help)nexalboatracing.admin
/br admin help [page]Show the admin commandsnexalboatracing.admin
/br admin create \<name>Create an arena with the defaults from config.ymlnexalboatracing.admin
/br admin delete \<arena>Delete an arena (stops its race)nexalboatracing.admin
/br admin edit \<arena>Enter arena editor modenexalboatracing.admin
/br admin cancelLeave arena editor modenexalboatracing.admin
/br admin info \<arena>Open the arena settings (GUI; console: text)nexalboatracing.admin
/br admin listArena management screen (GUI; console: text)nexalboatracing.admin
/br admin setcron \<arena> [cron]Set the race schedule; without a schedule (or none) clears itnexalboatracing.admin
/br admin enable \<arena>Enable an arena (it must be fully set up)nexalboatracing.admin
/br admin disable \<arena>Disable an arena (stops its race)nexalboatracing.admin
/br admin start \<arena>Open a race lobbynexalboatracing.admin
/br admin forcestart \<arena>Start an open lobby's countdown below the minimum playersnexalboatracing.admin
/br admin stop \<arena>Stop the running race without resultsnexalboatracing.admin
/br admin reloadReload configs (they also reload by themselves when the files change)nexalboatracing.admin
/br admin exportExport all data to plugins/NexalBoatRacing/export.jsonnexalboatracing.admin
/br admin importImport plugins/NexalBoatRacing/export.json into the current storagenexalboatracing.admin

/br export and /br import, the paths up to 1.0.5, still work.

Permissions​

PermissionDescriptionDefault
nexalboatracing.use/br and /br helptrue
nexalboatracing.joinJoin and leave races, open the arena browsertrue
nexalboatracing.spectateWatch a running race with /br spectate or from the arena browsertrue
nexalboatracing.statsView stats and leaderboardstrue
nexalboatracing.adminAdmin commands and menusop
nexalboatracing.bypass.fullJoin a race at its player limit, while a start position is freeop
nexalboatracing.bypass.commandsUse any command during a raceop

Arena Setup​

From the admin menu​

  1. /br admin > Arenas > Create Arena, and type the name in chat
  2. In the arena settings, click the lobby, start positions, finish line or checkpoints to open the editor
  3. Set laps, players, countdowns, the schedule and rewards on the same screen
  4. Click Disabled to enable the arena once it is ready

Using Editor Mode​

  1. Create the arena: /br admin create myarena
  2. Enter editor mode: /br admin edit myarena (your inventory is stored and given back when you leave)
  3. Use the hotbar tools:
    • Lime Bed (slot 1) - Right-click to set lobby at your position
    • Armor Stand (slot 2) - Right-click to set start positions (auto-increments, up to 8). Shift-right to clear all
    • Fence Gate (slot 3) - Right-click then left-click 2 blocks for finish line
    • Ender Pearl (slot 4) - Right-click then left-click 2 blocks for checkpoint zones. Shift-right to clear all
    • Paper (slot 5) - Shows live arena setup status
    • Comparator (slot 8) - Opens the settings GUI for laps, players, rewards
    • Barrier (slot 9) - Exit editor mode (restores inventory)
  4. Open settings GUI from editor or via /br admin info myarena
  5. Enable the arena from the settings GUI or via /br admin enable myarena

An arena is ready once it has a lobby, a finish line and at least as many start positions as its minimum players. Checkpoints are optional. At most as many players can race as the arena has start positions, and an arena takes 2 to 8 players.

An arena cannot be edited while its race runs (stop it first), and no lobby opens on an arena an admin has open in the editor.

Without checkpoints (or with anti-cheat.require-checkpoints: false), a lap counts when the racer crosses the finish line further than they ever did: driving back and forth over the line does not add laps.

How a Race Runs​

  1. Lobby - A lobby opens when a player joins an idle arena, an admin starts one, or its schedule fires. Joining stores your inventory, experience, game mode and location, and clears your inventory.
  2. Countdown - Once the minimum players have joined (or an admin force starts), the lobby countdown runs.
  3. Warmup - Racers are teleported to their start positions in frozen boats; the last five seconds are counted down on screen.
  4. Racing - Boats are released. Pass every checkpoint in order and cross the finish line to complete a lap. Crossing a later checkpoint before the next one sends the racer back to the last checkpoint they passed (anti-cheat.respawn-on-skip). Positions rank laps first, then checkpoints, then the distance to the next checkpoint (or to the finish line once all are passed).
  5. Finishing - After the first finisher, the others have the finish timeout to cross the line. Finished racers spectate the rest of the race when spectator.enabled is on.
  6. End - Results are broadcast, stats saved, everyone gets their state back, then the reward commands run.

Leaving with /br leave or disconnecting after the start counts as a DNF; the player gets their items back at once and is free to play elsewhere. If the server stops mid-race (or while an admin is in the editor), the items are given back when the player next joins.

Configuration​

Most settings can be changed in game: /br admin > Configuration.

config.yml​

# Storage type: "json" or "sql"
# To move your data: /br admin export, change the type, restart, /br admin import
storage:
type: json
sql:
host: localhost
port: 3306
database: minecraft
username: root
password: ""

# Settings a new arena starts with. Each arena changes its own in /br admin info \<arena>.
defaults:
min-players: 4
max-players: 8 # At most 8: an arena has up to 8 start positions
laps: 3
lobby-countdown: 30 # Seconds to wait before teleporting to start
warmup-countdown: 10 # Seconds boats are frozen before race starts
finish-timeout: 30 # Seconds to wait for remaining racers after first finishes

boat:
type: OAK # OAK, SPRUCE, BIRCH, JUNGLE, ACACIA, DARK_OAK, MANGROVE, CHERRY, BAMBOO, PALE_OAK (1.21.4+)
invincible: true # Boats can't break during race
step-height: 1.5 # How high boats can climb (1.0 = one block)

spectator:
enabled: true # Finished racers watch the rest of the race instead of waiting in their boat
allow-join: true # Anyone can watch a running race with /br spectate \<arena>
gamemode: SPECTATOR # SPECTATOR, or ADVENTURE (flying and invisible)

fireworks:
enabled: true
amount: 5 # Fireworks per podium finisher
# Colour names (YELLOW, ORANGE, WHITE, SILVER, RED, LIME, AQUA...) or hex (#CD7F32)
colors:
first: [YELLOW, ORANGE]
second: [WHITE, SILVER]
third: ["#CD7F32", ORANGE]
other: [WHITE]

broadcast:
race-start: true # Broadcast when race lobby opens
race-end: true # Broadcast race results
scope: GLOBAL # Race results: GLOBAL (everyone) or LOCAL (only racers and spectators)

# Scoreboard (the lines are in messages.yml, under scoreboard)
scoreboard:
enabled: true
title: "<#5DADE2>\<bold>BOAT RACING"
update-interval: 10 # Ticks between updates (20 ticks = 1 second)

anti-cheat:
require-checkpoints: true # A lap only counts after every checkpoint, in order
respawn-on-skip: true # Crossing a later checkpoint than the next one sends the racer back to the last one passed

# Whole command names racers may use during a race, besides /br leave (without the /)
command-whitelist: []

checkpoint-holograms:
enabled: true
height-above-ground: 4.0
lines:
- "<gradient:#5DADE2:#73B9E8>\<bold>Checkpoint #%number%\</bold>\</gradient>"
- "\<gray>%number% / %total%\</gray>"

The sidebar's lines are updated in place, so it does not flicker. Racers see a sidebar of their own for the race: a player on the server's main scoreboard gets a private copy of it (with its teams) until the race ends, so other players never see the race sidebar. A player another plugin gave a scoreboard keeps it, with the sidebar added.

messages.yml​

Every message, the scoreboard lines, and the player menus (arena browser, leaderboard, stats) are in messages.yml, in MiniMessage format with sounds and titles. Keys added in an update fall back to the plugin's defaults until you add them to your file.

PlaceholderAPI Placeholders​

Arena ids are matched ignoring case and may contain underscores. Placeholders asked for off the main thread (async chat, tab plugins) return the value worked out on the main thread a moment before.

Player Statistics​

PlaceholderDescription
%boatracing_wins%Total wins
%boatracing_races%Total races
%boatracing_finished%Races finished (not DNF)
%boatracing_podiums%Total podium finishes
%boatracing_dnfs%Total DNFs
%boatracing_winrate%Win percentage
%boatracing_finish_rate%Finish percentage
%boatracing_wins_\<arena>%Wins in an arena
%boatracing_races_\<arena>%Races in an arena
%boatracing_best_\<arena>%Best race time in an arena
%boatracing_best_lap_\<arena>%Best lap time in an arena

Current Race​

PlaceholderDescription
%boatracing_in_race%"yes" when racing, else "no"
%boatracing_spectating%"yes" when spectating, else "no"
%boatracing_current_arena%Arena ID of the race you are in or watching
%boatracing_current_state%LOBBY, COUNTDOWN, WARMUP, RACING, FINISHING
%boatracing_current_position%Current position
%boatracing_current_racers%Racers in the race
%boatracing_current_lap%Current lap number
%boatracing_current_laps%Laps of the race
%boatracing_current_checkpoint%Last checkpoint passed this lap
%boatracing_current_checkpoints%Checkpoints per lap
%boatracing_current_time%Elapsed race time
%boatracing_current_best_lap%Your best lap this race

Leaderboards​

PlaceholderDescription
%boatracing_top_wins_\<pos>_name%Player name at position
%boatracing_top_wins_\<pos>_count%Win count at position
%boatracing_top_\<arena>_\<pos>_name%Player name in arena leaderboard
%boatracing_top_\<arena>_\<pos>_time%Best time in arena leaderboard
%boatracing_top_\<arena>_\<pos>_wins%Wins in arena leaderboard

Global Info​

PlaceholderDescription
%boatracing_arena_count%Total arena count
%boatracing_active_races%Currently active races
%boatracing_arena_\<id>_status%IDLE or the race state
%boatracing_arena_\<id>_players%Players in the arena's race
%boatracing_arena_\<id>_max%Arena max players
%boatracing_arena_\<id>_min%Arena min players
%boatracing_arena_\<id>_laps%Arena laps
%boatracing_arena_\<id>_name%Arena display name
%boatracing_arena_\<id>_enabled%"yes" or "no"

Database Schema​

With storage.type: json, everything is in plugins/NexalBoatRacing/data.json. With SQL, the plugin creates these tables; list and map columns hold JSON.

boatracing_arenas​

ColumnTypeKeyDescription
idVARCHAR(64)PKArena identifier
displayNameVARCHAR(64)Display name
worldVARCHAR(64)World name
lobbyX, lobbyY, lobbyZDOUBLELobby location
lobbyYaw, lobbyPitchFLOATLobby rotation
startPositionsTEXTStart positions (JSON)
finishX1, finishY1, finishZ1DOUBLEFinish line point 1
finishX2, finishY2, finishZ2DOUBLEFinish line point 2
finishLineSetBOOLEANFinish line defined
checkpointsTEXTCheckpoints (JSON)
lapsINTLap count
minPlayersINTMinimum players
maxPlayersINTMaximum players
lobbyCountdownINTLobby countdown seconds
warmupCountdownINTWarmup countdown seconds
finishTimeoutINTFinish timeout seconds
cronScheduleVARCHAR(64)Cron schedule
positionCommandsTEXTReward commands by position (JSON)
enabledBOOLEANArena enabled

boatracing_races​

ColumnTypeKeyDescription
idVARCHAR(36)PKRace UUID
arena_idVARCHAR(64)Arena identifier
start_timeBIGINTRace start timestamp
end_timeBIGINTRace end timestamp
lapsINTLaps configured
participantsTEXTParticipants with results and lap times (JSON)
completedBOOLEANRace completed

boatracing_player_stats​

ColumnTypeKeyDescription
playerIdVARCHAR(36)PKPlayer UUID
player_nameVARCHAR(16)Last known name
totalRacesINTTotal races
winsINTTotal wins
podiumsINTPodium finishes
dnfsINTDid not finish
bestTimesTEXTBest times per arena (JSON)
bestLapTimesTEXTBest lap times per arena (JSON)
updated_atBIGINTLast update timestamp

Key Legend: PK = Primary Key

Cron Schedule Examples​

ScheduleDescription
0 * * * *Every hour on the hour
0 12 * * *Every day at noon
0 18 * * sat,sunWeekends at 6 PM
*/30 * * * *Every 30 minutes

Installation​

  1. Download the plugin JAR
  2. Place it in your server's plugins folder
  3. Start or restart the server
  4. Optionally install PlaceholderAPI for placeholders
  5. Set the storage in plugins/NexalBoatRacing/config.yml (JSON works out of the box)
  6. Create your first arena with /br admin

Dependencies​

  • Paper or Spigot 1.20.1+
  • PlaceholderAPI (optional, for placeholders)