Releases: castledking/Chess
Release list
v1.0.5: CPU opponents, Chess Hub, and web dashboard play
Chess v1.0.5
Chess v1.0.5 adds three major features: a built-in engine opponent you can play from the
command line, a cross-server hub that links every connected server into a shared roster, and a
web dashboard at castled.codes where you can challenge in-game players and play moves through
the browser.
Added
CPU opponent (/chess duelcpu)
Play against a built-in engine at one of ten difficulty levels. The bot runs off the server
threads — it receives an immutable FEN snapshot and never touches the live board — so it never
blocks a click handler or a clock tick.
/chess duelcpu <1-10> <time>
Difficulty 1 plays like a beginner: it searches only a couple of moves deep and deliberately
plays a worse move most of the time. Difficulty 10 searches deeper but still within a
wall-clock budget, so a move always exists and the bot never outlasts a player's patience. The
levels vary both depth and intentional error rate, because a shallow search alone still takes
every hanging piece and then makes an alien-looking move — erring on purpose reads far more
like a real beginner.
The bot holds a colour, has a clock, and can be checkmated. Everything downstream treats it as
a participant who happens never to be online, which the views and messaging already handled.
Its answer is not trusted: before it is applied the game is rechecked, the notation is parsed
defensively, and an illegal move resigns the bot rather than corrupting the game.
Chess Hub — cross-server play
Servers dial out to a central hub over a WebSocket and publish who is online. Tab completion
now offers players from every server on the network, not just this one.
# settings.yml — added in this version
network:
enabled: true # join the hub on startup (default: true)
url: wss://castled.codes/api/chess/ws
label: "" # defaults to the server MOTDZero configuration. A server generates its own key on first start and writes it back to
settings.yml. The hub has never seen the key before and does not need to: the key is the
identity. Nothing has to be pasted in to take part. The server name defaults to the MOTD so it
appears recognisable without being asked to name itself.
The roster is sent whole rather than as deltas, so a server that misses a frame recovers on
the next one. It is held locally and answered from memory because tab completion asks on the
main thread and must not wait on a network. Reconnection backs off so a hub restart does not
require restarting every server attached to it.
The hub refuses offline-mode servers outright. Players are matched by Mojang UUID, and offline
mode derives UUIDs from names, so two such servers can mint the same UUID for different people
— across a shared network that is an impersonation hole rather than an inconvenience.
Duelling someone who is only on another server now says "That player is on another server"
rather than claiming they are offline.
Web dashboard play
A web admin at castled.codes can challenge an in-game player, and the in-game player can
accept and play a real game through the browser.
Challenging from the dashboard:
- Click a player in the online list.
- Pick a time control (1, 5, 10, or 30 minutes).
- Choose a display name (shown in-game and on the board).
- Send the challenge.
The in-game player receives a normal duel request and accepts with
/chess accept <name>. The dashboard board opens automatically once the game starts.
Playing from the dashboard:
Click two squares to attempt a move in UCI notation. The move is relayed through the hub to
the server, which validates it against the engine. Illegal moves are silently rejected and the
board re-renders from the real position on the next poll.
The web player is held to the same standard as a bot: it is refused unless it really is that
participant's turn and the engine accepts the move in the position it lands in. A browser is
the least trustworthy source of a move in the system, so nothing about one is assumed.
Multi-word names: /chess accept Castled King works. All tokens after the subcommand are
joined into a single name.
Clock sync: The game clock publishes to the hub every few seconds in addition to after
moves, so the dashboard's extrapolated countdown stays in sync.
FEN, fifty-move clock, and threefold repetition
The engine now tracks a halfmove clock, a move number, and a count of how often each position
has occurred. Both draws are applied automatically rather than offered as a claim — nobody
will claim a draw against an engine, and a game with no pawn moves left could otherwise run
forever.
FEN loading and UCI move notation are also in, which is what lets the bot run off the server
threads and what lets a remote board read the position.
Changed
- Tab completion now includes remote players from the network roster for
/chess duel,
/chess accept,/chess decline, and/chess watch. /chess duelon a remote player says "That player is on another server" instead of
"Your requested opponent is not online."- The watch broadcast asks the bot or web participant for its own name instead of reading
from Bukkit, so spectating a CPU or web game works. - Config upgrades are tested: an upgraded server picks up new settings by merging in
whatever the bundled default has and it lacks. Tests now pin that an existingsettings.yml
gains every key the code reads, that explicit values survive the merge, and that nothing
quietly stays at a default forever.
Commands
/chess duel <player> <time>
/chess duelcpu <1-10> <time> (new)
/chess accept <player> (supports multi-word names)
/chess decline <player> (supports multi-word names)
/chess watch <player>
/chess open
/chess help
Configuration
settings.yml gains a network section:
network:
enabled: true
url: ""
label: ""When network.enabled is true and a hub URL is configured, the server connects on startup
and begins exchanging rosters. When disabled or misconfigured, an OfflineNetwork stands in
and everything works as before — tab completion shows only local players.
Existing installs need no editing. Chess merges keys missing from an on-disk config with the
bundled defaults at startup, so the network section is added automatically.
Verification
gradle clean buildsucceeds.- Tab completion for
/chess duel,/chess accept,/chess decline, and/chess watch
includes remote players from the network roster cache. - A headless game between two bots drives the same select, move, promote and toggle sequence
the plugin performs, asserts the engine accepts every move the bot proposes, and verifies the
game terminates via the fifty-move or repetition rules. - The dashboard board renders a square grid and relays moves through the hub to the server.
Upgrade Note
Replace the previous Chess.jar and fully restart the server. Chess will overwrite
plugins/Chess/resourcepack.zip with the bundled pack during startup.
The resource pack is unchanged from v1.0.4. The network section in settings.yml is added
automatically when absent — no manual edits are required. If you want to join the hub, set
network.url to your hub address; otherwise leave network.enabled: false and everything
works as before.
Chess v1.0.5 targets Java 21 and Minecraft 1.21.11 on Spigot, Paper, or Folia.
v1.0.4: Chess runs on Spigot
Chess v1.0.4
Chess v1.0.4 runs on Spigot. Where Paper's Dialog API is unavailable the board is drawn from
Bukkit inventories instead, and the plugin picks the right one automatically. Paper and Folia are
unaffected and keep the dialog board.
Added
- Inventory board: A second board rendered from Bukkit inventories, using no Paper API at all.
A chess board needs 64 squares and a chest holds 54, so it spans a six-row chest for the six
ranks furthest from you and the two rows of your own inventory nearest it for the two closest —
the two read as one continuous board. Your items are held aside while a board is open and given
back when it closes. - Automatic board selection: The plugin detects the Dialog API at startup and uses the dialog
board where it exists, the inventory board where it does not. The startup log line records which
it chose. ui.modeinsettings.yml(auto|dialog|inventory):autofollows the server.
inventoryforces the inventory board even on Paper.dialogon a server without the Dialog API
is refused with a warning rather than honoured, because honouring it would leave players with no
board at all.
Changed
- Scheduling picks a backend by platform: Paper and Folia keep the region-aware schedulers,
which Folia requires because its world state is split across region threads. Spigot uses the
legacy Bukkit scheduler. The plugin's rule is unchanged either way: authoritative game state is
mutated on the global region, which on Spigot is simply the main thread. - The clickable
[Watch Game]broadcast survives on both: Paper renders it with Adventure as
before, Spigot with the BungeeCord chat components it bundles instead, so the click and hover
work everywhere. /chess watchnow answers when spectating is unavailable instead of doing nothing. The
inventory board refuses spectators, because it borrows the viewer's own inventory to draw the
board and that is not a price to charge someone who is not playing.
Scope of the inventory board
It covers core chess: the board, moves, legal-move highlights, promotion, draw and resign.
These are dialog-board features and are inactive on the inventory board:
- Premoves, including the ghost pieces and blue highlights
- Spectating via
/chess watch - Focus mode
- The last-move highlight
- The on-board clock
The clock still runs. It is simply not drawn on the inventory board, so a player can still lose
on time there without a visible countdown. Use the dialog board on Paper if that matters to you.
Known limitation
Because the board occupies your inventory, your items are held in memory while it is open and
restored when it closes, when you resign, when you disconnect, or when the plugin disables. If the
server process is killed outright while a board is open, that in-memory copy goes with it and those
items are lost. Closing the board, ending the game, or a clean server stop all restore normally.
Configuration
settings.yml gains ui.mode above the existing ui.dialog block:
ui:
mode: auto
dialog:
...The existing ui.dialog keys are shared by both boards where they make sense, so
show-legal-moves and orientation-follows-player apply to the inventory board too. The
dialog-only keys (title, allow-escape-close, show-coordinates, show-captured-pieces,
square-button-width) are ignored when the inventory board is active.
Existing installs need no editing. Chess merges keys missing from an on-disk config with the
bundled defaults at startup, so ui.mode is added automatically and defaults to auto.
Commands
/chess duel <player> <time>
/chess accept <player>
/chess decline <player>
/chess watch <player>
/chess open
/chess help
Commands are unchanged from v1.0.3. /chess watch reports that spectating is unavailable when the
inventory board is active.
Verification
- 41 tests pass across five suites.
InventoryLayoutTestis new and pins the mapping between chess squares and inventory slots:
every square round-trips through its slot for both colours, no two squares share a slot, all 64
are placed, and the spare ninth column of each row holds no square. An error there would quietly
move the wrong piece rather than throw.- A scan of the compiled classes confirms every reference to a Paper or Adventure class sits in a
class that only loads on a server providing it — the dialog builders, the Adventure broadcaster,
and the region scheduler backend. The platform detector names those classes only as strings, so
it loads anywhere. gradle clean buildsucceeds.
Upgrade Note
Replace the previous Chess.jar and fully restart the server. Chess will overwrite
plugins/Chess/resourcepack.zip with the bundled pack during startup.
The resource pack is unchanged from v1.0.3 — the inventory board's piece models, item definition
and GUI background all shipped already. If you are coming from v1.0.2 or earlier, the pack's asset
namespace changed in v1.0.3 and the updated pack must reach clients or pieces will not render
correctly; see the v1.0.3 notes.
Chess v1.0.4 targets Java 21 and Minecraft 1.21.11 on Spigot, Paper, or Folia.
v1.0.3: premovable castling, the vertical castling easter egg, and an in-tree engine
Chess v1.0.3
Chess v1.0.3 fixes two premove bugs from v1.0.2 — castling could not be queued as a premove, and
premoving a capture onto a checked king drew a missing-glyph box — and adds an opt-in vertical
castling easter egg. Internally the chess engine now lives inside the plugin, so Chess no longer
depends on an external engine artifact.
Fixed
- Castling is premovable again: Castling could not be queued as the first premove. The
premove generator offered a king only its eight adjacent squares, so the two-square castling
destination was rejected and the whole queue was cancelled. Because only the head of the queue
is validated at queue time, castling already worked from the second position onwards, which is
why this went unnoticed in v1.0.2. Both premove generators now offer castling: the one used for
a selected piece, and the one used for a ghost selection on the projected board. - Premoving a capture onto a checked king no longer renders a raw glyph box: That square is
both the checked king's square and a premove destination, so it took the red check wash while
displaying the capturing piece as a ghost. The pack bakes the check wash for the two kings only
— nothing else can be in check — so the result was a request for a codepoint the pack does not
declare, and the client drew a tofu box. Such a square now stays premove blue and shows the
ghost piece, which is also what it means: by the time the premove plays, the king may have moved
away. Premove source squares follow the same rule, so a king premoved out of check shows its
origin in premove blue rather than check red.
Added
- Vertical castling easter egg (
easter-egg.enable-vertical-castling, defaultfalse): The
Pam-Krabbé castling. Promote a pawn to a rook on your king's own file and that rook has never
moved, so the king may castle with it straight up the board — the king moves two squares towards
it and the rook lands on the square the king crossed. WhiteKe1with a promoted rook one8
becomesKe3,Re2; Black castles the same way down the board. Every normal castling
restriction still applies: the king must not have moved, the file between them must be empty, and
the king may not castle out of, through, or into check. Both squares up the file highlight — the
first as an ordinary king step, the second as the castle — and the move is premovable like any
other castling.
Changed
- The chess engine is now vendored in-tree: The engine's rules, board, and game implementations
live in the plugin undercodes.castled.chess.engine, the same package the build previously
relocated them to. The shipped JAR layout is unchanged, and the plugin still has no runtime
engine dependency. Chess no longer needs the externalpocket-chess-apiandpocket-chess-common
artifacts, and the Guice compile dependency is gone with them. - Castling is derived from board geometry rather than fixed squares: Move results now carry the
rook's half of a castling move instead of a flag, so the rook's squares are no longer re-derived
from the king's destination file. Castling rights track unmoved rooks by square rather than
king-side and queen-side flags. Standard and vertical castling run through the same code. - Promotion is applied by the engine: Choosing a promotion piece previously wrote to the board
directly, so the engine never learned a promotion had happened. It now goes through the engine,
which is what lets a promoted rook count as never having moved.
Resource Pack
- The pack namespace changed from
pocketchesstochess.assets/pocketchess/is now
assets/chess/, and the board font is addressed aschess:board. Everything inside the pack
already used theminecraftnamespace and is unaffected. - The
pack.mcmetadescription is nowChess, replacing a leftover generated string. - No textures or codepoints were added or removed this release.
The pack SHA-1 has therefore changed and clients will redownload it, even though the board
looks identical.
Configuration
settings.yml gains an easter-egg section:
easter-egg:
enable-vertical-castling: falseExisting installs do not need editing. Chess merges any keys missing from an on-disk config with
the bundled defaults at startup, so the new section is added automatically and the easter egg stays
off until it is switched on.
Commands
/chess duel <player> <time>
/chess accept <player>
/chess decline <player>
/chess watch <player>
/chess open
/chess help
Commands are unchanged from v1.0.2.
Verification
- 35 tests pass across four suites:
CastlingTest(23),PremoveTest(8),GlyphPackContractTest
(3), andDialogContentGrowthTest(1). CastlingTestcovers standard king-side and queen-side castling, blocked paths, castling through
an attacked square, lost rights, the vertical easter egg on and off, and the premove behaviour of
each.GlyphPackContractTestis new. It walks every combination of piece, highlight, and square colour
and asserts the resource pack declares the codepoint the plugin emits. A missing glyph is
invisible to every other test — the dialog still builds and only a screenshot shows the damage —
so this pins the contract between the code andboard.json.gradle clean buildsucceeds.
Upgrade Note
Replace the previous Chess.jar and fully restart the server. Chess will overwrite
plugins/Chess/resourcepack.zip with the updated bundled pack during startup.
Because the pack's asset namespace changed, this release requires the updated pack to reach
clients; running v1.0.3 against the v1.0.2 pack leaves the board font unresolved, and pieces will
not render correctly. If ResourcePackManager merges the Chess pack, allow it to rebuild and
redistribute the combined pack. If the pack is hosted or merged manually, replace that external
copy with the new plugins/Chess/resourcepack.zip. Players may need to reconnect after the
updated pack is available.
Chess v1.0.3 continues to target Paper 1.21.11, Java 21, and compatible Folia servers.
v1.0.2: premoves, spectating, focus mode, and check highlighting
Chess v1.0.2
Chess v1.0.2 adds premoves (queue moves while your opponent is thinking), a spectator system
with a [Watch Game] chat broadcast, a focus mode that declutters the dialog for viewers,
and red check highlighting on kings.
Added
- Premove queue: Players can queue moves while it is not their turn. Click a piece, click a
destination, and the move is queued. Multiple premoves stack — each opponent move fires the
oldest queued premove. All queued premoves display simultaneously with blue highlights and ghost
pieces on their destination squares. - Premove stacking by clicking ghost pieces: Clicking a ghost piece (a premove destination)
selects the piece at its simulated position, showing legal moves from where it would be after
prior premoves execute. The premove chain is simulated on-the-fly so multi-move premove
sequences show correct legal-move highlights at each step. - Cancel Premoves button: A dedicated
[Cancel Premoves]button replaces[Resign]when
premoves are queued. Clicking it clears the entire queue. - Check highlighting: Kings in check now render on a red background tile (4 piece-on-red
textures + 2 empty red tiles). TheHighlight.CHECKenum and codepointsU+EB06/EC06were
added to the glyph system. /chess watch <player>: Spectate any active game. Opens a read-only dialog board for the
watcher. The target player can be either player in the game.[Watch Game]broadcast: When a game starts, all online players (except the two players)
receive a clickable<green><bold>[Watch Game]</bold></green> Player1 vs Player2chat message.
Clicking it suggests/chess watch <white>.- Focus mode: A
[Focus]/[Unfocus]toggle in the dialog controls hides the player names
line, spectating label, and captured-piece lists. Viewers see only[Flip]and[Focus]in the
controls line (resign and draw are hidden). Players see all controls plus the focus toggle.
Changed
- Legal-move highlights use premove geometry when off-turn: When a piece is selected on the
opponent's turn, legal-move highlights now usePremoveMoveCalculator(chessground-style
geometric validation) instead of the engine's strict legal-move generator. This shows relaxed
pawn diagonals, sliding-through-opponent paths, and other premove-valid squares as green
highlights. - Highlight priority reordered:
SELECTEDandLEGALnow take priority overPREMOVEwhen a
piece is selected, so legal-move highlights are visible even when premove blue tiles overlap. - Premove validation is geometric-only: Pawn diagonals are always allowed (no target-piece
check), sliding pieces are only blocked by own pieces, and no check/castling/en-passant
validation is performed at queue time. Strict validation happens at play time via the engine. - Removed "Your selected piece cannot move to that square" error message: Failed move
attempts no longer show the info-line error text. - Intermediate premove squares lose ghost, keep blue highlight: When the same piece is premoved
multiple times in a chain, intermediate waypoints show the blue empty tile but no ghost piece.
Only the final destination shows the ghost.
Resource Pack
- Added 24 premove piece textures (12 pieces x 2 light/dark variants) at codepoints
U+E900..E917. - Added 2 empty premove tiles at
U+E018/19. - Added 4 check king textures (white/black x light/dark) at
U+EB06/EC06andU+EB0C/EC0C. - Added 2 empty check tiles at
U+E01A/1B. - Updated
board.jsonwith premove and check providers for all piece types.
Commands
/chess duel <player> <time>
/chess accept <player>
/chess decline <player>
/chess watch <player>
/chess open
/chess help
Verification
- All 8 premoves tests pass: premove queue, 8-pawn premove storm, scholar's mate premove,
premove play-through, capture premove, discard when blocked, and same-piece stacking. - DialogContentGrowth test passes.
gradle clean buildsucceeds with zero warnings.- Tested premove stacking with same-piece and different-piece sequences.
- Tested focus mode toggle for both players and spectators.
- Tested
/chess watchcommand and[Watch Game]broadcast.
Upgrade Note
Replace the previous Chess.jar and fully restart the server. Chess will overwrite
plugins/Chess/resourcepack.zip with the updated bundled pack during startup.
If ResourcePackManager merges the Chess pack, allow it to rebuild and redistribute the combined
pack. If the resource pack is hosted or merged manually, replace that external copy with the new
plugins/Chess/resourcepack.zip; updating only the plugin JAR will leave clients on the old board
textures. Players may need to reconnect after the updated pack is available.
Chess v1.0.2 continues to target Paper 1.21.11, Java 21, and compatible Folia servers.
v1.0.1: make the native dialog chessboard seamless and stop oversized square glyphs from scrolling
Chess v1.0.1
Chess v1.0.1 gives the native dialog board a cleaner, continuous playing surface. The gaps
between its 64 clickable buttons are now covered by the board artwork, while every square remains
an independent action with the same move handling, highlights, and tooltips as before.
Fixed
- Removed visible seams between board squares: Board textures now span the full spacing used
by Minecraft's native dialog grid, creating one continuous 8x8 checkerboard instead of 64
separated tiles. - Stopped chess images from sliding from side to side: Oversized square glyphs now use
invisible font advances that keep their measured labels inside the buttons. This prevents
Minecraft's overflowing-button-text marquee from activating. - Kept the full board interactive: The visual overdraw does not replace the native button
grid. All 64 squares retain their individual click targets, coordinate and piece tooltips,
legal-move handling, and stale-click protection.
Changed
- Regenerated every normal, selected, and legal square combination as a 22x22 board tile so each
image covers the button and the two-pixel gap to the next cell. - Increased the piece canvas to 17x17 pixels and centered it within each board tile, keeping the
pieces clear and proportional on the larger seamless squares. - Removed the old inset tile borders so neighboring light, dark, selected, and legal squares meet
cleanly without doubled outlines. - Plain piece glyphs used in the captured-piece display remain at their original size and are not
affected by the board-only spacing changes.
Resource Pack Tooling
- Added a repeatable board-tile generator for rebuilding all 78 square and piece states from the
source piece artwork. - Added geometry verification covering tile dimensions, font metrics, opaque tile edges, and the
final measured label width that prevents scrolling. - The bundled resource pack continues to be packaged inside
Chess.jarand exported to
plugins/Chess/resourcepack.zipduring startup.
Verification
- Verified all 78 board textures at a 22-pixel visible pitch.
- Verified each composed button label measures 16 pixels, matching the available label area in a
20-pixel native dialog button. - Validated the generated resource-pack ZIP and confirmed it is bundled in the shaded plugin JAR.
- Built the complete plugin successfully with Java 21 and Gradle.
- Confirmed the updated board in game with a continuous checkerboard and stationary piece
artwork.
Upgrade Note
Replace the previous Chess.jar and fully restart the server. Chess will overwrite
plugins/Chess/resourcepack.zip with the updated bundled pack during startup.
If ResourcePackManager merges the Chess pack, allow it to rebuild and redistribute the combined
pack. If the resource pack is hosted or merged manually, replace that external copy with the new
plugins/Chess/resourcepack.zip; updating only the plugin JAR will leave clients on the old board
textures. Players may need to reconnect after the updated pack is available.
Chess v1.0.1 continues to target Paper 1.21.11, Java 21, and compatible Folia servers.

