Skip to content

Releases: castledking/Chess

v1.0.5: CPU opponents, Chess Hub, and web dashboard play

Choose a tag to compare

@castledking castledking released this 18 Aug 01:19

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 MOTD

Zero 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:

  1. Click a player in the online list.
  2. Pick a time control (1, 5, 10, or 30 minutes).
  3. Choose a display name (shown in-game and on the board).
  4. 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 duel on 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 existing settings.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 build succeeds.
  • 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

Choose a tag to compare

@castledking castledking released this 16 Aug 23:57

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.

The inventory 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.mode in settings.yml (auto | dialog | inventory): auto follows the server.
    inventory forces the inventory board even on Paper. dialog on 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 watch now 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.
  • InventoryLayoutTest is 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 build succeeds.

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

Choose a tag to compare

@castledking castledking released this 16 Aug 18:11

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, default false): 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. White Ke1 with a promoted rook on e8
    becomes Ke3, 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 under codes.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 external pocket-chess-api and pocket-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 pocketchess to chess. assets/pocketchess/ is now
    assets/chess/, and the board font is addressed as chess:board. Everything inside the pack
    already used the minecraft namespace and is unaffected.
  • The pack.mcmeta description is now Chess, 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: false

Existing 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), and DialogContentGrowthTest (1).
  • CastlingTest covers 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.
  • GlyphPackContractTest is 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 and board.json.
  • gradle clean build succeeds.

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

Choose a tag to compare

@castledking castledking released this 15 Aug 03:32

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.

Premove feature

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). The Highlight.CHECK enum and codepoints U+EB06/EC06 were
    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 Player2 chat 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 use PremoveMoveCalculator (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: SELECTED and LEGAL now take priority over PREMOVE when 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/EC06 and U+EB0C/EC0C.
  • Added 2 empty check tiles at U+E01A/1B.
  • Updated board.json with 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 build succeeds with zero warnings.
  • Tested premove stacking with same-piece and different-piece sequences.
  • Tested focus mode toggle for both players and spectators.
  • Tested /chess watch command 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

Choose a tag to compare

@castledking castledking released this 13 Aug 08:39

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.jar and exported to
    plugins/Chess/resourcepack.zip during 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.