No description
Find a file
2026-06-14 13:53:35 +02:00
.cursorj Initialer Commit 2026-06-14 13:53:35 +02:00
.idea Initialer Commit 2026-06-14 13:53:35 +02:00
client Initialer Commit 2026-06-14 13:53:35 +02:00
gradle/wrapper Initialer Commit 2026-06-14 13:53:35 +02:00
server Initialer Commit 2026-06-14 13:53:35 +02:00
shared Initialer Commit 2026-06-14 13:53:35 +02:00
.gitignore Initialer Commit 2026-06-14 13:53:35 +02:00
build.gradle.kts Initialer Commit 2026-06-14 13:53:35 +02:00
gradle.properties Initialer Commit 2026-06-14 13:53:35 +02:00
gradlew Initialer Commit 2026-06-14 13:53:35 +02:00
gradlew.bat Initialer Commit 2026-06-14 13:53:35 +02:00
README.md Initialer Commit 2026-06-14 13:53:35 +02:00
settings.gradle.kts Initialer Commit 2026-06-14 13:53:35 +02:00

HordeGame

A Kotlin-based virtual tabletop assistant for tabletop RPG sessions. HordeGame provides real-time dice rolling with visibility controls, chat, character sheet change tracking, and session history export.

Architecture

Module Description
shared Shared data models, DTOs, and WebSocket message types
server Ktor REST + WebSocket backend (port 8080)
client Compose Desktop client + HTTP test utilities

Stack: Kotlin 2.2.0, Ktor 3.0.1, Compose Desktop 1.7.1, kotlinx.serialization

Prerequisites

  • JDK 17 or newer
  • Gradle (wrapper included)

Running the Server

./gradlew :server:run

The server starts at http://localhost:8080.

Health check: GET /health

Running the Desktop Client

./gradlew :client:run

The client provides a full game UI:

  • GM: see all connected players (online/offline), view each player's roll history, roll any dice type with count and visibility, ping players to roll
  • Players: join session, roll dice (type + count), receive GM pings
  • Persistence: rolls saved to rolls/ on server and ~/.hordegame/rolls/ on client; reload via Reload Rolls button or RELOAD_ROLLS WebSocket message

HTTP Test Clients

With the server running:

./gradlew :client:runTestClient
./gradlew :client:runHistoryTestClient

REST API

Endpoint Method Description
/api/session/create POST Create a new GM session
/api/session/join POST Join session with invite code
/api/session/{id} GET Public session info
/api/session/{id}/auth POST GM authentication
/api/session/{id}/rolls GET Recent dice rolls (requires X-Player-ID)
/api/session/{id}/history GET Action history with filters
/api/session/{id}/history/search GET Search history (?q=term)
/api/session/{id}/statistics GET Session statistics
/api/session/{id}/export GET Export history (GM only, ?format=JSON|CSV|HTML)

WebSocket Protocol

Endpoint Headers Purpose
/ws/gm/{sessionId} X-GM-Password GM connection
/ws/player/{sessionId} X-Player-ID, X-Player-Name, X-Invite-Code Player connection

Message prefixes:

  • ROLL:{json} — Roll dice (RollDiceRequest with diceType, count, visibility)
  • PING_PLAYER:{json} — GM pings a player (PingPlayerRequest)
  • RELOAD_ROLLS — Reload all rolls from server disk
  • VISIBILITY:{rollId}:{visibility} — GM changes roll visibility
  • CHAT:{json} — Send chat message
  • CHARACTER:{json} — Record character sheet change
  • PING — Keepalive (responds with PONG)

Server messages: JSON-encoded GameMessage variants (DiceRolled, PlayerJoined, ChatMessage, etc.)

Dice Types

D4, D6, D8, D10, D12, D20, D100, and Coin Flip (Heads/Tails). Roll 120 dice at once.

Dice Visibility

Mode Who sees the roll
HIDDEN Rolling player only
GM_ONLY Rolling player + GM
ALL_VISIBLE Everyone in session

Building & Testing

./gradlew build
./gradlew :server:test

Data Persistence

  • Sessions and players are in-memory (lost on restart)
  • Action history is persisted to history/{sessionId}.jsonl

Project Status

Core server functionality is implemented: sessions, dice, WebSocket realtime, history, and export. The Compose Desktop client provides a minimal UI scaffold. Production hardening (persistent sessions, authentication, deployment) is not yet in place.