Storage
SQLite with no setup for a single server, MySQL for a network, and what each table holds.
storage:
type: sqlite
table-prefix: dialogforge_
mysql:
host: 127.0.0.1
port: 3306
database: dialogforge
username: root
password: ''
use-ssl: false
pool-size: 6sqlite, the default, writes to data.db in DialogForge's own folder and needs no setup.
mysql is for a network that wants player state shared across servers. Both go through the
same HikariCP pool and the same schema. table-prefix keeps the tables apart if you are
sharing a database with something else.
HikariCP and both JDBC drivers are declared as libraries in plugin.yml and downloaded by
the server at startup through the Bukkit library loader, so there is nothing to install by
hand and only the driver matching storage.type is ever touched.
Tables
Every table name is prefixed with storage.table-prefix.
| Table | What it holds |
|---|---|
meta | schema_version, currently 1 |
player_state | One row per player: the last menu and page they had open |
first_open | One row per player per menu, so auto-open fires exactly once each |
saved_inputs | One row per player, menu, page and input key, for anything with persist: true |
first_open is its own table rather than a column on player_state because
player_state is keyed by uuid alone and the first-open flag needs one row per menu, not
one for the whole player.
Where a lock's answer lives
A lock is satisfied by reading the matching row out of saved_inputs, not
by a record of its own. That is what makes unticking the box on a rules page and pressing
confirm hold the player again if their agreement is ever cleared some other way.
Everything is async
Every storage call returns a CompletableFuture and runs off the main thread on the
storage executor. Results are brought back to the main thread before anything touches the
Bukkit API, so a slow query never freezes the server, and a database outage on join does
not hold a player in a lock they cannot possibly answer.