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 |
|---|---|---|
| Copied from the JAR the first time it's missing ( | This page. |
| Same — copied on first load, then bound field-by-field into the | See Messages. |
| Same — copied on first load via | JDBC connection for |
| Not auto-copied. | One file per job — see Jobs. |
| Not auto-copied, same mechanism ( | 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
This whole file deserializes into one @ConfigSerializable record, JobsConfiguration, exposed as AstralJobs#configuration().
max-level
Key | Type | Default |
|---|---|---|
| int |
|
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 |
|---|---|---|
|
| 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 |
|---|---|---|
|
| 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 |
|---|---|---|
|
| 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 |
|---|---|
| XP for that action-type, after modifiers ( |
| Money for that action-type, after modifiers. |
| The matching |
| The reward's |
See Placeholders for the full %action_*% chain.
action-type-displays
Key | Type | Default |
|---|---|---|
|
| 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) — maxLevel → max-level, actionTypeDisplays → action-type-displays, actionDisplay → action-display, leaderboards → leaderboards. (As noted above, permissionBoosters → permission-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:
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 editingdatabase.propertiesstill requires a restart.messages.ymlreloaded intoJobsMessages.config.ymlreloaded intoJobsConfiguration(everything on this page).Every file under
jobs/reloaded (JobService#load) — replaces the in-memory job map wholesale.Every file under
boosters/reloaded (BoosterBlueprintService#load).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.