Astral Realms Documentation Help

Overview

AstralHeads is a player-head ("HeadDB"-style) catalog plugin: it stores a searchable library of decorative player-head ItemStacks (community skin heads pulled from a public catalog, plus every network player's own skin) in a shared MariaDB table, and exposes it in-game through a menu-driven /heads command, a full-text search, per-player favorites, and a coin-priced "buy" flow. plugin.yml declares AstralCore and AstralSync as hard dependencies (main: com.astralrealms.heads.AstralHeads, api-version: '26.1').

Two-module architecture

The plugin ships as two independent builds, both named AstralHeads but built from different bases and pointed at the same heads MariaDB schema (database.properties):

Module

Base class

Role

Paper

com.astralrealms.heads.AstralHeads extends AstralPaperPlugin

The player-facing side: /heads command, buy/favorite/search actions, the heads/head/category placeholder namespaces, the heads ItemStackSupplier, and the HeadPlayerData AstralSync snapshot (favorites). Reads the heads table only.

Master (MageHic)

com.astralrealms.heads.AstralHeads extends MageHicPlugin

A headless background worker: periodically imports a public head catalog CSV into a queued_heads table, then a rate-limited worker resolves each queued row against Mojang/Microsoft APIs and writes the result into heads. Has no commands, actions, or placeholders of its own.

The master module is the only writer that populates heads with Source.CATALOG rows; the paper module only reads the catalog (and separately writes its own Source.PLAYER rows — see Player heads below). See Catalog Import & Resolve Worker for the master module's full pipeline.

Data model

Both modules share one heads table (master/src/main/resources/schema.sql), mapped to HeadEntity (@Entity("heads")):

Column

Field

Notes

id

uniqueId (UUID)

Primary key. For CATALOG rows it's UUID.nameUUIDFromBytes("hash:" + textureHash) (deterministic from the texture hash); for PLAYER rows it's a fresh random UUID.

number

number (Long, nullable)

AUTO_INCREMENT human-friendly handle; null until the row is persisted and read back. This is the id the heads ItemStack supplier keys on.

source

source (HeadEntity.Source)

CATALOG (community heads, requires category + textureHash, forbids uuid) or PLAYER (requires uuid) — enforced by a DB CHECK constraint.

name

name

Catalog display name, or the player's Minecraft username.

texture_value/texture_signature

textureValue/textureSignature

Signed Mojang textures profile property (base64 + signature); always present so a head can always be built with no extra lookup.

texture_hash

textureHash

Catalog texture-CDN key; also stored (denormalized) for player heads.

category

category

CATALOG only — one of categories.yml's ids.

tags

tags (JsonArray)

CATALOG only — free-form search tags.

uuid

uuid

PLAYER only — the owning player's UUID.

skin_model

skinModel (SkinModel)

PLAYER only — CLASSIC or SLIM (Alex); null (defaults to CLASSIC) for catalog heads.

updated_at

updatedAt

DB-maintained timestamp.

HeadEntity#itemStack() lazily builds and caches a PLAYER_HEAD ItemStack: it creates a Bukkit PlayerProfile (using the real player UUID for PLAYER heads, or the head's own uniqueId under the display name "AstralHeads" for CATALOG heads), applies the texture — preferring the signed textures property, falling back to deriving a skin URL from textureHash (honoring skinModel), and finally the raw unsigned textureValue — sets the display name, and stamps the head's number into the item's PersistentDataContainer under astralheads:number (see PDCUtils).

Player heads

The paper module's HeadEntity is also a ComplexPlaceholder (namespace head, see Placeholders) resolving id, number, name, category, tags, item, favorite (per-viewing-player, via AstralSync HeadPlayerData) and price/currency (looked up from config.yml's prices map, keyed by source).

HeadService (paper) warms up on construction by loading every row from heads into a Caffeine AsyncLoadingCache<UUID, HeadEntity> (max 500k entries) and building two in-memory Multimaps — tag → UUID and category → UUID — plus a number → UUID map, kept in lock-step with the cache via its eviction listener and loader. HeadService#search(term) runs entirely against this in-memory cache (no per-query SQL): it tokenizes the (lower-cased, trimmed) term on whitespace, scores every CATALOG head against each token (exact name > numeric number match > name prefix > name whole-word > exact tag > name substring > tag substring > category substring > single-edit-distance fuzzy name match, in that order — a token that matches nothing disqualifies the whole head, i.e. AND semantics across tokens), and returns up to 50 UUIDs ranked by total score (ties broken alphabetically). Typo-tolerant fuzzy matching only kicks in as a fallback when the exact/substring scan finds nothing, and only for tokens of at least 4 characters. Results are cached per normalized search term for 5 minutes (searchCache, max 10k entries).

Buying & favoriting

  • Buying (buy-head action, see Actions) looks up the head's Source in config.yml's prices map; if unpriced, the head isn't for sale. On success it withdraws through EconomyService, then gives the head via MailboxService (if present) or directly into the player's inventory (dropping overflow at their feet).

  • Favoriting (toggle-favorite action) stores a Set<UUID> of favorited head ids in HeadPlayerData, an AstralSync player-data record synced across the network via HeadSnapshotAdapter (snapshot key astralheads:data).

Feature map

Area

Page

config.yml/categories.yml/messages.yml/database.properties keys

Configuration

/heads command tree, permissions

Commands

search-heads, toggle-favorite, buy-head actions

Actions

heads_*, head_*, category_* placeholders

Placeholders

Master module: catalog CSV import + Mojang/Microsoft resolve queue

Catalog Import & Resolve Worker

Requirements

Dependency

Required by

Notes

AstralCore

Paper module

Configuration loading, AstralPaperPlugin base, menu/dialog containers, placeholder framework, ItemStackSupplier/EconomyService/MailboxService registries.

AstralSync

Paper module

HeadPlayerData favorites snapshot (HeadSnapshotAdapter); declared as a hard plugin.yml dependency.

MariaDB

Both modules

Both connect to the same heads schema via DatabaseService (HikariCP), configured per-module in database.properties.

Mojang/Microsoft session-server & CDN APIs

Master module

NameResolver/UuidResolver (MojangAPI) and HashResolver (texture CDN) resolve queued lookups.

Last modified: 25 July 2026