Astral Realms Documentation Help

Configuration

AstralJobs' behavioural settings live in plugins/AstralJobs/config.yml. Localised strings live in messages.yml (see Messages), per-job definitions live under jobs/ (see Jobs), and booster item definitions live under boosters/ (see Boosters). Apply changes at runtime with /jobs reload (permission jobs.reload) — no restart required.

Files on disk

File / folder

Generated how

Purpose

config.yml

Copied from the JAR the first time it's missing (AstralJobs#loadConfigurationcopyResource/loadConfiguration).

This page.

messages.yml

Same — copied on first load, then bound field-by-field into the JobsMessages enum via loadEnum.

See Messages.

database.properties

Same — copied on first load via copyResource.

JDBC connection for DatabaseService (jdbcUrl, driverClassName, dataSource.user, dataSource.password, poolName).

jobs/*.yml

Not auto-copied. JobService#load only creates the jobs/ folder if it's missing, then walks whatever .yml/.yaml files are already there (ConfigurationManager#loadFolder).

One file per job — see Jobs.

boosters/*.yml

Not auto-copied, same mechanism (BoosterBlueprintService#load).

One file per booster blueprint — see Boosters.

The five shipped jobs (farmer, fisherman, hunter, lumberjack, miner) and the shipped example.yml booster blueprint only exist as resources bundled inside the plugin JAR — unlike config.yml/messages.yml/database.properties, nothing in AstralJobs' code extracts them onto disk. A fresh install ends up with empty jobs/ and boosters/ folders (and therefore no jobs and no boosters) until those files are placed on disk, e.g. by your server provisioning process.

config.yml

max-level: 200 permissions-boosters: "example.permission.booster1": EXPERIENCE: 2.0 MONEY: 1.5 "example.permission.booster2": EXPERIENCE: 1.5 MONEY: 2.0 leaderboards: fisherman: "jobs-fisherman" hunter: "jobs-hunter" miner: "jobs-miner" lumberjack: "jobs-lumberjack" farmer: "jobs-farmer" action-display: - " <red>Experience: <green>%experience%" - " <red>Money: <green>%money%" action-type-displays: block-break: "Casser" block-place: "Placer" harvest-block: "Récolter" shear-block: "Tondre" strip-block: "Écorcer" gather-honey: "Récolter" kill-entity: "Tuer" shear-entity: "Tondre" fish: "Pêcher" cook: "Cuire"

This whole file deserializes into one @ConfigSerializable record, JobsConfiguration, exposed as AstralJobs#configuration().

max-level

Key

Type

Default

max-level

int

200

A single cap shared by every job — there is no per-job override. ActionService's level-up loop keeps awarding levels while level < max-level; a value <= 0 is treated as uncapped (the loop then only stops when the job's level-progress-equation runs out of domain and starts returning a non-positive threshold). See Leveling model for the full algorithm.

permissions-boosters

Key

Type

Default

permissions-boosters

Map<String, Map<BoosterType, Double>>

Two example permission nodes (see above)

Maps a permission node to one or more BoosterType multipliers — EXPERIENCE, MONEY, or BOTH (BOTH applies to both, via JobModifierScope.GLOBAL). JobsConfiguration#permissionBoostersFor(Player) walks the map in declaration order and, for every node the player holds, overwrites the result with that entry's value map — so if a player matches more than one permission node, only the last matching entry in the YAML takes effect; matches don't stack.

BoosterService#applyPermissionModifiers runs this lookup once, on player join (PlayerConnectionListener), and turns each BoosterType → multiplier pair into a RELATIVE JobModifier. The multiplier is read as a bonus percentage two ways depending on its value: value > 1.0 is treated as a factor (2.0+100%), value <= 1.0 is used directly as the percentage (0.5+50%) — in code, bonusPercent = (multiplier > 1.0 ? multiplier - 1.0 : multiplier) * 100. The shipped defaults (2.0, 1.5) both use the factor form. Permission-booster modifiers are applied once at join and are not recomputed by /jobs reload or by a permission change mid-session — the player has to reconnect.

The shipped example.permission.booster1/example.permission.booster2 nodes are placeholders; replace them with real permission nodes from your rank/permissions plugin.

leaderboards

Key

Type

Default

leaderboards

Map<String, String>

All five shipped jobs mapped, see above

Maps a job id to an AstralAnalytics leaderboard id. On every level-up, LeaderboardListener looks up the leveled-up job's id in this map and, if present, pushes the player's new level into that leaderboard via AstralCore's LeaderboardService. A job whose id has no entry here simply never updates a leaderboard — no error, no fallback id.

action-display

Key

Type

Default

action-display

ComponentWrapperList

Two-line experience/money template, see above

A MiniMessage component-list template, rendered once per action-type entry when computing %action_computed% (JobActionPlaceholder). For every action-type defined under a material/entity key (e.g. a block's block-break reward), each line in action-display is rendered with:

Placeholder

Value

%experience%

XP for that action-type, after modifiers (ModifierService#computeWithLevel).

%money%

Money for that action-type, after modifiers.

%formattedName%

The matching action-type-displays entry for that action-type key.

%operation%

The reward's Operation glyph (//-), colored green/red/gray.

See Placeholders for the full %action_*% chain.

action-type-displays

Key

Type

Default

action-type-displays

Map<String, ComponentWrapper>

All ten action types, French labels, see above

Localized display name per tracked action type, keyed by the same ten action-type keys registered in ActionService (block-break, block-place, harvest-block, shear-block, strip-block, gather-honey, kill-entity, shear-entity, fish, cook — see Overview for what triggers each). JobsConfiguration#actionDisplayFor(actionTypeKey) looks up this map to fill %formattedName% above; if a key has no entry, that action-type's row is skipped entirely and a warning ("No action display found for action value key: …") is logged.

Configurate key mapping

config.yml deserializes through AstralCore's Configurate pipeline with the LOWER_CASE_DASHED naming scheme: a camelCase record component is looked up as its kebab-case equivalent (each uppercase letter gets a - inserted before it and is lowercased) — maxLevelmax-level, actionTypeDisplaysaction-type-displays, actionDisplayaction-display, leaderboardsleaderboards. (As noted above, permissionBoosterspermission-boosters, which the shipped file doesn't actually use.) Fields typed ComponentWrapper/ComponentWrapperList accept MiniMessage strings with %placeholders% inside them, resolved lazily against whatever PlaceholderContext they're rendered with — not at config-load time.

Reloading

/jobs reload calls AstralJobs#loadConfiguration(), which re-runs, in this order:

  1. copyResource("database.properties") — re-creates the file only if it's missing; does not re-read the JDBC settings into the live connection pool, so editing database.properties still requires a restart.

  2. messages.yml reloaded into JobsMessages.

  3. config.yml reloaded into JobsConfiguration (everything on this page).

  4. Every file under jobs/ reloaded (JobService#load) — replaces the in-memory job map wholesale.

  5. Every file under boosters/ reloaded (BoosterBlueprintService#load).

  6. Menu blueprints reloaded (MenuContainer#load).

Already-online players keep whatever JobModifiers they were given at join (see permissions-boosters above) — a reload doesn't recompute those.

Last modified: 25 July 2026