Content generated with AI — it may contain mistakes.

Reference

Database

The thirteen tables, what keys them, and what to know before touching them by hand.

Storage is ExyliaLib's. database.yml is written on first start and defaults to H2; MySQL, MariaDB, PostgreSQL and MongoDB are the other engines, and a redis block sits alongside them. Tables are created and migrated from the record definitions, so there is no schema file to apply.

The thirteen tables

TableKeyHolds
clansid (UUID text)Name, leader, balance, open, friendly fire, home, banned list, DTR, DTR freeze, EXP
clan_membersuuidThe player's clan and their rank
clan_rolesidEvery rank of every clan: name, weight, permissions, whether it is the default
clan_relationsclanId:targetClanIdOne directional opinion, ALLY or RIVAL
clan_invitesplayerUuid:clanIdA standing invitation
clan_claimsidOne rectangle: world, minX, minZ, maxX, maxZ, baseY
clan_statsclanIdKills, deaths, playtime seconds
player_statsplayerUuid:clanIdThe same per player per clan, plus the last name seen
clan_logsidAction, actor, target, detail, timestamp
clan_mailsidType, sender, recipient, subject, body, sent, expires, read list, deleted list, pinned
lfc_profilesplayerUuidStatus, posted, last posted, expires, the answers
lfp_postingsclanIdStatus, posted, last posted, expires, description, the answers
lfp_applicationsplayerUuid:clanIdStatus, applied, decided, message

What the keys buy you

Several rules that would otherwise need enforcing are enforced by the key itself:

  • A player is in one clan. clan_members is keyed by the player's UUID, so a second membership row cannot exist.
  • A clan has one claim, one LFP posting. Both are keyed by the clan id.
  • A player has one LFC profile, and one application per clan.
  • An invitation is unique per pair, and so is a relation.

Two indexes

IndexOnFor
idx_cl_clan_tsclan_logs (clanId, timestamp DESC)The logs menu: filter by clan, newest first, take a page
idx_cm_clan_sentclan_mails (clanId, sentAt DESC)The inbox, the same way

Both make a page a bounded read rather than a scan.

Columns worth knowing about

ColumnFormat
clans.bannedPlayersComma-separated UUIDs
clan_roles.permissionsComma-separated permission names. An unknown name is skipped when read
clans.homeLocationA serialised location that carries the server it was set on — server,world,x,y,z,yaw,pitch. null when unset
clan_mails.readByPlayers / deletedByPlayersComma-separated UUIDs — which is how read and deleted are per member off one row
lfc_profiles.data / lfp_postings.dataThe serialised answers
*.statusACTIVE / EXPIRED for postings and profiles; PENDING / ACCEPTED / REJECTED for applications

What is not in the database

  • Alliance requests. Held in memory with a 60-second expiry, so a restart drops the pending ones.
  • Chat channels. Per session; everybody is back on global after a restart.
  • Kill streaks. Per session, and reset by dying.
  • Camp, rally, focus and regroup markers. All in memory.
  • The clan level. Derived from clans.exp on every read, never stored.
  • Claim ownership of members. Derived from clan_members; the claim row names only the clan.

Caches

Clans, members, ranks, relations, claims and invitations are held in memory and written through on change, so the hot path never touches the database. Two things are cached with a TTL instead:

CacheTTLWhy
Each leaderboard ranking30 sA scoreboard asks four times a second
The online roster per clan and per alliance1 sThirty slots × several viewers × four times a second
Editing rows by hand needs a restart

The caches are loaded at enable and kept in step by the plugin's own writes. A row changed directly in the database is not noticed, and will be overwritten the next time that clan changes. Use /clanadmin where it covers what you need, and stop the server where it does not.

Startup

The repositories are read asynchronously, so the plugin finishes enabling before the tables have answered. Until they do, every lookup says no clan — the safe way to be wrong for a moment. Once the caches are true, anybody already online has their join replayed, so a player who logged in during that window is not left invisible to their own clan.

If the read fails outright, the console says so and the plugin stays idle rather than starting to write against caches it knows are empty.

Something missing on this page? Tell us on Discord